changeset 1789:65141d41e005

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
author pkoppula
date Fri, 15 Dec 2017 11:45:40 +0000
parents 160b59f43c34
children 1feac981ca93
files src/share/classes/com/sun/crypto/provider/SunJCE.java src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java src/share/classes/sun/security/internal/spec/TlsMasterSecretParameterSpec.java src/share/classes/sun/security/ssl/ClientHandshaker.java src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java src/share/classes/sun/security/ssl/HandshakeMessage.java src/share/classes/sun/security/ssl/Handshaker.java src/share/classes/sun/security/ssl/HelloExtensions.java src/share/classes/sun/security/ssl/SSLSessionImpl.java src/share/classes/sun/security/ssl/ServerHandshaker.java test/sun/security/ssl/com/sun/net/ssl/internal/ssl/DHKeyExchange/DHEKeySizing.java
diffstat 12 files changed, 411 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- 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");
 		    
--- 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 @@
         }
 
     }
+}
 
-}
--- 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 };
 
--- 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.
+     *
+     * <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
+     *
+     * @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();
+    }
 }
--- 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" +
--- /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
+ * <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/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();
--- 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) {
--- 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<ExtensionType> knownExtensions =
-                                            new ArrayList<ExtensionType>(9);
+                                            new ArrayList<ExtensionType>(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
--- 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;
--- 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());
--- 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.*;