|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
package sun.security.ssl; |
|
|
|
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.Set; |
|
import javax.crypto.KeyAgreement; |
|
import sun.security.ssl.DHKeyExchange.DHEPossession; |
|
import sun.security.ssl.ECDHKeyExchange.ECDHEPossession; |
|
import sun.security.util.CurveDB; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
enum NamedGroup { |
|
// Elliptic Curves (RFC 4492) |
|
// |
|
// See sun.security.util.CurveDB for the OIDs |
|
// NIST K-163 |
|
|
|
SECT163_K1(0x0001, "sect163k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect163k1")), |
|
SECT163_R1(0x0002, "sect163r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect163r1")), |
|
|
|
|
|
SECT163_R2(0x0003, "sect163r2", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect163r2")), |
|
SECT193_R1(0x0004, "sect193r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect193r1")), |
|
SECT193_R2(0x0005, "sect193r2", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect193r2")), |
|
|
|
|
|
SECT233_K1(0x0006, "sect233k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect233k1")), |
|
|
|
|
|
SECT233_R1(0x0007, "sect233r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect233r1")), |
|
SECT239_K1(0x0008, "sect239k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect239k1")), |
|
|
|
|
|
SECT283_K1(0x0009, "sect283k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect283k1")), |
|
|
|
|
|
SECT283_R1(0x000A, "sect283r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect283r1")), |
|
|
|
|
|
SECT409_K1(0x000B, "sect409k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect409k1")), |
|
|
|
|
|
SECT409_R1(0x000C, "sect409r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect409r1")), |
|
|
|
|
|
SECT571_K1(0x000D, "sect571k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect571k1")), |
|
|
|
|
|
SECT571_R1(0x000E, "sect571r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("sect571r1")), |
|
SECP160_K1(0x000F, "secp160k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp160k1")), |
|
SECP160_R1(0x0010, "secp160r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp160r1")), |
|
SECP160_R2(0x0011, "secp160r2", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp160r2")), |
|
SECP192_K1(0x0012, "secp192k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp192k1")), |
|
|
|
|
|
SECP192_R1(0x0013, "secp192r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp192r1")), |
|
SECP224_K1(0x0014, "secp224k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp224k1")), |
|
|
|
|
|
SECP224_R1(0x0015, "secp224r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp224r1")), |
|
SECP256_K1(0x0016, "secp256k1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
CurveDB.lookup("secp256k1")), |
|
|
|
|
|
SECP256_R1(0x0017, "secp256r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
CurveDB.lookup("secp256r1")), |
|
|
|
|
|
SECP384_R1(0x0018, "secp384r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
CurveDB.lookup("secp384r1")), |
|
|
|
|
|
SECP521_R1(0x0019, "secp521r1", |
|
NamedGroupSpec.NAMED_GROUP_ECDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
CurveDB.lookup("secp521r1")), |
|
|
|
|
|
X25519(0x001D, "x25519", |
|
NamedGroupSpec.NAMED_GROUP_XDH, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
NamedParameterSpec.X25519), |
|
X448(0x001E, "x448", |
|
NamedGroupSpec.NAMED_GROUP_XDH, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
NamedParameterSpec.X448), |
|
|
|
|
|
FFDHE_2048(0x0100, "ffdhe2048", |
|
NamedGroupSpec.NAMED_GROUP_FFDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
PredefinedDHParameterSpecs.ffdheParams.get(2048)), |
|
|
|
FFDHE_3072(0x0101, "ffdhe3072", |
|
NamedGroupSpec.NAMED_GROUP_FFDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
PredefinedDHParameterSpecs.ffdheParams.get(3072)), |
|
FFDHE_4096(0x0102, "ffdhe4096", |
|
NamedGroupSpec.NAMED_GROUP_FFDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
PredefinedDHParameterSpecs.ffdheParams.get(4096)), |
|
FFDHE_6144(0x0103, "ffdhe6144", |
|
NamedGroupSpec.NAMED_GROUP_FFDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
PredefinedDHParameterSpecs.ffdheParams.get(6144)), |
|
FFDHE_8192(0x0104, "ffdhe8192", |
|
NamedGroupSpec.NAMED_GROUP_FFDHE, |
|
ProtocolVersion.PROTOCOLS_TO_13, |
|
PredefinedDHParameterSpecs.ffdheParams.get(8192)), |
|
|
|
// Elliptic Curves (RFC 4492) |
|
// |
|
|
|
ARBITRARY_PRIME(0xFF01, "arbitrary_explicit_prime_curves", |
|
NamedGroupSpec.NAMED_GROUP_ARBITRARY, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
null), |
|
ARBITRARY_CHAR2(0xFF02, "arbitrary_explicit_char2_curves", |
|
NamedGroupSpec.NAMED_GROUP_ARBITRARY, |
|
ProtocolVersion.PROTOCOLS_TO_12, |
|
null); |
|
|
|
final int id; |
|
final String name; |
|
final NamedGroupSpec spec; |
|
final ProtocolVersion[] supportedProtocols; |
|
final String algorithm; |
|
final AlgorithmParameterSpec keAlgParamSpec; |
|
final AlgorithmParameters keAlgParams; |
|
final boolean isAvailable; |
|
|
|
|
|
private static final Set<CryptoPrimitive> KEY_AGREEMENT_PRIMITIVE_SET = |
|
Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.KEY_AGREEMENT)); |
|
|
|
|
|
private NamedGroup(int id, String name, |
|
NamedGroupSpec namedGroupSpec, |
|
ProtocolVersion[] supportedProtocols, |
|
AlgorithmParameterSpec keAlgParamSpec) { |
|
this.id = id; |
|
this.name = name; |
|
this.spec = namedGroupSpec; |
|
this.algorithm = namedGroupSpec.algorithm; |
|
this.supportedProtocols = supportedProtocols; |
|
this.keAlgParamSpec = keAlgParamSpec; |
|
|
|
|
|
AlgorithmParameters algParams = null; |
|
boolean mediator = (keAlgParamSpec != null); |
|
|
|
// An EC provider, for example the SunEC provider, may support |
|
// AlgorithmParameters but not KeyPairGenerator or KeyAgreement. |
|
// |
|
|
|
if (mediator && (namedGroupSpec == NamedGroupSpec.NAMED_GROUP_ECDHE)) { |
|
mediator = JsseJce.isEcAvailable(); |
|
} |
|
|
|
|
|
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 { |
|
// 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); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
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; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
static NamedGroup valueOf(ECParameterSpec params) { |
|
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.spec != NamedGroupSpec.NAMED_GROUP_FFDHE) { |
|
continue; |
|
} |
|
|
|
DHParameterSpec ngParams = (DHParameterSpec)ng.keAlgParamSpec; |
|
if (ngParams.getP().equals(params.getP()) |
|
&& ngParams.getG().equals(params.getG())) { |
|
return ng; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
static NamedGroup nameOf(String name) { |
|
for (NamedGroup group : NamedGroup.values()) { |
|
if (group.name.equalsIgnoreCase(name)) { |
|
return group; |
|
} |
|
} |
|
|
|
return null; |
|
} |
|
|
|
static String nameOf(int id) { |
|
for (NamedGroup group : NamedGroup.values()) { |
|
if (group.id == id) { |
|
return group.name; |
|
} |
|
} |
|
|
|
return "UNDEFINED-NAMED-GROUP(" + id + ")"; |
|
} |
|
|
|
|
|
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; |
|
} |
|
|
|
|
|
boolean isSupported(List<CipherSuite> cipherSuites) { |
|
for (CipherSuite cs : cipherSuites) { |
|
boolean isMatch = isAvailable(cs.supportedProtocols); |
|
if (isMatch && ((cs.keyExchange == null) |
|
|| (NamedGroupSpec.arrayContains( |
|
cs.keyExchange.groupTypes, spec)))) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
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) { |
|
return spec.encodePossessionPublicKey(namedGroupPossession); |
|
} |
|
|
|
SSLCredentials decodeCredentials(byte[] encoded, |
|
AlgorithmConstraints constraints, |
|
ExceptionSupplier onConstraintFail) |
|
throws IOException, GeneralSecurityException { |
|
return spec.decodeCredentials( |
|
this, encoded, constraints, onConstraintFail); |
|
} |
|
|
|
SSLPossession createPossession(SecureRandom random) { |
|
return spec.createPossession(this, random); |
|
} |
|
|
|
SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException { |
|
return spec.createKeyDerivation(hc); |
|
} |
|
|
|
interface ExceptionSupplier { |
|
void apply(String s) throws SSLException; |
|
} |
|
|
|
|
|
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"); |
|
} |
|
} |
|
|
|
byte[] encodePossessionPublicKey( |
|
NamedGroupPossession namedGroupPossession); |
|
|
|
SSLCredentials decodeCredentials( |
|
NamedGroup ng, byte[] encoded, |
|
AlgorithmConstraints constraints, |
|
ExceptionSupplier onConstraintFail |
|
) throws IOException, GeneralSecurityException; |
|
|
|
SSLPossession createPossession(NamedGroup ng, SecureRandom random); |
|
|
|
SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException; |
|
} |
|
|
|
enum NamedGroupSpec implements NamedGroupScheme { |
|
|
|
NAMED_GROUP_ECDHE("EC", ECDHEScheme.instance), |
|
|
|
|
|
NAMED_GROUP_FFDHE("DiffieHellman", FFDHEScheme.instance), |
|
|
|
|
|
NAMED_GROUP_XDH("XDH", XDHScheme.instance), |
|
|
|
|
|
NAMED_GROUP_ARBITRARY("EC", null), |
|
|
|
|
|
NAMED_GROUP_NONE("", null); |
|
|
|
private final String algorithm; |
|
private final NamedGroupScheme scheme; |
|
|
|
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)) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
static boolean arrayContains(NamedGroupSpec[] namedGroupTypes, |
|
NamedGroupSpec namedGroupType) { |
|
for (NamedGroupSpec ng : namedGroupTypes) { |
|
if (ng == namedGroupType) { |
|
return true; |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
@Override |
|
public byte[] encodePossessionPublicKey( |
|
NamedGroupPossession namedGroupPossession) { |
|
if (scheme != null) { |
|
return scheme.encodePossessionPublicKey(namedGroupPossession); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
@Override |
|
public SSLCredentials decodeCredentials(NamedGroup ng, byte[] encoded, |
|
AlgorithmConstraints constraints, |
|
ExceptionSupplier onConstraintFail |
|
) throws IOException, GeneralSecurityException { |
|
if (scheme != null) { |
|
return scheme.decodeCredentials( |
|
ng, encoded, constraints, onConstraintFail); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
@Override |
|
public SSLPossession createPossession( |
|
NamedGroup ng, SecureRandom random) { |
|
if (scheme != null) { |
|
return scheme.createPossession(ng, random); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
@Override |
|
public SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException { |
|
if (scheme != null) { |
|
return scheme.createKeyDerivation(hc); |
|
} |
|
|
|
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 { |
|
|
|
DHKeyExchange.DHECredentials result |
|
= DHKeyExchange.DHECredentials.valueOf(ng, encoded); |
|
|
|
checkConstraints(result.getPublicKey(), constraints, |
|
onConstraintFail); |
|
|
|
return result; |
|
} |
|
|
|
@Override |
|
public SSLPossession createPossession( |
|
NamedGroup ng, SecureRandom random) { |
|
return new DHKeyExchange.DHEPossession(ng, random); |
|
} |
|
|
|
@Override |
|
public SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException { |
|
|
|
return DHKeyExchange.kaGenerator.createKeyDerivation(hc); |
|
} |
|
} |
|
|
|
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 { |
|
|
|
ECDHKeyExchange.ECDHECredentials result |
|
= ECDHKeyExchange.ECDHECredentials.valueOf(ng, encoded); |
|
|
|
checkConstraints(result.getPublicKey(), constraints, |
|
onConstraintFail); |
|
|
|
return result; |
|
} |
|
|
|
@Override |
|
public SSLPossession createPossession( |
|
NamedGroup ng, SecureRandom random) { |
|
return new ECDHKeyExchange.ECDHEPossession(ng, random); |
|
} |
|
|
|
@Override |
|
public SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException { |
|
return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc); |
|
} |
|
} |
|
|
|
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 { |
|
|
|
XDHKeyExchange.XDHECredentials result |
|
= XDHKeyExchange.XDHECredentials.valueOf(ng, encoded); |
|
|
|
checkConstraints(result.getPublicKey(), constraints, |
|
onConstraintFail); |
|
|
|
return result; |
|
} |
|
|
|
@Override |
|
public SSLPossession createPossession( |
|
NamedGroup ng, SecureRandom random) { |
|
return new XDHKeyExchange.XDHEPossession(ng, random); |
|
} |
|
|
|
@Override |
|
public SSLKeyDerivation createKeyDerivation( |
|
HandshakeContext hc) throws IOException { |
|
return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc); |
|
} |
|
} |
|
} |