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