< prev index next >

src/java.base/share/classes/sun/security/ssl/NamedGroup.java

Print this page
rev 54061 : 8226374: Restrict TLS signature schemes and named groups
Reviewed-by: mullan

@@ -27,20 +27,19 @@
 import javax.crypto.spec.DHParameterSpec;
 import javax.net.ssl.SSLException;
 import java.io.IOException;
 import java.security.*;
 import java.security.spec.*;
+import java.util.Collections;
 import java.util.EnumSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import javax.crypto.*;
+import java.util.Set;
+import javax.crypto.KeyAgreement;
 import sun.security.ssl.DHKeyExchange.DHEPossession;
 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
+import sun.security.util.CurveDB;
 
-import sun.security.util.ECUtil;
 
 /**
  * An enum containing all known named groups for use in TLS.
  *
  * The enum also contains the required properties of each group and the

@@ -50,192 +49,258 @@
     // Elliptic Curves (RFC 4492)
     //
     // See sun.security.util.CurveDB for the OIDs
     // NIST K-163
 
-    SECT163_K1(0x0001, "sect163k1", "1.3.132.0.1", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECT163_R1(0x0002, "sect163r1", "1.3.132.0.2", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT163_K1(0x0001, "sect163k1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect163k1")),
+    SECT163_R1(0x0002, "sect163r1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect163r1")),
 
     // NIST B-163
-    SECT163_R2(0x0003, "sect163r2", "1.3.132.0.15", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECT193_R1(0x0004, "sect193r1", "1.3.132.0.24", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECT193_R2(0x0005, "sect193r2", "1.3.132.0.25", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT163_R2(0x0003, "sect163r2", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect163r2")),
+    SECT193_R1(0x0004, "sect193r1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect193r1")),
+    SECT193_R2(0x0005, "sect193r2", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect193r2")),
 
     // NIST K-233
-    SECT233_K1(0x0006, "sect233k1", "1.3.132.0.26", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT233_K1(0x0006, "sect233k1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect233k1")),
 
     // NIST B-233
-    SECT233_R1(0x0007, "sect233r1", "1.3.132.0.27", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECT239_K1(0x0008, "sect239k1", "1.3.132.0.3", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT233_R1(0x0007, "sect233r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect233r1")),
+    SECT239_K1(0x0008, "sect239k1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect239k1")),
 
     // NIST K-283
-    SECT283_K1(0x0009, "sect283k1", "1.3.132.0.16", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT283_K1(0x0009, "sect283k1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect163k1")),
 
     // NIST B-283
-    SECT283_R1(0x000A, "sect283r1", "1.3.132.0.17", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT283_R1(0x000A, "sect283r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect283r1")),
 
     // NIST K-409
-    SECT409_K1(0x000B, "sect409k1", "1.3.132.0.36", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT409_K1(0x000B, "sect409k1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect409k1")),
 
     // NIST B-409
-    SECT409_R1(0x000C, "sect409r1", "1.3.132.0.37", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT409_R1(0x000C, "sect409r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect409r1")),
 
     // NIST K-571
-    SECT571_K1(0x000D, "sect571k1", "1.3.132.0.38", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT571_K1(0x000D, "sect571k1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect571k1")),
 
     // NIST B-571
-    SECT571_R1(0x000E, "sect571r1", "1.3.132.0.39", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP160_K1(0x000F, "secp160k1", "1.3.132.0.9", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP160_R1(0x0010, "secp160r1", "1.3.132.0.8", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP160_R2(0x0011, "secp160r2", "1.3.132.0.30", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP192_K1(0x0012, "secp192k1", "1.3.132.0.31", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECT571_R1(0x000E, "sect571r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("sect571r1")),
+    SECP160_K1(0x000F, "secp160k1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp160k1")),
+    SECP160_R1(0x0010, "secp160r1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp160r1")),
+    SECP160_R2(0x0011, "secp160r2", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp160r2")),
+    SECP192_K1(0x0012, "secp192k1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp192k1")),
 
     // NIST P-192
-    SECP192_R1(0x0013, "secp192r1", "1.2.840.10045.3.1.1", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP224_K1(0x0014, "secp224k1", "1.3.132.0.32", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP192_R1(0x0013, "secp192r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp192r1")),
+    SECP224_K1(0x0014, "secp224k1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp224k1")),
 
     // NIST P-224
-    SECP224_R1(0x0015, "secp224r1", "1.3.132.0.33", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    SECP256_K1(0x0016, "secp256k1", "1.3.132.0.10", false,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_12),
+    SECP224_R1(0x0015, "secp224r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp224r1")),
+    SECP256_K1(0x0016, "secp256k1", false,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            CurveDB.lookup("secp256k1")),
 
     // NIST P-256
-    SECP256_R1(0x0017, "secp256r1", "1.2.840.10045.3.1.7", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
+    SECP256_R1(0x0017, "secp256r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            CurveDB.lookup("secp256r1")),
 
     // NIST P-384
-    SECP384_R1(0x0018, "secp384r1", "1.3.132.0.34", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
+    SECP384_R1(0x0018, "secp384r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            CurveDB.lookup("secp384r1")),
 
     // NIST P-521
-    SECP521_R1(0x0019, "secp521r1", "1.3.132.0.35", true,
-            NamedGroupType.NAMED_GROUP_ECDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
+    SECP521_R1(0x0019, "secp521r1", true,
+            NamedGroupSpec.NAMED_GROUP_ECDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            CurveDB.lookup("secp521r1")),
 
     // x25519 and x448 (RFC 8422/8446)
-    X25519(0x001D, "x25519", "1.3.101.110", true,
-            NamedGroupType.NAMED_GROUP_XDH,
-            ProtocolVersion.PROTOCOLS_TO_13),
-    X448(0x001E, "x448", "1.3.101.111", true,
-            NamedGroupType.NAMED_GROUP_XDH,
-            ProtocolVersion.PROTOCOLS_TO_13),
+    X25519(0x001D, "x25519", true,
+            NamedGroupSpec.NAMED_GROUP_XDH,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            NamedParameterSpec.X25519),
+    X448(0x001E, "x448", true,
+            NamedGroupSpec.NAMED_GROUP_XDH,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            NamedParameterSpec.X448),
 
     // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
-    FFDHE_2048(0x0100, "ffdhe2048", null, true,
-            NamedGroupType.NAMED_GROUP_FFDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
-    FFDHE_3072(0x0101, "ffdhe3072", null, true,
-            NamedGroupType.NAMED_GROUP_FFDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
-    FFDHE_4096(0x0102, "ffdhe4096", null, true,
-            NamedGroupType.NAMED_GROUP_FFDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
-    FFDHE_6144(0x0103, "ffdhe6144", null, true,
-            NamedGroupType.NAMED_GROUP_FFDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
-    FFDHE_8192(0x0104, "ffdhe8192", null, true,
-            NamedGroupType.NAMED_GROUP_FFDHE,
-            ProtocolVersion.PROTOCOLS_TO_13),
+    FFDHE_2048(0x0100, "ffdhe2048", true,
+            NamedGroupSpec.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            PredefinedDHParameterSpecs.ffdheParams.get(2048)),
+    FFDHE_3072(0x0101, "ffdhe3072", true,
+            NamedGroupSpec.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            PredefinedDHParameterSpecs.ffdheParams.get(3072)),
+    FFDHE_4096(0x0102, "ffdhe4096", true,
+            NamedGroupSpec.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            PredefinedDHParameterSpecs.ffdheParams.get(4096)),
+    FFDHE_6144(0x0103, "ffdhe6144", true,
+            NamedGroupSpec.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            PredefinedDHParameterSpecs.ffdheParams.get(6144)),
+    FFDHE_8192(0x0104, "ffdhe8192", true,
+            NamedGroupSpec.NAMED_GROUP_FFDHE,
+            ProtocolVersion.PROTOCOLS_TO_13,
+            PredefinedDHParameterSpecs.ffdheParams.get(8192)),
 
     // Elliptic Curves (RFC 4492)
     //
     // arbitrary prime and characteristic-2 curves
-    ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", null, false,
-            NamedGroupType.NAMED_GROUP_ARBITRARY,
-            ProtocolVersion.PROTOCOLS_TO_12),
-    ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", null, false,
-            NamedGroupType.NAMED_GROUP_ARBITRARY,
-            ProtocolVersion.PROTOCOLS_TO_12);
+    ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", false,
+            NamedGroupSpec.NAMED_GROUP_ARBITRARY,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            null),
+    ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", false,
+            NamedGroupSpec.NAMED_GROUP_ARBITRARY,
+            ProtocolVersion.PROTOCOLS_TO_12,
+            null);
 
     final int id;               // hash + signature
-    final NamedGroupType type;  // group type
     final String name;          // literal name
-    final String oid;           // object identifier of the named group
-    final String algorithm;     // signature algorithm
     final boolean isFips;       // can be used in FIPS mode?
+    final NamedGroupSpec spec;  // group type
     final ProtocolVersion[] supportedProtocols;
-    private final NamedGroupFunctions functions;    // may be null
+    final String algorithm;     // key exchange algorithm
+    final AlgorithmParameterSpec keAlgParamSpec;
+    final AlgorithmParameters keAlgParams;
+    final boolean isAvailable;
+
+    // performance optimization
+    private static final Set<CryptoPrimitive> KEY_AGREEMENT_PRIMITIVE_SET =
+        Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT));
 
     // Constructor used for all NamedGroup types
-    private NamedGroup(int id, String name, String oid, boolean isFips,
-            NamedGroupType namedGroupType,
-            ProtocolVersion[] supportedProtocols) {
+    private NamedGroup(int id, String name, boolean isFips,
+            NamedGroupSpec namedGroupSpec,
+            ProtocolVersion[] supportedProtocols,
+            AlgorithmParameterSpec keAlgParamSpec) {
         this.id = id;
         this.name = name;
-        this.oid = oid;
-        this.type = namedGroupType;
         this.isFips = isFips;
+        this.spec = namedGroupSpec;
+        this.algorithm = namedGroupSpec.algorithm;
         this.supportedProtocols = supportedProtocols;
+        this.keAlgParamSpec = keAlgParamSpec;
 
-        if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
-            this.functions = ECDHFunctions.getInstance();
-            this.algorithm = "EC";
-        } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
-            this.functions = FFDHFunctions.getInstance();
-            this.algorithm = "DiffieHellman";
-        } else if (this.type == NamedGroupType.NAMED_GROUP_XDH) {
-            this.functions = XDHFunctions.getInstance();
-            this.algorithm = "XDH";
-        } else if (this.type == NamedGroupType.NAMED_GROUP_ARBITRARY) {
-            this.functions = null;
-            this.algorithm = "EC";
+        AlgorithmParameters algParams = null;
+        boolean mediator = (keAlgParamSpec != null);
+        if (mediator) {
+            try {
+                algParams =
+                    AlgorithmParameters.getInstance(namedGroupSpec.algorithm);
+                algParams.init(keAlgParamSpec);
+            } catch (InvalidParameterSpecException
+                    | NoSuchAlgorithmException exp) {
+                if (namedGroupSpec != NamedGroupSpec.NAMED_GROUP_XDH) {
+                    mediator = false;
+                    if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                        SSLLogger.warning(
+                            "No AlgorithmParameters for " + name, exp);
+                    }
         } else {
-            throw new RuntimeException("Unexpected Named Group Type");
+                    // HACK CODE
+                    //
+                    // Please remove the following code if the XDH/X25519/X448
+                    // AlgorithmParameters algorithms are supported in JDK.
+                    algParams = null;
+                    try {
+                        KeyAgreement.getInstance(name);
+
+                        // The following service is also needed.  But for
+                        // performance, check the KeyAgreement impl only.
+                        //
+                        // KeyFactory.getInstance(name);
+                        // KeyPairGenerator.getInstance(name);
+                        // AlgorithmParameters.getInstance(name);
+                    } catch (NoSuchAlgorithmException nsae) {
+                        mediator = false;
+                        if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
+                            SSLLogger.warning(
+                                "No AlgorithmParameters for " + name, nsae);
+                        }
+                    }
+                }
         }
     }
 
-    private Optional<NamedGroupFunctions> getFunctions() {
-        return Optional.ofNullable(functions);
+        this.isAvailable = mediator;
+        this.keAlgParams = mediator ? algParams : null;
     }
 
+    //
     // The next set of methods search & retrieve NamedGroups.
-
+    //
     static NamedGroup valueOf(int id) {
         for (NamedGroup group : NamedGroup.values()) {
             if (group.id == id) {
                 return group;
             }

@@ -243,44 +308,29 @@
 
         return null;
     }
 
     static NamedGroup valueOf(ECParameterSpec params) {
-        String oid = JsseJce.getNamedCurveOid(params);
-        if ((oid != null) && (!oid.isEmpty())) {
-            for (NamedGroup group : NamedGroup.values()) {
-                if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE)
-                        && oid.equals(group.oid)) {
-                    return group;
+        for (NamedGroup ng : NamedGroup.values()) {
+            if (ng.spec == NamedGroupSpec.NAMED_GROUP_ECDHE) {
+                if ((params == ng.keAlgParamSpec) ||
+                        (ng.keAlgParamSpec == CurveDB.lookup(params))) {
+                    return ng;
                 }
             }
         }
 
         return null;
     }
 
     static NamedGroup valueOf(DHParameterSpec params) {
         for (NamedGroup ng : NamedGroup.values()) {
-            if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
-                continue;
-            }
-
-            DHParameterSpec ngParams = null;
-            // functions is non-null for FFDHE type
-            AlgorithmParameters aps = ng.functions.getParameters(ng);
-            if (aps == null)
-                continue;
-            try {
-                ngParams = aps.getParameterSpec(DHParameterSpec.class);
-            } catch (InvalidParameterSpecException ipse) {
-                // should be unlikely
-            }
-
-            if (ngParams == null) {
+            if (ng.spec != NamedGroupSpec.NAMED_GROUP_FFDHE) {
                 continue;
             }
 
+            DHParameterSpec ngParams = (DHParameterSpec)ng.keAlgParamSpec;
             if (ngParams.getP().equals(params.getP())
                     && ngParams.getG().equals(params.getG())) {
                 return ng;
             }
         }

@@ -306,122 +356,132 @@
         }
 
         return "UNDEFINED-NAMED-GROUP(" + id + ")";
     }
 
-    // Are the NamedGroups available for the protocol desired?
-
+    // Is the NamedGroup available for the protocols desired?
     boolean isAvailable(List<ProtocolVersion> protocolVersions) {
+        if (this.isAvailable) {
         for (ProtocolVersion pv : supportedProtocols) {
             if (protocolVersions.contains(pv)) {
                 return true;
             }
         }
+        }
+
         return false;
     }
 
     boolean isAvailable(ProtocolVersion protocolVersion) {
+        if (this.isAvailable) {
         for (ProtocolVersion pv : supportedProtocols) {
             if (protocolVersion == pv) {
                 return true;
             }
         }
+        }
+
         return false;
     }
 
     // Are the NamedGroups available for the ciphersuites desired?
-
     boolean isSupported(List<CipherSuite> cipherSuites) {
         for (CipherSuite cs : cipherSuites) {
             boolean isMatch = isAvailable(cs.supportedProtocols);
             if (isMatch && ((cs.keyExchange == null)
-                    || (NamedGroupType.arrayContains(
-                        cs.keyExchange.groupTypes, type)))) {
+                    || (NamedGroupSpec.arrayContains(
+                            cs.keyExchange.groupTypes, spec)))) {
                 return true;
             }
         }
+
         return false;
     }
 
-    // lazy loading of parameters
-    AlgorithmParameters getParameters() {
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
-        }
-        return ngf.get().getParameters(this);
-    }
-
-    // The next set of methods use the NamedGroupFunctions table
-    // to do various operations in a consistent way.
-
-    AlgorithmParameterSpec getParameterSpec() {
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
-        }
-        return ngf.get().getParameterSpec(this);
+    boolean isPermitted(AlgorithmConstraints constraints) {
+        return constraints.permits(KEY_AGREEMENT_PRIMITIVE_SET,
+                        this.name, null) &&
+                constraints.permits(KEY_AGREEMENT_PRIMITIVE_SET,
+                        this.algorithm, this.keAlgParams);
     }
 
     byte[] encodePossessionPublicKey(
             NamedGroupPossession namedGroupPossession) {
-
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
-        }
-        return ngf.get().encodePossessionPublicKey(namedGroupPossession);
+        return spec.encodePossessionPublicKey(namedGroupPossession);
     }
 
     SSLCredentials decodeCredentials(byte[] encoded,
             AlgorithmConstraints constraints,
             ExceptionSupplier onConstraintFail)
             throws IOException, GeneralSecurityException {
+        return spec.decodeCredentials(
+                this, encoded, constraints, onConstraintFail);
+    }
 
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
+    SSLPossession createPossession(SecureRandom random) {
+        return spec.createPossession(this, random);
         }
-        return ngf.get().decodeCredentials(this, encoded, constraints,
-                onConstraintFail);
+
+    SSLKeyDerivation createKeyDerivation(
+            HandshakeContext hc) throws IOException {
+        return spec.createKeyDerivation(hc);
     }
 
-    SSLPossession createPossession(SecureRandom random) {
+    interface ExceptionSupplier {
+        void apply(String s) throws SSLException;
+    }
 
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
+    // A list of operations related to named groups.
+    private interface NamedGroupScheme {
+        default void checkConstraints(PublicKey publicKey,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail) throws SSLException {
+            if (!constraints.permits(
+                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) {
+                onConstraintFail.apply("key share entry does not "
+                        + "comply with algorithm constraints");
         }
-        return ngf.get().createPossession(this, random);
     }
 
-    SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
-            throws IOException {
+        byte[] encodePossessionPublicKey(
+                NamedGroupPossession namedGroupPossession);
 
-        Optional<NamedGroupFunctions> ngf = getFunctions();
-        if (ngf.isEmpty()) {
-            return null;
-        }
-        return ngf.get().createKeyDerivation(hc);
+        SSLCredentials decodeCredentials(
+                NamedGroup ng, byte[] encoded,
+                AlgorithmConstraints constraints,
+                ExceptionSupplier onConstraintFail
+            ) throws IOException, GeneralSecurityException;
 
-    }
+        SSLPossession createPossession(NamedGroup ng, SecureRandom random);
 
-    boolean isAvailableGroup() {
-        Optional<NamedGroupFunctions> ngfOpt = getFunctions();
-        if (ngfOpt.isEmpty()) {
-            return false;
-        }
-        NamedGroupFunctions ngf = ngfOpt.get();
-        return ngf.isAvailable(this);
+        SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException;
     }
 
-    enum NamedGroupType {
-        NAMED_GROUP_ECDHE,      // Elliptic Curve Groups (ECDHE)
-        NAMED_GROUP_FFDHE,      // Finite Field Groups (DHE)
-        NAMED_GROUP_XDH,        // Finite Field Groups (XDH)
-        NAMED_GROUP_ARBITRARY,  // arbitrary prime and curves (ECDHE)
-        NAMED_GROUP_NONE;       // Not predefined named group
+    enum NamedGroupSpec implements NamedGroupScheme {
+        // Elliptic Curve Groups (ECDHE)
+        NAMED_GROUP_ECDHE("EC", ECDHEScheme.instance),
+
+        // Finite Field Groups (DHE)
+        NAMED_GROUP_FFDHE("DiffieHellman", FFDHEScheme.instance),
+
+        // Finite Field Groups (XDH)
+        NAMED_GROUP_XDH("XDH", XDHScheme.instance),
+
+        // arbitrary prime and curves (ECDHE)
+        NAMED_GROUP_ARBITRARY("EC", null),
+
+        // Not predefined named group
+        NAMED_GROUP_NONE("", null);
+
+        private final String algorithm;     // key exchange name
+        private final NamedGroupScheme scheme;  // named group operations
+
+        private NamedGroupSpec(String algorithm, NamedGroupScheme scheme) {
+            this.algorithm = algorithm;
+            this.scheme = scheme;
+        }
 
         boolean isSupported(List<CipherSuite> cipherSuites) {
             for (CipherSuite cs : cipherSuites) {
                 if (cs.keyExchange == null ||
                         arrayContains(cs.keyExchange.groupTypes, this)) {

@@ -430,108 +490,79 @@
             }
 
             return false;
         }
 
-        static boolean arrayContains(NamedGroupType[] namedGroupTypes,
-                NamedGroupType namedGroupType) {
-            for (NamedGroupType ng : namedGroupTypes) {
+        static boolean arrayContains(NamedGroupSpec[] namedGroupTypes,
+                NamedGroupSpec namedGroupType) {
+            for (NamedGroupSpec ng : namedGroupTypes) {
                 if (ng == namedGroupType) {
                     return true;
                 }
             }
+
             return false;
         }
-    }
 
-    interface ExceptionSupplier {
-        void apply(String s) throws SSLException;
+        @Override
+        public byte[] encodePossessionPublicKey(
+                NamedGroupPossession namedGroupPossession) {
+            if (scheme != null) {
+                return scheme.encodePossessionPublicKey(namedGroupPossession);
     }
 
-    /*
-     * A list of functions to do NamedGroup operations in a
-     * algorithm-independent and consistent way.
-     */
-    private static abstract class NamedGroupFunctions {
-
-        // cache to speed up the parameters construction
-        protected static final Map<NamedGroup, AlgorithmParameters>
-                namedGroupParams = new ConcurrentHashMap<>();
+            return null;
+        }
 
-        protected void checkConstraints(PublicKey publicKey,
+        @Override
+        public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
                 AlgorithmConstraints constraints,
-                ExceptionSupplier onConstraintFail)
-                throws SSLException {
-
-            if (!constraints.permits(
-                    EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
-                    publicKey)) {
-
-                onConstraintFail.apply("key share entry does not "
-                        + "comply with algorithm constraints");
-            }
+                    ExceptionSupplier onConstraintFail
+                ) throws IOException, GeneralSecurityException {
+            if (scheme != null) {
+                return scheme.decodeCredentials(
+                        ng, encoded, constraints, onConstraintFail);
         }
 
-        public AlgorithmParameters getParameters(NamedGroup ng) {
-
-            AlgorithmParameters result = namedGroupParams.get(ng);
-            if (result == null) {
-                Optional<AlgorithmParameters> paramsOpt = getParametersImpl(ng);
-                if (paramsOpt.isPresent()) {
-                    result = paramsOpt.get();
-                    namedGroupParams.put(ng, result);
-                }
+            return null;
             }
 
-            return result;
+        @Override
+        public SSLPossession createPossession(
+                NamedGroup ng, SecureRandom random) {
+            if (scheme != null) {
+                return scheme.createPossession(ng, random);
         }
 
-        public abstract byte[] encodePossessionPublicKey(
-                NamedGroupPossession namedGroupPossession);
-
-        public abstract SSLCredentials decodeCredentials(
-                NamedGroup ng, byte[] encoded,
-                AlgorithmConstraints constraints,
-                ExceptionSupplier onConstraintFail)
-                throws IOException, GeneralSecurityException;
-
-        public abstract SSLPossession createPossession(NamedGroup ng,
-                SecureRandom random);
-
-        public abstract SSLKeyDerivation createKeyDerivation(
-                HandshakeContext hc) throws IOException;
-
-        protected abstract Optional<AlgorithmParameters> getParametersImpl(
-                NamedGroup ng);
-
-        public abstract AlgorithmParameterSpec getParameterSpec(NamedGroup ng);
-
-        public abstract boolean isAvailable(NamedGroup ng);
+            return null;
     }
 
-    private static class FFDHFunctions extends NamedGroupFunctions {
-
-        // lazy initialization
-        private static class FunctionsHolder {
-            private static final FFDHFunctions instance = new FFDHFunctions();
+        @Override
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException {
+            if (scheme != null) {
+                return scheme.createKeyDerivation(hc);
         }
 
-        private static FFDHFunctions getInstance() {
-            return FunctionsHolder.instance;
+            return null;
+        }
         }
 
+    private static class FFDHEScheme implements NamedGroupScheme {
+        private static final FFDHEScheme instance = new FFDHEScheme();
+
         @Override
         public byte[] encodePossessionPublicKey(
                 NamedGroupPossession namedGroupPossession) {
             return ((DHEPossession)namedGroupPossession).encode();
         }
 
         @Override
         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
                 AlgorithmConstraints constraints,
-                ExceptionSupplier onConstraintFail)
-                throws IOException, GeneralSecurityException {
+                ExceptionSupplier onConstraintFail
+            ) throws IOException, GeneralSecurityException {
 
             DHKeyExchange.DHECredentials result
                     = DHKeyExchange.DHECredentials.valueOf(ng, encoded);
 
             checkConstraints(result.getPublicKey(), constraints,

@@ -545,127 +576,31 @@
                 NamedGroup ng, SecureRandom random) {
             return new DHKeyExchange.DHEPossession(ng, random);
         }
 
         @Override
-        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
-                throws IOException {
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException {
 
             return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
         }
-
-        @Override
-        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
-            return getDHParameterSpec(ng);
-        }
-
-        DHParameterSpec getDHParameterSpec(NamedGroup ng) {
-
-            AlgorithmParameters params = getParameters(ng);
-            try {
-                return params.getParameterSpec(DHParameterSpec.class);
-            } catch (InvalidParameterSpecException ipse) {
-                // should be unlikely
-                return getPredefinedDHParameterSpec(ng);
-            }
-        }
-
-        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(NamedGroup ng) {
-
-            AlgorithmParameters params = getParameters(ng);
-            return params != null;
-        }
-
-        @Override
-        protected Optional<AlgorithmParameters> getParametersImpl(
-                NamedGroup ng) {
-            try {
-                AlgorithmParameters params
-                        = JsseJce.getAlgorithmParameters("DiffieHellman");
-                AlgorithmParameterSpec spec
-                        = getFFDHEDHParameterSpec(ng);
-                params.init(spec);
-                return Optional.of(params);
-            } catch (InvalidParameterSpecException
-                    | NoSuchAlgorithmException ex) {
-                return Optional.empty();
-            }
-        }
-
-    }
-
-    private static class ECDHFunctions extends NamedGroupFunctions {
-
-        // lazy initialization
-        private static class FunctionsHolder {
-            private static final ECDHFunctions instance = new ECDHFunctions();
-        }
-
-        private static ECDHFunctions getInstance() {
-            return FunctionsHolder.instance;
-        }
+    private static class ECDHEScheme implements NamedGroupScheme {
+        private static final ECDHEScheme instance = new ECDHEScheme();
 
         @Override
         public byte[] encodePossessionPublicKey(
                 NamedGroupPossession namedGroupPossession) {
             return ((ECDHEPossession)namedGroupPossession).encode();
         }
 
         @Override
         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
                 AlgorithmConstraints constraints,
-                ExceptionSupplier onConstraintFail)
-                throws IOException, GeneralSecurityException {
+                ExceptionSupplier onConstraintFail
+            ) throws IOException, GeneralSecurityException {
 
             ECDHKeyExchange.ECDHECredentials result
                     = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
 
             checkConstraints(result.getPublicKey(), constraints,

@@ -679,67 +614,29 @@
                 NamedGroup ng, SecureRandom random) {
             return new ECDHKeyExchange.ECDHEPossession(ng, random);
         }
 
         @Override
-        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
-                throws IOException {
-
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException {
             return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
         }
-
-        @Override
-        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
-            return SupportedGroupsExtension.SupportedGroups
-                    .getECGenParamSpec(ng);
-        }
-
-        @Override
-        public boolean isAvailable(NamedGroup ng) {
-
-            AlgorithmParameters params = getParameters(ng);
-            return params != null;
-        }
-
-        @Override
-        protected Optional<AlgorithmParameters> getParametersImpl(
-                NamedGroup ng) {
-            try {
-                AlgorithmParameters params
-                        = JsseJce.getAlgorithmParameters("EC");
-                AlgorithmParameterSpec spec
-                        = new ECGenParameterSpec(ng.oid);
-                params.init(spec);
-                return Optional.of(params);
-            } catch (InvalidParameterSpecException
-                    | NoSuchAlgorithmException ex) {
-                return Optional.empty();
-            }
-        }
-    }
-
-    private static class XDHFunctions extends NamedGroupFunctions {
-
-        // lazy initialization
-        private static class FunctionsHolder {
-            private static final XDHFunctions instance = new XDHFunctions();
         }
 
-        private static XDHFunctions getInstance() {
-            return FunctionsHolder.instance;
-        }
+    private static class XDHScheme implements NamedGroupScheme {
+        private static final XDHScheme instance = new XDHScheme();
 
         @Override
         public byte[] encodePossessionPublicKey(NamedGroupPossession poss) {
             return ((XDHKeyExchange.XDHEPossession)poss).encode();
         }
 
         @Override
         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
                 AlgorithmConstraints constraints,
-                ExceptionSupplier onConstraintFail)
-                throws IOException, GeneralSecurityException {
+                ExceptionSupplier onConstraintFail
+            ) throws IOException, GeneralSecurityException {
 
             XDHKeyExchange.XDHECredentials result
                     = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
 
             checkConstraints(result.getPublicKey(), constraints,

@@ -753,33 +650,11 @@
                 NamedGroup ng, SecureRandom random) {
             return new XDHKeyExchange.XDHEPossession(ng, random);
         }
 
         @Override
-        public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
-                throws IOException {
+        public SSLKeyDerivation createKeyDerivation(
+                HandshakeContext hc) throws IOException {
             return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
         }
-
-        @Override
-        public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
-            return new NamedParameterSpec(ng.name);
-        }
-
-        @Override
-        public boolean isAvailable(NamedGroup ng) {
-
-            try {
-                JsseJce.getKeyAgreement(ng.algorithm);
-                return true;
-            } catch (NoSuchAlgorithmException ex) {
-                return false;
-            }
-        }
-
-        @Override
-        protected Optional<AlgorithmParameters> getParametersImpl(
-                NamedGroup ng) {
-            return Optional.empty();
-        }
     }
 }
< prev index next >