8148421: Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension
authorxuelei
Fri, 08 Dec 2017 16:41:30 +0000
changeset 48225 718669e6b375
parent 48224 be0df5ab3093
child 48226 ea47055160ef
8148421: Transport Layer Security (TLS) Session Hash and Extended Master Secret Extension Reviewed-by: jnimeh, ahgross, rhalade, wetmore Contributed-by: Martin Balao <mbalao@redhat.com>, Xuelei Fan <xuelei.fan@oracle.com>
src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java
src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
src/java.base/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java
src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java
src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java
src/java.base/share/classes/sun/security/ssl/ExtensionType.java
src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java
src/java.base/share/classes/sun/security/ssl/Handshaker.java
src/java.base/share/classes/sun/security/ssl/HelloExtensions.java
src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java
src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java
test/jdk/javax/net/ssl/DTLS/NoMacInitialClientHello.java
test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java
test/jdk/sun/security/ssl/ExtensionType/OptimalListSize.java
--- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java	Fri Dec 08 16:41:30 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, 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
@@ -769,6 +769,8 @@
                         "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");
--- a/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java	Fri Dec 08 16:41:30 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
@@ -102,21 +102,32 @@
 
         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]);
@@ -175,5 +186,5 @@
         }
 
     }
+}
 
-}
--- a/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java	Fri Dec 08 16:41:30 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
@@ -55,6 +55,11 @@
     static final byte[] LABEL_MASTER_SECRET = // "master secret"
         { 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 };
 
+    static final 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 };
+
     static final byte[] LABEL_KEY_EXPANSION = // "key expansion"
         { 107, 101, 121, 32, 101, 120, 112, 97, 110, 115, 105, 111, 110 };
 
--- a/src/java.base/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java	Fri Dec 08 16:41:30 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
@@ -48,6 +48,7 @@
     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 @@
             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.
+     *
+     * <p>The <code>getAlgorithm()</code> method of <code>premasterSecret</code>
+     * should return <code>"TlsRsaPremasterSecret"</code> if the key exchange
+     * algorithm was RSA and <code>"TlsPremasterSecret"</code> 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 @@
         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;
@@ -147,6 +195,17 @@
     }
 
     /**
+     * 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.
      *
      * @return the hash algorithm.
--- a/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Fri Dec 08 16:41:30 2017 +0000
@@ -655,7 +655,8 @@
 
                 // validate subject identity
                 ClientKeyExchangeService p =
-                        ClientKeyExchangeService.find(sessionSuite.keyExchange.name);
+                        ClientKeyExchangeService.find(
+                                sessionSuite.keyExchange.name);
                 if (p != null) {
                     Principal localPrincipal = session.getLocalPrincipal();
 
@@ -663,8 +664,9 @@
                         if (debug != null && Debug.isOn("session"))
                             System.out.println("Subject identity is same");
                     } else {
-                        throw new SSLProtocolException("Server resumed" +
-                                " session with wrong subject identity or no subject");
+                        throw new SSLProtocolException(
+                                "Server resumed session with " +
+                                "wrong subject identity or no subject");
                     }
                 }
 
@@ -707,6 +709,54 @@
         }   // Otherwise, using the value negotiated during the original
             // session initiation
 
+        // 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.useTLS10PlusSpec() || !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 the ALPN extension
         ALPNExtension serverHelloALPN =
             (ALPNExtension) mesg.extensions.get(ExtensionType.EXT_ALPN);
@@ -777,7 +827,8 @@
                     && (type != ExtensionType.EXT_ALPN)
                     && (type != ExtensionType.EXT_RENEGOTIATION_INFO)
                     && (type != ExtensionType.EXT_STATUS_REQUEST)
-                    && (type != ExtensionType.EXT_STATUS_REQUEST_V2)) {
+                    && (type != ExtensionType.EXT_STATUS_REQUEST_V2)
+                    && (type != ExtensionType.EXT_EXTENDED_MASTER_SECRET)) {
                 // Note: Better to check client requested extensions rather
                 // than all supported extensions.
                 fatalSE(Alerts.alert_unsupported_extension,
@@ -788,7 +839,8 @@
         // 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);
         session.setNegotiatedMaxFragSize(requestedMFLength);
         session.setMaximumPacketSize(maximumPacketSize);
@@ -1430,6 +1482,44 @@
                 session = null;
             }
 
+            if ((session != null) && useExtendedMasterSecret) {
+                boolean isTLS10Plus = sessionVersion.useTLS10PlusSpec();
+                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")) {
@@ -1539,6 +1629,14 @@
             clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs);
         }
 
+        // add Extended Master Secret extension
+        if (useExtendedMasterSecret && maxProtocolVersion.useTLS10PlusSpec()) {
+            if ((session == null) || session.getUseExtendedMasterSecret()) {
+                clientHelloMessage.addExtendedMasterSecretExtension();
+                requestedToUseEMS = true;
+            }
+        }
+
         // add server_name extension
         if (enableSNIExtension) {
             if (session != null) {
@@ -1647,10 +1745,14 @@
         // 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();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java	Fri Dec 08 16:41:30 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
+ * <a href="https://tools.ietf.org/html/rfc7627">RFC 7627</a>.
+ *
+ * @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;
+    }
+}
+
--- a/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Fri Dec 08 16:41:30 2017 +0000
@@ -43,7 +43,7 @@
         return name;
     }
 
-    static List<ExtensionType> knownExtensions = new ArrayList<>(15);
+    static List<ExtensionType> knownExtensions = new ArrayList<>(16);
 
     static ExtensionType get(int id) {
         for (ExtensionType ext : knownExtensions) {
@@ -105,6 +105,10 @@
     static final ExtensionType EXT_STATUS_REQUEST_V2 =
             e(0x0011, "status_request_v2");      // IANA registry value: 17
 
+    // 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
     static final ExtensionType EXT_RENEGOTIATION_INFO =
             e(0xff01, "renegotiation_info");     // IANA registry value: 65281
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Fri Dec 08 16:41:30 2017 +0000
@@ -389,6 +389,10 @@
         extensions.add(signatureAlgorithm);
     }
 
+    void addExtendedMasterSecretExtension() {
+        extensions.add(new ExtendedMasterSecretExtension());
+    }
+
     void addMFLExtension(int maximumPacketSize) {
         HelloExtension maxFragmentLength =
                 new MaxFragmentLengthExtension(maximumPacketSize);
@@ -1441,7 +1445,7 @@
         } else {
             sig = getSignature(privateKey.getAlgorithm());
         }
-        sig.initSign(privateKey);  // where is the SecureRandom?
+        sig.initSign(privateKey, sr);
 
         updateSignature(sig, clntNonce, svrNonce);
         signatureBytes = sig.sign();
--- a/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Fri Dec 08 16:41:30 2017 +0000
@@ -30,12 +30,6 @@
 import java.util.*;
 import java.security.*;
 import java.nio.ByteBuffer;
-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 java.util.function.BiFunction;
 
 import javax.crypto.*;
@@ -225,6 +219,20 @@
             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;
 
@@ -233,6 +241,24 @@
      */
     final boolean isDTLS;
 
+    // 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,
@@ -243,7 +269,7 @@
         init(context, enabledProtocols, needCertVerify, isClient,
             activeProtocolVersion, isInitialHandshake, secureRenegotiation,
             clientVerifyData, serverVerifyData);
-    }
+   }
 
     Handshaker(SSLEngineImpl engine, SSLContextImpl context,
             ProtocolList enabledProtocols, boolean needCertVerify,
@@ -1226,6 +1252,7 @@
      * 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) {
 
@@ -1276,11 +1303,37 @@
         int prfHashLength = prf.getPRFHashLength();
         int prfBlockSize = prf.getPRFBlockSize();
 
-        @SuppressWarnings("deprecation")
-        TlsMasterSecretParameterSpec spec = new TlsMasterSecretParameterSpec(
-                preMasterSecret, (majorVersion & 0xFF), (minorVersion & 0xFF),
-                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.useTLS12PlusSpec()) {
+                sessionHash = handshakeHash.getFinishedHash();
+            } else {
+                // TLS 1.0/1.1, DTLS 1.0
+                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,
+                    (majorVersion & 0xFF), (minorVersion & 0xFF),
+                    sessionHash,
+                    prfHashAlg, prfHashLength, prfBlockSize);
+        } else {
+            spec = new TlsMasterSecretParameterSpec(
+                    preMasterSecret,
+                    (majorVersion & 0xFF), (minorVersion & 0xFF),
+                    clnt_random.random_bytes, svr_random.random_bytes,
+                    prfHashAlg, prfHashLength, prfBlockSize);
+        }
 
         try {
             KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg);
--- a/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Fri Dec 08 16:41:30 2017 +0000
@@ -93,6 +93,8 @@
                 extension = new CertStatusReqExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_STATUS_REQUEST_V2) {
                 extension = new CertStatusReqListV2Extension(s, extlen);
+            } else if (extType == ExtensionType.EXT_EXTENDED_MASTER_SECRET) {
+                extension = new ExtendedMasterSecretExtension(s, extlen);
             } else {
                 extension = new UnknownExtension(s, extlen, extType);
             }
--- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java	Fri Dec 08 16:41:30 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, 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 @@
     private byte                compressionMethod;
     private CipherSuite         cipherSuite;
     private SecretKey           masterSecret;
+    private final boolean       useExtendedMasterSecret;
 
     /*
      * Information not part of the SSLv3 protocol spec, but used
@@ -148,7 +149,7 @@
      */
     private SSLSessionImpl() {
         this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
-            new SessionId(false, null), null, -1);
+            new SessionId(false, null), null, -1, false);
     }
 
     /*
@@ -158,9 +159,11 @@
      */
     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
             Collection<SignatureAndHashAlgorithm> 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);
     }
 
     /*
@@ -168,7 +171,8 @@
      */
     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
             Collection<SignatureAndHashAlgorithm> algorithms,
-            SessionId id, String host, int port) {
+            SessionId id, String host, int port,
+            boolean useExtendedMasterSecret) {
         this.protocolVersion = protocolVersion;
         sessionId = id;
         peerCerts = null;
@@ -182,6 +186,7 @@
             SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
         negotiatedMaxFragLen = -1;
         statusResponses = null;
+        this.useExtendedMasterSecret = useExtendedMasterSecret;
 
         if (debug != null && Debug.isOn("session")) {
             System.out.println("%% Initialized:  " + this);
@@ -203,6 +208,10 @@
         return masterSecret;
     }
 
+    boolean getUseExtendedMasterSecret() {
+        return useExtendedMasterSecret;
+    }
+
     void setPeerCertificates(X509Certificate[] peer) {
         if (peerCerts == null) {
             peerCerts = peer;
--- a/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Fri Dec 08 16:41:30 2017 +0000
@@ -529,6 +529,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.useTLS10PlusSpec()) {
+                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");
+                }
+            }
+        }
+
         // check the ALPN extension
         ALPNExtension clientHelloALPN = (ALPNExtension)
             mesg.extensions.get(ExtensionType.EXT_ALPN);
@@ -592,8 +613,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;
+                        }
                     }
                 }
 
@@ -630,7 +685,7 @@
                 if (resumingSession) {
                     CipherSuite suite = previous.getSuite();
                     ClientKeyExchangeService p =
-                            ClientKeyExchangeService.find(suite.keyExchange.name);
+                        ClientKeyExchangeService.find(suite.keyExchange.name);
                     if (p != null) {
                         Principal localPrincipal = previous.getLocalPrincipal();
 
@@ -784,7 +839,9 @@
             session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL,
                         getLocalSupportedSignAlgs(),
                         sslContext.getSecureRandom(),
-                        getHostAddressSE(), getPortSE());
+                        getHostAddressSE(), getPortSE(),
+                        (requestedToUseEMS &&
+                                protocolVersion.useTLS10PlusSpec()));
 
             if (protocolVersion.useTLS12PlusSpec()) {
                 if (peerSupportedSignAlgs != null) {
@@ -886,6 +943,10 @@
             m1.extensions.add(maxFragLenExt);
         }
 
+        if (session.getUseExtendedMasterSecret()) {
+            m1.extensions.add(new ExtendedMasterSecretExtension());
+        }
+
         StaplingParameters staplingParams = processStapling(mesg);
         if (staplingParams != null) {
             // We now can safely assert status_request[_v2] in our
@@ -963,7 +1024,8 @@
          * defined in the protocol spec are explicitly stated to require
          * using RSA certificates.
          */
-        if (ClientKeyExchangeService.find(cipherSuite.keyExchange.name) != null) {
+        if (ClientKeyExchangeService.find(
+                cipherSuite.keyExchange.name) != null) {
             // No external key exchange provider needs a cert now.
         } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) {
             if (certs == null) {
--- a/test/jdk/javax/net/ssl/DTLS/NoMacInitialClientHello.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/test/jdk/javax/net/ssl/DTLS/NoMacInitialClientHello.java	Fri Dec 08 16:41:30 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -44,6 +44,7 @@
     boolean needInvalidRecords = true;
 
     public static void main(String[] args) throws Exception {
+        System.setProperty("jdk.tls.useExtendedMasterSecret", "false");
         NoMacInitialClientHello testCase = new NoMacInitialClientHello();
         testCase.runTest(testCase);
     }
--- a/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/test/jdk/sun/security/ssl/DHKeyExchange/DHEKeySizing.java	Fri Dec 08 16:41:30 2017 +0000
@@ -31,45 +31,45 @@
  * @bug 6956398
  * @summary make ephemeral DH key match the length of the certificate key
  * @run main/othervm
- *      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 -Djsse.enableFFDHE=false
- *      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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
- *      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 -Djsse.enableFFDHE=false
- *      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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
- *      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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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 -Djsse.enableFFDHE=false
  *      -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
  */
 
 /*
@@ -101,10 +101,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.*;
--- a/test/jdk/sun/security/ssl/ExtensionType/OptimalListSize.java	Fri Dec 01 16:40:08 2017 -0500
+++ b/test/jdk/sun/security/ssl/ExtensionType/OptimalListSize.java	Fri Dec 08 16:41:30 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -38,6 +38,6 @@
     public static void main(String[] args) throws Throwable {
         OptimalCapacity.ofArrayList(
                 Class.forName("sun.security.ssl.ExtensionType"),
-                "knownExtensions", 15);
+                "knownExtensions", 16);
     }
 }