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:
parent
31fdd1b27c
commit
2f4af22f17
@ -58,6 +58,16 @@ extends AlgorithmParameterGeneratorSpi {
|
||||
// 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 @@ extends AlgorithmParameterGeneratorSpi {
|
||||
* @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 @@ extends AlgorithmParameterGeneratorSpi {
|
||||
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();
|
||||
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)");
|
||||
}
|
||||
primeSize = dhParamSpec.getPrimeSize();
|
||||
|
||||
exponentSize = dhParamSpec.getExponentSize();
|
||||
if (exponentSize <= 0) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Exponent size must be greater than zero");
|
||||
}
|
||||
// Re-uses DSA parameters and thus have the same range
|
||||
checkKeySize(primeSize);
|
||||
|
||||
// Require exponentSize < primeSize
|
||||
if (exponentSize >= primeSize) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Exponent size must be less than modulus size");
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
// 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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
} 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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
+ 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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
("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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
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());
|
||||
}
|
||||
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)) {
|
||||
// RSA, DH, DSA
|
||||
if (keySize < 512) {
|
||||
throw new InvalidAlgorithmParameterException
|
||||
("Key size must be a multiple of 64 and at most 1024 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)) {
|
||||
// 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 @@ final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
|
||||
token.releaseSession(session);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user