1 /*
2  * Copyright (c) 2003, 2019, 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 
P11SecretKeyFactory(Token token, String algorithm)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 
addKeyType(String name, long id)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     // returns the PKCS11 key type of the specified algorithm
90     // no psuedo KeyTypes
getPKCS11KeyType(String algorithm)91     static long getPKCS11KeyType(String algorithm) {
92         long kt = getKeyType(algorithm);
93         if (kt == -1 || kt > PCKK_ANY) {
94             kt = CKK_GENERIC_SECRET;
95         }
96         return kt;
97     }
98 
99     // returns direct lookup result of keyTypes using algorithm
getKeyType(String algorithm)100     static long getKeyType(String algorithm) {
101         Long l = keyTypes.get(algorithm);
102         if (l == null) {
103             algorithm = algorithm.toUpperCase(Locale.ENGLISH);
104             l = keyTypes.get(algorithm);
105             if (l == null) {
106                 if (algorithm.startsWith("HMAC")) {
107                     return PCKK_HMAC;
108                 } else if (algorithm.startsWith("SSLMAC")) {
109                     return PCKK_SSLMAC;
110                 }
111             }
112         }
113         return (l != null) ? l.longValue() : -1;
114     }
115 
116     /**
117      * Convert an arbitrary key of algorithm into a P11Key of provider.
118      * Used in engineTranslateKey(), P11Cipher.init(), and P11Mac.init().
119      */
convertKey(Token token, Key key, String algo)120     static P11Key convertKey(Token token, Key key, String algo)
121             throws InvalidKeyException {
122         return convertKey(token, key, algo, null);
123     }
124 
125     /**
126      * Convert an arbitrary key of algorithm w/ custom attributes into a
127      * P11Key of provider.
128      * Used in P11KeyStore.storeSkey.
129      */
convertKey(Token token, Key key, String algo, CK_ATTRIBUTE[] extraAttrs)130     static P11Key convertKey(Token token, Key key, String algo,
131             CK_ATTRIBUTE[] extraAttrs)
132             throws InvalidKeyException {
133         token.ensureValid();
134         if (key == null) {
135             throw new InvalidKeyException("Key must not be null");
136         }
137         if (key instanceof SecretKey == false) {
138             throw new InvalidKeyException("Key must be a SecretKey");
139         }
140         long algoType;
141         if (algo == null) {
142             algo = key.getAlgorithm();
143             algoType = getKeyType(algo);
144         } else {
145             algoType = getKeyType(algo);
146             long keyAlgorithmType = getKeyType(key.getAlgorithm());
147             if (algoType != keyAlgorithmType) {
148                 if ((algoType == PCKK_HMAC) || (algoType == PCKK_SSLMAC)) {
149                     // ignore key algorithm for MACs
150                 } else {
151                     throw new InvalidKeyException
152                             ("Key algorithm must be " + algo);
153                 }
154             }
155         }
156         if (key instanceof P11Key) {
157             P11Key p11Key = (P11Key)key;
158             if (p11Key.token == token) {
159                 if (extraAttrs != null) {
160                     P11Key newP11Key = null;
161                     Session session = null;
162                     long p11KeyID = p11Key.getKeyID();
163                     try {
164                         session = token.getObjSession();
165                         long newKeyID = token.p11.C_CopyObject(session.id(),
166                             p11KeyID, extraAttrs);
167                         newP11Key = (P11Key) (P11Key.secretKey(session,
168                                 newKeyID, p11Key.algorithm, p11Key.keyLength,
169                                 extraAttrs));
170                     } catch (PKCS11Exception p11e) {
171                         throw new InvalidKeyException
172                                 ("Cannot duplicate the PKCS11 key", p11e);
173                     } finally {
174                         p11Key.releaseKeyID();
175                         token.releaseSession(session);
176                     }
177                     p11Key = newP11Key;
178                 }
179                 return p11Key;
180             }
181         }
182         P11Key p11Key = token.secretCache.get(key);
183         if (p11Key != null) {
184             return p11Key;
185         }
186         if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
187             throw new InvalidKeyException("Encoded format must be RAW");
188         }
189         byte[] encoded = key.getEncoded();
190         p11Key = createKey(token, encoded, algo, algoType, extraAttrs);
191         token.secretCache.put(key, p11Key);
192         return p11Key;
193     }
194 
fixDESParity(byte[] key, int offset)195     static void fixDESParity(byte[] key, int offset) {
196         for (int i = 0; i < 8; i++) {
197             int b = key[offset] & 0xfe;
198             b |= (Integer.bitCount(b) & 1) ^ 1;
199             key[offset++] = (byte)b;
200         }
201     }
202 
createKey(Token token, byte[] encoded, String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)203     private static P11Key createKey(Token token, byte[] encoded,
204             String algorithm, long keyType, CK_ATTRIBUTE[] extraAttrs)
205             throws InvalidKeyException {
206         int n = encoded.length << 3;
207         int keyLength = n;
208         try {
209             switch ((int)keyType) {
210                 case (int)CKK_DES:
211                     keyLength =
212                         P11KeyGenerator.checkKeySize(CKM_DES_KEY_GEN, n, token);
213                     fixDESParity(encoded, 0);
214                     break;
215                 case (int)CKK_DES3:
216                     keyLength =
217                         P11KeyGenerator.checkKeySize(CKM_DES3_KEY_GEN, n, token);
218                     fixDESParity(encoded, 0);
219                     fixDESParity(encoded, 8);
220                     if (keyLength == 112) {
221                         keyType = CKK_DES2;
222                     } else {
223                         keyType = CKK_DES3;
224                         fixDESParity(encoded, 16);
225                     }
226                     break;
227                 case (int)CKK_AES:
228                     keyLength =
229                         P11KeyGenerator.checkKeySize(CKM_AES_KEY_GEN, n, token);
230                     break;
231                 case (int)CKK_RC4:
232                     keyLength =
233                         P11KeyGenerator.checkKeySize(CKM_RC4_KEY_GEN, n, token);
234                     break;
235                 case (int)CKK_BLOWFISH:
236                     keyLength =
237                         P11KeyGenerator.checkKeySize(CKM_BLOWFISH_KEY_GEN, n,
238                         token);
239                     break;
240                 case (int)CKK_GENERIC_SECRET:
241                 case (int)PCKK_TLSPREMASTER:
242                 case (int)PCKK_TLSRSAPREMASTER:
243                 case (int)PCKK_TLSMASTER:
244                     keyType = CKK_GENERIC_SECRET;
245                     break;
246                 case (int)PCKK_SSLMAC:
247                 case (int)PCKK_HMAC:
248                     if (n == 0) {
249                         throw new InvalidKeyException
250                                 ("MAC keys must not be empty");
251                     }
252                     keyType = CKK_GENERIC_SECRET;
253                     break;
254                 default:
255                     throw new InvalidKeyException("Unknown algorithm " +
256                             algorithm);
257             }
258         } catch (InvalidAlgorithmParameterException iape) {
259             throw new InvalidKeyException("Invalid key for " + algorithm,
260                     iape);
261         } catch (ProviderException pe) {
262             throw new InvalidKeyException("Could not create key", pe);
263         }
264         Session session = null;
265         try {
266             CK_ATTRIBUTE[] attributes;
267             if (extraAttrs != null) {
268                 attributes = new CK_ATTRIBUTE[3 + extraAttrs.length];
269                 System.arraycopy(extraAttrs, 0, attributes, 3,
270                         extraAttrs.length);
271             } else {
272                 attributes = new CK_ATTRIBUTE[3];
273             }
274             attributes[0] = new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY);
275             attributes[1] = new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType);
276             attributes[2] = new CK_ATTRIBUTE(CKA_VALUE, encoded);
277             attributes = token.getAttributes
278                 (O_IMPORT, CKO_SECRET_KEY, keyType, attributes);
279             session = token.getObjSession();
280             long keyID = token.p11.C_CreateObject(session.id(), attributes);
281             P11Key p11Key = (P11Key)P11Key.secretKey
282                 (session, keyID, algorithm, keyLength, attributes);
283             return p11Key;
284         } catch (PKCS11Exception e) {
285             throw new InvalidKeyException("Could not create key", e);
286         } finally {
287             token.releaseSession(session);
288         }
289     }
290 
291     // see JCE spec
engineGenerateSecret(KeySpec keySpec)292     protected SecretKey engineGenerateSecret(KeySpec keySpec)
293             throws InvalidKeySpecException {
294         token.ensureValid();
295         if (keySpec == null) {
296             throw new InvalidKeySpecException("KeySpec must not be null");
297         }
298         if (keySpec instanceof SecretKeySpec) {
299             try {
300                 Key key = convertKey(token, (SecretKey)keySpec, algorithm);
301                 return (SecretKey)key;
302             } catch (InvalidKeyException e) {
303                 throw new InvalidKeySpecException(e);
304             }
305         } else if (algorithm.equalsIgnoreCase("DES")) {
306             if (keySpec instanceof DESKeySpec) {
307                 byte[] keyBytes = ((DESKeySpec)keySpec).getKey();
308                 keySpec = new SecretKeySpec(keyBytes, "DES");
309                 return engineGenerateSecret(keySpec);
310             }
311         } else if (algorithm.equalsIgnoreCase("DESede")) {
312             if (keySpec instanceof DESedeKeySpec) {
313                 byte[] keyBytes = ((DESedeKeySpec)keySpec).getKey();
314                 keySpec = new SecretKeySpec(keyBytes, "DESede");
315                 return engineGenerateSecret(keySpec);
316             }
317         }
318         throw new InvalidKeySpecException
319                 ("Unsupported spec: " + keySpec.getClass().getName());
320     }
321 
getKeyBytes(SecretKey key)322     private byte[] getKeyBytes(SecretKey key) throws InvalidKeySpecException {
323         try {
324             key = engineTranslateKey(key);
325             if ("RAW".equalsIgnoreCase(key.getFormat()) == false) {
326                 throw new InvalidKeySpecException
327                     ("Could not obtain key bytes");
328             }
329             byte[] k = key.getEncoded();
330             return k;
331         } catch (InvalidKeyException e) {
332             throw new InvalidKeySpecException(e);
333         }
334     }
335 
336     // see JCE spec
engineGetKeySpec(SecretKey key, Class<?> keySpec)337     protected KeySpec engineGetKeySpec(SecretKey key, Class<?> keySpec)
338             throws InvalidKeySpecException {
339         token.ensureValid();
340         if ((key == null) || (keySpec == null)) {
341             throw new InvalidKeySpecException
342                 ("key and keySpec must not be null");
343         }
344         if (SecretKeySpec.class.isAssignableFrom(keySpec)) {
345             return new SecretKeySpec(getKeyBytes(key), algorithm);
346         } else if (algorithm.equalsIgnoreCase("DES")) {
347             try {
348                 if (DESKeySpec.class.isAssignableFrom(keySpec)) {
349                     return new DESKeySpec(getKeyBytes(key));
350                 }
351             } catch (InvalidKeyException e) {
352                 throw new InvalidKeySpecException(e);
353             }
354         } else if (algorithm.equalsIgnoreCase("DESede")) {
355             try {
356                 if (DESedeKeySpec.class.isAssignableFrom(keySpec)) {
357                     return new DESedeKeySpec(getKeyBytes(key));
358                 }
359             } catch (InvalidKeyException e) {
360                 throw new InvalidKeySpecException(e);
361             }
362         }
363         throw new InvalidKeySpecException
364                 ("Unsupported spec: " + keySpec.getName());
365     }
366 
367     // see JCE spec
engineTranslateKey(SecretKey key)368     protected SecretKey engineTranslateKey(SecretKey key)
369             throws InvalidKeyException {
370         return (SecretKey)convertKey(token, key, algorithm);
371     }
372 
373 }
374