# 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 knownExtensions = - new ArrayList(9); + new ArrayList(14); static ExtensionType get(int id) { for (ExtensionType ext : knownExtensions) { @@ -229,6 +231,10 @@ 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 -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/SSLSessionImpl.java --- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/sun/security/ssl/SSLSessionImpl.java Fri Dec 15 11:45:40 2017 +0000 @@ -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 @@ -92,6 +92,7 @@ private byte compressionMethod; private final CipherSuite cipherSuite; private SecretKey masterSecret; + private final boolean useExtendedMasterSecret; /* * Information not part of the SSLv3 protocol spec, but used @@ -142,7 +143,7 @@ */ private SSLSessionImpl() { this(ProtocolVersion.NONE, CipherSuite.C_NULL, - new SessionId(false, null), null, -1); + new SessionId(false, null), null, -1, false); } /* @@ -151,16 +152,18 @@ * is intended mostly for use by serves. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, - SecureRandom generator, String host, int port) { + SecureRandom generator, String host, int port, + boolean useExtendedMasterSecret) { this(protocolVersion, cipherSuite, - new SessionId(defaultRejoinable, generator), host, port); + new SessionId(defaultRejoinable, generator), host, port, useExtendedMasterSecret); } /* * Record a new session, using a given cipher spec and session ID. */ SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, - SessionId id, String host, int port) { + SessionId id, String host, int port, + boolean useExtendedMasterSecret) { this.protocolVersion = protocolVersion; sessionId = id; peerCerts = null; @@ -170,6 +173,7 @@ this.host = host; this.port = port; sessionCount = ++counter; + this.useExtendedMasterSecret = useExtendedMasterSecret; if (debug != null && Debug.isOn("session")) { System.out.println("%% Created: " + this); @@ -191,6 +195,10 @@ return masterSecret; } + boolean getUseExtendedMasterSecret() { + return useExtendedMasterSecret; + } + void setPeerCertificates(X509Certificate[] peer) { if (peerCerts == null) { peerCerts = peer; diff -r 160b59f43c34 -r 65141d41e005 src/share/classes/sun/security/ssl/ServerHandshaker.java --- a/src/share/classes/sun/security/ssl/ServerHandshaker.java Thu Feb 02 20:36:46 2017 +0000 +++ b/src/share/classes/sun/security/ssl/ServerHandshaker.java Fri Dec 15 11:45:40 2017 +0000 @@ -292,6 +292,11 @@ ("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. @@ -466,6 +471,27 @@ } } + // 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. @@ -538,8 +564,42 @@ 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; + } } } @@ -642,7 +702,9 @@ chooseCipherSuite(mesg); session = new SSLSessionImpl(protocolVersion, cipherSuite, sslContext.getSecureRandom(), - getHostAddressSE(), getPortSE()); + getHostAddressSE(), getPortSE(), + (requestedToUseEMS && + (protocolVersion.v >= ProtocolVersion.TLS10.v))); session.setLocalPrivateKey(privateKey); // chooseCompression(mesg); } @@ -666,6 +728,10 @@ m1.extensions.add(serverHelloRI); } + 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 -r 160b59f43c34 -r 65141d41e005 test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java --- a/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java Thu Feb 02 20:36:46 2017 +0000 +++ b/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java Fri Dec 15 11:45:40 2017 +0000 @@ -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.*;