/*
* Copyright (c) 2003, 2019, 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.pkcs11;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import javax.crypto.spec.DHParameterSpec;
import sun.security.provider.ParameterCache;
import static sun.security.util.SecurityProviderConstants.*;
import static sun.security.pkcs11.TemplateManager.*;
import sun.security.pkcs11.wrapper.*;
import static sun.security.pkcs11.wrapper.PKCS11Constants.*;
import sun.security.rsa.RSAKeyFactory;
/**
* KeyPairGenerator implementation class. This class currently supports
* RSA, DSA, DH, and EC.
*
* Note that for DSA and DH we rely on the Sun and SunJCE providers to
* obtain the parameters from.
*
* @author Andreas Sterbenz
* @since 1.5
*/
final class P11KeyPairGenerator extends KeyPairGeneratorSpi {
// token instance
private final Token token;
// algorithm name
private final String algorithm;
// mechanism id
private final long mechanism;
// selected or default key size, always valid
private int keySize;
// parameters specified via init, if any
private AlgorithmParameterSpec params;
// 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 mechanism info is unavailable, 0/Integer.MAX_VALUE 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 = 0;
int maxKeyLen = Integer.MAX_VALUE;
try {
CK_MECHANISM_INFO mechInfo = token.getMechanismInfo(mechanism);
if (mechInfo != null) {
minKeyLen = mechInfo.iMinKeySize;
maxKeyLen = mechInfo.iMaxKeySize;
}
} 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 = DEF_EC_KEY_SIZE;
if (minKeyLen < 112) {
minKeyLen = 112;
}
if (maxKeyLen > 2048) {
maxKeyLen = 2048;
}
} else {
if (algorithm.equals("DSA")) {
keySize = DEF_DSA_KEY_SIZE;
} else if (algorithm.equals("RSA")) {
keySize = DEF_RSA_KEY_SIZE;
if (maxKeyLen > 64 * 1024) {
maxKeyLen = 64 * 1024;
}
} else {
keySize = DEF_DH_KEY_SIZE;
}
if (minKeyLen < 512) {
minKeyLen = 512;
}
}
// auto-adjust default keysize in case it's out-of-range
if (keySize < minKeyLen) {
keySize = minKeyLen;
}
if (keySize > maxKeyLen) {
keySize = maxKeyLen;
}
this.token = token;
this.algorithm = algorithm;
this.mechanism = mechanism;
this.minKeySize = minKeyLen;
this.maxKeySize = maxKeyLen;
initialize(keySize, null);
}
// see JCA spec
@Override
public void initialize(int keySize, SecureRandom random) {
token.ensureValid();
try {
checkKeySize(keySize, null);
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidParameterException(e.getMessage());
}
this.params = null;
if (algorithm.equals("EC")) {
params = P11ECKeyFactory.getECParameterSpec(keySize);
if (params == null) {
throw new InvalidParameterException(
"No EC parameters available for key size "
+ keySize + " bits");
}
}
this.keySize = keySize;
this.random = random;
}
// see JCA spec
@Override
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;
tmpKeySize = dhParams.getP().bitLength();
checkKeySize(tmpKeySize, dhParams);
// 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;
tmpKeySize = rsaParams.getKeysize();
checkKeySize(tmpKeySize, rsaParams);
// override the supplied params to null
params = null;
this.rsaPublicExponent = rsaParams.getPublicExponent();
// XXX sanity check params
} else if (algorithm.equals("DSA")) {
if (params instanceof DSAParameterSpec == false) {
throw new InvalidAlgorithmParameterException
("DSAParameterSpec required for DSA");
}
DSAParameterSpec dsaParams = (DSAParameterSpec) params;
tmpKeySize = dsaParams.getP().bitLength();
checkKeySize(tmpKeySize, dsaParams);
// XXX sanity check params
} else if (algorithm.equals("EC")) {
ECParameterSpec ecParams;
if (params instanceof ECParameterSpec) {
ecParams = P11ECKeyFactory.getECParameterSpec(
(ECParameterSpec)params);
if (ecParams == null) {
throw new InvalidAlgorithmParameterException
("Unsupported curve: " + params);
}
} else if (params instanceof ECGenParameterSpec) {
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");
}
tmpKeySize = ecParams.getCurve().getField().getFieldSize();
checkKeySize(tmpKeySize, ecParams);
} 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 {
if (keySize <= 0) {
throw new InvalidAlgorithmParameterException
("key size must be positive, got " + keySize);
}
// check native range first
if (keySize < minKeySize) {
throw new InvalidAlgorithmParameterException(algorithm +
" key must be at least " + minKeySize + " bits. " +
"The specific key size " + keySize + " is not supported");
}
if (keySize > maxKeySize) {
throw new InvalidAlgorithmParameterException(algorithm +
" key must be at most " + maxKeySize + " bits. " +
"The specific key size " + keySize + " is not supported");
}
// check our own algorithm-specific limits also
if (algorithm.equals("EC")) {
if (keySize < 112) {
throw new InvalidAlgorithmParameterException(
"EC key size must be at least 112 bit. " +
"The specific key size " + keySize + " is not supported");
}
if (keySize > 2048) {
// sanity check, nobody really wants keys this large
throw new InvalidAlgorithmParameterException(
"EC key size must be at most 2048 bit. " +
"The specific key size " + keySize + " is not supported");
}
} else {
// RSA, DH, DSA
if (keySize < 512) {
throw new InvalidAlgorithmParameterException(algorithm +
" key size must be at least 512 bit. " +
"The specific key size " + keySize + " is not supported");
}
if (algorithm.equals("RSA")) {
BigInteger tmpExponent = rsaPublicExponent;
if (params != null) {
tmpExponent =
((RSAKeyGenParameterSpec)params).getPublicExponent();
}
try {
RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
minKeySize, maxKeySize);
} catch (InvalidKeyException e) {
throw new InvalidAlgorithmParameterException(e);
}
} else if (algorithm.equals("DH")) {
if (params != null) { // initialized with specified parameters
// sanity check, nobody really wants keys this large
if (keySize > 64 * 1024) {
throw new InvalidAlgorithmParameterException(
"DH key size must be at most 65536 bit. " +
"The specific key size " +
keySize + " is not supported");
}
} else { // default parameters will be used.
// Range is based on the values in
// sun.security.provider.ParameterCache class.
if ((keySize > 8192) || (keySize < 512) ||
((keySize & 0x3f) != 0)) {
throw new InvalidAlgorithmParameterException(
"DH key size must be multiple of 64, and can " +
"only range from 512 to 8192 (inclusive). " +
"The specific key size " +
keySize + " is not supported");
}
DHParameterSpec cache =
ParameterCache.getCachedDHParameterSpec(keySize);
// Except 2048 and 3072, not yet support generation of
// parameters bigger than 1024 bits.
if ((cache == null) && (keySize > 1024)) {
throw new InvalidAlgorithmParameterException(
"Unsupported " + keySize +
"-bit DH parameter generation");
}
}
} else {
// this restriction is in the spec for DSA
if ((keySize != 3072) && (keySize != 2048) &&
((keySize > 1024) || ((keySize & 0x3f) != 0))) {
throw new InvalidAlgorithmParameterException(
"DSA key must be multiples of 64 if less than " +
"1024 bits, or 2048, 3072 bits. " +
"The specific key size " +
keySize + " is not supported");
}
}
}
}
// see JCA spec
@Override
public KeyPair generateKeyPair() {
token.ensureValid();
CK_ATTRIBUTE[] publicKeyTemplate;
CK_ATTRIBUTE[] privateKeyTemplate;
long keyType;
if (algorithm.equals("RSA")) {
keyType = CKK_RSA;
publicKeyTemplate = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize),
new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent),
};
privateKeyTemplate = new CK_ATTRIBUTE[] {
// empty
};
} else if (algorithm.equals("DSA")) {
keyType = CKK_DSA;
DSAParameterSpec dsaParams;
if (params == null) {
try {
dsaParams = ParameterCache.getDSAParameterSpec
(keySize, random);
} catch (GeneralSecurityException e) {
throw new ProviderException
("Could not generate DSA parameters", e);
}
} else {
dsaParams = (DSAParameterSpec)params;
}
publicKeyTemplate = new CK_ATTRIBUTE[] {
new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()),
new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()),
new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()),
};
privateKeyTemplate = new CK_ATTRIBUTE[] {
// empty
};
} else if (algorithm.equals("DH")) {
keyType = CKK_DH;
DHParameterSpec dhParams;
int privateBits;
if (params == null) {
try {
dhParams = ParameterCache.getDHParameterSpec
(keySize, random);
} catch (GeneralSecurityException e) {
throw new ProviderException
("Could not generate DH parameters", e);
}
privateBits = 0;
} else {
dhParams = (DHParameterSpec)params;
privateBits = dhParams.getL();
}
if (privateBits <= 0) {
// XXX find better defaults
privateBits = (keySize >= 1024) ? 768 : 512;
}
publicKeyTemplate = new CK_ATTRIBUTE[] {
/**代码未完, 请加载全部代码(NowJava.com).**/