mrege JDK-8171279-XDH-TLS-branch-2
authorapetcher
Thu, 30 Aug 2018 11:08:01 -0400
branchJDK-8171279-XDH-TLS-branch-2
changeset 56880 6ba2f471478b
parent 56879 2aefd58f8ec5 (diff)
parent 51592 1ddd1ec04431 (current diff)
mrege
src/hotspot/share/utilities/errorReporter.cpp
src/hotspot/share/utilities/errorReporter.hpp
src/java.base/share/classes/sun/security/ssl/X509Authentication.java
src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java
--- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Thu Aug 30 11:08:01 2018 -0400
@@ -61,7 +61,7 @@
     static final SSLKeyAgreementGenerator kaGenerator =
             new DHEKAGenerator();
 
-    static final class DHECredentials implements SSLCredentials {
+    static final class DHECredentials implements SSLKeyAgreementCredentials {
         final DHPublicKey popPublicKey;
         final NamedGroup namedGroup;
 
@@ -70,6 +70,11 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
         static DHECredentials valueOf(NamedGroup ng,
             byte[] encodedPublic) throws IOException, GeneralSecurityException {
 
@@ -401,7 +406,7 @@
 
         @Override
         public SSLKeyDerivation createKeyDerivation(
-                HandshakeContext context) throws IOException {
+        HandshakeContext context) throws IOException {
             DHEPossession dhePossession = null;
             DHECredentials dheCredentials = null;
             for (SSLPossession poss : context.handshakePossessions) {
@@ -424,7 +429,7 @@
                         DHParameterSpec pps = dhep.publicKey.getParams();
                         DHParameterSpec cps = dhec.popPublicKey.getParams();
                         if (pps.getP().equals(cps.getP()) &&
-                                pps.getG().equals(cps.getG())) {
+                        pps.getG().equals(cps.getG())) {
                             dheCredentials = (DHECredentials)cred;
                             break;
                         }
@@ -439,96 +444,11 @@
 
             if (dhePossession == null || dheCredentials == null) {
                 context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
-                    "No sufficient DHE key agreement parameters negotiated");
-            }
-
-            return new DHEKAKeyDerivation(context,
-                    dhePossession.privateKey, dheCredentials.popPublicKey);
-        }
-
-        private static final
-                class DHEKAKeyDerivation implements SSLKeyDerivation {
-            private final HandshakeContext context;
-            private final PrivateKey localPrivateKey;
-            private final PublicKey peerPublicKey;
-
-            DHEKAKeyDerivation(HandshakeContext context,
-                    PrivateKey localPrivateKey,
-                    PublicKey peerPublicKey) {
-                this.context = context;
-                this.localPrivateKey = localPrivateKey;
-                this.peerPublicKey = peerPublicKey;
-            }
-
-            @Override
-            public SecretKey deriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
-                    return t12DeriveKey(algorithm, params);
-                } else {
-                    return t13DeriveKey(algorithm, params);
-                }
+                "No sufficient DHE key agreement parameters negotiated");
             }
 
-            private SecretKey t12DeriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                try {
-                    KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
-                    ka.init(localPrivateKey);
-                    ka.doPhase(peerPublicKey, true);
-                    SecretKey preMasterSecret =
-                            ka.generateSecret("TlsPremasterSecret");
-                    SSLMasterKeyDerivation mskd =
-                            SSLMasterKeyDerivation.valueOf(
-                                    context.negotiatedProtocol);
-                    if (mskd == null) {
-                        // unlikely
-                        throw new SSLHandshakeException(
-                            "No expected master key derivation for protocol: " +
-                            context.negotiatedProtocol.name);
-                    }
-                    SSLKeyDerivation kd = mskd.createKeyDerivation(
-                            context, preMasterSecret);
-                    return kd.deriveKey("MasterSecret", params);
-                } catch (GeneralSecurityException gse) {
-                    throw (SSLHandshakeException) new SSLHandshakeException(
-                        "Could not generate secret").initCause(gse);
-                }
-            }
-
-            private SecretKey t13DeriveKey(String algorithm,
-                    AlgorithmParameterSpec params) throws IOException {
-                try {
-                    KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman");
-                    ka.init(localPrivateKey);
-                    ka.doPhase(peerPublicKey, true);
-                    SecretKey sharedSecret =
-                            ka.generateSecret("TlsPremasterSecret");
-
-                    HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
-                    SSLKeyDerivation kd = context.handshakeKeyDerivation;
-                    HKDF hkdf = new HKDF(hashAlg.name);
-                    if (kd == null) {   // No PSK is in use.
-                        // If PSK is not in use Early Secret will still be
-                        // HKDF-Extract(0, 0).
-                        byte[] zeros = new byte[hashAlg.hashLength];
-                        SecretKeySpec ikm =
-                                new SecretKeySpec(zeros, "TlsPreSharedSecret");
-                        SecretKey earlySecret =
-                                hkdf.extract(zeros, ikm, "TlsEarlySecret");
-                        kd = new SSLSecretDerivation(context, earlySecret);
-                    }
-
-                    // derive salt secret
-                    SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
-                    // derive handshake secret
-                    return hkdf.extract(saltSecret, sharedSecret, algorithm);
-                } catch (GeneralSecurityException gse) {
-                    throw (SSLHandshakeException) new SSLHandshakeException(
-                        "Could not generate secret").initCause(gse);
-                }
-            }
+            return new KAKeyDerivation("DiffieHellman", context,
+                dhePossession.privateKey, dheCredentials.popPublicKey);
         }
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Thu Aug 30 11:08:01 2018 -0400
@@ -63,7 +63,7 @@
     static final SSLKeyAgreementGenerator ecdhKAGenerator =
             new ECDHKAGenerator();
 
-    static final class ECDHECredentials implements SSLCredentials {
+    static final class ECDHECredentials implements SSLKeyAgreementCredentials {
         final ECPublicKey popPublicKey;
         final NamedGroup namedGroup;
 
@@ -72,6 +72,11 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
         static ECDHECredentials valueOf(NamedGroup namedGroup,
             byte[] encodedPoint) throws IOException, GeneralSecurityException {
 
@@ -299,7 +304,7 @@
                     "No sufficient ECDHE key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(shc,
+            return new KAKeyDerivation("ECDH", shc,
                 x509Possession.popPrivateKey, ecdheCredentials.popPublicKey);
         }
 
@@ -348,7 +353,7 @@
                     "No sufficient ECDH key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(chc,
+            return new KAKeyDerivation("ECDH", chc,
                 ecdhePossession.privateKey, x509Credentials.popPublicKey);
         }
     }
@@ -392,94 +397,8 @@
                     "No sufficient ECDHE key agreement parameters negotiated");
             }
 
-            return new ECDHEKAKeyDerivation(context,
+            return new KAKeyDerivation("ECDH", context,
                 ecdhePossession.privateKey, ecdheCredentials.popPublicKey);
         }
     }
-
-    private static final
-            class ECDHEKAKeyDerivation implements SSLKeyDerivation {
-        private final HandshakeContext context;
-        private final PrivateKey localPrivateKey;
-        private final PublicKey peerPublicKey;
-
-        ECDHEKAKeyDerivation(HandshakeContext context,
-                PrivateKey localPrivateKey,
-                PublicKey peerPublicKey) {
-            this.context = context;
-            this.localPrivateKey = localPrivateKey;
-            this.peerPublicKey = peerPublicKey;
-        }
-
-        @Override
-        public SecretKey deriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
-                return t12DeriveKey(algorithm, params);
-            } else {
-                return t13DeriveKey(algorithm, params);
-            }
-        }
-
-        private SecretKey t12DeriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            try {
-                KeyAgreement ka = JsseJce.getKeyAgreement("ECDH");
-                ka.init(localPrivateKey);
-                ka.doPhase(peerPublicKey, true);
-                SecretKey preMasterSecret =
-                        ka.generateSecret("TlsPremasterSecret");
-
-                SSLMasterKeyDerivation mskd =
-                        SSLMasterKeyDerivation.valueOf(
-                                context.negotiatedProtocol);
-                if (mskd == null) {
-                    // unlikely
-                    throw new SSLHandshakeException(
-                            "No expected master key derivation for protocol: " +
-                            context.negotiatedProtocol.name);
-                }
-                SSLKeyDerivation kd = mskd.createKeyDerivation(
-                        context, preMasterSecret);
-                return kd.deriveKey("MasterSecret", params);
-            } catch (GeneralSecurityException gse) {
-                throw (SSLHandshakeException) new SSLHandshakeException(
-                    "Could not generate secret").initCause(gse);
-            }
-        }
-
-        private SecretKey t13DeriveKey(String algorithm,
-                AlgorithmParameterSpec params) throws IOException {
-            try {
-                KeyAgreement ka = JsseJce.getKeyAgreement("ECDH");
-                ka.init(localPrivateKey);
-                ka.doPhase(peerPublicKey, true);
-                SecretKey sharedSecret =
-                        ka.generateSecret("TlsPremasterSecret");
-
-                HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
-                SSLKeyDerivation kd = context.handshakeKeyDerivation;
-                HKDF hkdf = new HKDF(hashAlg.name);
-                if (kd == null) {   // No PSK is in use.
-                    // If PSK is not in use Early Secret will still be
-                    // HKDF-Extract(0, 0).
-                    byte[] zeros = new byte[hashAlg.hashLength];
-                    SecretKeySpec ikm =
-                            new SecretKeySpec(zeros, "TlsPreSharedSecret");
-                    SecretKey earlySecret =
-                            hkdf.extract(zeros, ikm, "TlsEarlySecret");
-                    kd = new SSLSecretDerivation(context, earlySecret);
-                }
-
-                // derive salt secret
-                SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
-
-                // derive handshake secret
-                return hkdf.extract(saltSecret, sharedSecret, algorithm);
-            } catch (GeneralSecurityException gse) {
-                throw (SSLHandshakeException) new SSLHandshakeException(
-                    "Could not generate secret").initCause(gse);
-            }
-        }
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java	Thu Aug 30 11:08:01 2018 -0400
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018, 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 javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLHandshakeException;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
+
+public class KAKeyDerivation implements SSLKeyDerivation {
+
+    private final String algorithmName;
+    private final HandshakeContext context;
+    private final PrivateKey localPrivateKey;
+    private final PublicKey peerPublicKey;
+
+    KAKeyDerivation(String algorithmName,
+                    HandshakeContext context,
+                    PrivateKey localPrivateKey,
+                    PublicKey peerPublicKey) {
+        this.algorithmName = algorithmName;
+        this.context = context;
+        this.localPrivateKey = localPrivateKey;
+        this.peerPublicKey = peerPublicKey;
+    }
+
+    @Override
+    public
+    SecretKey deriveKey(String algorithm,
+                        AlgorithmParameterSpec params) throws IOException {
+        if (!context.negotiatedProtocol.useTLS13PlusSpec()) {
+            return t12DeriveKey(algorithm, params);
+        } else {
+            return t13DeriveKey(algorithm, params);
+        }
+    }
+
+    private
+    SecretKey t12DeriveKey(String algorithm,
+                           AlgorithmParameterSpec params) throws IOException {
+        try {
+            KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName);
+            ka.init(localPrivateKey);
+            ka.doPhase(peerPublicKey, true);
+            SecretKey preMasterSecret =
+            ka.generateSecret("TlsPremasterSecret");
+            SSLMasterKeyDerivation mskd =
+            SSLMasterKeyDerivation.valueOf(
+            context.negotiatedProtocol);
+            if (mskd == null) {
+                // unlikely
+                throw new SSLHandshakeException(
+                "No expected master key derivation for protocol: " +
+                context.negotiatedProtocol.name);
+            }
+            SSLKeyDerivation kd = mskd.createKeyDerivation(
+            context, preMasterSecret);
+            return kd.deriveKey("MasterSecret", params);
+        } catch (GeneralSecurityException gse) {
+            throw (SSLHandshakeException) new SSLHandshakeException(
+            "Could not generate secret").initCause(gse);
+        }
+    }
+
+    private
+    SecretKey t13DeriveKey(String algorithm,
+                           AlgorithmParameterSpec params) throws IOException {
+        try {
+            KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName);
+            ka.init(localPrivateKey);
+            ka.doPhase(peerPublicKey, true);
+            SecretKey sharedSecret =
+            ka.generateSecret("TlsPremasterSecret");
+
+            CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg;
+            SSLKeyDerivation kd = context.handshakeKeyDerivation;
+            HKDF hkdf = new HKDF(hashAlg.name);
+            if (kd == null) {   // No PSK is in use.
+                // If PSK is not in use Early Secret will still be
+                // HKDF-Extract(0, 0).
+                byte[] zeros = new byte[hashAlg.hashLength];
+                SecretKeySpec ikm =
+                new SecretKeySpec(zeros, "TlsPreSharedSecret");
+                SecretKey earlySecret =
+                hkdf.extract(zeros, ikm, "TlsEarlySecret");
+                kd = new SSLSecretDerivation(context, earlySecret);
+            }
+
+            // derive salt secret
+            SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null);
+
+            // derive handshake secret
+            return hkdf.extract(saltSecret, sharedSecret, algorithm);
+        } catch (GeneralSecurityException gse) {
+            throw (SSLHandshakeException) new SSLHandshakeException(
+            "Could not generate secret").initCause(gse);
+        }
+    }
+}
--- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Thu Aug 30 11:08:01 2018 -0400
@@ -42,12 +42,14 @@
 import sun.security.ssl.DHKeyExchange.DHEPossession;
 import sun.security.ssl.ECDHKeyExchange.ECDHECredentials;
 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+import sun.security.ssl.XDHKeyExchange.XDHEPossession;
+import sun.security.ssl.XDHKeyExchange.XDHECredentials;
 import sun.security.ssl.KeyShareExtension.CHKeyShareSpec;
 import sun.security.ssl.SSLExtension.ExtensionConsumer;
 import sun.security.ssl.SSLExtension.SSLExtensionSpec;
 import sun.security.ssl.SSLHandshake.HandshakeMessage;
 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroupFunctions;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.util.HexDumpEncoder;
 
@@ -265,7 +267,8 @@
                     // update the context
                     chc.handshakePossessions.add(pos);
                     if (!(pos instanceof ECDHEPossession) &&
-                            !(pos instanceof DHEPossession)) {
+                        !(pos instanceof DHEPossession) &&
+                        !(pos instanceof XDHEPossession)) {
                         // May need more possesion types in the future.
                         continue;
                     }
@@ -354,46 +357,26 @@
                     continue;
                 }
 
-                if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                    try {
-                        ECDHECredentials ecdhec =
-                            ECDHECredentials.valueOf(ng, entry.keyExchange);
-                        if (ecdhec != null) {
-                            if (!shc.algorithmConstraints.permits(
-                                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                    ecdhec.popPublicKey)) {
-                                SSLLogger.warning(
-                                        "ECDHE key share entry does not " +
-                                        "comply to algorithm constraints");
-                            } else {
-                                credentials.add(ecdhec);
-                            }
+                try {
+                    NamedGroupFunctions ngf = ng.getFunctions().orElseThrow(
+                        GeneralSecurityException::new);
+                    SSLKeyAgreementCredentials kaCred =
+                        ngf.decodeCredentials(entry.keyExchange);
+                    if (kaCred != null) {
+                        if (!shc.algorithmConstraints.permits(
+                        EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                        kaCred.getPublicKey())) {
+                            SSLLogger.warning(
+                                "key share entry does not " +
+                                "comply with algorithm constraints");
+                        } else {
+                            credentials.add(kaCred);
                         }
-                    } catch (IOException | GeneralSecurityException ex) {
-                        SSLLogger.warning(
-                                "Cannot decode named group: " +
-                                NamedGroup.nameOf(entry.namedGroupId));
                     }
-                } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                    try {
-                        DHECredentials dhec =
-                                DHECredentials.valueOf(ng, entry.keyExchange);
-                        if (dhec != null) {
-                            if (!shc.algorithmConstraints.permits(
-                                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                    dhec.popPublicKey)) {
-                                SSLLogger.warning(
-                                        "DHE key share entry does not " +
-                                        "comply to algorithm constraints");
-                            } else {
-                                credentials.add(dhec);
-                            }
-                        }
-                    } catch (IOException | GeneralSecurityException ex) {
-                        SSLLogger.warning(
-                                "Cannot decode named group: " +
-                                NamedGroup.nameOf(entry.namedGroupId));
-                    }
+                } catch (GeneralSecurityException ex) {
+                    SSLLogger.warning(
+                        "Cannot decode named group: " +
+                        NamedGroup.nameOf(entry.namedGroupId));
                 }
             }
 
@@ -531,6 +514,8 @@
                     ng = ((ECDHECredentials)cd).namedGroup;
                 } else if (cd instanceof DHECredentials) {
                     ng = ((DHECredentials)cd).namedGroup;
+                } else if (cd instanceof XDHECredentials) {
+                    ng = ((XDHECredentials)cd).namedGroup;
                 }
 
                 if (ng == null) {
@@ -549,7 +534,8 @@
                 SSLPossession[] poses = ke.createPossessions(shc);
                 for (SSLPossession pos : poses) {
                     if (!(pos instanceof ECDHEPossession) &&
-                            !(pos instanceof DHEPossession)) {
+                        !(pos instanceof DHEPossession) &&
+                        !(pos instanceof XDHEPossession)) {
                         // May need more possesion types in the future.
                         continue;
                     }
@@ -649,50 +635,26 @@
             }
 
             SSLCredentials credentials = null;
-            if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                try {
-                    ECDHECredentials ecdhec =
-                            ECDHECredentials.valueOf(ng, keyShare.keyExchange);
-                    if (ecdhec != null) {
-                        if (!chc.algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                ecdhec.popPublicKey)) {
-                            chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                                    "ECDHE key share entry does not " +
-                                    "comply to algorithm constraints");
-                        } else {
-                            credentials = ecdhec;
-                        }
+            try {
+                NamedGroupFunctions ngf = ng.getFunctions().orElseThrow(
+                    GeneralSecurityException::new);
+                SSLKeyAgreementCredentials kaCred =
+                    ngf.decodeCredentials(keyShare.keyExchange);
+                if (kaCred != null) {
+                    if (!chc.algorithmConstraints.permits(
+                            EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+                            kaCred.getPublicKey())) {
+                        chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
+                            "key share entry does not " +
+                            "comply to algorithm constraints");
+                    } else {
+                        credentials = kaCred;
                     }
-                } catch (IOException | GeneralSecurityException ex) {
-                    chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                            "Cannot decode named group: " +
-                            NamedGroup.nameOf(keyShare.namedGroupId));
                 }
-            } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                try {
-                    DHECredentials dhec =
-                            DHECredentials.valueOf(ng, keyShare.keyExchange);
-                    if (dhec != null) {
-                        if (!chc.algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                dhec.popPublicKey)) {
-                            chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                                    "DHE key share entry does not " +
-                                    "comply to algorithm constraints");
-                        } else {
-                            credentials = dhec;
-                        }
-                    }
-                } catch (IOException | GeneralSecurityException ex) {
-                    chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                            "Cannot decode named group: " +
-                            NamedGroup.nameOf(keyShare.namedGroupId));
-                }
-            } else {
+            } catch (IOException | GeneralSecurityException ex) {
                 chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                        "Unsupported named group: " +
-                        NamedGroup.nameOf(keyShare.namedGroupId));
+                "Cannot decode named group: " +
+                NamedGroup.nameOf(keyShare.namedGroupId));
             }
 
             if (credentials == null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyAgreementCredentials.java	Thu Aug 30 11:08:01 2018 -0400
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018, 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.PublicKey;
+
+interface SSLKeyAgreementCredentials extends SSLCredentials {
+
+    PublicKey getPublicKey();
+}
--- a/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Thu Aug 30 11:08:01 2018 -0400
@@ -30,10 +30,9 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
-import sun.security.ssl.DHKeyExchange.DHEPossession;
-import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+import java.util.Optional;
 import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
-import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroupFunctions;
 import sun.security.ssl.SupportedGroupsExtension.SupportedGroups;
 import sun.security.ssl.X509Authentication.X509Possession;
 
@@ -570,27 +569,24 @@
 
         @Override
         public SSLPossession createPossession(HandshakeContext hc) {
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return new ECDHEPossession(
-                        namedGroup, hc.sslContext.getSecureRandom());
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return new DHEPossession(
-                        namedGroup, hc.sslContext.getSecureRandom());
+
+            Optional<NamedGroupFunctions> ngf = namedGroup.getFunctions();
+            if (ngf.isEmpty()) {
+                return null;
             }
-
-            return null;
+            return ngf.get().createPossession(hc.sslContext.getSecureRandom());
         }
 
         @Override
         public SSLKeyDerivation createKeyDerivation(
                 HandshakeContext hc) throws IOException {
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+
+            Optional<NamedGroupFunctions> ngf = namedGroup.getFunctions();
+            if (ngf.isEmpty()) {
+                return null;
             }
+            return ngf.get().createKeyDerivation(hc);
 
-            return null;
         }
     }
 }
--- a/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Thu Aug 30 11:08:01 2018 -0400
@@ -31,20 +31,24 @@
 import java.security.AlgorithmConstraints;
 import java.security.AlgorithmParameters;
 import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
 import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.NamedParameterSpec;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.EnumSet;
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 import javax.crypto.spec.DHParameterSpec;
 import javax.net.ssl.SSLProtocolException;
 import sun.security.action.GetPropertyAction;
@@ -158,7 +162,7 @@
         }
     }
 
-    static enum NamedGroupType {
+    enum NamedGroupType {
         NAMED_GROUP_ECDHE,          // Elliptic Curve Groups (ECDHE)
         NAMED_GROUP_FFDHE,          // Finite Field Groups (DHE)
         NAMED_GROUP_XDH,            // Finite Field Groups (XDH)
@@ -176,6 +180,264 @@
         }
     }
 
+    public static abstract class NamedGroupFunctions {
+
+        // cache to speed up the parameters construction
+        protected static final Map<NamedGroup, AlgorithmParameters>
+            namedGroupParams = new ConcurrentHashMap<>();
+
+        private final NamedGroup ng;
+
+        protected NamedGroupFunctions(NamedGroup ng) {
+            this.ng = ng;
+        }
+
+        public AlgorithmParameters getParameters() {
+
+            AlgorithmParameters result = namedGroupParams.get(ng);
+            if (result == null) {
+                Optional<AlgorithmParameters> paramsOpt = getParametersImpl();
+                if (paramsOpt.isPresent()) {
+                    result = paramsOpt.get();
+                    namedGroupParams.put(ng, result);
+                }
+            }
+
+            return result;
+        }
+
+        public NamedGroup getNamedGroup() {
+            return ng;
+        }
+
+        public abstract
+        SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+            throws IOException, GeneralSecurityException;
+
+        public abstract SSLPossession createPossession(SecureRandom random);
+
+        public abstract
+        SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+            throws IOException;
+
+        protected abstract Optional<AlgorithmParameters> getParametersImpl();
+        public abstract AlgorithmParameterSpec getParameterSpec();
+
+        public abstract boolean isAvailable();
+    }
+
+    private static class FFDHFunctions extends NamedGroupFunctions {
+
+
+        FFDHFunctions(NamedGroup ng) {
+            super(ng);
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+                throws IOException, GeneralSecurityException {
+            return DHKeyExchange.DHECredentials.valueOf(getNamedGroup(),
+                                                        encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new DHKeyExchange.DHEPossession(getNamedGroup(), random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return getDHParameterSpec();
+        }
+
+        DHParameterSpec getDHParameterSpec() {
+
+            AlgorithmParameters params = getParameters();
+            try {
+                return params.getParameterSpec(DHParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                // should be unlikely
+                return getPredefinedDHParameterSpec(getNamedGroup());
+            }
+        }
+
+        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;
+        }
+
+        @Override
+        public boolean isAvailable() {
+
+            AlgorithmParameters params = getParameters();
+            return params != null;
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl() {
+            try {
+                AlgorithmParameters params =
+                    JsseJce.getAlgorithmParameters("DiffieHellman");
+                AlgorithmParameterSpec spec =
+                    getFFDHEDHParameterSpec(getNamedGroup());
+                params.init(spec);
+                return Optional.of(params);
+            } catch (InvalidParameterSpecException |
+                     NoSuchAlgorithmException ex) {
+                return Optional.empty();
+            }
+        }
+
+    }
+
+    private static class ECDHFunctions extends NamedGroupFunctions {
+
+        ECDHFunctions(NamedGroup ng) {
+            super(ng);
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+        throws IOException, GeneralSecurityException {
+            return ECDHKeyExchange.ECDHECredentials.valueOf(getNamedGroup(),
+                                                            encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new ECDHKeyExchange.ECDHEPossession(getNamedGroup(),
+                                                       random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return SupportedGroups.getECGenParamSpec(getNamedGroup());
+        }
+
+        @Override
+        public boolean isAvailable() {
+
+            AlgorithmParameters params = getParameters();
+            return params != null;
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl() {
+            try {
+                AlgorithmParameters params =
+                    JsseJce.getAlgorithmParameters("EC");
+                AlgorithmParameterSpec spec =
+                    new ECGenParameterSpec(getNamedGroup().oid);
+                params.init(spec);
+                return Optional.of(params);
+            } catch (InvalidParameterSpecException |
+                     NoSuchAlgorithmException ex) {
+                return Optional.empty();
+            }
+        }
+    }
+
+    private static class XDHFunctions extends NamedGroupFunctions {
+
+        XDHFunctions(NamedGroup ng) {
+            super(ng);
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+                throws IOException, GeneralSecurityException {
+            return XDHKeyExchange.XDHECredentials.valueOf(getNamedGroup(),
+                                                          encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new XDHKeyExchange.XDHEPossession(getNamedGroup(), random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return new NamedParameterSpec(getNamedGroup().algorithm);
+        }
+
+        @Override
+        public boolean isAvailable() {
+
+            try {
+                JsseJce.getKeyAgreement(getNamedGroup().algorithm);
+                return true;
+            } catch (NoSuchAlgorithmException ex) {
+                return false;
+            }
+        }
+
+        @Override
+        protected Optional<AlgorithmParameters> getParametersImpl() {
+            return Optional.empty();
+        }
+    }
+
     static enum NamedGroup {
         // Elliptic Curves (RFC 4492)
         //
@@ -292,12 +554,14 @@
         final String algorithm;     // signature algorithm
         final boolean isFips;       // can be used in FIPS mode?
         final ProtocolVersion[] supportedProtocols;
+        private final NamedGroupFunctions functions;    // may be null
 
         // Constructor used for Elliptic Curve Groups (ECDHE)
         private NamedGroup(int id, String name, String oid, boolean isFips,
                 ProtocolVersion[] supportedProtocols) {
             this.id = id;
             this.type = NamedGroupType.NAMED_GROUP_ECDHE;
+            this.functions = new ECDHFunctions(this);
             this.name = name;
             this.oid = oid;
             this.algorithm = "EC";
@@ -311,6 +575,7 @@
                 ProtocolVersion[] supportedProtocols) {
             this.id = id;
             this.type = NamedGroupType.NAMED_GROUP_XDH;
+            this.functions = new XDHFunctions(this);
             this.name = name;
             this.oid = null;
             this.algorithm = algorithm;
@@ -323,6 +588,7 @@
                 ProtocolVersion[] supportedProtocols) {
             this.id = id;
             this.type = NamedGroupType.NAMED_GROUP_FFDHE;
+            this.functions = new FFDHFunctions(this);
             this.name = name;
             this.oid = null;
             this.algorithm = "DiffieHellman";
@@ -335,6 +601,7 @@
                 ProtocolVersion[] supportedProtocols) {
             this.id = id;
             this.type = NamedGroupType.NAMED_GROUP_ARBITRARY;
+            this.functions = null;
             this.name = name;
             this.oid = null;
             this.algorithm = "EC";
@@ -342,6 +609,10 @@
             this.supportedProtocols = supportedProtocols;
         }
 
+        Optional<NamedGroupFunctions> getFunctions() {
+            return Optional.ofNullable(functions);
+        }
+
         static NamedGroup valueOf(int id) {
             for (NamedGroup group : NamedGroup.values()) {
                 if (group.id == id) {
@@ -367,15 +638,14 @@
         }
 
         static NamedGroup valueOf(DHParameterSpec params) {
-            for (Map.Entry<NamedGroup, AlgorithmParameters> me :
-                    SupportedGroups.namedGroupParams.entrySet()) {
-                NamedGroup ng = me.getKey();
+            for (NamedGroup ng : NamedGroup.values()) {
                 if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
                     continue;
                 }
 
                 DHParameterSpec ngParams = null;
-                AlgorithmParameters aps = me.getValue();
+                // functions is non-null for FFDHE type
+                AlgorithmParameters aps = ng.functions.getParameters();
                 try {
                     ngParams = aps.getParameterSpec(DHParameterSpec.class);
                 } catch (InvalidParameterSpecException ipse) {
@@ -446,17 +716,18 @@
 
         // lazy loading of parameters
         AlgorithmParameters getParameters() {
-            return SupportedGroups.namedGroupParams.get(this);
+            if (functions == null) {
+                return null;
+            }
+            return functions.getParameters();
         }
 
         AlgorithmParameterSpec getParameterSpec() {
-            if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                return SupportedGroups.getECGenParamSpec(this);
-            } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                return SupportedGroups.getDHParameterSpec(this);
+            Optional<NamedGroupFunctions> ngf = getFunctions();
+            if (ngf.isEmpty()) {
+                return null;
             }
-
-            return null;
+            return ngf.get().getParameterSpec();
         }
     }
 
@@ -465,10 +736,6 @@
         static final boolean enableFFDHE =
                 Utilities.getBooleanProperty("jsse.enableFFDHE", true);
 
-        // cache to speed up the parameters construction
-        static final Map<NamedGroup,
-                    AlgorithmParameters> namedGroupParams = new HashMap<>();
-
         // the supported named groups
         static final NamedGroup[] supportedNamedGroups;
 
@@ -552,6 +819,10 @@
                         // non-NIST curves
                         NamedGroup.SECP256_K1,
 
+                        // XDH
+                        NamedGroup.X25519,
+                        NamedGroup.X448,
+
                         // FFDHE 2048
                         NamedGroup.FFDHE_2048,
                         NamedGroup.FFDHE_3072,
@@ -583,86 +854,13 @@
 
         // check whether the group is supported by the underlying providers
         private static boolean isAvailableGroup(NamedGroup namedGroup) {
-            AlgorithmParameters params = null;
-            AlgorithmParameterSpec spec = null;
-            if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-                if (namedGroup.oid != null) {
-                    try {
-                        params = JsseJce.getAlgorithmParameters("EC");
-                        spec = new ECGenParameterSpec(namedGroup.oid);
-                    } catch (NoSuchAlgorithmException e) {
-                        return false;
-                    }
-                }
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-                try {
-                    params = JsseJce.getAlgorithmParameters("DiffieHellman");
-                    spec = getFFDHEDHParameterSpec(namedGroup);
-                } catch (NoSuchAlgorithmException e) {
-                    return false;
-                }
-            }   // Otherwise, unsupported.
 
-            if ((params != null) && (spec != null)) {
-                try {
-                    params.init(spec);
-                } catch (InvalidParameterSpecException e) {
-                    return false;
-                }
-
-                // cache the parameters
-                namedGroupParams.put(namedGroup, params);
-
-                return true;
+            Optional<NamedGroupFunctions> ngfOpt = namedGroup.getFunctions();
+            if (ngfOpt.isEmpty()) {
+                return false;
             }
-
-            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;
+            NamedGroupFunctions ngf = ngfOpt.get();
+            return ngf.isAvailable();
         }
 
         static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
@@ -671,7 +869,8 @@
                         "Not a named EC group: " + namedGroup);
             }
 
-            AlgorithmParameters params = namedGroupParams.get(namedGroup);
+            // functions is non-null for ECDHE type
+            AlgorithmParameters params = namedGroup.functions.getParameters();
             try {
                 return params.getParameterSpec(ECGenParameterSpec.class);
             } catch (InvalidParameterSpecException ipse) {
@@ -680,19 +879,12 @@
             }
         }
 
-        static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
-            if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
-                throw new RuntimeException(
-                        "Not a named DH group: " + namedGroup);
+        static AlgorithmParameters getParameters(NamedGroup ng) {
+            AlgorithmParameters params = null;
+            if (ng.functions != null) {
+                params = ng.functions.getParameters();
             }
-
-            AlgorithmParameters params = namedGroupParams.get(namedGroup);
-            try {
-                return params.getParameterSpec(DHParameterSpec.class);
-            } catch (InvalidParameterSpecException ipse) {
-                // should be unlikely
-                return getPredefinedDHParameterSpec(namedGroup);
-            }
+            return params;
         }
 
         // Is there any supported group permitted by the constraints?
@@ -705,7 +897,7 @@
                     if (constraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             namedGroup.algorithm,
-                            namedGroupParams.get(namedGroup))) {
+                            getParameters(namedGroup))) {
 
                         return true;
                     }
@@ -736,7 +928,7 @@
             return constraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                             namedGroup.algorithm,
-                            namedGroupParams.get(namedGroup));
+                            getParameters(namedGroup));
         }
 
         // Is there any supported group permitted by the constraints?
@@ -760,7 +952,7 @@
                         constraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 namedGroup.algorithm,
-                                namedGroupParams.get(namedGroup))) {
+                                getParameters(namedGroup))) {
                     return namedGroup;
                 }
             }
@@ -777,7 +969,7 @@
                         constraints.permits(
                                 EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
                                 namedGroup.algorithm,
-                                namedGroupParams.get(namedGroup))) {
+                                getParameters(namedGroup))) {
                     return namedGroup;
                 }
             }
@@ -825,7 +1017,7 @@
                         ng.isSupported(chc.activeCipherSuites) &&
                         chc.algorithmConstraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                            ng.algorithm, namedGroupParams.get(ng))) {
+                            ng.algorithm, getParameters(ng))) {
                     namedGroups.add(ng);
                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                     SSLLogger.fine(
@@ -953,7 +1145,7 @@
                         ng.isSupported(shc.activeCipherSuites) &&
                         shc.algorithmConstraints.permits(
                             EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                            ng.algorithm, namedGroupParams.get(ng))) {
+                            ng.algorithm, getParameters(ng))) {
                     namedGroups.add(ng);
                 } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                     SSLLogger.fine(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java	Thu Aug 30 11:08:01 2018 -0400
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018, 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.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.interfaces.XECPublicKey;
+import java.security.spec.*;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroup;
+import sun.security.ssl.SupportedGroupsExtension.NamedGroupType;
+import sun.security.util.ECUtil;
+
+final class XDHKeyExchange {
+    static final SSLKeyAgreementGenerator xdheKAGenerator =
+            new XDHEKAGenerator();
+
+    static final class XDHECredentials implements SSLKeyAgreementCredentials {
+        final XECPublicKey popPublicKey;
+        final NamedGroup namedGroup;
+
+        XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) {
+            this.popPublicKey = popPublicKey;
+            this.namedGroup = namedGroup;
+        }
+
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
+        static XDHECredentials valueOf(NamedGroup namedGroup,
+            byte[] encodedPoint) throws IOException, GeneralSecurityException {
+
+            if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) {
+                throw new RuntimeException(
+                    "Credentials decoding:  Not XDH named group");
+            }
+
+            if (encodedPoint == null || encodedPoint.length == 0) {
+                return null;
+            }
+
+            NamedParameterSpec namedSpec =
+                new NamedParameterSpec(namedGroup.algorithm);
+            XECPublicKeySpec xecKeySpec =
+                ECUtil.decodeXecPublicKey(encodedPoint, namedSpec);
+            KeyFactory factory = JsseJce.getKeyFactory(namedGroup.algorithm);
+
+            XECPublicKey publicKey =
+                (XECPublicKey) factory.generatePublic(xecKeySpec);
+            return new XDHECredentials(publicKey, namedGroup);
+        }
+    }
+
+    static final class XDHEPossession implements SSLPossession {
+        final PrivateKey privateKey;
+        final XECPublicKey publicKey;
+        final NamedGroup namedGroup;
+
+        XDHEPossession(NamedGroup namedGroup, SecureRandom random) {
+            try {
+                KeyPairGenerator kpg =
+                    JsseJce.getKeyPairGenerator(namedGroup.algorithm);
+                AlgorithmParameterSpec params = namedGroup.getParameterSpec();
+                kpg.initialize(params, random);
+                KeyPair kp = kpg.generateKeyPair();
+                privateKey = kp.getPrivate();
+                publicKey = (XECPublicKey) kp.getPublic();
+            } catch (GeneralSecurityException e) {
+                throw new RuntimeException(
+                    "Could not generate XDH keypair", e);
+            }
+
+            this.namedGroup = namedGroup;
+        }
+
+        @Override
+        public byte[] encode() {
+            try {
+                return ECUtil.encodeXecPublicKey(publicKey.getU(),
+                                                 publicKey.getParams());
+            } catch (InvalidParameterSpecException ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+    }
+
+    private static final
+            class XDHEKAGenerator implements SSLKeyAgreementGenerator {
+        // Prevent instantiation of this class.
+        private XDHEKAGenerator() {
+            // blank
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext context) throws IOException {
+            XDHEPossession xdhePossession = null;
+            XDHECredentials xdheCredentials = null;
+            for (SSLPossession poss : context.handshakePossessions) {
+                if (!(poss instanceof XDHEPossession)) {
+                    continue;
+                }
+
+                NamedGroup ng = ((XDHEPossession) poss).namedGroup;
+                for (SSLCredentials cred : context.handshakeCredentials) {
+                    if (!(cred instanceof XDHECredentials)) {
+                        continue;
+                    }
+                    if (ng.equals(((XDHECredentials) cred).namedGroup)) {
+                        xdheCredentials = (XDHECredentials) cred;
+                        break;
+                    }
+                }
+
+                if (xdheCredentials != null) {
+                    xdhePossession = (XDHEPossession) poss;
+                    break;
+                }
+            }
+
+            if (xdhePossession == null || xdheCredentials == null) {
+                context.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+                    "No sufficient XDHE key agreement parameters negotiated");
+            }
+
+            return new KAKeyDerivation("XDH", context,
+                xdhePossession.privateKey, xdheCredentials.popPublicKey);
+        }
+    }
+
+}
--- a/src/java.base/share/classes/sun/security/util/ArrayUtil.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/util/ArrayUtil.java	Thu Aug 30 11:08:01 2018 -0400
@@ -32,7 +32,7 @@
 
 
 /**
- * This class holds the various utility methods for array range checks.
+ * This class holds the various utility methods for arrays.
  */
 
 public final class ArrayUtil {
@@ -52,4 +52,22 @@
         // NPE is thrown when array is null
         Preconditions.checkFromIndexSize(offset, len, array.length, AIOOBE_SUPPLIER);
     }
+
+
+    private static void swap(byte[] arr, int i, int j) {
+        byte tmp = arr[i];
+        arr[i] = arr[j];
+        arr[j] = tmp;
+    }
+
+    public static void reverse(byte [] arr) {
+        int i = 0;
+        int j = arr.length - 1;
+
+        while (i < j) {
+            swap(arr, i, j);
+            i++;
+            j--;
+        }
+    }
 }
--- a/src/java.base/share/classes/sun/security/util/ECUtil.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/java.base/share/classes/sun/security/util/ECUtil.java	Thu Aug 30 11:08:01 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2018, 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
@@ -227,5 +227,49 @@
         return nameSpec.getName();
     }
 
+    public static BigInteger decodeXecPublicKey(byte[] key,
+                                                XECParameters params) {
+
+        ArrayUtil.reverse(key);
+
+        // clear the extra bits
+        int bitsMod8 = params.getBits() % 8;
+        if (bitsMod8 != 0) {
+            int mask = (1 << bitsMod8) - 1;
+            key[0] &= mask;
+        }
+
+        return new BigInteger(1, key);
+    }
+
+    public static
+    XECPublicKeySpec decodeXecPublicKey(byte[] key, 
+                                        AlgorithmParameterSpec spec)
+        throws InvalidParameterSpecException {
+
+        XECParameters params = XECParameters.get(
+            InvalidParameterSpecException::new, spec);
+        BigInteger u = decodeXecPublicKey(key, params);
+        return new XECPublicKeySpec(spec, u);
+    }
+
+    public static byte[] encodeXecPublicKey(BigInteger u,
+                                            XECParameters params) {
+
+        byte[] u_arr = u.toByteArray();
+        ArrayUtil.reverse(u_arr);
+        // u_arr may be too large or too small, depending on the value of u
+        return Arrays.copyOf(u_arr, params.getBytes());
+    }
+
+    public static byte[] encodeXecPublicKey(BigInteger u,
+                                            AlgorithmParameterSpec spec)
+        throws InvalidParameterSpecException {
+
+        XECParameters params = XECParameters.get(
+            InvalidParameterSpecException::new, spec);
+        return encodeXecPublicKey(u, params);
+    }
+
     private ECUtil() {}
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/util/XECParameters.java	Thu Aug 30 11:08:01 2018 -0400
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2018, 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.util;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.NamedParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import sun.security.util.ObjectIdentifier;
+import sun.security.x509.AlgorithmId;
+
+public class XECParameters {
+
+    // Naming/identification parameters
+    private final ObjectIdentifier oid;
+    private final String name;
+
+    // Curve/field parameters
+    private final int bits;
+    private final BigInteger p;
+    private final int logCofactor;
+    private final int a24;
+    private final byte basePoint;
+
+    /**
+     *
+     * Construct an object holding the supplied parameters. No parameters are
+     * checked, so this method always succeeds. This method supports
+     * Montgomery curves of the form y^2 = x^3 + ax^2 + x.
+     *
+     * @param bits The number of relevant bits in a public/private key.
+     * @param p The prime that defines the finite field.
+     * @param a24 The value of (a - 2) / 4, where a is the second-degree curve
+     *            coefficient.
+     * @param basePoint The point that generates the desired group
+     * @param logCofactor The base-2 logarithm of the cofactor of the curve
+     * @param oid
+     * @param name
+     */
+    public XECParameters(int bits, BigInteger p, int a24,
+                         byte basePoint, int logCofactor,
+                         ObjectIdentifier oid, String name) {
+
+        this.bits = bits;
+        this.logCofactor = logCofactor;
+        this.p = p;
+        this.a24 = a24;
+        this.basePoint = basePoint;
+        this.oid = oid;
+        this.name = name;
+
+    }
+
+    public int getBits() {
+        return bits;
+    }
+    public int getBytes() {
+        return (bits + 7) / 8;
+    }
+    public int getLogCofactor() {
+        return logCofactor;
+    }
+    public BigInteger getP() {
+        return p;
+    }
+    public int getA24() {
+        return a24;
+    }
+    public byte getBasePoint() {
+        return basePoint;
+    }
+    public ObjectIdentifier getOid() {
+        return oid;
+    }
+    public String getName() {
+        return name;
+    }
+
+    private static final Map<Integer, XECParameters> SIZE_MAP;
+    private static final Map<ObjectIdentifier, XECParameters> OID_MAP;
+    private static final Map<String, XECParameters> NAME_MAP;
+
+    static {
+        final BigInteger TWO = BigInteger.valueOf(2);
+
+        Map<Integer, XECParameters> bySize = new HashMap<>();
+        Map<ObjectIdentifier, XECParameters> byOid = new HashMap<>();
+        Map<String, XECParameters> byName = new HashMap<>();
+
+        // set up X25519
+        try {
+            BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19));
+            addParameters(255, p, 121665, (byte) 0x09, 3,
+                new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(),
+                bySize, byOid, byName);
+
+        } catch (IOException ex) {
+            // Unable to set X25519 parameters---it will be disabled
+        }
+
+        // set up X448
+        try {
+            BigInteger p = TWO.pow(448).subtract(TWO.pow(224))
+                .subtract(BigInteger.ONE);
+            addParameters(448, p, 39081, (byte) 0x05, 2,
+                new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(),
+                bySize, byOid, byName);
+
+        } catch (IOException ex) {
+            // Unable to set X448 parameters---it will be disabled
+        }
+
+        SIZE_MAP = Collections.unmodifiableMap(bySize);
+        OID_MAP = Collections.unmodifiableMap(byOid);
+        NAME_MAP = Collections.unmodifiableMap(byName);
+    }
+
+    private static void addParameters(int bits, BigInteger p, int a24,
+        byte basePoint, int logCofactor, int[] oidBytes, String name,
+        Map<Integer, XECParameters> bySize,
+        Map<ObjectIdentifier, XECParameters> byOid,
+        Map<String, XECParameters> byName) throws IOException {
+
+        ObjectIdentifier oid = new ObjectIdentifier(oidBytes);
+        XECParameters params =
+            new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
+        bySize.put(bits, params);
+        byOid.put(oid, params);
+        byName.put(name.toLowerCase(), params);
+    }
+
+    public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
+        return Optional.ofNullable(OID_MAP.get(id));
+    }
+    public static Optional<XECParameters> getBySize(int size) {
+        return Optional.ofNullable(SIZE_MAP.get(size));
+    }
+    public static Optional<XECParameters> getByName(String name) {
+        return Optional.ofNullable(NAME_MAP.get(name.toLowerCase()));
+    }
+
+    public boolean oidEquals(XECParameters other) {
+        return oid.equals(other.getOid());
+    }
+
+    // Utility method that is used by the methods below to handle exception
+    // suppliers
+    private static
+    <A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
+        return new Supplier<B>() {
+            @Override
+            public B get() {
+                return func.apply(a);
+            }
+        };
+    }
+
+    /**
+     * Get parameters by key size, or throw an exception if no parameters are
+     * defined for the specified key size. This method is used in several
+     * contexts that should throw different exceptions when the parameters
+     * are not found. The first argument is a function that produces the
+     * desired exception.
+     *
+     * @param exception a function that produces an exception from a string
+     * @param size the desired key size
+     * @param <T> the type of exception that is thrown
+     * @return the parameters for the specified key size
+     * @throws T when suitable parameters do not exist
+     */
+    public static
+    <T extends Throwable>
+    XECParameters getBySize(Function<String, T> exception,
+                            int size) throws T {
+
+        Optional<XECParameters> xecParams = getBySize(size);
+        return xecParams.orElseThrow(
+            apply(exception, "Unsupported size: " + size));
+    }
+
+    /**
+     * Get parameters by algorithm ID, or throw an exception if no
+     * parameters are defined for the specified ID. This method is used in
+     * several contexts that should throw different exceptions when the
+     * parameters are not found. The first argument is a function that produces
+     * the desired exception.
+     *
+     * @param exception a function that produces an exception from a string
+     * @param algId the algorithm ID
+     * @param <T> the type of exception that is thrown
+     * @return the parameters for the specified algorithm ID
+     * @throws T when suitable parameters do not exist
+     */
+    public static
+    <T extends Throwable>
+    XECParameters get(Function<String, T> exception,
+                      AlgorithmId algId) throws T {
+
+        Optional<XECParameters> xecParams = getByOid(algId.getOID());
+        return xecParams.orElseThrow(
+            apply(exception, "Unsupported OID: " + algId.getOID()));
+    }
+
+    /**
+     * Get parameters by algorithm parameter spec, or throw an exception if no
+     * parameters are defined for the spec. This method is used in
+     * several contexts that should throw different exceptions when the
+     * parameters are not found. The first argument is a function that produces
+     * the desired exception.
+     *
+     * @param exception a function that produces an exception from a string
+     * @param params the algorithm parameters spec
+     * @param <T> the type of exception that is thrown
+     * @return the parameters for the spec
+     * @throws T when suitable parameters do not exist
+     */
+    public static
+    <T extends Throwable>
+    XECParameters get(Function<String, T> exception,
+                      AlgorithmParameterSpec params) throws T {
+
+        if (params instanceof NamedParameterSpec) {
+            NamedParameterSpec namedParams = (NamedParameterSpec) params;
+            Optional<XECParameters> xecParams =
+                getByName(namedParams.getName());
+            return xecParams.orElseThrow(
+                apply(exception, "Unsupported name: " + namedParams.getName()));
+        } else {
+            throw exception.apply("Only NamedParameterSpec is supported.");
+        }
+    }
+}
+
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java	Thu Aug 30 11:08:01 2018 -0400
@@ -38,8 +38,11 @@
 import javax.crypto.KeyAgreementSpi;
 import javax.crypto.SecretKey;
 import javax.crypto.ShortBufferException;
+import javax.crypto.spec.SecretKeySpec;
 import java.util.function.Function;
 
+import sun.security.util.XECParameters;
+
 public class XDHKeyAgreement extends KeyAgreementSpi {
 
     private byte[] privateKey;
@@ -202,7 +205,14 @@
             throws IllegalStateException, NoSuchAlgorithmException,
             InvalidKeyException {
 
-        throw new NoSuchAlgorithmException("Not supported");
+        if (algorithm == null) {
+            throw new NoSuchAlgorithmException("Algorithm must not be null");
+        }
+        if (!(algorithm.equals("TlsPremasterSecret"))) {
+            throw new NoSuchAlgorithmException
+                ("Only supported for algorithm TlsPremasterSecret");
+        }
+        return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");
     }
 
     static class X25519 extends XDHKeyAgreement {
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java	Thu Aug 30 11:08:01 2018 -0400
@@ -44,6 +44,8 @@
 import java.security.spec.XECPrivateKeySpec;
 import java.util.function.Function;
 
+import sun.security.util.XECParameters;
+
 public class XDHKeyFactory extends KeyFactorySpi {
 
     private XECParameters lockedParams = null;
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java	Thu Aug 30 11:08:01 2018 -0400
@@ -37,6 +37,7 @@
 import java.security.spec.NamedParameterSpec;
 
 import sun.security.jca.JCAUtil;
+import sun.security.util.XECParameters;
 
 /**
  * Key pair generator for the XDH key agreement algorithm.
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java	Thu Aug 30 11:08:01 2018 -0400
@@ -28,11 +28,11 @@
 import java.security.interfaces.XECPrivateKey;
 import java.util.Optional;
 import java.security.InvalidKeyException;
-import java.security.PrivateKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.NamedParameterSpec;
 
 import sun.security.pkcs.PKCS8Key;
+import sun.security.util.XECParameters;
 import sun.security.x509.AlgorithmId;
 
 public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey {
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java	Thu Aug 30 11:08:01 2018 -0400
@@ -28,13 +28,13 @@
 import java.math.BigInteger;
 import java.security.InvalidKeyException;
 import java.security.KeyRep;
-import java.security.PublicKey;
 import java.security.interfaces.XECPublicKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.NamedParameterSpec;
-import java.util.Arrays;
 
 import sun.security.util.BitArray;
+import sun.security.util.ECUtil;
+import sun.security.util.XECParameters;
 import sun.security.x509.AlgorithmId;
 import sun.security.x509.X509Key;
 
@@ -52,11 +52,7 @@
         this.algid = new AlgorithmId(params.getOid());
         this.u = u.mod(params.getP());
 
-        byte[] u_arr = this.u.toByteArray();
-        reverse(u_arr);
-        // u_arr may be too large or too small, depending on the value of u
-        u_arr = Arrays.copyOf(u_arr, params.getBytes());
-
+        byte[] u_arr = ECUtil.encodeXecPublicKey(this.u, params);
         setKey(new BitArray(u_arr.length * 8, u_arr));
 
         checkLength(params);
@@ -70,16 +66,7 @@
         this.paramSpec = new NamedParameterSpec(params.getName());
         // construct the BigInteger representation
         byte[] u_arr = getKey().toByteArray();
-        reverse(u_arr);
-
-        // clear the extra bits
-        int bitsMod8 = params.getBits() % 8;
-        if (bitsMod8 != 0) {
-            int mask = (1 << bitsMod8) - 1;
-            u_arr[0] &= mask;
-        }
-
-        this.u = new BigInteger(1, u_arr);
+        this.u = ECUtil.decodeXecPublicKey(u_arr, params);
 
         checkLength(params);
     }
@@ -113,22 +100,5 @@
             getFormat(),
             getEncoded());
     }
-
-    private static void swap(byte[] arr, int i, int j) {
-        byte tmp = arr[i];
-        arr[i] = arr[j];
-        arr[j] = tmp;
-    }
-
-    private static void reverse(byte [] arr) {
-        int i = 0;
-        int j = arr.length - 1;
-
-        while (i < j) {
-            swap(arr, i, j);
-            i++;
-            j--;
-        }
-    }
 }
 
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/src/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java	Thu Aug 30 11:08:01 2018 -0400
@@ -32,6 +32,7 @@
 import sun.security.util.math.SmallValue;
 import sun.security.util.math.intpoly.IntegerPolynomial25519;
 import sun.security.util.math.intpoly.IntegerPolynomial448;
+import sun.security.util.XECParameters;
 
 import java.math.BigInteger;
 import java.security.ProviderException;
--- a/src/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java	Thu Aug 30 09:08:23 2018 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,263 +0,0 @@
-/*
- * Copyright (c) 2018, 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.ec;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.NamedParameterSpec;
-import java.util.Collections;
-import java.util.Map;
-import java.util.HashMap;
-import java.util.Optional;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
-
-public class XECParameters {
-
-    // Naming/identification parameters
-    private final ObjectIdentifier oid;
-    private final String name;
-
-    // Curve/field parameters
-    private final int bits;
-    private final BigInteger p;
-    private final int logCofactor;
-    private final int a24;
-    private final byte basePoint;
-
-    /**
-     *
-     * Construct an object holding the supplied parameters. No parameters are
-     * checked, so this method always succeeds. This method supports
-     * Montgomery curves of the form y^2 = x^3 + ax^2 + x.
-     *
-     * @param bits The number of relevant bits in a public/private key.
-     * @param p The prime that defines the finite field.
-     * @param a24 The value of (a - 2) / 4, where a is the second-degree curve
-     *            coefficient.
-     * @param basePoint The point that generates the desired group
-     * @param logCofactor The base-2 logarithm of the cofactor of the curve
-     * @param oid
-     * @param name
-     */
-    public XECParameters(int bits, BigInteger p, int a24,
-                         byte basePoint, int logCofactor,
-                         ObjectIdentifier oid, String name) {
-
-        this.bits = bits;
-        this.logCofactor = logCofactor;
-        this.p = p;
-        this.a24 = a24;
-        this.basePoint = basePoint;
-        this.oid = oid;
-        this.name = name;
-
-    }
-
-    public int getBits() {
-        return bits;
-    }
-    public int getBytes() {
-        return (bits + 7) / 8;
-    }
-    public int getLogCofactor() {
-        return logCofactor;
-    }
-    public BigInteger getP() {
-        return p;
-    }
-    public int getA24() {
-        return a24;
-    }
-    public byte getBasePoint() {
-        return basePoint;
-    }
-    public ObjectIdentifier getOid() {
-        return oid;
-    }
-    public String getName() {
-        return name;
-    }
-
-    private static final Map<Integer, XECParameters> SIZE_MAP;
-    private static final Map<ObjectIdentifier, XECParameters> OID_MAP;
-    private static final Map<String, XECParameters> NAME_MAP;
-
-    static {
-        final BigInteger TWO = BigInteger.valueOf(2);
-
-        Map<Integer, XECParameters> bySize = new HashMap<>();
-        Map<ObjectIdentifier, XECParameters> byOid = new HashMap<>();
-        Map<String, XECParameters> byName = new HashMap<>();
-
-        // set up X25519
-        try {
-            BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19));
-            addParameters(255, p, 121665, (byte) 0x09, 3,
-                new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(),
-                bySize, byOid, byName);
-
-        } catch (IOException ex) {
-            // Unable to set X25519 parameters---it will be disabled
-        }
-
-        // set up X448
-        try {
-            BigInteger p = TWO.pow(448).subtract(TWO.pow(224))
-                .subtract(BigInteger.ONE);
-            addParameters(448, p, 39081, (byte) 0x05, 2,
-                new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(),
-                bySize, byOid, byName);
-
-        } catch (IOException ex) {
-            // Unable to set X448 parameters---it will be disabled
-        }
-
-        SIZE_MAP = Collections.unmodifiableMap(bySize);
-        OID_MAP = Collections.unmodifiableMap(byOid);
-        NAME_MAP = Collections.unmodifiableMap(byName);
-    }
-
-    private static void addParameters(int bits, BigInteger p, int a24,
-        byte basePoint, int logCofactor, int[] oidBytes, String name,
-        Map<Integer, XECParameters> bySize,
-        Map<ObjectIdentifier, XECParameters> byOid,
-        Map<String, XECParameters> byName) throws IOException {
-
-        ObjectIdentifier oid = new ObjectIdentifier(oidBytes);
-        XECParameters params =
-            new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name);
-        bySize.put(bits, params);
-        byOid.put(oid, params);
-        byName.put(name, params);
-    }
-
-    public static Optional<XECParameters> getByOid(ObjectIdentifier id) {
-        return Optional.ofNullable(OID_MAP.get(id));
-    }
-    public static Optional<XECParameters> getBySize(int size) {
-        return Optional.ofNullable(SIZE_MAP.get(size));
-    }
-    public static Optional<XECParameters> getByName(String name) {
-        return Optional.ofNullable(NAME_MAP.get(name));
-    }
-
-    boolean oidEquals(XECParameters other) {
-        return oid.equals(other.getOid());
-    }
-
-    // Utility method that is used by the methods below to handle exception
-    // suppliers
-    private static
-    <A, B> Supplier<B> apply(final Function<A, B> func, final A a) {
-        return new Supplier<B>() {
-            @Override
-            public B get() {
-                return func.apply(a);
-            }
-        };
-    }
-
-    /**
-     * Get parameters by key size, or throw an exception if no parameters are
-     * defined for the specified key size. This method is used in several
-     * contexts that should throw different exceptions when the parameters
-     * are not found. The first argument is a function that produces the
-     * desired exception.
-     *
-     * @param exception a function that produces an exception from a string
-     * @param size the desired key size
-     * @param <T> the type of exception that is thrown
-     * @return the parameters for the specified key size
-     * @throws T when suitable parameters do not exist
-     */
-    public static
-    <T extends Throwable>
-    XECParameters getBySize(Function<String, T> exception,
-                            int size) throws T {
-
-        Optional<XECParameters> xecParams = getBySize(size);
-        return xecParams.orElseThrow(
-            apply(exception, "Unsupported size: " + size));
-    }
-
-    /**
-     * Get parameters by algorithm ID, or throw an exception if no
-     * parameters are defined for the specified ID. This method is used in
-     * several contexts that should throw different exceptions when the
-     * parameters are not found. The first argument is a function that produces
-     * the desired exception.
-     *
-     * @param exception a function that produces an exception from a string
-     * @param algId the algorithm ID
-     * @param <T> the type of exception that is thrown
-     * @return the parameters for the specified algorithm ID
-     * @throws T when suitable parameters do not exist
-     */
-    public static
-    <T extends Throwable>
-    XECParameters get(Function<String, T> exception,
-                      AlgorithmId algId) throws T {
-
-        Optional<XECParameters> xecParams = getByOid(algId.getOID());
-        return xecParams.orElseThrow(
-            apply(exception, "Unsupported OID: " + algId.getOID()));
-    }
-
-    /**
-     * Get parameters by algorithm parameter spec, or throw an exception if no
-     * parameters are defined for the spec. This method is used in
-     * several contexts that should throw different exceptions when the
-     * parameters are not found. The first argument is a function that produces
-     * the desired exception.
-     *
-     * @param exception a function that produces an exception from a string
-     * @param params the algorithm parameters spec
-     * @param <T> the type of exception that is thrown
-     * @return the parameters for the spec
-     * @throws T when suitable parameters do not exist
-     */
-    public static
-    <T extends Throwable>
-    XECParameters get(Function<String, T> exception,
-                      AlgorithmParameterSpec params) throws T {
-
-        if (params instanceof NamedParameterSpec) {
-            NamedParameterSpec namedParams = (NamedParameterSpec) params;
-            Optional<XECParameters> xecParams =
-                getByName(namedParams.getName());
-            return xecParams.orElseThrow(
-                apply(exception, "Unsupported name: " + namedParams.getName()));
-        } else {
-            throw exception.apply("Only NamedParameterSpec is supported.");
-        }
-    }
-}
-
--- a/test/jdk/sun/security/ec/xec/TestXECOps.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/test/jdk/sun/security/ec/xec/TestXECOps.java	Thu Aug 30 11:08:01 2018 -0400
@@ -25,12 +25,13 @@
  * @test
  * @bug 8171277
  * @summary Test XEC curve operations
- * @modules jdk.crypto.ec/sun.security.ec
+ * @modules java.base/sun.security.util jdk.crypto.ec/sun.security.ec
  * @library /test/lib
  * @build jdk.test.lib.Convert
  * @run main TestXECOps
  */
 
+import sun.security.util.*;
 import sun.security.ec.*;
 import java.util.*;
 import jdk.test.lib.Convert;
--- a/test/jdk/sun/security/ec/xec/XECIterative.java	Thu Aug 30 09:08:23 2018 -0400
+++ b/test/jdk/sun/security/ec/xec/XECIterative.java	Thu Aug 30 11:08:01 2018 -0400
@@ -27,7 +27,7 @@
  * @summary XEC curve operations iterative test vectors
  * @library /test/lib
  * @build jdk.test.lib.Convert
- * @modules jdk.crypto.ec/sun.security.ec
+ * @modules java.base/sun.security.util jdk.crypto.ec/sun.security.ec
  * @run main XECIterative 0 10000
  * @run main XECIterative 10000 20000
  * @run main XECIterative 20000 30000
@@ -40,6 +40,7 @@
  * @run main XECIterative 90000 100000
  */
 
+import sun.security.util.*;
 import sun.security.ec.*;
 
 import java.io.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java	Thu Aug 30 11:08:01 2018 -0400
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * @test
+ * @bug 8171279
+ * @library /javax/net/ssl/templates
+ * @summary Test TLS connection with each individual supported group
+ * @run main/othervm SupportedGroups secp256r1
+ * @run main/othervm SupportedGroups secp384r1
+ * @run main/othervm SupportedGroups secp521r1
+ * @run main/othervm SupportedGroups x25519
+ * @run main/othervm SupportedGroups x448
+ * @run main/othervm SupportedGroups ffdhe2048
+ * @run main/othervm SupportedGroups ffdhe3072
+ * @run main/othervm SupportedGroups ffdhe4096
+ * @run main/othervm SupportedGroups ffdhe6144
+ * @run main/othervm SupportedGroups ffdhe8192
+ */
+
+
+public class SupportedGroups extends SSLSocketTemplate {
+    /*
+     * Run the test case.
+     */
+    public static void main(String[] args) throws Exception {
+        System.setProperty("jdk.tls.namedGroups", args[0]);
+
+        (new SupportedGroups()).run();
+    }
+}