changeset 17377:3abd28d7136d

8140436: Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS Reviewed-by: valeriep, jnimeh, apetcher
author igerasim
date Thu, 25 May 2017 23:31:47 -0700
parents 6c683034d1b5
children 3aea46a3cb48
files src/java.base/share/classes/sun/security/ssl/CipherSuite.java src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java src/java.base/share/classes/sun/security/ssl/DHCrypt.java src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.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/NamedGroup.java src/java.base/share/classes/sun/security/ssl/NamedGroupType.java src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java
diffstat 17 files changed, 1430 insertions(+), 867 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/CipherSuite.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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 @@
 import static sun.security.ssl.CipherSuite.MacAlg.*;
 import static sun.security.ssl.CipherSuite.BulkCipher.*;
 import static sun.security.ssl.JsseJce.*;
+import static sun.security.ssl.NamedGroupType.*;
 
 /**
  * An SSL/TLS CipherSuite. Constants for the standard key exchange, cipher,
@@ -376,38 +377,38 @@
     static enum KeyExchange {
 
         // key exchange algorithms
-        K_NULL       ("NULL",       false,      false),
-        K_RSA        ("RSA",        true,       false),
-        K_RSA_EXPORT ("RSA_EXPORT", true,       false),
-        K_DH_RSA     ("DH_RSA",     false,      false),
-        K_DH_DSS     ("DH_DSS",     false,      false),
-        K_DHE_DSS    ("DHE_DSS",    true,       false),
-        K_DHE_RSA    ("DHE_RSA",    true,       false),
-        K_DH_ANON    ("DH_anon",    true,       false),
+        K_NULL       ("NULL",       false,      NAMED_GROUP_NONE),
+        K_RSA        ("RSA",        true,       NAMED_GROUP_NONE),
+        K_RSA_EXPORT ("RSA_EXPORT", true,       NAMED_GROUP_NONE),
+        K_DH_RSA     ("DH_RSA",     false,      NAMED_GROUP_NONE),
+        K_DH_DSS     ("DH_DSS",     false,      NAMED_GROUP_NONE),
+        K_DHE_DSS    ("DHE_DSS",    true,       NAMED_GROUP_FFDHE),
+        K_DHE_RSA    ("DHE_RSA",    true,       NAMED_GROUP_FFDHE),
+        K_DH_ANON    ("DH_anon",    true,       NAMED_GROUP_FFDHE),
 
-        K_ECDH_ECDSA ("ECDH_ECDSA",  ALLOW_ECC, true),
-        K_ECDH_RSA   ("ECDH_RSA",    ALLOW_ECC, true),
-        K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, true),
-        K_ECDHE_RSA  ("ECDHE_RSA",   ALLOW_ECC, true),
-        K_ECDH_ANON  ("ECDH_anon",   ALLOW_ECC, true),
+        K_ECDH_ECDSA ("ECDH_ECDSA",  ALLOW_ECC, NAMED_GROUP_ECDHE),
+        K_ECDH_RSA   ("ECDH_RSA",    ALLOW_ECC, NAMED_GROUP_ECDHE),
+        K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, NAMED_GROUP_ECDHE),
+        K_ECDHE_RSA  ("ECDHE_RSA",   ALLOW_ECC, NAMED_GROUP_ECDHE),
+        K_ECDH_ANON  ("ECDH_anon",   ALLOW_ECC, NAMED_GROUP_ECDHE),
 
         // Kerberos cipher suites
-        K_KRB5       ("KRB5", true,             false),
-        K_KRB5_EXPORT("KRB5_EXPORT", true,      false),
+        K_KRB5       ("KRB5", true,             NAMED_GROUP_NONE),
+        K_KRB5_EXPORT("KRB5_EXPORT", true,      NAMED_GROUP_NONE),
 
         // renegotiation protection request signaling cipher suite
-        K_SCSV       ("SCSV",        true,      false);
+        K_SCSV       ("SCSV",        true,      NAMED_GROUP_NONE);
 
         // name of the key exchange algorithm, e.g. DHE_DSS
         final String name;
         final boolean allowed;
-        final boolean isEC;
+        final NamedGroupType groupType;
         private final boolean alwaysAvailable;
 
-        KeyExchange(String name, boolean allowed, boolean isEC) {
+        KeyExchange(String name, boolean allowed, NamedGroupType groupType) {
             this.name = name;
             this.allowed = allowed;
-            this.isEC = isEC;
+            this.groupType = groupType;
             this.alwaysAvailable = allowed &&
                 (!name.startsWith("EC")) && (!name.startsWith("KRB"));
         }
@@ -417,7 +418,7 @@
                 return true;
             }
 
-            if (isEC) {
+            if (groupType == NAMED_GROUP_ECDHE) {
                 return (allowed && JsseJce.isEcAvailable());
             } else if (name.startsWith("KRB")) {
                 return (allowed && JsseJce.isKerberosAvailable());
--- a/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 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
@@ -30,6 +30,7 @@
 import java.util.*;
 
 import javax.net.ssl.SSLException;
+import static sun.security.ssl.NamedGroupType.*;
 
 /**
  * A list of CipherSuites. Also maintains the lists of supported and
@@ -42,15 +43,16 @@
 
     private final Collection<CipherSuite> cipherSuites;
     private String[] suiteNames;
-
-    // flag indicating whether this list contains any ECC ciphersuites.
-    // null if not yet checked.
-    private volatile Boolean containsEC;
+    private final EnumSet<NamedGroupType> groupsTypes =
+            EnumSet.noneOf(NamedGroupType.class);
 
     // for use by buildAvailableCache() and
     // Handshaker.getKickstartMessage() only
     CipherSuiteList(Collection<CipherSuite> cipherSuites) {
         this.cipherSuites = cipherSuites;
+        for (CipherSuite suite : cipherSuites) {
+            updateGroupTypes(suite);
+        }
     }
 
     /**
@@ -59,6 +61,7 @@
     CipherSuiteList(CipherSuite suite) {
         cipherSuites = new ArrayList<CipherSuite>(1);
         cipherSuites.add(suite);
+        updateGroupTypes(suite);
     }
 
     /**
@@ -82,6 +85,7 @@
                     + suiteName + " with currently installed providers");
             }
             cipherSuites.add(suite);
+            updateGroupTypes(suite);
         }
     }
 
@@ -97,7 +101,20 @@
         }
         cipherSuites = new ArrayList<CipherSuite>(bytes.length >> 1);
         for (int i = 0; i < bytes.length; i += 2) {
-            cipherSuites.add(CipherSuite.valueOf(bytes[i], bytes[i+1]));
+            CipherSuite suite = CipherSuite.valueOf(bytes[i], bytes[i+1]);
+            cipherSuites.add(suite);
+            updateGroupTypes(suite);
+        }
+    }
+
+    // Please don't use this method except constructors.
+    private void updateGroupTypes(CipherSuite cipherSuite) {
+        if (cipherSuite.keyExchange != null && (!cipherSuite.exportable)) {
+            NamedGroupType groupType = cipherSuite.keyExchange.groupType;
+            if ((groupType != NAMED_GROUP_NONE) &&
+                    (!groupsTypes.contains(groupType))) {
+                groupsTypes.add(groupType);
+            }
         }
     }
 
@@ -108,20 +125,9 @@
         return cipherSuites.contains(suite);
     }
 
-    // Return whether this list contains any ECC ciphersuites
-    boolean containsEC() {
-        if (containsEC == null) {
-            for (CipherSuite c : cipherSuites) {
-                if (c.keyExchange.isEC) {
-                    containsEC = true;
-                    return true;
-                }
-            }
-
-            containsEC = false;
-        }
-
-        return containsEC;
+    // Return whether this list contains cipher suites of a named group type.
+    boolean contains(NamedGroupType groupType) {
+        return groupsTypes.contains(groupType);
     }
 
     /**
--- a/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, 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
@@ -148,6 +148,10 @@
     private static final boolean enableMFLExtension =
             Debug.getBooleanProperty("jsse.enableMFLExtension", false);
 
+    // To switch off the supported_groups extension for DHE cipher suite.
+    private static final boolean enableFFDHE =
+            Debug.getBooleanProperty("jsse.enableFFDHE", true);
+
     // Whether an ALPN extension was sent in the ClientHello
     private boolean alpnActive = false;
 
@@ -767,13 +771,15 @@
                     fatalSE(Alerts.alert_unexpected_message, "Server set " +
                             type + " extension when not requested by client");
                 }
-            } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES)
+            } else if ((type != ExtensionType.EXT_SUPPORTED_GROUPS)
                     && (type != ExtensionType.EXT_EC_POINT_FORMATS)
                     && (type != ExtensionType.EXT_SERVER_NAME)
                     && (type != ExtensionType.EXT_ALPN)
                     && (type != ExtensionType.EXT_RENEGOTIATION_INFO)
                     && (type != ExtensionType.EXT_STATUS_REQUEST)
                     && (type != ExtensionType.EXT_STATUS_REQUEST_V2)) {
+                // Note: Better to check client requested extensions rather
+                // than all supported extensions.
                 fatalSE(Alerts.alert_unsupported_extension,
                     "Server sent an unsupported extension: " + type);
             }
@@ -823,6 +829,17 @@
      * our own D-H algorithm object so we can defer key calculations
      * until after we've sent the client key exchange message (which
      * gives client and server some useful parallelism).
+     *
+     * Note per section 3 of RFC 7919, if the server is not compatible with
+     * FFDHE specification, the client MAY decide to continue the connection
+     * if the selected DHE group is acceptable under local policy, or it MAY
+     * decide to terminate the connection with a fatal insufficient_security
+     * (71) alert.  The algorithm constraints mechanism is JDK local policy
+     * used for additional DHE parameters checking.  So this implementation
+     * does not check the server compatibility and just pass to the local
+     * algorithm constraints checking.  The client will continue the
+     * connection if the server selected DHE group is acceptable by the
+     * specified algorithm constraints.
      */
     private void serverKeyExchange(DH_ServerKeyExchange mesg)
             throws IOException {
@@ -1495,14 +1512,17 @@
                 sslContext.getSecureRandom(), maxProtocolVersion,
                 sessionId, cipherSuites, isDTLS);
 
-        // add elliptic curves and point format extensions
-        if (cipherSuites.containsEC()) {
-            EllipticCurvesExtension ece =
-                EllipticCurvesExtension.createExtension(algorithmConstraints);
-            if (ece != null) {
-                clientHelloMessage.extensions.add(ece);
+        // Add named groups extension for ECDHE and FFDHE if necessary.
+        SupportedGroupsExtension sge =
+                SupportedGroupsExtension.createExtension(
+                        algorithmConstraints,
+                        cipherSuites, enableFFDHE);
+        if (sge != null) {
+            clientHelloMessage.extensions.add(sge);
+            // Add elliptic point format extensions
+            if (cipherSuites.contains(NamedGroupType.NAMED_GROUP_ECDHE)) {
                 clientHelloMessage.extensions.add(
-                        EllipticPointFormatsExtension.DEFAULT);
+                    EllipticPointFormatsExtension.DEFAULT);
             }
         }
 
--- a/src/java.base/share/classes/sun/security/ssl/DHCrypt.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/DHCrypt.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, 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
@@ -26,14 +26,8 @@
 
 package sun.security.ssl;
 
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Collections;
-import java.util.regex.Pattern;
-import java.util.regex.Matcher;
 import java.math.BigInteger;
 import java.security.*;
-import java.io.IOException;
 import javax.net.ssl.SSLHandshakeException;
 import javax.crypto.SecretKey;
 import javax.crypto.KeyAgreement;
@@ -101,7 +95,7 @@
      */
     DHCrypt(int keyLength, SecureRandom random) {
         this(keyLength,
-                ParametersHolder.definedParams.get(keyLength), random);
+            PredefinedDHParameterSpecs.definedParams.get(keyLength), random);
     }
 
     /**
@@ -116,6 +110,14 @@
     }
 
     /**
+     * Generate a Diffie-Hellman keypair using the named group.
+     */
+    DHCrypt(NamedGroup namedGroup, SecureRandom random) {
+        this(-1,        // The length (-1) is not used in the implementation.
+            SupportedGroupsExtension.getDHParameterSpec(namedGroup), random);
+    }
+
+    /**
      * Generate a Diffie-Hellman keypair using the specified size and
      * parameters.
      */
@@ -272,266 +274,5 @@
 
         return null;
     }
+}
 
-    // lazy initialization holder class idiom for static default parameters
-    //
-    // See Effective Java Second Edition: Item 71.
-    private static class ParametersHolder {
-        private final static boolean debugIsOn =
-                (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx");
-
-        //
-        // Default DH ephemeral parameters
-        //
-        private static final BigInteger p512 = new BigInteger(   // generated
-                "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" +
-                "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" +
-                "A43DD89D1D90921C6328884461E0B6D3", 16);
-        private static final BigInteger p768 = new BigInteger(   // RFC 2409
-                "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
-                "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
-                "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
-                "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
-
-        private static final BigInteger p1024 = new BigInteger(  // RFC 2409
-                "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
-                "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
-                "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
-                "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
-                "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
-                "FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p1536 = new BigInteger(  // RFC 3526
-                "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
-                "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
-                "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
-                "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
-                "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
-                "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
-                "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
-                "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p2048 = new BigInteger(  // TLS FFDHE
-                "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
-                "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
-                "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
-                "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
-                "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
-                "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
-                "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
-                "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
-                "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
-                "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
-                "886B423861285C97FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p3072 = new BigInteger(  // TLS FFDHE
-                "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
-                "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
-                "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
-                "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
-                "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
-                "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
-                "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
-                "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
-                "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
-                "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
-                "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
-                "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
-                "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
-                "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
-                "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
-                "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p4096 = new BigInteger(  // TLS FFDHE
-                "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
-                "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
-                "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
-                "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
-                "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
-                "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
-                "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
-                "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
-                "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
-                "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
-                "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
-                "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
-                "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
-                "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
-                "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
-                "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
-                "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
-                "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
-                "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
-                "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
-                "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" +
-                "FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p6144 = new BigInteger(  // TLS FFDHE
-                "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
-                "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
-                "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
-                "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
-                "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
-                "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
-                "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
-                "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
-                "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
-                "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
-                "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
-                "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
-                "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
-                "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
-                "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
-                "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
-                "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
-                "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
-                "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
-                "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
-                "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" +
-                "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" +
-                "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" +
-                "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" +
-                "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" +
-                "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" +
-                "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" +
-                "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" +
-                "D72B03746AE77F5E62292C311562A846505DC82DB854338A" +
-                "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" +
-                "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" +
-                "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16);
-        private static final BigInteger p8192 = new BigInteger(  // TLS FFDHE
-                "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
-                "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
-                "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
-                "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
-                "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
-                "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
-                "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
-                "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
-                "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
-                "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
-                "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
-                "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
-                "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
-                "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
-                "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
-                "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
-                "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
-                "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
-                "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
-                "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
-                "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" +
-                "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" +
-                "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" +
-                "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" +
-                "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" +
-                "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" +
-                "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" +
-                "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" +
-                "D72B03746AE77F5E62292C311562A846505DC82DB854338A" +
-                "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" +
-                "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" +
-                "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" +
-                "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" +
-                "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" +
-                "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" +
-                "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" +
-                "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" +
-                "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" +
-                "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" +
-                "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" +
-                "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" +
-                "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" +
-                "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16);
-
-        private static final BigInteger[] supportedPrimes = {
-                p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192};
-
-        // a measure of the uncertainty that prime modulus p is not a prime
-        //
-        // see BigInteger.isProbablePrime(int certainty)
-        private final static int PRIME_CERTAINTY = 120;
-
-        // the known security property, jdk.tls.server.defaultDHEParameters
-        private final static String PROPERTY_NAME =
-                "jdk.tls.server.defaultDHEParameters";
-
-        private static final Pattern spacesPattern = Pattern.compile("\\s+");
-
-        private final static Pattern syntaxPattern = Pattern.compile(
-                "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" +
-                "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*");
-
-        private static final Pattern paramsPattern = Pattern.compile(
-                "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}");
-
-        // cache of predefined default DH ephemeral parameters
-        private final static Map<Integer,DHParameterSpec> definedParams;
-
-        static {
-            String property = AccessController.doPrivileged(
-                new PrivilegedAction<String>() {
-                    public String run() {
-                        return Security.getProperty(PROPERTY_NAME);
-                    }
-                });
-
-            if (property != null && !property.isEmpty()) {
-                // remove double quote marks from beginning/end of the property
-                if (property.length() >= 2 && property.charAt(0) == '"' &&
-                        property.charAt(property.length() - 1) == '"') {
-                    property = property.substring(1, property.length() - 1);
-                }
-
-                property = property.trim();
-            }
-
-            if (property != null && !property.isEmpty()) {
-                Matcher spacesMatcher = spacesPattern.matcher(property);
-                property = spacesMatcher.replaceAll("");
-
-                if (debugIsOn) {
-                    System.out.println("The Security Property " +
-                            PROPERTY_NAME + ": " + property);
-                }
-            }
-
-            Map<Integer,DHParameterSpec> defaultParams = new HashMap<>();
-            if (property != null && !property.isEmpty()) {
-                Matcher syntaxMatcher = syntaxPattern.matcher(property);
-                if (syntaxMatcher.matches()) {
-                    Matcher paramsFinder = paramsPattern.matcher(property);
-                    while(paramsFinder.find()) {
-                        String primeModulus = paramsFinder.group(1);
-                        BigInteger p = new BigInteger(primeModulus, 16);
-                        if (!p.isProbablePrime(PRIME_CERTAINTY)) {
-                            if (debugIsOn) {
-                                System.out.println(
-                                    "Prime modulus p in Security Property, " +
-                                    PROPERTY_NAME + ", is not a prime: " +
-                                    primeModulus);
-                            }
-
-                            continue;
-                        }
-
-                        String baseGenerator = paramsFinder.group(2);
-                        BigInteger g = new BigInteger(baseGenerator, 16);
-
-                        DHParameterSpec spec = new DHParameterSpec(p, g);
-                        int primeLen = p.bitLength();
-                        defaultParams.put(primeLen, spec);
-                    }
-                } else if (debugIsOn) {
-                    System.out.println("Invalid Security Property, " +
-                            PROPERTY_NAME + ", definition");
-                }
-            }
-
-            for (BigInteger p : supportedPrimes) {
-                int primeLen = p.bitLength();
-                defaultParams.putIfAbsent(primeLen,
-                        new DHParameterSpec(p, BigInteger.TWO));
-            }
-
-            definedParams =
-                    Collections.<Integer,DHParameterSpec>unmodifiableMap(
-                                                                defaultParams);
-        }
-    }
-}
--- a/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -56,17 +56,17 @@
     }
 
     // Called by ServerHandshaker for ephemeral ECDH
-    ECDHCrypt(int curveId, SecureRandom random) {
+    ECDHCrypt(NamedGroup namedGroup, SecureRandom random) {
         try {
             KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
             ECGenParameterSpec params =
-                    EllipticCurvesExtension.getECGenParamSpec(curveId);
+                    SupportedGroupsExtension.getECGenParamSpec(namedGroup);
             kpg.initialize(params, random);
             KeyPair kp = kpg.generateKeyPair();
             privateKey = kp.getPrivate();
             publicKey = (ECPublicKey)kp.getPublic();
         } catch (GeneralSecurityException e) {
-            throw new RuntimeException("Could not generate DH keypair", e);
+            throw new RuntimeException("Could not generate ECDH keypair", e);
         }
     }
 
@@ -79,7 +79,7 @@
             privateKey = kp.getPrivate();
             publicKey = (ECPublicKey)kp.getPublic();
         } catch (GeneralSecurityException e) {
-            throw new RuntimeException("Could not generate DH keypair", e);
+            throw new RuntimeException("Could not generate ECDH keypair", e);
         }
     }
 
--- a/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java	Tue May 23 16:59:50 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
-/*
- * Copyright (c) 2006, 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
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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 java.security.spec.ECParameterSpec;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.security.AlgorithmParameters;
-import java.security.AlgorithmConstraints;
-import java.security.CryptoPrimitive;
-import java.security.AccessController;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.ArrayList;
-import javax.net.ssl.SSLProtocolException;
-
-import sun.security.action.GetPropertyAction;
-
-final class EllipticCurvesExtension extends HelloExtension {
-
-    /* Class and subclass dynamic debugging support */
-    private static final Debug debug = Debug.getInstance("ssl");
-
-    private static final int ARBITRARY_PRIME = 0xff01;
-    private static final int ARBITRARY_CHAR2 = 0xff02;
-
-    // speed up the searching
-    private static final Map<String, Integer> oidToIdMap = new HashMap<>();
-    private static final Map<Integer, String> idToOidMap = new HashMap<>();
-
-    // speed up the parameters construction
-    private static final Map<Integer,
-                AlgorithmParameters> idToParams = new HashMap<>();
-
-    // the supported elliptic curves
-    private static final int[] supportedCurveIds;
-
-    // the curves of the extension
-    private final int[] curveIds;
-
-    // See sun.security.util.CurveDB for the OIDs
-    private static enum NamedEllipticCurve {
-        T163_K1(1,  "sect163k1",    "1.3.132.0.1",      true),  // NIST K-163
-        T163_R1(2,  "sect163r1",    "1.3.132.0.2",      false),
-        T163_R2(3,  "sect163r2",    "1.3.132.0.15",     true),  // NIST B-163
-        T193_R1(4,  "sect193r1",    "1.3.132.0.24",     false),
-        T193_R2(5,  "sect193r2",    "1.3.132.0.25",     false),
-        T233_K1(6,  "sect233k1",    "1.3.132.0.26",     true),  // NIST K-233
-        T233_R1(7,  "sect233r1",    "1.3.132.0.27",     true),  // NIST B-233
-        T239_K1(8,  "sect239k1",    "1.3.132.0.3",      false),
-        T283_K1(9,  "sect283k1",    "1.3.132.0.16",     true),  // NIST K-283
-        T283_R1(10, "sect283r1",    "1.3.132.0.17",     true),  // NIST B-283
-        T409_K1(11, "sect409k1",    "1.3.132.0.36",     true),  // NIST K-409
-        T409_R1(12, "sect409r1",    "1.3.132.0.37",     true),  // NIST B-409
-        T571_K1(13, "sect571k1",    "1.3.132.0.38",     true),  // NIST K-571
-        T571_R1(14, "sect571r1",    "1.3.132.0.39",     true),  // NIST B-571
-
-        P160_K1(15, "secp160k1",    "1.3.132.0.9",      false),
-        P160_R1(16, "secp160r1",    "1.3.132.0.8",      false),
-        P160_R2(17, "secp160r2",    "1.3.132.0.30",     false),
-        P192_K1(18, "secp192k1",    "1.3.132.0.31",     false),
-        P192_R1(19, "secp192r1",    "1.2.840.10045.3.1.1", true), // NIST P-192
-        P224_K1(20, "secp224k1",    "1.3.132.0.32",     false),
-        P224_R1(21, "secp224r1",    "1.3.132.0.33",     true),  // NIST P-224
-        P256_K1(22, "secp256k1",    "1.3.132.0.10",     false),
-        P256_R1(23, "secp256r1",    "1.2.840.10045.3.1.7", true), // NIST P-256
-        P384_R1(24, "secp384r1",    "1.3.132.0.34",     true),  // NIST P-384
-        P521_R1(25, "secp521r1",    "1.3.132.0.35",     true);  // NIST P-521
-
-        int          id;
-        String       name;
-        String       oid;
-        boolean      isFips;
-
-        NamedEllipticCurve(int id, String name, String oid, boolean isFips) {
-            this.id = id;
-            this.name = name;
-            this.oid = oid;
-            this.isFips = isFips;
-
-            if (oidToIdMap.put(oid, id) != null ||
-                idToOidMap.put(id, oid) != null) {
-
-                throw new RuntimeException(
-                        "Duplicate named elliptic curve definition: " + name);
-            }
-        }
-
-        static NamedEllipticCurve getCurve(String name, boolean requireFips) {
-            for (NamedEllipticCurve curve : NamedEllipticCurve.values()) {
-                if (curve.name.equals(name) && (!requireFips || curve.isFips)) {
-                    return curve;
-                }
-            }
-
-            return null;
-        }
-    }
-
-    static {
-        boolean requireFips = SunJSSE.isFIPS();
-
-        // hack code to initialize NamedEllipticCurve
-        NamedEllipticCurve nec =
-                NamedEllipticCurve.getCurve("secp256r1", false);
-
-        // The value of the System Property defines a list of enabled named
-        // curves in preference order, separated with comma.  For example:
-        //
-        //      jdk.tls.namedGroups="secp521r1, secp256r1, secp384r1"
-        //
-        // If the System Property is not defined or the value is empty, the
-        // default curves and preferences will be used.
-        String property = AccessController.doPrivileged(
-                    new GetPropertyAction("jdk.tls.namedGroups"));
-        if (property != null && property.length() != 0) {
-            // remove double quote marks from beginning/end of the property
-            if (property.length() > 1 && property.charAt(0) == '"' &&
-                    property.charAt(property.length() - 1) == '"') {
-                property = property.substring(1, property.length() - 1);
-            }
-        }
-
-        ArrayList<Integer> idList;
-        if (property != null && property.length() != 0) {   // customized curves
-            String[] curves = property.split(",");
-            idList = new ArrayList<>(curves.length);
-            for (String curve : curves) {
-                curve = curve.trim();
-                if (!curve.isEmpty()) {
-                    NamedEllipticCurve namedCurve =
-                            NamedEllipticCurve.getCurve(curve, requireFips);
-                    if (namedCurve != null) {
-                        if (isAvailableCurve(namedCurve.id)) {
-                            idList.add(namedCurve.id);
-                        }
-                    }   // ignore unknown curves
-                }
-            }
-            if (idList.isEmpty() && JsseJce.isEcAvailable()) {
-                throw new IllegalArgumentException(
-                    "System property jdk.tls.namedGroups(" + property + ") " +
-                    "contains no supported elliptic curves");
-            }
-        } else {        // default curves
-            int[] ids;
-            if (requireFips) {
-                ids = new int[] {
-                    // only NIST curves in FIPS mode
-                    23, 24, 25, 9, 10, 11, 12, 13, 14,
-                };
-            } else {
-                ids = new int[] {
-                    // NIST curves first
-                    23, 24, 25, 9, 10, 11, 12, 13, 14,
-                    // non-NIST curves
-                    22,
-                };
-            }
-
-            idList = new ArrayList<>(ids.length);
-            for (int curveId : ids) {
-                if (isAvailableCurve(curveId)) {
-                    idList.add(curveId);
-                }
-            }
-        }
-
-        if (debug != null && idList.isEmpty()) {
-            Debug.log(
-                "Initialized [jdk.tls.namedGroups|default] list contains " +
-                "no available elliptic curves. " +
-                (property != null ? "(" + property + ")" : "[Default]"));
-        }
-
-        supportedCurveIds = new int[idList.size()];
-        int i = 0;
-        for (Integer id : idList) {
-            supportedCurveIds[i++] = id;
-        }
-    }
-
-    // check whether the curve is supported by the underlying providers
-    private static boolean isAvailableCurve(int curveId) {
-        String oid = idToOidMap.get(curveId);
-        if (oid != null) {
-            AlgorithmParameters params = null;
-            try {
-                params = JsseJce.getAlgorithmParameters("EC");
-                params.init(new ECGenParameterSpec(oid));
-            } catch (Exception e) {
-                return false;
-            }
-
-            // cache the parameters
-            idToParams.put(curveId, params);
-
-            return true;
-        }
-
-        return false;
-    }
-
-    private EllipticCurvesExtension(int[] curveIds) {
-        super(ExtensionType.EXT_ELLIPTIC_CURVES);
-
-        this.curveIds = curveIds;
-    }
-
-    EllipticCurvesExtension(HandshakeInStream s, int len)
-            throws IOException {
-        super(ExtensionType.EXT_ELLIPTIC_CURVES);
-
-        int k = s.getInt16();
-        if (((len & 1) != 0) || (k + 2 != len)) {
-            throw new SSLProtocolException("Invalid " + type + " extension");
-        }
-
-        // Note: unknown curves will be ignored later.
-        curveIds = new int[k >> 1];
-        for (int i = 0; i < curveIds.length; i++) {
-            curveIds[i] = s.getInt16();
-        }
-    }
-
-    // get the preferred active curve
-    static int getActiveCurves(AlgorithmConstraints constraints) {
-        return getPreferredCurve(supportedCurveIds, constraints);
-    }
-
-    static boolean hasActiveCurves(AlgorithmConstraints constraints) {
-        return getActiveCurves(constraints) >= 0;
-    }
-
-    static EllipticCurvesExtension createExtension(
-                AlgorithmConstraints constraints) {
-
-        ArrayList<Integer> idList = new ArrayList<>(supportedCurveIds.length);
-        for (int curveId : supportedCurveIds) {
-            if (constraints.permits(
-                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                "EC", idToParams.get(curveId))) {
-                idList.add(curveId);
-            }
-        }
-
-        if (!idList.isEmpty()) {
-            int[] ids = new int[idList.size()];
-            int i = 0;
-            for (Integer id : idList) {
-                ids[i++] = id;
-            }
-
-            return new EllipticCurvesExtension(ids);
-        }
-
-        return null;
-    }
-
-    // get the preferred activated curve
-    int getPreferredCurve(AlgorithmConstraints constraints) {
-        return getPreferredCurve(curveIds, constraints);
-    }
-
-    // get a preferred activated curve
-    private static int getPreferredCurve(int[] curves,
-                AlgorithmConstraints constraints) {
-        for (int curveId : curves) {
-            if (isSupported(curveId) && constraints.permits(
-                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                "EC", idToParams.get(curveId))) {
-                return curveId;
-            }
-        }
-
-        return -1;
-    }
-
-    boolean contains(int index) {
-        for (int curveId : curveIds) {
-            if (index == curveId) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    int length() {
-        return 6 + (curveIds.length << 1);
-    }
-
-    @Override
-    void send(HandshakeOutStream s) throws IOException {
-        s.putInt16(type.id);
-        int k = curveIds.length << 1;
-        s.putInt16(k + 2);
-        s.putInt16(k);
-        for (int curveId : curveIds) {
-            s.putInt16(curveId);
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("Extension " + type + ", curve names: {");
-        boolean first = true;
-        for (int curveId : curveIds) {
-            if (first) {
-                first = false;
-            } else {
-                sb.append(", ");
-            }
-            // first check if it is a known named curve, then try other cases.
-            String curveName = getCurveName(curveId);
-            if (curveName != null) {
-                sb.append(curveName);
-            } else if (curveId == ARBITRARY_PRIME) {
-                sb.append("arbitrary_explicit_prime_curves");
-            } else if (curveId == ARBITRARY_CHAR2) {
-                sb.append("arbitrary_explicit_char2_curves");
-            } else {
-                sb.append("unknown curve " + curveId);
-            }
-        }
-        sb.append("}");
-        return sb.toString();
-    }
-
-    // Test whether the given curve is supported.
-    static boolean isSupported(int index) {
-        for (int curveId : supportedCurveIds) {
-            if (index == curveId) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    static int getCurveIndex(ECParameterSpec params) {
-        String oid = JsseJce.getNamedCurveOid(params);
-        if (oid == null) {
-            return -1;
-        }
-        Integer n = oidToIdMap.get(oid);
-        return (n == null) ? -1 : n;
-    }
-
-    static String getCurveOid(int index) {
-        return idToOidMap.get(index);
-    }
-
-    static ECGenParameterSpec getECGenParamSpec(int index) {
-        AlgorithmParameters params = idToParams.get(index);
-        try {
-            return params.getParameterSpec(ECGenParameterSpec.class);
-        } catch (InvalidParameterSpecException ipse) {
-            // should be unlikely
-            String curveOid = getCurveOid(index);
-            return new ECGenParameterSpec(curveOid);
-        }
-    }
-
-    private static String getCurveName(int index) {
-        for (NamedEllipticCurve namedCurve : NamedEllipticCurve.values()) {
-            if (namedCurve.id == index) {
-                return namedCurve.name;
-            }
-        }
-
-        return null;
-    }
-}
--- a/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/ExtensionType.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -82,9 +82,9 @@
     static final ExtensionType EXT_CERT_TYPE =
             e(0x0009, "cert_type");              // IANA registry value: 9
 
-    // extensions defined in RFC 4492 (ECC)
-    static final ExtensionType EXT_ELLIPTIC_CURVES =
-            e(0x000A, "elliptic_curves");        // IANA registry value: 10
+    // extensions defined in RFC 4492 (ECC) and RFC 7919 (FFDHE)
+    static final ExtensionType EXT_SUPPORTED_GROUPS =
+            e(0x000A, "supported_groups");       // IANA registry value: 10
     static final ExtensionType EXT_EC_POINT_FORMATS =
             e(0x000B, "ec_point_formats");       // IANA registry value: 11
 
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, 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
@@ -1369,8 +1369,9 @@
     private static final int CURVE_EXPLICIT_CHAR2 = 2;
     private static final int CURVE_NAMED_CURVE    = 3;
 
-    // id of the curve we are using
-    private int curveId;
+    // id of the named group we are using
+    private int groupId;
+
     // encoded public point
     private byte[] pointBytes;
 
@@ -1389,7 +1390,8 @@
     ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey,
             byte[] clntNonce, byte[] svrNonce, SecureRandom sr,
             SignatureAndHashAlgorithm signAlgorithm,
-            ProtocolVersion protocolVersion) throws GeneralSecurityException {
+            ProtocolVersion protocolVersion)
+            throws SSLHandshakeException, GeneralSecurityException {
 
         this.protocolVersion = protocolVersion;
 
@@ -1397,7 +1399,14 @@
         ECParameterSpec params = publicKey.getParams();
         ECPoint point = publicKey.getW();
         pointBytes = JsseJce.encodePoint(point, params.getCurve());
-        curveId = EllipticCurvesExtension.getCurveIndex(params);
+
+        NamedGroup namedGroup = NamedGroup.valueOf(params);
+        if ((namedGroup == null) || (namedGroup.oid == null) ){
+            // unlikely
+            throw new SSLHandshakeException(
+                "Unnamed EC parameter spec: " + params);
+        }
+        groupId = namedGroup.id;
 
         if (privateKey == null) {
             // ECDH_anon
@@ -1434,20 +1443,27 @@
         // These parsing errors should never occur as we negotiated
         // the supported curves during the exchange of the Hello messages.
         if (curveType == CURVE_NAMED_CURVE) {
-            curveId = input.getInt16();
-            if (!EllipticCurvesExtension.isSupported(curveId)) {
+            groupId = input.getInt16();
+            NamedGroup namedGroup = NamedGroup.valueOf(groupId);
+            if (namedGroup == null) {
                 throw new SSLHandshakeException(
-                    "Unsupported curveId: " + curveId);
+                    "Unknown named group ID: " + groupId);
             }
-            String curveOid = EllipticCurvesExtension.getCurveOid(curveId);
-            if (curveOid == null) {
+
+            if (!SupportedGroupsExtension.supports(namedGroup)) {
                 throw new SSLHandshakeException(
-                    "Unknown named curve: " + curveId);
+                    "Unsupported named group: " + namedGroup);
             }
-            parameters = JsseJce.getECParameterSpec(curveOid);
+
+            if (namedGroup.oid == null) {
+                throw new SSLHandshakeException(
+                    "Unknown named EC curve: " + namedGroup);
+            }
+
+            parameters = JsseJce.getECParameterSpec(namedGroup.oid);
             if (parameters == null) {
                 throw new SSLHandshakeException(
-                    "Unsupported curve: " + curveOid);
+                    "No supported EC parameter for named group: " + namedGroup);
             }
         } else {
             throw new SSLHandshakeException(
@@ -1530,8 +1546,8 @@
         sig.update(svrNonce);
 
         sig.update((byte)CURVE_NAMED_CURVE);
-        sig.update((byte)(curveId >> 8));
-        sig.update((byte)curveId);
+        sig.update((byte)(groupId >> 8));
+        sig.update((byte)groupId);
         sig.update((byte)pointBytes.length);
         sig.update(pointBytes);
     }
@@ -1552,7 +1568,7 @@
     @Override
     void send(HandshakeOutStream s) throws IOException {
         s.putInt8(CURVE_NAMED_CURVE);
-        s.putInt16(curveId);
+        s.putInt16(groupId);
         s.putBytes8(pointBytes);
 
         if (signatureBytes != null) {
--- a/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/Handshaker.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, 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
@@ -52,6 +52,7 @@
 
 import static sun.security.ssl.CipherSuite.PRF.*;
 import static sun.security.ssl.CipherSuite.CipherType.*;
+import static sun.security.ssl.NamedGroupType.*;
 
 /**
  * Handshaker ... processes handshake records from an SSL V3.0
@@ -685,42 +686,14 @@
             ArrayList<CipherSuite> suites = new ArrayList<>();
             if (!(activeProtocols.collection().isEmpty()) &&
                     activeProtocols.min.v != ProtocolVersion.NONE.v) {
-                boolean checkedCurves = false;
-                boolean hasCurves = false;
+                Map<NamedGroupType, Boolean> cachedStatus =
+                        new EnumMap<>(NamedGroupType.class);
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
-                    if (!activeProtocols.min.obsoletes(suite) &&
+                    if (suite.isAvailable() &&
+                            (!activeProtocols.min.obsoletes(suite)) &&
                             activeProtocols.max.supports(suite)) {
-                        if (algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                suite.name, null)) {
-
-                            boolean available = true;
-                            if (suite.keyExchange.isEC) {
-                                if (!checkedCurves) {
-                                    hasCurves = EllipticCurvesExtension
-                                        .hasActiveCurves(algorithmConstraints);
-                                    checkedCurves = true;
-
-                                    if (!hasCurves && debug != null &&
-                                                Debug.isOn("verbose")) {
-                                        System.out.println(
-                                            "No available elliptic curves");
-                                    }
-                                }
-
-                                available = hasCurves;
-
-                                if (!available && debug != null &&
-                                        Debug.isOn("verbose")) {
-                                    System.out.println(
-                                        "No active elliptic curves, ignore " +
-                                        suite);
-                                }
-                            }
-
-                            if (available) {
-                                suites.add(suite);
-                            }
+                        if (isActivatable(suite, cachedStatus)) {
+                            suites.add(suite);
                         }
                     } else if (debug != null && Debug.isOn("verbose")) {
                         if (activeProtocols.min.obsoletes(suite)) {
@@ -779,46 +752,15 @@
                 }
 
                 boolean found = false;
+                Map<NamedGroupType, Boolean> cachedStatus =
+                        new EnumMap<>(NamedGroupType.class);
                 for (CipherSuite suite : enabledCipherSuites.collection()) {
                     if (suite.isAvailable() && (!protocol.obsoletes(suite)) &&
                                                protocol.supports(suite)) {
-                        if (algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                suite.name, null)) {
-
-                            boolean available = true;
-                            if (suite.keyExchange.isEC) {
-                                if (!checkedCurves) {
-                                    hasCurves = EllipticCurvesExtension
-                                        .hasActiveCurves(algorithmConstraints);
-                                    checkedCurves = true;
-
-                                    if (!hasCurves && debug != null &&
-                                                Debug.isOn("verbose")) {
-                                        System.out.println(
-                                            "No activated elliptic curves");
-                                    }
-                                }
-
-                                available = hasCurves;
-
-                                if (!available && debug != null &&
-                                        Debug.isOn("verbose")) {
-                                    System.out.println(
-                                        "No active elliptic curves, ignore " +
-                                        suite + " for " + protocol);
-                                }
-                            }
-
-                            if (available) {
-                                protocols.add(protocol);
-                                found = true;
-                                break;
-                            }
-                        } else if (debug != null && Debug.isOn("verbose")) {
-                            System.out.println(
-                                "Ignoring disabled cipher suite: " + suite +
-                                 " for " + protocol);
+                        if (isActivatable(suite, cachedStatus)) {
+                            protocols.add(protocol);
+                            found = true;
+                            break;
                         }
                     } else if (debug != null && Debug.isOn("verbose")) {
                         System.out.println(
@@ -826,6 +768,7 @@
                                  " for " + protocol);
                     }
                 }
+
                 if (!found && (debug != null) && Debug.isOn("handshake")) {
                     System.out.println(
                         "No available cipher suite for " + protocol);
@@ -842,6 +785,43 @@
         return activeProtocols;
     }
 
+    private boolean isActivatable(CipherSuite suite,
+            Map<NamedGroupType, Boolean> cachedStatus) {
+
+        if (algorithmConstraints.permits(
+                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), suite.name, null)) {
+            boolean available = true;
+            NamedGroupType groupType = suite.keyExchange.groupType;
+            if (groupType != NAMED_GROUP_NONE) {
+                Boolean checkedStatus = cachedStatus.get(groupType);
+                if (checkedStatus == null) {
+                    available = SupportedGroupsExtension.isActivatable(
+                            algorithmConstraints, groupType);
+                    cachedStatus.put(groupType, available);
+
+                    if (!available && debug != null && Debug.isOn("verbose")) {
+                        System.out.println("No activated named group");
+                    }
+                } else {
+                    available = checkedStatus.booleanValue();
+                }
+
+                if (!available && debug != null && Debug.isOn("verbose")) {
+                    System.out.println(
+                        "No active named group, ignore " + suite);
+                }
+
+                return available;
+            } else {
+                return true;
+            }
+        } else if (debug != null && Debug.isOn("verbose")) {
+            System.out.println("Ignoring disabled cipher suite: " + suite);
+        }
+
+        return false;
+    }
+
     /**
      * As long as handshaking has not activated, we can
      * change whether session creations are allowed.
--- a/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/HelloExtensions.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 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
@@ -49,7 +49,7 @@
  *      explicitly support.
  *  . ServerNameExtension: the server_name extension.
  *  . SignatureAlgorithmsExtension: the signature_algorithms extension.
- *  . EllipticCurvesExtension: the ECC supported curves extension.
+ *  . SupportedGroupsExtension: the supported groups extension.
  *  . EllipticPointFormatsExtension: the ECC supported point formats
  *      (compressed/uncompressed) extension.
  *  . ALPNExtension: the application_layer_protocol_negotiation extension.
@@ -79,8 +79,8 @@
                 extension = new ServerNameExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
                 extension = new SignatureAlgorithmsExtension(s, extlen);
-            } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
-                extension = new EllipticCurvesExtension(s, extlen);
+            } else if (extType == ExtensionType.EXT_SUPPORTED_GROUPS) {
+                extension = new SupportedGroupsExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
                 extension = new EllipticPointFormatsExtension(s, extlen);
             } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java	Thu May 25 23:31:47 2017 -0700
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.security.spec.ECParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import static sun.security.ssl.NamedGroupType.*;
+
+enum NamedGroup {
+    // Elliptic Curves (RFC 4492)
+    //
+    // See sun.security.util.CurveDB for the OIDs
+
+    // NIST K-163
+    SECT163_K1(1, NAMED_GROUP_ECDHE, "sect163k1", "1.3.132.0.1", true),
+
+    SECT163_R1(2, NAMED_GROUP_ECDHE, "sect163r1", "1.3.132.0.2", false),
+
+    // NIST B-163
+    SECT163_R2(3, NAMED_GROUP_ECDHE, "sect163r2", "1.3.132.0.15", true),
+
+    SECT193_R1(4, NAMED_GROUP_ECDHE, "sect193r1", "1.3.132.0.24", false),
+    SECT193_R2(5, NAMED_GROUP_ECDHE, "sect193r2", "1.3.132.0.25", false),
+
+    // NIST K-233
+    SECT233_K1(6, NAMED_GROUP_ECDHE, "sect233k1", "1.3.132.0.26", true),
+
+    // NIST B-233
+    SECT233_R1(7, NAMED_GROUP_ECDHE, "sect233r1", "1.3.132.0.27", true),
+
+    SECT239_K1(8, NAMED_GROUP_ECDHE, "sect239k1", "1.3.132.0.3", false),
+
+    // NIST K-283
+    SECT283_K1(9, NAMED_GROUP_ECDHE, "sect283k1", "1.3.132.0.16", true),
+
+    // NIST B-283
+    SECT283_R1(10, NAMED_GROUP_ECDHE, "sect283r1", "1.3.132.0.17", true),
+
+    // NIST K-409
+    SECT409_K1(11, NAMED_GROUP_ECDHE, "sect409k1", "1.3.132.0.36", true),
+
+    // NIST B-409
+    SECT409_R1(12, NAMED_GROUP_ECDHE, "sect409r1", "1.3.132.0.37", true),
+
+    // NIST K-571
+    SECT571_K1(13, NAMED_GROUP_ECDHE, "sect571k1", "1.3.132.0.38", true),
+
+    // NIST B-571
+    SECT571_R1(14, NAMED_GROUP_ECDHE, "sect571r1", "1.3.132.0.39", true),
+
+    SECP160_K1(15, NAMED_GROUP_ECDHE, "secp160k1", "1.3.132.0.9", false),
+    SECP160_R1(16, NAMED_GROUP_ECDHE, "secp160r1", "1.3.132.0.8", false),
+    SECP160_R2(17, NAMED_GROUP_ECDHE, "secp160r2", "1.3.132.0.30", false),
+    SECP192_K1(18, NAMED_GROUP_ECDHE, "secp192k1", "1.3.132.0.31", false),
+
+    // NIST P-192
+    SECP192_R1(19, NAMED_GROUP_ECDHE, "secp192r1", "1.2.840.10045.3.1.1", true),
+
+    SECP224_K1(20, NAMED_GROUP_ECDHE, "secp224k1", "1.3.132.0.32", false),
+    // NIST P-224
+    SECP224_R1(21, NAMED_GROUP_ECDHE, "secp224r1", "1.3.132.0.33", true),
+
+    SECP256_K1(22, NAMED_GROUP_ECDHE, "secp256k1", "1.3.132.0.10", false),
+
+    // NIST P-256
+    SECP256_R1(23, NAMED_GROUP_ECDHE, "secp256r1", "1.2.840.10045.3.1.7", true),
+
+    // NIST P-384
+    SECP384_R1(24, NAMED_GROUP_ECDHE, "secp384r1", "1.3.132.0.34", true),
+
+    // NIST P-521
+    SECP521_R1(25, NAMED_GROUP_ECDHE, "secp521r1", "1.3.132.0.35", true),
+
+    // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
+    FFDHE_2048(256, NAMED_GROUP_FFDHE, "ffdhe2048",  true),
+    FFDHE_3072(257, NAMED_GROUP_FFDHE, "ffdhe3072",  true),
+    FFDHE_4096(258, NAMED_GROUP_FFDHE, "ffdhe4096",  true),
+    FFDHE_6144(259, NAMED_GROUP_FFDHE, "ffdhe6144",  true),
+    FFDHE_8192(260, NAMED_GROUP_FFDHE, "ffdhe8192",  true);
+
+    int             id;
+    NamedGroupType  type;
+    String          name;
+    String          oid;
+    String          algorithm;
+    boolean         isFips;
+
+    // Constructor used for Elliptic Curve Groups (ECDHE)
+    NamedGroup(int id, NamedGroupType type,
+                String name, String oid, boolean isFips) {
+        this.id = id;
+        this.type = type;
+        this.name = name;
+        this.oid = oid;
+        this.algorithm = "EC";
+        this.isFips = isFips;
+    }
+
+    // Constructor used for Finite Field Diffie-Hellman Groups (FFDHE)
+    NamedGroup(int id, NamedGroupType type, String name, boolean isFips) {
+        this.id = id;
+        this.type = type;
+        this.name = name;
+        this.oid = null;
+        this.algorithm = "DiffieHellman";
+        this.isFips = isFips;
+    }
+
+    static NamedGroup valueOf(int id) {
+        for (NamedGroup group : NamedGroup.values()) {
+            if (group.id == id) {
+                return group;
+            }
+        }
+
+        return null;
+    }
+
+    static NamedGroup nameOf(String name) {
+        for (NamedGroup group : NamedGroup.values()) {
+            if (group.name.equals(name)) {
+                return group;
+            }
+        }
+
+        return null;
+    }
+
+    static NamedGroup valueOf(ECParameterSpec params) {
+        String oid = JsseJce.getNamedCurveOid(params);
+        if ((oid != null) && (!oid.isEmpty())) {
+            for (NamedGroup group : NamedGroup.values()) {
+                if (oid.equals(group.oid)) {
+                    return group;
+                }
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return this.name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/NamedGroupType.java	Thu May 25 23:31:47 2017 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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;
+
+enum NamedGroupType {
+    NAMED_GROUP_ECDHE,          // Elliptic Curve Groups (ECDHE)
+    NAMED_GROUP_FFDHE,          // Finite Field Groups (DHE)
+    NAMED_GROUP_NONE            // No predefined named group
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java	Thu May 25 23:31:47 2017 -0700
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.security.*;
+import java.math.BigInteger;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+import javax.crypto.spec.DHParameterSpec;
+
+/**
+ * Predefined default DH ephemeral parameters.
+ */
+final class PredefinedDHParameterSpecs {
+    private final static boolean debugIsOn =
+            (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx");
+
+    //
+    // Default DH ephemeral parameters
+    //
+    private static final BigInteger p512 = new BigInteger(       // generated
+            "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" +
+            "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" +
+            "A43DD89D1D90921C6328884461E0B6D3", 16);
+    private static final BigInteger p768 = new BigInteger(       // RFC 2409
+            "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+            "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+            "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+            "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
+
+    private static final BigInteger p1024 = new BigInteger(      // RFC 2409
+            "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+            "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+            "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+            "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+            "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
+            "FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p1536 = new BigInteger(      // RFC 3526
+            "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+            "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+            "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+            "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+            "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+            "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+            "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+            "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p2048 = new BigInteger(      // TLS FFDHE
+            "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+            "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+            "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+            "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+            "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+            "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+            "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+            "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+            "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+            "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+            "886B423861285C97FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p3072 = new BigInteger(      // TLS FFDHE
+            "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+            "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+            "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+            "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+            "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+            "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+            "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+            "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+            "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+            "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+            "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
+            "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
+            "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
+            "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
+            "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
+            "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p4096 = new BigInteger(      // TLS FFDHE
+            "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+            "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+            "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+            "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+            "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+            "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+            "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+            "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+            "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+            "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+            "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
+            "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
+            "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
+            "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
+            "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
+            "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
+            "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
+            "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
+            "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
+            "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
+            "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" +
+            "FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p6144 = new BigInteger(      // TLS FFDHE
+            "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+            "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+            "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+            "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+            "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+            "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+            "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+            "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+            "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+            "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+            "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
+            "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
+            "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
+            "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
+            "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
+            "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
+            "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
+            "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
+            "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
+            "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
+            "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" +
+            "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" +
+            "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" +
+            "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" +
+            "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" +
+            "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" +
+            "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" +
+            "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" +
+            "D72B03746AE77F5E62292C311562A846505DC82DB854338A" +
+            "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" +
+            "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" +
+            "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16);
+    private static final BigInteger p8192 = new BigInteger(      // TLS FFDHE
+            "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+            "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+            "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+            "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+            "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+            "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+            "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+            "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+            "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+            "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+            "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" +
+            "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" +
+            "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" +
+            "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" +
+            "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" +
+            "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" +
+            "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" +
+            "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" +
+            "A907600A918130C46DC778F971AD0038092999A333CB8B7A" +
+            "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" +
+            "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" +
+            "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" +
+            "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" +
+            "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" +
+            "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" +
+            "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" +
+            "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" +
+            "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" +
+            "D72B03746AE77F5E62292C311562A846505DC82DB854338A" +
+            "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" +
+            "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" +
+            "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" +
+            "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" +
+            "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" +
+            "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" +
+            "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" +
+            "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" +
+            "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" +
+            "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" +
+            "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" +
+            "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" +
+            "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" +
+            "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16);
+
+    private static final BigInteger[] supportedPrimes = {
+            p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192};
+
+    private static final BigInteger[] ffdhePrimes = {
+            p2048, p3072, p4096, p6144, p8192};
+
+    // a measure of the uncertainty that prime modulus p is not a prime
+    //
+    // see BigInteger.isProbablePrime(int certainty)
+    private final static int PRIME_CERTAINTY = 120;
+
+    // the known security property, jdk.tls.server.defaultDHEParameters
+    private final static String PROPERTY_NAME =
+            "jdk.tls.server.defaultDHEParameters";
+
+    private static final Pattern spacesPattern = Pattern.compile("\\s+");
+
+    private final static Pattern syntaxPattern = Pattern.compile(
+            "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" +
+            "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*");
+
+    private static final Pattern paramsPattern = Pattern.compile(
+            "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}");
+
+    // cache of predefined default DH ephemeral parameters
+    final static Map<Integer, DHParameterSpec> definedParams;
+
+    // cache of Finite Field DH Ephemeral parameters (RFC 7919/FFDHE)
+    final static Map<Integer, DHParameterSpec> ffdheParams;
+
+    static {
+        String property = AccessController.doPrivileged(
+            new PrivilegedAction<String>() {
+                public String run() {
+                    return Security.getProperty(PROPERTY_NAME);
+                }
+            });
+
+        if (property != null && !property.isEmpty()) {
+            // remove double quote marks from beginning/end of the property
+            if (property.length() >= 2 && property.charAt(0) == '"' &&
+                    property.charAt(property.length() - 1) == '"') {
+                property = property.substring(1, property.length() - 1);
+            }
+
+            property = property.trim();
+        }
+
+        if (property != null && !property.isEmpty()) {
+            Matcher spacesMatcher = spacesPattern.matcher(property);
+            property = spacesMatcher.replaceAll("");
+
+            if (debugIsOn) {
+                System.out.println("The Security Property " +
+                        PROPERTY_NAME + ": " + property);
+            }
+        }
+
+        Map<Integer,DHParameterSpec> defaultParams = new HashMap<>();
+        if (property != null && !property.isEmpty()) {
+            Matcher syntaxMatcher = syntaxPattern.matcher(property);
+            if (syntaxMatcher.matches()) {
+                Matcher paramsFinder = paramsPattern.matcher(property);
+                while(paramsFinder.find()) {
+                    String primeModulus = paramsFinder.group(1);
+                    BigInteger p = new BigInteger(primeModulus, 16);
+                    if (!p.isProbablePrime(PRIME_CERTAINTY)) {
+                        if (debugIsOn) {
+                            System.out.println(
+                                "Prime modulus p in Security Property, " +
+                                PROPERTY_NAME + ", is not a prime: " +
+                                primeModulus);
+                        }
+
+                        continue;
+                    }
+
+                    String baseGenerator = paramsFinder.group(2);
+                    BigInteger g = new BigInteger(baseGenerator, 16);
+
+                    DHParameterSpec spec = new DHParameterSpec(p, g);
+                    int primeLen = p.bitLength();
+                    defaultParams.put(primeLen, spec);
+                }
+            } else if (debugIsOn) {
+                System.out.println("Invalid Security Property, " +
+                        PROPERTY_NAME + ", definition");
+            }
+        }
+
+        Map<Integer,DHParameterSpec> tempFFDHEs = new HashMap<>();
+        for (BigInteger p : ffdhePrimes) {
+            int primeLen = p.bitLength();
+            DHParameterSpec dhps = new DHParameterSpec(p, BigInteger.TWO);
+            tempFFDHEs.put(primeLen, dhps);
+            defaultParams.putIfAbsent(primeLen, dhps);
+        }
+
+        for (BigInteger p : supportedPrimes) {
+            int primeLen = p.bitLength();
+            if (defaultParams.get(primeLen) == null) {
+                defaultParams.put(primeLen,
+                    new DHParameterSpec(p, BigInteger.TWO));
+            }
+        }
+
+        ffdheParams =
+            Collections.<Integer,DHParameterSpec>unmodifiableMap(tempFFDHEs);
+        definedParams =
+            Collections.<Integer,DHParameterSpec>unmodifiableMap(defaultParams);
+    }
+}
--- a/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Tue May 23 16:59:50 2017 +0100
+++ b/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, 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
@@ -96,7 +96,7 @@
     private ProtocolVersion clientRequestedVersion;
 
     // client supported elliptic curves
-    private EllipticCurvesExtension requestedCurves;
+    private SupportedGroupsExtension requestedGroups;
 
     // the preferable signature algorithm used by ServerKeyExchange message
     SignatureAndHashAlgorithm preferableSignatureAlgorithm;
@@ -751,8 +751,8 @@
                 throw new SSLException("Client did not resume a session");
             }
 
-            requestedCurves = (EllipticCurvesExtension)
-                        mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
+            requestedGroups = (SupportedGroupsExtension)
+                    mesg.extensions.get(ExtensionType.EXT_SUPPORTED_GROUPS);
 
             // We only need to handle the "signature_algorithm" extension
             // for full handshakes and TLS 1.2 or later.
@@ -1341,6 +1341,8 @@
             }
         }
 
+        // The named group used for ECDHE and FFDHE.
+        NamedGroup namedGroup = null;
         switch (keyExchange) {
         case K_RSA:
             // need RSA certs for authentication
@@ -1366,6 +1368,37 @@
             }
             break;
         case K_DHE_RSA:
+            // Is ephemeral DH cipher suite usable for the connection?
+            //
+            // [RFC 7919] If a compatible TLS server receives a Supported
+            // Groups extension from a client that includes any FFDHE group
+            // (i.e., any codepoint between 256 and 511, inclusive, even if
+            // unknown to the server), and if none of the client-proposed
+            // FFDHE groups are known and acceptable to the server, then
+            // the server MUST NOT select an FFDHE cipher suite.  In this
+            // case, the server SHOULD select an acceptable non-FFDHE cipher
+            // suite from the client's offered list.  If the extension is
+            // present with FFDHE groups, none of the client's offered
+            // groups are acceptable by the server, and none of the client's
+            // proposed non-FFDHE cipher suites are acceptable to the server,
+            // the server MUST end the connection with a fatal TLS alert
+            // of type insufficient_security(71).
+            //
+            // Note: For compatibility, if an application is customized to
+            // use legacy sizes (512 bits for exportable cipher suites and
+            // 768 bits for others), or the cipher suite is exportable, the
+            // FFDHE extension will not be used.
+            if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) &&
+                (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) {
+
+                namedGroup = requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE);
+                if (namedGroup == null) {
+                    // no match found, cannot use this cipher suite.
+                    return false;
+                }
+            }
+
             // need RSA certs for authentication
             if (setupPrivateKeyAndChain("RSA") == false) {
                 return false;
@@ -1386,9 +1419,20 @@
                 }
             }
 
-            setupEphemeralDHKeys(suite.exportable, privateKey);
+            setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey);
             break;
         case K_ECDHE_RSA:
+            // Is ECDHE cipher suite usable for the connection?
+            namedGroup = (requestedGroups != null) ?
+                requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) :
+                SupportedGroupsExtension.getPreferredECGroup(
+                    algorithmConstraints);
+            if (namedGroup == null) {
+                // no match found, cannot use this ciphersuite
+                return false;
+            }
+
             // need RSA certs for authentication
             if (setupPrivateKeyAndChain("RSA") == false) {
                 return false;
@@ -1409,11 +1453,23 @@
                 }
             }
 
-            if (setupEphemeralECDHKeys() == false) {
-                return false;
-            }
+            setupEphemeralECDHKeys(namedGroup);
             break;
         case K_DHE_DSS:
+            // Is ephemeral DH cipher suite usable for the connection?
+            //
+            // See comment in K_DHE_RSA case.
+            if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) &&
+                (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) {
+
+                namedGroup = requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE);
+                if (namedGroup == null) {
+                    // no match found, cannot use this cipher suite.
+                    return false;
+                }
+            }
+
             // get preferable peer signature algorithm for server key exchange
             if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
@@ -1434,9 +1490,20 @@
                 return false;
             }
 
-            setupEphemeralDHKeys(suite.exportable, privateKey);
+            setupEphemeralDHKeys(namedGroup, suite.exportable, privateKey);
             break;
         case K_ECDHE_ECDSA:
+            // Is ECDHE cipher suite usable for the connection?
+            namedGroup = (requestedGroups != null) ?
+                requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) :
+                SupportedGroupsExtension.getPreferredECGroup(
+                    algorithmConstraints);
+            if (namedGroup == null) {
+                // no match found, cannot use this ciphersuite
+                return false;
+            }
+
             // get preferable peer signature algorithm for server key exchange
             if (protocolVersion.useTLS12PlusSpec()) {
                 preferableSignatureAlgorithm =
@@ -1456,9 +1523,8 @@
             if (setupPrivateKeyAndChain("EC") == false) {
                 return false;
             }
-            if (setupEphemeralECDHKeys() == false) {
-                return false;
-            }
+
+            setupEphemeralECDHKeys(namedGroup);
             break;
         case K_ECDH_RSA:
             // need EC cert
@@ -1475,14 +1541,36 @@
             setupStaticECDHKeys();
             break;
         case K_DH_ANON:
+            // Is ephemeral DH cipher suite usable for the connection?
+            //
+            // See comment in K_DHE_RSA case.
+            if ((!useLegacyEphemeralDHKeys) && (!suite.exportable) &&
+                (requestedGroups != null) && requestedGroups.hasFFDHEGroup()) {
+                namedGroup = requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_FFDHE);
+                if (namedGroup == null) {
+                    // no match found, cannot use this cipher suite.
+                    return false;
+                }
+            }
+
             // no certs needed for anonymous
-            setupEphemeralDHKeys(suite.exportable, null);
+            setupEphemeralDHKeys(namedGroup, suite.exportable, null);
             break;
         case K_ECDH_ANON:
-            // no certs needed for anonymous
-            if (setupEphemeralECDHKeys() == false) {
+            // Is ECDHE cipher suite usable for the connection?
+            namedGroup = (requestedGroups != null) ?
+                requestedGroups.getPreferredGroup(
+                    algorithmConstraints, NamedGroupType.NAMED_GROUP_ECDHE) :
+                SupportedGroupsExtension.getPreferredECGroup(
+                    algorithmConstraints);
+            if (namedGroup == null) {
+                // no match found, cannot use this ciphersuite
                 return false;
             }
+
+            // no certs needed for anonymous
+            setupEphemeralECDHKeys(namedGroup);
             break;
         default:
             ClientKeyExchangeService p =
@@ -1544,7 +1632,15 @@
      * Acquire some "ephemeral" Diffie-Hellman  keys for this handshake.
      * We don't reuse these, for improved forward secrecy.
      */
-    private void setupEphemeralDHKeys(boolean export, Key key) {
+    private void setupEphemeralDHKeys(
+            NamedGroup namedGroup, boolean export, Key key) {
+        // Are the client and server willing to negotiate FFDHE groups?
+        if ((!useLegacyEphemeralDHKeys) && (!export) && (namedGroup != null)) {
+            dh = new DHCrypt(namedGroup, sslContext.getSecureRandom());
+
+            return;
+        }   // Otherwise, the client is not compatible with FFDHE extension.
+
         /*
          * 768 bits ephemeral DH private keys were used to be used in
          * ServerKeyExchange except that exportable ciphers max out at 512
@@ -1613,20 +1709,11 @@
         dh = new DHCrypt(keySize, sslContext.getSecureRandom());
     }
 
-    // Setup the ephemeral ECDH parameters.
-    // If we cannot continue because we do not support any of the curves that
-    // the client requested, return false. Otherwise (all is well), return true.
-    private boolean setupEphemeralECDHKeys() {
-        int index = (requestedCurves != null) ?
-                requestedCurves.getPreferredCurve(algorithmConstraints) :
-                EllipticCurvesExtension.getActiveCurves(algorithmConstraints);
-        if (index < 0) {
-            // no match found, cannot use this ciphersuite
-            return false;
-        }
-
-        ecdh = new ECDHCrypt(index, sslContext.getSecureRandom());
-        return true;
+    /**
+     * Setup the ephemeral ECDH parameters.
+     */
+    private void setupEphemeralECDHKeys(NamedGroup namedGroup) {
+        ecdh = new ECDHCrypt(namedGroup, sslContext.getSecureRandom());
     }
 
     private void setupStaticECDHKeys() {
@@ -1674,9 +1761,11 @@
                 return false;
             }
             ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
-            int id = EllipticCurvesExtension.getCurveIndex(params);
-            if ((id <= 0) || !EllipticCurvesExtension.isSupported(id) ||
-                ((requestedCurves != null) && !requestedCurves.contains(id))) {
+            NamedGroup namedGroup = NamedGroup.valueOf(params);
+            if ((namedGroup == null) ||
+                (!SupportedGroupsExtension.supports(namedGroup)) ||
+                ((requestedGroups != null) &&
+                        !requestedGroups.contains(namedGroup.id))) {
                 return false;
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Thu May 25 23:31:47 2017 -0700
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2006, 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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 java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.AlgorithmParameters;
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AccessController;
+import java.security.spec.AlgorithmParameterSpec;
+import javax.crypto.spec.DHParameterSpec;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.ArrayList;
+import javax.net.ssl.SSLProtocolException;
+
+import sun.security.action.GetPropertyAction;
+
+//
+// Note: Since RFC 7919, the extension's semantics are expanded from
+// "Supported Elliptic Curves" to "Supported Groups".  The enum datatype
+// used in the extension has been renamed from NamedCurve to NamedGroup.
+// Its semantics are likewise expanded from "named curve" to "named group".
+//
+final class SupportedGroupsExtension extends HelloExtension {
+
+    /* Class and subclass dynamic debugging support */
+    private static final Debug debug = Debug.getInstance("ssl");
+
+    private static final int ARBITRARY_PRIME = 0xff01;
+    private static final int ARBITRARY_CHAR2 = 0xff02;
+
+    // cache to speed up the parameters construction
+    private static final Map<NamedGroup,
+                AlgorithmParameters> namedGroupParams = new HashMap<>();
+
+    // the supported named groups
+    private static final NamedGroup[] supportedNamedGroups;
+
+    // the named group presented in the extension
+    private final int[] requestedNamedGroupIds;
+
+    static {
+        boolean requireFips = SunJSSE.isFIPS();
+
+        // The value of the System Property defines a list of enabled named
+        // groups in preference order, separated with comma.  For example:
+        //
+        //      jdk.tls.namedGroups="secp521r1, secp256r1, ffdhe2048"
+        //
+        // If the System Property is not defined or the value is empty, the
+        // default groups and preferences will be used.
+        String property = AccessController.doPrivileged(
+                    new GetPropertyAction("jdk.tls.namedGroups"));
+        if (property != null && property.length() != 0) {
+            // remove double quote marks from beginning/end of the property
+            if (property.length() > 1 && property.charAt(0) == '"' &&
+                    property.charAt(property.length() - 1) == '"') {
+                property = property.substring(1, property.length() - 1);
+            }
+        }
+
+        ArrayList<NamedGroup> groupList;
+        if (property != null && property.length() != 0) {   // customized groups
+            String[] groups = property.split(",");
+            groupList = new ArrayList<>(groups.length);
+            for (String group : groups) {
+                group = group.trim();
+                if (!group.isEmpty()) {
+                    NamedGroup namedGroup = NamedGroup.nameOf(group);
+                    if (namedGroup != null &&
+                            (!requireFips || namedGroup.isFips)) {
+                        if (isAvailableGroup(namedGroup)) {
+                            groupList.add(namedGroup);
+                        }
+                    }   // ignore unknown groups
+                }
+            }
+
+            if (groupList.isEmpty() && JsseJce.isEcAvailable()) {
+                throw new IllegalArgumentException(
+                    "System property jdk.tls.namedGroups(" + property + ") " +
+                    "contains no supported elliptic curves");
+            }
+        } else {        // default groups
+            NamedGroup[] groups;
+            if (requireFips) {
+                groups = new NamedGroup[] {
+                    // only NIST curves in FIPS mode
+                    NamedGroup.SECP256_R1,
+                    NamedGroup.SECP384_R1,
+                    NamedGroup.SECP521_R1,
+                    NamedGroup.SECT283_K1,
+                    NamedGroup.SECT283_R1,
+                    NamedGroup.SECT409_K1,
+                    NamedGroup.SECT409_R1,
+                    NamedGroup.SECT571_K1,
+                    NamedGroup.SECT571_R1,
+
+                    // FFDHE 2048
+                    NamedGroup.FFDHE_2048,
+                    NamedGroup.FFDHE_3072,
+                    NamedGroup.FFDHE_4096,
+                    NamedGroup.FFDHE_6144,
+                    NamedGroup.FFDHE_8192,
+                };
+            } else {
+                groups = new NamedGroup[] {
+                    // NIST curves first
+                    NamedGroup.SECP256_R1,
+                    NamedGroup.SECP384_R1,
+                    NamedGroup.SECP521_R1,
+                    NamedGroup.SECT283_K1,
+                    NamedGroup.SECT283_R1,
+                    NamedGroup.SECT409_K1,
+                    NamedGroup.SECT409_R1,
+                    NamedGroup.SECT571_K1,
+                    NamedGroup.SECT571_R1,
+
+                    // non-NIST curves
+                    NamedGroup.SECP256_K1,
+
+                    // FFDHE 2048
+                    NamedGroup.FFDHE_2048,
+                    NamedGroup.FFDHE_3072,
+                    NamedGroup.FFDHE_4096,
+                    NamedGroup.FFDHE_6144,
+                    NamedGroup.FFDHE_8192,
+                };
+            }
+
+            groupList = new ArrayList<>(groups.length);
+            for (NamedGroup group : groups) {
+                if (isAvailableGroup(group)) {
+                    groupList.add(group);
+                }
+            }
+        }
+
+        if (debug != null && groupList.isEmpty()) {
+            Debug.log(
+                "Initialized [jdk.tls.namedGroups|default] list contains " +
+                "no available elliptic curves. " +
+                (property != null ? "(" + property + ")" : "[Default]"));
+        }
+
+        supportedNamedGroups = new NamedGroup[groupList.size()];
+        int i = 0;
+        for (NamedGroup namedGroup : groupList) {
+            supportedNamedGroups[i++] = namedGroup;
+        }
+    }
+
+    // check whether the group is supported by the underlying providers
+    private static boolean isAvailableGroup(NamedGroup namedGroup) {
+        AlgorithmParameters params = null;
+        AlgorithmParameterSpec spec = null;
+        if ("EC".equals(namedGroup.algorithm)) {
+            if (namedGroup.oid != null) {
+                try {
+                    params = JsseJce.getAlgorithmParameters("EC");
+                    spec = new ECGenParameterSpec(namedGroup.oid);
+                } catch (Exception e) {
+                    return false;
+                }
+            }
+        } else if ("DiffieHellman".equals(namedGroup.algorithm)) {
+            try {
+                params = JsseJce.getAlgorithmParameters("DiffieHellman");
+                spec = getFFDHEDHParameterSpec(namedGroup);
+            } catch (Exception e) {
+                return false;
+            }
+        }
+
+        if ((params != null) && (spec != null)) {
+            try {
+                params.init(spec);
+            } catch (Exception e) {
+                return false;
+            }
+
+            // cache the parameters
+            namedGroupParams.put(namedGroup, params);
+
+            return true;
+        }
+
+        return false;
+    }
+
+    private static DHParameterSpec getFFDHEDHParameterSpec(
+            NamedGroup namedGroup) {
+        DHParameterSpec spec = null;
+        switch (namedGroup) {
+            case FFDHE_2048:
+                spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
+                break;
+            case FFDHE_3072:
+                spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
+                break;
+            case FFDHE_4096:
+                spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
+                break;
+            case FFDHE_6144:
+                spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
+                break;
+            case FFDHE_8192:
+                spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
+        }
+
+        return spec;
+    }
+
+    private static DHParameterSpec getPredefinedDHParameterSpec(
+            NamedGroup namedGroup) {
+        DHParameterSpec spec = null;
+        switch (namedGroup) {
+            case FFDHE_2048:
+                spec = PredefinedDHParameterSpecs.definedParams.get(2048);
+                break;
+            case FFDHE_3072:
+                spec = PredefinedDHParameterSpecs.definedParams.get(3072);
+                break;
+            case FFDHE_4096:
+                spec = PredefinedDHParameterSpecs.definedParams.get(4096);
+                break;
+            case FFDHE_6144:
+                spec = PredefinedDHParameterSpecs.definedParams.get(6144);
+                break;
+            case FFDHE_8192:
+                spec = PredefinedDHParameterSpecs.definedParams.get(8192);
+        }
+
+        return spec;
+    }
+
+    private SupportedGroupsExtension(int[] requestedNamedGroupIds) {
+        super(ExtensionType.EXT_SUPPORTED_GROUPS);
+
+        this.requestedNamedGroupIds = requestedNamedGroupIds;
+    }
+
+    SupportedGroupsExtension(HandshakeInStream s, int len) throws IOException {
+        super(ExtensionType.EXT_SUPPORTED_GROUPS);
+
+        int k = s.getInt16();
+        if (((len & 1) != 0) || (k == 0) || (k + 2 != len)) {
+            throw new SSLProtocolException("Invalid " + type + " extension");
+        }
+
+        // Note: unknown named group will be ignored later.
+        requestedNamedGroupIds = new int[k >> 1];
+        for (int i = 0; i < requestedNamedGroupIds.length; i++) {
+            requestedNamedGroupIds[i] = s.getInt16();
+        }
+    }
+
+    // Get a local preferred supported ECDHE group permitted by the constraints.
+    static NamedGroup getPreferredECGroup(AlgorithmConstraints constraints) {
+        for (NamedGroup namedGroup : supportedNamedGroups) {
+            if ((namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) &&
+                constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                    namedGroup.algorithm, namedGroupParams.get(namedGroup))) {
+
+                return namedGroup;
+            }
+        }
+
+        return null;
+    }
+
+    // Is there any supported group permitted by the constraints?
+    static boolean isActivatable(
+            AlgorithmConstraints constraints, NamedGroupType type) {
+
+        boolean hasFFDHEGroups = false;
+        for (NamedGroup namedGroup : supportedNamedGroups) {
+            if (namedGroup.type == type) {
+                if (constraints.permits(
+                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                        namedGroup.algorithm,
+                        namedGroupParams.get(namedGroup))) {
+
+                    return true;
+                }
+
+                if (!hasFFDHEGroups &&
+                        (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
+
+                    hasFFDHEGroups = true;
+                }
+            }
+        }
+
+        // For compatibility, if no FFDHE groups are defined, the non-FFDHE
+        // compatible mode (using DHE cipher suite without FFDHE extension)
+        // is allowed.
+        //
+        // Note that the constraints checking on DHE parameters will be
+        // performed during key exchanging in a handshake.
+        if (!hasFFDHEGroups && (type == NamedGroupType.NAMED_GROUP_FFDHE)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    // Create the default supported groups extension.
+    static SupportedGroupsExtension createExtension(
+            AlgorithmConstraints constraints,
+            CipherSuiteList cipherSuites, boolean enableFFDHE) {
+
+        ArrayList<Integer> groupList =
+                new ArrayList<>(supportedNamedGroups.length);
+        for (NamedGroup namedGroup : supportedNamedGroups) {
+            if ((!enableFFDHE) &&
+                (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE)) {
+                continue;
+            }
+
+            if (cipherSuites.contains(namedGroup.type) &&
+                constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                    namedGroup.algorithm, namedGroupParams.get(namedGroup))) {
+
+                groupList.add(namedGroup.id);
+            }
+        }
+
+        if (!groupList.isEmpty()) {
+            int[] ids = new int[groupList.size()];
+            int i = 0;
+            for (Integer id : groupList) {
+                ids[i++] = id;
+            }
+
+            return new SupportedGroupsExtension(ids);
+        }
+
+        return null;
+    }
+
+    // get the preferred activated named group
+    NamedGroup getPreferredGroup(
+            AlgorithmConstraints constraints, NamedGroupType type) {
+
+        for (int groupId : requestedNamedGroupIds) {
+            NamedGroup namedGroup = NamedGroup.valueOf(groupId);
+            if ((namedGroup != null) && (namedGroup.type == type) &&
+                SupportedGroupsExtension.supports(namedGroup) &&
+                constraints.permits(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                    namedGroup.algorithm, namedGroupParams.get(namedGroup))) {
+
+                return namedGroup;
+            }
+        }
+
+        return null;
+    }
+
+    boolean hasFFDHEGroup() {
+        for (int groupId : requestedNamedGroupIds) {
+            /*
+             * [RFC 7919] Codepoints in the "Supported Groups Registry"
+             * with a high byte of 0x01 (that is, between 256 and 511,
+             * inclusive) are set aside for FFDHE groups.
+             */
+            if ((groupId >= 256) && (groupId <= 511)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    boolean contains(int index) {
+        for (int groupId : requestedNamedGroupIds) {
+            if (index == groupId) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    int length() {
+        return 6 + (requestedNamedGroupIds.length << 1);
+    }
+
+    @Override
+    void send(HandshakeOutStream s) throws IOException {
+        s.putInt16(type.id);
+        int k = requestedNamedGroupIds.length << 1;
+        s.putInt16(k + 2);
+        s.putInt16(k);
+        for (int groupId : requestedNamedGroupIds) {
+            s.putInt16(groupId);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Extension " + type + ", group names: {");
+        boolean first = true;
+        for (int groupId : requestedNamedGroupIds) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            // first check if it is a known named group, then try other cases.
+            NamedGroup namedGroup = NamedGroup.valueOf(groupId);
+            if (namedGroup != null) {
+                sb.append(namedGroup.name);
+            } else if (groupId == ARBITRARY_PRIME) {
+                sb.append("arbitrary_explicit_prime_curves");
+            } else if (groupId == ARBITRARY_CHAR2) {
+                sb.append("arbitrary_explicit_char2_curves");
+            } else {
+                sb.append("unknown named group " + groupId);
+            }
+        }
+        sb.append("}");
+        return sb.toString();
+    }
+
+    static boolean supports(NamedGroup namedGroup) {
+        for (NamedGroup group : supportedNamedGroups) {
+            if (namedGroup.id == group.id) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
+        if (namedGroup.type != NamedGroupType.NAMED_GROUP_ECDHE) {
+            throw new RuntimeException("Not a named EC group: " + namedGroup);
+        }
+
+        AlgorithmParameters params = namedGroupParams.get(namedGroup);
+        try {
+            return params.getParameterSpec(ECGenParameterSpec.class);
+        } catch (InvalidParameterSpecException ipse) {
+            // should be unlikely
+            return new ECGenParameterSpec(namedGroup.oid);
+        }
+    }
+
+    static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
+        if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
+            throw new RuntimeException("Not a named DH group: " + namedGroup);
+        }
+
+        AlgorithmParameters params = namedGroupParams.get(namedGroup);
+        try {
+            return params.getParameterSpec(DHParameterSpec.class);
+        } catch (InvalidParameterSpecException ipse) {
+            // should be unlikely
+            return getPredefinedDHParameterSpec(namedGroup);
+        }
+    }
+}
--- a/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java	Tue May 23 16:59:50 2017 +0100
+++ b/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java	Thu May 25 23:31:47 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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
@@ -31,33 +31,44 @@
  * @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
+ * @run main/othervm -Djsse.enableFFDHE=false
  *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
  *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
  *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
  *      DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
  *
- * @run main/othervm
+ * @run main/othervm -Djsse.enableFFDHE=false
  *      DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 229 75
  *
- * @run main/othervm
+ * @run main/othervm -Djsse.enableFFDHE=false
  *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1383 139
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
  *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1319 107
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
  *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1639 267
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
  *      DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA  false 1383 139
  *
- * @run main/othervm
+ * @run main/othervm -Djsse.enableFFDHE=false
  *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 357 139
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=legacy
  *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 293 107
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=matched
  *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 357 139
- * @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
+ * @run main/othervm -Djsse.enableFFDHE=false
+ *      -Djdk.tls.ephemeralDHKeySize=1024
  *      DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5  false 357 139
  */
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/sun/security/ssl/DHKeyExchange/UseStrongDHSizes.java	Thu May 25 23:31:47 2017 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 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
+ * 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8140436
+ * @modules jdk.crypto.ec
+ * @library /javax/net/ssl/templates
+ * @summary Negotiated Finite Field Diffie-Hellman Ephemeral Parameters for TLS
+ * @run main/othervm UseStrongDHSizes 2048
+ */
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.security.Security;
+import javax.net.ssl.SSLSocket;
+
+public class UseStrongDHSizes extends SSLSocketTemplate {
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        // reset the security property to make sure that the algorithms
+        // and keys used in this test are not disabled unexpectedly.
+        String constraint = "DH keySize < " + Integer.valueOf(args[0]);
+        Security.setProperty("jdk.tls.disabledAlgorithms", constraint);
+        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
+
+        (new UseStrongDHSizes()).run();
+    }
+
+    @Override
+    protected void runServerApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"};
+
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setWantClientAuth(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslIS.read();
+        sslOS.write(85);
+        sslOS.flush();
+    }
+
+    @Override
+    protected void runClientApplication(SSLSocket socket) throws Exception {
+        String ciphers[] = {
+                "TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
+                "TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
+                "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
+                "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"};
+        socket.setEnabledCipherSuites(ciphers);
+        socket.setUseClientMode(true);
+
+        InputStream sslIS = socket.getInputStream();
+        OutputStream sslOS = socket.getOutputStream();
+
+        sslOS.write(280);
+        sslOS.flush();
+        sslIS.read();
+    }
+}