7196382: PKCS11 provider should support 2048-bit DH

Query and enforce range checking using the values from native PKCS11 library.

Reviewed-by: xuelei
This commit is contained in:
Valerie Peng 2013-10-08 11:07:31 -07:00
parent 31fdd1b27c
commit 2f4af22f17
3 changed files with 225 additions and 89 deletions

View File

@ -58,6 +58,16 @@ extends AlgorithmParameterGeneratorSpi {
// The source of randomness // The source of randomness
private SecureRandom random = null; 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 * Initializes this parameter generator for a certain keysize
* and source of randomness. * and source of randomness.
@ -67,11 +77,11 @@ extends AlgorithmParameterGeneratorSpi {
* @param random the source of randomness * @param random the source of randomness
*/ */
protected void engineInit(int keysize, SecureRandom random) { protected void engineInit(int keysize, SecureRandom random) {
if ((keysize < 512) || (keysize > 2048) || (keysize % 64 != 0)) { // Re-uses DSA parameters and thus have the same range
throw new InvalidParameterException("Keysize must be multiple " try {
+ "of 64, and can only range " checkKeySize(keysize);
+ "from 512 to 2048 " } catch (InvalidAlgorithmParameterException ex) {
+ "(inclusive)"); throw new InvalidParameterException(ex.getMessage());
} }
this.primeSize = keysize; this.primeSize = keysize;
this.random = random; this.random = random;
@ -99,11 +109,9 @@ extends AlgorithmParameterGeneratorSpi {
DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec; DHGenParameterSpec dhParamSpec = (DHGenParameterSpec)genParamSpec;
primeSize = dhParamSpec.getPrimeSize(); primeSize = dhParamSpec.getPrimeSize();
if ((primeSize<512) || (primeSize>2048) || (primeSize%64 != 0)) {
throw new InvalidAlgorithmParameterException // Re-uses DSA parameters and thus have the same range
("Modulus size must be multiple of 64, and can only range " checkKeySize(primeSize);
+ "from 512 to 2048 (inclusive)");
}
exponentSize = dhParamSpec.getExponentSize(); exponentSize = dhParamSpec.getExponentSize();
if (exponentSize <= 0) { if (exponentSize <= 0) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -70,20 +70,67 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
// for RSA, selected or default value of public exponent, always valid // for RSA, selected or default value of public exponent, always valid
private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4; 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 // SecureRandom instance, if specified in init
private SecureRandom random; private SecureRandom random;
P11KeyPairGenerator(Token token, String algorithm, long mechanism) P11KeyPairGenerator(Token token, String algorithm, long mechanism)
throws PKCS11Exception { throws PKCS11Exception {
super(); 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.token = token;
this.algorithm = algorithm; this.algorithm = algorithm;
this.mechanism = mechanism; this.mechanism = mechanism;
if (algorithm.equals("EC")) { this.minKeySize = minKeyLen;
initialize(256, null); this.maxKeySize = maxKeyLen;
} else { initialize(keySize, null);
initialize(1024, null);
}
} }
// see JCA spec // see JCA spec
@ -94,9 +141,7 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
} catch (InvalidAlgorithmParameterException e) { } catch (InvalidAlgorithmParameterException e) {
throw new InvalidParameterException(e.getMessage()); throw new InvalidParameterException(e.getMessage());
} }
this.keySize = keySize;
this.params = null; this.params = null;
this.random = random;
if (algorithm.equals("EC")) { if (algorithm.equals("EC")) {
params = P11ECKeyFactory.getECParameterSpec(keySize); params = P11ECKeyFactory.getECParameterSpec(keySize);
if (params == null) { if (params == null) {
@ -105,33 +150,35 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
+ keySize + " bits"); + keySize + " bits");
} }
} }
this.keySize = keySize;
this.random = random;
} }
// see JCA spec // see JCA spec
public void initialize(AlgorithmParameterSpec params, SecureRandom random) public void initialize(AlgorithmParameterSpec params, SecureRandom random)
throws InvalidAlgorithmParameterException { throws InvalidAlgorithmParameterException {
token.ensureValid(); token.ensureValid();
int tmpKeySize;
if (algorithm.equals("DH")) { if (algorithm.equals("DH")) {
if (params instanceof DHParameterSpec == false) { if (params instanceof DHParameterSpec == false) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("DHParameterSpec required for Diffie-Hellman"); ("DHParameterSpec required for Diffie-Hellman");
} }
DHParameterSpec dhParams = (DHParameterSpec)params; DHParameterSpec dhParams = (DHParameterSpec) params;
int tmpKeySize = dhParams.getP().bitLength(); tmpKeySize = dhParams.getP().bitLength();
checkKeySize(tmpKeySize, dhParams); checkKeySize(tmpKeySize, null);
this.keySize = tmpKeySize;
this.params = dhParams;
// XXX sanity check params // XXX sanity check params
} else if (algorithm.equals("RSA")) { } else if (algorithm.equals("RSA")) {
if (params instanceof RSAKeyGenParameterSpec == false) { if (params instanceof RSAKeyGenParameterSpec == false) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("RSAKeyGenParameterSpec required for RSA"); ("RSAKeyGenParameterSpec required for RSA");
} }
RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params; RSAKeyGenParameterSpec rsaParams =
int tmpKeySize = rsaParams.getKeysize(); (RSAKeyGenParameterSpec) params;
tmpKeySize = rsaParams.getKeysize();
checkKeySize(tmpKeySize, rsaParams); checkKeySize(tmpKeySize, rsaParams);
this.keySize = tmpKeySize; // override the supplied params to null
this.params = null; params = null;
this.rsaPublicExponent = rsaParams.getPublicExponent(); this.rsaPublicExponent = rsaParams.getPublicExponent();
// XXX sanity check params // XXX sanity check params
} else if (algorithm.equals("DSA")) { } else if (algorithm.equals("DSA")) {
@ -139,11 +186,9 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("DSAParameterSpec required for DSA"); ("DSAParameterSpec required for DSA");
} }
DSAParameterSpec dsaParams = (DSAParameterSpec)params; DSAParameterSpec dsaParams = (DSAParameterSpec) params;
int tmpKeySize = dsaParams.getP().bitLength(); tmpKeySize = dsaParams.getP().bitLength();
checkKeySize(tmpKeySize, dsaParams); checkKeySize(tmpKeySize, null);
this.keySize = tmpKeySize;
this.params = dsaParams;
// XXX sanity check params // XXX sanity check params
} else if (algorithm.equals("EC")) { } else if (algorithm.equals("EC")) {
ECParameterSpec ecParams; ECParameterSpec ecParams;
@ -155,28 +200,42 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
("Unsupported curve: " + params); ("Unsupported curve: " + params);
} }
} else if (params instanceof ECGenParameterSpec) { } else if (params instanceof ECGenParameterSpec) {
String name = ((ECGenParameterSpec)params).getName(); String name = ((ECGenParameterSpec) params).getName();
ecParams = P11ECKeyFactory.getECParameterSpec(name); ecParams = P11ECKeyFactory.getECParameterSpec(name);
if (ecParams == null) { if (ecParams == null) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Unknown curve name: " + name); ("Unknown curve name: " + name);
} }
// override the supplied params with the derived one
params = ecParams;
} else { } else {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("ECParameterSpec or ECGenParameterSpec required for EC"); ("ECParameterSpec or ECGenParameterSpec required for EC");
} }
int tmpKeySize = ecParams.getCurve().getField().getFieldSize(); tmpKeySize = ecParams.getCurve().getField().getFieldSize();
checkKeySize(tmpKeySize, ecParams); checkKeySize(tmpKeySize, null);
this.keySize = tmpKeySize;
this.params = ecParams;
} else { } else {
throw new ProviderException("Unknown algorithm: " + algorithm); throw new ProviderException("Unknown algorithm: " + algorithm);
} }
this.keySize = tmpKeySize;
this.params = params;
this.random = random; this.random = random;
} }
private void checkKeySize(int keySize, AlgorithmParameterSpec params) // NOTE: 'params' is only used for checking RSA keys currently.
private void checkKeySize(int keySize, RSAKeyGenParameterSpec params)
throws InvalidAlgorithmParameterException { 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 (algorithm.equals("EC")) {
if (keySize < 112) { if (keySize < 112) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
@ -187,28 +246,28 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Key size must be at most 2048 bit"); ("Key size must be at most 2048 bit");
} }
return; } else {
} else if (algorithm.equals("RSA")) { // RSA, DH, DSA
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());
}
return;
}
if (keySize < 512) { if (keySize < 512) {
throw new InvalidAlgorithmParameterException throw new InvalidAlgorithmParameterException
("Key size must be at least 512 bit"); ("Key size must be at least 512 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)) { if (algorithm.equals("DH") && (params != null)) {
// sanity check, nobody really wants keys this large // sanity check, nobody really wants keys this large
if (keySize > 64 * 1024) { if (keySize > 64 * 1024) {
@ -219,9 +278,13 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
// this restriction is in the spec for DSA // this restriction is in the spec for DSA
// since we currently use DSA parameters for DH as well, // since we currently use DSA parameters for DH as well,
// it also applies to DH if no parameters are specified // it also applies to DH if no parameters are specified
if ((keySize > 1024) || ((keySize & 0x3f) != 0)) { if ((keySize != 2048) &&
throw new InvalidAlgorithmParameterException ((keySize > 1024) || ((keySize & 0x3f) != 0))) {
("Key size must be a multiple of 64 and at most 1024 bit"); throw new InvalidAlgorithmParameterException(algorithm +
" key must be multiples of 64 if less than 1024 bits" +
", or 2048 bits");
}
}
} }
} }
} }
@ -325,5 +388,4 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
token.releaseSession(session); token.releaseSession(session);
} }
} }
} }

View File

@ -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());
}
}