1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package sun.security.ssl;
  26 
  27 import javax.crypto.spec.DHParameterSpec;
  28 import javax.net.ssl.SSLException;
  29 import java.io.IOException;
  30 import java.security.*;
  31 import java.security.spec.*;
  32 import java.util.EnumSet;
  33 import java.util.List;
  34 import java.util.Map;
  35 import java.util.Optional;
  36 import java.util.concurrent.ConcurrentHashMap;
  37 import javax.crypto.*;
  38 import sun.security.ssl.DHKeyExchange.DHEPossession;
  39 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
  40 
  41 import sun.security.util.ECUtil;
  42 
  43 /**
  44  * An enum containing all known named groups for use in TLS.
  45  *
  46  * The enum also contains the required properties of each group and the
  47  * required functions (e.g. encoding/decoding).
  48  */
  49 enum NamedGroup {
  50     // Elliptic Curves (RFC 4492)
  51     //
  52     // See sun.security.util.CurveDB for the OIDs
  53     // NIST K-163
  54 
  55     SECT163_K1(0x0001, "sect163k1", "1.3.132.0.1",
  56             NamedGroupType.NAMED_GROUP_ECDHE,
  57             ProtocolVersion.PROTOCOLS_TO_12),
  58     SECT163_R1(0x0002, "sect163r1", "1.3.132.0.2",
  59             NamedGroupType.NAMED_GROUP_ECDHE,
  60             ProtocolVersion.PROTOCOLS_TO_12),
  61 
  62     // NIST B-163
  63     SECT163_R2(0x0003, "sect163r2", "1.3.132.0.15",
  64             NamedGroupType.NAMED_GROUP_ECDHE,
  65             ProtocolVersion.PROTOCOLS_TO_12),
  66     SECT193_R1(0x0004, "sect193r1", "1.3.132.0.24",
  67             NamedGroupType.NAMED_GROUP_ECDHE,
  68             ProtocolVersion.PROTOCOLS_TO_12),
  69     SECT193_R2(0x0005, "sect193r2", "1.3.132.0.25",
  70             NamedGroupType.NAMED_GROUP_ECDHE,
  71             ProtocolVersion.PROTOCOLS_TO_12),
  72 
  73     // NIST K-233
  74     SECT233_K1(0x0006, "sect233k1", "1.3.132.0.26",
  75             NamedGroupType.NAMED_GROUP_ECDHE,
  76             ProtocolVersion.PROTOCOLS_TO_12),
  77 
  78     // NIST B-233
  79     SECT233_R1(0x0007, "sect233r1", "1.3.132.0.27",
  80             NamedGroupType.NAMED_GROUP_ECDHE,
  81             ProtocolVersion.PROTOCOLS_TO_12),
  82     SECT239_K1(0x0008, "sect239k1", "1.3.132.0.3",
  83             NamedGroupType.NAMED_GROUP_ECDHE,
  84             ProtocolVersion.PROTOCOLS_TO_12),
  85 
  86     // NIST K-283
  87     SECT283_K1(0x0009, "sect283k1", "1.3.132.0.16",
  88             NamedGroupType.NAMED_GROUP_ECDHE,
  89             ProtocolVersion.PROTOCOLS_TO_12),
  90 
  91     // NIST B-283
  92     SECT283_R1(0x000A, "sect283r1", "1.3.132.0.17",
  93             NamedGroupType.NAMED_GROUP_ECDHE,
  94             ProtocolVersion.PROTOCOLS_TO_12),
  95 
  96     // NIST K-409
  97     SECT409_K1(0x000B, "sect409k1", "1.3.132.0.36",
  98             NamedGroupType.NAMED_GROUP_ECDHE,
  99             ProtocolVersion.PROTOCOLS_TO_12),
 100 
 101     // NIST B-409
 102     SECT409_R1(0x000C, "sect409r1", "1.3.132.0.37",
 103             NamedGroupType.NAMED_GROUP_ECDHE,
 104             ProtocolVersion.PROTOCOLS_TO_12),
 105 
 106     // NIST K-571
 107     SECT571_K1(0x000D, "sect571k1", "1.3.132.0.38",
 108             NamedGroupType.NAMED_GROUP_ECDHE,
 109             ProtocolVersion.PROTOCOLS_TO_12),
 110 
 111     // NIST B-571
 112     SECT571_R1(0x000E, "sect571r1", "1.3.132.0.39",
 113             NamedGroupType.NAMED_GROUP_ECDHE,
 114             ProtocolVersion.PROTOCOLS_TO_12),
 115     SECP160_K1(0x000F, "secp160k1", "1.3.132.0.9",
 116             NamedGroupType.NAMED_GROUP_ECDHE,
 117             ProtocolVersion.PROTOCOLS_TO_12),
 118     SECP160_R1(0x0010, "secp160r1", "1.3.132.0.8",
 119             NamedGroupType.NAMED_GROUP_ECDHE,
 120             ProtocolVersion.PROTOCOLS_TO_12),
 121     SECP160_R2(0x0011, "secp160r2", "1.3.132.0.30",
 122             NamedGroupType.NAMED_GROUP_ECDHE,
 123             ProtocolVersion.PROTOCOLS_TO_12),
 124     SECP192_K1(0x0012, "secp192k1", "1.3.132.0.31",
 125             NamedGroupType.NAMED_GROUP_ECDHE,
 126             ProtocolVersion.PROTOCOLS_TO_12),
 127 
 128     // NIST P-192
 129     SECP192_R1(0x0013, "secp192r1", "1.2.840.10045.3.1.1",
 130             NamedGroupType.NAMED_GROUP_ECDHE,
 131             ProtocolVersion.PROTOCOLS_TO_12),
 132     SECP224_K1(0x0014, "secp224k1", "1.3.132.0.32",
 133             NamedGroupType.NAMED_GROUP_ECDHE,
 134             ProtocolVersion.PROTOCOLS_TO_12),
 135 
 136     // NIST P-224
 137     SECP224_R1(0x0015, "secp224r1", "1.3.132.0.33",
 138             NamedGroupType.NAMED_GROUP_ECDHE,
 139             ProtocolVersion.PROTOCOLS_TO_12),
 140     SECP256_K1(0x0016, "secp256k1", "1.3.132.0.10",
 141             NamedGroupType.NAMED_GROUP_ECDHE,
 142             ProtocolVersion.PROTOCOLS_TO_12),
 143 
 144     // NIST P-256
 145     SECP256_R1(0x0017, "secp256r1", "1.2.840.10045.3.1.7",
 146             NamedGroupType.NAMED_GROUP_ECDHE,
 147             ProtocolVersion.PROTOCOLS_TO_13),
 148 
 149     // NIST P-384
 150     SECP384_R1(0x0018, "secp384r1", "1.3.132.0.34",
 151             NamedGroupType.NAMED_GROUP_ECDHE,
 152             ProtocolVersion.PROTOCOLS_TO_13),
 153 
 154     // NIST P-521
 155     SECP521_R1(0x0019, "secp521r1", "1.3.132.0.35",
 156             NamedGroupType.NAMED_GROUP_ECDHE,
 157             ProtocolVersion.PROTOCOLS_TO_13),
 158 
 159     // x25519 and x448 (RFC 8422/8446)
 160     X25519(0x001D, "x25519", "1.3.101.110",
 161             NamedGroupType.NAMED_GROUP_XDH,
 162             ProtocolVersion.PROTOCOLS_TO_13),
 163     X448(0x001E, "x448", "1.3.101.111",
 164             NamedGroupType.NAMED_GROUP_XDH,
 165             ProtocolVersion.PROTOCOLS_TO_13),
 166 
 167     // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
 168     FFDHE_2048(0x0100, "ffdhe2048", null,
 169             NamedGroupType.NAMED_GROUP_FFDHE,
 170             ProtocolVersion.PROTOCOLS_TO_13),
 171     FFDHE_3072(0x0101, "ffdhe3072", null,
 172             NamedGroupType.NAMED_GROUP_FFDHE,
 173             ProtocolVersion.PROTOCOLS_TO_13),
 174     FFDHE_4096(0x0102, "ffdhe4096", null,
 175             NamedGroupType.NAMED_GROUP_FFDHE,
 176             ProtocolVersion.PROTOCOLS_TO_13),
 177     FFDHE_6144(0x0103, "ffdhe6144", null,
 178             NamedGroupType.NAMED_GROUP_FFDHE,
 179             ProtocolVersion.PROTOCOLS_TO_13),
 180     FFDHE_8192(0x0104, "ffdhe8192", null,
 181             NamedGroupType.NAMED_GROUP_FFDHE,
 182             ProtocolVersion.PROTOCOLS_TO_13),
 183 
 184     // Elliptic Curves (RFC 4492)
 185     //
 186     // arbitrary prime and characteristic-2 curves
 187     ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", null,
 188             NamedGroupType.NAMED_GROUP_ARBITRARY,
 189             ProtocolVersion.PROTOCOLS_TO_12),
 190     ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", null,
 191             NamedGroupType.NAMED_GROUP_ARBITRARY,
 192             ProtocolVersion.PROTOCOLS_TO_12);
 193 
 194     final int id;               // hash + signature
 195     final NamedGroupType type;  // group type
 196     final String name;          // literal name
 197     final String oid;           // object identifier of the named group
 198     final String algorithm;     // signature algorithm
 199     final ProtocolVersion[] supportedProtocols;
 200     private final NamedGroupFunctions functions;    // may be null
 201 
 202     // Constructor used for all NamedGroup types
 203     private NamedGroup(int id, String name, String oid,
 204             NamedGroupType namedGroupType,
 205             ProtocolVersion[] supportedProtocols) {
 206         this.id = id;
 207         this.name = name;
 208         this.oid = oid;
 209         this.type = namedGroupType;
 210         this.supportedProtocols = supportedProtocols;
 211 
 212         if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) {
 213             this.functions = ECDHFunctions.getInstance();
 214             this.algorithm = "EC";
 215         } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) {
 216             this.functions = FFDHFunctions.getInstance();
 217             this.algorithm = "DiffieHellman";
 218         } else if (this.type == NamedGroupType.NAMED_GROUP_XDH) {
 219             this.functions = XDHFunctions.getInstance();
 220             this.algorithm = "XDH";
 221         } else if (this.type == NamedGroupType.NAMED_GROUP_ARBITRARY) {
 222             this.functions = null;
 223             this.algorithm = "EC";
 224         } else {
 225             throw new RuntimeException("Unexpected Named Group Type");
 226         }
 227     }
 228 
 229     private Optional<NamedGroupFunctions> getFunctions() {
 230         return Optional.ofNullable(functions);
 231     }
 232 
 233     // The next set of methods search & retrieve NamedGroups.
 234 
 235     static NamedGroup valueOf(int id) {
 236         for (NamedGroup group : NamedGroup.values()) {
 237             if (group.id == id) {
 238                 return group;
 239             }
 240         }
 241 
 242         return null;
 243     }
 244 
 245     static NamedGroup valueOf(ECParameterSpec params) {
 246         String oid = ECUtil.getCurveName(null, params);
 247         if ((oid != null) && (!oid.isEmpty())) {
 248             for (NamedGroup group : NamedGroup.values()) {
 249                 if ((group.type == NamedGroupType.NAMED_GROUP_ECDHE)
 250                         && oid.equals(group.oid)) {
 251                     return group;
 252                 }
 253             }
 254         }
 255 
 256         return null;
 257     }
 258 
 259     static NamedGroup valueOf(DHParameterSpec params) {
 260         for (NamedGroup ng : NamedGroup.values()) {
 261             if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) {
 262                 continue;
 263             }
 264 
 265             DHParameterSpec ngParams = null;
 266             // functions is non-null for FFDHE type
 267             AlgorithmParameters aps = ng.functions.getParameters(ng);
 268             try {
 269                 ngParams = aps.getParameterSpec(DHParameterSpec.class);
 270             } catch (InvalidParameterSpecException ipse) {
 271                 // should be unlikely
 272             }
 273 
 274             if (ngParams == null) {
 275                 continue;
 276             }
 277 
 278             if (ngParams.getP().equals(params.getP())
 279                     && ngParams.getG().equals(params.getG())) {
 280                 return ng;
 281             }
 282         }
 283 
 284         return null;
 285     }
 286 
 287     static NamedGroup nameOf(String name) {
 288         for (NamedGroup group : NamedGroup.values()) {
 289             if (group.name.equals(name)) {
 290                 return group;
 291             }
 292         }
 293 
 294         return null;
 295     }
 296 
 297     static String nameOf(int id) {
 298         for (NamedGroup group : NamedGroup.values()) {
 299             if (group.id == id) {
 300                 return group.name;
 301             }
 302         }
 303 
 304         return "UNDEFINED-NAMED-GROUP(" + id + ")";
 305     }
 306 
 307     // Are the NamedGroups available for the protocol desired?
 308 
 309     boolean isAvailable(List<ProtocolVersion> protocolVersions) {
 310         for (ProtocolVersion pv : supportedProtocols) {
 311             if (protocolVersions.contains(pv)) {
 312                 return true;
 313             }
 314         }
 315         return false;
 316     }
 317 
 318     boolean isAvailable(ProtocolVersion protocolVersion) {
 319         for (ProtocolVersion pv : supportedProtocols) {
 320             if (protocolVersion == pv) {
 321                 return true;
 322             }
 323         }
 324         return false;
 325     }
 326 
 327     // Are the NamedGroups available for the ciphersuites desired?
 328 
 329     boolean isSupported(List<CipherSuite> cipherSuites) {
 330         for (CipherSuite cs : cipherSuites) {
 331             boolean isMatch = isAvailable(cs.supportedProtocols);
 332             if (isMatch && ((cs.keyExchange == null)
 333                     || (NamedGroupType.arrayContains(
 334                         cs.keyExchange.groupTypes, type)))) {
 335                 return true;
 336             }
 337         }
 338         return false;
 339     }
 340 
 341     // lazy loading of parameters
 342     AlgorithmParameters getParameters() {
 343         Optional<NamedGroupFunctions> ngf = getFunctions();
 344         if (ngf.isEmpty()) {
 345             return null;
 346         }
 347         return ngf.get().getParameters(this);
 348     }
 349 
 350     // The next set of methods use the NamedGroupFunctions table
 351     // to do various operations in a consistent way.
 352 
 353     AlgorithmParameterSpec getParameterSpec() {
 354         Optional<NamedGroupFunctions> ngf = getFunctions();
 355         if (ngf.isEmpty()) {
 356             return null;
 357         }
 358         return ngf.get().getParameterSpec(this);
 359     }
 360 
 361     byte[] encodePossessionPublicKey(
 362             NamedGroupPossession namedGroupPossession) {
 363 
 364         Optional<NamedGroupFunctions> ngf = getFunctions();
 365         if (ngf.isEmpty()) {
 366             return null;
 367         }
 368         return ngf.get().encodePossessionPublicKey(namedGroupPossession);
 369     }
 370 
 371     SSLCredentials decodeCredentials(byte[] encoded,
 372             AlgorithmConstraints constraints,
 373             ExceptionSupplier onConstraintFail)
 374             throws IOException, GeneralSecurityException {
 375 
 376         Optional<NamedGroupFunctions> ngf = getFunctions();
 377         if (ngf.isEmpty()) {
 378             return null;
 379         }
 380         return ngf.get().decodeCredentials(this, encoded, constraints,
 381                 onConstraintFail);
 382     }
 383 
 384     SSLPossession createPossession(SecureRandom random) {
 385 
 386         Optional<NamedGroupFunctions> ngf = getFunctions();
 387         if (ngf.isEmpty()) {
 388             return null;
 389         }
 390         return ngf.get().createPossession(this, random);
 391     }
 392 
 393     SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
 394             throws IOException {
 395 
 396         Optional<NamedGroupFunctions> ngf = getFunctions();
 397         if (ngf.isEmpty()) {
 398             return null;
 399         }
 400         return ngf.get().createKeyDerivation(hc);
 401 
 402     }
 403 
 404     boolean isAvailableGroup() {
 405         Optional<NamedGroupFunctions> ngfOpt = getFunctions();
 406         if (ngfOpt.isEmpty()) {
 407             return false;
 408         }
 409         NamedGroupFunctions ngf = ngfOpt.get();
 410         return ngf.isAvailable(this);
 411     }
 412 
 413     enum NamedGroupType {
 414         NAMED_GROUP_ECDHE,      // Elliptic Curve Groups (ECDHE)
 415         NAMED_GROUP_FFDHE,      // Finite Field Groups (DHE)
 416         NAMED_GROUP_XDH,        // Finite Field Groups (XDH)
 417         NAMED_GROUP_ARBITRARY,  // arbitrary prime and curves (ECDHE)
 418         NAMED_GROUP_NONE;       // Not predefined named group
 419 
 420         boolean isSupported(List<CipherSuite> cipherSuites) {
 421             for (CipherSuite cs : cipherSuites) {
 422                 if (cs.keyExchange == null ||
 423                         arrayContains(cs.keyExchange.groupTypes, this)) {
 424                     return true;
 425                 }
 426             }
 427 
 428             return false;
 429         }
 430 
 431         static boolean arrayContains(NamedGroupType[] namedGroupTypes,
 432                 NamedGroupType namedGroupType) {
 433             for (NamedGroupType ng : namedGroupTypes) {
 434                 if (ng == namedGroupType) {
 435                     return true;
 436                 }
 437             }
 438             return false;
 439         }
 440     }
 441 
 442     interface ExceptionSupplier {
 443         void apply(String s) throws SSLException;
 444     }
 445 
 446     /*
 447      * A list of functions to do NamedGroup operations in a
 448      * algorithm-independent and consistent way.
 449      */
 450     private static abstract class NamedGroupFunctions {
 451 
 452         // cache to speed up the parameters construction
 453         protected static final Map<NamedGroup, AlgorithmParameters>
 454                 namedGroupParams = new ConcurrentHashMap<>();
 455 
 456         protected void checkConstraints(PublicKey publicKey,
 457                 AlgorithmConstraints constraints,
 458                 ExceptionSupplier onConstraintFail)
 459                 throws SSLException {
 460 
 461             if (!constraints.permits(
 462                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
 463                     publicKey)) {
 464 
 465                 onConstraintFail.apply("key share entry does not "
 466                         + "comply with algorithm constraints");
 467             }
 468         }
 469 
 470         public AlgorithmParameters getParameters(NamedGroup ng) {
 471 
 472             AlgorithmParameters result = namedGroupParams.get(ng);
 473             if (result == null) {
 474                 Optional<AlgorithmParameters> paramsOpt = getParametersImpl(ng);
 475                 if (paramsOpt.isPresent()) {
 476                     result = paramsOpt.get();
 477                     namedGroupParams.put(ng, result);
 478                 }
 479             }
 480 
 481             return result;
 482         }
 483 
 484         public abstract byte[] encodePossessionPublicKey(
 485                 NamedGroupPossession namedGroupPossession);
 486 
 487         public abstract SSLCredentials decodeCredentials(
 488                 NamedGroup ng, byte[] encoded,
 489                 AlgorithmConstraints constraints,
 490                 ExceptionSupplier onConstraintFail)
 491                 throws IOException, GeneralSecurityException;
 492 
 493         public abstract SSLPossession createPossession(NamedGroup ng,
 494                 SecureRandom random);
 495 
 496         public abstract SSLKeyDerivation createKeyDerivation(
 497                 HandshakeContext hc) throws IOException;
 498 
 499         protected abstract Optional<AlgorithmParameters> getParametersImpl(
 500                 NamedGroup ng);
 501 
 502         public abstract AlgorithmParameterSpec getParameterSpec(NamedGroup ng);
 503 
 504         public abstract boolean isAvailable(NamedGroup ng);
 505     }
 506 
 507     private static class FFDHFunctions extends NamedGroupFunctions {
 508 
 509         // lazy initialization
 510         private static class FunctionsHolder {
 511             private static final FFDHFunctions instance = new FFDHFunctions();
 512         }
 513 
 514         private static FFDHFunctions getInstance() {
 515             return FunctionsHolder.instance;
 516         }
 517 
 518         @Override
 519         public byte[] encodePossessionPublicKey(
 520                 NamedGroupPossession namedGroupPossession) {
 521             return ((DHEPossession)namedGroupPossession).encode();
 522         }
 523 
 524         @Override
 525         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 526                 AlgorithmConstraints constraints,
 527                 ExceptionSupplier onConstraintFail)
 528                 throws IOException, GeneralSecurityException {
 529 
 530             DHKeyExchange.DHECredentials result
 531                     = DHKeyExchange.DHECredentials.valueOf(ng, encoded);
 532 
 533             checkConstraints(result.getPublicKey(), constraints,
 534                     onConstraintFail);
 535 
 536             return result;
 537         }
 538 
 539         @Override
 540         public SSLPossession createPossession(
 541                 NamedGroup ng, SecureRandom random) {
 542             return new DHKeyExchange.DHEPossession(ng, random);
 543         }
 544 
 545         @Override
 546         public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
 547                 throws IOException {
 548 
 549             return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
 550         }
 551 
 552         @Override
 553         public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
 554             return getDHParameterSpec(ng);
 555         }
 556 
 557         DHParameterSpec getDHParameterSpec(NamedGroup ng) {
 558 
 559             AlgorithmParameters params = getParameters(ng);
 560             try {
 561                 return params.getParameterSpec(DHParameterSpec.class);
 562             } catch (InvalidParameterSpecException ipse) {
 563                 // should be unlikely
 564                 return getPredefinedDHParameterSpec(ng);
 565             }
 566         }
 567 
 568         private static DHParameterSpec getFFDHEDHParameterSpec(
 569                 NamedGroup namedGroup) {
 570 
 571             DHParameterSpec spec = null;
 572             switch (namedGroup) {
 573                 case FFDHE_2048:
 574                     spec = PredefinedDHParameterSpecs.ffdheParams.get(2048);
 575                     break;
 576                 case FFDHE_3072:
 577                     spec = PredefinedDHParameterSpecs.ffdheParams.get(3072);
 578                     break;
 579                 case FFDHE_4096:
 580                     spec = PredefinedDHParameterSpecs.ffdheParams.get(4096);
 581                     break;
 582                 case FFDHE_6144:
 583                     spec = PredefinedDHParameterSpecs.ffdheParams.get(6144);
 584                     break;
 585                 case FFDHE_8192:
 586                     spec = PredefinedDHParameterSpecs.ffdheParams.get(8192);
 587             }
 588 
 589             return spec;
 590         }
 591 
 592         private static DHParameterSpec getPredefinedDHParameterSpec(
 593                 NamedGroup namedGroup) {
 594 
 595             DHParameterSpec spec = null;
 596             switch (namedGroup) {
 597                 case FFDHE_2048:
 598                     spec = PredefinedDHParameterSpecs.definedParams.get(2048);
 599                     break;
 600                 case FFDHE_3072:
 601                     spec = PredefinedDHParameterSpecs.definedParams.get(3072);
 602                     break;
 603                 case FFDHE_4096:
 604                     spec = PredefinedDHParameterSpecs.definedParams.get(4096);
 605                     break;
 606                 case FFDHE_6144:
 607                     spec = PredefinedDHParameterSpecs.definedParams.get(6144);
 608                     break;
 609                 case FFDHE_8192:
 610                     spec = PredefinedDHParameterSpecs.definedParams.get(8192);
 611             }
 612 
 613             return spec;
 614         }
 615 
 616         @Override
 617         public boolean isAvailable(NamedGroup ng) {
 618 
 619             AlgorithmParameters params = getParameters(ng);
 620             return params != null;
 621         }
 622 
 623         @Override
 624         protected Optional<AlgorithmParameters> getParametersImpl(
 625                 NamedGroup ng) {
 626             try {
 627                 AlgorithmParameters params
 628                         = AlgorithmParameters.getInstance("DiffieHellman");
 629                 AlgorithmParameterSpec spec
 630                         = getFFDHEDHParameterSpec(ng);
 631                 params.init(spec);
 632                 return Optional.of(params);
 633             } catch (InvalidParameterSpecException
 634                     | NoSuchAlgorithmException ex) {
 635                 return Optional.empty();
 636             }
 637         }
 638 
 639     }
 640 
 641     private static class ECDHFunctions extends NamedGroupFunctions {
 642 
 643         // lazy initialization
 644         private static class FunctionsHolder {
 645             private static final ECDHFunctions instance = new ECDHFunctions();
 646         }
 647 
 648         private static ECDHFunctions getInstance() {
 649             return FunctionsHolder.instance;
 650         }
 651 
 652         @Override
 653         public byte[] encodePossessionPublicKey(
 654                 NamedGroupPossession namedGroupPossession) {
 655             return ((ECDHEPossession)namedGroupPossession).encode();
 656         }
 657 
 658         @Override
 659         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 660                 AlgorithmConstraints constraints,
 661                 ExceptionSupplier onConstraintFail)
 662                 throws IOException, GeneralSecurityException {
 663 
 664             ECDHKeyExchange.ECDHECredentials result
 665                     = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
 666 
 667             checkConstraints(result.getPublicKey(), constraints,
 668                     onConstraintFail);
 669 
 670             return result;
 671         }
 672 
 673         @Override
 674         public SSLPossession createPossession(
 675                 NamedGroup ng, SecureRandom random) {
 676             return new ECDHKeyExchange.ECDHEPossession(ng, random);
 677         }
 678 
 679         @Override
 680         public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
 681                 throws IOException {
 682 
 683             return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
 684         }
 685 
 686         @Override
 687         public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
 688             return SupportedGroupsExtension.SupportedGroups
 689                     .getECGenParamSpec(ng);
 690         }
 691 
 692         @Override
 693         public boolean isAvailable(NamedGroup ng) {
 694 
 695             AlgorithmParameters params = getParameters(ng);
 696             return params != null;
 697         }
 698 
 699         @Override
 700         protected Optional<AlgorithmParameters> getParametersImpl(
 701                 NamedGroup ng) {
 702             try {
 703                 AlgorithmParameters params
 704                         = AlgorithmParameters.getInstance("EC");
 705                 AlgorithmParameterSpec spec
 706                         = new ECGenParameterSpec(ng.oid);
 707                 params.init(spec);
 708                 return Optional.of(params);
 709             } catch (InvalidParameterSpecException
 710                     | NoSuchAlgorithmException ex) {
 711                 return Optional.empty();
 712             }
 713         }
 714     }
 715 
 716     private static class XDHFunctions extends NamedGroupFunctions {
 717 
 718         // lazy initialization
 719         private static class FunctionsHolder {
 720             private static final XDHFunctions instance = new XDHFunctions();
 721         }
 722 
 723         private static XDHFunctions getInstance() {
 724             return FunctionsHolder.instance;
 725         }
 726 
 727         @Override
 728         public byte[] encodePossessionPublicKey(NamedGroupPossession poss) {
 729             return ((XDHKeyExchange.XDHEPossession)poss).encode();
 730         }
 731 
 732         @Override
 733         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 734                 AlgorithmConstraints constraints,
 735                 ExceptionSupplier onConstraintFail)
 736                 throws IOException, GeneralSecurityException {
 737 
 738             XDHKeyExchange.XDHECredentials result
 739                     = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
 740 
 741             checkConstraints(result.getPublicKey(), constraints,
 742                     onConstraintFail);
 743 
 744             return result;
 745         }
 746 
 747         @Override
 748         public SSLPossession createPossession(
 749                 NamedGroup ng, SecureRandom random) {
 750             return new XDHKeyExchange.XDHEPossession(ng, random);
 751         }
 752 
 753         @Override
 754         public SSLKeyDerivation createKeyDerivation(HandshakeContext hc)
 755                 throws IOException {
 756             return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
 757         }
 758 
 759         @Override
 760         public AlgorithmParameterSpec getParameterSpec(NamedGroup ng) {
 761             return new NamedParameterSpec(ng.name);
 762         }
 763 
 764         @Override
 765         public boolean isAvailable(NamedGroup ng) {
 766 
 767             try {
 768                 KeyAgreement.getInstance(ng.algorithm);
 769                 return true;
 770             } catch (NoSuchAlgorithmException ex) {
 771                 return false;
 772             }
 773         }
 774 
 775         @Override
 776         protected Optional<AlgorithmParameters> getParametersImpl(
 777                 NamedGroup ng) {
 778             return Optional.empty();
 779         }
 780     }
 781 }