--- old/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java 2018-08-30 11:09:01.105608001 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/DHKeyExchange.java 2018-08-30 11:09:00.333608001 -0400 @@ -61,7 +61,7 @@ static final SSLKeyAgreementGenerator kaGenerator = new DHEKAGenerator(); - static final class DHECredentials implements SSLCredentials { + static final class DHECredentials implements SSLKeyAgreementCredentials { final DHPublicKey popPublicKey; final NamedGroup namedGroup; @@ -70,6 +70,11 @@ this.namedGroup = namedGroup; } + @Override + public PublicKey getPublicKey() { + return popPublicKey; + } + static DHECredentials valueOf(NamedGroup ng, byte[] encodedPublic) throws IOException, GeneralSecurityException { @@ -401,7 +406,7 @@ @Override public SSLKeyDerivation createKeyDerivation( - HandshakeContext context) throws IOException { + HandshakeContext context) throws IOException { DHEPossession dhePossession = null; DHECredentials dheCredentials = null; for (SSLPossession poss : context.handshakePossessions) { @@ -424,7 +429,7 @@ DHParameterSpec pps = dhep.publicKey.getParams(); DHParameterSpec cps = dhec.popPublicKey.getParams(); if (pps.getP().equals(cps.getP()) && - pps.getG().equals(cps.getG())) { + pps.getG().equals(cps.getG())) { dheCredentials = (DHECredentials)cred; break; } @@ -439,96 +444,11 @@ if (dhePossession == null || dheCredentials == null) { context.conContext.fatal(Alert.HANDSHAKE_FAILURE, - "No sufficient DHE key agreement parameters negotiated"); - } - - return new DHEKAKeyDerivation(context, - dhePossession.privateKey, dheCredentials.popPublicKey); - } - - private static final - class DHEKAKeyDerivation implements SSLKeyDerivation { - private final HandshakeContext context; - private final PrivateKey localPrivateKey; - private final PublicKey peerPublicKey; - - DHEKAKeyDerivation(HandshakeContext context, - PrivateKey localPrivateKey, - PublicKey peerPublicKey) { - this.context = context; - this.localPrivateKey = localPrivateKey; - this.peerPublicKey = peerPublicKey; - } - - @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - if (!context.negotiatedProtocol.useTLS13PlusSpec()) { - return t12DeriveKey(algorithm, params); - } else { - return t13DeriveKey(algorithm, params); - } + "No sufficient DHE key agreement parameters negotiated"); } - private SecretKey t12DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - try { - KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - SecretKey preMasterSecret = - ka.generateSecret("TlsPremasterSecret"); - SSLMasterKeyDerivation mskd = - SSLMasterKeyDerivation.valueOf( - context.negotiatedProtocol); - if (mskd == null) { - // unlikely - throw new SSLHandshakeException( - "No expected master key derivation for protocol: " + - context.negotiatedProtocol.name); - } - SSLKeyDerivation kd = mskd.createKeyDerivation( - context, preMasterSecret); - return kd.deriveKey("MasterSecret", params); - } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); - } - } - - private SecretKey t13DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - try { - KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - SecretKey sharedSecret = - ka.generateSecret("TlsPremasterSecret"); - - HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; - SSLKeyDerivation kd = context.handshakeKeyDerivation; - HKDF hkdf = new HKDF(hashAlg.name); - if (kd == null) { // No PSK is in use. - // If PSK is not in use Early Secret will still be - // HKDF-Extract(0, 0). - byte[] zeros = new byte[hashAlg.hashLength]; - SecretKeySpec ikm = - new SecretKeySpec(zeros, "TlsPreSharedSecret"); - SecretKey earlySecret = - hkdf.extract(zeros, ikm, "TlsEarlySecret"); - kd = new SSLSecretDerivation(context, earlySecret); - } - - // derive salt secret - SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); - - // derive handshake secret - return hkdf.extract(saltSecret, sharedSecret, algorithm); - } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); - } - } + return new KAKeyDerivation("DiffieHellman", context, + dhePossession.privateKey, dheCredentials.popPublicKey); } } } --- old/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java 2018-08-30 11:09:04.077608001 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/ECDHKeyExchange.java 2018-08-30 11:09:03.201608001 -0400 @@ -63,7 +63,7 @@ static final SSLKeyAgreementGenerator ecdhKAGenerator = new ECDHKAGenerator(); - static final class ECDHECredentials implements SSLCredentials { + static final class ECDHECredentials implements SSLKeyAgreementCredentials { final ECPublicKey popPublicKey; final NamedGroup namedGroup; @@ -72,6 +72,11 @@ this.namedGroup = namedGroup; } + @Override + public PublicKey getPublicKey() { + return popPublicKey; + } + static ECDHECredentials valueOf(NamedGroup namedGroup, byte[] encodedPoint) throws IOException, GeneralSecurityException { @@ -299,7 +304,7 @@ "No sufficient ECDHE key agreement parameters negotiated"); } - return new ECDHEKAKeyDerivation(shc, + return new KAKeyDerivation("ECDH", shc, x509Possession.popPrivateKey, ecdheCredentials.popPublicKey); } @@ -348,7 +353,7 @@ "No sufficient ECDH key agreement parameters negotiated"); } - return new ECDHEKAKeyDerivation(chc, + return new KAKeyDerivation("ECDH", chc, ecdhePossession.privateKey, x509Credentials.popPublicKey); } } @@ -392,94 +397,8 @@ "No sufficient ECDHE key agreement parameters negotiated"); } - return new ECDHEKAKeyDerivation(context, + return new KAKeyDerivation("ECDH", context, ecdhePossession.privateKey, ecdheCredentials.popPublicKey); } } - - private static final - class ECDHEKAKeyDerivation implements SSLKeyDerivation { - private final HandshakeContext context; - private final PrivateKey localPrivateKey; - private final PublicKey peerPublicKey; - - ECDHEKAKeyDerivation(HandshakeContext context, - PrivateKey localPrivateKey, - PublicKey peerPublicKey) { - this.context = context; - this.localPrivateKey = localPrivateKey; - this.peerPublicKey = peerPublicKey; - } - - @Override - public SecretKey deriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - if (!context.negotiatedProtocol.useTLS13PlusSpec()) { - return t12DeriveKey(algorithm, params); - } else { - return t13DeriveKey(algorithm, params); - } - } - - private SecretKey t12DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - try { - KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - SecretKey preMasterSecret = - ka.generateSecret("TlsPremasterSecret"); - - SSLMasterKeyDerivation mskd = - SSLMasterKeyDerivation.valueOf( - context.negotiatedProtocol); - if (mskd == null) { - // unlikely - throw new SSLHandshakeException( - "No expected master key derivation for protocol: " + - context.negotiatedProtocol.name); - } - SSLKeyDerivation kd = mskd.createKeyDerivation( - context, preMasterSecret); - return kd.deriveKey("MasterSecret", params); - } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); - } - } - - private SecretKey t13DeriveKey(String algorithm, - AlgorithmParameterSpec params) throws IOException { - try { - KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); - ka.init(localPrivateKey); - ka.doPhase(peerPublicKey, true); - SecretKey sharedSecret = - ka.generateSecret("TlsPremasterSecret"); - - HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; - SSLKeyDerivation kd = context.handshakeKeyDerivation; - HKDF hkdf = new HKDF(hashAlg.name); - if (kd == null) { // No PSK is in use. - // If PSK is not in use Early Secret will still be - // HKDF-Extract(0, 0). - byte[] zeros = new byte[hashAlg.hashLength]; - SecretKeySpec ikm = - new SecretKeySpec(zeros, "TlsPreSharedSecret"); - SecretKey earlySecret = - hkdf.extract(zeros, ikm, "TlsEarlySecret"); - kd = new SSLSecretDerivation(context, earlySecret); - } - - // derive salt secret - SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); - - // derive handshake secret - return hkdf.extract(saltSecret, sharedSecret, algorithm); - } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(gse); - } - } - } } --- old/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java 2018-08-30 11:09:06.813608001 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/KeyShareExtension.java 2018-08-30 11:09:06.061608001 -0400 @@ -42,12 +42,14 @@ import sun.security.ssl.DHKeyExchange.DHEPossession; import sun.security.ssl.ECDHKeyExchange.ECDHECredentials; import sun.security.ssl.ECDHKeyExchange.ECDHEPossession; +import sun.security.ssl.XDHKeyExchange.XDHEPossession; +import sun.security.ssl.XDHKeyExchange.XDHECredentials; import sun.security.ssl.KeyShareExtension.CHKeyShareSpec; import sun.security.ssl.SSLExtension.ExtensionConsumer; import sun.security.ssl.SSLExtension.SSLExtensionSpec; import sun.security.ssl.SSLHandshake.HandshakeMessage; import sun.security.ssl.SupportedGroupsExtension.NamedGroup; -import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; +import sun.security.ssl.SupportedGroupsExtension.NamedGroupFunctions; import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; import sun.security.util.HexDumpEncoder; @@ -265,7 +267,8 @@ // update the context chc.handshakePossessions.add(pos); if (!(pos instanceof ECDHEPossession) && - !(pos instanceof DHEPossession)) { + !(pos instanceof DHEPossession) && + !(pos instanceof XDHEPossession)) { // May need more possesion types in the future. continue; } @@ -354,46 +357,26 @@ continue; } - if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) { - try { - ECDHECredentials ecdhec = - ECDHECredentials.valueOf(ng, entry.keyExchange); - if (ecdhec != null) { - if (!shc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - ecdhec.popPublicKey)) { - SSLLogger.warning( - "ECDHE key share entry does not " + - "comply to algorithm constraints"); - } else { - credentials.add(ecdhec); - } + try { + NamedGroupFunctions ngf = ng.getFunctions().orElseThrow( + GeneralSecurityException::new); + SSLKeyAgreementCredentials kaCred = + ngf.decodeCredentials(entry.keyExchange); + if (kaCred != null) { + if (!shc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + kaCred.getPublicKey())) { + SSLLogger.warning( + "key share entry does not " + + "comply with algorithm constraints"); + } else { + credentials.add(kaCred); } - } catch (IOException | GeneralSecurityException ex) { - SSLLogger.warning( - "Cannot decode named group: " + - NamedGroup.nameOf(entry.namedGroupId)); - } - } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) { - try { - DHECredentials dhec = - DHECredentials.valueOf(ng, entry.keyExchange); - if (dhec != null) { - if (!shc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - dhec.popPublicKey)) { - SSLLogger.warning( - "DHE key share entry does not " + - "comply to algorithm constraints"); - } else { - credentials.add(dhec); - } - } - } catch (IOException | GeneralSecurityException ex) { - SSLLogger.warning( - "Cannot decode named group: " + - NamedGroup.nameOf(entry.namedGroupId)); } + } catch (GeneralSecurityException ex) { + SSLLogger.warning( + "Cannot decode named group: " + + NamedGroup.nameOf(entry.namedGroupId)); } } @@ -531,6 +514,8 @@ ng = ((ECDHECredentials)cd).namedGroup; } else if (cd instanceof DHECredentials) { ng = ((DHECredentials)cd).namedGroup; + } else if (cd instanceof XDHECredentials) { + ng = ((XDHECredentials)cd).namedGroup; } if (ng == null) { @@ -549,7 +534,8 @@ SSLPossession[] poses = ke.createPossessions(shc); for (SSLPossession pos : poses) { if (!(pos instanceof ECDHEPossession) && - !(pos instanceof DHEPossession)) { + !(pos instanceof DHEPossession) && + !(pos instanceof XDHEPossession)) { // May need more possesion types in the future. continue; } @@ -649,50 +635,26 @@ } SSLCredentials credentials = null; - if (ng.type == NamedGroupType.NAMED_GROUP_ECDHE) { - try { - ECDHECredentials ecdhec = - ECDHECredentials.valueOf(ng, keyShare.keyExchange); - if (ecdhec != null) { - if (!chc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - ecdhec.popPublicKey)) { - chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, - "ECDHE key share entry does not " + - "comply to algorithm constraints"); - } else { - credentials = ecdhec; - } - } - } catch (IOException | GeneralSecurityException ex) { - chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, - "Cannot decode named group: " + - NamedGroup.nameOf(keyShare.namedGroupId)); - } - } else if (ng.type == NamedGroupType.NAMED_GROUP_FFDHE) { - try { - DHECredentials dhec = - DHECredentials.valueOf(ng, keyShare.keyExchange); - if (dhec != null) { - if (!chc.algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - dhec.popPublicKey)) { - chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, - "DHE key share entry does not " + - "comply to algorithm constraints"); - } else { - credentials = dhec; - } + try { + NamedGroupFunctions ngf = ng.getFunctions().orElseThrow( + GeneralSecurityException::new); + SSLKeyAgreementCredentials kaCred = + ngf.decodeCredentials(keyShare.keyExchange); + if (kaCred != null) { + if (!chc.algorithmConstraints.permits( + EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), + kaCred.getPublicKey())) { + chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, + "key share entry does not " + + "comply to algorithm constraints"); + } else { + credentials = kaCred; } - } catch (IOException | GeneralSecurityException ex) { - chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, - "Cannot decode named group: " + - NamedGroup.nameOf(keyShare.namedGroupId)); } - } else { + } catch (IOException | GeneralSecurityException ex) { chc.conContext.fatal(Alert.UNEXPECTED_MESSAGE, - "Unsupported named group: " + - NamedGroup.nameOf(keyShare.namedGroupId)); + "Cannot decode named group: " + + NamedGroup.nameOf(keyShare.namedGroupId)); } if (credentials == null) { --- old/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java 2018-08-30 11:09:12.413608001 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/SSLKeyExchange.java 2018-08-30 11:09:11.513608001 -0400 @@ -30,10 +30,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; -import sun.security.ssl.DHKeyExchange.DHEPossession; -import sun.security.ssl.ECDHKeyExchange.ECDHEPossession; +import java.util.Optional; import sun.security.ssl.SupportedGroupsExtension.NamedGroup; -import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; +import sun.security.ssl.SupportedGroupsExtension.NamedGroupFunctions; import sun.security.ssl.SupportedGroupsExtension.SupportedGroups; import sun.security.ssl.X509Authentication.X509Possession; @@ -570,27 +569,24 @@ @Override public SSLPossession createPossession(HandshakeContext hc) { - if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { - return new ECDHEPossession( - namedGroup, hc.sslContext.getSecureRandom()); - } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) { - return new DHEPossession( - namedGroup, hc.sslContext.getSecureRandom()); - } - return null; + Optional ngf = namedGroup.getFunctions(); + if (ngf.isEmpty()) { + return null; + } + return ngf.get().createPossession(hc.sslContext.getSecureRandom()); } @Override public SSLKeyDerivation createKeyDerivation( HandshakeContext hc) throws IOException { - if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { - return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc); - } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) { - return DHKeyExchange.kaGenerator.createKeyDerivation(hc); + + Optional ngf = namedGroup.getFunctions(); + if (ngf.isEmpty()) { + return null; } + return ngf.get().createKeyDerivation(hc); - return null; } } } --- old/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java 2018-08-30 11:09:14.929608001 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/SupportedGroupsExtension.java 2018-08-30 11:09:14.213608001 -0400 @@ -31,20 +31,24 @@ import java.security.AlgorithmConstraints; import java.security.AlgorithmParameters; import java.security.CryptoPrimitive; +import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; import java.security.spec.InvalidParameterSpecException; +import java.security.spec.NamedParameterSpec; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import java.util.EnumSet; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import javax.crypto.spec.DHParameterSpec; import javax.net.ssl.SSLProtocolException; import sun.security.action.GetPropertyAction; @@ -158,7 +162,7 @@ } } - static enum NamedGroupType { + enum NamedGroupType { NAMED_GROUP_ECDHE, // Elliptic Curve Groups (ECDHE) NAMED_GROUP_FFDHE, // Finite Field Groups (DHE) NAMED_GROUP_XDH, // Finite Field Groups (XDH) @@ -176,6 +180,264 @@ } } + public static abstract class NamedGroupFunctions { + + // cache to speed up the parameters construction + protected static final Map + namedGroupParams = new ConcurrentHashMap<>(); + + private final NamedGroup ng; + + protected NamedGroupFunctions(NamedGroup ng) { + this.ng = ng; + } + + public AlgorithmParameters getParameters() { + + AlgorithmParameters result = namedGroupParams.get(ng); + if (result == null) { + Optional paramsOpt = getParametersImpl(); + if (paramsOpt.isPresent()) { + result = paramsOpt.get(); + namedGroupParams.put(ng, result); + } + } + + return result; + } + + public NamedGroup getNamedGroup() { + return ng; + } + + public abstract + SSLKeyAgreementCredentials decodeCredentials(byte[] encoded) + throws IOException, GeneralSecurityException; + + public abstract SSLPossession createPossession(SecureRandom random); + + public abstract + SSLKeyDerivation createKeyDerivation(HandshakeContext hc) + throws IOException; + + protected abstract Optional getParametersImpl(); + public abstract AlgorithmParameterSpec getParameterSpec(); + + public abstract boolean isAvailable(); + } + + private static class FFDHFunctions extends NamedGroupFunctions { + + + FFDHFunctions(NamedGroup ng) { + super(ng); + } + + @Override + public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded) + throws IOException, GeneralSecurityException { + return DHKeyExchange.DHECredentials.valueOf(getNamedGroup(), + encoded); + } + + @Override + public SSLPossession createPossession(SecureRandom random) { + return new DHKeyExchange.DHEPossession(getNamedGroup(), random); + } + + @Override + public SSLKeyDerivation createKeyDerivation(HandshakeContext hc) + throws IOException { + return DHKeyExchange.kaGenerator.createKeyDerivation(hc); + } + + @Override + public AlgorithmParameterSpec getParameterSpec() { + return getDHParameterSpec(); + } + + DHParameterSpec getDHParameterSpec() { + + AlgorithmParameters params = getParameters(); + try { + return params.getParameterSpec(DHParameterSpec.class); + } catch (InvalidParameterSpecException ipse) { + // should be unlikely + return getPredefinedDHParameterSpec(getNamedGroup()); + } + } + + private static DHParameterSpec getFFDHEDHParameterSpec( + NamedGroup namedGroup) { + + DHParameterSpec spec = null; + switch (namedGroup) { + case FFDHE_2048: + spec = PredefinedDHParameterSpecs.ffdheParams.get(2048); + break; + case FFDHE_3072: + spec = PredefinedDHParameterSpecs.ffdheParams.get(3072); + break; + case FFDHE_4096: + spec = PredefinedDHParameterSpecs.ffdheParams.get(4096); + break; + case FFDHE_6144: + spec = PredefinedDHParameterSpecs.ffdheParams.get(6144); + break; + case FFDHE_8192: + spec = PredefinedDHParameterSpecs.ffdheParams.get(8192); + } + + return spec; + } + + private static DHParameterSpec getPredefinedDHParameterSpec( + NamedGroup namedGroup) { + + DHParameterSpec spec = null; + switch (namedGroup) { + case FFDHE_2048: + spec = PredefinedDHParameterSpecs.definedParams.get(2048); + break; + case FFDHE_3072: + spec = PredefinedDHParameterSpecs.definedParams.get(3072); + break; + case FFDHE_4096: + spec = PredefinedDHParameterSpecs.definedParams.get(4096); + break; + case FFDHE_6144: + spec = PredefinedDHParameterSpecs.definedParams.get(6144); + break; + case FFDHE_8192: + spec = PredefinedDHParameterSpecs.definedParams.get(8192); + } + + return spec; + } + + @Override + public boolean isAvailable() { + + AlgorithmParameters params = getParameters(); + return params != null; + } + + @Override + protected Optional getParametersImpl() { + try { + AlgorithmParameters params = + JsseJce.getAlgorithmParameters("DiffieHellman"); + AlgorithmParameterSpec spec = + getFFDHEDHParameterSpec(getNamedGroup()); + params.init(spec); + return Optional.of(params); + } catch (InvalidParameterSpecException | + NoSuchAlgorithmException ex) { + return Optional.empty(); + } + } + + } + + private static class ECDHFunctions extends NamedGroupFunctions { + + ECDHFunctions(NamedGroup ng) { + super(ng); + } + + @Override + public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded) + throws IOException, GeneralSecurityException { + return ECDHKeyExchange.ECDHECredentials.valueOf(getNamedGroup(), + encoded); + } + + @Override + public SSLPossession createPossession(SecureRandom random) { + return new ECDHKeyExchange.ECDHEPossession(getNamedGroup(), + random); + } + + @Override + public SSLKeyDerivation createKeyDerivation(HandshakeContext hc) + throws IOException { + return ECDHKeyExchange.ecdheKAGenerator.createKeyDerivation(hc); + } + + @Override + public AlgorithmParameterSpec getParameterSpec() { + return SupportedGroups.getECGenParamSpec(getNamedGroup()); + } + + @Override + public boolean isAvailable() { + + AlgorithmParameters params = getParameters(); + return params != null; + } + + @Override + protected Optional getParametersImpl() { + try { + AlgorithmParameters params = + JsseJce.getAlgorithmParameters("EC"); + AlgorithmParameterSpec spec = + new ECGenParameterSpec(getNamedGroup().oid); + params.init(spec); + return Optional.of(params); + } catch (InvalidParameterSpecException | + NoSuchAlgorithmException ex) { + return Optional.empty(); + } + } + } + + private static class XDHFunctions extends NamedGroupFunctions { + + XDHFunctions(NamedGroup ng) { + super(ng); + } + + @Override + public SSLKeyAgreementCredentials decodeCredentials(byte[] encoded) + throws IOException, GeneralSecurityException { + return XDHKeyExchange.XDHECredentials.valueOf(getNamedGroup(), + encoded); + } + + @Override + public SSLPossession createPossession(SecureRandom random) { + return new XDHKeyExchange.XDHEPossession(getNamedGroup(), random); + } + + @Override + public SSLKeyDerivation createKeyDerivation(HandshakeContext hc) + throws IOException { + return XDHKeyExchange.xdheKAGenerator.createKeyDerivation(hc); + } + + @Override + public AlgorithmParameterSpec getParameterSpec() { + return new NamedParameterSpec(getNamedGroup().algorithm); + } + + @Override + public boolean isAvailable() { + + try { + JsseJce.getKeyAgreement(getNamedGroup().algorithm); + return true; + } catch (NoSuchAlgorithmException ex) { + return false; + } + } + + @Override + protected Optional getParametersImpl() { + return Optional.empty(); + } + } + static enum NamedGroup { // Elliptic Curves (RFC 4492) // @@ -292,12 +554,14 @@ final String algorithm; // signature algorithm final boolean isFips; // can be used in FIPS mode? final ProtocolVersion[] supportedProtocols; + private final NamedGroupFunctions functions; // may be null // Constructor used for Elliptic Curve Groups (ECDHE) private NamedGroup(int id, String name, String oid, boolean isFips, ProtocolVersion[] supportedProtocols) { this.id = id; this.type = NamedGroupType.NAMED_GROUP_ECDHE; + this.functions = new ECDHFunctions(this); this.name = name; this.oid = oid; this.algorithm = "EC"; @@ -311,6 +575,7 @@ ProtocolVersion[] supportedProtocols) { this.id = id; this.type = NamedGroupType.NAMED_GROUP_XDH; + this.functions = new XDHFunctions(this); this.name = name; this.oid = null; this.algorithm = algorithm; @@ -323,6 +588,7 @@ ProtocolVersion[] supportedProtocols) { this.id = id; this.type = NamedGroupType.NAMED_GROUP_FFDHE; + this.functions = new FFDHFunctions(this); this.name = name; this.oid = null; this.algorithm = "DiffieHellman"; @@ -335,6 +601,7 @@ ProtocolVersion[] supportedProtocols) { this.id = id; this.type = NamedGroupType.NAMED_GROUP_ARBITRARY; + this.functions = null; this.name = name; this.oid = null; this.algorithm = "EC"; @@ -342,6 +609,10 @@ this.supportedProtocols = supportedProtocols; } + Optional getFunctions() { + return Optional.ofNullable(functions); + } + static NamedGroup valueOf(int id) { for (NamedGroup group : NamedGroup.values()) { if (group.id == id) { @@ -367,15 +638,14 @@ } static NamedGroup valueOf(DHParameterSpec params) { - for (Map.Entry me : - SupportedGroups.namedGroupParams.entrySet()) { - NamedGroup ng = me.getKey(); + for (NamedGroup ng : NamedGroup.values()) { if (ng.type != NamedGroupType.NAMED_GROUP_FFDHE) { continue; } DHParameterSpec ngParams = null; - AlgorithmParameters aps = me.getValue(); + // functions is non-null for FFDHE type + AlgorithmParameters aps = ng.functions.getParameters(); try { ngParams = aps.getParameterSpec(DHParameterSpec.class); } catch (InvalidParameterSpecException ipse) { @@ -446,17 +716,18 @@ // lazy loading of parameters AlgorithmParameters getParameters() { - return SupportedGroups.namedGroupParams.get(this); + if (functions == null) { + return null; + } + return functions.getParameters(); } AlgorithmParameterSpec getParameterSpec() { - if (this.type == NamedGroupType.NAMED_GROUP_ECDHE) { - return SupportedGroups.getECGenParamSpec(this); - } else if (this.type == NamedGroupType.NAMED_GROUP_FFDHE) { - return SupportedGroups.getDHParameterSpec(this); + Optional ngf = getFunctions(); + if (ngf.isEmpty()) { + return null; } - - return null; + return ngf.get().getParameterSpec(); } } @@ -465,10 +736,6 @@ static final boolean enableFFDHE = Utilities.getBooleanProperty("jsse.enableFFDHE", true); - // cache to speed up the parameters construction - static final Map namedGroupParams = new HashMap<>(); - // the supported named groups static final NamedGroup[] supportedNamedGroups; @@ -552,6 +819,10 @@ // non-NIST curves NamedGroup.SECP256_K1, + // XDH + NamedGroup.X25519, + NamedGroup.X448, + // FFDHE 2048 NamedGroup.FFDHE_2048, NamedGroup.FFDHE_3072, @@ -583,86 +854,13 @@ // check whether the group is supported by the underlying providers private static boolean isAvailableGroup(NamedGroup namedGroup) { - AlgorithmParameters params = null; - AlgorithmParameterSpec spec = null; - if (namedGroup.type == NamedGroupType.NAMED_GROUP_ECDHE) { - if (namedGroup.oid != null) { - try { - params = JsseJce.getAlgorithmParameters("EC"); - spec = new ECGenParameterSpec(namedGroup.oid); - } catch (NoSuchAlgorithmException e) { - return false; - } - } - } else if (namedGroup.type == NamedGroupType.NAMED_GROUP_FFDHE) { - try { - params = JsseJce.getAlgorithmParameters("DiffieHellman"); - spec = getFFDHEDHParameterSpec(namedGroup); - } catch (NoSuchAlgorithmException e) { - return false; - } - } // Otherwise, unsupported. - - if ((params != null) && (spec != null)) { - try { - params.init(spec); - } catch (InvalidParameterSpecException e) { - return false; - } - // cache the parameters - namedGroupParams.put(namedGroup, params); - - return true; - } - - return false; - } - - private static DHParameterSpec getFFDHEDHParameterSpec( - NamedGroup namedGroup) { - DHParameterSpec spec = null; - switch (namedGroup) { - case FFDHE_2048: - spec = PredefinedDHParameterSpecs.ffdheParams.get(2048); - break; - case FFDHE_3072: - spec = PredefinedDHParameterSpecs.ffdheParams.get(3072); - break; - case FFDHE_4096: - spec = PredefinedDHParameterSpecs.ffdheParams.get(4096); - break; - case FFDHE_6144: - spec = PredefinedDHParameterSpecs.ffdheParams.get(6144); - break; - case FFDHE_8192: - spec = PredefinedDHParameterSpecs.ffdheParams.get(8192); - } - - return spec; - } - - private static DHParameterSpec getPredefinedDHParameterSpec( - NamedGroup namedGroup) { - DHParameterSpec spec = null; - switch (namedGroup) { - case FFDHE_2048: - spec = PredefinedDHParameterSpecs.definedParams.get(2048); - break; - case FFDHE_3072: - spec = PredefinedDHParameterSpecs.definedParams.get(3072); - break; - case FFDHE_4096: - spec = PredefinedDHParameterSpecs.definedParams.get(4096); - break; - case FFDHE_6144: - spec = PredefinedDHParameterSpecs.definedParams.get(6144); - break; - case FFDHE_8192: - spec = PredefinedDHParameterSpecs.definedParams.get(8192); + Optional ngfOpt = namedGroup.getFunctions(); + if (ngfOpt.isEmpty()) { + return false; } - - return spec; + NamedGroupFunctions ngf = ngfOpt.get(); + return ngf.isAvailable(); } static ECGenParameterSpec getECGenParamSpec(NamedGroup namedGroup) { @@ -671,7 +869,8 @@ "Not a named EC group: " + namedGroup); } - AlgorithmParameters params = namedGroupParams.get(namedGroup); + // functions is non-null for ECDHE type + AlgorithmParameters params = namedGroup.functions.getParameters(); try { return params.getParameterSpec(ECGenParameterSpec.class); } catch (InvalidParameterSpecException ipse) { @@ -680,19 +879,12 @@ } } - static DHParameterSpec getDHParameterSpec(NamedGroup namedGroup) { - if (namedGroup.type != NamedGroupType.NAMED_GROUP_FFDHE) { - throw new RuntimeException( - "Not a named DH group: " + namedGroup); - } - - AlgorithmParameters params = namedGroupParams.get(namedGroup); - try { - return params.getParameterSpec(DHParameterSpec.class); - } catch (InvalidParameterSpecException ipse) { - // should be unlikely - return getPredefinedDHParameterSpec(namedGroup); + static AlgorithmParameters getParameters(NamedGroup ng) { + AlgorithmParameters params = null; + if (ng.functions != null) { + params = ng.functions.getParameters(); } + return params; } // Is there any supported group permitted by the constraints? @@ -705,7 +897,7 @@ if (constraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), namedGroup.algorithm, - namedGroupParams.get(namedGroup))) { + getParameters(namedGroup))) { return true; } @@ -736,7 +928,7 @@ return constraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), namedGroup.algorithm, - namedGroupParams.get(namedGroup)); + getParameters(namedGroup)); } // Is there any supported group permitted by the constraints? @@ -760,7 +952,7 @@ constraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), namedGroup.algorithm, - namedGroupParams.get(namedGroup))) { + getParameters(namedGroup))) { return namedGroup; } } @@ -777,7 +969,7 @@ constraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), namedGroup.algorithm, - namedGroupParams.get(namedGroup))) { + getParameters(namedGroup))) { return namedGroup; } } @@ -825,7 +1017,7 @@ ng.isSupported(chc.activeCipherSuites) && chc.algorithmConstraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - ng.algorithm, namedGroupParams.get(ng))) { + ng.algorithm, getParameters(ng))) { namedGroups.add(ng); } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( @@ -953,7 +1145,7 @@ ng.isSupported(shc.activeCipherSuites) && shc.algorithmConstraints.permits( EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - ng.algorithm, namedGroupParams.get(ng))) { + ng.algorithm, getParameters(ng))) { namedGroups.add(ng); } else if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( --- old/src/java.base/share/classes/sun/security/util/ArrayUtil.java 2018-08-30 11:09:20.129608001 -0400 +++ new/src/java.base/share/classes/sun/security/util/ArrayUtil.java 2018-08-30 11:09:19.413608001 -0400 @@ -32,7 +32,7 @@ /** - * This class holds the various utility methods for array range checks. + * This class holds the various utility methods for arrays. */ public final class ArrayUtil { @@ -52,4 +52,22 @@ // NPE is thrown when array is null Preconditions.checkFromIndexSize(offset, len, array.length, AIOOBE_SUPPLIER); } + + + private static void swap(byte[] arr, int i, int j) { + byte tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + } + + public static void reverse(byte [] arr) { + int i = 0; + int j = arr.length - 1; + + while (i < j) { + swap(arr, i, j); + i++; + j--; + } + } } --- old/src/java.base/share/classes/sun/security/util/ECUtil.java 2018-08-30 11:09:22.597608001 -0400 +++ new/src/java.base/share/classes/sun/security/util/ECUtil.java 2018-08-30 11:09:21.929608001 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -227,5 +227,49 @@ return nameSpec.getName(); } + public static BigInteger decodeXecPublicKey(byte[] key, + XECParameters params) { + + ArrayUtil.reverse(key); + + // clear the extra bits + int bitsMod8 = params.getBits() % 8; + if (bitsMod8 != 0) { + int mask = (1 << bitsMod8) - 1; + key[0] &= mask; + } + + return new BigInteger(1, key); + } + + public static + XECPublicKeySpec decodeXecPublicKey(byte[] key, + AlgorithmParameterSpec spec) + throws InvalidParameterSpecException { + + XECParameters params = XECParameters.get( + InvalidParameterSpecException::new, spec); + BigInteger u = decodeXecPublicKey(key, params); + return new XECPublicKeySpec(spec, u); + } + + public static byte[] encodeXecPublicKey(BigInteger u, + XECParameters params) { + + byte[] u_arr = u.toByteArray(); + ArrayUtil.reverse(u_arr); + // u_arr may be too large or too small, depending on the value of u + return Arrays.copyOf(u_arr, params.getBytes()); + } + + public static byte[] encodeXecPublicKey(BigInteger u, + AlgorithmParameterSpec spec) + throws InvalidParameterSpecException { + + XECParameters params = XECParameters.get( + InvalidParameterSpecException::new, spec); + return encodeXecPublicKey(u, params); + } + private ECUtil() {} } --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java 2018-08-30 11:09:24.985608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java 2018-08-30 11:09:24.081608001 -0400 @@ -38,8 +38,11 @@ import javax.crypto.KeyAgreementSpi; import javax.crypto.SecretKey; import javax.crypto.ShortBufferException; +import javax.crypto.spec.SecretKeySpec; import java.util.function.Function; +import sun.security.util.XECParameters; + public class XDHKeyAgreement extends KeyAgreementSpi { private byte[] privateKey; @@ -202,7 +205,14 @@ throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException { - throw new NoSuchAlgorithmException("Not supported"); + if (algorithm == null) { + throw new NoSuchAlgorithmException("Algorithm must not be null"); + } + if (!(algorithm.equals("TlsPremasterSecret"))) { + throw new NoSuchAlgorithmException + ("Only supported for algorithm TlsPremasterSecret"); + } + return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret"); } static class X25519 extends XDHKeyAgreement { --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java 2018-08-30 11:09:28.013608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyFactory.java 2018-08-30 11:09:27.069608001 -0400 @@ -44,6 +44,8 @@ import java.security.spec.XECPrivateKeySpec; import java.util.function.Function; +import sun.security.util.XECParameters; + public class XDHKeyFactory extends KeyFactorySpi { private XECParameters lockedParams = null; --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java 2018-08-30 11:09:31.581608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyPairGenerator.java 2018-08-30 11:09:30.701608001 -0400 @@ -37,6 +37,7 @@ import java.security.spec.NamedParameterSpec; import sun.security.jca.JCAUtil; +import sun.security.util.XECParameters; /** * Key pair generator for the XDH key agreement algorithm. --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java 2018-08-30 11:09:35.033608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPrivateKeyImpl.java 2018-08-30 11:09:34.341608001 -0400 @@ -28,11 +28,11 @@ import java.security.interfaces.XECPrivateKey; import java.util.Optional; import java.security.InvalidKeyException; -import java.security.PrivateKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; import sun.security.pkcs.PKCS8Key; +import sun.security.util.XECParameters; import sun.security.x509.AlgorithmId; public final class XDHPrivateKeyImpl extends PKCS8Key implements XECPrivateKey { --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java 2018-08-30 11:09:38.821608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHPublicKeyImpl.java 2018-08-30 11:09:38.017608001 -0400 @@ -28,13 +28,13 @@ import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.KeyRep; -import java.security.PublicKey; import java.security.interfaces.XECPublicKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; -import java.util.Arrays; import sun.security.util.BitArray; +import sun.security.util.ECUtil; +import sun.security.util.XECParameters; import sun.security.x509.AlgorithmId; import sun.security.x509.X509Key; @@ -52,11 +52,7 @@ this.algid = new AlgorithmId(params.getOid()); this.u = u.mod(params.getP()); - byte[] u_arr = this.u.toByteArray(); - reverse(u_arr); - // u_arr may be too large or too small, depending on the value of u - u_arr = Arrays.copyOf(u_arr, params.getBytes()); - + byte[] u_arr = ECUtil.encodeXecPublicKey(this.u, params); setKey(new BitArray(u_arr.length * 8, u_arr)); checkLength(params); @@ -70,16 +66,7 @@ this.paramSpec = new NamedParameterSpec(params.getName()); // construct the BigInteger representation byte[] u_arr = getKey().toByteArray(); - reverse(u_arr); - - // clear the extra bits - int bitsMod8 = params.getBits() % 8; - if (bitsMod8 != 0) { - int mask = (1 << bitsMod8) - 1; - u_arr[0] &= mask; - } - - this.u = new BigInteger(1, u_arr); + this.u = ECUtil.decodeXecPublicKey(u_arr, params); checkLength(params); } @@ -113,22 +100,5 @@ getFormat(), getEncoded()); } - - private static void swap(byte[] arr, int i, int j) { - byte tmp = arr[i]; - arr[i] = arr[j]; - arr[j] = tmp; - } - - private static void reverse(byte [] arr) { - int i = 0; - int j = arr.length - 1; - - while (i < j) { - swap(arr, i, j); - i++; - j--; - } - } } --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java 2018-08-30 11:09:41.913608001 -0400 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XECOperations.java 2018-08-30 11:09:41.181608001 -0400 @@ -32,6 +32,7 @@ import sun.security.util.math.SmallValue; import sun.security.util.math.intpoly.IntegerPolynomial25519; import sun.security.util.math.intpoly.IntegerPolynomial448; +import sun.security.util.XECParameters; import java.math.BigInteger; import java.security.ProviderException; --- old/test/jdk/sun/security/ec/xec/TestXECOps.java 2018-08-30 11:09:45.497608001 -0400 +++ new/test/jdk/sun/security/ec/xec/TestXECOps.java 2018-08-30 11:09:44.497608001 -0400 @@ -25,12 +25,13 @@ * @test * @bug 8171277 * @summary Test XEC curve operations - * @modules jdk.crypto.ec/sun.security.ec + * @modules java.base/sun.security.util jdk.crypto.ec/sun.security.ec * @library /test/lib * @build jdk.test.lib.Convert * @run main TestXECOps */ +import sun.security.util.*; import sun.security.ec.*; import java.util.*; import jdk.test.lib.Convert; --- old/test/jdk/sun/security/ec/xec/XECIterative.java 2018-08-30 11:09:49.409608001 -0400 +++ new/test/jdk/sun/security/ec/xec/XECIterative.java 2018-08-30 11:09:48.421608001 -0400 @@ -27,7 +27,7 @@ * @summary XEC curve operations iterative test vectors * @library /test/lib * @build jdk.test.lib.Convert - * @modules jdk.crypto.ec/sun.security.ec + * @modules java.base/sun.security.util jdk.crypto.ec/sun.security.ec * @run main XECIterative 0 10000 * @run main XECIterative 10000 20000 * @run main XECIterative 20000 30000 @@ -40,6 +40,7 @@ * @run main XECIterative 90000 100000 */ +import sun.security.util.*; import sun.security.ec.*; import java.io.*; --- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/KAKeyDerivation.java 2018-08-30 11:09:51.993608001 -0400 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.SSLHandshakeException; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.AlgorithmParameterSpec; + +public class KAKeyDerivation implements SSLKeyDerivation { + + private final String algorithmName; + private final HandshakeContext context; + private final PrivateKey localPrivateKey; + private final PublicKey peerPublicKey; + + KAKeyDerivation(String algorithmName, + HandshakeContext context, + PrivateKey localPrivateKey, + PublicKey peerPublicKey) { + this.algorithmName = algorithmName; + this.context = context; + this.localPrivateKey = localPrivateKey; + this.peerPublicKey = peerPublicKey; + } + + @Override + public + SecretKey deriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + if (!context.negotiatedProtocol.useTLS13PlusSpec()) { + return t12DeriveKey(algorithm, params); + } else { + return t13DeriveKey(algorithm, params); + } + } + + private + SecretKey t12DeriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + try { + KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + SecretKey preMasterSecret = + ka.generateSecret("TlsPremasterSecret"); + SSLMasterKeyDerivation mskd = + SSLMasterKeyDerivation.valueOf( + context.negotiatedProtocol); + if (mskd == null) { + // unlikely + throw new SSLHandshakeException( + "No expected master key derivation for protocol: " + + context.negotiatedProtocol.name); + } + SSLKeyDerivation kd = mskd.createKeyDerivation( + context, preMasterSecret); + return kd.deriveKey("MasterSecret", params); + } catch (GeneralSecurityException gse) { + throw (SSLHandshakeException) new SSLHandshakeException( + "Could not generate secret").initCause(gse); + } + } + + private + SecretKey t13DeriveKey(String algorithm, + AlgorithmParameterSpec params) throws IOException { + try { + KeyAgreement ka = JsseJce.getKeyAgreement(algorithmName); + ka.init(localPrivateKey); + ka.doPhase(peerPublicKey, true); + SecretKey sharedSecret = + ka.generateSecret("TlsPremasterSecret"); + + CipherSuite.HashAlg hashAlg = context.negotiatedCipherSuite.hashAlg; + SSLKeyDerivation kd = context.handshakeKeyDerivation; + HKDF hkdf = new HKDF(hashAlg.name); + if (kd == null) { // No PSK is in use. + // If PSK is not in use Early Secret will still be + // HKDF-Extract(0, 0). + byte[] zeros = new byte[hashAlg.hashLength]; + SecretKeySpec ikm = + new SecretKeySpec(zeros, "TlsPreSharedSecret"); + SecretKey earlySecret = + hkdf.extract(zeros, ikm, "TlsEarlySecret"); + kd = new SSLSecretDerivation(context, earlySecret); + } + + // derive salt secret + SecretKey saltSecret = kd.deriveKey("TlsSaltSecret", null); + + // derive handshake secret + return hkdf.extract(saltSecret, sharedSecret, algorithm); + } catch (GeneralSecurityException gse) { + throw (SSLHandshakeException) new SSLHandshakeException( + "Could not generate secret").initCause(gse); + } + } +} --- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/SSLKeyAgreementCredentials.java 2018-08-30 11:09:55.041608001 -0400 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.security.PublicKey; + +interface SSLKeyAgreementCredentials extends SSLCredentials { + + PublicKey getPublicKey(); +} --- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/src/java.base/share/classes/sun/security/ssl/XDHKeyExchange.java 2018-08-30 11:09:57.577608001 -0400 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.interfaces.XECPublicKey; +import java.security.spec.*; +import sun.security.ssl.SupportedGroupsExtension.NamedGroup; +import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; +import sun.security.util.ECUtil; + +final class XDHKeyExchange { + static final SSLKeyAgreementGenerator xdheKAGenerator = + new XDHEKAGenerator(); + + static final class XDHECredentials implements SSLKeyAgreementCredentials { + final XECPublicKey popPublicKey; + final NamedGroup namedGroup; + + XDHECredentials(XECPublicKey popPublicKey, NamedGroup namedGroup) { + this.popPublicKey = popPublicKey; + this.namedGroup = namedGroup; + } + + @Override + public PublicKey getPublicKey() { + return popPublicKey; + } + + static XDHECredentials valueOf(NamedGroup namedGroup, + byte[] encodedPoint) throws IOException, GeneralSecurityException { + + if (namedGroup.type != NamedGroupType.NAMED_GROUP_XDH) { + throw new RuntimeException( + "Credentials decoding: Not XDH named group"); + } + + if (encodedPoint == null || encodedPoint.length == 0) { + return null; + } + + NamedParameterSpec namedSpec = + new NamedParameterSpec(namedGroup.algorithm); + XECPublicKeySpec xecKeySpec = + ECUtil.decodeXecPublicKey(encodedPoint, namedSpec); + KeyFactory factory = JsseJce.getKeyFactory(namedGroup.algorithm); + + XECPublicKey publicKey = + (XECPublicKey) factory.generatePublic(xecKeySpec); + return new XDHECredentials(publicKey, namedGroup); + } + } + + static final class XDHEPossession implements SSLPossession { + final PrivateKey privateKey; + final XECPublicKey publicKey; + final NamedGroup namedGroup; + + XDHEPossession(NamedGroup namedGroup, SecureRandom random) { + try { + KeyPairGenerator kpg = + JsseJce.getKeyPairGenerator(namedGroup.algorithm); + AlgorithmParameterSpec params = namedGroup.getParameterSpec(); + kpg.initialize(params, random); + KeyPair kp = kpg.generateKeyPair(); + privateKey = kp.getPrivate(); + publicKey = (XECPublicKey) kp.getPublic(); + } catch (GeneralSecurityException e) { + throw new RuntimeException( + "Could not generate XDH keypair", e); + } + + this.namedGroup = namedGroup; + } + + @Override + public byte[] encode() { + try { + return ECUtil.encodeXecPublicKey(publicKey.getU(), + publicKey.getParams()); + } catch (InvalidParameterSpecException ex) { + throw new RuntimeException(ex); + } + } + } + + private static final + class XDHEKAGenerator implements SSLKeyAgreementGenerator { + // Prevent instantiation of this class. + private XDHEKAGenerator() { + // blank + } + + @Override + public SSLKeyDerivation createKeyDerivation( + HandshakeContext context) throws IOException { + XDHEPossession xdhePossession = null; + XDHECredentials xdheCredentials = null; + for (SSLPossession poss : context.handshakePossessions) { + if (!(poss instanceof XDHEPossession)) { + continue; + } + + NamedGroup ng = ((XDHEPossession) poss).namedGroup; + for (SSLCredentials cred : context.handshakeCredentials) { + if (!(cred instanceof XDHECredentials)) { + continue; + } + if (ng.equals(((XDHECredentials) cred).namedGroup)) { + xdheCredentials = (XDHECredentials) cred; + break; + } + } + + if (xdheCredentials != null) { + xdhePossession = (XDHEPossession) poss; + break; + } + } + + if (xdhePossession == null || xdheCredentials == null) { + context.conContext.fatal(Alert.HANDSHAKE_FAILURE, + "No sufficient XDHE key agreement parameters negotiated"); + } + + return new KAKeyDerivation("XDH", context, + xdhePossession.privateKey, xdheCredentials.popPublicKey); + } + } + +} --- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/src/java.base/share/classes/sun/security/util/XECParameters.java 2018-08-30 11:10:00.457608001 -0400 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.util; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.NamedParameterSpec; +import java.util.Collections; +import java.util.Map; +import java.util.HashMap; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +import sun.security.util.ObjectIdentifier; +import sun.security.x509.AlgorithmId; + +public class XECParameters { + + // Naming/identification parameters + private final ObjectIdentifier oid; + private final String name; + + // Curve/field parameters + private final int bits; + private final BigInteger p; + private final int logCofactor; + private final int a24; + private final byte basePoint; + + /** + * + * Construct an object holding the supplied parameters. No parameters are + * checked, so this method always succeeds. This method supports + * Montgomery curves of the form y^2 = x^3 + ax^2 + x. + * + * @param bits The number of relevant bits in a public/private key. + * @param p The prime that defines the finite field. + * @param a24 The value of (a - 2) / 4, where a is the second-degree curve + * coefficient. + * @param basePoint The point that generates the desired group + * @param logCofactor The base-2 logarithm of the cofactor of the curve + * @param oid + * @param name + */ + public XECParameters(int bits, BigInteger p, int a24, + byte basePoint, int logCofactor, + ObjectIdentifier oid, String name) { + + this.bits = bits; + this.logCofactor = logCofactor; + this.p = p; + this.a24 = a24; + this.basePoint = basePoint; + this.oid = oid; + this.name = name; + + } + + public int getBits() { + return bits; + } + public int getBytes() { + return (bits + 7) / 8; + } + public int getLogCofactor() { + return logCofactor; + } + public BigInteger getP() { + return p; + } + public int getA24() { + return a24; + } + public byte getBasePoint() { + return basePoint; + } + public ObjectIdentifier getOid() { + return oid; + } + public String getName() { + return name; + } + + private static final Map SIZE_MAP; + private static final Map OID_MAP; + private static final Map NAME_MAP; + + static { + final BigInteger TWO = BigInteger.valueOf(2); + + Map bySize = new HashMap<>(); + Map byOid = new HashMap<>(); + Map byName = new HashMap<>(); + + // set up X25519 + try { + BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19)); + addParameters(255, p, 121665, (byte) 0x09, 3, + new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(), + bySize, byOid, byName); + + } catch (IOException ex) { + // Unable to set X25519 parameters---it will be disabled + } + + // set up X448 + try { + BigInteger p = TWO.pow(448).subtract(TWO.pow(224)) + .subtract(BigInteger.ONE); + addParameters(448, p, 39081, (byte) 0x05, 2, + new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(), + bySize, byOid, byName); + + } catch (IOException ex) { + // Unable to set X448 parameters---it will be disabled + } + + SIZE_MAP = Collections.unmodifiableMap(bySize); + OID_MAP = Collections.unmodifiableMap(byOid); + NAME_MAP = Collections.unmodifiableMap(byName); + } + + private static void addParameters(int bits, BigInteger p, int a24, + byte basePoint, int logCofactor, int[] oidBytes, String name, + Map bySize, + Map byOid, + Map byName) throws IOException { + + ObjectIdentifier oid = new ObjectIdentifier(oidBytes); + XECParameters params = + new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name); + bySize.put(bits, params); + byOid.put(oid, params); + byName.put(name.toLowerCase(), params); + } + + public static Optional getByOid(ObjectIdentifier id) { + return Optional.ofNullable(OID_MAP.get(id)); + } + public static Optional getBySize(int size) { + return Optional.ofNullable(SIZE_MAP.get(size)); + } + public static Optional getByName(String name) { + return Optional.ofNullable(NAME_MAP.get(name.toLowerCase())); + } + + public boolean oidEquals(XECParameters other) { + return oid.equals(other.getOid()); + } + + // Utility method that is used by the methods below to handle exception + // suppliers + private static + Supplier apply(final Function func, final A a) { + return new Supplier() { + @Override + public B get() { + return func.apply(a); + } + }; + } + + /** + * Get parameters by key size, or throw an exception if no parameters are + * defined for the specified key size. This method is used in several + * contexts that should throw different exceptions when the parameters + * are not found. The first argument is a function that produces the + * desired exception. + * + * @param exception a function that produces an exception from a string + * @param size the desired key size + * @param the type of exception that is thrown + * @return the parameters for the specified key size + * @throws T when suitable parameters do not exist + */ + public static + + XECParameters getBySize(Function exception, + int size) throws T { + + Optional xecParams = getBySize(size); + return xecParams.orElseThrow( + apply(exception, "Unsupported size: " + size)); + } + + /** + * Get parameters by algorithm ID, or throw an exception if no + * parameters are defined for the specified ID. This method is used in + * several contexts that should throw different exceptions when the + * parameters are not found. The first argument is a function that produces + * the desired exception. + * + * @param exception a function that produces an exception from a string + * @param algId the algorithm ID + * @param the type of exception that is thrown + * @return the parameters for the specified algorithm ID + * @throws T when suitable parameters do not exist + */ + public static + + XECParameters get(Function exception, + AlgorithmId algId) throws T { + + Optional xecParams = getByOid(algId.getOID()); + return xecParams.orElseThrow( + apply(exception, "Unsupported OID: " + algId.getOID())); + } + + /** + * Get parameters by algorithm parameter spec, or throw an exception if no + * parameters are defined for the spec. This method is used in + * several contexts that should throw different exceptions when the + * parameters are not found. The first argument is a function that produces + * the desired exception. + * + * @param exception a function that produces an exception from a string + * @param params the algorithm parameters spec + * @param the type of exception that is thrown + * @return the parameters for the spec + * @throws T when suitable parameters do not exist + */ + public static + + XECParameters get(Function exception, + AlgorithmParameterSpec params) throws T { + + if (params instanceof NamedParameterSpec) { + NamedParameterSpec namedParams = (NamedParameterSpec) params; + Optional xecParams = + getByName(namedParams.getName()); + return xecParams.orElseThrow( + apply(exception, "Unsupported name: " + namedParams.getName())); + } else { + throw exception.apply("Only NamedParameterSpec is supported."); + } + } +} + --- /dev/null 2018-08-17 14:52:30.860000000 -0400 +++ new/test/jdk/sun/security/ssl/CipherSuite/SupportedGroups.java 2018-08-30 11:10:03.189608001 -0400 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8171279 + * @library /javax/net/ssl/templates + * @summary Test TLS connection with each individual supported group + * @run main/othervm SupportedGroups secp256r1 + * @run main/othervm SupportedGroups secp384r1 + * @run main/othervm SupportedGroups secp521r1 + * @run main/othervm SupportedGroups x25519 + * @run main/othervm SupportedGroups x448 + * @run main/othervm SupportedGroups ffdhe2048 + * @run main/othervm SupportedGroups ffdhe3072 + * @run main/othervm SupportedGroups ffdhe4096 + * @run main/othervm SupportedGroups ffdhe6144 + * @run main/othervm SupportedGroups ffdhe8192 + */ + + +public class SupportedGroups extends SSLSocketTemplate { + /* + * Run the test case. + */ + public static void main(String[] args) throws Exception { + System.setProperty("jdk.tls.namedGroups", args[0]); + + (new SupportedGroups()).run(); + } +} --- old/src/jdk.crypto.ec/share/classes/sun/security/ec/XECParameters.java 2018-08-30 11:10:06.529608001 -0400 +++ /dev/null 2018-08-17 14:52:30.860000000 -0400 @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.ec; - -import java.io.IOException; -import java.math.BigInteger; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.NamedParameterSpec; -import java.util.Collections; -import java.util.Map; -import java.util.HashMap; -import java.util.Optional; -import java.util.function.Function; -import java.util.function.Supplier; - -import sun.security.util.ObjectIdentifier; -import sun.security.x509.AlgorithmId; - -public class XECParameters { - - // Naming/identification parameters - private final ObjectIdentifier oid; - private final String name; - - // Curve/field parameters - private final int bits; - private final BigInteger p; - private final int logCofactor; - private final int a24; - private final byte basePoint; - - /** - * - * Construct an object holding the supplied parameters. No parameters are - * checked, so this method always succeeds. This method supports - * Montgomery curves of the form y^2 = x^3 + ax^2 + x. - * - * @param bits The number of relevant bits in a public/private key. - * @param p The prime that defines the finite field. - * @param a24 The value of (a - 2) / 4, where a is the second-degree curve - * coefficient. - * @param basePoint The point that generates the desired group - * @param logCofactor The base-2 logarithm of the cofactor of the curve - * @param oid - * @param name - */ - public XECParameters(int bits, BigInteger p, int a24, - byte basePoint, int logCofactor, - ObjectIdentifier oid, String name) { - - this.bits = bits; - this.logCofactor = logCofactor; - this.p = p; - this.a24 = a24; - this.basePoint = basePoint; - this.oid = oid; - this.name = name; - - } - - public int getBits() { - return bits; - } - public int getBytes() { - return (bits + 7) / 8; - } - public int getLogCofactor() { - return logCofactor; - } - public BigInteger getP() { - return p; - } - public int getA24() { - return a24; - } - public byte getBasePoint() { - return basePoint; - } - public ObjectIdentifier getOid() { - return oid; - } - public String getName() { - return name; - } - - private static final Map SIZE_MAP; - private static final Map OID_MAP; - private static final Map NAME_MAP; - - static { - final BigInteger TWO = BigInteger.valueOf(2); - - Map bySize = new HashMap<>(); - Map byOid = new HashMap<>(); - Map byName = new HashMap<>(); - - // set up X25519 - try { - BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19)); - addParameters(255, p, 121665, (byte) 0x09, 3, - new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(), - bySize, byOid, byName); - - } catch (IOException ex) { - // Unable to set X25519 parameters---it will be disabled - } - - // set up X448 - try { - BigInteger p = TWO.pow(448).subtract(TWO.pow(224)) - .subtract(BigInteger.ONE); - addParameters(448, p, 39081, (byte) 0x05, 2, - new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(), - bySize, byOid, byName); - - } catch (IOException ex) { - // Unable to set X448 parameters---it will be disabled - } - - SIZE_MAP = Collections.unmodifiableMap(bySize); - OID_MAP = Collections.unmodifiableMap(byOid); - NAME_MAP = Collections.unmodifiableMap(byName); - } - - private static void addParameters(int bits, BigInteger p, int a24, - byte basePoint, int logCofactor, int[] oidBytes, String name, - Map bySize, - Map byOid, - Map byName) throws IOException { - - ObjectIdentifier oid = new ObjectIdentifier(oidBytes); - XECParameters params = - new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name); - bySize.put(bits, params); - byOid.put(oid, params); - byName.put(name, params); - } - - public static Optional getByOid(ObjectIdentifier id) { - return Optional.ofNullable(OID_MAP.get(id)); - } - public static Optional getBySize(int size) { - return Optional.ofNullable(SIZE_MAP.get(size)); - } - public static Optional getByName(String name) { - return Optional.ofNullable(NAME_MAP.get(name)); - } - - boolean oidEquals(XECParameters other) { - return oid.equals(other.getOid()); - } - - // Utility method that is used by the methods below to handle exception - // suppliers - private static - Supplier apply(final Function func, final A a) { - return new Supplier() { - @Override - public B get() { - return func.apply(a); - } - }; - } - - /** - * Get parameters by key size, or throw an exception if no parameters are - * defined for the specified key size. This method is used in several - * contexts that should throw different exceptions when the parameters - * are not found. The first argument is a function that produces the - * desired exception. - * - * @param exception a function that produces an exception from a string - * @param size the desired key size - * @param the type of exception that is thrown - * @return the parameters for the specified key size - * @throws T when suitable parameters do not exist - */ - public static - - XECParameters getBySize(Function exception, - int size) throws T { - - Optional xecParams = getBySize(size); - return xecParams.orElseThrow( - apply(exception, "Unsupported size: " + size)); - } - - /** - * Get parameters by algorithm ID, or throw an exception if no - * parameters are defined for the specified ID. This method is used in - * several contexts that should throw different exceptions when the - * parameters are not found. The first argument is a function that produces - * the desired exception. - * - * @param exception a function that produces an exception from a string - * @param algId the algorithm ID - * @param the type of exception that is thrown - * @return the parameters for the specified algorithm ID - * @throws T when suitable parameters do not exist - */ - public static - - XECParameters get(Function exception, - AlgorithmId algId) throws T { - - Optional xecParams = getByOid(algId.getOID()); - return xecParams.orElseThrow( - apply(exception, "Unsupported OID: " + algId.getOID())); - } - - /** - * Get parameters by algorithm parameter spec, or throw an exception if no - * parameters are defined for the spec. This method is used in - * several contexts that should throw different exceptions when the - * parameters are not found. The first argument is a function that produces - * the desired exception. - * - * @param exception a function that produces an exception from a string - * @param params the algorithm parameters spec - * @param the type of exception that is thrown - * @return the parameters for the spec - * @throws T when suitable parameters do not exist - */ - public static - - XECParameters get(Function exception, - AlgorithmParameterSpec params) throws T { - - if (params instanceof NamedParameterSpec) { - NamedParameterSpec namedParams = (NamedParameterSpec) params; - Optional xecParams = - getByName(namedParams.getName()); - return xecParams.orElseThrow( - apply(exception, "Unsupported name: " + namedParams.getName())); - } else { - throw exception.apply("Only NamedParameterSpec is supported."); - } - } -} -