8370885: Default namedGroups values are not being filtered against algorithm constraints

Reviewed-by: hchao
This commit is contained in:
Artur Barashev 2026-01-22 13:11:42 +00:00
parent eda15aa19c
commit 025041ba04
2 changed files with 189 additions and 73 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,10 +30,12 @@ import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.NamedParameterSpec;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.ArrayList;
import java.util.Objects;
import java.util.Set;
import javax.crypto.KeyAgreement;
import javax.crypto.spec.DHParameterSpec;
@ -463,10 +465,9 @@ enum NamedGroup {
AlgorithmConstraints constraints, NamedGroupSpec type) {
boolean hasFFDHEGroups = false;
for (String ng : sslConfig.namedGroups) {
NamedGroup namedGroup = NamedGroup.nameOf(ng);
if (namedGroup != null &&
namedGroup.isAvailable && namedGroup.spec == type) {
for (NamedGroup namedGroup :
SupportedGroups.getGroupsFromConfig(sslConfig)) {
if (namedGroup.isAvailable && namedGroup.spec == type) {
if (namedGroup.isPermitted(constraints)) {
return true;
}
@ -501,8 +502,8 @@ enum NamedGroup {
// Is the named group supported?
static boolean isEnabled(SSLConfiguration sslConfig,
NamedGroup namedGroup) {
for (String ng : sslConfig.namedGroups) {
if (namedGroup.name.equalsIgnoreCase(ng)) {
for (NamedGroup ng : SupportedGroups.getGroupsFromConfig(sslConfig)) {
if (namedGroup.equals(ng)) {
return true;
}
}
@ -516,12 +517,10 @@ enum NamedGroup {
SSLConfiguration sslConfig,
ProtocolVersion negotiatedProtocol,
AlgorithmConstraints constraints, NamedGroupSpec[] types) {
for (String name : sslConfig.namedGroups) {
NamedGroup ng = NamedGroup.nameOf(name);
if (ng != null && ng.isAvailable &&
(NamedGroupSpec.arrayContains(types, ng.spec)) &&
ng.isAvailable(negotiatedProtocol) &&
ng.isPermitted(constraints)) {
for (NamedGroup ng : SupportedGroups.getGroupsFromConfig(sslConfig)) {
if (ng.isAvailable && NamedGroupSpec.arrayContains(types, ng.spec)
&& ng.isAvailable(negotiatedProtocol)
&& ng.isPermitted(constraints)) {
return ng;
}
}
@ -857,19 +856,92 @@ enum NamedGroup {
}
}
// Inner class encapsulating supported named groups.
static final class SupportedGroups {
// the supported named groups, non-null immutable list
// Default named groups.
private static final NamedGroup[] defaultGroups = new NamedGroup[]{
// Hybrid key agreement
X25519MLKEM768,
// Primary XDH (RFC 7748) curves
X25519,
// Primary NIST Suite B curves
SECP256_R1,
SECP384_R1,
SECP521_R1,
// Secondary XDH curves
X448,
// FFDHE (RFC 7919)
FFDHE_2048,
FFDHE_3072,
FFDHE_4096,
FFDHE_6144,
FFDHE_8192
};
// Filter default groups names against default constraints.
// Those are the values being displayed to the user with
// "java -XshowSettings:security:tls" command.
private static final String[] defaultNames = Arrays.stream(
defaultGroups)
.filter(ng -> ng.isAvailable)
.filter(ng -> ng.isPermitted(SSLAlgorithmConstraints.DEFAULT))
.map(ng -> ng.name)
.toArray(String[]::new);
private static final NamedGroup[] customizedGroups =
getCustomizedNamedGroups();
// Note: user-passed groups are not being filtered against default
// algorithm constraints here. They will be displayed as-is.
private static final String[] customizedNames =
customizedGroups == null ?
null : Arrays.stream(customizedGroups)
.map(ng -> ng.name)
.toArray(String[]::new);
// Named group names for SSLConfiguration.
static final String[] namedGroups;
static {
// The value of the System Property defines a list of enabled named
// groups in preference order, separated with comma. For example:
//
// jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
//
// If the System Property is not defined or the value is empty, the
// default groups and preferences will be used.
if (customizedNames != null) {
namedGroups = customizedNames;
} else {
if (defaultNames.length == 0) {
SSLLogger.logWarning("ssl", "No default named groups");
}
namedGroups = defaultNames;
}
}
// Avoid the group lookup for default and customized groups.
static NamedGroup[] getGroupsFromConfig(SSLConfiguration sslConfig) {
if (sslConfig.namedGroups == defaultNames) {
return defaultGroups;
} else if (sslConfig.namedGroups == customizedNames) {
return customizedGroups;
} else {
return Arrays.stream(sslConfig.namedGroups)
.map(NamedGroup::nameOf)
.filter(Objects::nonNull)
.toArray(NamedGroup[]::new);
}
}
// The value of the System Property defines a list of enabled named
// groups in preference order, separated with comma. For example:
//
// jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
//
// If the System Property is not defined or the value is empty, the
// default groups and preferences will be used.
private static NamedGroup[] getCustomizedNamedGroups() {
String property = System.getProperty("jdk.tls.namedGroups");
if (property != null && !property.isEmpty()) {
// remove double quote marks from beginning/end of the property
if (property.length() > 1 && property.charAt(0) == '"' &&
@ -878,66 +950,25 @@ enum NamedGroup {
}
}
ArrayList<String> groupList;
if (property != null && !property.isEmpty()) {
String[] groups = property.split(",");
groupList = new ArrayList<>(groups.length);
for (String group : groups) {
group = group.trim();
if (!group.isEmpty()) {
NamedGroup namedGroup = nameOf(group);
if (namedGroup != null) {
if (namedGroup.isAvailable) {
groupList.add(namedGroup.name);
}
} // ignore unknown groups
}
}
NamedGroup[] ret = Arrays.stream(property.split(","))
.map(String::trim)
.map(NamedGroup::nameOf)
.filter(Objects::nonNull)
.filter(ng -> ng.isAvailable)
.toArray(NamedGroup[]::new);
if (groupList.isEmpty()) {
if (ret.length == 0) {
throw new IllegalArgumentException(
"System property jdk.tls.namedGroups(" +
property + ") contains no supported named groups");
}
} else { // default groups
NamedGroup[] groups = new NamedGroup[] {
// Hybrid key agreement
X25519MLKEM768,
// Primary XDH (RFC 7748) curves
X25519,
// Primary NIST Suite B curves
SECP256_R1,
SECP384_R1,
SECP521_R1,
// Secondary XDH curves
X448,
// FFDHE (RFC 7919)
FFDHE_2048,
FFDHE_3072,
FFDHE_4096,
FFDHE_6144,
FFDHE_8192,
};
groupList = new ArrayList<>(groups.length);
for (NamedGroup group : groups) {
if (group.isAvailable) {
groupList.add(group.name);
}
property
+ ") contains no supported named groups");
}
if (groupList.isEmpty() &&
SSLLogger.isOn() && SSLLogger.isOn("ssl")) {
SSLLogger.warning("No default named groups");
}
return ret;
}
namedGroups = groupList.toArray(new String[0]);
return null;
}
}
}

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import static jdk.test.lib.Asserts.assertFalse;
import static jdk.test.lib.Asserts.assertTrue;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import javax.net.ssl.SSLEngine;
import jdk.test.lib.security.SecurityUtils;
/*
* @test
* @bug 8370885
* @summary Default namedGroups values are not being filtered against
* algorithm constraints
* @library /javax/net/ssl/templates
* /test/lib
* @run main/othervm DefaultNamedGroups
*/
public class DefaultNamedGroups extends SSLEngineTemplate {
protected static final String DISABLED_NG = "secp256r1";
protected static final List<String> REFERENCE_NG = Stream.of(
"X25519MLKEM768",
"x25519",
"secp256r1",
"secp384r1",
"secp521r1",
"x448",
"ffdhe2048",
"ffdhe3072",
"ffdhe4096",
"ffdhe6144",
"ffdhe8192")
.sorted()
.toList();
protected DefaultNamedGroups() throws Exception {
super();
}
public static void main(String[] args) throws Exception {
SecurityUtils.addToDisabledTlsAlgs(DISABLED_NG);
var test = new DefaultNamedGroups();
for (SSLEngine engine :
new SSLEngine[]{test.serverEngine, test.clientEngine}) {
checkEngineDefaultNG(engine);
}
}
private static void checkEngineDefaultNG(SSLEngine engine) {
var defaultConfigNG = new ArrayList<>(List.of(
engine.getSSLParameters().getNamedGroups()));
assertFalse(defaultConfigNG.contains(DISABLED_NG));
defaultConfigNG.add(DISABLED_NG);
assertTrue(REFERENCE_NG.equals(
defaultConfigNG.stream().sorted().toList()),
"Named groups returned by engine: " + defaultConfigNG);
}
}