/* * Copyright (c) 2003, 2008, 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.security.*; import java.security.spec.AlgorithmParameterSpec; import javax.crypto.*; import static sun.security.pkcs11.TemplateManager.*; import sun.security.pkcs11.wrapper.*; import static sun.security.pkcs11.wrapper.PKCS11Constants.*; /** * KeyGenerator implementation class. This class currently supports * DES, DESede, AES, ARCFOUR, and Blowfish. * * @author Andreas Sterbenz * @since 1.5 */ final class P11KeyGenerator extends KeyGeneratorSpi { // token instance private final Token token; // algorithm name private final String algorithm; // mechanism id private long mechanism; // raw key size in bits, e.g. 64 for DES. Always valid. private int keySize; // bits of entropy in the key, e.g. 56 for DES. Always valid. private int significantKeySize; // keyType (CKK_*), needed for TemplateManager call only. private long keyType; // for determining if both 112 and 168 bits of DESede key lengths // are supported. private boolean supportBothKeySizes; /** * Utility method for checking if the specified key size is valid * and within the supported range. Return the significant key size * upon successful validation. * @param keyGenMech the PKCS#11 key generation mechanism. * @param keySize the to-be-checked key size for this mechanism. * @param token token which provides this mechanism. * @return the significant key size (in bits) corresponding to the * specified key size. * @throws InvalidParameterException if the specified key size is invalid. * @throws ProviderException if this mechanism isn't supported by SunPKCS11 * or underlying native impl. */ static int checkKeySize(long keyGenMech, int keySize, Token token) throws InvalidAlgorithmParameterException, ProviderException { int sigKeySize; switch ((int)keyGenMech) { case (int)CKM_DES_KEY_GEN: if ((keySize != 64) && (keySize != 56)) { throw new InvalidAlgorithmParameterException ("DES key length must be 56 bits"); } sigKeySize = 56; break; case (int)CKM_DES2_KEY_GEN: case (int)CKM_DES3_KEY_GEN: if ((keySize == 112) || (keySize == 128)) { sigKeySize = 112; } else if ((keySize == 168) || (keySize == 192)) { sigKeySize = 168; } else { throw new InvalidAlgorithmParameterException ("DESede key length must be 112, or 168 bits"); } break; default: // Handle all variable-key-length algorithms here CK_MECHANISM_INFO info = null; try { info = token.getMechanismInfo(keyGenMech); } catch (PKCS11Exception p11e) { // Should never happen throw new ProviderException ("Cannot retrieve mechanism info", p11e); } if (info == null) { // XXX Unable to retrieve the supported key length from // the underlying native impl. Skip the checking for now. return keySize; } // PKCS#11 defines these to be in number of bytes except for // RC4 which is in bits. However, some PKCS#11 impls still use // bytes for all mechs, e.g. NSS. We try to detect this // inconsistency if the minKeySize seems unreasonably small. int minKeySize = (int)info.ulMinKeySize; int maxKeySize = (int)info.ulMaxKeySize; if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) { minKeySize = (int)info.ulMinKeySize << 3; maxKeySize = (int)info.ulMaxKeySize << 3; } // Explicitly disallow keys shorter than 40-bits for security if (minKeySize < 40) minKeySize = 40; if (keySize < minKeySize || keySize > maxKeySize) { throw new InvalidAlgorithmParameterException ("Key length must be between " + minKeySize + " and " + maxKeySize + " bits"); } if (keyGenMech == CKM_AES_KEY_GEN) { if ((keySize != 128) && (keySize != 192) && (keySize != 256)) { throw new InvalidAlgorithmParameterException ("AES key length must be " + minKeySize + (maxKeySize >= 192? ", 192":"") + (maxKeySize >= 256? ", or 256":"") + " bits"); } } sigKeySize = keySize; } return sigKeySize; } P11KeyGenerator(Token token, String algorithm, long mechanism) throws PKCS11Exception { super(); this.token = token; this.algorithm = algorithm; this.mechanism = mechanism; if (this.mechanism == CKM_DES3_KEY_GEN) { /* Given the current lookup order specified in SunPKCS11.java, if CKM_DES2_KEY_GEN is used to construct this object, it means that CKM_DES3_KEY_GEN is disabled or unsupported. */ supportBothKeySizes = (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) && (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null)); } setDefaultKeySize(); } // set default keysize and also initialize keyType private void setDefaultKeySize() { switch ((int)mechanism) { case (int)CKM_DES_KEY_GEN: keySize = 64; keyType = CKK_DES; break; case (int)CKM_DES2_KEY_GEN: keySize = 128; keyType = CKK_DES2; break; case (int)CKM_DES3_KEY_GEN: keySize = 192; keyType = CKK_DES3; break; case (int)CKM_AES_KEY_GEN: keySize = 128; keyType = CKK_AES; break; case (int)CKM_RC4_KEY_GEN: keySize = 128; keyType = CKK_RC4; break; case (int)CKM_BLOWFISH_KEY_GEN: keySize = 128; keyType = CKK_BLOWFISH; break; default: throw new ProviderException("Unknown mechanism " + mechanism); } try { significantKeySize = checkKeySize(mechanism, keySize, token); } catch (InvalidAlgorithmParameterException iape) { throw new ProviderException("Unsupported default key size", iape); } } // see JCE spec protected void engineInit(SecureRandom random) { token.ensureValid(); setDefaultKeySize(); } // see JCE spec protected void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { throw new InvalidAlgorithmParameterException ("AlgorithmParameterSpec not supported"); } // see JCE spec protected void engineInit(int keySize, SecureRandom random) { token.ensureValid(); int newSignificantKeySize; try { newSignificantKeySize = checkKeySize(mechanism, keySize, token); } catch (InvalidAlgorithmParameterException iape) { throw (InvalidParameterException) (new InvalidParameterException().initCause(iape)); } if ((mechanism == CKM_DES2_KEY_GEN) || (mechanism == CKM_DES3_KEY_GEN)) { long newMechanism = (newSignificantKeySize == 112 ? CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN); if (mechanism != newMechanism) { if (supportBothKeySizes) { mechanism = newMechanism; // Adjust keyType to reflect the mechanism change keyType = (mechanism == CKM_DES2_KEY_GEN ? CKK_DES2 : CKK_DES3); } else { throw new InvalidParameterException ("Only " + significantKeySize + "-bit DESede is supported"); } } } this.keySize = keySize; this.significantKeySize = newSignificantKeySize; } // see JCE spec protected SecretKey engineGenerateKey() { Session session = null; try { session = token.getObjSession(); CK_ATTRIBUTE[] attributes; switch ((int)keyType) { case (int)CKK_DES: case (int)CKK_DES2: case (int)CKK_DES3: // fixed length, do not specify CKA_VALUE_LEN attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), }; break; default: attributes = new CK_ATTRIBUTE[] { new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3), }; break; } attributes = token.getAttributes (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); long keyID = token.p11.C_GenerateKey (session.id(), new CK_MECHANISM(mechanism), attributes); return P11Key.secretKey (session, keyID, algorithm, significantKeySize, attributes); } catch (PKCS11Exception e) { throw new ProviderException("Could not generate key", e); } finally { token.releaseSession(session); } } }