7196382: PKCS11 provider should support 2048-bit DH
Summary: Query and enforce range checking using the values from native PKCS11 library.
Reviewed-by: xuelei
--- a/jdk/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java Tue Oct 08 10:49:09 2013 +0100
+++ b/jdk/src/share/classes/com/sun/crypto/provider/DHParameterGenerator.java Tue Oct 08 11:07:31 2013 -0700
@@ -58,6 +58,16 @@
// The source of randomness
private SecureRandom random = null;
+ private static void checkKeySize(int keysize)
+ throws InvalidAlgorithmParameterException {
+ if ((keysize != 2048) &&
+ ((keysize < 512) || (keysize > 1024) || (keysize % 64 != 0))) {
+ throw new InvalidAlgorithmParameterException(
+ "Keysize must be multiple of 64 ranging from "
+ + "512 to 1024 (inclusive), or 2048");
+ }
+ }
+
/**
* Initializes this parameter generator for a certain keysize
* and source of randomness.
@@ -67,11 +77,11 @@
* @param random the source of randomness
*/
protected void engineInit(int keysize, SecureRandom random) {
- if ((keysize < 512) || (keysize > 2048) || (keysize % 64 != 0)) {
- throw new InvalidParameterException("Keysize must be multiple "
- + "of 64, and can only range "
- + "from 512 to 2048 "
- + "(inclusive)");
+ // Re-uses DSA parameters and thus have the same range
+ try {
+ checkKeySize(keysize);
+ } catch (InvalidAlgorithmParameterException ex) {
+ throw new InvalidParameterException(ex.getMessage());
}
this.primeSize = keysize;
this.random = random;
@@ -91,31 +101,29 @@
protected void engineInit(AlgorithmParameterSpec genParamSpec,
SecureRandom random)
throws InvalidAlgorithmParameterException {
- if (!(genParamSpec instanceof DHGenParameterSpec)) {
- throw new InvalidAlgorithmParameterException
- ("Inappropriate parameter type");
- }
+ if (!(genParamSpec instanceof DHGenParameterSpec)) {
+ throw new InvalidAlgorithmParameterException
+ ("Inappropriate parameter type");
+ }
- DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec;
+ DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec;
+
+ primeSize = dhParamSpec.getPrimeSize();
+
+ // Re-uses DSA parameters and thus have the same range
+ checkKeySize(primeSize);
- primeSize = dhParamSpec.getPrimeSize();
- if ((primeSize<512) || (primeSize>2048) || (primeSize%64 != 0)) {
- throw new InvalidAlgorithmParameterException
- ("Modulus size must be multiple of 64, and can only range "
- + "from 512 to 2048 (inclusive)");
- }
+ exponentSize = dhParamSpec.getExponentSize();
+ if (exponentSize <= 0) {
+ throw new InvalidAlgorithmParameterException
+ ("Exponent size must be greater than zero");
+ }
- exponentSize = dhParamSpec.getExponentSize();
- if (exponentSize <= 0) {
- throw new InvalidAlgorithmParameterException
- ("Exponent size must be greater than zero");
- }
-
- // Require exponentSize < primeSize
- if (exponentSize >= primeSize) {
- throw new InvalidAlgorithmParameterException
- ("Exponent size must be less than modulus size");
- }
+ // Require exponentSize < primeSize
+ if (exponentSize >= primeSize) {
+ throw new InvalidAlgorithmParameterException
+ ("Exponent size must be less than modulus size");
+ }
}
/**
--- a/jdk/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java Tue Oct 08 10:49:09 2013 +0100
+++ b/jdk/src/share/classes/sun/security/pkcs11/P11KeyPairGenerator.java Tue Oct 08 11:07:31 2013 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -70,20 +70,67 @@
// for RSA, selected or default value of public exponent, always valid
private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;
+ // the supported keysize range of the native PKCS11 library
+ // if the value cannot be retrieved or unspecified, -1 is used.
+ private final int minKeySize;
+ private final int maxKeySize;
+
// SecureRandom instance, if specified in init
private SecureRandom random;
P11KeyPairGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception {
super();
+ int minKeyLen = -1;
+ int maxKeyLen = -1;
+ try {
+ CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism);
+ if (mechInfo != null) {
+ minKeyLen = (int) mechInfo.ulMinKeySize;
+ maxKeyLen = (int) mechInfo.ulMaxKeySize;
+ }
+ } catch (PKCS11Exception p11e) {
+ // Should never happen
+ throw new ProviderException
+ ("Unexpected error while getting mechanism info", p11e);
+ }
+ // set default key sizes and apply our own algorithm-specific limits
+ // override lower limit to disallow unsecure keys being generated
+ // override upper limit to deter DOS attack
+ if (algorithm.equals("EC")) {
+ keySize = 256;
+ if ((minKeyLen == -1) || (minKeyLen < 112)) {
+ minKeyLen = 112;
+ }
+ if ((maxKeyLen == -1) || (maxKeyLen > 2048)) {
+ maxKeyLen = 2048;
+ }
+ } else {
+ // RSA, DH, and DSA
+ keySize = 1024;
+ if ((minKeyLen == -1) || (minKeyLen < 512)) {
+ minKeyLen = 512;
+ }
+ if (algorithm.equals("RSA")) {
+ if ((maxKeyLen == -1) || (maxKeyLen > 64 * 1024)) {
+ maxKeyLen = 64 * 1024;
+ }
+ }
+ }
+
+ // auto-adjust default keysize in case it's out-of-range
+ if ((minKeyLen != -1) && (keySize < minKeyLen)) {
+ keySize = minKeyLen;
+ }
+ if ((maxKeyLen != -1) && (keySize > maxKeyLen)) {
+ keySize = maxKeyLen;
+ }
this.token = token;
this.algorithm = algorithm;
this.mechanism = mechanism;
- if (algorithm.equals("EC")) {
- initialize(256, null);
- } else {
- initialize(1024, null);
- }
+ this.minKeySize = minKeyLen;
+ this.maxKeySize = maxKeyLen;
+ initialize(keySize, null);
}
// see JCA spec
@@ -94,9 +141,7 @@
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidParameterException(e.getMessage());
}
- this.keySize = keySize;
this.params = null;
- this.random = random;
if (algorithm.equals("EC")) {
params = P11ECKeyFactory.getECParameterSpec(keySize);
if (params == null) {
@@ -105,33 +150,35 @@
+ keySize + " bits");
}
}
+ this.keySize = keySize;
+ this.random = random;
}
// see JCA spec
public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException {
token.ensureValid();
+ int tmpKeySize;
if (algorithm.equals("DH")) {
if (params instanceof DHParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("DHParameterSpec required for Diffie-Hellman");
}
- DHParameterSpec dhParams = (DHParameterSpec)params;
- int tmpKeySize = dhParams.getP().bitLength();
- checkKeySize(tmpKeySize, dhParams);
- this.keySize = tmpKeySize;
- this.params = dhParams;
+ DHParameterSpec dhParams = (DHParameterSpec) params;
+ tmpKeySize = dhParams.getP().bitLength();
+ checkKeySize(tmpKeySize, null);
// XXX sanity check params
} else if (algorithm.equals("RSA")) {
if (params instanceof RSAKeyGenParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("RSAKeyGenParameterSpec required for RSA");
}
- RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
- int tmpKeySize = rsaParams.getKeysize();
+ RSAKeyGenParameterSpec rsaParams =
+ (RSAKeyGenParameterSpec) params;
+ tmpKeySize = rsaParams.getKeysize();
checkKeySize(tmpKeySize, rsaParams);
- this.keySize = tmpKeySize;
- this.params = null;
+ // override the supplied params to null
+ params = null;
this.rsaPublicExponent = rsaParams.getPublicExponent();
// XXX sanity check params
} else if (algorithm.equals("DSA")) {
@@ -139,11 +186,9 @@
throw new InvalidAlgorithmParameterException
("DSAParameterSpec required for DSA");
}
- DSAParameterSpec dsaParams = (DSAParameterSpec)params;
- int tmpKeySize = dsaParams.getP().bitLength();
- checkKeySize(tmpKeySize, dsaParams);
- this.keySize = tmpKeySize;
- this.params = dsaParams;
+ DSAParameterSpec dsaParams = (DSAParameterSpec) params;
+ tmpKeySize = dsaParams.getP().bitLength();
+ checkKeySize(tmpKeySize, null);
// XXX sanity check params
} else if (algorithm.equals("EC")) {
ECParameterSpec ecParams;
@@ -155,28 +200,42 @@
("Unsupported curve: " + params);
}
} else if (params instanceof ECGenParameterSpec) {
- String name = ((ECGenParameterSpec)params).getName();
+ String name = ((ECGenParameterSpec) params).getName();
ecParams = P11ECKeyFactory.getECParameterSpec(name);
if (ecParams == null) {
throw new InvalidAlgorithmParameterException
("Unknown curve name: " + name);
}
+ // override the supplied params with the derived one
+ params = ecParams;
} else {
throw new InvalidAlgorithmParameterException
("ECParameterSpec or ECGenParameterSpec required for EC");
}
- int tmpKeySize = ecParams.getCurve().getField().getFieldSize();
- checkKeySize(tmpKeySize, ecParams);
- this.keySize = tmpKeySize;
- this.params = ecParams;
+ tmpKeySize = ecParams.getCurve().getField().getFieldSize();
+ checkKeySize(tmpKeySize, null);
} else {
throw new ProviderException("Unknown algorithm: " + algorithm);
}
+ this.keySize = tmpKeySize;
+ this.params = params;
this.random = random;
}
- private void checkKeySize(int keySize, AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
+ // NOTE: 'params' is only used for checking RSA keys currently.
+ private void checkKeySize(int keySize, RSAKeyGenParameterSpec params)
+ throws InvalidAlgorithmParameterException {
+ // check native range first
+ if ((minKeySize != -1) && (keySize < minKeySize)) {
+ throw new InvalidAlgorithmParameterException(algorithm +
+ " key must be at least " + minKeySize + " bits");
+ }
+ if ((maxKeySize != -1) && (keySize > maxKeySize)) {
+ throw new InvalidAlgorithmParameterException(algorithm +
+ " key must be at most " + maxKeySize + " bits");
+ }
+
+ // check our own algorithm-specific limits also
if (algorithm.equals("EC")) {
if (keySize < 112) {
throw new InvalidAlgorithmParameterException
@@ -187,41 +246,45 @@
throw new InvalidAlgorithmParameterException
("Key size must be at most 2048 bit");
}
- return;
- } else if (algorithm.equals("RSA")) {
- BigInteger tmpExponent = rsaPublicExponent;
- if (params != null) {
- // Already tested for instanceof RSAKeyGenParameterSpec above
- tmpExponent =
- ((RSAKeyGenParameterSpec)params).getPublicExponent();
- }
- try {
- // This provider supports 64K or less.
- RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
- 512, 64 * 1024);
- } catch (InvalidKeyException e) {
- throw new InvalidAlgorithmParameterException(e.getMessage());
+ } else {
+ // RSA, DH, DSA
+ if (keySize < 512) {
+ throw new InvalidAlgorithmParameterException
+ ("Key size must be at least 512 bit");
}
- return;
- }
-
- if (keySize < 512) {
- throw new InvalidAlgorithmParameterException
- ("Key size must be at least 512 bit");
- }
- if (algorithm.equals("DH") && (params != null)) {
- // sanity check, nobody really wants keys this large
- if (keySize > 64 * 1024) {
- throw new InvalidAlgorithmParameterException
- ("Key size must be at most 65536 bit");
- }
- } else {
- // this restriction is in the spec for DSA
- // since we currently use DSA parameters for DH as well,
- // it also applies to DH if no parameters are specified
- if ((keySize > 1024) || ((keySize & 0x3f) != 0)) {
- throw new InvalidAlgorithmParameterException
- ("Key size must be a multiple of 64 and at most 1024 bit");
+ if (algorithm.equals("RSA")) {
+ BigInteger tmpExponent = rsaPublicExponent;
+ if (params != null) {
+ tmpExponent = params.getPublicExponent();
+ }
+ try {
+ // Reuse the checking in SunRsaSign provider.
+ // If maxKeySize is -1, then replace it with
+ // Integer.MAX_VALUE to indicate no limit.
+ RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
+ minKeySize,
+ (maxKeySize==-1? Integer.MAX_VALUE:maxKeySize));
+ } catch (InvalidKeyException e) {
+ throw new InvalidAlgorithmParameterException(e.getMessage());
+ }
+ } else {
+ if (algorithm.equals("DH") && (params != null)) {
+ // sanity check, nobody really wants keys this large
+ if (keySize > 64 * 1024) {
+ throw new InvalidAlgorithmParameterException
+ ("Key size must be at most 65536 bit");
+ }
+ } else {
+ // this restriction is in the spec for DSA
+ // since we currently use DSA parameters for DH as well,
+ // it also applies to DH if no parameters are specified
+ if ((keySize != 2048) &&
+ ((keySize > 1024) || ((keySize & 0x3f) != 0))) {
+ throw new InvalidAlgorithmParameterException(algorithm +
+ " key must be multiples of 64 if less than 1024 bits" +
+ ", or 2048 bits");
+ }
+ }
}
}
}
@@ -325,5 +388,4 @@
token.releaseSession(session);
}
}
-
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/pkcs11/KeyPairGenerator/TestDH2048.java Tue Oct 08 11:07:31 2013 -0700
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2013, 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 7196382
+ * @summary Ensure that 2048-bit DH key pairs can be generated
+ * @author Valerie Peng
+ * @library ..
+ */
+
+import java.io.*;
+import java.util.*;
+
+import java.security.*;
+
+import javax.crypto.*;
+
+public class TestDH2048 extends PKCS11Test {
+
+ private static void checkUnsupportedKeySize(KeyPairGenerator kpg, int ks)
+ throws Exception {
+ try {
+ kpg.initialize(ks);
+ throw new Exception("Expected IPE not thrown for " + ks);
+ } catch (InvalidParameterException ipe) {
+ }
+ }
+
+ public void main(Provider p) throws Exception {
+ if (p.getService("KeyPairGenerator", "DH") == null) {
+ System.out.println("KPG for DH not supported, skipping");
+ return;
+ }
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", p);
+ kpg.initialize(2048);
+ KeyPair kp1 = kpg.generateKeyPair();
+ checkUnsupportedKeySize(kpg, 1536);
+ checkUnsupportedKeySize(kpg, 2176);
+ checkUnsupportedKeySize(kpg, 3072);
+ }
+
+ public static void main(String[] args) throws Exception {
+ main(new TestDH2048());
+ }
+}