0N/A/*
2362N/A * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.security.pkcs11;
0N/A
0N/Aimport java.math.BigInteger;
0N/A
0N/Aimport java.security.*;
0N/Aimport java.security.spec.*;
0N/A
0N/Aimport javax.crypto.spec.DHParameterSpec;
0N/A
0N/Aimport sun.security.provider.ParameterCache;
0N/A
0N/Aimport static sun.security.pkcs11.TemplateManager.*;
0N/Aimport sun.security.pkcs11.wrapper.*;
0N/Aimport static sun.security.pkcs11.wrapper.PKCS11Constants.*;
0N/A
1111N/Aimport sun.security.rsa.RSAKeyFactory;
1111N/A
0N/A/**
0N/A * KeyPairGenerator implementation class. This class currently supports
0N/A * RSA, DSA, DH, and EC.
0N/A *
0N/A * Note that for DSA and DH we rely on the Sun and SunJCE providers to
0N/A * obtain the parameters from.
0N/A *
0N/A * @author Andreas Sterbenz
0N/A * @since 1.5
0N/A */
0N/Afinal class P11KeyPairGenerator extends KeyPairGeneratorSpi {
0N/A
0N/A // token instance
0N/A private final Token token;
0N/A
0N/A // algorithm name
0N/A private final String algorithm;
0N/A
0N/A // mechanism id
0N/A private final long mechanism;
0N/A
0N/A // selected or default key size, always valid
0N/A private int keySize;
0N/A
0N/A // parameters specified via init, if any
0N/A private AlgorithmParameterSpec params;
0N/A
0N/A // for RSA, selected or default value of public exponent, always valid
1111N/A private BigInteger rsaPublicExponent = RSAKeyGenParameterSpec.F4;
0N/A
0N/A // SecureRandom instance, if specified in init
0N/A private SecureRandom random;
0N/A
0N/A P11KeyPairGenerator(Token token, String algorithm, long mechanism)
0N/A throws PKCS11Exception {
0N/A super();
0N/A this.token = token;
0N/A this.algorithm = algorithm;
0N/A this.mechanism = mechanism;
0N/A if (algorithm.equals("EC")) {
0N/A initialize(256, null);
0N/A } else {
0N/A initialize(1024, null);
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A public void initialize(int keySize, SecureRandom random) {
0N/A token.ensureValid();
0N/A try {
1111N/A checkKeySize(keySize, null);
0N/A } catch (InvalidAlgorithmParameterException e) {
0N/A throw new InvalidParameterException(e.getMessage());
0N/A }
0N/A this.keySize = keySize;
0N/A this.params = null;
0N/A this.random = random;
0N/A if (algorithm.equals("EC")) {
0N/A params = P11ECKeyFactory.getECParameterSpec(keySize);
0N/A if (params == null) {
1111N/A throw new InvalidParameterException(
1111N/A "No EC parameters available for key size "
1111N/A + keySize + " bits");
0N/A }
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A public void initialize(AlgorithmParameterSpec params, SecureRandom random)
0N/A throws InvalidAlgorithmParameterException {
0N/A token.ensureValid();
0N/A if (algorithm.equals("DH")) {
0N/A if (params instanceof DHParameterSpec == false) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("DHParameterSpec required for Diffie-Hellman");
0N/A }
0N/A DHParameterSpec dhParams = (DHParameterSpec)params;
1111N/A int tmpKeySize = dhParams.getP().bitLength();
1111N/A checkKeySize(tmpKeySize, dhParams);
1111N/A this.keySize = tmpKeySize;
1111N/A this.params = dhParams;
0N/A // XXX sanity check params
0N/A } else if (algorithm.equals("RSA")) {
0N/A if (params instanceof RSAKeyGenParameterSpec == false) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("RSAKeyGenParameterSpec required for RSA");
0N/A }
0N/A RSAKeyGenParameterSpec rsaParams = (RSAKeyGenParameterSpec)params;
1111N/A int tmpKeySize = rsaParams.getKeysize();
1111N/A checkKeySize(tmpKeySize, rsaParams);
1111N/A this.keySize = tmpKeySize;
0N/A this.params = null;
0N/A this.rsaPublicExponent = rsaParams.getPublicExponent();
0N/A // XXX sanity check params
0N/A } else if (algorithm.equals("DSA")) {
0N/A if (params instanceof DSAParameterSpec == false) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("DSAParameterSpec required for DSA");
0N/A }
0N/A DSAParameterSpec dsaParams = (DSAParameterSpec)params;
1111N/A int tmpKeySize = dsaParams.getP().bitLength();
1111N/A checkKeySize(tmpKeySize, dsaParams);
1111N/A this.keySize = tmpKeySize;
1111N/A this.params = dsaParams;
0N/A // XXX sanity check params
0N/A } else if (algorithm.equals("EC")) {
0N/A ECParameterSpec ecParams;
0N/A if (params instanceof ECParameterSpec) {
1111N/A ecParams = P11ECKeyFactory.getECParameterSpec(
1111N/A (ECParameterSpec)params);
0N/A if (ecParams == null) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Unsupported curve: " + params);
0N/A }
0N/A } else if (params instanceof ECGenParameterSpec) {
0N/A String name = ((ECGenParameterSpec)params).getName();
0N/A ecParams = P11ECKeyFactory.getECParameterSpec(name);
0N/A if (ecParams == null) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Unknown curve name: " + name);
0N/A }
0N/A } else {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("ECParameterSpec or ECGenParameterSpec required for EC");
0N/A }
1111N/A int tmpKeySize = ecParams.getCurve().getField().getFieldSize();
1111N/A checkKeySize(tmpKeySize, ecParams);
1111N/A this.keySize = tmpKeySize;
0N/A this.params = ecParams;
0N/A } else {
0N/A throw new ProviderException("Unknown algorithm: " + algorithm);
0N/A }
0N/A this.random = random;
0N/A }
0N/A
1111N/A private void checkKeySize(int keySize, AlgorithmParameterSpec params)
0N/A throws InvalidAlgorithmParameterException {
0N/A if (algorithm.equals("EC")) {
0N/A if (keySize < 112) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Key size must be at least 112 bit");
0N/A }
0N/A if (keySize > 2048) {
0N/A // sanity check, nobody really wants keys this large
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Key size must be at most 2048 bit");
0N/A }
0N/A return;
1111N/A } else if (algorithm.equals("RSA")) {
1111N/A BigInteger tmpExponent = rsaPublicExponent;
1111N/A if (params != null) {
1111N/A // Already tested for instanceof RSAKeyGenParameterSpec above
1111N/A tmpExponent =
1111N/A ((RSAKeyGenParameterSpec)params).getPublicExponent();
1111N/A }
1111N/A try {
1111N/A // This provider supports 64K or less.
1111N/A RSAKeyFactory.checkKeyLengths(keySize, tmpExponent,
1111N/A 512, 64 * 1024);
1111N/A } catch (InvalidKeyException e) {
1111N/A throw new InvalidAlgorithmParameterException(e.getMessage());
1111N/A }
1111N/A return;
0N/A }
1111N/A
0N/A if (keySize < 512) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Key size must be at least 512 bit");
0N/A }
1111N/A if (algorithm.equals("DH") && (params != null)) {
0N/A // sanity check, nobody really wants keys this large
0N/A if (keySize > 64 * 1024) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Key size must be at most 65536 bit");
0N/A }
0N/A } else {
0N/A // this restriction is in the spec for DSA
0N/A // since we currently use DSA parameters for DH as well,
0N/A // it also applies to DH if no parameters are specified
0N/A if ((keySize > 1024) || ((keySize & 0x3f) != 0)) {
0N/A throw new InvalidAlgorithmParameterException
0N/A ("Key size must be a multiple of 64 and at most 1024 bit");
0N/A }
0N/A }
0N/A }
0N/A
0N/A // see JCA spec
0N/A public KeyPair generateKeyPair() {
0N/A token.ensureValid();
0N/A CK_ATTRIBUTE[] publicKeyTemplate;
0N/A CK_ATTRIBUTE[] privateKeyTemplate;
0N/A long keyType;
0N/A if (algorithm.equals("RSA")) {
0N/A keyType = CKK_RSA;
0N/A publicKeyTemplate = new CK_ATTRIBUTE[] {
0N/A new CK_ATTRIBUTE(CKA_MODULUS_BITS, keySize),
0N/A new CK_ATTRIBUTE(CKA_PUBLIC_EXPONENT, rsaPublicExponent),
0N/A };
0N/A privateKeyTemplate = new CK_ATTRIBUTE[] {
0N/A // empty
0N/A };
0N/A } else if (algorithm.equals("DSA")) {
0N/A keyType = CKK_DSA;
0N/A DSAParameterSpec dsaParams;
0N/A if (params == null) {
0N/A try {
0N/A dsaParams = ParameterCache.getDSAParameterSpec
0N/A (keySize, random);
0N/A } catch (GeneralSecurityException e) {
0N/A throw new ProviderException
0N/A ("Could not generate DSA parameters", e);
0N/A }
0N/A } else {
0N/A dsaParams = (DSAParameterSpec)params;
0N/A }
0N/A publicKeyTemplate = new CK_ATTRIBUTE[] {
0N/A new CK_ATTRIBUTE(CKA_PRIME, dsaParams.getP()),
0N/A new CK_ATTRIBUTE(CKA_SUBPRIME, dsaParams.getQ()),
0N/A new CK_ATTRIBUTE(CKA_BASE, dsaParams.getG()),
0N/A };
0N/A privateKeyTemplate = new CK_ATTRIBUTE[] {
0N/A // empty
0N/A };
0N/A } else if (algorithm.equals("DH")) {
0N/A keyType = CKK_DH;
0N/A DHParameterSpec dhParams;
0N/A int privateBits;
0N/A if (params == null) {
0N/A try {
0N/A dhParams = ParameterCache.getDHParameterSpec
0N/A (keySize, random);
0N/A } catch (GeneralSecurityException e) {
0N/A throw new ProviderException
0N/A ("Could not generate DH parameters", e);
0N/A }
0N/A privateBits = 0;
0N/A } else {
0N/A dhParams = (DHParameterSpec)params;
0N/A privateBits = dhParams.getL();
0N/A }
0N/A if (privateBits <= 0) {
0N/A // XXX find better defaults
0N/A privateBits = (keySize >= 1024) ? 768 : 512;
0N/A }
0N/A publicKeyTemplate = new CK_ATTRIBUTE[] {
0N/A new CK_ATTRIBUTE(CKA_PRIME, dhParams.getP()),
0N/A new CK_ATTRIBUTE(CKA_BASE, dhParams.getG())
0N/A };
0N/A privateKeyTemplate = new CK_ATTRIBUTE[] {
0N/A new CK_ATTRIBUTE(CKA_VALUE_BITS, privateBits),
0N/A };
0N/A } else if (algorithm.equals("EC")) {
0N/A keyType = CKK_EC;
0N/A byte[] encodedParams =
0N/A P11ECKeyFactory.encodeParameters((ECParameterSpec)params);
0N/A publicKeyTemplate = new CK_ATTRIBUTE[] {
0N/A new CK_ATTRIBUTE(CKA_EC_PARAMS, encodedParams),
0N/A };
0N/A privateKeyTemplate = new CK_ATTRIBUTE[] {
0N/A // empty
0N/A };
0N/A } else {
0N/A throw new ProviderException("Unknown algorithm: " + algorithm);
0N/A }
0N/A Session session = null;
0N/A try {
0N/A session = token.getObjSession();
0N/A publicKeyTemplate = token.getAttributes
0N/A (O_GENERATE, CKO_PUBLIC_KEY, keyType, publicKeyTemplate);
0N/A privateKeyTemplate = token.getAttributes
0N/A (O_GENERATE, CKO_PRIVATE_KEY, keyType, privateKeyTemplate);
0N/A long[] keyIDs = token.p11.C_GenerateKeyPair
0N/A (session.id(), new CK_MECHANISM(mechanism),
0N/A publicKeyTemplate, privateKeyTemplate);
0N/A PublicKey publicKey = P11Key.publicKey
0N/A (session, keyIDs[0], algorithm, keySize, publicKeyTemplate);
0N/A PrivateKey privateKey = P11Key.privateKey
0N/A (session, keyIDs[1], algorithm, keySize, privateKeyTemplate);
0N/A return new KeyPair(publicKey, privateKey);
0N/A } catch (PKCS11Exception e) {
0N/A throw new ProviderException(e);
0N/A } finally {
0N/A token.releaseSession(session);
0N/A }
0N/A }
0N/A
0N/A}