# HG changeset patch # User pkoppula # Date 1513338340 0 # Node ID 65141d41e00556556b629e3412dfd09af0da1fd1 # Parent 160b59f43c345bfe2aaaea1a29e424dd34648955 8148421: Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension Reviewed-by: wetmore, xuelei, rhalade, coffeys, bgopularam Contributed-by: prasadarao.koppula@oracle.com diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/com/sun/crypto/provider/SunJCE.java --- a/src/share/classes/com/sun/crypto/provider/SunJCE.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java Fri Dec 15 11:45:40 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2017, 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 @@ -503,7 +503,9 @@ put("KeyGenerator.SunTlsMasterSecret", "com.sun.crypto.provider.TlsMasterSecretGenerator"); - + put("Alg.Alias.KeyGenerator.SunTlsExtendedMasterSecret", + "SunTlsMasterSecret"); + put("KeyGenerator.SunTlsKeyMaterial", "com.sun.crypto.provider.TlsKeyMaterialGenerator"); diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java --- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java Fri Dec 15 11:45:40 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -98,17 +98,29 @@ try { byte[] master; - byte[] clientRandom = spec.getClientRandom(); - byte[] serverRandom = spec.getServerRandom(); if (protocolVersion >= 0x0301) { - byte[] seed = concat(clientRandom, serverRandom); - master = doPRF(premaster, LABEL_MASTER_SECRET, seed, 48); + byte[] label; + byte[] seed; + byte[] extendedMasterSecretSessionHash = + spec.getExtendedMasterSecretSessionHash(); + if (extendedMasterSecretSessionHash.length != 0) { + label = LABEL_EXTENDED_MASTER_SECRET; + seed = extendedMasterSecretSessionHash; + } else { + byte[] clientRandom = spec.getClientRandom(); + byte[] serverRandom = spec.getServerRandom(); + label = LABEL_MASTER_SECRET; + seed = concat(clientRandom, serverRandom); + } + master = doPRF(premaster, label, seed, 48); } else { master = new byte[48]; MessageDigest md5 = MessageDigest.getInstance("MD5"); MessageDigest sha = MessageDigest.getInstance("SHA"); + byte[] clientRandom = spec.getClientRandom(); + byte[] serverRandom = spec.getServerRandom(); byte[] tmp = new byte[20]; for (int i = 0; i < 3; i++) { sha.update(SSL3_CONST[i]); @@ -165,5 +177,5 @@ } } +} -} diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java --- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java Fri Dec 15 11:45:40 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -51,6 +51,11 @@ final static byte[] LABEL_MASTER_SECRET = // "master secret" { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 }; + final static byte[] LABEL_EXTENDED_MASTER_SECRET = + // "extended master secret" + { 101, 120, 116, 101, 110, 100, 101, 100, 32, 109, 97, 115, 116, + 101, 114, 32, 115, 101, 99, 114, 101, 116 }; + final static byte[] LABEL_KEY_EXPANSION = // "key expansion" { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 }; diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java --- a/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java Fri Dec 15 11:45:40 2017 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2017, 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 @@ -47,6 +47,7 @@ private final SecretKey premasterSecret; private final int majorVersion, minorVersion; private final byte[] clientRandom, serverRandom; + private final byte[] extendedMasterSecretSessionHash; /** * Constructs a new TlsMasterSecretParameterSpec. @@ -77,6 +78,40 @@ this.minorVersion = checkVersion(minorVersion); this.clientRandom = clientRandom.clone(); this.serverRandom = serverRandom.clone(); + this.extendedMasterSecretSessionHash = new byte[0]; + } + + /** + * Constructs a new TlsMasterSecretParameterSpec. + * + *
The getAlgorithm()
method of premasterSecret
+ * should return "TlsRsaPremasterSecret"
if the key exchange
+ * algorithm was RSA and "TlsPremasterSecret"
otherwise.
+ *
+ * @param premasterSecret the premaster secret
+ * @param majorVersion the major number of the protocol version
+ * @param minorVersion the minor number of the protocol version
+ * @param extendedMasterSecretSessionHash the session hash for
+ * Extended Master Secret
+ *
+ * @throws NullPointerException if premasterSecret is null
+ * @throws IllegalArgumentException if minorVersion or majorVersion are
+ * negative or larger than 255
+ */
+ public TlsMasterSecretParameterSpec(SecretKey premasterSecret,
+ int majorVersion, int minorVersion,
+ byte[] extendedMasterSecretSessionHash) {
+ if (premasterSecret == null) {
+ throw new NullPointerException("premasterSecret must not be null");
+ }
+ this.premasterSecret = premasterSecret;
+ this.majorVersion = checkVersion(majorVersion);
+ this.minorVersion = checkVersion(minorVersion);
+ this.clientRandom = new byte[0];
+ this.serverRandom = new byte[0];
+ this.extendedMasterSecretSessionHash =
+ (extendedMasterSecretSessionHash != null ?
+ extendedMasterSecretSessionHash.clone() : new byte[0]);
}
static int checkVersion(int version) {
@@ -132,4 +167,14 @@
return serverRandom.clone();
}
+ /**
+ + * Returns a copy of the Extended Master Secret session hash.
+ + *
+ + * @return a copy of the Extended Master Secret session hash, or an empty
+ + * array if no extended master secret session hash was provided
+ + * at instantiation time
+ + */
+ public byte[] getExtendedMasterSecretSessionHash() {
+ return extendedMasterSecretSessionHash.clone();
+ }
}
diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/ClientHandshaker.java
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java Thu Feb 02 20:36:46 2017 +0000
+++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java Fri Dec 15 11:45:40 2017 +0000
@@ -588,12 +588,61 @@
}
}
+ // check the "extended_master_secret" extension
+ ExtendedMasterSecretExtension extendedMasterSecretExt =
+ (ExtendedMasterSecretExtension)mesg.extensions.get(
+ ExtensionType.EXT_EXTENDED_MASTER_SECRET);
+ if (extendedMasterSecretExt != null) {
+ // Is it the expected server extension?
+ if (!useExtendedMasterSecret ||
+ !(mesgVersion.v >= ProtocolVersion.TLS10.v) || !requestedToUseEMS) {
+ fatalSE(Alerts.alert_unsupported_extension,
+ "Server sent the extended_master_secret " +
+ "extension improperly");
+ }
+
+ // For abbreviated handshake, if the original session did not use
+ // the "extended_master_secret" extension but the new ServerHello
+ // contains the extension, the client MUST abort the handshake.
+ if (resumingSession && (session != null) &&
+ !session.getUseExtendedMasterSecret()) {
+ fatalSE(Alerts.alert_unsupported_extension,
+ "Server sent an unexpected extended_master_secret " +
+ "extension on session resumption");
+ }
+ } else {
+ if (useExtendedMasterSecret && !allowLegacyMasterSecret) {
+ // For full handshake, if a client receives a ServerHello
+ // without the extension, it SHOULD abort the handshake if
+ // it does not wish to interoperate with legacy servers.
+ fatalSE(Alerts.alert_handshake_failure,
+ "Extended Master Secret extension is required");
+ }
+
+ if (resumingSession && (session != null)) {
+ if (session.getUseExtendedMasterSecret()) {
+ // For abbreviated handshake, if the original session used
+ // the "extended_master_secret" extension but the new
+ // ServerHello does not contain the extension, the client
+ // MUST abort the handshake.
+ fatalSE(Alerts.alert_handshake_failure,
+ "Missing Extended Master Secret extension " +
+ "on session resumption");
+ } else if (useExtendedMasterSecret && !allowLegacyResumption) {
+ // Unlikely, abbreviated handshake should be discarded.
+ fatalSE(Alerts.alert_handshake_failure,
+ "Extended Master Secret extension is required");
+ }
+ }
+ }
+
// check extensions
for (HelloExtension ext : mesg.extensions.list()) {
ExtensionType type = ext.type;
if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
&& (type != ExtensionType.EXT_EC_POINT_FORMATS)
- && (type != ExtensionType.EXT_RENEGOTIATION_INFO)) {
+ && (type != ExtensionType.EXT_RENEGOTIATION_INFO)
+ && (type != ExtensionType.EXT_EXTENDED_MASTER_SECRET)) {
fatalSE(Alerts.alert_unsupported_extension,
"Server sent an unsupported extension: " + type);
}
@@ -601,7 +650,8 @@
// Create a new session, we need to do the full handshake
session = new SSLSessionImpl(protocolVersion, cipherSuite,
- mesg.sessionId, getHostSE(), getPortSE());
+ mesg.sessionId, getHostSE(), getPortSE(),
+ (extendedMasterSecretExt != null));
if (debug != null && Debug.isOn("handshake")) {
System.out.println("** " + cipherSuite);
}
@@ -1177,6 +1227,39 @@
session = null;
}
+ if ((session != null) && useExtendedMasterSecret) {
+ boolean isTLS10Plus = sessionVersion.v >= ProtocolVersion.TLS10.v;
+ if (isTLS10Plus && !session.getUseExtendedMasterSecret()) {
+ if (!allowLegacyResumption) {
+ // perform full handshake instead
+ //
+ // The client SHOULD NOT offer an abbreviated handshake
+ // to resume a session that does not use an extended
+ // master secret. Instead, it SHOULD offer a full
+ // handshake.
+ session = null;
+ }
+ }
+
+ if ((session != null) && !allowUnsafeServerCertChange) {
+ if (isTLS10Plus) {
+ if (!session.getUseExtendedMasterSecret()) {
+ // perform full handshake instead
+ session = null;
+ } // Otherwise, use extended master secret.
+ } else {
+ // The extended master secret extension does not
+ // apply to SSL 3.0. Perform a full handshake
+ // instead.
+ //
+ // Note that the useExtendedMasterSecret is
+ // extended to protect SSL 3.0 connections,
+ // by discarding abbreviate handshake.
+ session = null;
+ }
+ }
+ }
+
if (session != null) {
if (debug != null) {
if (Debug.isOn("handshake") || Debug.isOn("session")) {
@@ -1262,6 +1345,14 @@
}
}
+ // add Extended Master Secret extension
+ if (useExtendedMasterSecret && (maxProtocolVersion.v >= ProtocolVersion.TLS10.v)) {
+ if ((session == null) || session.getUseExtendedMasterSecret()) {
+ clientHelloMessage.addExtendedMasterSecretExtension();
+ requestedToUseEMS = true;
+ }
+ }
+
// reset the client random cookie
clnt_random = clientHelloMessage.clnt_random;
@@ -1311,7 +1402,11 @@
// DO NOT need to check allowUnsafeServerCertChange here. We only
// reserve server certificates when allowUnsafeServerCertChange is
// false.
- if (reservedServerCerts != null) {
+ //
+ // Allow server certificate change if it is negotiated to use the
+ // extended master secret.
+ if ((reservedServerCerts != null) &&
+ !session.getUseExtendedMasterSecret()) {
if (!isIdentityEquivalent(peerCerts[0], reservedServerCerts[0])) {
fatalSE(Alerts.alert_bad_certificate,
"server certificate change is restricted" +
diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java Fri Dec 15 11:45:40 2017 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates.
+ *
+ * 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.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import javax.net.ssl.SSLProtocolException;
+
+/**
+ * Extended Master Secret TLS extension (TLS 1.0+). This extension
+ * defines how to calculate the TLS connection master secret and
+ * mitigates some types of man-in-the-middle attacks.
+ *
+ * See further information in
+ * RFC 7627.
+ *
+ * @author Martin Balao (mbalao@redhat.com)
+ */
+final class ExtendedMasterSecretExtension extends HelloExtension {
+ ExtendedMasterSecretExtension() {
+ super(ExtensionType.EXT_EXTENDED_MASTER_SECRET);
+ }
+
+ ExtendedMasterSecretExtension(HandshakeInStream s,
+ int len) throws IOException {
+ super(ExtensionType.EXT_EXTENDED_MASTER_SECRET);
+
+ if (len != 0) {
+ throw new SSLProtocolException("Invalid " + type + " extension");
+ }
+ }
+
+ @Override
+ int length() {
+ return 4; // 4: extension type and length fields
+ }
+
+ @Override
+ void send(HandshakeOutStream s) throws IOException {
+ s.putInt16(type.id); // ExtensionType extension_type;
+ s.putInt16(0); // extension_data length
+ }
+
+ @Override
+ public String toString() {
+ return "Extension " + type;
+ }
+}
+
diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/HandshakeMessage.java
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java Thu Feb 02 20:36:46 2017 +0000
+++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java Fri Dec 15 11:45:40 2017 +0000
@@ -256,6 +256,10 @@
extensions.add(renegotiationInfo);
}
+ void addExtendedMasterSecretExtension() {
+ extensions.add(new ExtendedMasterSecretExtension());
+ }
+
@Override
int messageType() { return ht_client_hello; }
@@ -893,7 +897,7 @@
}
Signature sig = getSignature(privateKey.getAlgorithm());
- sig.initSign(privateKey);
+ sig.initSign(privateKey, sr);
updateSignature(sig, clntNonce, svrNonce);
signatureBytes = sig.sign();
diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/Handshaker.java
--- a/src/share/classes/sun/security/ssl/Handshaker.java Thu Feb 02 20:36:46 2017 +0000
+++ b/src/share/classes/sun/security/ssl/Handshaker.java Fri Dec 15 11:45:40 2017 +0000
@@ -177,9 +177,41 @@
static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty(
"sun.security.ssl.allowLegacyHelloMessages", true);
+ // To switch off the extended_master_secret extension.
+ static final boolean useExtendedMasterSecret;
+
+ // Allow session resumption without Extended Master Secret extension.
+ static final boolean allowLegacyResumption =
+ Debug.getBooleanProperty("jdk.tls.allowLegacyResumption", true);
+
+ // Allow full handshake without Extended Master Secret extension.
+ static final boolean allowLegacyMasterSecret =
+ Debug.getBooleanProperty("jdk.tls.allowLegacyMasterSecret", true);
+
+ // Is it requested to use extended master secret extension?
+ boolean requestedToUseEMS = false;
+
// need to dispose the object when it is invalidated
boolean invalidated;
+ // Is the extended_master_secret extension supported?
+ static {
+ boolean supportExtendedMasterSecret = true;
+ try {
+ KeyGenerator kg =
+ JsseJce.getKeyGenerator("SunTlsExtendedMasterSecret");
+ } catch (NoSuchAlgorithmException nae) {
+ supportExtendedMasterSecret = false;
+ }
+
+ if (supportExtendedMasterSecret) {
+ useExtendedMasterSecret = Debug.getBooleanProperty(
+ "jdk.tls.useExtendedMasterSecret", true);
+ } else {
+ useExtendedMasterSecret = false;
+ }
+ }
+
Handshaker(SSLSocketImpl c, SSLContextImpl context,
ProtocolList enabledProtocols, boolean needCertVerify,
boolean isClient, ProtocolVersion activeProtocolVersion,
@@ -189,7 +221,7 @@
init(context, enabledProtocols, needCertVerify, isClient,
activeProtocolVersion, isInitialHandshake, secureRenegotiation,
clientVerifyData, serverVerifyData);
- }
+ }
Handshaker(SSLEngineImpl engine, SSLContextImpl context,
ProtocolList enabledProtocols, boolean needCertVerify,
@@ -1038,12 +1070,34 @@
* SHA1 hashes are of (different) constant strings, the pre-master
* secret, and the nonces provided by the client and the server.
*/
+ @SuppressWarnings("deprecation")
private SecretKey calculateMasterSecret(SecretKey preMasterSecret,
ProtocolVersion requestedVersion) {
- TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec
- (preMasterSecret, protocolVersion.major, protocolVersion.minor,
- clnt_random.random_bytes, svr_random.random_bytes);
+ TlsMasterSecretParameterSpec spec;
+ String masterAlg;
+ if (session.getUseExtendedMasterSecret()) {
+ // reset to use the extended master secret algorithm
+ masterAlg = "SunTlsExtendedMasterSecret";
+
+ byte[] sessionHash;
+ // TLS 1.0/1.1
+ sessionHash = new byte[36];
+ try {
+ handshakeHash.getMD5Clone().digest(sessionHash, 0, 16);
+ handshakeHash.getSHAClone().digest(sessionHash, 16, 20);
+ } catch (DigestException de) {
+ throw new ProviderException(de);
+ }
+
+ spec = new TlsMasterSecretParameterSpec(
+ preMasterSecret, protocolVersion.major, protocolVersion.minor, sessionHash);
+ } else {
+ masterAlg = "SunTlsMasterSecret";
+ spec = new TlsMasterSecretParameterSpec(
+ preMasterSecret, protocolVersion.major, protocolVersion.minor,
+ clnt_random.random_bytes, svr_random.random_bytes);
+ }
if (debug != null && Debug.isOn("keygen")) {
HexDumpEncoder dump = new HexDumpEncoder();
@@ -1058,7 +1112,7 @@
}
try {
- KeyGenerator kg = JsseJce.getKeyGenerator("SunTlsMasterSecret");
+ KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg);
kg.init(spec);
return kg.generateKey();
} catch (InvalidAlgorithmParameterException e) {
diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/HelloExtensions.java
--- a/src/share/classes/sun/security/ssl/HelloExtensions.java Thu Feb 02 20:36:46 2017 +0000
+++ b/src/share/classes/sun/security/ssl/HelloExtensions.java Fri Dec 15 11:45:40 2017 +0000
@@ -94,6 +94,8 @@
new SupportedEllipticPointFormatsExtension(s, extlen);
} else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
extension = new RenegotiationInfoExtension(s, extlen);
+ } else if (extType == ExtensionType.EXT_EXTENDED_MASTER_SECRET) {
+ extension = new ExtendedMasterSecretExtension(s, extlen);
} else {
extension = new UnknownExtension(s, extlen, extType);
}
@@ -176,7 +178,7 @@
}
static List