--- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Wed Jun 12 18:58:00 2019 -0700
@@ -35,8 +35,8 @@
import static sun.security.ssl.CipherSuite.KeyExchange.*;
import static sun.security.ssl.CipherSuite.MacAlg.*;
import static sun.security.ssl.SSLCipher.*;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
-import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import static sun.security.ssl.NamedGroup.NamedGroupType.*;
/**
* Enum for SSL/(D)TLS cipher suites.
@@ -184,7 +184,7 @@
K_DHE_DSS, B_AES_128, M_SHA256, H_SHA256),
//
- // not forward screcy cipher suites.
+ // not forward secret cipher suites.
//
// AES_256(GCM)
@@ -1106,11 +1106,18 @@
K_DH_ANON ("DH_anon", true, true, NAMED_GROUP_FFDHE),
K_DH_ANON_EXPORT("DH_anon_EXPORT", true, true, NAMED_GROUP_NONE),
- K_ECDH_ECDSA ("ECDH_ECDSA", true, false, NAMED_GROUP_ECDHE),
- K_ECDH_RSA ("ECDH_RSA", true, false, NAMED_GROUP_ECDHE),
- K_ECDHE_ECDSA ("ECDHE_ECDSA", true, false, NAMED_GROUP_ECDHE),
- K_ECDHE_RSA ("ECDHE_RSA", true, false, NAMED_GROUP_ECDHE),
- K_ECDH_ANON ("ECDH_anon", true, true, NAMED_GROUP_ECDHE),
+ // These KeyExchanges can use either ECDHE/XDH, so we'll use a
+ // varargs here.
+ K_ECDH_ECDSA ("ECDH_ECDSA", JsseJce.ALLOW_ECC, false,
+ NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+ K_ECDH_RSA ("ECDH_RSA", JsseJce.ALLOW_ECC, false,
+ NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+ K_ECDHE_ECDSA ("ECDHE_ECDSA", JsseJce.ALLOW_ECC, false,
+ NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+ K_ECDHE_RSA ("ECDHE_RSA", JsseJce.ALLOW_ECC, false,
+ NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
+ K_ECDH_ANON ("ECDH_anon", JsseJce.ALLOW_ECC, true,
+ NAMED_GROUP_ECDHE, NAMED_GROUP_XDH),
// renegotiation protection request signaling cipher suite
K_SCSV ("SCSV", true, true, NAMED_GROUP_NONE);
@@ -1118,19 +1125,16 @@
// name of the key exchange algorithm, e.g. DHE_DSS
final String name;
final boolean allowed;
- final NamedGroupType groupType;
+ final NamedGroupType[] groupTypes;
private final boolean alwaysAvailable;
private final boolean isAnonymous;
KeyExchange(String name, boolean allowed,
- boolean isAnonymous, NamedGroupType groupType) {
+ boolean isAnonymous, NamedGroupType... groupTypes) {
this.name = name;
- if (groupType == NAMED_GROUP_ECDHE) {
- this.allowed = JsseJce.ALLOW_ECC;
- } else {
- this.allowed = allowed;
- }
- this.groupType = groupType;
+ this.groupTypes = groupTypes;
+ this.allowed = allowed;
+
this.alwaysAvailable = allowed && (!name.startsWith("EC"));
this.isAnonymous = isAnonymous;
}
@@ -1140,7 +1144,8 @@
return true;
}
- if (groupType == NAMED_GROUP_ECDHE) {
+ if (NamedGroupType.arrayContains(
+ groupTypes, NamedGroupType.NAMED_GROUP_ECDHE)) {
return (allowed && JsseJce.isEcAvailable());
} else {
return allowed;
--- a/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/DHClientKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -42,7 +42,6 @@
import sun.security.ssl.DHKeyExchange.DHECredentials;
import sun.security.ssl.DHKeyExchange.DHEPossession;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.util.HexDumpEncoder;
/**
--- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -36,19 +36,12 @@
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
-import javax.crypto.KeyAgreement;
-import javax.crypto.SecretKey;
import javax.crypto.interfaces.DHPublicKey;
import javax.crypto.spec.DHParameterSpec;
import javax.crypto.spec.DHPublicKeySpec;
-import javax.crypto.spec.SecretKeySpec;
-import javax.net.ssl.SSLHandshakeException;
import sun.security.action.GetPropertyAction;
-import sun.security.ssl.CipherSuite.HashAlg;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.ssl.X509Authentication.X509Possession;
import sun.security.util.KeyUtil;
@@ -61,7 +54,7 @@
static final SSLKeyAgreementGenerator kaGenerator =
new DHEKAGenerator();
- static final class DHECredentials implements SSLCredentials {
+ static final class DHECredentials implements NamedGroupCredentials {
final DHPublicKey popPublicKey;
final NamedGroup namedGroup;
@@ -70,6 +63,16 @@
this.namedGroup = namedGroup;
}
+ @Override
+ public PublicKey getPublicKey() {
+ return popPublicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
static DHECredentials valueOf(NamedGroup ng,
byte[] encodedPublic) throws IOException, GeneralSecurityException {
@@ -98,7 +101,7 @@
}
}
- static final class DHEPossession implements SSLPossession {
+ static final class DHEPossession implements NamedGroupPossession {
final PrivateKey privateKey;
final DHPublicKey publicKey;
final NamedGroup namedGroup;
@@ -174,13 +177,13 @@
// Generate and validate DHPublicKeySpec
private KeyPair generateDHKeyPair(
KeyPairGenerator kpg) throws GeneralSecurityException {
- boolean doExtraValiadtion =
+ boolean doExtraValidation =
(!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName()));
boolean isRecovering = false;
for (int i = 0; i <= 2; i++) { // Try to recover from failure.
KeyPair kp = kpg.generateKeyPair();
// validate the Diffie-Hellman public key
- if (doExtraValiadtion) {
+ if (doExtraValidation) {
DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic());
try {
KeyUtil.validate(spec);
@@ -231,6 +234,21 @@
return encoded;
}
+
+ @Override
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
+ @Override
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
}
private static final class
@@ -298,7 +316,7 @@
// Used for ServerKeyExchange, TLS 1.2 and prior versions.
@Override
public SSLPossession createPossession(HandshakeContext context) {
- NamedGroup preferableNamedGroup = null;
+ NamedGroup preferableNamedGroup;
if (!useLegacyEphemeralDHKeys &&
(context.clientRequestedNamedGroups != null) &&
(!context.clientRequestedNamedGroups.isEmpty())) {
@@ -306,7 +324,8 @@
SupportedGroups.getPreferredGroup(
context.negotiatedProtocol,
context.algorithmConstraints,
- NamedGroupType.NAMED_GROUP_FFDHE,
+ new NamedGroupType [] {
+ NamedGroupType.NAMED_GROUP_FFDHE },
context.clientRequestedNamedGroups);
if (preferableNamedGroup != null) {
return new DHEPossession(preferableNamedGroup,
@@ -392,7 +411,7 @@
private static final
class DHEKAGenerator implements SSLKeyAgreementGenerator {
- static private DHEKAGenerator instance = new DHEKAGenerator();
+ private static final DHEKAGenerator instance = new DHEKAGenerator();
// Prevent instantiation of this class.
private DHEKAGenerator() {
@@ -442,93 +461,8 @@
"No sufficient DHE key agreement parameters negotiated");
}
- return new DHEKAKeyDerivation(context,
+ return new KAKeyDerivation("DiffieHellman", context,
dhePossession.privateKey, dheCredentials.popPublicKey);
}
-
- private static final
- class DHEKAKeyDerivation implements SSLKeyDerivation {
- private final HandshakeContext context;
- private final PrivateKey localPrivateKey;
- private final PublicKey peerPublicKey;
-
- DHEKAKeyDerivation(HandshakeContext context,
- PrivateKey localPrivateKey,
- PublicKey peerPublicKey) {
- this.context = context;
- this.localPrivateKey = localPrivateKey;
- this.peerPublicKey = peerPublicKey;
- }
-
- @Override
- public SecretKey deriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
- return t12DeriveKey(algorithm, params);
- } else {
- return t13DeriveKey(algorithm, params);
- }
- }
-
- private SecretKey t12DeriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- try {
- KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
- ka.init(localPrivateKey);
- ka.doPhase(peerPublicKey, true);
- SecretKey preMasterSecret =
- ka.generateSecret("TlsPremasterSecret");
- SSLMasterKeyDerivation mskd =
- SSLMasterKeyDerivation.valueOf(
- context.negotiatedProtocol);
- if (mskd == null) {
- // unlikely
- throw new SSLHandshakeException(
- "No expected master key derivation for protocol: " +
- context.negotiatedProtocol.name);
- }
- SSLKeyDerivation kd = mskd.createKeyDerivation(
- context, preMasterSecret);
- return kd.deriveKey("MasterSecret", params);
- } catch (GeneralSecurityException gse) {
- throw (SSLHandshakeException) new SSLHandshakeException(
- "Could not generate secret").initCause(gse);
- }
- }
-
- private SecretKey t13DeriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- try {
- KeyAgreement ka = KeyAgreement.getInstance("DiffieHellman");
- ka.init(localPrivateKey);
- ka.doPhase(peerPublicKey, true);
- SecretKey sharedSecret =
- ka.generateSecret("TlsPremasterSecret");
-
- HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
- SSLKeyDerivation kd = context.handshakeKeyDerivation;
- HKDF hkdf = new HKDF(hashAlg.name);
- if (kd == null) { // No PSK is in use.
- // If PSK is not in use Early Secret will still be
- // HKDF-Extract(0, 0).
- byte[] zeros = new byte[hashAlg.hashLength];
- SecretKeySpec ikm =
- new SecretKeySpec(zeros, "TlsPreSharedSecret");
- SecretKey earlySecret =
- hkdf.extract(zeros, ikm, "TlsEarlySecret");
- kd = new SSLSecretDerivation(context, earlySecret);
- }
-
- // derive salt secret
- SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
- // derive handshake secret
- return hkdf.extract(saltSecret, sharedSecret, algorithm);
- } catch (GeneralSecurityException gse) {
- throw (SSLHandshakeException) new SSLHandshakeException(
- "Could not generate secret").initCause(gse);
- }
- }
- }
}
}
--- a/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/DHServerKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -48,7 +48,6 @@
import sun.security.ssl.DHKeyExchange.DHECredentials;
import sun.security.ssl.DHKeyExchange.DHEPossession;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.X509Authentication.X509Credentials;
import sun.security.ssl.X509Authentication.X509Possession;
import sun.security.util.HexDumpEncoder;
--- a/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHClientKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -27,31 +27,28 @@
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.security.AlgorithmConstraints;
-import java.security.CryptoPrimitive;
import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
+import java.security.spec.NamedParameterSpec;
import java.text.MessageFormat;
-import java.util.EnumSet;
import java.util.Locale;
import javax.crypto.SecretKey;
-import javax.net.ssl.SSLHandshakeException;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.X509Authentication.X509Credentials;
import sun.security.ssl.X509Authentication.X509Possession;
-import sun.security.util.ECUtil;
import sun.security.util.HexDumpEncoder;
/**
* Pack of the "ClientKeyExchange" handshake message.
+ *
+ * This file is used by both the ECDH/ECDHE/XDH code since much of the
+ * code is the same between the EC named groups (i.e.
+ * x25519/x448/secp*r1), even though the APIs are very different (i.e.
+ * ECPublicKey/XECPublicKey, KeyExchange.getInstance("EC"/"XDH"), etc.).
*/
final class ECDHClientKeyExchange {
static final SSLConsumer ecdhHandshakeConsumer =
@@ -65,19 +62,17 @@
new ECDHEClientKeyExchangeProducer();
/**
- * The ECDH/ECDHE ClientKeyExchange handshake message.
+ * The ECDH/ECDHE/XDH ClientKeyExchange handshake message.
*/
private static final
class ECDHClientKeyExchangeMessage extends HandshakeMessage {
private final byte[] encodedPoint;
ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
- ECPublicKey publicKey) {
+ byte[] encodedPublicKey) {
super(handshakeContext);
- ECPoint point = publicKey.getW();
- ECParameterSpec params = publicKey.getParams();
- encodedPoint = ECUtil.encodePoint(point, params.getCurve());
+ this.encodedPoint = encodedPublicKey;
}
ECDHClientKeyExchangeMessage(HandshakeContext handshakeContext,
@@ -90,34 +85,6 @@
}
}
- // Check constraints of the specified EC public key.
- static void checkConstraints(AlgorithmConstraints constraints,
- ECPublicKey publicKey,
- byte[] encodedPoint) throws SSLHandshakeException {
-
- try {
- ECParameterSpec params = publicKey.getParams();
- ECPoint point =
- ECUtil.decodePoint(encodedPoint, params.getCurve());
- ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
-
- KeyFactory kf = KeyFactory.getInstance("EC");
- ECPublicKey peerPublicKey =
- (ECPublicKey)kf.generatePublic(spec);
-
- // check constraints of ECPublicKey
- if (!constraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- peerPublicKey)) {
- throw new SSLHandshakeException(
- "ECPublicKey does not comply to algorithm constraints");
- }
- } catch (GeneralSecurityException | java.io.IOException e) {
- throw (SSLHandshakeException) new SSLHandshakeException(
- "Could not generate ECPublicKey").initCause(e);
- }
- }
-
@Override
public SSLHandshake handshakeType() {
return SSLHandshake.CLIENT_KEY_EXCHANGE;
@@ -194,24 +161,41 @@
}
PublicKey publicKey = x509Credentials.popPublicKey;
- if (!publicKey.getAlgorithm().equals("EC")) {
+
+ NamedGroup namedGroup = null;
+ String algorithm = publicKey.getAlgorithm();
+
+ // Determine which NamedGroup we'll be using, then use
+ // the creator functions.
+ if (algorithm.equals("EC")) {
+ ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
+ namedGroup = NamedGroup.valueOf(params);
+ } else if (algorithm.equals("XDH")) {
+ AlgorithmParameterSpec params =
+ ((XECPublicKey)publicKey).getParams();
+ if (params instanceof NamedParameterSpec) {
+ String name = ((NamedParameterSpec)params).getName();
+ namedGroup = NamedGroup.nameOf(name);
+ }
+ } else {
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Not EC server certificate for ECDH client key exchange");
+ "Not EC/XDH server certificate for " +
+ "ECDH client key exchange");
}
- ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
- NamedGroup namedGroup = NamedGroup.valueOf(params);
if (namedGroup == null) {
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Unsupported EC server cert for ECDH client key exchange");
+ "Unsupported EC/XDH server cert for " +
+ "ECDH client key exchange");
}
- ECDHEPossession ecdhePossession = new ECDHEPossession(
- namedGroup, chc.sslContext.getSecureRandom());
- chc.handshakePossessions.add(ecdhePossession);
+ SSLPossession sslPossession = namedGroup.createPossession(
+ chc.sslContext.getSecureRandom());
+
+ chc.handshakePossessions.add(sslPossession);
ECDHClientKeyExchangeMessage cke =
new ECDHClientKeyExchangeMessage(
- chc, ecdhePossession.publicKey);
+ chc, sslPossession.encode());
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Produced ECDH ClientKeyExchange handshake message", cke);
@@ -283,18 +267,35 @@
"No expected EC server cert for ECDH client key exchange");
}
- ECParameterSpec params = x509Possession.getECParameterSpec();
- if (params == null) {
+ // Determine which NamedGroup we'll be using, then use
+ // the creator functions.
+ NamedGroup namedGroup = null;
+
+ // Iteratively determine the X509Possession type's ParameterSpec.
+ ECParameterSpec ecParams = x509Possession.getECParameterSpec();
+ NamedParameterSpec namedParams = null;
+ if (ecParams != null) {
+ namedGroup = NamedGroup.valueOf(ecParams);
+ }
+
+ // Wasn't EC, try XEC.
+ if (ecParams == null) {
+ namedParams = x509Possession.getXECParameterSpec();
+ namedGroup = NamedGroup.nameOf(namedParams.getName());
+ }
+
+ // Can't figure this out, bail.
+ if ((ecParams == null) && (namedParams == null)) {
// unlikely, have been checked during cipher suite negotiation.
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Not EC server cert for ECDH client key exchange");
+ "Not EC/XDH server cert for ECDH client key exchange");
}
- NamedGroup namedGroup = NamedGroup.valueOf(params);
+ // unlikely, have been checked during cipher suite negotiation.
if (namedGroup == null) {
- // unlikely, have been checked during cipher suite negotiation.
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Unsupported EC server cert for ECDH client key exchange");
+ "Unknown named group in server cert for " +
+ "ECDH client key exchange");
}
SSLKeyExchange ke = SSLKeyExchange.valueOf(
@@ -306,7 +307,7 @@
"Not supported key exchange type");
}
- // parse the handshake message
+ // parse either handshake message containing either EC/XEC.
ECDHClientKeyExchangeMessage cke =
new ECDHClientKeyExchangeMessage(shc, message);
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -316,27 +317,17 @@
// create the credentials
try {
- ECPoint point =
- ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
- ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
-
- KeyFactory kf = KeyFactory.getInstance("EC");
- ECPublicKey peerPublicKey =
- (ECPublicKey)kf.generatePublic(spec);
+ NamedGroup ng = namedGroup; // "effectively final" the lambda
+ // AlgorithmConstraints are checked internally.
+ SSLCredentials sslCredentials = namedGroup.decodeCredentials(
+ cke.encodedPoint, shc.algorithmConstraints,
+ s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+ "ClientKeyExchange " + ng + ": " + s));
- // check constraints of peer ECPublicKey
- if (!shc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- peerPublicKey)) {
- throw new SSLHandshakeException(
- "ECPublicKey does not comply to algorithm constraints");
- }
-
- shc.handshakeCredentials.add(new ECDHECredentials(
- peerPublicKey, namedGroup));
- } catch (GeneralSecurityException | java.io.IOException e) {
- throw (SSLHandshakeException)(new SSLHandshakeException(
- "Could not generate ECPublicKey").initCause(e));
+ shc.handshakeCredentials.add(sslCredentials);
+ } catch (GeneralSecurityException e) {
+ throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+ "Cannot decode ECDH PublicKey: " + namedGroup);
}
// update the states
@@ -374,25 +365,37 @@
// The producing happens in client side only.
ClientHandshakeContext chc = (ClientHandshakeContext)context;
- ECDHECredentials ecdheCredentials = null;
+ SSLCredentials sslCredentials = null;
+ NamedGroup ng = null;
+ PublicKey publicKey = null;
+
+ // Find a good EC/XEC credential to use, determine the
+ // NamedGroup to use for creating Possessions/Credentials/Keys.
for (SSLCredentials cd : chc.handshakeCredentials) {
- if (cd instanceof ECDHECredentials) {
- ecdheCredentials = (ECDHECredentials)cd;
+ if (cd instanceof NamedGroupCredentials) {
+ NamedGroupCredentials creds = (NamedGroupCredentials)cd;
+ ng = creds.getNamedGroup();
+ publicKey = creds.getPublicKey();
+ sslCredentials = cd;
break;
}
}
- if (ecdheCredentials == null) {
+ if (sslCredentials == null) {
throw chc.conContext.fatal(Alert.INTERNAL_ERROR,
"No ECDHE credentials negotiated for client key exchange");
}
- ECDHEPossession ecdhePossession = new ECDHEPossession(
- ecdheCredentials, chc.sslContext.getSecureRandom());
- chc.handshakePossessions.add(ecdhePossession);
+ SSLPossession sslPossession = ng.createPossession(
+ chc.sslContext.getSecureRandom());
+
+ chc.handshakePossessions.add(sslPossession);
+
+ // Write the EC/XEC message.
ECDHClientKeyExchangeMessage cke =
new ECDHClientKeyExchangeMessage(
- chc, ecdhePossession.publicKey);
+ chc, sslPossession.encode());
+
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
"Produced ECDHE ClientKeyExchange handshake message", cke);
@@ -450,23 +453,29 @@
// The consuming happens in server side only.
ServerHandshakeContext shc = (ServerHandshakeContext)context;
- ECDHEPossession ecdhePossession = null;
+ SSLPossession sslPossession = null;
+ NamedGroup namedGroup = null;
+
+ // Find a good EC/XEC credential to use, determine the
+ // NamedGroup to use for creating Possessions/Credentials/Keys.
for (SSLPossession possession : shc.handshakePossessions) {
- if (possession instanceof ECDHEPossession) {
- ecdhePossession = (ECDHEPossession)possession;
+ if (possession instanceof NamedGroupPossession) {
+ NamedGroupPossession poss =
+ (NamedGroupPossession)possession;
+ namedGroup = poss.getNamedGroup();
+ sslPossession = poss;
break;
}
}
- if (ecdhePossession == null) {
+
+ if (sslPossession == null) {
// unlikely
throw shc.conContext.fatal(Alert.INTERNAL_ERROR,
"No expected ECDHE possessions for client key exchange");
}
- ECParameterSpec params = ecdhePossession.publicKey.getParams();
- NamedGroup namedGroup = NamedGroup.valueOf(params);
if (namedGroup == null) {
- // unlikely, have been checked during cipher suite negotiation.
+ // unlikely, have been checked during cipher suite negotiation
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
"Unsupported EC server cert for ECDHE client key exchange");
}
@@ -480,7 +489,7 @@
"Not supported key exchange type");
}
- // parse the handshake message
+ // parse the EC/XEC handshake message
ECDHClientKeyExchangeMessage cke =
new ECDHClientKeyExchangeMessage(shc, message);
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -490,27 +499,17 @@
// create the credentials
try {
- ECPoint point =
- ECUtil.decodePoint(cke.encodedPoint, params.getCurve());
- ECPublicKeySpec spec = new ECPublicKeySpec(point, params);
-
- KeyFactory kf = KeyFactory.getInstance("EC");
- ECPublicKey peerPublicKey =
- (ECPublicKey)kf.generatePublic(spec);
+ NamedGroup ng = namedGroup; // "effectively final" the lambda
+ // AlgorithmConstraints are checked internally.
+ SSLCredentials sslCredentials = namedGroup.decodeCredentials(
+ cke.encodedPoint, shc.algorithmConstraints,
+ s -> shc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+ "ClientKeyExchange " + ng + ": " + s));
- // check constraints of peer ECPublicKey
- if (!shc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- peerPublicKey)) {
- throw new SSLHandshakeException(
- "ECPublicKey does not comply to algorithm constraints");
- }
-
- shc.handshakeCredentials.add(new ECDHECredentials(
- peerPublicKey, namedGroup));
- } catch (GeneralSecurityException | java.io.IOException e) {
- throw (SSLHandshakeException)(new SSLHandshakeException(
- "Could not generate ECPublicKey").initCause(e));
+ shc.handshakeCredentials.add(sslCredentials);
+ } catch (GeneralSecurityException e) {
+ throw shc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+ "Cannot decode named group: " + namedGroup);
}
// update the states
--- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -36,7 +36,6 @@
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.ECPublicKey;
-import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
@@ -44,25 +43,30 @@
import java.util.EnumSet;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLHandshakeException;
-import sun.security.ssl.CipherSuite.HashAlg;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.ssl.X509Authentication.X509Credentials;
import sun.security.ssl.X509Authentication.X509Possession;
+import sun.security.ssl.XDHKeyExchange.XDHECredentials;
+import sun.security.ssl.XDHKeyExchange.XDHEPossession;
import sun.security.util.ECUtil;
final class ECDHKeyExchange {
static final SSLPossessionGenerator poGenerator =
new ECDHEPossessionGenerator();
- static final SSLKeyAgreementGenerator ecdheKAGenerator =
- new ECDHEKAGenerator();
static final SSLKeyAgreementGenerator ecdhKAGenerator =
new ECDHKAGenerator();
- static final class ECDHECredentials implements SSLCredentials {
+ // TLSv1.3
+ static final SSLKeyAgreementGenerator ecdheKAGenerator =
+ new ECDHEKAGenerator();
+
+ // TLSv1-1.2, the KA gets more difficult with EC/XEC keys
+ static final SSLKeyAgreementGenerator ecdheXdhKAGenerator =
+ new ECDHEXDHKAGenerator();
+
+ static final class ECDHECredentials implements NamedGroupCredentials {
final ECPublicKey popPublicKey;
final NamedGroup namedGroup;
@@ -71,6 +75,16 @@
this.namedGroup = namedGroup;
}
+ @Override
+ public PublicKey getPublicKey() {
+ return popPublicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
static ECDHECredentials valueOf(NamedGroup namedGroup,
byte[] encodedPoint) throws IOException, GeneralSecurityException {
@@ -98,7 +112,7 @@
}
}
- static final class ECDHEPossession implements SSLPossession {
+ static final class ECDHEPossession implements NamedGroupPossession {
final PrivateKey privateKey;
final ECPublicKey publicKey;
final NamedGroup namedGroup;
@@ -199,6 +213,21 @@
"Could not generate ECPublicKey").initCause(e);
}
}
+
+ @Override
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
+ @Override
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
}
private static final
@@ -210,24 +239,31 @@
@Override
public SSLPossession createPossession(HandshakeContext context) {
- NamedGroup preferableNamedGroup = null;
+
+ NamedGroup preferableNamedGroup;
+
+ // Find most preferred EC or XEC groups
if ((context.clientRequestedNamedGroups != null) &&
(!context.clientRequestedNamedGroups.isEmpty())) {
preferableNamedGroup = SupportedGroups.getPreferredGroup(
context.negotiatedProtocol,
context.algorithmConstraints,
- NamedGroupType.NAMED_GROUP_ECDHE,
+ new NamedGroupType[] {
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ NamedGroupType.NAMED_GROUP_XDH },
context.clientRequestedNamedGroups);
} else {
preferableNamedGroup = SupportedGroups.getPreferredGroup(
context.negotiatedProtocol,
context.algorithmConstraints,
- NamedGroupType.NAMED_GROUP_ECDHE);
+ new NamedGroupType[] {
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ NamedGroupType.NAMED_GROUP_XDH });
}
if (preferableNamedGroup != null) {
- return new ECDHEPossession(preferableNamedGroup,
- context.sslContext.getSecureRandom());
+ return preferableNamedGroup.createPossession(
+ context.sslContext.getSecureRandom());
}
// no match found, cannot use this cipher suite.
@@ -298,7 +334,7 @@
"No sufficient ECDHE key agreement parameters negotiated");
}
- return new ECDHEKAKeyDerivation(shc,
+ return new KAKeyDerivation("ECDH", shc,
x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
}
@@ -347,7 +383,7 @@
"No sufficient ECDH key agreement parameters negotiated");
}
- return new ECDHEKAKeyDerivation(chc,
+ return new KAKeyDerivation("ECDH", chc,
ecdhePossession.privateKey, x509Credentials.popPublicKey);
}
}
@@ -391,94 +427,73 @@
"No sufficient ECDHE key agreement parameters negotiated");
}
- return new ECDHEKAKeyDerivation(context,
+ return new KAKeyDerivation("ECDH", context,
ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
}
}
+ /*
+ * A Generator for TLSv1-1.2 to create a ECDHE or a XDH KeyDerivation
+ * object depending on the negotiated group.
+ */
private static final
- class ECDHEKAKeyDerivation implements SSLKeyDerivation {
- private final HandshakeContext context;
- private final PrivateKey localPrivateKey;
- private final PublicKey peerPublicKey;
-
- ECDHEKAKeyDerivation(HandshakeContext context,
- PrivateKey localPrivateKey,
- PublicKey peerPublicKey) {
- this.context = context;
- this.localPrivateKey = localPrivateKey;
- this.peerPublicKey = peerPublicKey;
+ class ECDHEXDHKAGenerator implements SSLKeyAgreementGenerator {
+ // Prevent instantiation of this class.
+ private ECDHEXDHKAGenerator() {
+ // blank
}
@Override
- public SecretKey deriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
- return t12DeriveKey(algorithm, params);
- } else {
- return t13DeriveKey(algorithm, params);
- }
- }
+ public SSLKeyDerivation createKeyDerivation(
+ HandshakeContext context) throws IOException {
+
+ NamedGroupPossession namedGroupPossession = null;
+ NamedGroupCredentials namedGroupCredentials = null;
+ NamedGroup namedGroup = null;
- private SecretKey t12DeriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- try {
- KeyAgreement ka = KeyAgreement.getInstance("ECDH");
- ka.init(localPrivateKey);
- ka.doPhase(peerPublicKey, true);
- SecretKey preMasterSecret =
- ka.generateSecret("TlsPremasterSecret");
-
- SSLMasterKeyDerivation mskd =
- SSLMasterKeyDerivation.valueOf(
- context.negotiatedProtocol);
- if (mskd == null) {
- // unlikely
- throw new SSLHandshakeException(
- "No expected master key derivation for protocol: " +
- context.negotiatedProtocol.name);
+ // Find a possession/credential combo using the same named group
+ search:
+ for (SSLPossession poss : context.handshakePossessions) {
+ for (SSLCredentials cred : context.handshakeCredentials) {
+ if (((poss instanceof ECDHEPossession) &&
+ (cred instanceof ECDHECredentials)) ||
+ (((poss instanceof XDHEPossession) &&
+ (cred instanceof XDHECredentials)))) {
+ NamedGroupPossession p = (NamedGroupPossession)poss;
+ NamedGroupCredentials c = (NamedGroupCredentials)cred;
+ if (p.getNamedGroup() != c.getNamedGroup()) {
+ continue;
+ } else {
+ namedGroup = p.getNamedGroup();
+ }
+ namedGroupPossession = p;
+ namedGroupCredentials = c;
+ break search;
+ }
}
- SSLKeyDerivation kd = mskd.createKeyDerivation(
- context, preMasterSecret);
- return kd.deriveKey("MasterSecret", params);
- } catch (GeneralSecurityException gse) {
- throw (SSLHandshakeException) new SSLHandshakeException(
- "Could not generate secret").initCause(gse);
}
- }
- private SecretKey t13DeriveKey(String algorithm,
- AlgorithmParameterSpec params) throws IOException {
- try {
- KeyAgreement ka = KeyAgreement.getInstance("ECDH");
- ka.init(localPrivateKey);
- ka.doPhase(peerPublicKey, true);
- SecretKey sharedSecret =
- ka.generateSecret("TlsPremasterSecret");
+ if (namedGroupPossession == null || namedGroupCredentials == null) {
+ throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+ "No sufficient ECDHE/XDH key agreement " +
+ "parameters negotiated");
+ }
- HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
- SSLKeyDerivation kd = context.handshakeKeyDerivation;
- HKDF hkdf = new HKDF(hashAlg.name);
- if (kd == null) { // No PSK is in use.
- // If PSK is not in use Early Secret will still be
- // HKDF-Extract(0, 0).
- byte[] zeros = new byte[hashAlg.hashLength];
- SecretKeySpec ikm =
- new SecretKeySpec(zeros, "TlsPreSharedSecret");
- SecretKey earlySecret =
- hkdf.extract(zeros, ikm, "TlsEarlySecret");
- kd = new SSLSecretDerivation(context, earlySecret);
- }
+ String alg;
+ switch (namedGroup.type) {
+ case NAMED_GROUP_ECDHE:
+ alg = "ECDH";
+ break;
+ case NAMED_GROUP_XDH:
+ alg = "XDH";
+ break;
+ default:
+ throw new RuntimeException("Unexpected named group type");
+ }
- // derive salt secret
- SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
- // derive handshake secret
- return hkdf.extract(saltSecret, sharedSecret, algorithm);
- } catch (GeneralSecurityException gse) {
- throw (SSLHandshakeException) new SSLHandshakeException(
- "Could not generate secret").initCause(gse);
- }
+ return new KAKeyDerivation(alg, context,
+ namedGroupPossession.getPrivateKey(),
+ namedGroupCredentials.getPublicKey());
}
}
}
--- a/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHServerKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -27,32 +27,21 @@
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
-import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
import java.text.MessageFormat;
-import java.util.EnumSet;
import java.util.Locale;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.ssl.X509Authentication.X509Credentials;
import sun.security.ssl.X509Authentication.X509Possession;
-import sun.security.util.ECUtil;
import sun.security.util.HexDumpEncoder;
/**
@@ -80,14 +69,14 @@
// signature bytes, or null if anonymous
private final byte[] paramsSignature;
- // public key object encapsulated in this message
- private final ECPublicKey publicKey;
-
private final boolean useExplicitSigAlgorithm;
// the signature algorithm used by this ServerKeyExchange message
private final SignatureScheme signatureScheme;
+ // the parsed credential object
+ private SSLCredentials sslCredentials;
+
ECDHServerKeyExchangeMessage(
HandshakeContext handshakeContext) throws IOException {
super(handshakeContext);
@@ -96,38 +85,38 @@
ServerHandshakeContext shc =
(ServerHandshakeContext)handshakeContext;
- ECDHEPossession ecdhePossession = null;
+ // Find the Possessions needed
+ NamedGroupPossession namedGroupPossession = null;
X509Possession x509Possession = null;
for (SSLPossession possession : shc.handshakePossessions) {
- if (possession instanceof ECDHEPossession) {
- ecdhePossession = (ECDHEPossession)possession;
+ if (possession instanceof NamedGroupPossession) {
+ namedGroupPossession = (NamedGroupPossession)possession;
if (x509Possession != null) {
break;
}
} else if (possession instanceof X509Possession) {
x509Possession = (X509Possession)possession;
- if (ecdhePossession != null) {
+ if (namedGroupPossession != null) {
break;
}
}
}
- if (ecdhePossession == null) {
+ if (namedGroupPossession == null) {
// unlikely
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
"No ECDHE credentials negotiated for server key exchange");
}
- publicKey = ecdhePossession.publicKey;
- ECParameterSpec params = publicKey.getParams();
- ECPoint point = publicKey.getW();
- publicPoint = ECUtil.encodePoint(point, params.getCurve());
+ // Find the NamedGroup used for the ephemeral keys.
+ namedGroup = namedGroupPossession.getNamedGroup();
+ publicPoint = namedGroup.encodePossessionPublicKey(
+ namedGroupPossession);
- this.namedGroup = NamedGroup.valueOf(params);
if ((namedGroup == null) || (namedGroup.oid == null) ) {
// unlikely
throw shc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Unnamed EC parameter spec: " + params);
+ "Missing Named Group");
}
if (x509Possession == null) {
@@ -216,39 +205,23 @@
"Unsupported named group: " + namedGroup);
}
- if (namedGroup.oid == null) {
- throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Unknown named EC curve: " + namedGroup);
- }
-
- ECParameterSpec parameters =
- ECUtil.getECParameterSpec(null, namedGroup.oid);
- if (parameters == null) {
- throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "No supported EC parameter: " + namedGroup);
- }
-
publicPoint = Record.getBytes8(m);
if (publicPoint.length == 0) {
throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Insufficient ECPoint data: " + namedGroup);
+ "Insufficient Point data: " + namedGroup);
}
- ECPublicKey ecPublicKey = null;
try {
- ECPoint point =
- ECUtil.decodePoint(publicPoint, parameters.getCurve());
- KeyFactory factory = KeyFactory.getInstance("EC");
- ecPublicKey = (ECPublicKey)factory.generatePublic(
- new ECPublicKeySpec(point, parameters));
- } catch (NoSuchAlgorithmException |
- InvalidKeySpecException | IOException ex) {
- throw chc.conContext.fatal(Alert.ILLEGAL_PARAMETER,
- "Invalid ECPoint: " + namedGroup, ex);
+ sslCredentials = namedGroup.decodeCredentials(
+ publicPoint, handshakeContext.algorithmConstraints,
+ s -> chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
+ "ServerKeyExchange " + namedGroup + ": " + (s)));
+ } catch (GeneralSecurityException ex) {
+ throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+ "Cannot decode named group: " +
+ NamedGroup.nameOf(namedGroupId));
}
- publicKey = ecPublicKey;
-
X509Credentials x509Credentials = null;
for (SSLCredentials cd : chc.handshakeCredentials) {
if (cd instanceof X509Credentials) {
@@ -529,6 +502,7 @@
// The consuming happens in client side only.
ClientHandshakeContext chc = (ClientHandshakeContext)context;
+ // AlgorithmConstraints are checked during decoding
ECDHServerKeyExchangeMessage skem =
new ECDHServerKeyExchangeMessage(chc, message);
if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
@@ -537,22 +511,9 @@
}
//
- // validate
- //
- // check constraints of EC PublicKey
- if (!chc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- skem.publicKey)) {
- throw chc.conContext.fatal(Alert.INSUFFICIENT_SECURITY,
- "ECDH ServerKeyExchange does not comply " +
- "to algorithm constraints");
- }
-
- //
// update
//
- chc.handshakeCredentials.add(
- new ECDHECredentials(skem.publicKey, skem.namedGroup));
+ chc.handshakeCredentials.add(skem.sslCredentials);
//
// produce
--- a/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/ECPointFormatsExtension.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -34,7 +34,7 @@
import sun.security.ssl.SSLExtension.ExtensionConsumer;
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
/**
* Pack of the "ec_point_formats" extensions [RFC 4492].
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java Wed Jun 12 18:58:00 2019 -0700
@@ -46,9 +46,8 @@
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLHandshakeException;
import javax.security.auth.x500.X500Principal;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
-import static sun.security.ssl.SupportedGroupsExtension.NamedGroupType.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import static sun.security.ssl.NamedGroup.NamedGroupType.*;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
abstract class HandshakeContext implements ConnectionContext {
@@ -519,31 +518,38 @@
return true;
}
- boolean available;
- NamedGroupType groupType = suite.keyExchange.groupType;
- if (groupType != NAMED_GROUP_NONE) {
- Boolean checkedStatus = cachedStatus.get(groupType);
- if (checkedStatus == null) {
- available = SupportedGroups.isActivatable(
- algorithmConstraints, groupType);
- cachedStatus.put(groupType, available);
+ // Is at least one of the group types available?
+ boolean groupAvailable, retval = false;
+ NamedGroupType[] groupTypes = suite.keyExchange.groupTypes;
+ for (NamedGroupType groupType : groupTypes) {
+ if (groupType != NAMED_GROUP_NONE) {
+ Boolean checkedStatus = cachedStatus.get(groupType);
+ if (checkedStatus == null) {
+ groupAvailable = SupportedGroups.isActivatable(
+ algorithmConstraints, groupType);
+ cachedStatus.put(groupType, groupAvailable);
- if (!available &&
- SSLLogger.isOn && SSLLogger.isOn("verbose")) {
- SSLLogger.fine("No activated named group");
+ if (!groupAvailable &&
+ SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+ SSLLogger.fine(
+ "No activated named group in " + groupType);
+ }
+ } else {
+ groupAvailable = checkedStatus;
}
+
+ retval |= groupAvailable;
} else {
- available = checkedStatus;
+ retval |= true;
}
+ }
- if (!available && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
- SSLLogger.fine(
- "No active named group, ignore " + suite);
- }
- return available;
- } else {
- return true;
+ if (!retval && SSLLogger.isOn && SSLLogger.isOn("verbose")) {
+ SSLLogger.fine("No active named group(s), ignore " + suite);
}
+
+ return retval;
+
} else if (SSLLogger.isOn && SSLLogger.isOn("verbose")) {
SSLLogger.fine("Ignore disabled cipher suite: " + suite);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package sun.security.ssl;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+/**
+ * A common class for creating various KeyDerivation types.
+ */
+public class KAKeyDerivation implements SSLKeyDerivation {
+
+ private final String algorithmName;
+ private final HandshakeContext context;
+ private final PrivateKey localPrivateKey;
+ private final PublicKey peerPublicKey;
+
+ KAKeyDerivation(String algorithmName,
+ HandshakeContext context,
+ PrivateKey localPrivateKey,
+ PublicKey peerPublicKey) {
+ this.algorithmName = algorithmName;
+ this.context = context;
+ this.localPrivateKey = localPrivateKey;
+ this.peerPublicKey = peerPublicKey;
+ }
+
+ @Override
+ public SecretKey deriveKey(String algorithm,
+ AlgorithmParameterSpec params) throws IOException {
+ if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
+ return t12DeriveKey(algorithm, params);
+ } else {
+ return t13DeriveKey(algorithm, params);
+ }
+ }
+
+ /**
+ * Handle the TLSv1-1.2 objects, which don't use the HKDF algorithms.
+ */
+ private SecretKey t12DeriveKey(String algorithm,
+ AlgorithmParameterSpec params) throws IOException {
+ try {
+ KeyAgreement ka = KeyAgreement.getInstance(algorithmName);
+ ka.init(localPrivateKey);
+ ka.doPhase(peerPublicKey, true);
+ SecretKey preMasterSecret
+ = ka.generateSecret("TlsPremasterSecret");
+ SSLMasterKeyDerivation mskd
+ = SSLMasterKeyDerivation.valueOf(
+ context.negotiatedProtocol);
+ if (mskd == null) {
+ // unlikely
+ throw new SSLHandshakeException(
+ "No expected master key derivation for protocol: "
+ + context.negotiatedProtocol.name);
+ }
+ SSLKeyDerivation kd = mskd.createKeyDerivation(
+ context, preMasterSecret);
+ return kd.deriveKey("MasterSecret", params);
+ } catch (GeneralSecurityException gse) {
+ throw (SSLHandshakeException) new SSLHandshakeException(
+ "Could not generate secret").initCause(gse);
+ }
+ }
+
+ /**
+ * Handle the TLSv1.3 objects, which use the HKDF algorithms.
+ */
+ private SecretKey t13DeriveKey(String algorithm,
+ AlgorithmParameterSpec params) throws IOException {
+ try {
+ KeyAgreement ka = KeyAgreement.getInstance(algorithmName);
+ ka.init(localPrivateKey);
+ ka.doPhase(peerPublicKey, true);
+ SecretKey sharedSecret
+ = ka.generateSecret("TlsPremasterSecret");
+
+ CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
+ SSLKeyDerivation kd = context.handshakeKeyDerivation;
+ HKDF hkdf = new HKDF(hashAlg.name);
+ if (kd == null) { // No PSK is in use.
+ // If PSK is not in use Early Secret will still be
+ // HKDF-Extract(0, 0).
+ byte[] zeros = new byte[hashAlg.hashLength];
+ SecretKeySpec ikm
+ = new SecretKeySpec(zeros, "TlsPreSharedSecret");
+ SecretKey earlySecret
+ = hkdf.extract(zeros, ikm, "TlsEarlySecret");
+ kd = new SSLSecretDerivation(context, earlySecret);
+ }
+
+ // derive salt secret
+ SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
+
+ // derive handshake secret
+ return hkdf.extract(saltSecret, sharedSecret, algorithm);
+ } catch (GeneralSecurityException gse) {
+ throw (SSLHandshakeException) new SSLHandshakeException(
+ "Could not generate secret").initCause(gse);
+ }
+ }
+}
--- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -27,27 +27,19 @@
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.security.CryptoPrimitive;
import java.security.GeneralSecurityException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.Collections;
-import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.net.ssl.SSLProtocolException;
-import sun.security.ssl.DHKeyExchange.DHECredentials;
-import sun.security.ssl.DHKeyExchange.DHEPossession;
-import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
import sun.security.ssl.KeyShareExtension.CHKeyShareSpec;
import sun.security.ssl.SSLExtension.ExtensionConsumer;
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.util.HexDumpEncoder;
@@ -264,8 +256,7 @@
for (SSLPossession pos : poses) {
// update the context
chc.handshakePossessions.add(pos);
- if (!(pos instanceof ECDHEPossession) &&
- !(pos instanceof DHEPossession)) {
+ if (!(pos instanceof NamedGroupPossession)) {
// May need more possesion types in the future.
continue;
}
@@ -353,46 +344,18 @@
continue;
}
- if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- try {
- ECDHECredentials ecdhec =
- ECDHECredentials.valueOf(ng, entry.keyExchange);
- if (ecdhec != null) {
- if (!shc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- ecdhec.popPublicKey)) {
- SSLLogger.warning(
- "ECDHE key share entry does not " +
- "comply to algorithm constraints");
- } else {
- credentials.add(ecdhec);
- }
- }
- } catch (IOException | GeneralSecurityException ex) {
- SSLLogger.warning(
- "Cannot decode named group: " +
- NamedGroup.nameOf(entry.namedGroupId));
+ try {
+ SSLCredentials kaCred =
+ ng.decodeCredentials(entry.keyExchange,
+ shc.algorithmConstraints,
+ s -> SSLLogger.warning(s));
+ if (kaCred != null) {
+ credentials.add(kaCred);
}
- } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- try {
- DHECredentials dhec =
- DHECredentials.valueOf(ng, entry.keyExchange);
- if (dhec != null) {
- if (!shc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- dhec.popPublicKey)) {
- SSLLogger.warning(
- "DHE key share entry does not " +
- "comply to algorithm constraints");
- } else {
- credentials.add(dhec);
- }
- }
- } catch (IOException | GeneralSecurityException ex) {
- SSLLogger.warning(
- "Cannot decode named group: " +
- NamedGroup.nameOf(entry.namedGroupId));
- }
+ } catch (GeneralSecurityException ex) {
+ SSLLogger.warning(
+ "Cannot decode named group: " +
+ NamedGroup.nameOf(entry.namedGroupId));
}
}
@@ -526,10 +489,9 @@
KeyShareEntry keyShare = null;
for (SSLCredentials cd : shc.handshakeCredentials) {
NamedGroup ng = null;
- if (cd instanceof ECDHECredentials) {
- ng = ((ECDHECredentials)cd).namedGroup;
- } else if (cd instanceof DHECredentials) {
- ng = ((DHECredentials)cd).namedGroup;
+ if (cd instanceof NamedGroupCredentials) {
+ NamedGroupCredentials creds = (NamedGroupCredentials)cd;
+ ng = creds.getNamedGroup();
}
if (ng == null) {
@@ -547,8 +509,7 @@
SSLPossession[] poses = ke.createPossessions(shc);
for (SSLPossession pos : poses) {
- if (!(pos instanceof ECDHEPossession) &&
- !(pos instanceof DHEPossession)) {
+ if (!(pos instanceof NamedGroupPossession)) {
// May need more possesion types in the future.
continue;
}
@@ -567,7 +528,7 @@
me.getKey(), me.getValue());
}
- // We have got one! Don't forgor to break.
+ // We have got one! Don't forget to break.
break;
}
}
@@ -643,49 +604,16 @@
}
SSLCredentials credentials = null;
- if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- try {
- ECDHECredentials ecdhec =
- ECDHECredentials.valueOf(ng, keyShare.keyExchange);
- if (ecdhec != null) {
- if (!chc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- ecdhec.popPublicKey)) {
- throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
- "ECDHE key share entry does not " +
- "comply to algorithm constraints");
- } else {
- credentials = ecdhec;
- }
- }
- } catch (IOException | GeneralSecurityException ex) {
- throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
- "Cannot decode named group: " +
- NamedGroup.nameOf(keyShare.namedGroupId));
+ try {
+ SSLCredentials kaCred = ng.decodeCredentials(
+ keyShare.keyExchange, chc.algorithmConstraints,
+ s -> chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, s));
+ if (kaCred != null) {
+ credentials = kaCred;
}
- } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- try {
- DHECredentials dhec =
- DHECredentials.valueOf(ng, keyShare.keyExchange);
- if (dhec != null) {
- if (!chc.algorithmConstraints.permits(
- EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- dhec.popPublicKey)) {
- throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
- "DHE key share entry does not " +
- "comply to algorithm constraints");
- } else {
- credentials = dhec;
- }
- }
- } catch (IOException | GeneralSecurityException ex) {
- throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
- "Cannot decode named group: " +
- NamedGroup.nameOf(keyShare.namedGroupId));
- }
- } else {
+ } catch (GeneralSecurityException ex) {
throw chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
- "Unsupported named group: " +
+ "Cannot decode named group: " +
NamedGroup.nameOf(keyShare.namedGroupId));
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package sun.security.ssl;
+
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.SSLException;
+import java.io.IOException;
+import java.security.*;
+import java.security.spec.*;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.crypto.*;
+import sun.security.ssl.DHKeyExchange.DHEPossession;
+import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+
+import sun.security.util.ECUtil;
+
+/**
+ * An enum containing all known named groups for use in TLS.
+ *
+ * The enum also contains the required properties of each group and the
+ * required functions (e.g. encoding/decoding).
+ */
+enum NamedGroup {
+ // Elliptic Curves (RFC 4492)
+ //
+ // See sun.security.util.CurveDB for the OIDs
+ // NIST K-163
+
+ SECT163_K1(0x0001, "sect163k1", "1.3.132.0.1",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECT163_R1(0x0002, "sect163r1", "1.3.132.0.2",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST B-163
+ SECT163_R2(0x0003, "sect163r2", "1.3.132.0.15",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECT193_R1(0x0004, "sect193r1", "1.3.132.0.24",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECT193_R2(0x0005, "sect193r2", "1.3.132.0.25",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST K-233
+ SECT233_K1(0x0006, "sect233k1", "1.3.132.0.26",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST B-233
+ SECT233_R1(0x0007, "sect233r1", "1.3.132.0.27",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECT239_K1(0x0008, "sect239k1", "1.3.132.0.3",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST K-283
+ SECT283_K1(0x0009, "sect283k1", "1.3.132.0.16",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST B-283
+ SECT283_R1(0x000A, "sect283r1", "1.3.132.0.17",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST K-409
+ SECT409_K1(0x000B, "sect409k1", "1.3.132.0.36",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST B-409
+ SECT409_R1(0x000C, "sect409r1", "1.3.132.0.37",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST K-571
+ SECT571_K1(0x000D, "sect571k1", "1.3.132.0.38",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST B-571
+ SECT571_R1(0x000E, "sect571r1", "1.3.132.0.39",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP160_K1(0x000F, "secp160k1", "1.3.132.0.9",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP160_R1(0x0010, "secp160r1", "1.3.132.0.8",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP160_R2(0x0011, "secp160r2", "1.3.132.0.30",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP192_K1(0x0012, "secp192k1", "1.3.132.0.31",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST P-192
+ SECP192_R1(0x0013, "secp192r1", "1.2.840.10045.3.1.1",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP224_K1(0x0014, "secp224k1", "1.3.132.0.32",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST P-224
+ SECP224_R1(0x0015, "secp224r1", "1.3.132.0.33",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ SECP256_K1(0x0016, "secp256k1", "1.3.132.0.10",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_12),
+
+ // NIST P-256
+ SECP256_R1(0x0017, "secp256r1", "1.2.840.10045.3.1.7",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+
+ // NIST P-384
+ SECP384_R1(0x0018, "secp384r1", "1.3.132.0.34",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+
+ // NIST P-521
+ SECP521_R1(0x0019, "secp521r1", "1.3.132.0.35",
+ NamedGroupType.NAMED_GROUP_ECDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+
+ // x25519 and x448 (RFC 8422/8446)
+ X25519(0x001D, "x25519", "1.3.101.110",
+ NamedGroupType.NAMED_GROUP_XDH,
+ ProtocolVersion.PROTOCOLS_TO_13),
+ X448(0x001E, "x448", "1.3.101.111",
+ NamedGroupType.NAMED_GROUP_XDH,
+ ProtocolVersion.PROTOCOLS_TO_13),
+
+ // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
+ FFDHE_2048(0x0100, "ffdhe2048", null,
+ NamedGroupType.NAMED_GROUP_FFDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+ FFDHE_3072(0x0101, "ffdhe3072", null,
+ NamedGroupType.NAMED_GROUP_FFDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+ FFDHE_4096(0x0102, "ffdhe4096", null,
+ NamedGroupType.NAMED_GROUP_FFDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+ FFDHE_6144(0x0103, "ffdhe6144", null,
+ NamedGroupType.NAMED_GROUP_FFDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+ FFDHE_8192(0x0104, "ffdhe8192", null,
+ NamedGroupType.NAMED_GROUP_FFDHE,
+ ProtocolVersion.PROTOCOLS_TO_13),
+
+ // Elliptic Curves (RFC 4492)
+ //
+ // arbitrary prime and characteristic-2 curves
+ ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", null,
+ NamedGroupType.NAMED_GROUP_ARBITRARY,
+ ProtocolVersion.PROTOCOLS_TO_12),
+ ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", null,
+ NamedGroupType.NAMED_GROUP_ARBITRARY,
+ ProtocolVersion.PROTOCOLS_TO_12);
+
+ final int id; // hash + signature
+ final NamedGroupType type; // group type
+ final String name; // literal name
+ final String oid; // object identifier of the named group
+ final String algorithm; // signature algorithm
+ final ProtocolVersion[] supportedProtocols;
+ private final NamedGroupFunctions functions; // may be null
+
+ // Constructor used for all NamedGroup types
+ private NamedGroup(int id, String name, String oid,
+ NamedGroupType namedGroupType,
+ ProtocolVersion[] supportedProtocols) {
+ this.id = id;
+ this.name = name;
+ this.oid = oid;
+ this.type = namedGroupType;
+ this.supportedProtocols = supportedProtocols;
+
+ if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+ this.functions = ECDHFunctions.getInstance();
+ this.algorithm = "EC";
+ } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
+ this.functions = FFDHFunctions.getInstance();
+ this.algorithm = "DiffieHellman";
+ } else if (this.type == NamedGroupType.NAMED_GROUP_XDH) {
+ this.functions = XDHFunctions.getInstance();
+ this.algorithm = "XDH";
+ } else if (this.type == NamedGroupType.NAMED_GROUP_ARBITRARY) {
+ this.functions = null;
+ this.algorithm = "EC";
+ } else {
+ throw new RuntimeException("Unexpected Named Group Type");
+ }
+ }
+
+ private Optional<NamedGroupFunctions> getFunctions() {
+ return Optional.ofNullable(functions);
+ }
+
+ // The next set of methods search & retrieve NamedGroups.
+
+ static NamedGroup valueOf(int id) {
+ for (NamedGroup group : NamedGroup.values()) {
+ if (group.id == id) {
+ return group;
+ }
+ }
+
+ return null;
+ }
+
+ static NamedGroup valueOf(ECParameterSpec params) {
+ String oid = ECUtil.getCurveName(null, params);
+ if ((oid != null) && (!oid.isEmpty())) {
+ for (NamedGroup group : NamedGroup.values()) {
+ if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE)
+ && oid.equals(group.oid)) {
+ return group;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ static NamedGroup valueOf(DHParameterSpec params) {
+ for (NamedGroup ng : NamedGroup.values()) {
+ if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
+ continue;
+ }
+
+ DHParameterSpec ngParams = null;
+ // functions is non-null for FFDHE type
+ AlgorithmParameters aps = ng.functions.getParameters(ng);
+ try {
+ ngParams = aps.getParameterSpec(DHParameterSpec.class);
+ } catch (InvalidParameterSpecException ipse) {
+ // should be unlikely
+ }
+
+ if (ngParams == null) {
+ continue;
+ }
+
+ if (ngParams.getP().equals(params.getP())
+ && ngParams.getG().equals(params.getG())) {
+ return ng;
+ }
+ }
+
+ return null;
+ }
+
+ static NamedGroup nameOf(String name) {
+ for (NamedGroup group : NamedGroup.values()) {
+ if (group.name.equals(name)) {
+ return group;
+ }
+ }
+
+ return null;
+ }
+
+ static String nameOf(int id) {
+ for (NamedGroup group : NamedGroup.values()) {
+ if (group.id == id) {
+ return group.name;
+ }
+ }
+
+ return "UNDEFINED-NAMED-GROUP(" + id + ")";
+ }
+
+ // Are the NamedGroups available for the protocol desired?
+
+ boolean isAvailable(List<ProtocolVersion> protocolVersions) {
+ for (ProtocolVersion pv : supportedProtocols) {
+ if (protocolVersions.contains(pv)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ boolean isAvailable(ProtocolVersion protocolVersion) {
+ for (ProtocolVersion pv : supportedProtocols) {
+ if (protocolVersion == pv) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Are the NamedGroups available for the ciphersuites desired?
+
+ boolean isSupported(List<CipherSuite> cipherSuites) {
+ for (CipherSuite cs : cipherSuites) {
+ boolean isMatch = isAvailable(cs.supportedProtocols);
+ if (isMatch && ((cs.keyExchange == null)
+ || (NamedGroupType.arrayContains(
+ cs.keyExchange.groupTypes, type)))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // lazy loading of parameters
+ AlgorithmParameters getParameters() {
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().getParameters(this);
+ }
+
+ // The next set of methods use the NamedGroupFunctions table
+ // to do various operations in a consistent way.
+
+ AlgorithmParameterSpec getParameterSpec() {
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().getParameterSpec(this);
+ }
+
+ byte[] encodePossessionPublicKey(
+ NamedGroupPossession namedGroupPossession) {
+
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().encodePossessionPublicKey(namedGroupPossession);
+ }
+
+ SSLCredentials decodeCredentials(byte[] encoded,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws IOException, GeneralSecurityException {
+
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().decodeCredentials(this, encoded, constraints,
+ onConstraintFail);
+ }
+
+ SSLPossession createPossession(SecureRandom random) {
+
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().createPossession(this, random);
+ }
+
+ SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+ throws IOException {
+
+ Optional<NamedGroupFunctions> ngf = getFunctions();
+ if (ngf.isEmpty()) {
+ return null;
+ }
+ return ngf.get().createKeyDerivation(hc);
+
+ }
+
+ boolean isAvailableGroup() {
+ Optional<NamedGroupFunctions> ngfOpt = getFunctions();
+ if (ngfOpt.isEmpty()) {
+ return false;
+ }
+ NamedGroupFunctions ngf = ngfOpt.get();
+ return ngf.isAvailable(this);
+ }
+
+ enum NamedGroupType {
+ NAMED_GROUP_ECDHE, // Elliptic Curve Groups (ECDHE)
+ NAMED_GROUP_FFDHE, // Finite Field Groups (DHE)
+ NAMED_GROUP_XDH, // Finite Field Groups (XDH)
+ NAMED_GROUP_ARBITRARY, // arbitrary prime and curves (ECDHE)
+ NAMED_GROUP_NONE; // Not predefined named group
+
+ boolean isSupported(List<CipherSuite> cipherSuites) {
+ for (CipherSuite cs : cipherSuites) {
+ if (cs.keyExchange == null ||
+ arrayContains(cs.keyExchange.groupTypes, this)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static boolean arrayContains(NamedGroupType[] namedGroupTypes,
+ NamedGroupType namedGroupType) {
+ for (NamedGroupType ng : namedGroupTypes) {
+ if (ng == namedGroupType) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ interface ExceptionSupplier {
+ void apply(String s) throws SSLException;
+ }
+
+ /*
+ * A list of functions to do NamedGroup operations in a
+ * algorithm-independent and consistent way.
+ */
+ private static abstract class NamedGroupFunctions {
+
+ // cache to speed up the parameters construction
+ protected static final Map<NamedGroup, AlgorithmParameters>
+ namedGroupParams = new ConcurrentHashMap<>();
+
+ protected void checkConstraints(PublicKey publicKey,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws SSLException {
+
+ if (!constraints.permits(
+ EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+ publicKey)) {
+
+ onConstraintFail.apply("key share entry does not "
+ + "comply with algorithm constraints");
+ }
+ }
+
+ public AlgorithmParameters getParameters(NamedGroup ng) {
+
+ AlgorithmParameters result = namedGroupParams.get(ng);
+ if (result == null) {
+ Optional<AlgorithmParameters> paramsOpt = getParametersImpl(ng);
+ if (paramsOpt.isPresent()) {
+ result = paramsOpt.get();
+ namedGroupParams.put(ng, result);
+ }
+ }
+
+ return result;
+ }
+
+ public abstract byte[] encodePossessionPublicKey(
+ NamedGroupPossession namedGroupPossession);
+
+ public abstract SSLCredentials decodeCredentials(
+ NamedGroup ng, byte[] encoded,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws IOException, GeneralSecurityException;
+
+ public abstract SSLPossession createPossession(NamedGroup ng,
+ SecureRandom random);
+
+ public abstract SSLKeyDerivation createKeyDerivation(
+ HandshakeContext hc) throws IOException;
+
+ protected abstract Optional<AlgorithmParameters> getParametersImpl(
+ NamedGroup ng);
+
+ public abstract AlgorithmParameterSpec getParameterSpec(NamedGroup ng);
+
+ public abstract boolean isAvailable(NamedGroup ng);
+ }
+
+ private static class FFDHFunctions extends NamedGroupFunctions {
+
+ // lazy initialization
+ private static class FunctionsHolder {
+ private static final FFDHFunctions instance = new FFDHFunctions();
+ }
+
+ private static FFDHFunctions getInstance() {
+ return FunctionsHolder.instance;
+ }
+
+ @Override
+ public byte[] encodePossessionPublicKey(
+ NamedGroupPossession namedGroupPossession) {
+ return ((DHEPossession)namedGroupPossession).encode();
+ }
+
+ @Override
+ public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws IOException, GeneralSecurityException {
+
+ DHKeyExchange.DHECredentials result
+ = DHKeyExchange.DHECredentials.valueOf(ng, encoded);
+
+ checkConstraints(result.getPublicKey(), constraints,
+ onConstraintFail);
+
+ return result;
+ }
+
+ @Override
+ public SSLPossession createPossession(
+ NamedGroup ng, SecureRandom random) {
+ return new DHKeyExchange.DHEPossession(ng, random);
+ }
+
+ @Override
+ public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+ throws IOException {
+
+ return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+ return getDHParameterSpec(ng);
+ }
+
+ DHParameterSpec getDHParameterSpec(NamedGroup ng) {
+
+ AlgorithmParameters params = getParameters(ng);
+ try {
+ return params.getParameterSpec(DHParameterSpec.class);
+ } catch (InvalidParameterSpecException ipse) {
+ // should be unlikely
+ return getPredefinedDHParameterSpec(ng);
+ }
+ }
+
+ private static DHParameterSpec getFFDHEDHParameterSpec(
+ NamedGroup namedGroup) {
+
+ DHParameterSpec spec = null;
+ switch (namedGroup) {
+ case FFDHE_2048:
+ spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
+ break;
+ case FFDHE_3072:
+ spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
+ break;
+ case FFDHE_4096:
+ spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
+ break;
+ case FFDHE_6144:
+ spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
+ break;
+ case FFDHE_8192:
+ spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
+ }
+
+ return spec;
+ }
+
+ private static DHParameterSpec getPredefinedDHParameterSpec(
+ NamedGroup namedGroup) {
+
+ DHParameterSpec spec = null;
+ switch (namedGroup) {
+ case FFDHE_2048:
+ spec = PredefinedDHParameterSpecs.definedParams.get(2048);
+ break;
+ case FFDHE_3072:
+ spec = PredefinedDHParameterSpecs.definedParams.get(3072);
+ break;
+ case FFDHE_4096:
+ spec = PredefinedDHParameterSpecs.definedParams.get(4096);
+ break;
+ case FFDHE_6144:
+ spec = PredefinedDHParameterSpecs.definedParams.get(6144);
+ break;
+ case FFDHE_8192:
+ spec = PredefinedDHParameterSpecs.definedParams.get(8192);
+ }
+
+ return spec;
+ }
+
+ @Override
+ public boolean isAvailable(NamedGroup ng) {
+
+ AlgorithmParameters params = getParameters(ng);
+ return params != null;
+ }
+
+ @Override
+ protected Optional<AlgorithmParameters> getParametersImpl(
+ NamedGroup ng) {
+ try {
+ AlgorithmParameters params
+ = AlgorithmParameters.getInstance("DiffieHellman");
+ AlgorithmParameterSpec spec
+ = getFFDHEDHParameterSpec(ng);
+ params.init(spec);
+ return Optional.of(params);
+ } catch (InvalidParameterSpecException
+ | NoSuchAlgorithmException ex) {
+ return Optional.empty();
+ }
+ }
+
+ }
+
+ private static class ECDHFunctions extends NamedGroupFunctions {
+
+ // lazy initialization
+ private static class FunctionsHolder {
+ private static final ECDHFunctions instance = new ECDHFunctions();
+ }
+
+ private static ECDHFunctions getInstance() {
+ return FunctionsHolder.instance;
+ }
+
+ @Override
+ public byte[] encodePossessionPublicKey(
+ NamedGroupPossession namedGroupPossession) {
+ return ((ECDHEPossession)namedGroupPossession).encode();
+ }
+
+ @Override
+ public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws IOException, GeneralSecurityException {
+
+ ECDHKeyExchange.ECDHECredentials result
+ = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
+
+ checkConstraints(result.getPublicKey(), constraints,
+ onConstraintFail);
+
+ return result;
+ }
+
+ @Override
+ public SSLPossession createPossession(
+ NamedGroup ng, SecureRandom random) {
+ return new ECDHKeyExchange.ECDHEPossession(ng, random);
+ }
+
+ @Override
+ public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+ throws IOException {
+
+ return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+ return SupportedGroupsExtension.SupportedGroups
+ .getECGenParamSpec(ng);
+ }
+
+ @Override
+ public boolean isAvailable(NamedGroup ng) {
+
+ AlgorithmParameters params = getParameters(ng);
+ return params != null;
+ }
+
+ @Override
+ protected Optional<AlgorithmParameters> getParametersImpl(
+ NamedGroup ng) {
+ try {
+ AlgorithmParameters params
+ = AlgorithmParameters.getInstance("EC");
+ AlgorithmParameterSpec spec
+ = new ECGenParameterSpec(ng.oid);
+ params.init(spec);
+ return Optional.of(params);
+ } catch (InvalidParameterSpecException
+ | NoSuchAlgorithmException ex) {
+ return Optional.empty();
+ }
+ }
+ }
+
+ private static class XDHFunctions extends NamedGroupFunctions {
+
+ // lazy initialization
+ private static class FunctionsHolder {
+ private static final XDHFunctions instance = new XDHFunctions();
+ }
+
+ private static XDHFunctions getInstance() {
+ return FunctionsHolder.instance;
+ }
+
+ @Override
+ public byte[] encodePossessionPublicKey(NamedGroupPossession poss) {
+ return ((XDHKeyExchange.XDHEPossession)poss).encode();
+ }
+
+ @Override
+ public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
+ AlgorithmConstraints constraints,
+ ExceptionSupplier onConstraintFail)
+ throws IOException, GeneralSecurityException {
+
+ XDHKeyExchange.XDHECredentials result
+ = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
+
+ checkConstraints(result.getPublicKey(), constraints,
+ onConstraintFail);
+
+ return result;
+ }
+
+ @Override
+ public SSLPossession createPossession(
+ NamedGroup ng, SecureRandom random) {
+ return new XDHKeyExchange.XDHEPossession(ng, random);
+ }
+
+ @Override
+ public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+ throws IOException {
+ return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
+ }
+
+ @Override
+ public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
+ return new NamedParameterSpec(ng.name);
+ }
+
+ @Override
+ public boolean isAvailable(NamedGroup ng) {
+
+ try {
+ KeyAgreement.getInstance(ng.algorithm);
+ return true;
+ } catch (NoSuchAlgorithmException ex) {
+ return false;
+ }
+ }
+
+ @Override
+ protected Optional<AlgorithmParameters> getParametersImpl(
+ NamedGroup ng) {
+ return Optional.empty();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroupCredentials.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package sun.security.ssl;
+
+import java.security.PublicKey;
+
+interface NamedGroupCredentials extends SSLCredentials {
+
+ PublicKey getPublicKey();
+
+ NamedGroup getNamedGroup();
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroupPossession.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package sun.security.ssl;
+
+import java.security.PrivateKey;
+import java.security.PublicKey;
+
+interface NamedGroupPossession extends SSLPossession {
+
+ NamedGroup getNamedGroup();
+
+ PublicKey getPublicKey();
+
+ PrivateKey getPrivateKey();
+}
--- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -484,6 +484,25 @@
final SSLHandshake handshakeType;
final String name;
final ProtocolVersion[] supportedProtocols;
+
+ /*
+ * networkProducer: produces outbound handshake data.
+ *
+ * onLoadConsumer: parses inbound data. It may not be appropriate
+ * to act until all of the message inputs have
+ * been parsed. (e.g. parsing keyShares and choosing
+ * a local value without having seen the SupportedGroups
+ * extension.)
+ *
+ * onLoadAbsence: if a missing message needs special handling
+ * during the load phase.
+ *
+ * onTradeConsumer: act on the parsed message once all inbound data has
+ * been traded and parsed.
+ *
+ * onTradeAbsence: if a missing message needs special handling
+ * during the trade phase.
+ */
final HandshakeProducer networkProducer;
final ExtensionConsumer onLoadConsumer;
final HandshakeAbsence onLoadAbsence;
--- a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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,6 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
-import sun.security.ssl.DHKeyExchange.DHEPossession;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
import sun.security.ssl.X509Authentication.X509Possession;
@@ -243,8 +239,7 @@
static SSLKeyExchange valueOf(NamedGroup namedGroup) {
SSLKeyAgreement ka = T13KeyAgreement.valueOf(namedGroup);
if (ka != null) {
- return new SSLKeyExchange(
- null, T13KeyAgreement.valueOf(namedGroup));
+ return new SSLKeyExchange(null, ka);
}
return null;
@@ -337,7 +332,7 @@
ECDH ("ecdh", null,
ECDHKeyExchange.ecdhKAGenerator),
ECDHE ("ecdhe", ECDHKeyExchange.poGenerator,
- ECDHKeyExchange.ecdheKAGenerator);
+ ECDHKeyExchange.ecdheXdhKAGenerator);
final String name;
final SSLPossessionGenerator possessionGenerator;
@@ -570,27 +565,13 @@
@Override
public SSLPossession createPossession(HandshakeContext hc) {
- if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- return new ECDHEPossession(
- namedGroup, hc.sslContext.getSecureRandom());
- } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- return new DHEPossession(
- namedGroup, hc.sslContext.getSecureRandom());
- }
-
- return null;
+ return namedGroup.createPossession(hc.sslContext.getSecureRandom());
}
@Override
public SSLKeyDerivation createKeyDerivation(
HandshakeContext hc) throws IOException {
- if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
- } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
- }
-
- return null;
+ return namedGroup.createKeyDerivation(hc);
}
}
}
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, 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
@@ -313,7 +313,9 @@
handshakeBuffer.put(handshakeFrag);
handshakeBuffer.rewind();
break;
- } if (remaining == handshakeMessageLen) {
+ }
+
+ if (remaining == handshakeMessageLen) {
if (handshakeHash.isHashable(handshakeType)) {
handshakeHash.receive(handshakeFrag);
}
--- a/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java Wed Jun 12 18:58:00 2019 -0700
@@ -26,7 +26,6 @@
package sun.security.ssl;
import java.security.*;
-import java.security.interfaces.ECPrivateKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.MGF1ParameterSpec;
@@ -39,8 +38,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.NamedGroup.NamedGroupType;
import sun.security.ssl.X509Authentication.X509Possession;
import sun.security.util.KeyUtil;
import sun.security.util.SignatureUtil;
@@ -432,10 +430,10 @@
}
for (SignatureScheme ss : schemes) {
if (ss.isAvailable && (keySize >= ss.minimalKeySize) &&
- ss.handshakeSupportedProtocols.contains(version) &&
- keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
- if (ss.namedGroup != null &&
- ss.namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
+ ss.handshakeSupportedProtocols.contains(version) &&
+ keyAlgorithm.equalsIgnoreCase(ss.keyAlgorithm)) {
+ if ((ss.namedGroup != null) && (ss.namedGroup.type ==
+ NamedGroupType.NAMED_GROUP_ECDHE)) {
ECParameterSpec params =
x509Possession.getECParameterSpec();
if (params != null &&
--- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java Wed Jun 12 18:58:00 2019 -0700
@@ -30,29 +30,24 @@
import java.security.AlgorithmConstraints;
import java.security.AlgorithmParameters;
import java.security.CryptoPrimitive;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
-import java.security.spec.ECParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
-import javax.crypto.spec.DHParameterSpec;
import javax.net.ssl.SSLProtocolException;
import sun.security.action.GetPropertyAction;
+import sun.security.ssl.NamedGroup.NamedGroupType;
import static sun.security.ssl.SSLExtension.CH_SUPPORTED_GROUPS;
import static sun.security.ssl.SSLExtension.EE_SUPPORTED_GROUPS;
import sun.security.ssl.SSLExtension.ExtensionConsumer;
import sun.security.ssl.SSLExtension.SSLExtensionSpec;
import sun.security.ssl.SSLHandshake.HandshakeMessage;
-import sun.security.util.ECUtil;
+
/**
* Pack of the "supported_groups" extensions [RFC 4492/7919].
@@ -158,320 +153,11 @@
}
}
- static enum NamedGroupType {
- NAMED_GROUP_ECDHE ("EC"),
- NAMED_GROUP_FFDHE ("DiffieHellman"),
- NAMED_GROUP_X25519 ("x25519"),
- NAMED_GROUP_X448 ("x448"),
- NAMED_GROUP_ARBITRARY ("EC"),
- NAMED_GROUP_NONE ("");
-
- private final String algorithm;
-
- private NamedGroupType(String algorithm) {
- this.algorithm = algorithm;
- }
-
- boolean isSupported(List<CipherSuite> cipherSuites) {
- for (CipherSuite cs : cipherSuites) {
- if (cs.keyExchange == null ||
- cs.keyExchange.groupType == this) {
- return true;
- }
- }
-
- return false;
- }
- }
-
- static enum NamedGroup {
- // Elliptic Curves (RFC 4492)
- //
- // See sun.security.util.CurveDB for the OIDs
- // NIST K-163
- SECT163_K1 (0x0001, "sect163k1", "1.3.132.0.1",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECT163_R1 (0x0002, "sect163r1", "1.3.132.0.2",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST B-163
- SECT163_R2 (0x0003, "sect163r2", "1.3.132.0.15",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECT193_R1 (0x0004, "sect193r1", "1.3.132.0.24",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECT193_R2 (0x0005, "sect193r2", "1.3.132.0.25",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST K-233
- SECT233_K1 (0x0006, "sect233k1", "1.3.132.0.26",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST B-233
- SECT233_R1 (0x0007, "sect233r1", "1.3.132.0.27",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECT239_K1 (0x0008, "sect239k1", "1.3.132.0.3",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST K-283
- SECT283_K1 (0x0009, "sect283k1", "1.3.132.0.16",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST B-283
- SECT283_R1 (0x000A, "sect283r1", "1.3.132.0.17",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST K-409
- SECT409_K1 (0x000B, "sect409k1", "1.3.132.0.36",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST B-409
- SECT409_R1 (0x000C, "sect409r1", "1.3.132.0.37",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST K-571
- SECT571_K1 (0x000D, "sect571k1", "1.3.132.0.38",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST B-571
- SECT571_R1 (0x000E, "sect571r1", "1.3.132.0.39",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP160_K1 (0x000F, "secp160k1", "1.3.132.0.9",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP160_R1 (0x0010, "secp160r1", "1.3.132.0.8",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP160_R2 (0x0011, "secp160r2", "1.3.132.0.30",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP192_K1 (0x0012, "secp192k1", "1.3.132.0.31",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST P-192
- SECP192_R1 (0x0013, "secp192r1", "1.2.840.10045.3.1.1",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP224_K1 (0x0014, "secp224k1", "1.3.132.0.32",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- // NIST P-224
- SECP224_R1 (0x0015, "secp224r1", "1.3.132.0.33",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
- SECP256_K1 (0x0016, "secp256k1", "1.3.132.0.10",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_12),
-
- // NIST P-256
- SECP256_R1 (0x0017, "secp256r1", "1.2.840.10045.3.1.7",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
-
- // NIST P-384
- SECP384_R1 (0x0018, "secp384r1", "1.3.132.0.34",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
-
- // NIST P-521
- SECP521_R1 (0x0019, "secp521r1", "1.3.132.0.35",
- NamedGroupType.NAMED_GROUP_ECDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
-
- // x25519 and x448
- X25519 (0x001D, "x25519", null,
- NamedGroupType.NAMED_GROUP_X25519,
- ProtocolVersion.PROTOCOLS_TO_13),
- X448 (0x001E, "x448", null,
- NamedGroupType.NAMED_GROUP_X448,
- ProtocolVersion.PROTOCOLS_TO_13),
-
- // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
- FFDHE_2048 (0x0100, "ffdhe2048", null,
- NamedGroupType.NAMED_GROUP_FFDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
- FFDHE_3072 (0x0101, "ffdhe3072", null,
- NamedGroupType.NAMED_GROUP_FFDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
- FFDHE_4096 (0x0102, "ffdhe4096", null,
- NamedGroupType.NAMED_GROUP_FFDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
- FFDHE_6144 (0x0103, "ffdhe6144", null,
- NamedGroupType.NAMED_GROUP_FFDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
- FFDHE_8192 (0x0104, "ffdhe8192", null,
- NamedGroupType.NAMED_GROUP_FFDHE,
- ProtocolVersion.PROTOCOLS_TO_13),
-
- // Elliptic Curves (RFC 4492)
- //
- // arbitrary prime and characteristic-2 curves
- ARBITRARY_PRIME (0xFF01, "arbitrary_explicit_prime_curves", null,
- NamedGroupType.NAMED_GROUP_ARBITRARY,
- ProtocolVersion.PROTOCOLS_TO_12),
- ARBITRARY_CHAR2 (0xFF02, "arbitrary_explicit_char2_curves", null,
- NamedGroupType.NAMED_GROUP_ARBITRARY,
- ProtocolVersion.PROTOCOLS_TO_12);
-
- final int id; // hash + signature
- final NamedGroupType type; // group type
- final String name; // literal name
- final String oid; // object identifier of the named group
- final String algorithm; // signature algorithm
- final ProtocolVersion[] supportedProtocols;
-
- private NamedGroup(int id, String name, String oid,
- NamedGroupType namedGroupType,
- ProtocolVersion[] supportedProtocols) {
- this.id = id;
- this.type = namedGroupType;
- this.name = name;
- this.oid = oid;
- this.algorithm = namedGroupType.algorithm;
- this.supportedProtocols = supportedProtocols;
- }
-
- static NamedGroup valueOf(int id) {
- for (NamedGroup group : NamedGroup.values()) {
- if (group.id == id) {
- return group;
- }
- }
-
- return null;
- }
-
- static NamedGroup valueOf(ECParameterSpec params) {
- String oid = ECUtil.getCurveName(null, params);
- if ((oid != null) && (!oid.isEmpty())) {
- for (NamedGroup group : NamedGroup.values()) {
- if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
- oid.equals(group.oid)) {
- return group;
- }
- }
- }
-
- return null;
- }
-
- static NamedGroup valueOf(DHParameterSpec params) {
- for (Map.Entry<NamedGroup, AlgorithmParameters> me :
- SupportedGroups.namedGroupParams.entrySet()) {
- NamedGroup ng = me.getKey();
- if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
- continue;
- }
-
- DHParameterSpec ngParams = null;
- AlgorithmParameters aps = me.getValue();
- try {
- ngParams = aps.getParameterSpec(DHParameterSpec.class);
- } catch (InvalidParameterSpecException ipse) {
- // should be unlikely
- }
-
- if (ngParams == null) {
- continue;
- }
-
- if (ngParams.getP().equals(params.getP()) &&
- ngParams.getG().equals(params.getG())) {
- return ng;
- }
- }
-
- return null;
- }
-
- static NamedGroup nameOf(String name) {
- for (NamedGroup group : NamedGroup.values()) {
- if (group.name.equals(name)) {
- return group;
- }
- }
-
- return null;
- }
-
- static String nameOf(int id) {
- for (NamedGroup group : NamedGroup.values()) {
- if (group.id == id) {
- return group.name;
- }
- }
-
- return "UNDEFINED-NAMED-GROUP(" + id + ")";
- }
-
- boolean isAvailable(List<ProtocolVersion> protocolVersions) {
- for (ProtocolVersion pv : supportedProtocols) {
- if (protocolVersions.contains(pv)) {
- return true;
- }
- }
- return false;
- }
-
- boolean isAvailable(ProtocolVersion protocolVersion) {
- for (ProtocolVersion pv : supportedProtocols) {
- if (protocolVersion == pv) {
- return true;
- }
- }
- return false;
- }
-
- boolean isSupported(List<CipherSuite> cipherSuites) {
- for (CipherSuite cs : cipherSuites) {
- boolean isMatch = isAvailable(cs.supportedProtocols);
- if (isMatch && (cs.keyExchange == null ||
- cs.keyExchange.groupType == type)) {
- return true;
- }
- }
- return false;
- }
-
- // lazy loading of parameters
- AlgorithmParameters getParameters() {
- return SupportedGroups.namedGroupParams.get(this);
- }
-
- AlgorithmParameterSpec getParameterSpec() {
- if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- return SupportedGroups.getECGenParamSpec(this);
- } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- return SupportedGroups.getDHParameterSpec(this);
- }
-
- return null;
- }
- }
-
static class SupportedGroups {
// To switch off the supported_groups extension for DHE cipher suite.
static final boolean enableFFDHE =
Utilities.getBooleanProperty("jsse.enableFFDHE", true);
- // cache to speed up the parameters construction
- static final Map<NamedGroup,
- AlgorithmParameters> namedGroupParams = new HashMap<>();
-
// the supported named groups
static final NamedGroup[] supportedNamedGroups;
@@ -516,10 +202,19 @@
}
} else { // default groups
NamedGroup[] groups = new NamedGroup[] {
- // NIST curves first
+
+ // Primary XDH (RFC 7748) curves
+ NamedGroup.X25519,
+
+ // Primary NIST curves (e.g. used in TLSv1.3)
NamedGroup.SECP256_R1,
NamedGroup.SECP384_R1,
NamedGroup.SECP521_R1,
+
+ // Secondary XDH curves
+ NamedGroup.X448,
+
+ // Secondary NIST curves
NamedGroup.SECT283_K1,
NamedGroup.SECT283_R1,
NamedGroup.SECT409_K1,
@@ -530,7 +225,7 @@
// non-NIST curves
NamedGroup.SECP256_K1,
- // FFDHE 2048
+ // FFDHE (RFC 7919)
NamedGroup.FFDHE_2048,
NamedGroup.FFDHE_3072,
NamedGroup.FFDHE_4096,
@@ -560,126 +255,27 @@
// check whether the group is supported by the underlying providers
private static boolean isAvailableGroup(NamedGroup namedGroup) {
- AlgorithmParameters params = null;
- AlgorithmParameterSpec spec = null;
- if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
- if (namedGroup.oid != null) {
- try {
- params = AlgorithmParameters.getInstance("EC");
- spec = new ECGenParameterSpec(namedGroup.oid);
- } catch (NoSuchAlgorithmException e) {
- return false;
- }
- }
- } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
- try {
- params = AlgorithmParameters.getInstance("DiffieHellman");
- spec = getFFDHEDHParameterSpec(namedGroup);
- } catch (NoSuchAlgorithmException e) {
- return false;
- }
- } // Otherwise, unsupported.
-
- if ((params != null) && (spec != null)) {
- try {
- params.init(spec);
- } catch (InvalidParameterSpecException e) {
- return false;
- }
-
- // cache the parameters
- namedGroupParams.put(namedGroup, params);
-
- return true;
- }
-
- return false;
+ return namedGroup.isAvailableGroup();
}
- private static DHParameterSpec getFFDHEDHParameterSpec(
- NamedGroup namedGroup) {
- DHParameterSpec spec = null;
- switch (namedGroup) {
- case FFDHE_2048:
- spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
- break;
- case FFDHE_3072:
- spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
- break;
- case FFDHE_4096:
- spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
- break;
- case FFDHE_6144:
- spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
- break;
- case FFDHE_8192:
- spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
+ static ECGenParameterSpec getECGenParamSpec(NamedGroup ng) {
+ if (ng.type != NamedGroupType.NAMED_GROUP_ECDHE) {
+ throw new RuntimeException(
+ "Not a named EC group: " + ng);
}
- return spec;
- }
-
- private static DHParameterSpec getPredefinedDHParameterSpec(
- NamedGroup namedGroup) {
- DHParameterSpec spec = null;
- switch (namedGroup) {
- case FFDHE_2048:
- spec = PredefinedDHParameterSpecs.definedParams.get(2048);
- break;
- case FFDHE_3072:
- spec = PredefinedDHParameterSpecs.definedParams.get(3072);
- break;
- case FFDHE_4096:
- spec = PredefinedDHParameterSpecs.definedParams.get(4096);
- break;
- case FFDHE_6144:
- spec = PredefinedDHParameterSpecs.definedParams.get(6144);
- break;
- case FFDHE_8192:
- spec = PredefinedDHParameterSpecs.definedParams.get(8192);
- }
-
- return spec;
- }
-
- static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
- if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
- throw new RuntimeException(
- "Not a named EC group: " + namedGroup);
- }
-
- AlgorithmParameters params = namedGroupParams.get(namedGroup);
- if (params == null) {
- throw new RuntimeException(
- "Not a supported EC named group: " + namedGroup);
- }
-
+ // parameters are non-null
+ AlgorithmParameters params = ng.getParameters();
try {
return params.getParameterSpec(ECGenParameterSpec.class);
} catch (InvalidParameterSpecException ipse) {
// should be unlikely
- return new ECGenParameterSpec(namedGroup.oid);
+ return new ECGenParameterSpec(ng.oid);
}
}
- static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
- if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
- throw new RuntimeException(
- "Not a named DH group: " + namedGroup);
- }
-
- AlgorithmParameters params = namedGroupParams.get(namedGroup);
- if (params == null) {
- throw new RuntimeException(
- "Not a supported DH named group: " + namedGroup);
- }
-
- try {
- return params.getParameterSpec(DHParameterSpec.class);
- } catch (InvalidParameterSpecException ipse) {
- // should be unlikely
- return getPredefinedDHParameterSpec(namedGroup);
- }
+ static AlgorithmParameters getParameters(NamedGroup ng) {
+ return ng.getParameters();
}
// Is there any supported group permitted by the constraints?
@@ -692,7 +288,7 @@
if (constraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
namedGroup.algorithm,
- namedGroupParams.get(namedGroup))) {
+ getParameters(namedGroup))) {
return true;
}
@@ -723,7 +319,7 @@
return constraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
namedGroup.algorithm,
- namedGroupParams.get(namedGroup));
+ getParameters(namedGroup));
}
// Is the named group supported?
@@ -739,16 +335,16 @@
static NamedGroup getPreferredGroup(
ProtocolVersion negotiatedProtocol,
- AlgorithmConstraints constraints, NamedGroupType type,
+ AlgorithmConstraints constraints, NamedGroupType[] types,
List<NamedGroup> requestedNamedGroups) {
for (NamedGroup namedGroup : requestedNamedGroups) {
- if ((namedGroup.type == type) &&
+ if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
namedGroup.isAvailable(negotiatedProtocol) &&
isSupported(namedGroup) &&
constraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
namedGroup.algorithm,
- namedGroupParams.get(namedGroup))) {
+ getParameters(namedGroup))) {
return namedGroup;
}
}
@@ -758,14 +354,14 @@
static NamedGroup getPreferredGroup(
ProtocolVersion negotiatedProtocol,
- AlgorithmConstraints constraints, NamedGroupType type) {
+ AlgorithmConstraints constraints, NamedGroupType[] types) {
for (NamedGroup namedGroup : supportedNamedGroups) {
- if ((namedGroup.type == type) &&
+ if ((NamedGroupType.arrayContains(types, namedGroup.type)) &&
namedGroup.isAvailable(negotiatedProtocol) &&
constraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
namedGroup.algorithm,
- namedGroupParams.get(namedGroup))) {
+ getParameters(namedGroup))) {
return namedGroup;
}
}
@@ -813,7 +409,7 @@
ng.isSupported(chc.activeCipherSuites) &&
chc.algorithmConstraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- ng.algorithm, namedGroupParams.get(ng))) {
+ ng.algorithm, getParameters(ng))) {
namedGroups.add(ng);
} else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
@@ -940,7 +536,7 @@
ng.isSupported(shc.activeCipherSuites) &&
shc.algorithmConstraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
- ng.algorithm, namedGroupParams.get(ng))) {
+ ng.algorithm, getParameters(ng))) {
namedGroups.add(ng);
} else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
SSLLogger.fine(
--- a/src/java.base/share/classes/sun/security/ssl/TransportContext.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/TransportContext.java Wed Jun 12 18:58:00 2019 -0700
@@ -39,7 +39,6 @@
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
/**
* SSL/(D)TLS transportation context.
--- a/src/java.base/share/classes/sun/security/ssl/Utilities.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/Utilities.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, 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
@@ -61,8 +61,8 @@
int size = serverNames.size();
List<SNIServerName> sniList = (size != 0) ?
- new ArrayList<SNIServerName>(serverNames) :
- new ArrayList<SNIServerName>(1);
+ new ArrayList<>(serverNames) :
+ new ArrayList<>(1);
boolean reset = false;
for (int i = 0; i < size; i++) {
@@ -147,7 +147,7 @@
static String indent(String source, String prefix) {
StringBuilder builder = new StringBuilder();
if (source == null) {
- builder.append("\n" + prefix + "<blank message>");
+ builder.append("\n").append(prefix).append("<blank message>");
} else {
String[] lines = lineBreakPatern.split(source);
boolean isFirst = true;
@@ -232,4 +232,21 @@
}
return b;
}
+
+ static void reverseBytes(byte[] arr) {
+ int i = 0;
+ int j = arr.length - 1;
+
+ while (i < j) {
+ swap(arr, i, j);
+ i++;
+ j--;
+ }
+ }
+
+ private static void swap(byte[] arr, int i, int j) {
+ byte tmp = arr[i];
+ arr[i] = arr[j];
+ arr[j] = tmp;
+ }
}
--- a/src/java.base/share/classes/sun/security/ssl/X509Authentication.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/java.base/share/classes/sun/security/ssl/X509Authentication.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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,13 +30,15 @@
import java.security.cert.X509Certificate;
import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.XECKey;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECParameterSpec;
+import java.security.spec.NamedParameterSpec;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.Map;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.X509ExtendedKeyManager;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
enum X509Authentication implements SSLAuthentication {
@@ -148,6 +150,35 @@
return null;
}
+
+ // Similar to above, but for XEC.
+ NamedParameterSpec getXECParameterSpec() {
+ if (popPrivateKey == null ||
+ !"XEC".equals(popPrivateKey.getAlgorithm())) {
+ return null;
+ }
+
+ if (popPrivateKey instanceof XECKey) {
+ AlgorithmParameterSpec params =
+ ((XECKey)popPrivateKey).getParams();
+ if (params instanceof NamedParameterSpec){
+ return (NamedParameterSpec)params;
+ }
+ } else if (popCerts != null && popCerts.length != 0) {
+ // The private key not extractable, get the parameters from
+ // the X.509 certificate.
+ PublicKey publicKey = popCerts[0].getPublicKey();
+ if (publicKey instanceof XECKey) {
+ AlgorithmParameterSpec params =
+ ((XECKey)publicKey).getParams();
+ if (params instanceof NamedParameterSpec){
+ return (NamedParameterSpec)params;
+ }
+ }
+ }
+
+ return null;
+ }
}
static final class X509Credentials implements SSLCredentials {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2019, 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.*;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.*;
+import sun.security.ssl.NamedGroup.NamedGroupType;
+import sun.security.util.*;
+
+/**
+ * Specifics for XEC/XDH Keys/Exchanges
+ */
+final class XDHKeyExchange {
+
+ static final SSLKeyAgreementGenerator xdheKAGenerator
+ = new XDHEKAGenerator();
+
+ static final class XDHECredentials implements NamedGroupCredentials {
+
+ final XECPublicKey popPublicKey;
+ final NamedGroup namedGroup;
+
+ XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) {
+ this.popPublicKey = popPublicKey;
+ this.namedGroup = namedGroup;
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return popPublicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
+ /**
+ * Parse the encoded Point into the XDHECredentials using the
+ * namedGroup.
+ */
+ static XDHECredentials valueOf(NamedGroup namedGroup,
+ byte[] encodedPoint) throws IOException,
+ GeneralSecurityException {
+
+ if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) {
+ throw new RuntimeException(
+ "Credentials decoding: Not XDH named group");
+ }
+
+ if (encodedPoint == null || encodedPoint.length == 0) {
+ return null;
+ }
+
+ byte[] uBytes = encodedPoint.clone();
+ Utilities.reverseBytes(uBytes);
+ BigInteger u = new BigInteger(1, uBytes);
+
+ XECPublicKeySpec xecPublicKeySpec = new XECPublicKeySpec(
+ new NamedParameterSpec(namedGroup.name), u);
+ KeyFactory factory = KeyFactory.getInstance(namedGroup.algorithm);
+ XECPublicKey publicKey = (XECPublicKey) factory.generatePublic(
+ xecPublicKeySpec);
+
+ return new XDHECredentials(publicKey, namedGroup);
+ }
+ }
+
+ static final class XDHEPossession implements NamedGroupPossession {
+
+ final PrivateKey privateKey;
+ final XECPublicKey publicKey;
+ final NamedGroup namedGroup;
+
+ XDHEPossession(NamedGroup namedGroup, SecureRandom random) {
+ try {
+ KeyPairGenerator kpg
+ = KeyPairGenerator.getInstance(namedGroup.algorithm);
+ AlgorithmParameterSpec params = namedGroup.getParameterSpec();
+ kpg.initialize(params, random);
+ KeyPair kp = kpg.generateKeyPair();
+ privateKey = kp.getPrivate();
+ publicKey = (XECPublicKey) kp.getPublic();
+ } catch (GeneralSecurityException e) {
+ throw new RuntimeException(
+ "Could not generate XDH keypair", e);
+ }
+
+ this.namedGroup = namedGroup;
+ }
+
+ @Override
+ public byte[] encode() {
+
+ byte[] uBytes = ECUtil.trimZeroes(publicKey.getU().toByteArray());
+
+ int expLength;
+ switch (namedGroup) {
+ case X25519:
+ expLength = 32;
+ break;
+ case X448:
+ expLength = 56;
+ break;
+ default:
+ throw new RuntimeException("Invalid XDH group");
+ }
+
+ if (uBytes.length > expLength) {
+ throw new RuntimeException("Encoded XDH key too large");
+ }
+
+ if (uBytes.length != expLength) {
+ byte[] tmp = new byte[expLength];
+ System.arraycopy(uBytes, 0, tmp,
+ expLength - uBytes.length, uBytes.length);
+ uBytes = tmp;
+ }
+
+ Utilities.reverseBytes(uBytes);
+ return (uBytes);
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return publicKey;
+ }
+
+ @Override
+ public NamedGroup getNamedGroup() {
+ return namedGroup;
+ }
+
+ @Override
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+ }
+
+ private static final class XDHEKAGenerator
+ implements SSLKeyAgreementGenerator {
+
+ // Prevent instantiation of this class.
+ private XDHEKAGenerator() {
+ // blank
+ }
+
+ @Override
+ public SSLKeyDerivation createKeyDerivation(
+ HandshakeContext context) throws IOException {
+ XDHEPossession xdhePossession = null;
+ XDHECredentials xdheCredentials = null;
+ for (SSLPossession poss : context.handshakePossessions) {
+ if (!(poss instanceof XDHEPossession)) {
+ continue;
+ }
+
+ NamedGroup ng = ((XDHEPossession) poss).namedGroup;
+ for (SSLCredentials cred : context.handshakeCredentials) {
+ if (!(cred instanceof XDHECredentials)) {
+ continue;
+ }
+ if (ng.equals(((XDHECredentials) cred).namedGroup)) {
+ xdheCredentials = (XDHECredentials) cred;
+ break;
+ }
+ }
+
+ if (xdheCredentials != null) {
+ xdhePossession = (XDHEPossession) poss;
+ break;
+ }
+ }
+
+ if (xdhePossession == null || xdheCredentials == null) {
+ context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+ "No sufficient XDHE key agreement "
+ + "parameters negotiated");
+ }
+
+ return new KAKeyDerivation("XDH", context,
+ xdhePossession.privateKey, xdheCredentials.popPublicKey);
+ }
+ }
+}
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -38,6 +38,7 @@
import javax.crypto.KeyAgreementSpi;
import javax.crypto.SecretKey;
import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
import java.util.function.Function;
public class XDHKeyAgreement extends KeyAgreementSpi {
@@ -202,7 +203,15 @@
throws IllegalStateException, NoSuchAlgorithmException,
InvalidKeyException {
- throw new NoSuchAlgorithmException("Not supported");
+ if (algorithm == null) {
+ throw new NoSuchAlgorithmException("Algorithm must not be null");
+ }
+
+ if (!(algorithm.equals("TlsPremasterSecret"))) {
+ throw new NoSuchAlgorithmException(
+ "Only supported for algorithm TlsPremasterSecret");
+ }
+ return new SecretKeySpec(engineGenerateSecret(), algorithm);
}
static class X25519 extends XDHKeyAgreement {
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java Wed Jun 12 23:21:24 2019 +0200
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, 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
@@ -156,7 +156,7 @@
new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
bySize.put(bits, params);
byOid.put(oid, params);
- byName.put(name, params);
+ byName.put(name.toLowerCase(), params);
}
public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
@@ -166,7 +166,7 @@
return Optional.ofNullable(SIZE_MAP.get(size));
}
public static Optional<XECParameters> getByName(String name) {
- return Optional.ofNullable(NAME_MAP.get(name));
+ return Optional.ofNullable(NAME_MAP.get(name.toLowerCase()));
}
boolean oidEquals(XECParameters other) {
--- a/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java Wed Jun 12 23:21:24 2019 +0200
+++ b/test/jdk/javax/net/ssl/templates/SSLSocketTemplate.java Wed Jun 12 18:58:00 2019 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, 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
@@ -189,10 +189,15 @@
}
/*
+ * Configure the client side socket.
+ */
+ protected void configureClientSocket(SSLSocket socket) {
+ }
+
+ /*
* Configure the server side socket.
*/
protected void configureServerSocket(SSLServerSocket socket) {
-
}
/*
@@ -317,6 +322,7 @@
try (SSLSocket sslSocket = (SSLSocket)sslsf.createSocket()) {
try {
+ configureClientSocket(sslSocket);
sslSocket.connect(
new InetSocketAddress("localhost", serverPort), 15000);
} catch (IOException ioe) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java Wed Jun 12 18:58:00 2019 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+ /*
+ * @test
+ * @bug 8171279
+ * @library /javax/net/ssl/templates
+ * @summary Test TLS connection with each individual supported group
+ * @run main/othervm SupportedGroups x25519
+ * @run main/othervm SupportedGroups x448
+ * @run main/othervm SupportedGroups secp256r1
+ * @run main/othervm SupportedGroups secp384r1
+ * @run main/othervm SupportedGroups secp521r1
+ * @run main/othervm SupportedGroups ffdhe2048
+ * @run main/othervm SupportedGroups ffdhe3072
+ * @run main/othervm SupportedGroups ffdhe4096
+ * @run main/othervm SupportedGroups ffdhe6144
+ * @run main/othervm SupportedGroups ffdhe8192
+ */
+import java.util.Arrays;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLServerSocket;
+
+public class SupportedGroups extends SSLSocketTemplate {
+
+ private static volatile int index;
+ private static final String[][][] protocols = {
+ {{"TLSv1.3"}, {"TLSv1.3"}},
+ {{"TLSv1.3", "TLSv1.2"}, {"TLSv1.2"}},
+ {{"TLSv1.2"}, {"TLSv1.3", "TLSv1.2"}},
+ {{"TLSv1.2"}, {"TLSv1.2"}}
+ };
+
+ // Servers are configured before clients, increment test case after.
+ @Override
+ protected void configureClientSocket(SSLSocket socket) {
+ String[] ps = protocols[index][0];
+
+ System.out.print("Setting client protocol(s): ");
+ Arrays.stream(ps).forEachOrdered(System.out::print);
+ System.out.println();
+
+ socket.setEnabledProtocols(ps);
+ }
+
+ @Override
+ protected void configureServerSocket(SSLServerSocket serverSocket) {
+ String[] ps = protocols[index][1];
+
+ System.out.print("Setting server protocol(s): ");
+ Arrays.stream(ps).forEachOrdered(System.out::print);
+ System.out.println();
+
+ serverSocket.setEnabledProtocols(ps);
+ }
+
+ /*
+ * Run the test case.
+ */
+ public static void main(String[] args) throws Exception {
+ System.setProperty("jdk.tls.namedGroups", args[0]);
+
+ for (index = 0; index < protocols.length; index++) {
+ (new SupportedGroups()).run();
+ }
+ }
+}