Committing so I can merge JDK-8171279-XDH-TLS-branch
authorapetcher
Thu, 16 Aug 2018 13:16:18 -0400
branchJDK-8171279-XDH-TLS-branch
changeset 56855 ee6aa4c74a4b
parent 56591 35891b3c2e28
child 56856 74041d6dcf9d
Committing so I can merge
src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java
src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java
src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java
src/java.base/share/classes/sun/security/ssl/SSLCredentials.java
src/java.base/share/classes/sun/security/ssl/SSLKeyAgreementCredentials.java
src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java
src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java
src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java
--- a/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java	Thu Aug 16 13:16:18 2018 -0400
@@ -59,7 +59,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;
 
@@ -68,6 +68,11 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
         static DHECredentials valueOf(NamedGroup ng,
             byte[] encodedPublic) throws IOException, GeneralSecurityException {
 
--- a/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java	Thu Aug 16 13:16:18 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 {
 
--- a/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java	Thu Aug 16 13:16:18 2018 -0400
@@ -49,7 +49,7 @@
 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;
 
@@ -357,66 +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));
-                    }
-                } else if (ng.type == NamedGroupType.NAMED_GROUP_XDH) {
-                    try {
-                        XDHECredentials xdhec =
-                                XDHECredentials.valueOf(ng, entry.keyExchange);
-                        if (xdhec != null) {
-                            if (!shc.algorithmConstraints.permits(
-                                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                    xdhec.popPublicKey)) {
-                                SSLLogger.warning(
-                                "XDHE key share entry does not " +
-                                "comply to algorithm constraints");
-                            } else {
-                                credentials.add(xdhec);
-                            }
-                        }
-                    } catch (IOException | GeneralSecurityException ex) {
-                        SSLLogger.warning(
+                } catch (GeneralSecurityException ex) {
+                    SSLLogger.warning(
                         "Cannot decode named group: " +
                         NamedGroup.nameOf(entry.namedGroupId));
-                    }
                 }
             }
 
@@ -675,70 +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 if (ng.type == NamedGroupType.NAMED_GROUP_XDH) {
-                try {
-                    XDHECredentials xdhec =
-                            XDHECredentials.valueOf(ng, keyShare.keyExchange);
-                    if (xdhec != null) {
-                        if (!chc.algorithmConstraints.permits(
-                                EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                                xdhec.popPublicKey)) {
-                            chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE,
-                            "XDHE key share entry does not " +
-                            "comply to algorithm constraints");
-                        } else {
-                            credentials = xdhec;
-                        }
-                    }
-                } 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) {
--- a/src/java.base/share/classes/sun/security/ssl/SSLCredentials.java	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SSLCredentials.java	Thu Aug 16 13:16:18 2018 -0400
@@ -26,4 +26,5 @@
 package sun.security.ssl;
 
 interface SSLCredentials {
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyAgreementCredentials.java	Thu Aug 16 13:16:18 2018 -0400
@@ -0,0 +1,8 @@
+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	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java	Thu Aug 16 13:16:18 2018 -0400
@@ -30,11 +30,13 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
 import sun.security.ssl.DHKeyExchange.DHEPossession;
 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
 import sun.security.ssl.XDHKeyExchange.XDHEPossession;
 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;
 
@@ -559,32 +561,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());
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_XDH) {
-                return new XDHEPossession(
-                    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);
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_XDH) {
-                return XDHKeyExchange.xdheKAGenerator.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	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java	Thu Aug 16 13:16:18 2018 -0400
@@ -31,7 +31,9 @@
 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;
@@ -46,6 +48,7 @@
 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;
@@ -177,6 +180,214 @@
         }
     }
 
+    interface NamedGroupFunctions {
+
+        SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+            throws IOException, GeneralSecurityException;
+
+        SSLPossession createPossession(SecureRandom random);
+
+        SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+            throws IOException;
+
+        AlgorithmParameterSpec getParameterSpec();
+
+        boolean isAvailable();
+    }
+
+    private static class FFDHFunctions implements NamedGroupFunctions {
+
+        private final NamedGroup ng;
+
+        FFDHFunctions(NamedGroup ng) {
+            this.ng = ng;
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+                throws IOException, GeneralSecurityException {
+            return DHKeyExchange.DHECredentials.valueOf(ng, encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new DHKeyExchange.DHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return getDHParameterSpec(ng);
+        }
+
+        static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
+            if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
+                throw new RuntimeException(
+                    "Not a named DH group: " + namedGroup);
+            }
+
+            AlgorithmParameters params = SupportedGroups.namedGroupParams.get(namedGroup);
+            try {
+                return params.getParameterSpec(DHParameterSpec.class);
+            } catch (InvalidParameterSpecException ipse) {
+                // should be unlikely
+                return getPredefinedDHParameterSpec(namedGroup);
+            }
+        }
+
+        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() {
+
+            try {
+                AlgorithmParameters params = JsseJce.getAlgorithmParameters("DiffieHellman");
+                AlgorithmParameterSpec spec = getFFDHEDHParameterSpec(ng);
+                params.init(spec);
+                SupportedGroups.putNamedGroupParams(ng, params);
+                return true;
+            } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+                return false;
+            }
+        }
+    }
+
+    private static class ECDHFunctions implements NamedGroupFunctions {
+
+        private final NamedGroup ng;
+
+        ECDHFunctions(NamedGroup ng) {
+            this.ng = ng;
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+        throws IOException, GeneralSecurityException {
+            return ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new ECDHKeyExchange.ECDHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return SupportedGroups.getECGenParamSpec(ng);
+        }
+
+        @Override
+        public boolean isAvailable() {
+
+            try {
+                AlgorithmParameters params = JsseJce.getAlgorithmParameters("EC");
+                AlgorithmParameterSpec spec = new ECGenParameterSpec(ng.oid);
+                params.init(spec);
+                SupportedGroups.putNamedGroupParams(ng, params);
+                return true;
+            } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+                return false;
+            }
+        }
+    }
+
+    private static class XDHFunctions implements NamedGroupFunctions {
+
+        private final NamedGroup ng;
+
+        XDHFunctions(NamedGroup ng) {
+            this.ng = ng;
+        }
+
+        @Override
+        public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded)
+                throws IOException, GeneralSecurityException {
+            return XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
+        }
+
+        @Override
+        public SSLPossession createPossession(SecureRandom random) {
+            return new XDHKeyExchange.XDHEPossession(ng, random);
+        }
+
+        @Override
+        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
+                throws IOException {
+            return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
+        }
+
+        @Override
+        public AlgorithmParameterSpec getParameterSpec() {
+            return new NamedParameterSpec(ng.algorithm);
+        }
+
+        @Override
+        public boolean isAvailable() {
+
+            try {
+                JsseJce.getKeyAgreement(ng.algorithm);
+                return true;
+            } catch (NoSuchAlgorithmException ex) {
+                return false;
+            }
+        }
+    }
+
     static enum NamedGroup {
         // Elliptic Curves (RFC 4492)
         //
@@ -293,12 +504,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";
@@ -312,6 +525,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;
@@ -324,6 +538,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";
@@ -336,6 +551,7 @@
                 ProtocolVersion[] supportedProtocols) {
             this.id = id;
             this.type = NamedGroupType.NAMED_GROUP_ARBITRARY;
+            this.functions = null;
             this.name = name;
             this.oid = null;
             this.algorithm = "EC";
@@ -343,6 +559,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) {
@@ -451,15 +671,11 @@
         }
 
         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);
-            } else if (this.type == NamedGroupType.NAMED_GROUP_XDH) {
-                return new NamedParameterSpec(this.algorithm);
+            Optional<NamedGroupFunctions> ngf = getFunctions();
+            if (ngf.isEmpty()) {
+                return null;
             }
-
-            return null;
+            return ngf.get().getParameterSpec();
         }
     }
 
@@ -590,94 +806,18 @@
 
         // 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;
-                }
-            } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_XDH) {
-                try {
-                    JsseJce.getKeyAgreement(namedGroup.algorithm);
-                    // no parameters
-                    return true;
-                } catch (NoSuchAlgorithmException e) {
-                    return false;
-                }
-            }   // Otherwise, unsupported.
 
-            if ((params != null) && (spec != null)) {
-                try {
-                    params.init(spec);
-                } catch (InvalidParameterSpecException e) {
-                    return false;
-                }
+            Optional<NamedGroupFunctions> ngf = namedGroup.getFunctions();
+            if (ngf.isEmpty()) {
+                return false;
+            }
+            return ngf.get().isAvailable();
 
-                // cache the parameters
-                namedGroupParams.put(namedGroup, params);
-
-                return true;
-            }
-
-            return false;
         }
 
-        private static DHParameterSpec getFFDHEDHParameterSpec(
-                NamedGroup namedGroup) {
-            DHParameterSpec spec = null;
-            switch (namedGroup) {
-                case FFDHE_2048:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
-                    break;
-                case FFDHE_3072:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
-                    break;
-                case FFDHE_4096:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
-                    break;
-                case FFDHE_6144:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
-                    break;
-                case FFDHE_8192:
-                    spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
-            }
-
-            return spec;
-        }
-
-        private static DHParameterSpec getPredefinedDHParameterSpec(
-                NamedGroup namedGroup) {
-            DHParameterSpec spec = null;
-            switch (namedGroup) {
-                case FFDHE_2048:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(2048);
-                    break;
-                case FFDHE_3072:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(3072);
-                    break;
-                case FFDHE_4096:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(4096);
-                    break;
-                case FFDHE_6144:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(6144);
-                    break;
-                case FFDHE_8192:
-                    spec = PredefinedDHParameterSpecs.definedParams.get(8192);
-            }
-
-            return spec;
+        static void putNamedGroupParams(NamedGroup ng,
+                                        AlgorithmParameters params) {
+            namedGroupParams.put(ng, params);
         }
 
         static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) {
@@ -695,21 +835,6 @@
             }
         }
 
-        static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) {
-            if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) {
-                throw new RuntimeException(
-                        "Not a named DH group: " + namedGroup);
-            }
-
-            AlgorithmParameters params = namedGroupParams.get(namedGroup);
-            try {
-                return params.getParameterSpec(DHParameterSpec.class);
-            } catch (InvalidParameterSpecException ipse) {
-                // should be unlikely
-                return getPredefinedDHParameterSpec(namedGroup);
-            }
-        }
-
         // Is there any supported group permitted by the constraints?
         static boolean isActivatable(
                 AlgorithmConstraints constraints, NamedGroupType type) {
--- a/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java	Tue May 22 14:12:14 2018 -0400
+++ b/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java	Thu Aug 16 13:16:18 2018 -0400
@@ -59,7 +59,7 @@
     static final SSLKeyAgreementGenerator xdhKAGenerator =
             new XDHKAGenerator();
 
-    static final class XDHECredentials implements SSLCredentials {
+    static final class XDHECredentials implements SSLKeyAgreementCredentials {
         final XECPublicKey popPublicKey;
         final NamedGroup namedGroup;
 
@@ -68,6 +68,11 @@
             this.namedGroup = namedGroup;
         }
 
+        @Override
+        public PublicKey getPublicKey() {
+            return popPublicKey;
+        }
+
         static XDHECredentials valueOf(NamedGroup namedGroup,
             byte[] encodedPoint) throws IOException, GeneralSecurityException {