From 93e5849d598f60781426cd9678c4f121483e8e13 Mon Sep 17 00:00:00 2001 From: pkoppula Date: Fri, 15 Dec 2017 11:45:40 +0000 Subject: [PATCH] 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 --- .../com/sun/crypto/provider/SunJCE.java | 4 +- .../provider/TlsMasterSecretGenerator.java | 31 +++-- .../sun/crypto/provider/TlsPrfGenerator.java | 7 +- .../spec/TlsMasterSecretParameterSpec.java | 61 +++++++++- .../sun/security/ssl/ClientHandshaker.java | 108 +++++++++++++++++- .../ssl/ExtendedMasterSecretExtension.java | 70 ++++++++++++ .../sun/security/ssl/ExtensionType.java | 6 +- .../sun/security/ssl/HandshakeMessage.java | 6 +- .../classes/sun/security/ssl/Handshaker.java | 73 ++++++++++-- .../sun/security/ssl/HelloExtensions.java | 2 + .../sun/security/ssl/SSLSessionImpl.java | 19 ++- .../sun/security/ssl/ServerHandshaker.java | 70 +++++++++++- .../ssl/DHKeyExchange/DHEKeySizing.java | 34 +++--- 13 files changed, 437 insertions(+), 54 deletions(-) create mode 100644 src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java diff --git a/src/share/classes/com/sun/crypto/provider/SunJCE.java b/src/share/classes/com/sun/crypto/provider/SunJCE.java index 08e1e2ae7..55c55e2de 100644 --- a/src/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, 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 @@ -762,6 +762,8 @@ public final class SunJCE extends Provider { "com.sun.crypto.provider.TlsMasterSecretGenerator"); put("Alg.Alias.KeyGenerator.SunTls12MasterSecret", "SunTlsMasterSecret"); + put("Alg.Alias.KeyGenerator.SunTlsExtendedMasterSecret", + "SunTlsMasterSecret"); put("KeyGenerator.SunTlsKeyMaterial", "com.sun.crypto.provider.TlsKeyMaterialGenerator"); diff --git a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java index 0efa0aef9..9a6308f34 100644 --- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java @@ -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 @@ -100,21 +100,32 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi { try { byte[] master; - byte[] clientRandom = spec.getClientRandom(); - byte[] serverRandom = spec.getServerRandom(); - if (protocolVersion >= 0x0301) { - byte[] seed = concat(clientRandom, serverRandom); + 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 = ((protocolVersion >= 0x0303) ? - doTLS12PRF(premaster, LABEL_MASTER_SECRET, seed, 48, - spec.getPRFHashAlg(), spec.getPRFHashLength(), - spec.getPRFBlockSize()) : - doTLS10PRF(premaster, LABEL_MASTER_SECRET, seed, 48)); + doTLS12PRF(premaster, label, seed, 48, + spec.getPRFHashAlg(), spec.getPRFHashLength(), + spec.getPRFBlockSize()) : + doTLS10PRF(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]); @@ -172,5 +183,5 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi { } } - } + diff --git a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java index f09b7d875..a84083947 100644 --- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java +++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java @@ -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 @@ -55,6 +55,11 @@ abstract class TlsPrfGenerator extends KeyGeneratorSpi { 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 --git a/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java index 832b38edd..e56336048 100644 --- a/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java +++ b/src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java @@ -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 @@ -48,6 +48,7 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec { private final SecretKey premasterSecret; private final int majorVersion, minorVersion; private final byte[] clientRandom, serverRandom; + private final byte[] extendedMasterSecretSessionHash; private final String prfHashAlg; private final int prfHashLength; private final int prfBlockSize; @@ -80,6 +81,50 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec { int majorVersion, int minorVersion, byte[] clientRandom, byte[] serverRandom, String prfHashAlg, int prfHashLength, int prfBlockSize) { + this(premasterSecret, majorVersion, minorVersion, + clientRandom, serverRandom, + new byte[0], + prfHashAlg, prfHashLength, prfBlockSize); + } + + /** + * 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 + * @param prfHashAlg the name of the TLS PRF hash algorithm to use. + * Used only for TLS 1.2+. TLS1.1 and earlier use a fixed PRF. + * @param prfHashLength the output length of the TLS PRF hash algorithm. + * Used only for TLS 1.2+. + * @param prfBlockSize the input block size of the TLS PRF hash algorithm. + * Used only for TLS 1.2+. + * + * @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, + String prfHashAlg, int prfHashLength, int prfBlockSize) { + this(premasterSecret, majorVersion, minorVersion, + new byte[0], new byte[0], + extendedMasterSecretSessionHash, + prfHashAlg, prfHashLength, prfBlockSize); + } + + private TlsMasterSecretParameterSpec(SecretKey premasterSecret, + int majorVersion, int minorVersion, + byte[] clientRandom, byte[] serverRandom, + byte[] extendedMasterSecretSessionHash, + String prfHashAlg, int prfHashLength, int prfBlockSize) { if (premasterSecret == null) { throw new NullPointerException("premasterSecret must not be null"); } @@ -88,6 +133,9 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec { this.minorVersion = checkVersion(minorVersion); this.clientRandom = clientRandom.clone(); this.serverRandom = serverRandom.clone(); + this.extendedMasterSecretSessionHash = + (extendedMasterSecretSessionHash != null ? + extendedMasterSecretSessionHash.clone() : new byte[0]); this.prfHashAlg = prfHashAlg; this.prfHashLength = prfHashLength; this.prfBlockSize = prfBlockSize; @@ -146,6 +194,17 @@ public class TlsMasterSecretParameterSpec implements AlgorithmParameterSpec { 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(); + } + /** * Obtains the PRF hash algorithm to use in the PRF calculation. * diff --git a/src/share/classes/sun/security/ssl/ClientHandshaker.java b/src/share/classes/sun/security/ssl/ClientHandshaker.java index 73dc663a2..7edef24c4 100644 --- a/src/share/classes/sun/security/ssl/ClientHandshaker.java +++ b/src/share/classes/sun/security/ssl/ClientHandshaker.java @@ -633,6 +633,54 @@ final class ClientHandshaker extends Handshaker { } } + // 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"); + } + } + } + if (resumingSession && session != null) { setHandshakeSessionSE(session); // Reserve the handshake state if this is a session-resumption @@ -652,7 +700,8 @@ final class ClientHandshaker extends Handshaker { } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) && (type != ExtensionType.EXT_EC_POINT_FORMATS) && (type != ExtensionType.EXT_SERVER_NAME) - && (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); } @@ -661,7 +710,8 @@ final class ClientHandshaker extends Handshaker { // Create a new session, we need to do the full handshake session = new SSLSessionImpl(protocolVersion, cipherSuite, getLocalSupportedSignAlgs(), - mesg.sessionId, getHostSE(), getPortSE()); + mesg.sessionId, getHostSE(), getPortSE(), + (extendedMasterSecretExt != null)); session.setRequestedServerNames(requestedServerNames); setHandshakeSessionSE(session); if (debug != null && Debug.isOn("handshake")) { @@ -1297,6 +1347,44 @@ final class ClientHandshaker extends Handshaker { 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) { + // It is fine to move on with abbreviate handshake if + // endpoint identification is enabled. + String identityAlg = getEndpointIdentificationAlgorithmSE(); + if ((identityAlg == null || identityAlg.length() == 0)) { + 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")) { @@ -1403,6 +1491,14 @@ final class ClientHandshaker extends Handshaker { clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs); } + // add Extended Master Secret extension + if (useExtendedMasterSecret && (maxProtocolVersion.v >= ProtocolVersion.TLS10.v)) { + if ((session == null) || session.getUseExtendedMasterSecret()) { + clientHelloMessage.addExtendedMasterSecretExtension(); + requestedToUseEMS = true; + } + } + // add server_name extension if (enableSNIExtension) { if (session != null) { @@ -1463,10 +1559,14 @@ final class ClientHandshaker extends Handshaker { // Allow server certificate change in client side during renegotiation // after a session-resumption abbreviated initial handshake? // - // DO NOT need to check allowUnsafeServerCertChange here. We only + // DO NOT need to check allowUnsafeServerCertChange here. We only // reserve server certificates when allowUnsafeServerCertChange is // flase. - if (reservedServerCerts != null) { + // + // Allow server certificate change if it is negotiated to use the + // extended master secret. + if ((reservedServerCerts != null) && + !session.getUseExtendedMasterSecret()) { // It is not necessary to check the certificate update if endpoint // identification is enabled. String identityAlg = getEndpointIdentificationAlgorithmSE(); diff --git a/src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java b/src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java new file mode 100644 index 000000000..bf7f7aefd --- /dev/null +++ b/src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java @@ -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 --git a/src/share/classes/sun/security/ssl/ExtensionType.java b/src/share/classes/sun/security/ssl/ExtensionType.java index 99de20a6c..4c5dcf252 100644 --- a/src/share/classes/sun/security/ssl/ExtensionType.java +++ b/src/share/classes/sun/security/ssl/ExtensionType.java @@ -43,7 +43,7 @@ final class ExtensionType { return name; } - static List knownExtensions = new ArrayList(9); + static List knownExtensions = new ArrayList(14); static ExtensionType get(int id) { for (ExtensionType ext : knownExtensions) { @@ -96,6 +96,10 @@ final class ExtensionType { final static ExtensionType EXT_SIGNATURE_ALGORITHMS = e(0x000D, "signature_algorithms"); // IANA registry value: 13 + // extensions defined in RFC 7627 + static final ExtensionType EXT_EXTENDED_MASTER_SECRET = + e(0x0017, "extended_master_secret"); // IANA registry value: 23 + // extensions defined in RFC 5746 final static ExtensionType EXT_RENEGOTIATION_INFO = e(0xff01, "renegotiation_info"); // IANA registry value: 65281 diff --git a/src/share/classes/sun/security/ssl/HandshakeMessage.java b/src/share/classes/sun/security/ssl/HandshakeMessage.java index 3ee8ab223..976b76e6f 100644 --- a/src/share/classes/sun/security/ssl/HandshakeMessage.java +++ b/src/share/classes/sun/security/ssl/HandshakeMessage.java @@ -274,6 +274,10 @@ static final class ClientHello extends HandshakeMessage { extensions.add(signatureAlgorithm); } + void addExtendedMasterSecretExtension() { + extensions.add(new ExtendedMasterSecretExtension()); + } + @Override int messageType() { return ht_client_hello; } @@ -1024,7 +1028,7 @@ class ECDH_ServerKeyExchange extends ServerKeyExchange { } else { sig = getSignature(privateKey.getAlgorithm()); } - sig.initSign(privateKey); // where is the SecureRandom? + sig.initSign(privateKey, sr); updateSignature(sig, clntNonce, svrNonce); signatureBytes = sig.sign(); diff --git a/src/share/classes/sun/security/ssl/Handshaker.java b/src/share/classes/sun/security/ssl/Handshaker.java index e15f1918d..8e570c404 100644 --- a/src/share/classes/sun/security/ssl/Handshaker.java +++ b/src/share/classes/sun/security/ssl/Handshaker.java @@ -29,12 +29,6 @@ package sun.security.ssl; import java.io.*; import java.util.*; import java.security.*; -import java.security.NoSuchAlgorithmException; -import java.security.AccessController; -import java.security.AlgorithmConstraints; -import java.security.AccessControlContext; -import java.security.PrivilegedExceptionAction; -import java.security.PrivilegedActionException; import javax.crypto.*; import javax.crypto.spec.*; @@ -204,9 +198,41 @@ abstract class Handshaker { Debug.getBooleanProperty( "jdk.tls.rejectClientInitiatedRenegotiation", false); + // 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, @@ -216,7 +242,7 @@ abstract class Handshaker { init(context, enabledProtocols, needCertVerify, isClient, activeProtocolVersion, isInitialHandshake, secureRenegotiation, clientVerifyData, serverVerifyData); - } + } Handshaker(SSLEngineImpl engine, SSLContextImpl context, ProtocolList enabledProtocols, boolean needCertVerify, @@ -1169,6 +1195,7 @@ abstract class Handshaker { * 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) { @@ -1200,10 +1227,34 @@ abstract class Handshaker { int prfHashLength = prf.getPRFHashLength(); int prfBlockSize = prf.getPRFBlockSize(); - TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec( - preMasterSecret, protocolVersion.major, protocolVersion.minor, - clnt_random.random_bytes, svr_random.random_bytes, - prfHashAlg, prfHashLength, prfBlockSize); + TlsMasterSecretParameterSpec spec; + if (session.getUseExtendedMasterSecret()) { + // reset to use the extended master secret algorithm + masterAlg = "SunTlsExtendedMasterSecret"; + + byte[] sessionHash = null; + if (protocolVersion.v >= ProtocolVersion.TLS12.v) { + sessionHash = handshakeHash.getFinishedHash(); + } else { + // 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, prfHashAlg, prfHashLength, prfBlockSize); + } else { + spec = new TlsMasterSecretParameterSpec( + preMasterSecret, protocolVersion.major, protocolVersion.minor, + clnt_random.random_bytes, svr_random.random_bytes, + prfHashAlg, prfHashLength, prfBlockSize); + } try { KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg); diff --git a/src/share/classes/sun/security/ssl/HelloExtensions.java b/src/share/classes/sun/security/ssl/HelloExtensions.java index ddd53d1d9..4fd03aaf0 100644 --- a/src/share/classes/sun/security/ssl/HelloExtensions.java +++ b/src/share/classes/sun/security/ssl/HelloExtensions.java @@ -84,6 +84,8 @@ final class HelloExtensions { extension = new EllipticPointFormatsExtension(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); } diff --git a/src/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/share/classes/sun/security/ssl/SSLSessionImpl.java index b5f304b6b..d96cde620 100644 --- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -91,6 +91,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { private byte compressionMethod; private CipherSuite cipherSuite; private SecretKey masterSecret; + private final boolean useExtendedMasterSecret; /* * Information not part of the SSLv3 protocol spec, but used @@ -145,7 +146,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { */ private SSLSessionImpl() { this(ProtocolVersion.NONE, CipherSuite.C_NULL, null, - new SessionId(false, null), null, -1); + new SessionId(false, null), null, -1, false); } /* @@ -155,9 +156,11 @@ final class SSLSessionImpl extends ExtendedSSLSession { */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection algorithms, - SecureRandom generator, String host, int port) { + SecureRandom generator, String host, int port, + boolean useExtendedMasterSecret) { this(protocolVersion, cipherSuite, algorithms, - new SessionId(defaultRejoinable, generator), host, port); + new SessionId(defaultRejoinable, generator), host, port, + useExtendedMasterSecret); } /* @@ -165,7 +168,8 @@ final class SSLSessionImpl extends ExtendedSSLSession { */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection algorithms, - SessionId id, String host, int port) { + SessionId id, String host, int port, + boolean useExtendedMasterSecret) { this.protocolVersion = protocolVersion; sessionId = id; peerCerts = null; @@ -177,6 +181,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { sessionCount = ++counter; localSupportedSignAlgs = SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); + this.useExtendedMasterSecret = useExtendedMasterSecret; if (debug != null && Debug.isOn("session")) { System.out.println("%% Initialized: " + this); @@ -198,6 +203,10 @@ final class SSLSessionImpl extends ExtendedSSLSession { return masterSecret; } + boolean getUseExtendedMasterSecret() { + return useExtendedMasterSecret; + } + void setPeerCertificates(X509Certificate[] peer) { if (peerCerts == null) { peerCerts = peer; diff --git a/src/share/classes/sun/security/ssl/ServerHandshaker.java b/src/share/classes/sun/security/ssl/ServerHandshaker.java index b863db3ff..2652bcc2b 100644 --- a/src/share/classes/sun/security/ssl/ServerHandshaker.java +++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java @@ -289,6 +289,11 @@ final class ServerHandshaker extends Handshaker { ("Unrecognized key exchange: " + keyExchange); } + // Need to add the hash for RFC 7627. + if (session.getUseExtendedMasterSecret()) { + input.digestNow(); + } + // // All keys are calculated from the premaster secret // and the exchanged nonces in the same way. @@ -495,6 +500,27 @@ final class ServerHandshaker extends Handshaker { } } + // check out the "extended_master_secret" extension + if (useExtendedMasterSecret) { + ExtendedMasterSecretExtension extendedMasterSecretExtension = + (ExtendedMasterSecretExtension)mesg.extensions.get( + ExtensionType.EXT_EXTENDED_MASTER_SECRET); + if (extendedMasterSecretExtension != null) { + requestedToUseEMS = true; + } else if (mesg.protocolVersion.v >= ProtocolVersion.TLS10.v) { + if (!allowLegacyMasterSecret) { + // For full handshake, if the server receives a ClientHello + // without the extension, it SHOULD abort the handshake if + // it does not wish to interoperate with legacy clients. + // + // As if extended master extension is required for full + // handshake, it MUST be used in abbreviated handshake too. + fatalSE(Alerts.alert_handshake_failure, + "Extended Master Secret extension is required"); + } + } + } + /* * Always make sure this entire record has been digested before we * start emitting output, to ensure correct digesting order. @@ -569,11 +595,45 @@ final class ServerHandshaker extends Handshaker { if (resumingSession) { ProtocolVersion oldVersion = previous.getProtocolVersion(); // cannot resume session with different version - if (oldVersion != protocolVersion) { + if (oldVersion != mesg.protocolVersion) { resumingSession = false; } } + if (resumingSession && useExtendedMasterSecret) { + if (requestedToUseEMS && + !previous.getUseExtendedMasterSecret()) { + // For abbreviated handshake request, If the original + // session did not use the "extended_master_secret" + // extension but the new ClientHello contains the + // extension, then the server MUST NOT perform the + // abbreviated handshake. Instead, it SHOULD continue + // with a full handshake. + resumingSession = false; + } else if (!requestedToUseEMS && + previous.getUseExtendedMasterSecret()) { + // For abbreviated handshake request, if the original + // session used the "extended_master_secret" extension + // but the new ClientHello does not contain it, the + // server MUST abort the abbreviated handshake. + fatalSE(Alerts.alert_handshake_failure, + "Missing Extended Master Secret extension " + + "on session resumption"); + } else if (!requestedToUseEMS && + !previous.getUseExtendedMasterSecret()) { + // For abbreviated handshake request, if neither the + // original session nor the new ClientHello uses the + // extension, the server SHOULD abort the handshake. + if (!allowLegacyResumption) { + fatalSE(Alerts.alert_handshake_failure, + "Missing Extended Master Secret extension " + + "on session resumption"); + } else { // Otherwise, continue with a full handshake. + resumingSession = false; + } + } + } + // cannot resume session with different server name indication if (resumingSession) { List oldServerNames = @@ -720,7 +780,9 @@ final class ServerHandshaker extends Handshaker { session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL, getLocalSupportedSignAlgs(), sslContext.getSecureRandom(), - getHostAddressSE(), getPortSE()); + getHostAddressSE(), getPortSE(), + (requestedToUseEMS && + (protocolVersion.v >= ProtocolVersion.TLS10.v))); if (protocolVersion.v >= ProtocolVersion.TLS12.v) { if (peerSupportedSignAlgs != null) { @@ -785,6 +847,10 @@ final class ServerHandshaker extends Handshaker { } } + if (session.getUseExtendedMasterSecret()) { + m1.extensions.add(new ExtendedMasterSecretExtension()); + } + if (debug != null && Debug.isOn("handshake")) { m1.print(System.out); System.out.println("Cipher suite: " + session.getSuite()); diff --git a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java index ddf260b15..1b332c000 100644 --- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java @@ -31,34 +31,34 @@ * @bug 6956398 * @summary make ephemeral DH key match the length of the certificate key * @run main/othervm - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75 + * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1259 75 * * @run main/othervm - * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 229 75 + * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 233 75 * * @run main/othervm - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1387 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1319 107 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1323 107 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1639 267 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1643 267 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139 + * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1387 139 * * @run main/othervm - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 361 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 293 107 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 297 107 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 361 139 * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024 - * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139 + * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 361 139 */ /* @@ -90,10 +90,10 @@ * Here is a summary of the record length in the test case. * * | ServerHello Series | ClientKeyExchange | ServerHello Anon - * 512-bit | 1255 bytes | 75 bytes | 229 bytes - * 768-bit | 1319 bytes | 107 bytes | 293 bytes - * 1024-bit | 1383 bytes | 139 bytes | 357 bytes - * 2048-bit | 1639 bytes | 267 bytes | 357 bytes + * 512-bit | 1259 bytes | 75 bytes | 233 bytes + * 768-bit | 1323 bytes | 107 bytes | 297 bytes + * 1024-bit | 1387 bytes | 139 bytes | 361 bytes + * 2048-bit | 1643 bytes | 267 bytes | 361 bytes */ import javax.net.ssl.*; -- GitLab