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.Collections;
  33 import java.util.EnumSet;
  34 import java.util.List;
  35 import java.util.Set;
  36 import javax.crypto.KeyAgreement;
  37 import sun.security.ssl.DHKeyExchange.DHEPossession;
  38 import sun.security.ssl.ECDHKeyExchange.ECDHEPossession;
  39 import sun.security.util.CurveDB;
  40 
  41 
  42 /**
  43  * An enum containing all known named groups for use in TLS.
  44  *
  45  * The enum also contains the required properties of each group and the
  46  * required functions (e.g. encoding/decoding).
  47  */
  48 enum NamedGroup {
  49     // Elliptic Curves (RFC 4492)
  50     //
  51     // See sun.security.util.CurveDB for the OIDs
  52     // NIST K-163
  53 
  54     SECT163_K1(0x0001, "sect163k1", true,
  55             NamedGroupSpec.NAMED_GROUP_ECDHE,
  56             ProtocolVersion.PROTOCOLS_TO_12,
  57             CurveDB.lookup("sect163k1")),
  58     SECT163_R1(0x0002, "sect163r1", false,
  59             NamedGroupSpec.NAMED_GROUP_ECDHE,
  60             ProtocolVersion.PROTOCOLS_TO_12,
  61             CurveDB.lookup("sect163r1")),
  62 
  63     // NIST B-163
  64     SECT163_R2(0x0003, "sect163r2", true,
  65             NamedGroupSpec.NAMED_GROUP_ECDHE,
  66             ProtocolVersion.PROTOCOLS_TO_12,
  67             CurveDB.lookup("sect163r2")),
  68     SECT193_R1(0x0004, "sect193r1", false,
  69             NamedGroupSpec.NAMED_GROUP_ECDHE,
  70             ProtocolVersion.PROTOCOLS_TO_12,
  71             CurveDB.lookup("sect193r1")),
  72     SECT193_R2(0x0005, "sect193r2", false,
  73             NamedGroupSpec.NAMED_GROUP_ECDHE,
  74             ProtocolVersion.PROTOCOLS_TO_12,
  75             CurveDB.lookup("sect193r2")),
  76 
  77     // NIST K-233
  78     SECT233_K1(0x0006, "sect233k1", true,
  79             NamedGroupSpec.NAMED_GROUP_ECDHE,
  80             ProtocolVersion.PROTOCOLS_TO_12,
  81             CurveDB.lookup("sect233k1")),
  82 
  83     // NIST B-233
  84     SECT233_R1(0x0007, "sect233r1", true,
  85             NamedGroupSpec.NAMED_GROUP_ECDHE,
  86             ProtocolVersion.PROTOCOLS_TO_12,
  87             CurveDB.lookup("sect233r1")),
  88     SECT239_K1(0x0008, "sect239k1", false,
  89             NamedGroupSpec.NAMED_GROUP_ECDHE,
  90             ProtocolVersion.PROTOCOLS_TO_12,
  91             CurveDB.lookup("sect239k1")),
  92 
  93     // NIST K-283
  94     SECT283_K1(0x0009, "sect283k1", true,
  95             NamedGroupSpec.NAMED_GROUP_ECDHE,
  96             ProtocolVersion.PROTOCOLS_TO_12,
  97             CurveDB.lookup("sect283k1")),
  98 
  99     // NIST B-283
 100     SECT283_R1(0x000A, "sect283r1", true,
 101             NamedGroupSpec.NAMED_GROUP_ECDHE,
 102             ProtocolVersion.PROTOCOLS_TO_12,
 103             CurveDB.lookup("sect283r1")),
 104 
 105     // NIST K-409
 106     SECT409_K1(0x000B, "sect409k1", true,
 107             NamedGroupSpec.NAMED_GROUP_ECDHE,
 108             ProtocolVersion.PROTOCOLS_TO_12,
 109             CurveDB.lookup("sect409k1")),
 110 
 111     // NIST B-409
 112     SECT409_R1(0x000C, "sect409r1", true,
 113             NamedGroupSpec.NAMED_GROUP_ECDHE,
 114             ProtocolVersion.PROTOCOLS_TO_12,
 115             CurveDB.lookup("sect409r1")),
 116 
 117     // NIST K-571
 118     SECT571_K1(0x000D, "sect571k1", true,
 119             NamedGroupSpec.NAMED_GROUP_ECDHE,
 120             ProtocolVersion.PROTOCOLS_TO_12,
 121             CurveDB.lookup("sect571k1")),
 122 
 123     // NIST B-571
 124     SECT571_R1(0x000E, "sect571r1", true,
 125             NamedGroupSpec.NAMED_GROUP_ECDHE,
 126             ProtocolVersion.PROTOCOLS_TO_12,
 127             CurveDB.lookup("sect571r1")),
 128     SECP160_K1(0x000F, "secp160k1", false,
 129             NamedGroupSpec.NAMED_GROUP_ECDHE,
 130             ProtocolVersion.PROTOCOLS_TO_12,
 131             CurveDB.lookup("secp160k1")),
 132     SECP160_R1(0x0010, "secp160r1", false,
 133             NamedGroupSpec.NAMED_GROUP_ECDHE,
 134             ProtocolVersion.PROTOCOLS_TO_12,
 135             CurveDB.lookup("secp160r1")),
 136     SECP160_R2(0x0011, "secp160r2", false,
 137             NamedGroupSpec.NAMED_GROUP_ECDHE,
 138             ProtocolVersion.PROTOCOLS_TO_12,
 139             CurveDB.lookup("secp160r2")),
 140     SECP192_K1(0x0012, "secp192k1", false,
 141             NamedGroupSpec.NAMED_GROUP_ECDHE,
 142             ProtocolVersion.PROTOCOLS_TO_12,
 143             CurveDB.lookup("secp192k1")),
 144 
 145     // NIST P-192
 146     SECP192_R1(0x0013, "secp192r1", true,
 147             NamedGroupSpec.NAMED_GROUP_ECDHE,
 148             ProtocolVersion.PROTOCOLS_TO_12,
 149             CurveDB.lookup("secp192r1")),
 150     SECP224_K1(0x0014, "secp224k1", false,
 151             NamedGroupSpec.NAMED_GROUP_ECDHE,
 152             ProtocolVersion.PROTOCOLS_TO_12,
 153             CurveDB.lookup("secp224k1")),
 154 
 155     // NIST P-224
 156     SECP224_R1(0x0015, "secp224r1", true,
 157             NamedGroupSpec.NAMED_GROUP_ECDHE,
 158             ProtocolVersion.PROTOCOLS_TO_12,
 159             CurveDB.lookup("secp224r1")),
 160     SECP256_K1(0x0016, "secp256k1", false,
 161             NamedGroupSpec.NAMED_GROUP_ECDHE,
 162             ProtocolVersion.PROTOCOLS_TO_12,
 163             CurveDB.lookup("secp256k1")),
 164 
 165     // NIST P-256
 166     SECP256_R1(0x0017, "secp256r1", true,
 167             NamedGroupSpec.NAMED_GROUP_ECDHE,
 168             ProtocolVersion.PROTOCOLS_TO_13,
 169             CurveDB.lookup("secp256r1")),
 170 
 171     // NIST P-384
 172     SECP384_R1(0x0018, "secp384r1", true,
 173             NamedGroupSpec.NAMED_GROUP_ECDHE,
 174             ProtocolVersion.PROTOCOLS_TO_13,
 175             CurveDB.lookup("secp384r1")),
 176 
 177     // NIST P-521
 178     SECP521_R1(0x0019, "secp521r1", true,
 179             NamedGroupSpec.NAMED_GROUP_ECDHE,
 180             ProtocolVersion.PROTOCOLS_TO_13,
 181             CurveDB.lookup("secp521r1")),
 182 
 183     // x25519 and x448 (RFC 8422/8446)
 184     X25519(0x001D, "x25519", true,
 185             NamedGroupSpec.NAMED_GROUP_XDH,
 186             ProtocolVersion.PROTOCOLS_TO_13,
 187             NamedParameterSpec.X25519),
 188     X448(0x001E, "x448", true,
 189             NamedGroupSpec.NAMED_GROUP_XDH,
 190             ProtocolVersion.PROTOCOLS_TO_13,
 191             NamedParameterSpec.X448),
 192 
 193     // Finite Field Diffie-Hellman Ephemeral Parameters (RFC 7919)
 194     FFDHE_2048(0x0100, "ffdhe2048", true,
 195             NamedGroupSpec.NAMED_GROUP_FFDHE,
 196             ProtocolVersion.PROTOCOLS_TO_13,
 197             PredefinedDHParameterSpecs.ffdheParams.get(2048)),
 198 
 199     FFDHE_3072(0x0101, "ffdhe3072", true,
 200             NamedGroupSpec.NAMED_GROUP_FFDHE,
 201             ProtocolVersion.PROTOCOLS_TO_13,
 202             PredefinedDHParameterSpecs.ffdheParams.get(3072)),
 203     FFDHE_4096(0x0102, "ffdhe4096", true,
 204             NamedGroupSpec.NAMED_GROUP_FFDHE,
 205             ProtocolVersion.PROTOCOLS_TO_13,
 206             PredefinedDHParameterSpecs.ffdheParams.get(4096)),
 207     FFDHE_6144(0x0103, "ffdhe6144", true,
 208             NamedGroupSpec.NAMED_GROUP_FFDHE,
 209             ProtocolVersion.PROTOCOLS_TO_13,
 210             PredefinedDHParameterSpecs.ffdheParams.get(6144)),
 211     FFDHE_8192(0x0104, "ffdhe8192", true,
 212             NamedGroupSpec.NAMED_GROUP_FFDHE,
 213             ProtocolVersion.PROTOCOLS_TO_13,
 214             PredefinedDHParameterSpecs.ffdheParams.get(8192)),
 215 
 216     // Elliptic Curves (RFC 4492)
 217     //
 218     // arbitrary prime and characteristic-2 curves
 219     ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", false,
 220             NamedGroupSpec.NAMED_GROUP_ARBITRARY,
 221             ProtocolVersion.PROTOCOLS_TO_12,
 222             null),
 223     ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", false,
 224             NamedGroupSpec.NAMED_GROUP_ARBITRARY,
 225             ProtocolVersion.PROTOCOLS_TO_12,
 226             null);
 227 
 228     final int id;               // hash + signature
 229     final String name;          // literal name
 230     final boolean isFips;       // can be used in FIPS mode?
 231     final NamedGroupSpec spec;  // group type
 232     final ProtocolVersion[] supportedProtocols;
 233     final String algorithm;     // key exchange algorithm
 234     final AlgorithmParameterSpec keAlgParamSpec;
 235     final AlgorithmParameters keAlgParams;
 236     final boolean isAvailable;
 237 
 238     // performance optimization
 239     private static final Set<CryptoPrimitive> KEY_AGREEMENT_PRIMITIVE_SET =
 240         Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT));
 241 
 242     // Constructor used for all NamedGroup types
 243     private NamedGroup(int id, String name, boolean isFips,
 244             NamedGroupSpec namedGroupSpec,
 245             ProtocolVersion[] supportedProtocols,
 246             AlgorithmParameterSpec keAlgParamSpec) {
 247         this.id = id;
 248         this.name = name;
 249         this.isFips = isFips;
 250         this.spec = namedGroupSpec;
 251         this.algorithm = namedGroupSpec.algorithm;
 252         this.supportedProtocols = supportedProtocols;
 253         this.keAlgParamSpec = keAlgParamSpec;
 254 
 255         AlgorithmParameters algParams = null;
 256         boolean mediator = (keAlgParamSpec != null);
 257         if (mediator) {
 258             try {
 259                 algParams =
 260                     AlgorithmParameters.getInstance(namedGroupSpec.algorithm);
 261                 algParams.init(keAlgParamSpec);
 262             } catch (InvalidParameterSpecException
 263                     | NoSuchAlgorithmException exp) {
 264                 if (namedGroupSpec != NamedGroupSpec.NAMED_GROUP_XDH) {
 265                     mediator = false;
 266                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 267                         SSLLogger.warning(
 268                             "No AlgorithmParameters for " + name, exp);
 269                     }
 270                 } else {
 271                     // HACK CODE
 272                     //
 273                     // Please remove the following code if the XDH/X25519/X448
 274                     // AlgorithmParameters algorithms are supported in JDK.
 275                     algParams = null;
 276                     try {
 277                         KeyAgreement.getInstance(name);
 278 
 279                         // The following service is also needed.  But for
 280                         // performance, check the KeyAgreement impl only.
 281                         //
 282                         // KeyFactory.getInstance(name);
 283                         // KeyPairGenerator.getInstance(name);
 284                         // AlgorithmParameters.getInstance(name);
 285                     } catch (NoSuchAlgorithmException nsae) {
 286                         mediator = false;
 287                         if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
 288                             SSLLogger.warning(
 289                                 "No AlgorithmParameters for " + name, nsae);
 290                         }
 291                     }
 292                 }
 293             }
 294         }
 295 
 296         this.isAvailable = mediator;
 297         this.keAlgParams = mediator ? algParams : null;
 298     }
 299 
 300     //
 301     // The next set of methods search & retrieve NamedGroups.
 302     //
 303     static NamedGroup valueOf(int id) {
 304         for (NamedGroup group : NamedGroup.values()) {
 305             if (group.id == id) {
 306                 return group;
 307             }
 308         }
 309 
 310         return null;
 311     }
 312 
 313     static NamedGroup valueOf(ECParameterSpec params) {
 314         for (NamedGroup ng : NamedGroup.values()) {
 315             if (ng.spec == NamedGroupSpec.NAMED_GROUP_ECDHE) {
 316                 if ((params == ng.keAlgParamSpec) ||
 317                         (ng.keAlgParamSpec == CurveDB.lookup(params))) {
 318                     return ng;
 319                 }
 320             }
 321         }
 322 
 323         return null;
 324     }
 325 
 326     static NamedGroup valueOf(DHParameterSpec params) {
 327         for (NamedGroup ng : NamedGroup.values()) {
 328             if (ng.spec != NamedGroupSpec.NAMED_GROUP_FFDHE) {
 329                 continue;
 330             }
 331 
 332             DHParameterSpec ngParams = (DHParameterSpec)ng.keAlgParamSpec;
 333             if (ngParams.getP().equals(params.getP())
 334                     && ngParams.getG().equals(params.getG())) {
 335                 return ng;
 336             }
 337         }
 338 
 339         return null;
 340     }
 341 
 342     static NamedGroup nameOf(String name) {
 343         for (NamedGroup group : NamedGroup.values()) {
 344             if (group.name.equals(name)) {
 345                 return group;
 346             }
 347         }
 348 
 349         return null;
 350     }
 351 
 352     static String nameOf(int id) {
 353         for (NamedGroup group : NamedGroup.values()) {
 354             if (group.id == id) {
 355                 return group.name;
 356             }
 357         }
 358 
 359         return "UNDEFINED-NAMED-GROUP(" + id + ")";
 360     }
 361 
 362     // Is the NamedGroup available for the protocols desired?
 363     boolean isAvailable(List<ProtocolVersion> protocolVersions) {
 364         if (this.isAvailable) {
 365             for (ProtocolVersion pv : supportedProtocols) {
 366                 if (protocolVersions.contains(pv)) {
 367                     return true;
 368                 }
 369             }
 370         }
 371 
 372         return false;
 373     }
 374 
 375     boolean isAvailable(ProtocolVersion protocolVersion) {
 376         if (this.isAvailable) {
 377             for (ProtocolVersion pv : supportedProtocols) {
 378                 if (protocolVersion == pv) {
 379                     return true;
 380                 }
 381             }
 382         }
 383 
 384         return false;
 385     }
 386 
 387     // Are the NamedGroups available for the ciphersuites desired?
 388     boolean isSupported(List<CipherSuite> cipherSuites) {
 389         for (CipherSuite cs : cipherSuites) {
 390             boolean isMatch = isAvailable(cs.supportedProtocols);
 391             if (isMatch && ((cs.keyExchange == null)
 392                     || (NamedGroupSpec.arrayContains(
 393                             cs.keyExchange.groupTypes, spec)))) {
 394                 return true;
 395             }
 396         }
 397 
 398         return false;
 399     }
 400 
 401     boolean isPermitted(AlgorithmConstraints constraints) {
 402         return constraints.permits(KEY_AGREEMENT_PRIMITIVE_SET,
 403                         this.name, null) &&
 404                 constraints.permits(KEY_AGREEMENT_PRIMITIVE_SET,
 405                         this.algorithm, this.keAlgParams);
 406     }
 407 
 408     byte[] encodePossessionPublicKey(
 409             NamedGroupPossession namedGroupPossession) {
 410         return spec.encodePossessionPublicKey(namedGroupPossession);
 411     }
 412 
 413     SSLCredentials decodeCredentials(byte[] encoded,
 414             AlgorithmConstraints constraints,
 415             ExceptionSupplier onConstraintFail)
 416             throws IOException, GeneralSecurityException {
 417         return spec.decodeCredentials(
 418                 this, encoded, constraints, onConstraintFail);
 419     }
 420 
 421     SSLPossession createPossession(SecureRandom random) {
 422         return spec.createPossession(this, random);
 423     }
 424 
 425     SSLKeyDerivation createKeyDerivation(
 426             HandshakeContext hc) throws IOException {
 427         return spec.createKeyDerivation(hc);
 428     }
 429 
 430     interface ExceptionSupplier {
 431         void apply(String s) throws SSLException;
 432     }
 433 
 434     // A list of operations related to named groups.
 435     private interface NamedGroupScheme {
 436         default void checkConstraints(PublicKey publicKey,
 437                 AlgorithmConstraints constraints,
 438                 ExceptionSupplier onConstraintFail) throws SSLException {
 439             if (!constraints.permits(
 440                     EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) {
 441                 onConstraintFail.apply("key share entry does not "
 442                         + "comply with algorithm constraints");
 443             }
 444         }
 445 
 446         byte[] encodePossessionPublicKey(
 447                 NamedGroupPossession namedGroupPossession);
 448 
 449         SSLCredentials decodeCredentials(
 450                 NamedGroup ng, byte[] encoded,
 451                 AlgorithmConstraints constraints,
 452                 ExceptionSupplier onConstraintFail
 453             ) throws IOException, GeneralSecurityException;
 454 
 455         SSLPossession createPossession(NamedGroup ng, SecureRandom random);
 456 
 457         SSLKeyDerivation createKeyDerivation(
 458                 HandshakeContext hc) throws IOException;
 459     }
 460 
 461     enum NamedGroupSpec implements NamedGroupScheme {
 462         // Elliptic Curve Groups (ECDHE)
 463         NAMED_GROUP_ECDHE("EC", ECDHEScheme.instance),
 464 
 465         // Finite Field Groups (DHE)
 466         NAMED_GROUP_FFDHE("DiffieHellman", FFDHEScheme.instance),
 467 
 468         // Finite Field Groups (XDH)
 469         NAMED_GROUP_XDH("XDH", XDHScheme.instance),
 470 
 471         // arbitrary prime and curves (ECDHE)
 472         NAMED_GROUP_ARBITRARY("EC", null),
 473 
 474         // Not predefined named group
 475         NAMED_GROUP_NONE("", null);
 476 
 477         private final String algorithm;     // key exchange name
 478         private final NamedGroupScheme scheme;  // named group operations
 479 
 480         private NamedGroupSpec(String algorithm, NamedGroupScheme scheme) {
 481             this.algorithm = algorithm;
 482             this.scheme = scheme;
 483         }
 484 
 485         boolean isSupported(List<CipherSuite> cipherSuites) {
 486             for (CipherSuite cs : cipherSuites) {
 487                 if (cs.keyExchange == null ||
 488                         arrayContains(cs.keyExchange.groupTypes, this)) {
 489                     return true;
 490                 }
 491             }
 492 
 493             return false;
 494         }
 495 
 496         static boolean arrayContains(NamedGroupSpec[] namedGroupTypes,
 497                 NamedGroupSpec namedGroupType) {
 498             for (NamedGroupSpec ng : namedGroupTypes) {
 499                 if (ng == namedGroupType) {
 500                     return true;
 501                 }
 502             }
 503 
 504             return false;
 505         }
 506 
 507         @Override
 508         public byte[] encodePossessionPublicKey(
 509                 NamedGroupPossession namedGroupPossession) {
 510             if (scheme != null) {
 511                 return scheme.encodePossessionPublicKey(namedGroupPossession);
 512             }
 513 
 514             return null;
 515         }
 516 
 517         @Override
 518         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 519                     AlgorithmConstraints constraints,
 520                     ExceptionSupplier onConstraintFail
 521                 ) throws IOException, GeneralSecurityException {
 522             if (scheme != null) {
 523                 return scheme.decodeCredentials(
 524                         ng, encoded, constraints, onConstraintFail);
 525             }
 526 
 527             return null;
 528         }
 529 
 530         @Override
 531         public SSLPossession createPossession(
 532                 NamedGroup ng, SecureRandom random) {
 533             if (scheme != null) {
 534                 return scheme.createPossession(ng, random);
 535             }
 536 
 537             return null;
 538         }
 539 
 540         @Override
 541         public SSLKeyDerivation createKeyDerivation(
 542                 HandshakeContext hc) throws IOException {
 543             if (scheme != null) {
 544                 return scheme.createKeyDerivation(hc);
 545             }
 546 
 547             return null;
 548         }
 549     }
 550 
 551     private static class FFDHEScheme implements NamedGroupScheme {
 552         private static final FFDHEScheme instance = new FFDHEScheme();
 553 
 554         @Override
 555         public byte[] encodePossessionPublicKey(
 556                 NamedGroupPossession namedGroupPossession) {
 557             return ((DHEPossession)namedGroupPossession).encode();
 558         }
 559 
 560         @Override
 561         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 562                 AlgorithmConstraints constraints,
 563                 ExceptionSupplier onConstraintFail
 564             ) throws IOException, GeneralSecurityException {
 565 
 566             DHKeyExchange.DHECredentials result
 567                     = DHKeyExchange.DHECredentials.valueOf(ng, encoded);
 568 
 569             checkConstraints(result.getPublicKey(), constraints,
 570                     onConstraintFail);
 571 
 572             return result;
 573         }
 574 
 575         @Override
 576         public SSLPossession createPossession(
 577                 NamedGroup ng, SecureRandom random) {
 578             return new DHKeyExchange.DHEPossession(ng, random);
 579         }
 580 
 581         @Override
 582         public SSLKeyDerivation createKeyDerivation(
 583                 HandshakeContext hc) throws IOException {
 584 
 585             return DHKeyExchange.kaGenerator.createKeyDerivation(hc);
 586         }
 587     }
 588 
 589     private static class ECDHEScheme implements NamedGroupScheme {
 590         private static final ECDHEScheme instance = new ECDHEScheme();
 591 
 592         @Override
 593         public byte[] encodePossessionPublicKey(
 594                 NamedGroupPossession namedGroupPossession) {
 595             return ((ECDHEPossession)namedGroupPossession).encode();
 596         }
 597 
 598         @Override
 599         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 600                 AlgorithmConstraints constraints,
 601                 ExceptionSupplier onConstraintFail
 602             ) throws IOException, GeneralSecurityException {
 603 
 604             ECDHKeyExchange.ECDHECredentials result
 605                     = ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded);
 606 
 607             checkConstraints(result.getPublicKey(), constraints,
 608                     onConstraintFail);
 609 
 610             return result;
 611         }
 612 
 613         @Override
 614         public SSLPossession createPossession(
 615                 NamedGroup ng, SecureRandom random) {
 616             return new ECDHKeyExchange.ECDHEPossession(ng, random);
 617         }
 618 
 619         @Override
 620         public SSLKeyDerivation createKeyDerivation(
 621                 HandshakeContext hc) throws IOException {
 622             return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc);
 623         }
 624     }
 625 
 626     private static class XDHScheme implements NamedGroupScheme {
 627         private static final XDHScheme instance = new XDHScheme();
 628 
 629         @Override
 630         public byte[] encodePossessionPublicKey(NamedGroupPossession poss) {
 631             return ((XDHKeyExchange.XDHEPossession)poss).encode();
 632         }
 633 
 634         @Override
 635         public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded,
 636                 AlgorithmConstraints constraints,
 637                 ExceptionSupplier onConstraintFail
 638             ) throws IOException, GeneralSecurityException {
 639 
 640             XDHKeyExchange.XDHECredentials result
 641                     = XDHKeyExchange.XDHECredentials.valueOf(ng, encoded);
 642 
 643             checkConstraints(result.getPublicKey(), constraints,
 644                     onConstraintFail);
 645 
 646             return result;
 647         }
 648 
 649         @Override
 650         public SSLPossession createPossession(
 651                 NamedGroup ng, SecureRandom random) {
 652             return new XDHKeyExchange.XDHEPossession(ng, random);
 653         }
 654 
 655         @Override
 656         public SSLKeyDerivation createKeyDerivation(
 657                 HandshakeContext hc) throws IOException {
 658             return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc);
 659         }
 660     }
 661 }