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 }