1 /* 2 * Copyright (c) 2003, 2011, 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.util.*; 29 30 import java.security.*; 31 import java.security.spec.*; 32 33 import javax.crypto.*; 34 import javax.crypto.spec.*; 35 36 import static sun.security.pkcs11.TemplateManager.*; 37 import sun.security.pkcs11.wrapper.*; 38 import static sun.security.pkcs11.wrapper.PKCS11Constants.*; 39 40 /** 41 * SecretKeyFactory implementation class. This class currently supports 42 * DES, DESede, AES, ARCFOUR, and Blowfish. 43 * 44 * @author Andreas Sterbenz 45 * @since 1.5 46 */ 47 final class P11SecretKeyFactory extends SecretKeyFactorySpi { 48 49 // token instance 50 private final Token token; 51 52 // algorithm name 53 private final String algorithm; 54 55 P11SecretKeyFactory(Token token, String algorithm) { 56 super(); 57 this.token = token; 58 this.algorithm = algorithm; 59 } 60 61 private static final Map<String,Long> keyTypes; 62 63 static { 64 keyTypes = new HashMap<String,Long>(); 65 addKeyType("RC4", CKK_RC4); 66 addKeyType("ARCFOUR", CKK_RC4); 67 addKeyType("DES", CKK_DES); 68 addKeyType("DESede", CKK_DES3); 69 addKeyType("AES", CKK_AES); 70 addKeyType("Blowfish", CKK_BLOWFISH); 71 72 // we don't implement RC2 or IDEA, but we want to be able to generate 73 // keys for those SSL/TLS ciphersuites. 74 addKeyType("RC2", CKK_RC2); 75 addKeyType("IDEA", CKK_IDEA); 76 77 addKeyType("TlsPremasterSecret", PCKK_TLSPREMASTER); 78 addKeyType("TlsRsaPremasterSecret", PCKK_TLSRSAPREMASTER); 79 addKeyType("TlsMasterSecret", PCKK_TLSMASTER); 80 addKeyType("Generic", CKK_GENERIC_SECRET); 81 } 82 83 private static void addKeyType(String name, long id) { 84 Long l = Long.valueOf(id); 85 keyTypes.put(name, l); 86 keyTypes.put(name.toUpperCase(Locale.ENGLISH), l); 87 } 88 89 static long getKeyType(String algorithm) { 90 Long l = keyTypes.get(algorithm); 91 if (l == null) { 92 algorithm = algorithm.toUpperCase(Locale.ENGLISH); 93 l = keyTypes.get(algorithm); 94 if (l == null) { 95 if (algorithm.startsWith("HMAC")) { 96 return PCKK_HMAC; 97 } else if (algorithm.startsWith("SSLMAC")) { 98 return PCKK_SSLMAC; 99 } 100 } 101 } 102 return (l != null) ? l.longValue() : -1; 103 } 104 105 /** 106 * Convert an arbitrary key of algorithm into a P11Key of provider. 107 * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init(). 108 */ 109 static P11Key convertKey(Token token, Key key, String algo) 110 throws InvalidKeyException { 111 return convertKey(token, key, algo, null); 112 } 113 114 /** 115 * Convert an arbitrary key of algorithm w/ custom attributes into a 116 * P11Key of provider. 117 * Used in P11KeyStore.storeSkey. 118 */ 119 static P11Key convertKey(Token token, Key key, String algo, 120 CK_ATTRIBUTE[] extraAttrs) 121 throws InvalidKeyException { 122 token.ensureValid(); 123 if (key == null) { 124 throw new InvalidKeyException("Key must not be null"); 125 } 126 if (key instanceof SecretKey == false) { 127 throw new InvalidKeyException("Key must be a SecretKey"); 128 } 129 long algoType; 130 if (algo == null) { 131 algo = key.getAlgorithm(); 132 algoType = getKeyType(algo); 133 } else { 134 algoType = getKeyType(algo); 135 long keyAlgorithmType = getKeyType(key.getAlgorithm()); 136 if (algoType != keyAlgorithmType) { 137 if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) { 138 // ignore key algorithm for MACs 139 } else { 140 throw new InvalidKeyException 141 ("Key algorithm must be " + algo); 142 } 143 } 144 } 145 if (key instanceof P11Key) { 146 P11Key p11Key = (P11Key)key; 147 if (p11Key.token == token) { 148 if (extraAttrs != null) { 149 Session session = null; 150 try { 151 session = token.getObjSession(); 152 long newKeyID = token.p11.C_CopyObject(session.id(), 153 p11Key.keyID, extraAttrs); 154 p11Key = (P11Key) (P11Key.secretKey(session, 155 newKeyID, p11Key.algorithm, p11Key.keyLength, 156 extraAttrs)); 157 } catch (PKCS11Exception p11e) { 158 throw new InvalidKeyException 159 ("Cannot duplicate the PKCS11 key", p11e); 160 } finally { 161 token.releaseSession(session); 162 } 163 } 164 return p11Key; 165 } 166 } 167 P11Key p11Key = token.secretCache.get(key); 168 if (p11Key != null) { 169 return p11Key; 170 } 171 if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { 172 throw new InvalidKeyException("Encoded format must be RAW"); 173 } 174 byte[] encoded = key.getEncoded(); 175 p11Key = createKey(token, encoded, algo, algoType, extraAttrs); 176 token.secretCache.put(key, p11Key); 177 return p11Key; 178 } 179 180 static void fixDESParity(byte[] key, int offset) { 181 for (int i = 0; i < 8; i++) { 182 int b = key[offset] & 0xfe; 183 b |= (Integer.bitCount(b) & 1) ^ 1; 184 key[offset++] = (byte)b; 185 } 186 } 187 188 private static P11Key createKey(Token token, byte[] encoded, 189 String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs) 190 throws InvalidKeyException { 191 int n = encoded.length << 3; 192 int keyLength = n; 193 try { 194 switch ((int)keyType) { 195 case (int)CKK_DES: 196 keyLength = 197 P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token); 198 fixDESParity(encoded, 0); 199 break; 200 case (int)CKK_DES3: 201 keyLength = 202 P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token); 203 fixDESParity(encoded, 0); 204 fixDESParity(encoded, 8); 205 if (keyLength == 112) { 206 keyType = CKK_DES2; 207 } else { 208 keyType = CKK_DES3; 209 fixDESParity(encoded, 16); 210 } 211 break; 212 case (int)CKK_AES: 213 keyLength = 214 P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token); 215 break; 216 case (int)CKK_RC4: 217 keyLength = 218 P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token); 219 break; 220 case (int)CKK_BLOWFISH: 221 keyLength = 222 P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n, 223 token); 224 break; 225 case (int)CKK_GENERIC_SECRET: 226 case (int)PCKK_TLSPREMASTER: 227 case (int)PCKK_TLSRSAPREMASTER: 228 case (int)PCKK_TLSMASTER: 229 keyType = CKK_GENERIC_SECRET; 230 break; 231 case (int)PCKK_SSLMAC: 232 case (int)PCKK_HMAC: 233 if (n == 0) { 234 throw new InvalidKeyException 235 ("MAC keys must not be empty"); 236 } 237 keyType = CKK_GENERIC_SECRET; 238 break; 239 default: 240 throw new InvalidKeyException("Unknown algorithm " + 241 algorithm); 242 } 243 } catch (InvalidAlgorithmParameterException iape) { 244 throw new InvalidKeyException("Invalid key for " + algorithm, 245 iape); 246 } catch (ProviderException pe) { 247 throw new InvalidKeyException("Could not create key", pe); 248 } 249 Session session = null; 250 try { 251 CK_ATTRIBUTE[] attributes; 252 if (extraAttrs != null) { 253 attributes = new CK_ATTRIBUTE[3 + extraAttrs.length]; 254 System.arraycopy(extraAttrs, 0, attributes, 3, 255 extraAttrs.length); 256 } else { 257 attributes = new CK_ATTRIBUTE[3]; 258 } 259 attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY); 260 attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType); 261 attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded); 262 attributes = token.getAttributes 263 (O_IMPORT, CKO_SECRET_KEY, keyType, attributes); 264 session = token.getObjSession(); 265 long keyID = token.p11.C_CreateObject(session.id(), attributes); 266 P11Key p11Key = (P11Key)P11Key.secretKey 267 (session, keyID, algorithm, keyLength, attributes); 268 return p11Key; 269 } catch (PKCS11Exception e) { 270 throw new InvalidKeyException("Could not create key", e); 271 } finally { 272 token.releaseSession(session); 273 } 274 } 275 276 // see JCE spec 277 protected SecretKey engineGenerateSecret(KeySpec keySpec) 278 throws InvalidKeySpecException { 279 token.ensureValid(); 280 if (keySpec == null) { 281 throw new InvalidKeySpecException("KeySpec must not be null"); 282 } 283 if (keySpec instanceof SecretKeySpec) { 284 try { 285 Key key = convertKey(token, (SecretKey)keySpec, algorithm); 286 return (SecretKey)key; 287 } catch (InvalidKeyException e) { 288 throw new InvalidKeySpecException(e); 289 } 290 } else if (algorithm.equalsIgnoreCase("DES")) { 291 if (keySpec instanceof DESKeySpec) { 292 byte[] keyBytes = ((DESKeySpec)keySpec).getKey(); 293 keySpec = new SecretKeySpec(keyBytes, "DES"); 294 return engineGenerateSecret(keySpec); 295 } 296 } else if (algorithm.equalsIgnoreCase("DESede")) { 297 if (keySpec instanceof DESedeKeySpec) { 298 byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey(); 299 keySpec = new SecretKeySpec(keyBytes, "DESede"); 300 return engineGenerateSecret(keySpec); 301 } 302 } 303 throw new InvalidKeySpecException 304 ("Unsupported spec: " + keySpec.getClass().getName()); 305 } 306 307 private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException { 308 try { 309 key = engineTranslateKey(key); 310 if ("RAW".equalsIgnoreCase(key.getFormat()) == false) { 311 throw new InvalidKeySpecException 312 ("Could not obtain key bytes"); 313 } 314 byte[] k = key.getEncoded(); 315 return k; 316 } catch (InvalidKeyException e) { 317 throw new InvalidKeySpecException(e); 318 } 319 } 320 321 // see JCE spec 322 protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec) 323 throws InvalidKeySpecException { 324 token.ensureValid(); 325 if ((key == null) || (keySpec == null)) { 326 throw new InvalidKeySpecException 327 ("key and keySpec must not be null"); 328 } 329 if (SecretKeySpec.class.isAssignableFrom(keySpec)) { 330 return new SecretKeySpec(getKeyBytes(key), algorithm); 331 } else if (algorithm.equalsIgnoreCase("DES")) { 332 try { 333 if (DESKeySpec.class.isAssignableFrom(keySpec)) { 334 return new DESKeySpec(getKeyBytes(key)); 335 } 336 } catch (InvalidKeyException e) { 337 throw new InvalidKeySpecException(e); 338 } 339 } else if (algorithm.equalsIgnoreCase("DESede")) { 340 try { 341 if (DESedeKeySpec.class.isAssignableFrom(keySpec)) { 342 return new DESedeKeySpec(getKeyBytes(key)); 343 } 344 } catch (InvalidKeyException e) { 345 throw new InvalidKeySpecException(e); 346 } 347 } 348 throw new InvalidKeySpecException 349 ("Unsupported spec: " + keySpec.getName()); 350 } 351 352 // see JCE spec 353 protected SecretKey engineTranslateKey(SecretKey key) 354 throws InvalidKeyException { 355 return (SecretKey)convertKey(token, key, algorithm); 356 } 357 358 }