8081760: Better group dynamics
Summary: Allows user to specify custom DH groups. Also reviewed by Alexander Fomin <alexander.fomin@oracle.com>.
Reviewed-by: coffeys, mullan, weijun, jnimeh, ahgross, asmotrak
--- a/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java Tue Jul 14 17:06:41 2015 -0500
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/DHCrypt.java Mon Jul 20 01:45:23 2015 +0000
@@ -26,6 +26,11 @@
package sun.security.ssl;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
import java.math.BigInteger;
import java.security.*;
import java.io.IOException;
@@ -95,9 +100,35 @@
* Generate a Diffie-Hellman keypair of the specified size.
*/
DHCrypt(int keyLength, SecureRandom random) {
+ this(keyLength,
+ ParametersHolder.definedParams.get(keyLength), random);
+ }
+
+ /**
+ * Generate a Diffie-Hellman keypair using the specified parameters.
+ *
+ * @param modulus the Diffie-Hellman modulus P
+ * @param base the Diffie-Hellman base G
+ */
+ DHCrypt(BigInteger modulus, BigInteger base, SecureRandom random) {
+ this(modulus.bitLength(),
+ new DHParameterSpec(modulus, base), random);
+ }
+
+ /**
+ * Generate a Diffie-Hellman keypair using the specified size and
+ * parameters.
+ */
+ private DHCrypt(int keyLength,
+ DHParameterSpec params, SecureRandom random) {
+
try {
KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
- kpg.initialize(keyLength, random);
+ if (params != null) {
+ kpg.initialize(params, random);
+ } else {
+ kpg.initialize(keyLength, random);
+ }
DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
if (spec == null) {
@@ -112,33 +143,6 @@
}
}
-
- /**
- * Generate a Diffie-Hellman keypair using the specified parameters.
- *
- * @param modulus the Diffie-Hellman modulus P
- * @param base the Diffie-Hellman base G
- */
- DHCrypt(BigInteger modulus, BigInteger base, SecureRandom random) {
- this.modulus = modulus;
- this.base = base;
- try {
- KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman");
- DHParameterSpec params = new DHParameterSpec(modulus, base);
- kpg.initialize(params, random);
-
- DHPublicKeySpec spec = generateDHPublicKeySpec(kpg);
- if (spec == null) {
- throw new RuntimeException("Could not generate DH keypair");
- }
-
- publicValue = spec.getY();
- } catch (GeneralSecurityException e) {
- throw new RuntimeException("Could not generate DH keypair", e);
- }
- }
-
-
static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) {
if (key instanceof DHPublicKey) {
DHPublicKey dhKey = (DHPublicKey)key;
@@ -268,4 +272,141 @@
return null;
}
+
+ // lazy initialization holder class idiom for static default parameters
+ //
+ // See Effective Java Second Edition: Item 71.
+ private static class ParametersHolder {
+ private final static boolean debugIsOn =
+ (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx");
+
+ //
+ // Default DH ephemeral parameters
+ //
+ private static final BigInteger g2 = BigInteger.valueOf(2);
+
+ private static final BigInteger p512 = new BigInteger( // generated
+ "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" +
+ "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" +
+ "A43DD89D1D90921C6328884461E0B6D3", 16);
+ private static final BigInteger p768 = new BigInteger( // RFC 2409
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
+
+ private static final BigInteger p1024 = new BigInteger( // RFC 2409
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
+ "FFFFFFFFFFFFFFFF", 16);
+ private static final BigInteger p2048 = new BigInteger( // TLS FEDHE
+ "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" +
+ "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" +
+ "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" +
+ "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" +
+ "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" +
+ "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" +
+ "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" +
+ "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" +
+ "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" +
+ "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" +
+ "886B423861285C97FFFFFFFFFFFFFFFF", 16);
+
+ private static final BigInteger[] supportedPrimes = {
+ p512, p768, p1024, p2048};
+
+ // a measure of the uncertainty that prime modulus p is not a prime
+ //
+ // see BigInteger.isProbablePrime(int certainty)
+ private final static int PRIME_CERTAINTY = 120;
+
+ // the known security property, jdk.tls.server.defaultDHEParameters
+ private final static String PROPERTY_NAME =
+ "jdk.tls.server.defaultDHEParameters";
+
+ private static final Pattern spacesPattern = Pattern.compile("\\s+");
+
+ private final static Pattern syntaxPattern = Pattern.compile(
+ "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" +
+ "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*");
+
+ private static final Pattern paramsPattern = Pattern.compile(
+ "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}");
+
+ // cache of predefined default DH ephemeral parameters
+ private final static Map<Integer,DHParameterSpec> definedParams;
+
+ static {
+ String property = AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ public String run() {
+ return Security.getProperty(PROPERTY_NAME);
+ }
+ });
+
+ if (property != null && !property.isEmpty()) {
+ // remove double quote marks from beginning/end of the property
+ if (property.length() >= 2 && property.charAt(0) == '"' &&
+ property.charAt(property.length() - 1) == '"') {
+ property = property.substring(1, property.length() - 1);
+ }
+
+ property = property.trim();
+ }
+
+ if (property != null && !property.isEmpty()) {
+ Matcher spacesMatcher = spacesPattern.matcher(property);
+ property = spacesMatcher.replaceAll("");
+
+ if (debugIsOn) {
+ System.out.println("The Security Property " +
+ PROPERTY_NAME + ": " + property);
+ }
+ }
+
+ Map<Integer,DHParameterSpec> defaultParams = new HashMap<>();
+ if (property != null && !property.isEmpty()) {
+ Matcher syntaxMatcher = syntaxPattern.matcher(property);
+ if (syntaxMatcher.matches()) {
+ Matcher paramsFinder = paramsPattern.matcher(property);
+ while(paramsFinder.find()) {
+ String primeModulus = paramsFinder.group(1);
+ BigInteger p = new BigInteger(primeModulus, 16);
+ if (!p.isProbablePrime(PRIME_CERTAINTY)) {
+ if (debugIsOn) {
+ System.out.println(
+ "Prime modulus p in Security Property, " +
+ PROPERTY_NAME + ", is not a prime: " +
+ primeModulus);
+ }
+
+ continue;
+ }
+
+ String baseGenerator = paramsFinder.group(2);
+ BigInteger g = new BigInteger(baseGenerator, 16);
+
+ DHParameterSpec spec = new DHParameterSpec(p, g);
+ int primeLen = p.bitLength();
+ defaultParams.put(primeLen, spec);
+ }
+ } else if (debugIsOn) {
+ System.out.println("Invalid Security Property, " +
+ PROPERTY_NAME + ", definition");
+ }
+ }
+
+ for (BigInteger p : supportedPrimes) {
+ int primeLen = p.bitLength();
+ defaultParams.putIfAbsent(primeLen, new DHParameterSpec(p, g2));
+ }
+
+ definedParams =
+ Collections.<Integer,DHParameterSpec>unmodifiableMap(
+ defaultParams);
+ }
+ }
}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java Tue Jul 14 17:06:41 2015 -0500
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLEngineInputRecord.java Mon Jul 20 01:45:23 2015 +0000
@@ -284,7 +284,7 @@
((plaintext.get() & 0xFF) << 8) |
(plaintext.get() & 0xFF);
plaintext.position(frgPos);
- if (remains < (handshakeLen + 1)) { // 1: handshake type
+ if (remains < (handshakeLen + 4)) { // 4: handshake header
// This handshake message is fragmented.
prevType = handshakeType;
hsMsgOff = remains - 4; // 4: handshake header
--- a/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java Tue Jul 14 17:06:41 2015 -0500
+++ b/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java Mon Jul 20 01:45:23 2015 +0000
@@ -54,13 +54,12 @@
String[] algorithmsInProperty = null;
if (property != null && !property.isEmpty()) {
// remove double quote marks from beginning/end of the property
- if (property.charAt(0) == '"'
- && property.charAt(property.length() - 1) == '"') {
+ if (property.length() >= 2 && property.charAt(0) == '"' &&
+ property.charAt(property.length() - 1) == '"') {
property = property.substring(1, property.length() - 1);
}
algorithmsInProperty = property.split(",");
- for (int i = 0; i < algorithmsInProperty.length;
- i++) {
+ for (int i = 0; i < algorithmsInProperty.length; i++) {
algorithmsInProperty[i] = algorithmsInProperty[i].trim();
}
}
--- a/jdk/src/java.base/share/conf/security/java.security Tue Jul 14 17:06:41 2015 -0500
+++ b/jdk/src/java.base/share/conf/security/java.security Mon Jul 20 01:45:23 2015 +0000
@@ -634,3 +634,60 @@
DH_RSA_EXPORT, RSA_EXPORT, \
DH_anon, ECDH_anon, \
RC4_128, RC4_40, DES_CBC, DES40_CBC
+
+# The pre-defined default finite field Diffie-Hellman ephemeral (DHE)
+# parameters for Transport Layer Security (SSL/TLS/DTLS) processing.
+#
+# In traditional SSL/TLS/DTLS connections where finite field DHE parameters
+# negotiation mechanism is not used, the server offers the client group
+# parameters, base generator g and prime modulus p, for DHE key exchange.
+# It is recommended to use dynamic group parameters. This property defines
+# a mechanism that allows you to specify custom group parameters.
+#
+# The syntax of this property string is described as this Java BNF-style:
+# DefaultDHEParameters:
+# DefinedDHEParameters { , DefinedDHEParameters }
+#
+# DefinedDHEParameters:
+# "{" DHEPrimeModulus , DHEBaseGenerator "}"
+#
+# DHEPrimeModulus:
+# HexadecimalDigits
+#
+# DHEBaseGenerator:
+# HexadecimalDigits
+#
+# HexadecimalDigits:
+# HexadecimalDigit { HexadecimalDigit }
+#
+# HexadecimalDigit: one of
+# 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f
+#
+# Whitespace characters are ignored.
+#
+# The "DefinedDHEParameters" defines the custom group parameters, prime
+# modulus p and base generator g, for a particular size of prime modulus p.
+# The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the
+# "DHEBaseGenerator" defines the hexadecimal base generator g of a group
+# parameter. It is recommended to use safe primes for the custom group
+# parameters.
+#
+# If this property is not defined or the value is empty, the underlying JSSE
+# provider's default group parameter is used for each connection.
+#
+# If the property value does not follow the grammar, or a particular group
+# parameter is not valid, the connection will fall back and use the
+# underlying JSSE provider's default group parameter.
+#
+# Note: This property is currently used by OpenJDK's JSSE implementation. It
+# is not guaranteed to be examined and used by other implementations.
+#
+# Example:
+# jdk.tls.server.defaultDHEParameters=
+# { \
+# FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \
+# 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \
+# EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \
+# E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \
+# EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \
+# FFFFFFFF FFFFFFFF, 2}
--- a/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Tue Jul 14 17:06:41 2015 -0500
+++ b/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Mon Jul 20 01:45:23 2015 +0000
@@ -31,34 +31,34 @@
* @bug 6956398
* @summary make ephemeral DH key match the length of the certificate key
* @run main/othervm
- * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75
+ * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
- * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75
+ * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
- * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75
+ * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
- * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1318 75
+ * DHEKeySizing SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA true 1255 75
*
* @run main/othervm
- * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 292 75
+ * DHEKeySizing SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA true 229 75
*
* @run main/othervm
- * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139
+ * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
- * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1414 107
+ * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1319 107
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
- * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1894 267
+ * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1639 267
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
- * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1510 139
+ * DHEKeySizing TLS_DHE_RSA_WITH_AES_128_CBC_SHA false 1383 139
*
* @run main/othervm
- * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139
+ * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=legacy
- * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 388 107
+ * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 293 107
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=matched
- * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139
+ * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139
* @run main/othervm -Djdk.tls.ephemeralDHKeySize=1024
- * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 484 139
+ * DHEKeySizing SSL_DH_anon_WITH_RC4_128_MD5 false 357 139
*/
/*
@@ -90,10 +90,10 @@
* Here is a summary of the record length in the test case.
*
* | ServerHello Series | ClientKeyExchange | ServerHello Anon
- * 512-bit | 1318 bytes | 75 bytes | 292 bytes
- * 768-bit | 1414 bytes | 107 bytes | 388 bytes
- * 1024-bit | 1510 bytes | 139 bytes | 484 bytes
- * 2048-bit | 1894 bytes | 267 bytes | 484 bytes
+ * 512-bit | 1255 bytes | 75 bytes | 229 bytes
+ * 768-bit | 1319 bytes | 107 bytes | 293 bytes
+ * 1024-bit | 1383 bytes | 139 bytes | 357 bytes
+ * 2048-bit | 1639 bytes | 267 bytes | 357 bytes
*/
import javax.net.ssl.*;