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 }