1 /* 2 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.pkcs11; 27 28 import java.security.*; 29 import java.security.spec.AlgorithmParameterSpec; 30 31 import javax.crypto.*; 32 33 import static sun.security.pkcs11.TemplateManager.*; 34 import sun.security.pkcs11.wrapper.*; 35 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 36 37 /** 38 * KeyGenerator implementation class. This class currently supports 39 * DES, DESede, AES, ARCFOUR, and Blowfish. 40 * 41 * @author Andreas Sterbenz 42 * @since 1.5 43 */ 44 final class P11KeyGenerator extends KeyGeneratorSpi { 45 46 // token instance 47 private final Token token; 48 49 // algorithm name 50 private final String algorithm; 51 52 // mechanism id 53 private long mechanism; 54 55 // raw key size in bits, e.g. 64 for DES. Always valid. 56 private int keySize; 57 58 // bits of entropy in the key, e.g. 56 for DES. Always valid. 59 private int significantKeySize; 60 61 // keyType (CKK_*), needed for TemplateManager call only. 62 private long keyType; 63 64 // for determining if both 112 and 168 bits of DESede key lengths 65 // are supported. 66 private boolean supportBothKeySizes; 67 68 /** 69 * Utility method for checking if the specified key size is valid 70 * and within the supported range. Return the significant key size 71 * upon successful validation. 72 * @param keyGenMech the PKCS#11 key generation mechanism. 73 * @param keySize the to-be-checked key size for this mechanism. 74 * @param token token which provides this mechanism. 75 * @return the significant key size (in bits) corresponding to the 76 * specified key size. 77 * @throws InvalidParameterException if the specified key size is invalid. 78 * @throws ProviderException if this mechanism isn't supported by SunPKCS11 79 * or underlying native impl. 80 */ 81 static int checkKeySize(long keyGenMech, int keySize, Token token) 82 throws InvalidAlgorithmParameterException, ProviderException { 83 int sigKeySize; 84 switch ((int)keyGenMech) { 85 case (int)CKM_DES_KEY_GEN: 86 if ((keySize != 64) && (keySize != 56)) { 87 throw new InvalidAlgorithmParameterException 88 ("DES key length must be 56 bits"); 89 } 90 sigKeySize = 56; 91 break; 92 case (int)CKM_DES2_KEY_GEN: 93 case (int)CKM_DES3_KEY_GEN: 94 if ((keySize == 112) || (keySize == 128)) { 95 sigKeySize = 112; 96 } else if ((keySize == 168) || (keySize == 192)) { 97 sigKeySize = 168; 98 } else { 99 throw new InvalidAlgorithmParameterException 100 ("DESede key length must be 112, or 168 bits"); 101 } 102 break; 103 default: 104 // Handle all variable-key-length algorithms here 105 CK_MECHANISM_INFO info = null; 106 try { 107 info = token.getMechanismInfo(keyGenMech); 108 } catch (PKCS11Exception p11e) { 109 // Should never happen 110 throw new ProviderException 111 ("Cannot retrieve mechanism info", p11e); 112 } 113 if (info == null) { 114 // XXX Unable to retrieve the supported key length from 115 // the underlying native impl. Skip the checking for now. 116 return keySize; 117 } 118 // PKCS#11 defines these to be in number of bytes except for 119 // RC4 which is in bits. However, some PKCS#11 impls still use 120 // bytes for all mechs, e.g. NSS. We try to detect this 121 // inconsistency if the minKeySize seems unreasonably small. 122 int minKeySize = (int)info.ulMinKeySize; 123 int maxKeySize = (int)info.ulMaxKeySize; 124 if (keyGenMech != CKM_RC4_KEY_GEN || minKeySize < 8) { 125 minKeySize = (int)info.ulMinKeySize << 3; 126 maxKeySize = (int)info.ulMaxKeySize << 3; 127 } 128 // Explicitly disallow keys shorter than 40-bits for security 129 if (minKeySize < 40) minKeySize = 40; 130 if (keySize < minKeySize || keySize > maxKeySize) { 131 throw new InvalidAlgorithmParameterException 132 ("Key length must be between " + minKeySize + 133 " and " + maxKeySize + " bits"); 134 } 135 if (keyGenMech == CKM_AES_KEY_GEN) { 136 if ((keySize != 128) && (keySize != 192) && 137 (keySize != 256)) { 138 throw new InvalidAlgorithmParameterException 139 ("AES key length must be " + minKeySize + 140 (maxKeySize >= 192? ", 192":"") + 141 (maxKeySize >= 256? ", or 256":"") + " bits"); 142 } 143 } 144 sigKeySize = keySize; 145 } 146 return sigKeySize; 147 } 148 149 P11KeyGenerator(Token token, String algorithm, long mechanism) 150 throws PKCS11Exception { 151 super(); 152 this.token = token; 153 this.algorithm = algorithm; 154 this.mechanism = mechanism; 155 156 if (this.mechanism == CKM_DES3_KEY_GEN) { 157 /* Given the current lookup order specified in SunPKCS11.java, 158 if CKM_DES2_KEY_GEN is used to construct this object, it 159 means that CKM_DES3_KEY_GEN is disabled or unsupported. 160 */ 161 supportBothKeySizes = 162 (token.provider.config.isEnabled(CKM_DES2_KEY_GEN) && 163 (token.getMechanismInfo(CKM_DES2_KEY_GEN) != null)); 164 } 165 setDefaultKeySize(); 166 } 167 168 // set default keysize and also initialize keyType 169 private void setDefaultKeySize() { 170 switch ((int)mechanism) { 171 case (int)CKM_DES_KEY_GEN: 172 keySize = 64; 173 keyType = CKK_DES; 174 break; 175 case (int)CKM_DES2_KEY_GEN: 176 keySize = 128; 177 keyType = CKK_DES2; 178 break; 179 case (int)CKM_DES3_KEY_GEN: 180 keySize = 192; 181 keyType = CKK_DES3; 182 break; 183 case (int)CKM_AES_KEY_GEN: 184 keySize = 128; 185 keyType = CKK_AES; 186 break; 187 case (int)CKM_RC4_KEY_GEN: 188 keySize = 128; 189 keyType = CKK_RC4; 190 break; 191 case (int)CKM_BLOWFISH_KEY_GEN: 192 keySize = 128; 193 keyType = CKK_BLOWFISH; 194 break; 195 default: 196 throw new ProviderException("Unknown mechanism " + mechanism); 197 } 198 try { 199 significantKeySize = checkKeySize(mechanism, keySize, token); 200 } catch (InvalidAlgorithmParameterException iape) { 201 throw new ProviderException("Unsupported default key size", iape); 202 } 203 } 204 205 // see JCE spec 206 protected void engineInit(SecureRandom random) { 207 token.ensureValid(); 208 setDefaultKeySize(); 209 } 210 211 // see JCE spec 212 protected void engineInit(AlgorithmParameterSpec params, 213 SecureRandom random) throws InvalidAlgorithmParameterException { 214 throw new InvalidAlgorithmParameterException 215 ("AlgorithmParameterSpec not supported"); 216 } 217 218 // see JCE spec 219 protected void engineInit(int keySize, SecureRandom random) { 220 token.ensureValid(); 221 int newSignificantKeySize; 222 try { 223 newSignificantKeySize = checkKeySize(mechanism, keySize, token); 224 } catch (InvalidAlgorithmParameterException iape) { 225 throw (InvalidParameterException) 226 (new InvalidParameterException().initCause(iape)); 227 } 228 if ((mechanism == CKM_DES2_KEY_GEN) || 229 (mechanism == CKM_DES3_KEY_GEN)) { 230 long newMechanism = (newSignificantKeySize == 112 ? 231 CKM_DES2_KEY_GEN : CKM_DES3_KEY_GEN); 232 if (mechanism != newMechanism) { 233 if (supportBothKeySizes) { 234 mechanism = newMechanism; 235 // Adjust keyType to reflect the mechanism change 236 keyType = (mechanism == CKM_DES2_KEY_GEN ? 237 CKK_DES2 : CKK_DES3); 238 } else { 239 throw new InvalidParameterException 240 ("Only " + significantKeySize + 241 "-bit DESede is supported"); 242 } 243 } 244 } 245 this.keySize = keySize; 246 this.significantKeySize = newSignificantKeySize; 247 } 248 249 // see JCE spec 250 protected SecretKey engineGenerateKey() { 251 Session session = null; 252 try { 253 session = token.getObjSession(); 254 CK_ATTRIBUTE[] attributes; 255 switch ((int)keyType) { 256 case (int)CKK_DES: 257 case (int)CKK_DES2: 258 case (int)CKK_DES3: 259 // fixed length, do not specify CKA_VALUE_LEN 260 attributes = new CK_ATTRIBUTE[] { 261 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), 262 }; 263 break; 264 default: 265 attributes = new CK_ATTRIBUTE[] { 266 new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY), 267 new CK_ATTRIBUTE(CKA_VALUE_LEN, keySize >> 3), 268 }; 269 break; 270 } 271 attributes = token.getAttributes 272 (O_GENERATE, CKO_SECRET_KEY, keyType, attributes); 273 long keyID = token.p11.C_GenerateKey 274 (session.id(), new CK_MECHANISM(mechanism), attributes); 275 return P11Key.secretKey 276 (session, keyID, algorithm, significantKeySize, attributes); 277 } catch (PKCS11Exception e) { 278 throw new ProviderException("Could not generate key", e); 279 } finally { 280 token.releaseSession(session); 281 } 282 } 283 284 }