diff --git a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java index d78c0204382..4cc979cb29a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/DHKeyPairGenerator.java @@ -61,9 +61,6 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { // The size in bits of the prime modulus private int pSize; - // The size in bits of the random exponent (private value) - private int lSize; - // The source of randomness private SecureRandom random; @@ -111,7 +108,6 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { } this.pSize = keysize; - this.lSize = params.getL(); this.random = random; } @@ -138,9 +134,8 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { params = (DHParameterSpec) algParams; pSize = params.getP().bitLength(); - lSize = params.getL(); try { - checkKeySize(pSize, lSize); + checkKeySize(pSize, params.getL()); } catch (InvalidParameterException ipe) { throw new InvalidAlgorithmParameterException(ipe.getMessage()); } @@ -157,20 +152,12 @@ public final class DHKeyPairGenerator extends KeyPairGeneratorSpi { random = SunJCE.getRandom(); } - if (params == null) { // when init() not called - try { - params = ParameterCache.getDHParameterSpec(pSize, random); - lSize = params.getL(); - } catch (GeneralSecurityException e) { - // should never happen - throw new ProviderException(e); - } - } BigInteger p = params.getP(); BigInteger g = params.getG(); + int lSize = params.getL(); if (lSize == 0) { // not specified; use our own default - lSize = getDefDHPrivateExpSize(pSize); + lSize = getDefDHPrivateExpSize(params); } BigInteger x; diff --git a/src/java.base/share/classes/sun/security/provider/ParameterCache.java b/src/java.base/share/classes/sun/security/provider/ParameterCache.java index ed6efae16cf..9cdc7a215c3 100644 --- a/src/java.base/share/classes/sun/security/provider/ParameterCache.java +++ b/src/java.base/share/classes/sun/security/provider/ParameterCache.java @@ -34,7 +34,7 @@ import java.security.SecureRandom; import java.security.spec.*; import javax.crypto.spec.DHParameterSpec; -import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; +import sun.security.util.SafeDHParameterSpec; /** * Cache for DSA and DH parameter specs. Used by the KeyPairGenerators @@ -56,6 +56,26 @@ public final class ParameterCache { // cache of DH parameters private static final Map dhCache; + // convert DHParameterSpec to SafeDHParameterSpec if its parameters are + // safe primes; validation takes time but should be worthwhile for the + // parameter cache since the parameters may be reused many times. + private static DHParameterSpec makeSafe(DHParameterSpec spec) { + if (spec instanceof SafeDHParameterSpec) { + return spec; + } + + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + + boolean isSafe = (g.equals(BigInteger.TWO) && p.testBit(0) && + p.shiftRight(1).isProbablePrime(100)); + if (isSafe) { + return new SafeDHParameterSpec(p, g, spec.getL()); + } else { + return spec; + } + } + /** * Return cached DSA parameters for the given length combination of * prime and subprime, or null if none are available in the cache. @@ -75,7 +95,7 @@ public final class ParameterCache { * are available in the cache. */ public static DHParameterSpec getCachedDHParameterSpec(int keyLength) { - return dhCache.get(Integer.valueOf(keyLength)); + return dhCache.get(keyLength); } /** @@ -133,7 +153,7 @@ public final class ParameterCache { gen.init(keyLength, random); AlgorithmParameters params = gen.generateParameters(); spec = params.getParameterSpec(DHParameterSpec.class); - dhCache.put(Integer.valueOf(keyLength), spec); + dhCache.put(keyLength, makeSafe(spec)); return spec; } @@ -394,6 +414,12 @@ public final class ParameterCache { // the common generator BigInteger dhG = BigInteger.TWO; + // Self generated following the approach from RFC 2412 Appendix E but + // using random source instead of binary expansion of pi + BigInteger dhP512 = new BigInteger( + "FFFFFFFFFFFFFFFF8B479B3A6E8DE86C294188F0BF2CD86C" + + "DB950ADB36D0F61FD51E46F69C99ED95ABE5A7BBB230A6ED" + + "1D0B4506B5317284FFFFFFFFFFFFFFFF", 16); // // From RFC 7296 @@ -562,24 +588,18 @@ public final class ParameterCache { "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" + "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16); - // use DSA parameters for DH for sizes not defined in RFC 7296, 3526 - dhCache.put(Integer.valueOf(512), new DHParameterSpec(p512, g512, - getDefDHPrivateExpSize(512))); - dhCache.put(Integer.valueOf(768), new DHParameterSpec(dhP768, dhG, - getDefDHPrivateExpSize(768))); - dhCache.put(Integer.valueOf(1024), new DHParameterSpec(dhP1024, dhG, - getDefDHPrivateExpSize(1024))); - dhCache.put(Integer.valueOf(1536), new DHParameterSpec(dhP1536, dhG, - getDefDHPrivateExpSize(1536))); - dhCache.put(Integer.valueOf(2048), new DHParameterSpec(dhP2048, dhG, - getDefDHPrivateExpSize(2048))); - dhCache.put(Integer.valueOf(3072), new DHParameterSpec(dhP3072, dhG, - getDefDHPrivateExpSize(3072))); - dhCache.put(Integer.valueOf(4096), new DHParameterSpec(dhP4096, dhG, - getDefDHPrivateExpSize(4096))); - dhCache.put(Integer.valueOf(6144), new DHParameterSpec(dhP6144, dhG, - getDefDHPrivateExpSize(6144))); - dhCache.put(Integer.valueOf(8192), new DHParameterSpec(dhP8192, dhG, - getDefDHPrivateExpSize(8192))); + // self-generated safe prime + dhCache.put(512, new SafeDHParameterSpec(dhP512, dhG)); + + // from RFC 7296 + dhCache.put(768, new SafeDHParameterSpec(dhP768, dhG)); + dhCache.put(1024, new SafeDHParameterSpec(dhP1024, dhG)); + // from RFC 3526 + dhCache.put(1536, new SafeDHParameterSpec(dhP1536, dhG)); + dhCache.put(2048, new SafeDHParameterSpec(dhP2048, dhG)); + dhCache.put(3072, new SafeDHParameterSpec(dhP3072, dhG)); + dhCache.put(4096, new SafeDHParameterSpec(dhP4096, dhG)); + dhCache.put(6144, new SafeDHParameterSpec(dhP6144, dhG)); + dhCache.put(8192, new SafeDHParameterSpec(dhP8192, dhG)); } } diff --git a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java index 2a8b5209f2e..14f4a9b4d90 100644 --- a/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java +++ b/src/java.base/share/classes/sun/security/ssl/PredefinedDHParameterSpecs.java @@ -33,7 +33,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.spec.DHParameterSpec; -import static sun.security.util.SecurityProviderConstants.getDefDHPrivateExpSize; +import sun.security.util.SafeDHParameterSpec; /** * Predefined default DH ephemeral parameters. @@ -282,8 +282,7 @@ final class PredefinedDHParameterSpecs { BigInteger g = new BigInteger(baseGenerator, 16); int primeLen = p.bitLength(); - DHParameterSpec spec = new DHParameterSpec(p, g, - getDefDHPrivateExpSize(primeLen)); + DHParameterSpec spec = new DHParameterSpec(p, g); defaultParams.put(primeLen, spec); } } else if (SSLLogger.isOn && SSLLogger.isOn("sslctx")) { @@ -295,8 +294,7 @@ final class PredefinedDHParameterSpecs { Map tempFFDHEs = new HashMap<>(); for (BigInteger p : ffdhePrimes) { int primeLen = p.bitLength(); - DHParameterSpec dhps = new DHParameterSpec(p, BigInteger.TWO, - getDefDHPrivateExpSize(primeLen)); + DHParameterSpec dhps = new SafeDHParameterSpec(p, BigInteger.TWO); tempFFDHEs.put(primeLen, dhps); defaultParams.putIfAbsent(primeLen, dhps); } @@ -304,8 +302,8 @@ final class PredefinedDHParameterSpecs { for (BigInteger p : supportedPrimes) { int primeLen = p.bitLength(); if (defaultParams.get(primeLen) == null) { - defaultParams.put(primeLen, new DHParameterSpec(p, - BigInteger.TWO, getDefDHPrivateExpSize(primeLen))); + defaultParams.put(primeLen, new SafeDHParameterSpec(p, + BigInteger.TWO)); } } diff --git a/src/java.base/share/classes/sun/security/util/SafeDHParameterSpec.java b/src/java.base/share/classes/sun/security/util/SafeDHParameterSpec.java new file mode 100644 index 00000000000..6d95b9f498d --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/SafeDHParameterSpec.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022, 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.math.BigInteger; +import javax.crypto.spec.DHParameterSpec; + +/** + * Internal marker class for well-known safe DH parameters. It should + * only be used with trusted callers since it does not have all the needed + * values for validation. + */ + +public final class SafeDHParameterSpec extends DHParameterSpec { + public SafeDHParameterSpec(BigInteger p, BigInteger g) { + super(p, g); + } + + public SafeDHParameterSpec(BigInteger p, BigInteger g, int l) { + super(p, g, l); + } +} diff --git a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java index b3b2c5c9b0b..66c88cd63a9 100644 --- a/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java +++ b/src/java.base/share/classes/sun/security/util/SecurityProviderConstants.java @@ -33,6 +33,7 @@ import java.security.InvalidParameterException; import java.security.ProviderException; import java.security.NoSuchAlgorithmException; import javax.crypto.Cipher; +import javax.crypto.spec.DHParameterSpec; import sun.security.action.GetPropertyAction; /** @@ -102,28 +103,40 @@ public final class SecurityProviderConstants { } } - public static final int getDefDHPrivateExpSize(int dhGroupSize) { - // use 2*security strength as default private exponent size - // as in table 2 of NIST SP 800-57 part 1 rev 5, sec 5.6.1.1 - // and table 25 of NIST SP 800-56A rev 3, appendix D. - if (dhGroupSize >= 15360) { - return 512; - } else if (dhGroupSize >= 8192) { - return 400; - } else if (dhGroupSize >= 7680) { - return 384; - } else if (dhGroupSize >= 6144) { - return 352; - } else if (dhGroupSize >= 4096) { - return 304; - } else if (dhGroupSize >= 3072) { - return 256; - } else if (dhGroupSize >= 2048) { - return 224; + public static final int getDefDHPrivateExpSize(DHParameterSpec spec) { + + int dhGroupSize = spec.getP().bitLength(); + + if (spec instanceof SafeDHParameterSpec) { + // Known safe primes + // use 2*security strength as default private exponent size + // as in table 2 of NIST SP 800-57 part 1 rev 5, sec 5.6.1.1 + // and table 25 of NIST SP 800-56A rev 3, appendix D. + if (dhGroupSize >= 15360) { + return 512; + } else if (dhGroupSize >= 8192) { + return 400; + } else if (dhGroupSize >= 7680) { + return 384; + } else if (dhGroupSize >= 6144) { + return 352; + } else if (dhGroupSize >= 4096) { + return 304; + } else if (dhGroupSize >= 3072) { + return 256; + } else if (dhGroupSize >= 2048) { + return 224; + } else { + // min value for legacy key sizes + return 160; + } } else { - // min value for legacy key sizes - return 160; + // assume the worst and use groupSize/2 as private exp length + // up to 1024-bit and use the same minimum 384 as before + return Math.max((dhGroupSize >= 2048 ? 1024 : dhGroupSize >> 1), + 384); } + } public static final int getDefAESKeySize() {