--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuite.java Sat Jul 09 05:56:18 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -376,36 +376,38 @@
static enum KeyExchange {
// key exchange algorithms
- K_NULL ("NULL", false),
- K_RSA ("RSA", true),
- K_RSA_EXPORT ("RSA_EXPORT", true),
- K_DH_RSA ("DH_RSA", false),
- K_DH_DSS ("DH_DSS", false),
- K_DHE_DSS ("DHE_DSS", true),
- K_DHE_RSA ("DHE_RSA", true),
- K_DH_ANON ("DH_anon", true),
+ K_NULL ("NULL", false, false),
+ K_RSA ("RSA", true, false),
+ K_RSA_EXPORT ("RSA_EXPORT", true, false),
+ K_DH_RSA ("DH_RSA", false, false),
+ K_DH_DSS ("DH_DSS", false, false),
+ K_DHE_DSS ("DHE_DSS", true, false),
+ K_DHE_RSA ("DHE_RSA", true, false),
+ K_DH_ANON ("DH_anon", true, false),
- K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC),
- K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC),
- K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC),
- K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC),
- K_ECDH_ANON ("ECDH_anon", ALLOW_ECC),
+ K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC, true),
+ K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC, true),
+ K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, true),
+ K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC, true),
+ K_ECDH_ANON ("ECDH_anon", ALLOW_ECC, true),
// Kerberos cipher suites
- K_KRB5 ("KRB5", true),
- K_KRB5_EXPORT("KRB5_EXPORT", true),
+ K_KRB5 ("KRB5", true, false),
+ K_KRB5_EXPORT("KRB5_EXPORT", true, false),
// renegotiation protection request signaling cipher suite
- K_SCSV ("SCSV", true);
+ K_SCSV ("SCSV", true, false);
// name of the key exchange algorithm, e.g. DHE_DSS
final String name;
final boolean allowed;
+ final boolean isEC;
private final boolean alwaysAvailable;
- KeyExchange(String name, boolean allowed) {
+ KeyExchange(String name, boolean allowed, boolean isEC) {
this.name = name;
this.allowed = allowed;
+ this.isEC = isEC;
this.alwaysAvailable = allowed &&
(!name.startsWith("EC")) && (!name.startsWith("KRB"));
}
@@ -415,7 +417,7 @@
return true;
}
- if (name.startsWith("EC")) {
+ if (isEC) {
return (allowed && JsseJce.isEcAvailable());
} else if (name.startsWith("KRB")) {
return (allowed && JsseJce.isKerberosAvailable());
--- a/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/CipherSuiteList.java Sat Jul 09 05:56:18 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, 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
@@ -112,20 +112,15 @@
boolean containsEC() {
if (containsEC == null) {
for (CipherSuite c : cipherSuites) {
- switch (c.keyExchange) {
- case K_ECDH_ECDSA:
- case K_ECDH_RSA:
- case K_ECDHE_ECDSA:
- case K_ECDHE_RSA:
- case K_ECDH_ANON:
+ if (c.keyExchange.isEC) {
containsEC = true;
return true;
- default:
- break;
}
}
+
containsEC = false;
}
+
return containsEC;
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Sat Jul 09 05:56:18 2016 +0000
@@ -877,30 +877,33 @@
String typeName;
switch (certRequest.types[i]) {
- case CertificateRequest.cct_rsa_sign:
- typeName = "RSA";
- break;
+ case CertificateRequest.cct_rsa_sign:
+ typeName = "RSA";
+ break;
- case CertificateRequest.cct_dss_sign:
- typeName = "DSA";
- break;
+ case CertificateRequest.cct_dss_sign:
+ typeName = "DSA";
+ break;
+
+ case CertificateRequest.cct_ecdsa_sign:
+ // ignore if we do not have EC crypto available
+ typeName = JsseJce.isEcAvailable() ? "EC" : null;
+ break;
- case CertificateRequest.cct_ecdsa_sign:
- // ignore if we do not have EC crypto available
- typeName = JsseJce.isEcAvailable() ? "EC" : null;
- break;
-
- // Fixed DH/ECDH client authentication not supported
- case CertificateRequest.cct_rsa_fixed_dh:
- case CertificateRequest.cct_dss_fixed_dh:
- case CertificateRequest.cct_rsa_fixed_ecdh:
- case CertificateRequest.cct_ecdsa_fixed_ecdh:
- // Any other values (currently not used in TLS)
- case CertificateRequest.cct_rsa_ephemeral_dh:
- case CertificateRequest.cct_dss_ephemeral_dh:
- default:
- typeName = null;
- break;
+ // Fixed DH/ECDH client authentication not supported
+ //
+ // case CertificateRequest.cct_rsa_fixed_dh:
+ // case CertificateRequest.cct_dss_fixed_dh:
+ // case CertificateRequest.cct_rsa_fixed_ecdh:
+ // case CertificateRequest.cct_ecdsa_fixed_ecdh:
+ //
+ // Any other values (currently not used in TLS)
+ //
+ // case CertificateRequest.cct_rsa_ephemeral_dh:
+ // case CertificateRequest.cct_dss_ephemeral_dh:
+ default:
+ typeName = null;
+ break;
}
if ((typeName != null) && (!keytypesTmp.contains(typeName))) {
@@ -928,16 +931,6 @@
X509Certificate[] certs = km.getCertificateChain(alias);
if ((certs != null) && (certs.length != 0)) {
PublicKey publicKey = certs[0].getPublicKey();
- // for EC, make sure we use a supported named curve
- if (publicKey instanceof ECPublicKey) {
- ECParameterSpec params =
- ((ECPublicKey)publicKey).getParams();
- int index =
- EllipticCurvesExtension.getCurveIndex(params);
- if (!EllipticCurvesExtension.isSupported(index)) {
- publicKey = null;
- }
- }
if (publicKey != null) {
m1 = new CertificateMsg(certs);
signingKey = km.getPrivateKey(alias);
@@ -1499,6 +1492,17 @@
sslContext.getSecureRandom(), maxProtocolVersion,
sessionId, cipherSuites, isDTLS);
+ // add elliptic curves and point format extensions
+ if (cipherSuites.containsEC()) {
+ EllipticCurvesExtension ece =
+ EllipticCurvesExtension.createExtension(algorithmConstraints);
+ if (ece != null) {
+ clientHelloMessage.extensions.add(ece);
+ clientHelloMessage.extensions.add(
+ EllipticPointFormatsExtension.DEFAULT);
+ }
+ }
+
// add signature_algorithm extension
if (maxProtocolVersion.useTLS12PlusSpec()) {
// we will always send the signature_algorithm extension
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ECDHCrypt.java Sat Jul 09 05:56:18 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2016, 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
@@ -56,10 +56,11 @@
}
// Called by ServerHandshaker for ephemeral ECDH
- ECDHCrypt(String curveName, SecureRandom random) {
+ ECDHCrypt(int curveId, SecureRandom random) {
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC");
- ECGenParameterSpec params = new ECGenParameterSpec(curveName);
+ ECGenParameterSpec params =
+ EllipticCurvesExtension.getECGenParamSpec(curveId);
kpg.initialize(params, random);
KeyPair kp = kpg.generateKeyPair();
privateKey = kp.getPrivate();
--- a/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/EllipticCurvesExtension.java Sat Jul 09 05:56:18 2016 +0000
@@ -27,58 +27,271 @@
import java.io.IOException;
import java.security.spec.ECParameterSpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.AlgorithmParameters;
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AccessController;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
+import java.util.ArrayList;
+import javax.net.ssl.SSLProtocolException;
-import javax.net.ssl.SSLProtocolException;
+import sun.security.action.GetPropertyAction;
final class EllipticCurvesExtension extends HelloExtension {
- // the extension value to send in the ClientHello message
- static final EllipticCurvesExtension DEFAULT;
+ private static final int ARBITRARY_PRIME = 0xff01;
+ private static final int ARBITRARY_CHAR2 = 0xff02;
+
+ // speed up the searching
+ private static final Map<String, Integer> oidToIdMap = new HashMap<>();
+ private static final Map<Integer, String> idToOidMap = new HashMap<>();
+
+ // speed up the parameters construction
+ private static final Map<Integer,
+ AlgorithmParameters> idToParams = new HashMap<>();
+
+ // the supported elliptic curves
+ private static final int[] supportedCurveIds;
+
+ // the curves of the extension
+ private final int[] curveIds;
+
+ // See sun.security.util.CurveDB for the OIDs
+ private static enum NamedEllipticCurve {
+ T163_K1(1, "sect163k1", "1.3.132.0.1", true), // NIST K-163
+ T163_R1(2, "sect163r1", "1.3.132.0.2", false),
+ T163_R2(3, "sect163r2", "1.3.132.0.15", true), // NIST B-163
+ T193_R1(4, "sect193r1", "1.3.132.0.24", false),
+ T193_R2(5, "sect193r2", "1.3.132.0.25", false),
+ T233_K1(6, "sect233k1", "1.3.132.0.26", true), // NIST K-233
+ T233_R1(7, "sect233r1", "1.3.132.0.27", true), // NIST B-233
+ T239_K1(8, "sect239k1", "1.3.132.0.3", false),
+ T283_K1(9, "sect283k1", "1.3.132.0.16", true), // NIST K-283
+ T283_R1(10, "sect283r1", "1.3.132.0.17", true), // NIST B-283
+ T409_K1(11, "sect409k1", "1.3.132.0.36", true), // NIST K-409
+ T409_R1(12, "sect409r1", "1.3.132.0.37", true), // NIST B-409
+ T571_K1(13, "sect571k1", "1.3.132.0.38", true), // NIST K-571
+ T571_R1(14, "sect571r1", "1.3.132.0.39", true), // NIST B-571
- private static final boolean fips;
+ P160_K1(15, "secp160k1", "1.3.132.0.9", false),
+ P160_R1(16, "secp160r1", "1.3.132.0.8", false),
+ P160_R2(17, "secp160r2", "1.3.132.0.30", false),
+ P192_K1(18, "secp192k1", "1.3.132.0.31", false),
+ P192_R1(19, "secp192r1", "1.2.840.10045.3.1.1", true), // NIST P-192
+ P224_K1(20, "secp224k1", "1.3.132.0.32", false),
+ P224_R1(21, "secp224r1", "1.3.132.0.33", true), // NIST P-224
+ P256_K1(22, "secp256k1", "1.3.132.0.10", false),
+ P256_R1(23, "secp256r1", "1.2.840.10045.3.1.7", true), // NIST P-256
+ P384_R1(24, "secp384r1", "1.3.132.0.34", true), // NIST P-384
+ P521_R1(25, "secp521r1", "1.3.132.0.35", true); // NIST P-521
+
+ int id;
+ String name;
+ String oid;
+ boolean isFips;
+
+ NamedEllipticCurve(int id, String name, String oid, boolean isFips) {
+ this.id = id;
+ this.name = name;
+ this.oid = oid;
+ this.isFips = isFips;
+
+ if (oidToIdMap.put(oid, id) != null ||
+ idToOidMap.put(id, oid) != null) {
+
+ throw new RuntimeException(
+ "Duplicate named elliptic curve definition: " + name);
+ }
+ }
+
+ static NamedEllipticCurve getCurve(String name, boolean requireFips) {
+ for (NamedEllipticCurve curve : NamedEllipticCurve.values()) {
+ if (curve.name.equals(name) && (!requireFips || curve.isFips)) {
+ return curve;
+ }
+ }
+
+ return null;
+ }
+ }
static {
- int[] ids;
- fips = SunJSSE.isFIPS();
- if (fips == false) {
- ids = new int[] {
- // NIST curves first
- // prefer NIST P-256, rest in order of increasing key length
- 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
- // non-NIST curves
- 15, 16, 17, 2, 18, 4, 5, 20, 8, 22,
- };
+ boolean requireFips = SunJSSE.isFIPS();
+
+ // hack code to initialize NamedEllipticCurve
+ NamedEllipticCurve nec =
+ NamedEllipticCurve.getCurve("secp256r1", false);
+
+ // The value of the System Property defines a list of enabled named
+ // curves in preference order, separated with comma. For example:
+ //
+ // jdk.tls.namedGroups="secp521r1, secp256r1, secp384r1"
+ //
+ // If the System Property is not defined or the value is empty, the
+ // default curves and preferences will be used.
+ String property = AccessController.doPrivileged(
+ new GetPropertyAction("jdk.tls.namedGroups"));
+ if (property != null && property.length() != 0) {
+ // remove double quote marks from beginning/end of the property
+ if (property.length() > 1 && property.charAt(0) == '"' &&
+ property.charAt(property.length() - 1) == '"') {
+ property = property.substring(1, property.length() - 1);
+ }
+ }
+
+ ArrayList<Integer> idList;
+ if (property != null && property.length() != 0) { // customized curves
+ String[] curves = property.split(",");
+ idList = new ArrayList<>(curves.length);
+ for (String curve : curves) {
+ curve = curve.trim();
+ if (!curve.isEmpty()) {
+ NamedEllipticCurve namedCurve =
+ NamedEllipticCurve.getCurve(curve, requireFips);
+ if (namedCurve != null) {
+ if (isAvailableCurve(namedCurve.id)) {
+ idList.add(namedCurve.id);
+ }
+ } // ignore unknown curves
+ }
+ }
+ } else { // default curves
+ int[] ids;
+ if (requireFips) {
+ ids = new int[] {
+ // only NIST curves in FIPS mode
+ 23, 24, 25, 9, 10, 11, 12, 13, 14,
+ };
+ } else {
+ ids = new int[] {
+ // NIST curves first
+ 23, 24, 25, 9, 10, 11, 12, 13, 14,
+ // non-NIST curves
+ 22,
+ };
+ }
+
+ idList = new ArrayList<>(ids.length);
+ for (int curveId : ids) {
+ if (isAvailableCurve(curveId)) {
+ idList.add(curveId);
+ }
+ }
+ }
+
+ if (idList.isEmpty()) {
+ throw new IllegalArgumentException(
+ "System property jdk.tls.namedGroups(" + property + ") " +
+ "contains no supported elliptic curves");
} else {
- ids = new int[] {
- // same as above, but allow only NIST curves in FIPS mode
- 23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
- };
+ supportedCurveIds = new int[idList.size()];
+ int i = 0;
+ for (Integer id : idList) {
+ supportedCurveIds[i++] = id;
+ }
}
- DEFAULT = new EllipticCurvesExtension(ids);
}
- private final int[] curveIds;
+ // check whether the curve is supported by the underlying providers
+ private static boolean isAvailableCurve(int curveId) {
+ String oid = idToOidMap.get(curveId);
+ if (oid != null) {
+ AlgorithmParameters params = null;
+ try {
+ params = JsseJce.getAlgorithmParameters("EC");
+ params.init(new ECGenParameterSpec(oid));
+ } catch (Exception e) {
+ return false;
+ }
+
+ // cache the parameters
+ idToParams.put(curveId, params);
+
+ return true;
+ }
+
+ return false;
+ }
private EllipticCurvesExtension(int[] curveIds) {
super(ExtensionType.EXT_ELLIPTIC_CURVES);
+
this.curveIds = curveIds;
}
EllipticCurvesExtension(HandshakeInStream s, int len)
throws IOException {
super(ExtensionType.EXT_ELLIPTIC_CURVES);
+
int k = s.getInt16();
if (((len & 1) != 0) || (k + 2 != len)) {
throw new SSLProtocolException("Invalid " + type + " extension");
}
+
+ // Note: unknown curves will be ignored later.
curveIds = new int[k >> 1];
for (int i = 0; i < curveIds.length; i++) {
curveIds[i] = s.getInt16();
}
}
+ // get the preferred active curve
+ static int getActiveCurves(AlgorithmConstraints constraints) {
+ return getPreferredCurve(supportedCurveIds, constraints);
+ }
+
+ static boolean hasActiveCurves(AlgorithmConstraints constraints) {
+ return getActiveCurves(constraints) >= 0;
+ }
+
+ static EllipticCurvesExtension createExtension(
+ AlgorithmConstraints constraints) {
+
+ ArrayList<Integer> idList = new ArrayList<>(supportedCurveIds.length);
+ for (int curveId : supportedCurveIds) {
+ if (constraints.permits(
+ EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+ "EC", idToParams.get(curveId))) {
+ idList.add(curveId);
+ }
+ }
+
+ if (!idList.isEmpty()) {
+ int[] ids = new int[idList.size()];
+ int i = 0;
+ for (Integer id : idList) {
+ ids[i++] = id;
+ }
+
+ return new EllipticCurvesExtension(ids);
+ }
+
+ return null;
+ }
+
+ // get the preferred activated curve
+ int getPreferredCurve(AlgorithmConstraints constraints) {
+ return getPreferredCurve(curveIds, constraints);
+ }
+
+ // get a preferred activated curve
+ private static int getPreferredCurve(int[] curves,
+ AlgorithmConstraints constraints) {
+ for (int curveId : curves) {
+ if (constraints.permits(
+ EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
+ "EC", idToParams.get(curveId))) {
+ return curveId;
+ }
+ }
+
+ return -1;
+ }
+
boolean contains(int index) {
for (int curveId : curveIds) {
if (index == curveId) {
@@ -88,12 +301,6 @@
return false;
}
- // Return a reference to the internal curveIds array.
- // The caller must NOT modify the contents.
- int[] curveIds() {
- return curveIds;
- }
-
@Override
int length() {
return 6 + (curveIds.length << 1);
@@ -122,17 +329,9 @@
sb.append(", ");
}
// first check if it is a known named curve, then try other cases.
- String oid = getCurveOid(curveId);
- if (oid != null) {
- ECParameterSpec spec = JsseJce.getECParameterSpec(oid);
- // this toString() output will look nice for the current
- // implementation of the ECParameterSpec class in the Sun
- // provider, but may not look good for other implementations.
- if (spec != null) {
- sb.append(spec.toString().split(" ")[0]);
- } else {
- sb.append(oid);
- }
+ String curveName = getCurveName(curveId);
+ if (curveName != null) {
+ sb.append(curveName);
} else if (curveId == ARBITRARY_PRIME) {
sb.append("arbitrary_explicit_prime_curves");
} else if (curveId == ARBITRARY_CHAR2) {
@@ -145,16 +344,15 @@
return sb.toString();
}
- // Test whether we support the curve with the given index.
+ // Test whether the given curve is supported.
static boolean isSupported(int index) {
- if ((index <= 0) || (index >= NAMED_CURVE_OID_TABLE.length)) {
- return false;
+ for (int curveId : supportedCurveIds) {
+ if (index == curveId) {
+ return true;
+ }
}
- if (fips == false) {
- // in non-FIPS mode, we support all valid indices
- return true;
- }
- return DEFAULT.contains(index);
+
+ return false;
}
static int getCurveIndex(ECParameterSpec params) {
@@ -162,57 +360,32 @@
if (oid == null) {
return -1;
}
- Integer n = curveIndices.get(oid);
+ Integer n = oidToIdMap.get(oid);
return (n == null) ? -1 : n;
}
static String getCurveOid(int index) {
- if ((index > 0) && (index < NAMED_CURVE_OID_TABLE.length)) {
- return NAMED_CURVE_OID_TABLE[index];
- }
- return null;
+ return idToOidMap.get(index);
}
- private static final int ARBITRARY_PRIME = 0xff01;
- private static final int ARBITRARY_CHAR2 = 0xff02;
-
- // See sun.security.util.NamedCurve for the OIDs
- private static final String[] NAMED_CURVE_OID_TABLE = new String[] {
- null, // (0) unused
- "1.3.132.0.1", // (1) sect163k1, NIST K-163
- "1.3.132.0.2", // (2) sect163r1
- "1.3.132.0.15", // (3) sect163r2, NIST B-163
- "1.3.132.0.24", // (4) sect193r1
- "1.3.132.0.25", // (5) sect193r2
- "1.3.132.0.26", // (6) sect233k1, NIST K-233
- "1.3.132.0.27", // (7) sect233r1, NIST B-233
- "1.3.132.0.3", // (8) sect239k1
- "1.3.132.0.16", // (9) sect283k1, NIST K-283
- "1.3.132.0.17", // (10) sect283r1, NIST B-283
- "1.3.132.0.36", // (11) sect409k1, NIST K-409
- "1.3.132.0.37", // (12) sect409r1, NIST B-409
- "1.3.132.0.38", // (13) sect571k1, NIST K-571
- "1.3.132.0.39", // (14) sect571r1, NIST B-571
- "1.3.132.0.9", // (15) secp160k1
- "1.3.132.0.8", // (16) secp160r1
- "1.3.132.0.30", // (17) secp160r2
- "1.3.132.0.31", // (18) secp192k1
- "1.2.840.10045.3.1.1", // (19) secp192r1, NIST P-192
- "1.3.132.0.32", // (20) secp224k1
- "1.3.132.0.33", // (21) secp224r1, NIST P-224
- "1.3.132.0.10", // (22) secp256k1
- "1.2.840.10045.3.1.7", // (23) secp256r1, NIST P-256
- "1.3.132.0.34", // (24) secp384r1, NIST P-384
- "1.3.132.0.35", // (25) secp521r1, NIST P-521
- };
-
- private static final Map<String,Integer> curveIndices;
-
- static {
- curveIndices = new HashMap<String,Integer>();
- for (int i = 1; i < NAMED_CURVE_OID_TABLE.length; i++) {
- curveIndices.put(NAMED_CURVE_OID_TABLE[i], i);
+ static ECGenParameterSpec getECGenParamSpec(int index) {
+ AlgorithmParameters params = idToParams.get(index);
+ try {
+ return params.getParameterSpec(ECGenParameterSpec.class);
+ } catch (InvalidParameterSpecException ipse) {
+ // should be unlikely
+ String curveOid = getCurveOid(index);
+ return new ECGenParameterSpec(curveOid);
}
}
+ private static String getCurveName(int index) {
+ for (NamedEllipticCurve namedCurve : NamedEllipticCurve.values()) {
+ if (namedCurve.id == index) {
+ return namedCurve.name;
+ }
+ }
+
+ return null;
+ }
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/HandshakeMessage.java Sat Jul 09 05:56:18 2016 +0000
@@ -313,11 +313,6 @@
this.cookie = null;
}
- if (cipherSuites.containsEC()) {
- extensions.add(EllipticCurvesExtension.DEFAULT);
- extensions.add(EllipticPointFormatsExtension.DEFAULT);
- }
-
clnt_random = new RandomCookie(generator);
compression_methods = NULL_COMPRESSION;
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Handshaker.java Sat Jul 09 05:56:18 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, 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
@@ -660,13 +660,42 @@
ArrayList<CipherSuite> suites = new ArrayList<>();
if (!(activeProtocols.collection().isEmpty()) &&
activeProtocols.min.v != ProtocolVersion.NONE.v) {
+ boolean checkedCurves = false;
+ boolean hasCurves = false;
for (CipherSuite suite : enabledCipherSuites.collection()) {
if (!activeProtocols.min.obsoletes(suite) &&
activeProtocols.max.supports(suite)) {
if (algorithmConstraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
suite.name, null)) {
- suites.add(suite);
+
+ boolean available = true;
+ if (suite.keyExchange.isEC) {
+ if (!checkedCurves) {
+ hasCurves = EllipticCurvesExtension
+ .hasActiveCurves(algorithmConstraints);
+ checkedCurves = true;
+
+ if (!hasCurves && debug != null &&
+ Debug.isOn("verbose")) {
+ System.out.println(
+ "No available elliptic curves");
+ }
+ }
+
+ available = hasCurves;
+
+ if (!available && debug != null &&
+ Debug.isOn("verbose")) {
+ System.out.println(
+ "No active elliptic curves, ignore " +
+ suite);
+ }
+ }
+
+ if (available) {
+ suites.add(suite);
+ }
}
} else if (debug != null && Debug.isOn("verbose")) {
if (activeProtocols.min.obsoletes(suite)) {
@@ -703,6 +732,8 @@
ProtocolList getActiveProtocols() {
if (activeProtocols == null) {
boolean enabledSSL20Hello = false;
+ boolean checkedCurves = false;
+ boolean hasCurves = false;
ArrayList<ProtocolVersion> protocols = new ArrayList<>(4);
for (ProtocolVersion protocol : enabledProtocols.collection()) {
// Need not to check the SSL20Hello protocol.
@@ -729,9 +760,36 @@
if (algorithmConstraints.permits(
EnumSet.of(CryptoPrimitive.KEY_AGREEMENT),
suite.name, null)) {
- protocols.add(protocol);
- found = true;
- break;
+
+ boolean available = true;
+ if (suite.keyExchange.isEC) {
+ if (!checkedCurves) {
+ hasCurves = EllipticCurvesExtension
+ .hasActiveCurves(algorithmConstraints);
+ checkedCurves = true;
+
+ if (!hasCurves && debug != null &&
+ Debug.isOn("verbose")) {
+ System.out.println(
+ "No activated elliptic curves");
+ }
+ }
+
+ available = hasCurves;
+
+ if (!available && debug != null &&
+ Debug.isOn("verbose")) {
+ System.out.println(
+ "No active elliptic curves, ignore " +
+ suite + " for " + protocol);
+ }
+ }
+
+ if (available) {
+ protocols.add(protocol);
+ found = true;
+ break;
+ }
} else if (debug != null && Debug.isOn("verbose")) {
System.out.println(
"Ignoring disabled cipher suite: " + suite +
--- a/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/JsseJce.java Sat Jul 09 05:56:18 2016 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2016, 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
@@ -275,6 +275,15 @@
}
}
+ static AlgorithmParameters getAlgorithmParameters(String algorithm)
+ throws NoSuchAlgorithmException {
+ if (cryptoProvider == null) {
+ return AlgorithmParameters.getInstance(algorithm);
+ } else {
+ return AlgorithmParameters.getInstance(algorithm, cryptoProvider);
+ }
+ }
+
static SecureRandom getSecureRandom() throws KeyManagementException {
if (cryptoProvider == null) {
return new SecureRandom();
@@ -394,6 +403,7 @@
JsseJce.getKeyAgreement("ECDH");
JsseJce.getKeyFactory("EC");
JsseJce.getKeyPairGenerator("EC");
+ JsseJce.getAlgorithmParameters("EC");
} catch (Exception e) {
mediator = false;
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java Sat Jul 09 05:56:18 2016 +0000
@@ -94,7 +94,8 @@
// we remember it for the RSA premaster secret version check
private ProtocolVersion clientRequestedVersion;
- private EllipticCurvesExtension supportedCurves;
+ // client supported elliptic curves
+ private EllipticCurvesExtension requestedCurves;
// the preferable signature algorithm used by ServerKeyExchange message
SignatureAndHashAlgorithm preferableSignatureAlgorithm;
@@ -741,7 +742,7 @@
throw new SSLException("Client did not resume a session");
}
- supportedCurves = (EllipticCurvesExtension)
+ requestedCurves = (EllipticCurvesExtension)
mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
// We only need to handle the "signature_algorithm" extension
@@ -1572,26 +1573,15 @@
// If we cannot continue because we do not support any of the curves that
// the client requested, return false. Otherwise (all is well), return true.
private boolean setupEphemeralECDHKeys() {
- int index = -1;
- if (supportedCurves != null) {
- // if the client sent the supported curves extension, pick the
- // first one that we support;
- for (int curveId : supportedCurves.curveIds()) {
- if (EllipticCurvesExtension.isSupported(curveId)) {
- index = curveId;
- break;
- }
- }
- if (index < 0) {
- // no match found, cannot use this ciphersuite
- return false;
- }
- } else {
- // pick our preference
- index = EllipticCurvesExtension.DEFAULT.curveIds()[0];
+ int index = (requestedCurves != null) ?
+ requestedCurves.getPreferredCurve(algorithmConstraints) :
+ EllipticCurvesExtension.getActiveCurves(algorithmConstraints);
+ if (index < 0) {
+ // no match found, cannot use this ciphersuite
+ return false;
}
- String oid = EllipticCurvesExtension.getCurveOid(index);
- ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());
+
+ ecdh = new ECDHCrypt(index, sslContext.getSecureRandom());
return true;
}
@@ -1633,18 +1623,16 @@
return false;
}
// For ECC certs, check whether we support the EC domain parameters.
- // If the client sent a EllipticCurves ClientHello extension,
+ // If the client sent a SupportedEllipticCurves ClientHello extension,
// check against that too.
if (keyAlgorithm.equals("EC")) {
if (publicKey instanceof ECPublicKey == false) {
return false;
}
ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
- int index = EllipticCurvesExtension.getCurveIndex(params);
- if (!EllipticCurvesExtension.isSupported(index)) {
- return false;
- }
- if ((supportedCurves != null) && !supportedCurves.contains(index)) {
+ int id = EllipticCurvesExtension.getCurveIndex(params);
+ if ((id <= 0) || !EllipticCurvesExtension.isSupported(id) ||
+ ((requestedCurves != null) && !requestedCurves.contains(id))) {
return false;
}
}
--- a/jdk/src/java.base/share/conf/security/java.security Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/src/java.base/share/conf/security/java.security Sat Jul 09 05:56:18 2016 +0000
@@ -653,7 +653,7 @@
#
#
jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
- DSA keySize < 1024
+ DSA keySize < 1024, EC keySize < 224
# Algorithm restrictions for Secure Socket Layer/Transport Layer Security
# (SSL/TLS/DTLS) processing
@@ -681,7 +681,8 @@
#
# Example:
# jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048
-jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 1024
+jdk.tls.disabledAlgorithms=SSLv3, RC4, MD5withRSA, DH keySize < 1024, \
+ EC keySize < 224
# Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS)
# processing in JSSE implementation.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/net/ssl/ciphersuites/ECCurvesconstraints.java Sat Jul 09 05:56:18 2016 +0000
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 2016, 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.
+ */
+
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
+/*
+ * @test
+ * @bug 8148516
+ * @summary Improve the default strength of EC in JDK
+ * @run main/othervm ECCurvesconstraints PKIX
+ * @run main/othervm ECCurvesconstraints SunX509
+ */
+
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import javax.net.ssl.*;
+import java.security.Security;
+import java.security.KeyStore;
+import java.security.KeyFactory;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateFactory;
+import java.security.spec.*;
+import java.security.interfaces.*;
+import java.util.Base64;
+
+
+public class ECCurvesconstraints {
+
+ /*
+ * =============================================================
+ * Set the various variables needed for the tests, then
+ * specify what tests to run on each side.
+ */
+
+ /*
+ * Should we run the client or server in a separate thread?
+ * Both sides can throw exceptions, but do you have a preference
+ * as to which side should be the main thread.
+ */
+ static boolean separateServerThread = false;
+
+ /*
+ * Where do we find the keystores?
+ */
+ // Certificates and key used in the test.
+ //
+ // EC curve: secp224k1
+ static String trustedCertStr =
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIBCzCBugIEVz2lcjAKBggqhkjOPQQDAjAaMRgwFgYDVQQDDA93d3cuZXhhbXBs\n" +
+ "ZS5vcmcwHhcNMTYwNTE5MTEzNzM5WhcNMTcwNTE5MTEzNzM5WjAaMRgwFgYDVQQD\n" +
+ "DA93d3cuZXhhbXBsZS5vcmcwTjAQBgcqhkjOPQIBBgUrgQQAIAM6AAT68uovMZ8f\n" +
+ "KARn5NOjvieJaq6h8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4\n" +
+ "djAKBggqhkjOPQQDAgNAADA9AhwMNIujM0R0llpPH6d89d1S3VRGH/78ovc+zw51\n" +
+ "Ah0AuZ1YlQkUbrJIzkuPSICxz5UfCWPe+7w4as+wiA==\n" +
+ "-----END CERTIFICATE-----";
+
+ // Private key in the format of PKCS#8
+ static String targetPrivateKey =
+ "MIGCAgEAMBAGByqGSM49AgEGBSuBBAAgBGswaQIBAQQdAPbckc86mgW/zexB1Ajq\n" +
+ "38HntWOjdxL6XSoiAsWgBwYFK4EEACChPAM6AAT68uovMZ8fKARn5NOjvieJaq6h\n" +
+ "8zHYkM9w5DuN0kkOo4KBhke06EkQj0nvQQcSvppTV6RoDLY4dg==";
+
+ static String[] serverCerts = {trustedCertStr};
+ static String[] serverKeys = {targetPrivateKey};
+ static String[] clientCerts = {trustedCertStr};
+ static String[] clientKeys = {targetPrivateKey};
+
+ static char passphrase[] = "passphrase".toCharArray();
+
+ /*
+ * Is the server ready to serve?
+ */
+ volatile static boolean serverReady = false;
+
+ /*
+ * Turn on SSL debugging?
+ */
+ static boolean debug = false;
+
+ /*
+ * Define the server side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doServerSide() throws Exception {
+ SSLContext context = generateSSLContext(false);
+ SSLServerSocketFactory sslssf = context.getServerSocketFactory();
+ SSLServerSocket sslServerSocket =
+ (SSLServerSocket)sslssf.createServerSocket(serverPort);
+ serverPort = sslServerSocket.getLocalPort();
+
+ /*
+ * Signal Client, we're ready for his connect.
+ */
+ serverReady = true;
+
+ SSLSocket sslSocket = (SSLSocket)sslServerSocket.accept();
+ try {
+ sslSocket.setSoTimeout(5000);
+ sslSocket.setSoLinger(true, 5);
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslIS.read();
+ sslOS.write('A');
+ sslOS.flush();
+
+ throw new Exception("EC curve secp224k1 should be disabled");
+ } catch (SSLHandshakeException she) {
+ // expected exception: no cipher suites in common
+ System.out.println("Expected exception: " + she);
+ } finally {
+ sslSocket.close();
+ sslServerSocket.close();
+ }
+ }
+
+ /*
+ * Define the client side of the test.
+ *
+ * If the server prematurely exits, serverReady will be set to true
+ * to avoid infinite hangs.
+ */
+ void doClientSide() throws Exception {
+
+ /*
+ * Wait for server to get started.
+ */
+ while (!serverReady) {
+ Thread.sleep(50);
+ }
+
+ SSLContext context = generateSSLContext(true);
+ SSLSocketFactory sslsf = context.getSocketFactory();
+
+ SSLSocket sslSocket =
+ (SSLSocket)sslsf.createSocket("localhost", serverPort);
+
+ try {
+ sslSocket.setSoTimeout(5000);
+ sslSocket.setSoLinger(true, 5);
+
+ InputStream sslIS = sslSocket.getInputStream();
+ OutputStream sslOS = sslSocket.getOutputStream();
+
+ sslOS.write('B');
+ sslOS.flush();
+ sslIS.read();
+
+ throw new Exception("EC curve secp224k1 should be disabled");
+ } catch (SSLHandshakeException she) {
+ // expected exception: Received fatal alert
+ System.out.println("Expected exception: " + she);
+ } finally {
+ sslSocket.close();
+ }
+ }
+
+ /*
+ * =============================================================
+ * The remainder is just support stuff
+ */
+ private static String tmAlgorithm; // trust manager
+
+ private static void parseArguments(String[] args) {
+ tmAlgorithm = args[0];
+ }
+
+ private static SSLContext generateSSLContext(boolean isClient)
+ throws Exception {
+
+ // generate certificate from cert string
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+
+ // create a key store
+ KeyStore ks = KeyStore.getInstance("JKS");
+ ks.load(null, null);
+
+ // import the trused cert
+ ByteArrayInputStream is =
+ new ByteArrayInputStream(trustedCertStr.getBytes());
+ Certificate trusedCert = cf.generateCertificate(is);
+ is.close();
+
+ ks.setCertificateEntry("Export Signer", trusedCert);
+
+ String[] certStrs = null;
+ String[] keyStrs = null;
+ if (isClient) {
+ certStrs = clientCerts;
+ keyStrs = clientKeys;
+ } else {
+ certStrs = serverCerts;
+ keyStrs = serverKeys;
+ }
+
+ for (int i = 0; i < certStrs.length; i++) {
+ // generate the private key.
+ String keySpecStr = keyStrs[i];
+ PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(
+ Base64.getMimeDecoder().decode(keySpecStr));
+ KeyFactory kf = KeyFactory.getInstance("EC");
+ ECPrivateKey priKey =
+ (ECPrivateKey)kf.generatePrivate(priKeySpec);
+
+ // generate certificate chain
+ String keyCertStr = certStrs[i];
+ is = new ByteArrayInputStream(keyCertStr.getBytes());
+ Certificate keyCert = cf.generateCertificate(is);
+ is.close();
+
+ Certificate[] chain = new Certificate[2];
+ chain[0] = keyCert;
+ chain[1] = trusedCert;
+
+ // import the key entry.
+ ks.setKeyEntry("key-entry-" + i, priKey, passphrase, chain);
+ }
+
+ // create SSL context
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmAlgorithm);
+ tmf.init(ks);
+
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
+ kmf.init(ks, passphrase);
+
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ ks = null;
+
+ return ctx;
+ }
+
+ // use any free port by default
+ volatile int serverPort = 0;
+
+ volatile Exception serverException = null;
+ volatile Exception clientException = null;
+
+ public static void main(String[] args) throws Exception {
+ if (debug) {
+ System.setProperty("javax.net.debug", "all");
+ }
+
+ /*
+ * Get the customized arguments.
+ */
+ parseArguments(args);
+
+ /*
+ * Start the tests.
+ */
+ new ECCurvesconstraints();
+ }
+
+ Thread clientThread = null;
+ Thread serverThread = null;
+
+ /*
+ * Primary constructor, used to drive remainder of the test.
+ *
+ * Fork off the other side, then do your work.
+ */
+ ECCurvesconstraints() throws Exception {
+ try {
+ if (separateServerThread) {
+ startServer(true);
+ startClient(false);
+ } else {
+ startClient(true);
+ startServer(false);
+ }
+ } catch (Exception e) {
+ // swallow for now. Show later
+ }
+
+ /*
+ * Wait for other side to close down.
+ */
+ if (separateServerThread) {
+ serverThread.join();
+ } else {
+ clientThread.join();
+ }
+
+ /*
+ * When we get here, the test is pretty much over.
+ * Which side threw the error?
+ */
+ Exception local;
+ Exception remote;
+ String whichRemote;
+
+ if (separateServerThread) {
+ remote = serverException;
+ local = clientException;
+ whichRemote = "server";
+ } else {
+ remote = clientException;
+ local = serverException;
+ whichRemote = "client";
+ }
+
+ /*
+ * If both failed, return the curthread's exception, but also
+ * print the remote side Exception
+ */
+ if ((local != null) && (remote != null)) {
+ System.out.println(whichRemote + " also threw:");
+ remote.printStackTrace();
+ System.out.println();
+ throw local;
+ }
+
+ if (remote != null) {
+ throw remote;
+ }
+
+ if (local != null) {
+ throw local;
+ }
+ }
+
+ void startServer(boolean newThread) throws Exception {
+ if (newThread) {
+ serverThread = new Thread() {
+ public void run() {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ /*
+ * Our server thread just died.
+ *
+ * Release the client, if not active already...
+ */
+ System.err.println("Server died, because of " + e);
+ serverReady = true;
+ serverException = e;
+ }
+ }
+ };
+ serverThread.start();
+ } else {
+ try {
+ doServerSide();
+ } catch (Exception e) {
+ serverException = e;
+ } finally {
+ serverReady = true;
+ }
+ }
+ }
+
+ void startClient(boolean newThread) throws Exception {
+ if (newThread) {
+ clientThread = new Thread() {
+ public void run() {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ /*
+ * Our client thread just died.
+ */
+ System.err.println("Client died, because of " + e);
+ clientException = e;
+ }
+ }
+ };
+ clientThread.start();
+ } else {
+ try {
+ doClientSide();
+ } catch (Exception e) {
+ clientException = e;
+ }
+ }
+ }
+}
--- a/jdk/test/sun/security/ec/TestEC.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/test/sun/security/ec/TestEC.java Sat Jul 09 05:56:18 2016 +0000
@@ -36,7 +36,7 @@
* @library ../../../java/security/testlibrary
* @modules jdk.crypto.pkcs11/sun.security.pkcs11.wrapper
* @compile -XDignore.symbol.file TestEC.java
- * @run main/othervm TestEC
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1" TestEC
*/
import java.security.NoSuchProviderException;
--- a/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java Sat Jul 09 05:48:16 2016 +0000
+++ b/jdk/test/sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java Sat Jul 09 05:56:18 2016 +0000
@@ -33,8 +33,10 @@
* @author Andreas Sterbenz
* @library ..
* @library ../../../../java/security/testlibrary
- * @run main/othervm ClientJSSEServerJSSE
- * @run main/othervm ClientJSSEServerJSSE sm policy
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
+ * ClientJSSEServerJSSE
+ * @run main/othervm -Djdk.tls.namedGroups="secp256r1,sect193r1"
+ * ClientJSSEServerJSSE sm policy
*/
import java.security.Provider;