Skip to content

Commit 5d4c71c

Browse files
committed
8281236: (D)TLS key exchange named groups
Reviewed-by: mullan
1 parent 10356e7 commit 5d4c71c

17 files changed

+806
-236
lines changed

src/java.base/share/classes/javax/net/ssl/SSLParameters.java

Lines changed: 129 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@
3434
* the list of protocols to be allowed, the endpoint identification
3535
* algorithm during SSL/TLS/DTLS handshaking, the Server Name Indication (SNI),
3636
* the maximum network packet size, the algorithm constraints, the signature
37-
* schemes and whether SSL/TLS/DTLS servers should request or require client
38-
* authentication, etc.
37+
* schemes, the key exchange named groups and whether SSL/TLS/DTLS servers
38+
* should request or require client authentication, etc.
3939
* <p>
4040
* {@code SSLParameter} objects can be created via the constructors in this
4141
* class, and can be described as pre-populated objects. {@code SSLParameter}
@@ -85,6 +85,7 @@ public class SSLParameters {
8585
private int maximumPacketSize = 0;
8686
private String[] applicationProtocols = new String[0];
8787
private String[] signatureSchemes = null;
88+
private String[] namedGroups = null;
8889

8990
/**
9091
* Constructs SSLParameters.
@@ -810,4 +811,130 @@ public void setSignatureSchemes(String[] signatureSchemes) {
810811

811812
this.signatureSchemes = tempSchemes;
812813
}
814+
815+
/**
816+
* Returns a prioritized array of key exchange named groups names that
817+
* can be used over the SSL/TLS/DTLS protocols.
818+
* <p>
819+
* Note that the standard list of key exchange named groups are defined
820+
* in the <a href=
821+
* "{@docRoot}/../specs/security/standard-names.html#named-groups">
822+
* Named Groups</a> section of the Java Security Standard Algorithm
823+
* Names Specification. Providers may support named groups not defined
824+
* in this list or may not use the recommended name for a certain named
825+
* group.
826+
* <p>
827+
* The set of named groups that will be used over the SSL/TLS/DTLS
828+
* connections is determined by the returned array of this method and the
829+
* underlying provider-specific default named groups.
830+
* <p>
831+
* If the returned array is {@code null}, then the underlying
832+
* provider-specific default named groups will be used over the
833+
* SSL/TLS/DTLS connections.
834+
* <p>
835+
* If the returned array is empty (zero-length), then the named group
836+
* negotiation mechanism is turned off for SSL/TLS/DTLS protocols, and
837+
* the connections may not be able to be established if the negotiation
838+
* mechanism is required by a certain SSL/TLS/DTLS protocol. This
839+
* parameter will override the underlying provider-specific default
840+
* name groups.
841+
* <p>
842+
* If the returned array is not {@code null} or empty (zero-length),
843+
* then the named groups in the returned array will be used over
844+
* the SSL/TLS/DTLS connections. This parameter will override the
845+
* underlying provider-specific default named groups.
846+
* <p>
847+
* This method returns the most recent value passed to
848+
* {@link #setNamedGroups} if that method has been called and otherwise
849+
* returns the default named groups for connection populated objects,
850+
* or {@code null} for pre-populated objects.
851+
*
852+
* @apiNote
853+
* Note that a provider may not have been updated to support this method
854+
* and in that case may return {@code null} instead of the default
855+
* named groups for connection populated objects.
856+
*
857+
* @implNote
858+
* The SunJSSE provider supports this method.
859+
*
860+
* @implNote
861+
* Note that applications may use the
862+
* {@systemProperty jdk.tls.namedGroups} system property with the SunJSSE
863+
* provider to override the provider-specific default named groups.
864+
*
865+
* @return an array of key exchange named group names {@code Strings} or
866+
* {@code null} if none have been set. For non-null returns, this
867+
* method will return a new array each time it is invoked. The
868+
* array is ordered based on named group preference, with the first
869+
* entry being the most preferred. Providers should ignore unknown
870+
* named group names while establishing the SSL/TLS/DTLS
871+
* connections.
872+
* @see #setNamedGroups
873+
*
874+
* @since 20
875+
*/
876+
public String[] getNamedGroups() {
877+
return clone(namedGroups);
878+
}
879+
880+
/**
881+
* Sets the prioritized array of key exchange named groups names that
882+
* can be used over the SSL/TLS/DTLS protocols.
883+
* <p>
884+
* Note that the standard list of key exchange named groups are defined in
885+
* the <a href=
886+
* "{@docRoot}/../specs/security/standard-names.html#named-groups">
887+
* Named Groups</a> section of the Java Security Standard Algorithm
888+
* Names Specification. Providers may support named groups not defined
889+
* in this list or may not use the recommended name for a certain named
890+
* group.
891+
* <p>
892+
* The set of named groups that will be used over the SSL/TLS/DTLS
893+
* connections is determined by the input parameter {@code namedGroups}
894+
* array and the underlying provider-specific default named groups.
895+
* See {@link #getNamedGroups} for specific details on how the
896+
* parameters are used in SSL/TLS/DTLS connections.
897+
*
898+
* @apiNote
899+
* Note that a provider may not have been updated to support this method
900+
* and in that case may ignore the named groups that are set.
901+
*
902+
* @implNote
903+
* The SunJSSE provider supports this method.
904+
*
905+
* @param namedGroups an ordered array of key exchange named group names
906+
* with the first entry being the most preferred, or {@code null}.
907+
* This method will make a copy of this array. Providers should
908+
* ignore unknown named group scheme names while establishing the
909+
* SSL/TLS/DTLS connections.
910+
* @throws IllegalArgumentException if any element in the
911+
* {@code namedGroups} array is a duplicate, {@code null} or
912+
* {@linkplain String#isBlank() blank}.
913+
*
914+
* @see #getNamedGroups
915+
*
916+
* @since 20
917+
*/
918+
public void setNamedGroups(String[] namedGroups) {
919+
String[] tempGroups = null;
920+
921+
if (namedGroups != null) {
922+
tempGroups = namedGroups.clone();
923+
Set<String> groupsSet = new HashSet<>();
924+
for (String namedGroup : tempGroups) {
925+
if (namedGroup == null || namedGroup.isBlank()) {
926+
throw new IllegalArgumentException(
927+
"An element of namedGroups is null or blank");
928+
}
929+
930+
if (groupsSet.contains(namedGroup)) {
931+
throw new IllegalArgumentException(
932+
"Duplicate element of namedGroups: " + namedGroup);
933+
}
934+
groupsSet.add(namedGroup);
935+
}
936+
}
937+
938+
this.namedGroups = tempGroups;
939+
}
813940
}

src/java.base/share/classes/sun/security/ssl/CertificateVerify.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,7 @@ static final class T12CertificateVerifyMessage extends HandshakeMessage {
590590
ClientHandshakeContext chc = (ClientHandshakeContext)context;
591591
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
592592
SignatureScheme.getSignerOfPreferableAlgorithm(
593+
chc.sslConfig,
593594
chc.algorithmConstraints,
594595
chc.peerRequestedSignatureSchemes,
595596
x509Possession,
@@ -901,6 +902,7 @@ static final class T13CertificateVerifyMessage extends HandshakeMessage {
901902

902903
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
903904
SignatureScheme.getSignerOfPreferableAlgorithm(
905+
context.sslConfig,
904906
context.algorithmConstraints,
905907
context.peerRequestedSignatureSchemes,
906908
x509Possession,

src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import javax.crypto.spec.DHPublicKeySpec;
4343
import sun.security.action.GetPropertyAction;
4444
import sun.security.ssl.NamedGroup.NamedGroupSpec;
45-
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
4645
import sun.security.ssl.X509Authentication.X509Possession;
4746
import sun.security.util.KeyUtil;
4847

@@ -313,12 +312,13 @@ public SSLPossession createPossession(HandshakeContext context) {
313312
if (!useLegacyEphemeralDHKeys &&
314313
(context.clientRequestedNamedGroups != null) &&
315314
(!context.clientRequestedNamedGroups.isEmpty())) {
316-
preferableNamedGroup =
317-
SupportedGroups.getPreferredGroup(context.negotiatedProtocol,
318-
context.algorithmConstraints,
319-
new NamedGroupSpec [] {
320-
NamedGroupSpec.NAMED_GROUP_FFDHE },
321-
context.clientRequestedNamedGroups);
315+
preferableNamedGroup = NamedGroup.getPreferredGroup(
316+
context.sslConfig,
317+
context.negotiatedProtocol,
318+
context.algorithmConstraints,
319+
new NamedGroupSpec [] {
320+
NamedGroupSpec.NAMED_GROUP_FFDHE },
321+
context.clientRequestedNamedGroups);
322322
if (preferableNamedGroup != null) {
323323
return new DHEPossession(preferableNamedGroup,
324324
context.sslContext.getSecureRandom());

src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class DHServerKeyExchangeMessage extends HandshakeMessage {
127127
if (useExplicitSigAlgorithm) {
128128
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
129129
SignatureScheme.getSignerOfPreferableAlgorithm(
130+
shc.sslConfig,
130131
shc.algorithmConstraints,
131132
shc.peerRequestedSignatureSchemes,
132133
x509Possession,

src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import javax.crypto.SecretKey;
4545
import javax.net.ssl.SSLHandshakeException;
4646
import sun.security.ssl.NamedGroup.NamedGroupSpec;
47-
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
4847
import sun.security.ssl.X509Authentication.X509Credentials;
4948
import sun.security.ssl.X509Authentication.X509Possession;
5049
import sun.security.ssl.XDHKeyExchange.XDHECredentials;
@@ -236,15 +235,17 @@ public SSLPossession createPossession(HandshakeContext context) {
236235
// Find most preferred EC or XEC groups
237236
if ((context.clientRequestedNamedGroups != null) &&
238237
(!context.clientRequestedNamedGroups.isEmpty())) {
239-
preferableNamedGroup = SupportedGroups.getPreferredGroup(
238+
preferableNamedGroup = NamedGroup.getPreferredGroup(
239+
context.sslConfig,
240240
context.negotiatedProtocol,
241241
context.algorithmConstraints,
242242
new NamedGroupSpec[] {
243243
NamedGroupSpec.NAMED_GROUP_ECDHE,
244244
NamedGroupSpec.NAMED_GROUP_XDH },
245245
context.clientRequestedNamedGroups);
246246
} else {
247-
preferableNamedGroup = SupportedGroups.getPreferredGroup(
247+
preferableNamedGroup = NamedGroup.getPreferredGroup(
248+
context.sslConfig,
248249
context.negotiatedProtocol,
249250
context.algorithmConstraints,
250251
new NamedGroupSpec[] {

src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
import java.util.Locale;
4343
import java.util.Map;
4444
import sun.security.ssl.SSLHandshake.HandshakeMessage;
45-
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
4645
import sun.security.ssl.X509Authentication.X509Credentials;
4746
import sun.security.ssl.X509Authentication.X509Possession;
4847
import sun.security.util.HexDumpEncoder;
@@ -139,6 +138,7 @@ class ECDHServerKeyExchangeMessage extends HandshakeMessage {
139138
if (useExplicitSigAlgorithm) {
140139
Map.Entry<SignatureScheme, Signature> schemeAndSigner =
141140
SignatureScheme.getSignerOfPreferableAlgorithm(
141+
shc.sslConfig,
142142
shc.algorithmConstraints,
143143
shc.peerRequestedSignatureSchemes,
144144
x509Possession,
@@ -204,7 +204,7 @@ class ECDHServerKeyExchangeMessage extends HandshakeMessage {
204204
"Unknown named group ID: " + namedGroupId);
205205
}
206206

207-
if (!SupportedGroups.isSupported(namedGroup)) {
207+
if (!NamedGroup.isEnabled(chc.sslConfig, namedGroup)) {
208208
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
209209
"Unsupported named group: " + namedGroup);
210210
}

src/java.base/share/classes/sun/security/ssl/HandshakeContext.java

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
import javax.security.auth.x500.X500Principal;
4040
import sun.security.ssl.NamedGroup.NamedGroupSpec;
4141
import static sun.security.ssl.NamedGroup.NamedGroupSpec.*;
42-
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
4342

4443
abstract class HandshakeContext implements ConnectionContext {
4544
// System properties
@@ -157,8 +156,8 @@ protected HandshakeContext(SSLContextImpl sslContext,
157156

158157
this.algorithmConstraints = SSLAlgorithmConstraints.wrap(
159158
sslConfig.userSpecifiedAlgorithmConstraints);
160-
this.activeProtocols = getActiveProtocols(sslConfig.enabledProtocols,
161-
sslConfig.enabledCipherSuites, algorithmConstraints);
159+
this.activeProtocols =
160+
getActiveProtocols(sslConfig, algorithmConstraints);
162161
if (activeProtocols.isEmpty()) {
163162
throw new SSLHandshakeException(
164163
"No appropriate protocol (protocol is disabled or " +
@@ -173,8 +172,8 @@ protected HandshakeContext(SSLContextImpl sslContext,
173172
}
174173
}
175174
this.maximumActiveProtocol = maximumVersion;
176-
this.activeCipherSuites = getActiveCipherSuites(this.activeProtocols,
177-
sslConfig.enabledCipherSuites, algorithmConstraints);
175+
this.activeCipherSuites = getActiveCipherSuites(sslConfig,
176+
this.activeProtocols, algorithmConstraints);
178177
if (activeCipherSuites.isEmpty()) {
179178
throw new SSLHandshakeException("No appropriate cipher suite");
180179
}
@@ -256,12 +255,11 @@ private void initialize() {
256255
}
257256

258257
private static List<ProtocolVersion> getActiveProtocols(
259-
List<ProtocolVersion> enabledProtocols,
260-
List<CipherSuite> enabledCipherSuites,
258+
SSLConfiguration sslConfig,
261259
AlgorithmConstraints algorithmConstraints) {
262260
boolean enabledSSL20Hello = false;
263261
ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
264-
for (ProtocolVersion protocol : enabledProtocols) {
262+
for (ProtocolVersion protocol : sslConfig.enabledProtocols) {
265263
if (!enabledSSL20Hello && protocol == ProtocolVersion.SSL20Hello) {
266264
enabledSSL20Hello = true;
267265
continue;
@@ -277,9 +275,9 @@ private static List<ProtocolVersion> getActiveProtocols(
277275
boolean found = false;
278276
Map<NamedGroupSpec, Boolean> cachedStatus =
279277
new EnumMap<>(NamedGroupSpec.class);
280-
for (CipherSuite suite : enabledCipherSuites) {
278+
for (CipherSuite suite : sslConfig.enabledCipherSuites) {
281279
if (suite.isAvailable() && suite.supports(protocol)) {
282-
if (isActivatable(suite,
280+
if (isActivatable(sslConfig, suite,
283281
algorithmConstraints, cachedStatus)) {
284282
protocols.add(protocol);
285283
found = true;
@@ -309,15 +307,15 @@ private static List<ProtocolVersion> getActiveProtocols(
309307
}
310308

311309
private static List<CipherSuite> getActiveCipherSuites(
310+
SSLConfiguration sslConfig,
312311
List<ProtocolVersion> enabledProtocols,
313-
List<CipherSuite> enabledCipherSuites,
314312
AlgorithmConstraints algorithmConstraints) {
315313

316314
List<CipherSuite> suites = new LinkedList<>();
317315
if (enabledProtocols != null && !enabledProtocols.isEmpty()) {
318316
Map<NamedGroupSpec, Boolean> cachedStatus =
319317
new EnumMap<>(NamedGroupSpec.class);
320-
for (CipherSuite suite : enabledCipherSuites) {
318+
for (CipherSuite suite : sslConfig.enabledCipherSuites) {
321319
if (!suite.isAvailable()) {
322320
continue;
323321
}
@@ -327,7 +325,7 @@ private static List<CipherSuite> getActiveCipherSuites(
327325
if (!suite.supports(protocol)) {
328326
continue;
329327
}
330-
if (isActivatable(suite,
328+
if (isActivatable(sslConfig, suite,
331329
algorithmConstraints, cachedStatus)) {
332330
suites.add(suite);
333331
isSupported = true;
@@ -525,7 +523,9 @@ boolean isNegotiable(ProtocolVersion protocolVersion) {
525523
return activeProtocols.contains(protocolVersion);
526524
}
527525

528-
private static boolean isActivatable(CipherSuite suite,
526+
private static boolean isActivatable(
527+
SSLConfiguration sslConfig,
528+
CipherSuite suite,
529529
AlgorithmConstraints algorithmConstraints,
530530
Map<NamedGroupSpec, Boolean> cachedStatus) {
531531

@@ -543,8 +543,8 @@ private static boolean isActivatable(CipherSuite suite,
543543
if (groupType != NAMED_GROUP_NONE) {
544544
Boolean checkedStatus = cachedStatus.get(groupType);
545545
if (checkedStatus == null) {
546-
groupAvailable = SupportedGroups.isActivatable(
547-
algorithmConstraints, groupType);
546+
groupAvailable = NamedGroup.isActivatable(
547+
sslConfig, algorithmConstraints, groupType);
548548
cachedStatus.put(groupType, groupAvailable);
549549

550550
if (!groupAvailable &&

src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import sun.security.ssl.SSLExtension.ExtensionConsumer;
3737
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
3838
import sun.security.ssl.SSLHandshake.HandshakeMessage;
39-
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
4039
import sun.security.util.HexDumpEncoder;
4140

4241
/**
@@ -345,7 +344,7 @@ public void consume(ConnectionContext context,
345344
List<SSLCredentials> credentials = new LinkedList<>();
346345
for (KeyShareEntry entry : spec.clientShares) {
347346
NamedGroup ng = NamedGroup.valueOf(entry.namedGroupId);
348-
if (ng == null || !SupportedGroups.isActivatable(
347+
if (ng == null || !NamedGroup.isActivatable(shc.sslConfig,
349348
shc.algorithmConstraints, ng)) {
350349
if (SSLLogger.isOn &&
351350
SSLLogger.isOn("ssl,handshake")) {
@@ -647,7 +646,7 @@ public void consume(ConnectionContext context,
647646
SHKeyShareSpec spec = new SHKeyShareSpec(chc, buffer);
648647
KeyShareEntry keyShare = spec.serverShare;
649648
NamedGroup ng = NamedGroup.valueOf(keyShare.namedGroupId);
650-
if (ng == null || !SupportedGroups.isActivatable(
649+
if (ng == null || !NamedGroup.isActivatable(chc.sslConfig,
651650
chc.algorithmConstraints, ng)) {
652651
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
653652
"Unsupported named group: " +
@@ -800,7 +799,7 @@ public byte[] produce(ConnectionContext context,
800799

801800
NamedGroup selectedGroup = null;
802801
for (NamedGroup ng : shc.clientRequestedNamedGroups) {
803-
if (SupportedGroups.isActivatable(
802+
if (NamedGroup.isActivatable(shc.sslConfig,
804803
shc.algorithmConstraints, ng)) {
805804
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
806805
SSLLogger.fine(

0 commit comments

Comments
 (0)