|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 /* |
|
5 * This file contains functions to manage asymetric keys, (public and |
|
6 * private keys). |
|
7 */ |
|
8 #include "seccomon.h" |
|
9 #include "secmod.h" |
|
10 #include "secmodi.h" |
|
11 #include "secmodti.h" |
|
12 #include "pkcs11.h" |
|
13 #include "pkcs11t.h" |
|
14 #include "pk11func.h" |
|
15 #include "cert.h" |
|
16 #include "key.h" |
|
17 #include "secitem.h" |
|
18 #include "secasn1.h" |
|
19 #include "secoid.h" |
|
20 #include "secerr.h" |
|
21 #include "sslerr.h" |
|
22 #include "sechash.h" |
|
23 |
|
24 #include "secpkcs5.h" |
|
25 #include "blapit.h" |
|
26 |
|
27 static SECItem * |
|
28 pk11_MakeIDFromPublicKey(SECKEYPublicKey *pubKey) |
|
29 { |
|
30 /* set the ID to the public key so we can find it again */ |
|
31 SECItem *pubKeyIndex = NULL; |
|
32 switch (pubKey->keyType) { |
|
33 case rsaKey: |
|
34 pubKeyIndex = &pubKey->u.rsa.modulus; |
|
35 break; |
|
36 case dsaKey: |
|
37 pubKeyIndex = &pubKey->u.dsa.publicValue; |
|
38 break; |
|
39 case dhKey: |
|
40 pubKeyIndex = &pubKey->u.dh.publicValue; |
|
41 break; |
|
42 case ecKey: |
|
43 pubKeyIndex = &pubKey->u.ec.publicValue; |
|
44 break; |
|
45 default: |
|
46 return NULL; |
|
47 } |
|
48 PORT_Assert(pubKeyIndex != NULL); |
|
49 |
|
50 return PK11_MakeIDFromPubKey(pubKeyIndex); |
|
51 } |
|
52 |
|
53 /* |
|
54 * import a public key into the desired slot |
|
55 * |
|
56 * This function takes a public key structure and creates a public key in a |
|
57 * given slot. If isToken is set, then a persistant public key is created. |
|
58 * |
|
59 * Note: it is possible for this function to return a handle for a key which |
|
60 * is persistant, even if isToken is not set. |
|
61 */ |
|
62 CK_OBJECT_HANDLE |
|
63 PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, |
|
64 PRBool isToken) |
|
65 { |
|
66 CK_BBOOL cktrue = CK_TRUE; |
|
67 CK_BBOOL ckfalse = CK_FALSE; |
|
68 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; |
|
69 CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; |
|
70 CK_OBJECT_HANDLE objectID; |
|
71 CK_ATTRIBUTE theTemplate[11]; |
|
72 CK_ATTRIBUTE *signedattr = NULL; |
|
73 CK_ATTRIBUTE *attrs = theTemplate; |
|
74 SECItem *ckaId = NULL; |
|
75 SECItem *pubValue = NULL; |
|
76 int signedcount = 0; |
|
77 int templateCount = 0; |
|
78 SECStatus rv; |
|
79 |
|
80 /* if we already have an object in the desired slot, use it */ |
|
81 if (!isToken && pubKey->pkcs11Slot == slot) { |
|
82 return pubKey->pkcs11ID; |
|
83 } |
|
84 |
|
85 /* free the existing key */ |
|
86 if (pubKey->pkcs11Slot != NULL) { |
|
87 PK11SlotInfo *oSlot = pubKey->pkcs11Slot; |
|
88 if (!PK11_IsPermObject(pubKey->pkcs11Slot,pubKey->pkcs11ID)) { |
|
89 PK11_EnterSlotMonitor(oSlot); |
|
90 (void) PK11_GETTAB(oSlot)->C_DestroyObject(oSlot->session, |
|
91 pubKey->pkcs11ID); |
|
92 PK11_ExitSlotMonitor(oSlot); |
|
93 } |
|
94 PK11_FreeSlot(oSlot); |
|
95 pubKey->pkcs11Slot = NULL; |
|
96 } |
|
97 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass) ); attrs++; |
|
98 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType) ); attrs++; |
|
99 PK11_SETATTRS(attrs, CKA_TOKEN, isToken ? &cktrue : &ckfalse, |
|
100 sizeof(CK_BBOOL) ); attrs++; |
|
101 if (isToken) { |
|
102 ckaId = pk11_MakeIDFromPublicKey(pubKey); |
|
103 if (ckaId == NULL) { |
|
104 PORT_SetError( SEC_ERROR_BAD_KEY ); |
|
105 return CK_INVALID_HANDLE; |
|
106 } |
|
107 PK11_SETATTRS(attrs, CKA_ID, ckaId->data, ckaId->len); attrs++; |
|
108 } |
|
109 |
|
110 /* now import the key */ |
|
111 { |
|
112 switch (pubKey->keyType) { |
|
113 case rsaKey: |
|
114 keyType = CKK_RSA; |
|
115 PK11_SETATTRS(attrs, CKA_WRAP, &cktrue, sizeof(CK_BBOOL) ); attrs++; |
|
116 PK11_SETATTRS(attrs, CKA_ENCRYPT, &cktrue, |
|
117 sizeof(CK_BBOOL) ); attrs++; |
|
118 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL)); attrs++; |
|
119 signedattr = attrs; |
|
120 PK11_SETATTRS(attrs, CKA_MODULUS, pubKey->u.rsa.modulus.data, |
|
121 pubKey->u.rsa.modulus.len); attrs++; |
|
122 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, |
|
123 pubKey->u.rsa.publicExponent.data, |
|
124 pubKey->u.rsa.publicExponent.len); attrs++; |
|
125 break; |
|
126 case dsaKey: |
|
127 keyType = CKK_DSA; |
|
128 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; |
|
129 signedattr = attrs; |
|
130 PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dsa.params.prime.data, |
|
131 pubKey->u.dsa.params.prime.len); attrs++; |
|
132 PK11_SETATTRS(attrs,CKA_SUBPRIME,pubKey->u.dsa.params.subPrime.data, |
|
133 pubKey->u.dsa.params.subPrime.len); attrs++; |
|
134 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dsa.params.base.data, |
|
135 pubKey->u.dsa.params.base.len); attrs++; |
|
136 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dsa.publicValue.data, |
|
137 pubKey->u.dsa.publicValue.len); attrs++; |
|
138 break; |
|
139 case fortezzaKey: |
|
140 keyType = CKK_DSA; |
|
141 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; |
|
142 signedattr = attrs; |
|
143 PK11_SETATTRS(attrs, CKA_PRIME,pubKey->u.fortezza.params.prime.data, |
|
144 pubKey->u.fortezza.params.prime.len); attrs++; |
|
145 PK11_SETATTRS(attrs,CKA_SUBPRIME, |
|
146 pubKey->u.fortezza.params.subPrime.data, |
|
147 pubKey->u.fortezza.params.subPrime.len);attrs++; |
|
148 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.fortezza.params.base.data, |
|
149 pubKey->u.fortezza.params.base.len); attrs++; |
|
150 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.fortezza.DSSKey.data, |
|
151 pubKey->u.fortezza.DSSKey.len); attrs++; |
|
152 break; |
|
153 case dhKey: |
|
154 keyType = CKK_DH; |
|
155 PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; |
|
156 signedattr = attrs; |
|
157 PK11_SETATTRS(attrs, CKA_PRIME, pubKey->u.dh.prime.data, |
|
158 pubKey->u.dh.prime.len); attrs++; |
|
159 PK11_SETATTRS(attrs, CKA_BASE, pubKey->u.dh.base.data, |
|
160 pubKey->u.dh.base.len); attrs++; |
|
161 PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data, |
|
162 pubKey->u.dh.publicValue.len); attrs++; |
|
163 break; |
|
164 case ecKey: |
|
165 keyType = CKK_EC; |
|
166 PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; |
|
167 PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; |
|
168 signedattr = attrs; |
|
169 PK11_SETATTRS(attrs, CKA_EC_PARAMS, |
|
170 pubKey->u.ec.DEREncodedParams.data, |
|
171 pubKey->u.ec.DEREncodedParams.len); attrs++; |
|
172 if (PR_GetEnv("NSS_USE_DECODED_CKA_EC_POINT")) { |
|
173 PK11_SETATTRS(attrs, CKA_EC_POINT, |
|
174 pubKey->u.ec.publicValue.data, |
|
175 pubKey->u.ec.publicValue.len); attrs++; |
|
176 } else { |
|
177 pubValue = SEC_ASN1EncodeItem(NULL, NULL, |
|
178 &pubKey->u.ec.publicValue, |
|
179 SEC_ASN1_GET(SEC_OctetStringTemplate)); |
|
180 if (pubValue == NULL) { |
|
181 if (ckaId) { |
|
182 SECITEM_FreeItem(ckaId,PR_TRUE); |
|
183 } |
|
184 return CK_INVALID_HANDLE; |
|
185 } |
|
186 PK11_SETATTRS(attrs, CKA_EC_POINT, |
|
187 pubValue->data, pubValue->len); attrs++; |
|
188 } |
|
189 break; |
|
190 default: |
|
191 if (ckaId) { |
|
192 SECITEM_FreeItem(ckaId,PR_TRUE); |
|
193 } |
|
194 PORT_SetError( SEC_ERROR_BAD_KEY ); |
|
195 return CK_INVALID_HANDLE; |
|
196 } |
|
197 |
|
198 templateCount = attrs - theTemplate; |
|
199 signedcount = attrs - signedattr; |
|
200 PORT_Assert(templateCount <= (sizeof(theTemplate)/sizeof(CK_ATTRIBUTE))); |
|
201 for (attrs=signedattr; signedcount; attrs++, signedcount--) { |
|
202 pk11_SignedToUnsigned(attrs); |
|
203 } |
|
204 rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, theTemplate, |
|
205 templateCount, isToken, &objectID); |
|
206 if (ckaId) { |
|
207 SECITEM_FreeItem(ckaId,PR_TRUE); |
|
208 } |
|
209 if (pubValue) { |
|
210 SECITEM_FreeItem(pubValue,PR_TRUE); |
|
211 } |
|
212 if ( rv != SECSuccess) { |
|
213 return CK_INVALID_HANDLE; |
|
214 } |
|
215 } |
|
216 |
|
217 pubKey->pkcs11ID = objectID; |
|
218 pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); |
|
219 |
|
220 return objectID; |
|
221 } |
|
222 |
|
223 /* |
|
224 * take an attribute and copy it into a secitem |
|
225 */ |
|
226 static CK_RV |
|
227 pk11_Attr2SecItem(PLArenaPool *arena, const CK_ATTRIBUTE *attr, SECItem *item) |
|
228 { |
|
229 item->data = NULL; |
|
230 |
|
231 (void)SECITEM_AllocItem(arena, item, attr->ulValueLen); |
|
232 if (item->data == NULL) { |
|
233 return CKR_HOST_MEMORY; |
|
234 } |
|
235 PORT_Memcpy(item->data, attr->pValue, item->len); |
|
236 return CKR_OK; |
|
237 } |
|
238 |
|
239 |
|
240 /* |
|
241 * get a curve length from a set of ecParams. |
|
242 * |
|
243 * We need this so we can reliably determine if the ecPoint passed to us |
|
244 * was encoded or not. With out this, for many curves, we would incorrectly |
|
245 * identify an unencoded curve as an encoded curve 1 in 65536 times, and for |
|
246 * a few we would make that same mistake 1 in 32768 times. These are bad |
|
247 * numbers since they are rare enough to pass tests, but common enough to |
|
248 * be tripped over in the field. |
|
249 * |
|
250 * This function will only work for curves we recognized as of March 2009. |
|
251 * The assumption is curves in use after March of 2009 would be supplied by |
|
252 * PKCS #11 modules that already pass the correct encoding to us. |
|
253 * |
|
254 * Point length = (Roundup(curveLenInBits/8)*2+1) |
|
255 */ |
|
256 static int |
|
257 pk11_get_EC_PointLenInBytes(PLArenaPool *arena, const SECItem *ecParams) |
|
258 { |
|
259 SECItem oid; |
|
260 SECOidTag tag; |
|
261 SECStatus rv; |
|
262 |
|
263 /* decode the OID tag */ |
|
264 rv = SEC_QuickDERDecodeItem(arena, &oid, |
|
265 SEC_ASN1_GET(SEC_ObjectIDTemplate), ecParams); |
|
266 if (rv != SECSuccess) { |
|
267 /* could be explict curves, allow them to work if the |
|
268 * PKCS #11 module support them. If we try to parse the |
|
269 * explicit curve value in the future, we may return -1 here |
|
270 * to indicate an invalid parameter if the explicit curve |
|
271 * decode fails. */ |
|
272 return 0; |
|
273 } |
|
274 |
|
275 tag = SECOID_FindOIDTag(&oid); |
|
276 switch (tag) { |
|
277 case SEC_OID_SECG_EC_SECP112R1: |
|
278 case SEC_OID_SECG_EC_SECP112R2: |
|
279 return 29; /* curve len in bytes = 14 bytes */ |
|
280 case SEC_OID_SECG_EC_SECT113R1: |
|
281 case SEC_OID_SECG_EC_SECT113R2: |
|
282 return 31; /* curve len in bytes = 15 bytes */ |
|
283 case SEC_OID_SECG_EC_SECP128R1: |
|
284 case SEC_OID_SECG_EC_SECP128R2: |
|
285 return 33; /* curve len in bytes = 16 bytes */ |
|
286 case SEC_OID_SECG_EC_SECT131R1: |
|
287 case SEC_OID_SECG_EC_SECT131R2: |
|
288 return 35; /* curve len in bytes = 17 bytes */ |
|
289 case SEC_OID_SECG_EC_SECP160K1: |
|
290 case SEC_OID_SECG_EC_SECP160R1: |
|
291 case SEC_OID_SECG_EC_SECP160R2: |
|
292 return 41; /* curve len in bytes = 20 bytes */ |
|
293 case SEC_OID_SECG_EC_SECT163K1: |
|
294 case SEC_OID_SECG_EC_SECT163R1: |
|
295 case SEC_OID_SECG_EC_SECT163R2: |
|
296 case SEC_OID_ANSIX962_EC_C2PNB163V1: |
|
297 case SEC_OID_ANSIX962_EC_C2PNB163V2: |
|
298 case SEC_OID_ANSIX962_EC_C2PNB163V3: |
|
299 return 43; /* curve len in bytes = 21 bytes */ |
|
300 case SEC_OID_ANSIX962_EC_C2PNB176V1: |
|
301 return 45; /* curve len in bytes = 22 bytes */ |
|
302 case SEC_OID_ANSIX962_EC_C2TNB191V1: |
|
303 case SEC_OID_ANSIX962_EC_C2TNB191V2: |
|
304 case SEC_OID_ANSIX962_EC_C2TNB191V3: |
|
305 case SEC_OID_SECG_EC_SECP192K1: |
|
306 case SEC_OID_ANSIX962_EC_PRIME192V1: |
|
307 case SEC_OID_ANSIX962_EC_PRIME192V2: |
|
308 case SEC_OID_ANSIX962_EC_PRIME192V3: |
|
309 return 49; /*curve len in bytes = 24 bytes */ |
|
310 case SEC_OID_SECG_EC_SECT193R1: |
|
311 case SEC_OID_SECG_EC_SECT193R2: |
|
312 return 51; /*curve len in bytes = 25 bytes */ |
|
313 case SEC_OID_ANSIX962_EC_C2PNB208W1: |
|
314 return 53; /*curve len in bytes = 26 bytes */ |
|
315 case SEC_OID_SECG_EC_SECP224K1: |
|
316 case SEC_OID_SECG_EC_SECP224R1: |
|
317 return 57; /*curve len in bytes = 28 bytes */ |
|
318 case SEC_OID_SECG_EC_SECT233K1: |
|
319 case SEC_OID_SECG_EC_SECT233R1: |
|
320 case SEC_OID_SECG_EC_SECT239K1: |
|
321 case SEC_OID_ANSIX962_EC_PRIME239V1: |
|
322 case SEC_OID_ANSIX962_EC_PRIME239V2: |
|
323 case SEC_OID_ANSIX962_EC_PRIME239V3: |
|
324 case SEC_OID_ANSIX962_EC_C2TNB239V1: |
|
325 case SEC_OID_ANSIX962_EC_C2TNB239V2: |
|
326 case SEC_OID_ANSIX962_EC_C2TNB239V3: |
|
327 return 61; /*curve len in bytes = 30 bytes */ |
|
328 case SEC_OID_ANSIX962_EC_PRIME256V1: |
|
329 case SEC_OID_SECG_EC_SECP256K1: |
|
330 return 65; /*curve len in bytes = 32 bytes */ |
|
331 case SEC_OID_ANSIX962_EC_C2PNB272W1: |
|
332 return 69; /*curve len in bytes = 34 bytes */ |
|
333 case SEC_OID_SECG_EC_SECT283K1: |
|
334 case SEC_OID_SECG_EC_SECT283R1: |
|
335 return 73; /*curve len in bytes = 36 bytes */ |
|
336 case SEC_OID_ANSIX962_EC_C2PNB304W1: |
|
337 return 77; /*curve len in bytes = 38 bytes */ |
|
338 case SEC_OID_ANSIX962_EC_C2TNB359V1: |
|
339 return 91; /*curve len in bytes = 45 bytes */ |
|
340 case SEC_OID_ANSIX962_EC_C2PNB368W1: |
|
341 return 93; /*curve len in bytes = 46 bytes */ |
|
342 case SEC_OID_SECG_EC_SECP384R1: |
|
343 return 97; /*curve len in bytes = 48 bytes */ |
|
344 case SEC_OID_SECG_EC_SECT409K1: |
|
345 case SEC_OID_SECG_EC_SECT409R1: |
|
346 return 105; /*curve len in bytes = 52 bytes */ |
|
347 case SEC_OID_ANSIX962_EC_C2TNB431R1: |
|
348 return 109; /*curve len in bytes = 54 bytes */ |
|
349 case SEC_OID_SECG_EC_SECP521R1: |
|
350 return 133; /*curve len in bytes = 66 bytes */ |
|
351 case SEC_OID_SECG_EC_SECT571K1: |
|
352 case SEC_OID_SECG_EC_SECT571R1: |
|
353 return 145; /*curve len in bytes = 72 bytes */ |
|
354 /* unknown or unrecognized OIDs. return unknown length */ |
|
355 default: |
|
356 break; |
|
357 } |
|
358 return 0; |
|
359 } |
|
360 |
|
361 /* |
|
362 * returns the decoded point. In some cases the point may already be decoded. |
|
363 * this function tries to detect those cases and return the point in |
|
364 * publicKeyValue. In other cases it's DER encoded. In those cases the point |
|
365 * is first decoded and returned. Space for the point is allocated out of |
|
366 * the passed in arena. |
|
367 */ |
|
368 static CK_RV |
|
369 pk11_get_Decoded_ECPoint(PLArenaPool *arena, const SECItem *ecParams, |
|
370 const CK_ATTRIBUTE *ecPoint, SECItem *publicKeyValue) |
|
371 { |
|
372 SECItem encodedPublicValue; |
|
373 SECStatus rv; |
|
374 int keyLen; |
|
375 |
|
376 if (ecPoint->ulValueLen == 0) { |
|
377 return CKR_ATTRIBUTE_VALUE_INVALID; |
|
378 } |
|
379 |
|
380 /* |
|
381 * The PKCS #11 spec requires ecPoints to be encoded as a DER OCTET String. |
|
382 * NSS has mistakenly passed unencoded values, and some PKCS #11 vendors |
|
383 * followed that mistake. Now we need to detect which encoding we were |
|
384 * passed in. The task is made more complicated by the fact the the |
|
385 * DER encoding byte (SEC_ASN_OCTET_STRING) is the same as the |
|
386 * EC_POINT_FORM_UNCOMPRESSED byte (0x04), so we can't use that to |
|
387 * determine which curve we are using. |
|
388 */ |
|
389 |
|
390 /* get the expected key length for the passed in curve. |
|
391 * pk11_get_EC_PointLenInBytes only returns valid values for curves |
|
392 * NSS has traditionally recognized. If the curve is not recognized, |
|
393 * it will return '0', and we have to figure out if the key was |
|
394 * encoded or not heuristically. If the ecParams are invalid, it |
|
395 * will return -1 for the keyLen. |
|
396 */ |
|
397 keyLen = pk11_get_EC_PointLenInBytes(arena, ecParams); |
|
398 if (keyLen < 0) { |
|
399 return CKR_ATTRIBUTE_VALUE_INVALID; |
|
400 } |
|
401 |
|
402 |
|
403 /* If the point is uncompressed and the lengths match, it |
|
404 * must be an unencoded point */ |
|
405 if ((*((char *)ecPoint->pValue) == EC_POINT_FORM_UNCOMPRESSED) |
|
406 && (ecPoint->ulValueLen == keyLen)) { |
|
407 return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue); |
|
408 } |
|
409 |
|
410 /* now assume the key passed to us was encoded and decode it */ |
|
411 if (*((char *)ecPoint->pValue) == SEC_ASN1_OCTET_STRING) { |
|
412 /* OK, now let's try to decode it and see if it's valid */ |
|
413 encodedPublicValue.data = ecPoint->pValue; |
|
414 encodedPublicValue.len = ecPoint->ulValueLen; |
|
415 rv = SEC_QuickDERDecodeItem(arena, publicKeyValue, |
|
416 SEC_ASN1_GET(SEC_OctetStringTemplate), &encodedPublicValue); |
|
417 |
|
418 /* it coded correctly & we know the key length (and they match) |
|
419 * then we are done, return the results. */ |
|
420 if (keyLen && rv == SECSuccess && publicKeyValue->len == keyLen) { |
|
421 return CKR_OK; |
|
422 } |
|
423 |
|
424 /* if we know the key length, one of the above tests should have |
|
425 * succeded. If it doesn't the module gave us bad data */ |
|
426 if (keyLen) { |
|
427 return CKR_ATTRIBUTE_VALUE_INVALID; |
|
428 } |
|
429 |
|
430 |
|
431 /* We don't know the key length, so we don't know deterministically |
|
432 * which encoding was used. We now will try to pick the most likely |
|
433 * form that's correct, with a preference for the encoded form if we |
|
434 * can't determine for sure. We do this by checking the key we got |
|
435 * back from SEC_QuickDERDecodeItem for defects. If no defects are |
|
436 * found, we assume the encoded parameter was was passed to us. |
|
437 * our defect tests include: |
|
438 * 1) it didn't decode. |
|
439 * 2) The decode key had an invalid length (must be odd). |
|
440 * 3) The decoded key wasn't an UNCOMPRESSED key. |
|
441 * 4) The decoded key didn't include the entire encoded block |
|
442 * except the DER encoding values. (fixing DER length to one |
|
443 * particular value). |
|
444 */ |
|
445 if ((rv != SECSuccess) |
|
446 || ((publicKeyValue->len & 1) != 1) |
|
447 || (publicKeyValue->data[0] != EC_POINT_FORM_UNCOMPRESSED) |
|
448 || (PORT_Memcmp(&encodedPublicValue.data[encodedPublicValue.len - |
|
449 publicKeyValue->len], publicKeyValue->data, |
|
450 publicKeyValue->len) != 0)) { |
|
451 /* The decoded public key was flawed, the original key must have |
|
452 * already been in decoded form. Do a quick sanity check then |
|
453 * return the original key value. |
|
454 */ |
|
455 if ((encodedPublicValue.len & 1) == 0) { |
|
456 return CKR_ATTRIBUTE_VALUE_INVALID; |
|
457 } |
|
458 return pk11_Attr2SecItem(arena, ecPoint, publicKeyValue); |
|
459 } |
|
460 |
|
461 /* as best we can figure, the passed in key was encoded, and we've |
|
462 * now decoded it. Note: there is a chance this could be wrong if the |
|
463 * following conditions hold: |
|
464 * 1) The first byte or bytes of the X point looks like a valid length |
|
465 * of precisely the right size (2*curveSize -1). this means for curves |
|
466 * less than 512 bits (64 bytes), this will happen 1 in 256 times*. |
|
467 * for curves between 512 and 1024, this will happen 1 in 65,536 times* |
|
468 * for curves between 1024 and 256K this will happen 1 in 16 million* |
|
469 * 2) The length of the 'DER length field' is odd |
|
470 * (making both the encoded and decode |
|
471 * values an odd length. this is true of all curves less than 512, |
|
472 * as well as curves between 1024 and 256K). |
|
473 * 3) The X[length of the 'DER length field'] == 0x04, 1 in 256. |
|
474 * |
|
475 * (* assuming all values are equally likely in the first byte, |
|
476 * This isn't true if the curve length is not a multiple of 8. In these |
|
477 * cases, if the DER length is possible, it's more likely, |
|
478 * if it's not possible, then we have no false decodes). |
|
479 * |
|
480 * For reference here are the odds for the various curves we currently |
|
481 * have support for (and the only curves SSL will negotiate at this |
|
482 * time). NOTE: None of the supported curves will show up here |
|
483 * because we return a valid length for all of these curves. |
|
484 * The only way to get here is to have some application (not SSL) |
|
485 * which supports some unknown curve and have some vendor supplied |
|
486 * PKCS #11 module support that curve. NOTE: in this case, one |
|
487 * presumes that that pkcs #11 module is likely to be using the |
|
488 * correct encodings. |
|
489 * |
|
490 * Prime Curves (GFp): |
|
491 * Bit False Odds of |
|
492 * Size DER Len False Decode Positive |
|
493 * 112 27 1 in 65536 |
|
494 * 128 31 1 in 65536 |
|
495 * 160 39 1 in 65536 |
|
496 * 192 47 1 in 65536 |
|
497 * 224 55 1 in 65536 |
|
498 * 239 59 1 in 32768 (top byte can only be 0-127) |
|
499 * 256 63 1 in 65536 |
|
500 * 521 129,131 0 (decoded value would be even) |
|
501 * |
|
502 * Binary curves (GF2m). |
|
503 * Bit False Odds of |
|
504 * Size DER Len False Decode Positive |
|
505 * 131 33 0 (top byte can only be 0-7) |
|
506 * 163 41 0 (top byte can only be 0-7) |
|
507 * 176 43 1 in 65536 |
|
508 * 191 47 1 in 32768 (top byte can only be 0-127) |
|
509 * 193 49 0 (top byte can only be 0-1) |
|
510 * 208 51 1 in 65536 |
|
511 * 233 59 0 (top byte can only be 0-1) |
|
512 * 239 59 1 in 32768 (top byte can only be 0-127) |
|
513 * 272 67 1 in 65536 |
|
514 * 283 71 0 (top byte can only be 0-7) |
|
515 * 304 75 1 in 65536 |
|
516 * 359 89 1 in 32768 (top byte can only be 0-127) |
|
517 * 368 91 1 in 65536 |
|
518 * 409 103 0 (top byte can only be 0-1) |
|
519 * 431 107 1 in 32768 (top byte can only be 0-127) |
|
520 * 571 129,143 0 (decoded value would be even) |
|
521 * |
|
522 */ |
|
523 |
|
524 return CKR_OK; |
|
525 } |
|
526 |
|
527 /* In theory, we should handle the case where the curve == 0 and |
|
528 * the first byte is EC_POINT_FORM_UNCOMPRESSED, (which would be |
|
529 * handled by doing a santity check on the key length and returning |
|
530 * pk11_Attr2SecItem() to copy the ecPoint to the publicKeyValue). |
|
531 * |
|
532 * This test is unnecessary, however, due to the fact that |
|
533 * EC_POINT_FORM_UNCOMPRESSED == SEC_ASIN1_OCTET_STRING, that case is |
|
534 * handled in the above if. That means if we get here, the initial |
|
535 * byte of our ecPoint value was invalid, so we can safely return. |
|
536 * invalid attribute. |
|
537 */ |
|
538 |
|
539 return CKR_ATTRIBUTE_VALUE_INVALID; |
|
540 } |
|
541 |
|
542 /* |
|
543 * extract a public key from a slot and id |
|
544 */ |
|
545 SECKEYPublicKey * |
|
546 PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) |
|
547 { |
|
548 CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY; |
|
549 PLArenaPool *arena; |
|
550 PLArenaPool *tmp_arena; |
|
551 SECKEYPublicKey *pubKey; |
|
552 int templateCount = 0; |
|
553 CK_KEY_TYPE pk11KeyType; |
|
554 CK_RV crv; |
|
555 CK_ATTRIBUTE template[8]; |
|
556 CK_ATTRIBUTE *attrs= template; |
|
557 CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value; |
|
558 CK_ATTRIBUTE *ecparams; |
|
559 |
|
560 /* if we didn't know the key type, get it */ |
|
561 if (keyType== nullKey) { |
|
562 |
|
563 pk11KeyType = PK11_ReadULongAttribute(slot,id,CKA_KEY_TYPE); |
|
564 if (pk11KeyType == CK_UNAVAILABLE_INFORMATION) { |
|
565 return NULL; |
|
566 } |
|
567 switch (pk11KeyType) { |
|
568 case CKK_RSA: |
|
569 keyType = rsaKey; |
|
570 break; |
|
571 case CKK_DSA: |
|
572 keyType = dsaKey; |
|
573 break; |
|
574 case CKK_DH: |
|
575 keyType = dhKey; |
|
576 break; |
|
577 case CKK_EC: |
|
578 keyType = ecKey; |
|
579 break; |
|
580 default: |
|
581 PORT_SetError( SEC_ERROR_BAD_KEY ); |
|
582 return NULL; |
|
583 } |
|
584 } |
|
585 |
|
586 |
|
587 /* now we need to create space for the public key */ |
|
588 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); |
|
589 if (arena == NULL) return NULL; |
|
590 tmp_arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); |
|
591 if (tmp_arena == NULL) { |
|
592 PORT_FreeArena (arena, PR_FALSE); |
|
593 return NULL; |
|
594 } |
|
595 |
|
596 |
|
597 pubKey = (SECKEYPublicKey *) |
|
598 PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); |
|
599 if (pubKey == NULL) { |
|
600 PORT_FreeArena (arena, PR_FALSE); |
|
601 PORT_FreeArena (tmp_arena, PR_FALSE); |
|
602 return NULL; |
|
603 } |
|
604 |
|
605 pubKey->arena = arena; |
|
606 pubKey->keyType = keyType; |
|
607 pubKey->pkcs11Slot = PK11_ReferenceSlot(slot); |
|
608 pubKey->pkcs11ID = id; |
|
609 PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, |
|
610 sizeof(keyClass)); attrs++; |
|
611 PK11_SETATTRS(attrs, CKA_KEY_TYPE, &pk11KeyType, |
|
612 sizeof(pk11KeyType) ); attrs++; |
|
613 switch (pubKey->keyType) { |
|
614 case rsaKey: |
|
615 modulus = attrs; |
|
616 PK11_SETATTRS(attrs, CKA_MODULUS, NULL, 0); attrs++; |
|
617 exponent = attrs; |
|
618 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, NULL, 0); attrs++; |
|
619 |
|
620 templateCount = attrs - template; |
|
621 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); |
|
622 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); |
|
623 if (crv != CKR_OK) break; |
|
624 |
|
625 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_RSA)) { |
|
626 crv = CKR_OBJECT_HANDLE_INVALID; |
|
627 break; |
|
628 } |
|
629 crv = pk11_Attr2SecItem(arena,modulus,&pubKey->u.rsa.modulus); |
|
630 if (crv != CKR_OK) break; |
|
631 crv = pk11_Attr2SecItem(arena,exponent,&pubKey->u.rsa.publicExponent); |
|
632 if (crv != CKR_OK) break; |
|
633 break; |
|
634 case dsaKey: |
|
635 prime = attrs; |
|
636 PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; |
|
637 subprime = attrs; |
|
638 PK11_SETATTRS(attrs, CKA_SUBPRIME, NULL, 0); attrs++; |
|
639 base = attrs; |
|
640 PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; |
|
641 value = attrs; |
|
642 PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; |
|
643 templateCount = attrs - template; |
|
644 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); |
|
645 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); |
|
646 if (crv != CKR_OK) break; |
|
647 |
|
648 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DSA)) { |
|
649 crv = CKR_OBJECT_HANDLE_INVALID; |
|
650 break; |
|
651 } |
|
652 crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dsa.params.prime); |
|
653 if (crv != CKR_OK) break; |
|
654 crv = pk11_Attr2SecItem(arena,subprime,&pubKey->u.dsa.params.subPrime); |
|
655 if (crv != CKR_OK) break; |
|
656 crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dsa.params.base); |
|
657 if (crv != CKR_OK) break; |
|
658 crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dsa.publicValue); |
|
659 if (crv != CKR_OK) break; |
|
660 break; |
|
661 case dhKey: |
|
662 prime = attrs; |
|
663 PK11_SETATTRS(attrs, CKA_PRIME, NULL, 0); attrs++; |
|
664 base = attrs; |
|
665 PK11_SETATTRS(attrs, CKA_BASE, NULL, 0); attrs++; |
|
666 value =attrs; |
|
667 PK11_SETATTRS(attrs, CKA_VALUE, NULL, 0); attrs++; |
|
668 templateCount = attrs - template; |
|
669 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); |
|
670 crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); |
|
671 if (crv != CKR_OK) break; |
|
672 |
|
673 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_DH)) { |
|
674 crv = CKR_OBJECT_HANDLE_INVALID; |
|
675 break; |
|
676 } |
|
677 crv = pk11_Attr2SecItem(arena,prime,&pubKey->u.dh.prime); |
|
678 if (crv != CKR_OK) break; |
|
679 crv = pk11_Attr2SecItem(arena,base,&pubKey->u.dh.base); |
|
680 if (crv != CKR_OK) break; |
|
681 crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue); |
|
682 if (crv != CKR_OK) break; |
|
683 break; |
|
684 case ecKey: |
|
685 pubKey->u.ec.size = 0; |
|
686 ecparams = attrs; |
|
687 PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; |
|
688 value =attrs; |
|
689 PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; |
|
690 templateCount = attrs - template; |
|
691 PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); |
|
692 crv = PK11_GetAttributes(arena,slot,id,template,templateCount); |
|
693 if (crv != CKR_OK) break; |
|
694 |
|
695 if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) { |
|
696 crv = CKR_OBJECT_HANDLE_INVALID; |
|
697 break; |
|
698 } |
|
699 |
|
700 crv = pk11_Attr2SecItem(arena,ecparams, |
|
701 &pubKey->u.ec.DEREncodedParams); |
|
702 if (crv != CKR_OK) break; |
|
703 crv = pk11_get_Decoded_ECPoint(arena, |
|
704 &pubKey->u.ec.DEREncodedParams, value, |
|
705 &pubKey->u.ec.publicValue); |
|
706 break; |
|
707 case fortezzaKey: |
|
708 case nullKey: |
|
709 default: |
|
710 crv = CKR_OBJECT_HANDLE_INVALID; |
|
711 break; |
|
712 } |
|
713 |
|
714 PORT_FreeArena(tmp_arena,PR_FALSE); |
|
715 |
|
716 if (crv != CKR_OK) { |
|
717 PORT_FreeArena(arena,PR_FALSE); |
|
718 PK11_FreeSlot(slot); |
|
719 PORT_SetError( PK11_MapError(crv) ); |
|
720 return NULL; |
|
721 } |
|
722 |
|
723 return pubKey; |
|
724 } |
|
725 |
|
726 /* |
|
727 * Build a Private Key structure from raw PKCS #11 information. |
|
728 */ |
|
729 SECKEYPrivateKey * |
|
730 PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, |
|
731 PRBool isTemp, CK_OBJECT_HANDLE privID, void *wincx) |
|
732 { |
|
733 PLArenaPool *arena; |
|
734 SECKEYPrivateKey *privKey; |
|
735 PRBool isPrivate; |
|
736 SECStatus rv; |
|
737 |
|
738 /* don't know? look it up */ |
|
739 if (keyType == nullKey) { |
|
740 CK_KEY_TYPE pk11Type = CKK_RSA; |
|
741 |
|
742 pk11Type = PK11_ReadULongAttribute(slot,privID,CKA_KEY_TYPE); |
|
743 isTemp = (PRBool)!PK11_HasAttributeSet(slot,privID,CKA_TOKEN,PR_FALSE); |
|
744 switch (pk11Type) { |
|
745 case CKK_RSA: keyType = rsaKey; break; |
|
746 case CKK_DSA: keyType = dsaKey; break; |
|
747 case CKK_DH: keyType = dhKey; break; |
|
748 case CKK_KEA: keyType = fortezzaKey; break; |
|
749 case CKK_EC: keyType = ecKey; break; |
|
750 default: |
|
751 break; |
|
752 } |
|
753 } |
|
754 |
|
755 /* if the key is private, make sure we are authenticated to the |
|
756 * token before we try to use it */ |
|
757 isPrivate = (PRBool)PK11_HasAttributeSet(slot,privID,CKA_PRIVATE,PR_FALSE); |
|
758 if (isPrivate) { |
|
759 rv = PK11_Authenticate(slot, PR_TRUE, wincx); |
|
760 if (rv != SECSuccess) { |
|
761 return NULL; |
|
762 } |
|
763 } |
|
764 |
|
765 /* now we need to create space for the private key */ |
|
766 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); |
|
767 if (arena == NULL) return NULL; |
|
768 |
|
769 privKey = (SECKEYPrivateKey *) |
|
770 PORT_ArenaZAlloc(arena, sizeof(SECKEYPrivateKey)); |
|
771 if (privKey == NULL) { |
|
772 PORT_FreeArena(arena, PR_FALSE); |
|
773 return NULL; |
|
774 } |
|
775 |
|
776 privKey->arena = arena; |
|
777 privKey->keyType = keyType; |
|
778 privKey->pkcs11Slot = PK11_ReferenceSlot(slot); |
|
779 privKey->pkcs11ID = privID; |
|
780 privKey->pkcs11IsTemp = isTemp; |
|
781 privKey->wincx = wincx; |
|
782 |
|
783 return privKey; |
|
784 } |
|
785 |
|
786 |
|
787 PK11SlotInfo * |
|
788 PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key) |
|
789 { |
|
790 PK11SlotInfo *slot = key->pkcs11Slot; |
|
791 slot = PK11_ReferenceSlot(slot); |
|
792 return slot; |
|
793 } |
|
794 |
|
795 /* |
|
796 * Get the modulus length for raw parsing |
|
797 */ |
|
798 int |
|
799 PK11_GetPrivateModulusLen(SECKEYPrivateKey *key) |
|
800 { |
|
801 CK_ATTRIBUTE theTemplate = { CKA_MODULUS, NULL, 0 }; |
|
802 PK11SlotInfo *slot = key->pkcs11Slot; |
|
803 CK_RV crv; |
|
804 int length; |
|
805 |
|
806 switch (key->keyType) { |
|
807 case rsaKey: |
|
808 crv = PK11_GetAttributes(NULL, slot, key->pkcs11ID, &theTemplate, 1); |
|
809 if (crv != CKR_OK) { |
|
810 PORT_SetError( PK11_MapError(crv) ); |
|
811 return -1; |
|
812 } |
|
813 length = theTemplate.ulValueLen; |
|
814 if ( *(unsigned char *)theTemplate.pValue == 0) { |
|
815 length--; |
|
816 } |
|
817 if (theTemplate.pValue != NULL) |
|
818 PORT_Free(theTemplate.pValue); |
|
819 return (int) length; |
|
820 |
|
821 case fortezzaKey: |
|
822 case dsaKey: |
|
823 case dhKey: |
|
824 default: |
|
825 break; |
|
826 } |
|
827 if (theTemplate.pValue != NULL) |
|
828 PORT_Free(theTemplate.pValue); |
|
829 PORT_SetError( SEC_ERROR_INVALID_KEY ); |
|
830 return -1; |
|
831 } |
|
832 |
|
833 |
|
834 |
|
835 /* |
|
836 * take a private key in one pkcs11 module and load it into another: |
|
837 * NOTE: the source private key is a rare animal... it can't be sensitive. |
|
838 * This is used to do a key gen using one pkcs11 module and storing the |
|
839 * result into another. |
|
840 */ |
|
841 static SECKEYPrivateKey * |
|
842 pk11_loadPrivKeyWithFlags(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, |
|
843 SECKEYPublicKey *pubKey, PK11AttrFlags attrFlags) |
|
844 { |
|
845 CK_ATTRIBUTE privTemplate[] = { |
|
846 /* class must be first */ |
|
847 { CKA_CLASS, NULL, 0 }, |
|
848 { CKA_KEY_TYPE, NULL, 0 }, |
|
849 { CKA_ID, NULL, 0 }, |
|
850 /* RSA - the attributes below will be replaced for other |
|
851 * key types. |
|
852 */ |
|
853 { CKA_MODULUS, NULL, 0 }, |
|
854 { CKA_PRIVATE_EXPONENT, NULL, 0 }, |
|
855 { CKA_PUBLIC_EXPONENT, NULL, 0 }, |
|
856 { CKA_PRIME_1, NULL, 0 }, |
|
857 { CKA_PRIME_2, NULL, 0 }, |
|
858 { CKA_EXPONENT_1, NULL, 0 }, |
|
859 { CKA_EXPONENT_2, NULL, 0 }, |
|
860 { CKA_COEFFICIENT, NULL, 0 }, |
|
861 { CKA_DECRYPT, NULL, 0 }, |
|
862 { CKA_DERIVE, NULL, 0 }, |
|
863 { CKA_SIGN, NULL, 0 }, |
|
864 { CKA_SIGN_RECOVER, NULL, 0 }, |
|
865 { CKA_UNWRAP, NULL, 0 }, |
|
866 /* reserve space for the attributes that may be |
|
867 * specified in attrFlags */ |
|
868 { CKA_TOKEN, NULL, 0 }, |
|
869 { CKA_PRIVATE, NULL, 0 }, |
|
870 { CKA_MODIFIABLE, NULL, 0 }, |
|
871 { CKA_SENSITIVE, NULL, 0 }, |
|
872 { CKA_EXTRACTABLE, NULL, 0 }, |
|
873 #define NUM_RESERVED_ATTRS 5 /* number of reserved attributes above */ |
|
874 }; |
|
875 CK_BBOOL cktrue = CK_TRUE; |
|
876 CK_BBOOL ckfalse = CK_FALSE; |
|
877 CK_ATTRIBUTE *attrs = NULL, *ap; |
|
878 const int templateSize = sizeof(privTemplate)/sizeof(privTemplate[0]); |
|
879 PLArenaPool *arena; |
|
880 CK_OBJECT_HANDLE objectID; |
|
881 int i, count = 0; |
|
882 int extra_count = 0; |
|
883 CK_RV crv; |
|
884 SECStatus rv; |
|
885 PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); |
|
886 |
|
887 if (pk11_BadAttrFlags(attrFlags)) { |
|
888 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
889 return NULL; |
|
890 } |
|
891 |
|
892 for (i=0; i < templateSize; i++) { |
|
893 if (privTemplate[i].type == CKA_MODULUS) { |
|
894 attrs= &privTemplate[i]; |
|
895 count = i; |
|
896 break; |
|
897 } |
|
898 } |
|
899 PORT_Assert(attrs != NULL); |
|
900 if (attrs == NULL) { |
|
901 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
|
902 return NULL; |
|
903 } |
|
904 |
|
905 ap = attrs; |
|
906 |
|
907 switch (privKey->keyType) { |
|
908 case rsaKey: |
|
909 count = templateSize - NUM_RESERVED_ATTRS; |
|
910 extra_count = count - (attrs - privTemplate); |
|
911 break; |
|
912 case dsaKey: |
|
913 ap->type = CKA_PRIME; ap++; count++; extra_count++; |
|
914 ap->type = CKA_SUBPRIME; ap++; count++; extra_count++; |
|
915 ap->type = CKA_BASE; ap++; count++; extra_count++; |
|
916 ap->type = CKA_VALUE; ap++; count++; extra_count++; |
|
917 ap->type = CKA_SIGN; ap++; count++; extra_count++; |
|
918 break; |
|
919 case dhKey: |
|
920 ap->type = CKA_PRIME; ap++; count++; extra_count++; |
|
921 ap->type = CKA_BASE; ap++; count++; extra_count++; |
|
922 ap->type = CKA_VALUE; ap++; count++; extra_count++; |
|
923 ap->type = CKA_DERIVE; ap++; count++; extra_count++; |
|
924 break; |
|
925 case ecKey: |
|
926 ap->type = CKA_EC_PARAMS; ap++; count++; extra_count++; |
|
927 ap->type = CKA_VALUE; ap++; count++; extra_count++; |
|
928 ap->type = CKA_DERIVE; ap++; count++; extra_count++; |
|
929 ap->type = CKA_SIGN; ap++; count++; extra_count++; |
|
930 break; |
|
931 default: |
|
932 count = 0; |
|
933 extra_count = 0; |
|
934 break; |
|
935 } |
|
936 |
|
937 if (count == 0) { |
|
938 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
|
939 return NULL; |
|
940 } |
|
941 |
|
942 arena = PORT_NewArena( DER_DEFAULT_CHUNKSIZE); |
|
943 if (arena == NULL) return NULL; |
|
944 /* |
|
945 * read out the old attributes. |
|
946 */ |
|
947 crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, |
|
948 privTemplate,count); |
|
949 if (crv != CKR_OK) { |
|
950 PORT_SetError( PK11_MapError(crv) ); |
|
951 PORT_FreeArena(arena, PR_TRUE); |
|
952 return NULL; |
|
953 } |
|
954 |
|
955 /* Set token, private, modifiable, sensitive, and extractable */ |
|
956 count += pk11_AttrFlagsToAttributes(attrFlags, &privTemplate[count], |
|
957 &cktrue, &ckfalse); |
|
958 |
|
959 /* Not everyone can handle zero padded key values, give |
|
960 * them the raw data as unsigned */ |
|
961 for (ap=attrs; extra_count; ap++, extra_count--) { |
|
962 pk11_SignedToUnsigned(ap); |
|
963 } |
|
964 |
|
965 /* now Store the puppies */ |
|
966 rv = PK11_CreateNewObject(slot, CK_INVALID_SESSION, privTemplate, |
|
967 count, token, &objectID); |
|
968 PORT_FreeArena(arena, PR_TRUE); |
|
969 if (rv != SECSuccess) { |
|
970 return NULL; |
|
971 } |
|
972 |
|
973 /* try loading the public key */ |
|
974 if (pubKey) { |
|
975 PK11_ImportPublicKey(slot, pubKey, token); |
|
976 if (pubKey->pkcs11Slot) { |
|
977 PK11_FreeSlot(pubKey->pkcs11Slot); |
|
978 pubKey->pkcs11Slot = NULL; |
|
979 pubKey->pkcs11ID = CK_INVALID_HANDLE; |
|
980 } |
|
981 } |
|
982 |
|
983 /* build new key structure */ |
|
984 return PK11_MakePrivKey(slot, privKey->keyType, !token, |
|
985 objectID, privKey->wincx); |
|
986 } |
|
987 |
|
988 static SECKEYPrivateKey * |
|
989 pk11_loadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, |
|
990 SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) |
|
991 { |
|
992 PK11AttrFlags attrFlags = 0; |
|
993 if (token) { |
|
994 attrFlags |= (PK11_ATTR_TOKEN | PK11_ATTR_PRIVATE); |
|
995 } else { |
|
996 attrFlags |= (PK11_ATTR_SESSION | PK11_ATTR_PUBLIC); |
|
997 } |
|
998 if (sensitive) { |
|
999 attrFlags |= PK11_ATTR_SENSITIVE; |
|
1000 } else { |
|
1001 attrFlags |= PK11_ATTR_INSENSITIVE; |
|
1002 } |
|
1003 return pk11_loadPrivKeyWithFlags(slot, privKey, pubKey, attrFlags); |
|
1004 } |
|
1005 |
|
1006 /* |
|
1007 * export this for PSM |
|
1008 */ |
|
1009 SECKEYPrivateKey * |
|
1010 PK11_LoadPrivKey(PK11SlotInfo *slot,SECKEYPrivateKey *privKey, |
|
1011 SECKEYPublicKey *pubKey, PRBool token, PRBool sensitive) |
|
1012 { |
|
1013 return pk11_loadPrivKey(slot,privKey,pubKey,token,sensitive); |
|
1014 } |
|
1015 |
|
1016 |
|
1017 /* |
|
1018 * Use the token to generate a key pair. |
|
1019 */ |
|
1020 SECKEYPrivateKey * |
|
1021 PK11_GenerateKeyPairWithOpFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, |
|
1022 void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, |
|
1023 CK_FLAGS opFlags, CK_FLAGS opFlagsMask, void *wincx) |
|
1024 { |
|
1025 /* we have to use these native types because when we call PKCS 11 modules |
|
1026 * we have to make sure that we are using the correct sizes for all the |
|
1027 * parameters. */ |
|
1028 CK_BBOOL ckfalse = CK_FALSE; |
|
1029 CK_BBOOL cktrue = CK_TRUE; |
|
1030 CK_ULONG modulusBits; |
|
1031 CK_BYTE publicExponent[4]; |
|
1032 CK_ATTRIBUTE privTemplate[] = { |
|
1033 { CKA_SENSITIVE, NULL, 0}, |
|
1034 { CKA_TOKEN, NULL, 0}, |
|
1035 { CKA_PRIVATE, NULL, 0}, |
|
1036 { CKA_DERIVE, NULL, 0}, |
|
1037 { CKA_UNWRAP, NULL, 0}, |
|
1038 { CKA_SIGN, NULL, 0}, |
|
1039 { CKA_DECRYPT, NULL, 0}, |
|
1040 { CKA_EXTRACTABLE, NULL, 0}, |
|
1041 { CKA_MODIFIABLE, NULL, 0}, |
|
1042 }; |
|
1043 CK_ATTRIBUTE rsaPubTemplate[] = { |
|
1044 { CKA_MODULUS_BITS, NULL, 0}, |
|
1045 { CKA_PUBLIC_EXPONENT, NULL, 0}, |
|
1046 { CKA_TOKEN, NULL, 0}, |
|
1047 { CKA_DERIVE, NULL, 0}, |
|
1048 { CKA_WRAP, NULL, 0}, |
|
1049 { CKA_VERIFY, NULL, 0}, |
|
1050 { CKA_VERIFY_RECOVER, NULL, 0}, |
|
1051 { CKA_ENCRYPT, NULL, 0}, |
|
1052 { CKA_MODIFIABLE, NULL, 0}, |
|
1053 }; |
|
1054 CK_ATTRIBUTE dsaPubTemplate[] = { |
|
1055 { CKA_PRIME, NULL, 0 }, |
|
1056 { CKA_SUBPRIME, NULL, 0 }, |
|
1057 { CKA_BASE, NULL, 0 }, |
|
1058 { CKA_TOKEN, NULL, 0}, |
|
1059 { CKA_DERIVE, NULL, 0}, |
|
1060 { CKA_WRAP, NULL, 0}, |
|
1061 { CKA_VERIFY, NULL, 0}, |
|
1062 { CKA_VERIFY_RECOVER, NULL, 0}, |
|
1063 { CKA_ENCRYPT, NULL, 0}, |
|
1064 { CKA_MODIFIABLE, NULL, 0}, |
|
1065 }; |
|
1066 CK_ATTRIBUTE dhPubTemplate[] = { |
|
1067 { CKA_PRIME, NULL, 0 }, |
|
1068 { CKA_BASE, NULL, 0 }, |
|
1069 { CKA_TOKEN, NULL, 0}, |
|
1070 { CKA_DERIVE, NULL, 0}, |
|
1071 { CKA_WRAP, NULL, 0}, |
|
1072 { CKA_VERIFY, NULL, 0}, |
|
1073 { CKA_VERIFY_RECOVER, NULL, 0}, |
|
1074 { CKA_ENCRYPT, NULL, 0}, |
|
1075 { CKA_MODIFIABLE, NULL, 0}, |
|
1076 }; |
|
1077 CK_ATTRIBUTE ecPubTemplate[] = { |
|
1078 { CKA_EC_PARAMS, NULL, 0 }, |
|
1079 { CKA_TOKEN, NULL, 0}, |
|
1080 { CKA_DERIVE, NULL, 0}, |
|
1081 { CKA_WRAP, NULL, 0}, |
|
1082 { CKA_VERIFY, NULL, 0}, |
|
1083 { CKA_VERIFY_RECOVER, NULL, 0}, |
|
1084 { CKA_ENCRYPT, NULL, 0}, |
|
1085 { CKA_MODIFIABLE, NULL, 0}, |
|
1086 }; |
|
1087 SECKEYECParams * ecParams; |
|
1088 |
|
1089 /*CK_ULONG key_size = 0;*/ |
|
1090 CK_ATTRIBUTE *pubTemplate; |
|
1091 int privCount = 0; |
|
1092 int pubCount = 0; |
|
1093 PK11RSAGenParams *rsaParams; |
|
1094 SECKEYPQGParams *dsaParams; |
|
1095 SECKEYDHParams * dhParams; |
|
1096 CK_MECHANISM mechanism; |
|
1097 CK_MECHANISM test_mech; |
|
1098 CK_MECHANISM test_mech2; |
|
1099 CK_SESSION_HANDLE session_handle; |
|
1100 CK_RV crv; |
|
1101 CK_OBJECT_HANDLE privID,pubID; |
|
1102 SECKEYPrivateKey *privKey; |
|
1103 KeyType keyType; |
|
1104 PRBool restore; |
|
1105 int peCount,i; |
|
1106 CK_ATTRIBUTE *attrs; |
|
1107 CK_ATTRIBUTE *privattrs; |
|
1108 CK_ATTRIBUTE setTemplate; |
|
1109 CK_MECHANISM_INFO mechanism_info; |
|
1110 CK_OBJECT_CLASS keyClass; |
|
1111 SECItem *cka_id; |
|
1112 PRBool haslock = PR_FALSE; |
|
1113 PRBool pubIsToken = PR_FALSE; |
|
1114 PRBool token = ((attrFlags & PK11_ATTR_TOKEN) != 0); |
|
1115 /* subset of attrFlags applicable to the public key */ |
|
1116 PK11AttrFlags pubKeyAttrFlags = attrFlags & |
|
1117 (PK11_ATTR_TOKEN | PK11_ATTR_SESSION |
|
1118 | PK11_ATTR_MODIFIABLE | PK11_ATTR_UNMODIFIABLE); |
|
1119 |
|
1120 if (pk11_BadAttrFlags(attrFlags)) { |
|
1121 PORT_SetError( SEC_ERROR_INVALID_ARGS ); |
|
1122 return NULL; |
|
1123 } |
|
1124 |
|
1125 if (!param) { |
|
1126 PORT_SetError( SEC_ERROR_INVALID_ARGS ); |
|
1127 return NULL; |
|
1128 } |
|
1129 |
|
1130 /* |
|
1131 * The opFlags and opFlagMask parameters allow us to control the |
|
1132 * settings of the key usage attributes (CKA_ENCRYPT and friends). |
|
1133 * opFlagMask is set to one if the flag is specified in opFlags and |
|
1134 * zero if it is to take on a default value calculated by |
|
1135 * PK11_GenerateKeyPairWithOpFlags. |
|
1136 * opFlags specifies the actual value of the flag 1 or 0. |
|
1137 * Bits not corresponding to one bits in opFlagMask should be zero. |
|
1138 */ |
|
1139 |
|
1140 /* if we are trying to turn on a flag, it better be in the mask */ |
|
1141 PORT_Assert ((opFlags & ~opFlagsMask) == 0); |
|
1142 opFlags &= opFlagsMask; |
|
1143 |
|
1144 PORT_Assert(slot != NULL); |
|
1145 if (slot == NULL) { |
|
1146 PORT_SetError( SEC_ERROR_NO_MODULE); |
|
1147 return NULL; |
|
1148 } |
|
1149 |
|
1150 /* if our slot really doesn't do this mechanism, Generate the key |
|
1151 * in our internal token and write it out */ |
|
1152 if (!PK11_DoesMechanism(slot,type)) { |
|
1153 PK11SlotInfo *int_slot = PK11_GetInternalSlot(); |
|
1154 |
|
1155 /* don't loop forever looking for a slot */ |
|
1156 if (slot == int_slot) { |
|
1157 PK11_FreeSlot(int_slot); |
|
1158 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
|
1159 return NULL; |
|
1160 } |
|
1161 |
|
1162 /* if there isn't a suitable slot, then we can't do the keygen */ |
|
1163 if (int_slot == NULL) { |
|
1164 PORT_SetError( SEC_ERROR_NO_MODULE ); |
|
1165 return NULL; |
|
1166 } |
|
1167 |
|
1168 /* generate the temporary key to load */ |
|
1169 privKey = PK11_GenerateKeyPair(int_slot,type, param, pubKey, PR_FALSE, |
|
1170 PR_FALSE, wincx); |
|
1171 PK11_FreeSlot(int_slot); |
|
1172 |
|
1173 /* if successful, load the temp key into the new token */ |
|
1174 if (privKey != NULL) { |
|
1175 SECKEYPrivateKey *newPrivKey = pk11_loadPrivKeyWithFlags(slot, |
|
1176 privKey,*pubKey,attrFlags); |
|
1177 SECKEY_DestroyPrivateKey(privKey); |
|
1178 if (newPrivKey == NULL) { |
|
1179 SECKEY_DestroyPublicKey(*pubKey); |
|
1180 *pubKey = NULL; |
|
1181 } |
|
1182 return newPrivKey; |
|
1183 } |
|
1184 return NULL; |
|
1185 } |
|
1186 |
|
1187 |
|
1188 mechanism.mechanism = type; |
|
1189 mechanism.pParameter = NULL; |
|
1190 mechanism.ulParameterLen = 0; |
|
1191 test_mech.pParameter = NULL; |
|
1192 test_mech.ulParameterLen = 0; |
|
1193 test_mech2.mechanism = CKM_INVALID_MECHANISM; |
|
1194 test_mech2.pParameter = NULL; |
|
1195 test_mech2.ulParameterLen = 0; |
|
1196 |
|
1197 /* set up the private key template */ |
|
1198 privattrs = privTemplate; |
|
1199 privattrs += pk11_AttrFlagsToAttributes(attrFlags, privattrs, |
|
1200 &cktrue, &ckfalse); |
|
1201 |
|
1202 /* set up the mechanism specific info */ |
|
1203 switch (type) { |
|
1204 case CKM_RSA_PKCS_KEY_PAIR_GEN: |
|
1205 case CKM_RSA_X9_31_KEY_PAIR_GEN: |
|
1206 rsaParams = (PK11RSAGenParams *)param; |
|
1207 if (rsaParams->pe == 0) { |
|
1208 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
1209 return NULL; |
|
1210 } |
|
1211 modulusBits = rsaParams->keySizeInBits; |
|
1212 peCount = 0; |
|
1213 |
|
1214 /* convert pe to a PKCS #11 string */ |
|
1215 for (i=0; i < 4; i++) { |
|
1216 if (peCount || (rsaParams->pe & |
|
1217 ((unsigned long)0xff000000L >> (i*8)))) { |
|
1218 publicExponent[peCount] = |
|
1219 (CK_BYTE)((rsaParams->pe >> (3-i)*8) & 0xff); |
|
1220 peCount++; |
|
1221 } |
|
1222 } |
|
1223 PORT_Assert(peCount != 0); |
|
1224 attrs = rsaPubTemplate; |
|
1225 PK11_SETATTRS(attrs, CKA_MODULUS_BITS, |
|
1226 &modulusBits, sizeof(modulusBits)); attrs++; |
|
1227 PK11_SETATTRS(attrs, CKA_PUBLIC_EXPONENT, |
|
1228 publicExponent, peCount);attrs++; |
|
1229 pubTemplate = rsaPubTemplate; |
|
1230 keyType = rsaKey; |
|
1231 test_mech.mechanism = CKM_RSA_PKCS; |
|
1232 break; |
|
1233 case CKM_DSA_KEY_PAIR_GEN: |
|
1234 dsaParams = (SECKEYPQGParams *)param; |
|
1235 attrs = dsaPubTemplate; |
|
1236 PK11_SETATTRS(attrs, CKA_PRIME, dsaParams->prime.data, |
|
1237 dsaParams->prime.len); attrs++; |
|
1238 PK11_SETATTRS(attrs, CKA_SUBPRIME, dsaParams->subPrime.data, |
|
1239 dsaParams->subPrime.len); attrs++; |
|
1240 PK11_SETATTRS(attrs, CKA_BASE, dsaParams->base.data, |
|
1241 dsaParams->base.len); attrs++; |
|
1242 pubTemplate = dsaPubTemplate; |
|
1243 keyType = dsaKey; |
|
1244 test_mech.mechanism = CKM_DSA; |
|
1245 break; |
|
1246 case CKM_DH_PKCS_KEY_PAIR_GEN: |
|
1247 dhParams = (SECKEYDHParams *)param; |
|
1248 attrs = dhPubTemplate; |
|
1249 PK11_SETATTRS(attrs, CKA_PRIME, dhParams->prime.data, |
|
1250 dhParams->prime.len); attrs++; |
|
1251 PK11_SETATTRS(attrs, CKA_BASE, dhParams->base.data, |
|
1252 dhParams->base.len); attrs++; |
|
1253 pubTemplate = dhPubTemplate; |
|
1254 keyType = dhKey; |
|
1255 test_mech.mechanism = CKM_DH_PKCS_DERIVE; |
|
1256 break; |
|
1257 case CKM_EC_KEY_PAIR_GEN: |
|
1258 ecParams = (SECKEYECParams *)param; |
|
1259 attrs = ecPubTemplate; |
|
1260 PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, |
|
1261 ecParams->len); attrs++; |
|
1262 pubTemplate = ecPubTemplate; |
|
1263 keyType = ecKey; |
|
1264 /* |
|
1265 * ECC supports 2 different mechanism types (unlike RSA, which |
|
1266 * supports different usages with the same mechanism). |
|
1267 * We may need to query both mechanism types and or the results |
|
1268 * together -- but we only do that if either the user has |
|
1269 * requested both usages, or not specified any usages. |
|
1270 */ |
|
1271 if ((opFlags & (CKF_SIGN|CKF_DERIVE)) == (CKF_SIGN|CKF_DERIVE)) { |
|
1272 /* We've explicitly turned on both flags, use both mechanism */ |
|
1273 test_mech.mechanism = CKM_ECDH1_DERIVE; |
|
1274 test_mech2.mechanism = CKM_ECDSA; |
|
1275 } else if (opFlags & CKF_SIGN) { |
|
1276 /* just do signing */ |
|
1277 test_mech.mechanism = CKM_ECDSA; |
|
1278 } else if (opFlags & CKF_DERIVE) { |
|
1279 /* just do ECDH */ |
|
1280 test_mech.mechanism = CKM_ECDH1_DERIVE; |
|
1281 } else { |
|
1282 /* neither was specified default to both */ |
|
1283 test_mech.mechanism = CKM_ECDH1_DERIVE; |
|
1284 test_mech2.mechanism = CKM_ECDSA; |
|
1285 } |
|
1286 break; |
|
1287 default: |
|
1288 PORT_SetError( SEC_ERROR_BAD_KEY ); |
|
1289 return NULL; |
|
1290 } |
|
1291 |
|
1292 /* now query the slot to find out how "good" a key we can generate */ |
|
1293 if (!slot->isThreadSafe) PK11_EnterSlotMonitor(slot); |
|
1294 crv = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, |
|
1295 test_mech.mechanism,&mechanism_info); |
|
1296 /* |
|
1297 * EC keys are used in multiple different types of mechanism, if we |
|
1298 * are using dual use keys, we need to query the second mechanism |
|
1299 * as well. |
|
1300 */ |
|
1301 if (test_mech2.mechanism != CKM_INVALID_MECHANISM) { |
|
1302 CK_MECHANISM_INFO mechanism_info2; |
|
1303 CK_RV crv2; |
|
1304 |
|
1305 if (crv != CKR_OK) { |
|
1306 /* the first failed, make sure there is no trash in the |
|
1307 * mechanism flags when we or it below */ |
|
1308 mechanism_info.flags = 0; |
|
1309 } |
|
1310 crv2 = PK11_GETTAB(slot)->C_GetMechanismInfo(slot->slotID, |
|
1311 test_mech2.mechanism, &mechanism_info2); |
|
1312 if (crv2 == CKR_OK) { |
|
1313 crv = CKR_OK; /* succeed if either mechnaism info succeeds */ |
|
1314 /* combine the 2 sets of mechnanism flags */ |
|
1315 mechanism_info.flags |= mechanism_info2.flags; |
|
1316 } |
|
1317 } |
|
1318 if (!slot->isThreadSafe) PK11_ExitSlotMonitor(slot); |
|
1319 if ((crv != CKR_OK) || (mechanism_info.flags == 0)) { |
|
1320 /* must be old module... guess what it should be... */ |
|
1321 switch (test_mech.mechanism) { |
|
1322 case CKM_RSA_PKCS: |
|
1323 mechanism_info.flags = (CKF_SIGN | CKF_DECRYPT | |
|
1324 CKF_WRAP | CKF_VERIFY_RECOVER | CKF_ENCRYPT | CKF_WRAP); |
|
1325 break; |
|
1326 case CKM_DSA: |
|
1327 mechanism_info.flags = CKF_SIGN | CKF_VERIFY; |
|
1328 break; |
|
1329 case CKM_DH_PKCS_DERIVE: |
|
1330 mechanism_info.flags = CKF_DERIVE; |
|
1331 break; |
|
1332 case CKM_ECDH1_DERIVE: |
|
1333 mechanism_info.flags = CKF_DERIVE; |
|
1334 if (test_mech2.mechanism == CKM_ECDSA) { |
|
1335 mechanism_info.flags |= CKF_SIGN | CKF_VERIFY; |
|
1336 } |
|
1337 break; |
|
1338 case CKM_ECDSA: |
|
1339 mechanism_info.flags = CKF_SIGN | CKF_VERIFY; |
|
1340 break; |
|
1341 default: |
|
1342 break; |
|
1343 } |
|
1344 } |
|
1345 /* now adjust our flags according to the user's key usage passed to us */ |
|
1346 mechanism_info.flags = (mechanism_info.flags & (~opFlagsMask)) | opFlags; |
|
1347 /* set the public key attributes */ |
|
1348 attrs += pk11_AttrFlagsToAttributes(pubKeyAttrFlags, attrs, |
|
1349 &cktrue, &ckfalse); |
|
1350 PK11_SETATTRS(attrs, CKA_DERIVE, |
|
1351 mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, |
|
1352 sizeof(CK_BBOOL)); attrs++; |
|
1353 PK11_SETATTRS(attrs, CKA_WRAP, |
|
1354 mechanism_info.flags & CKF_WRAP ? &cktrue : &ckfalse, |
|
1355 sizeof(CK_BBOOL)); attrs++; |
|
1356 PK11_SETATTRS(attrs, CKA_VERIFY, |
|
1357 mechanism_info.flags & CKF_VERIFY ? &cktrue : &ckfalse, |
|
1358 sizeof(CK_BBOOL)); attrs++; |
|
1359 PK11_SETATTRS(attrs, CKA_VERIFY_RECOVER, |
|
1360 mechanism_info.flags & CKF_VERIFY_RECOVER ? &cktrue : &ckfalse, |
|
1361 sizeof(CK_BBOOL)); attrs++; |
|
1362 PK11_SETATTRS(attrs, CKA_ENCRYPT, |
|
1363 mechanism_info.flags & CKF_ENCRYPT? &cktrue : &ckfalse, |
|
1364 sizeof(CK_BBOOL)); attrs++; |
|
1365 /* set the private key attributes */ |
|
1366 PK11_SETATTRS(privattrs, CKA_DERIVE, |
|
1367 mechanism_info.flags & CKF_DERIVE ? &cktrue : &ckfalse, |
|
1368 sizeof(CK_BBOOL)); privattrs++; |
|
1369 PK11_SETATTRS(privattrs, CKA_UNWRAP, |
|
1370 mechanism_info.flags & CKF_UNWRAP ? &cktrue : &ckfalse, |
|
1371 sizeof(CK_BBOOL)); privattrs++; |
|
1372 PK11_SETATTRS(privattrs, CKA_SIGN, |
|
1373 mechanism_info.flags & CKF_SIGN ? &cktrue : &ckfalse, |
|
1374 sizeof(CK_BBOOL)); privattrs++; |
|
1375 PK11_SETATTRS(privattrs, CKA_DECRYPT, |
|
1376 mechanism_info.flags & CKF_DECRYPT ? &cktrue : &ckfalse, |
|
1377 sizeof(CK_BBOOL)); privattrs++; |
|
1378 |
|
1379 if (token) { |
|
1380 session_handle = PK11_GetRWSession(slot); |
|
1381 haslock = PK11_RWSessionHasLock(slot,session_handle); |
|
1382 restore = PR_TRUE; |
|
1383 } else { |
|
1384 session_handle = slot->session; |
|
1385 if (session_handle != CK_INVALID_SESSION) |
|
1386 PK11_EnterSlotMonitor(slot); |
|
1387 restore = PR_FALSE; |
|
1388 haslock = PR_TRUE; |
|
1389 } |
|
1390 |
|
1391 if (session_handle == CK_INVALID_SESSION) { |
|
1392 PORT_SetError(SEC_ERROR_BAD_DATA); |
|
1393 return NULL; |
|
1394 } |
|
1395 privCount = privattrs - privTemplate; |
|
1396 pubCount = attrs - pubTemplate; |
|
1397 crv = PK11_GETTAB(slot)->C_GenerateKeyPair(session_handle, &mechanism, |
|
1398 pubTemplate,pubCount,privTemplate,privCount,&pubID,&privID); |
|
1399 |
|
1400 if (crv != CKR_OK) { |
|
1401 if (restore) { |
|
1402 PK11_RestoreROSession(slot,session_handle); |
|
1403 } else PK11_ExitSlotMonitor(slot); |
|
1404 PORT_SetError( PK11_MapError(crv) ); |
|
1405 return NULL; |
|
1406 } |
|
1407 /* This locking code is dangerous and needs to be more thought |
|
1408 * out... the real problem is that we're holding the mutex open this long |
|
1409 */ |
|
1410 if (haslock) { PK11_ExitSlotMonitor(slot); } |
|
1411 |
|
1412 /* swap around the ID's for older PKCS #11 modules */ |
|
1413 keyClass = PK11_ReadULongAttribute(slot,pubID,CKA_CLASS); |
|
1414 if (keyClass != CKO_PUBLIC_KEY) { |
|
1415 CK_OBJECT_HANDLE tmp = pubID; |
|
1416 pubID = privID; |
|
1417 privID = tmp; |
|
1418 } |
|
1419 |
|
1420 *pubKey = PK11_ExtractPublicKey(slot, keyType, pubID); |
|
1421 if (*pubKey == NULL) { |
|
1422 if (restore) { |
|
1423 /* we may have to restore the mutex so it get's exited properly |
|
1424 * in RestoreROSession */ |
|
1425 if (haslock) PK11_EnterSlotMonitor(slot); |
|
1426 PK11_RestoreROSession(slot,session_handle); |
|
1427 } |
|
1428 PK11_DestroyObject(slot,pubID); |
|
1429 PK11_DestroyObject(slot,privID); |
|
1430 return NULL; |
|
1431 } |
|
1432 |
|
1433 /* set the ID to the public key so we can find it again */ |
|
1434 cka_id = pk11_MakeIDFromPublicKey(*pubKey); |
|
1435 pubIsToken = (PRBool)PK11_HasAttributeSet(slot,pubID, CKA_TOKEN,PR_FALSE); |
|
1436 |
|
1437 PK11_SETATTRS(&setTemplate, CKA_ID, cka_id->data, cka_id->len); |
|
1438 |
|
1439 if (haslock) { PK11_EnterSlotMonitor(slot); } |
|
1440 crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, privID, |
|
1441 &setTemplate, 1); |
|
1442 |
|
1443 if (crv == CKR_OK && pubIsToken) { |
|
1444 crv = PK11_GETTAB(slot)->C_SetAttributeValue(session_handle, pubID, |
|
1445 &setTemplate, 1); |
|
1446 } |
|
1447 |
|
1448 |
|
1449 if (restore) { |
|
1450 PK11_RestoreROSession(slot,session_handle); |
|
1451 } else { |
|
1452 PK11_ExitSlotMonitor(slot); |
|
1453 } |
|
1454 SECITEM_FreeItem(cka_id,PR_TRUE); |
|
1455 |
|
1456 |
|
1457 if (crv != CKR_OK) { |
|
1458 PK11_DestroyObject(slot,pubID); |
|
1459 PK11_DestroyObject(slot,privID); |
|
1460 PORT_SetError( PK11_MapError(crv) ); |
|
1461 *pubKey = NULL; |
|
1462 return NULL; |
|
1463 } |
|
1464 |
|
1465 privKey = PK11_MakePrivKey(slot,keyType,!token,privID,wincx); |
|
1466 if (privKey == NULL) { |
|
1467 SECKEY_DestroyPublicKey(*pubKey); |
|
1468 PK11_DestroyObject(slot,privID); |
|
1469 *pubKey = NULL; |
|
1470 return NULL; |
|
1471 } |
|
1472 |
|
1473 return privKey; |
|
1474 } |
|
1475 |
|
1476 SECKEYPrivateKey * |
|
1477 PK11_GenerateKeyPairWithFlags(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, |
|
1478 void *param, SECKEYPublicKey **pubKey, PK11AttrFlags attrFlags, void *wincx) |
|
1479 { |
|
1480 return PK11_GenerateKeyPairWithOpFlags(slot,type,param,pubKey,attrFlags, |
|
1481 0, 0, wincx); |
|
1482 } |
|
1483 |
|
1484 /* |
|
1485 * Use the token to generate a key pair. |
|
1486 */ |
|
1487 SECKEYPrivateKey * |
|
1488 PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, |
|
1489 void *param, SECKEYPublicKey **pubKey, PRBool token, |
|
1490 PRBool sensitive, void *wincx) |
|
1491 { |
|
1492 PK11AttrFlags attrFlags = 0; |
|
1493 |
|
1494 if (token) { |
|
1495 attrFlags |= PK11_ATTR_TOKEN; |
|
1496 } else { |
|
1497 attrFlags |= PK11_ATTR_SESSION; |
|
1498 } |
|
1499 if (sensitive) { |
|
1500 attrFlags |= (PK11_ATTR_SENSITIVE | PK11_ATTR_PRIVATE); |
|
1501 } else { |
|
1502 attrFlags |= (PK11_ATTR_INSENSITIVE | PK11_ATTR_PUBLIC); |
|
1503 } |
|
1504 return PK11_GenerateKeyPairWithFlags(slot, type, param, pubKey, |
|
1505 attrFlags, wincx); |
|
1506 } |
|
1507 |
|
1508 /* build a public KEA key from the public value */ |
|
1509 SECKEYPublicKey * |
|
1510 PK11_MakeKEAPubKey(unsigned char *keyData,int length) |
|
1511 { |
|
1512 SECKEYPublicKey *pubk; |
|
1513 SECItem pkData; |
|
1514 SECStatus rv; |
|
1515 PLArenaPool *arena; |
|
1516 |
|
1517 pkData.data = keyData; |
|
1518 pkData.len = length; |
|
1519 |
|
1520 arena = PORT_NewArena (DER_DEFAULT_CHUNKSIZE); |
|
1521 if (arena == NULL) |
|
1522 return NULL; |
|
1523 |
|
1524 pubk = (SECKEYPublicKey *) PORT_ArenaZAlloc(arena, sizeof(SECKEYPublicKey)); |
|
1525 if (pubk == NULL) { |
|
1526 PORT_FreeArena (arena, PR_FALSE); |
|
1527 return NULL; |
|
1528 } |
|
1529 |
|
1530 pubk->arena = arena; |
|
1531 pubk->pkcs11Slot = 0; |
|
1532 pubk->pkcs11ID = CK_INVALID_HANDLE; |
|
1533 pubk->keyType = fortezzaKey; |
|
1534 rv = SECITEM_CopyItem(arena, &pubk->u.fortezza.KEAKey, &pkData); |
|
1535 if (rv != SECSuccess) { |
|
1536 PORT_FreeArena (arena, PR_FALSE); |
|
1537 return NULL; |
|
1538 } |
|
1539 return pubk; |
|
1540 } |
|
1541 |
|
1542 /* |
|
1543 * NOTE: This function doesn't return a SECKEYPrivateKey struct to represent |
|
1544 * the new private key object. If it were to create a session object that |
|
1545 * could later be looked up by its nickname, it would leak a SECKEYPrivateKey. |
|
1546 * So isPerm must be true. |
|
1547 */ |
|
1548 SECStatus |
|
1549 PK11_ImportEncryptedPrivateKeyInfo(PK11SlotInfo *slot, |
|
1550 SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, |
|
1551 SECItem *nickname, SECItem *publicValue, PRBool isPerm, |
|
1552 PRBool isPrivate, KeyType keyType, |
|
1553 unsigned int keyUsage, void *wincx) |
|
1554 { |
|
1555 if (!isPerm) { |
|
1556 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
1557 return SECFailure; |
|
1558 } |
|
1559 return PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(slot, epki, |
|
1560 pwitem, nickname, publicValue, isPerm, isPrivate, keyType, |
|
1561 keyUsage, NULL, wincx); |
|
1562 } |
|
1563 |
|
1564 SECStatus |
|
1565 PK11_ImportEncryptedPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot, |
|
1566 SECKEYEncryptedPrivateKeyInfo *epki, SECItem *pwitem, |
|
1567 SECItem *nickname, SECItem *publicValue, PRBool isPerm, |
|
1568 PRBool isPrivate, KeyType keyType, |
|
1569 unsigned int keyUsage, SECKEYPrivateKey **privk, |
|
1570 void *wincx) |
|
1571 { |
|
1572 CK_MECHANISM_TYPE pbeMechType; |
|
1573 SECItem *crypto_param = NULL; |
|
1574 PK11SymKey *key = NULL; |
|
1575 SECStatus rv = SECSuccess; |
|
1576 CK_MECHANISM_TYPE cryptoMechType; |
|
1577 SECKEYPrivateKey *privKey = NULL; |
|
1578 PRBool faulty3DES = PR_FALSE; |
|
1579 int usageCount = 0; |
|
1580 CK_KEY_TYPE key_type; |
|
1581 CK_ATTRIBUTE_TYPE *usage = NULL; |
|
1582 CK_ATTRIBUTE_TYPE rsaUsage[] = { |
|
1583 CKA_UNWRAP, CKA_DECRYPT, CKA_SIGN, CKA_SIGN_RECOVER }; |
|
1584 CK_ATTRIBUTE_TYPE dsaUsage[] = { CKA_SIGN }; |
|
1585 CK_ATTRIBUTE_TYPE dhUsage[] = { CKA_DERIVE }; |
|
1586 CK_ATTRIBUTE_TYPE ecUsage[] = { CKA_SIGN, CKA_DERIVE }; |
|
1587 if((epki == NULL) || (pwitem == NULL)) |
|
1588 return SECFailure; |
|
1589 |
|
1590 pbeMechType = PK11_AlgtagToMechanism(SECOID_FindOIDTag( |
|
1591 &epki->algorithm.algorithm)); |
|
1592 |
|
1593 switch (keyType) { |
|
1594 default: |
|
1595 case rsaKey: |
|
1596 key_type = CKK_RSA; |
|
1597 switch (keyUsage & (KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE)) { |
|
1598 case KU_KEY_ENCIPHERMENT: |
|
1599 usage = rsaUsage; |
|
1600 usageCount = 2; |
|
1601 break; |
|
1602 case KU_DIGITAL_SIGNATURE: |
|
1603 usage = &rsaUsage[2]; |
|
1604 usageCount = 2; |
|
1605 break; |
|
1606 case KU_KEY_ENCIPHERMENT|KU_DIGITAL_SIGNATURE: |
|
1607 case 0: /* default to everything */ |
|
1608 usage = rsaUsage; |
|
1609 usageCount = 4; |
|
1610 break; |
|
1611 } |
|
1612 break; |
|
1613 case dhKey: |
|
1614 key_type = CKK_DH; |
|
1615 usage = dhUsage; |
|
1616 usageCount = sizeof(dhUsage)/sizeof(dhUsage[0]); |
|
1617 break; |
|
1618 case dsaKey: |
|
1619 key_type = CKK_DSA; |
|
1620 usage = dsaUsage; |
|
1621 usageCount = sizeof(dsaUsage)/sizeof(dsaUsage[0]); |
|
1622 break; |
|
1623 case ecKey: |
|
1624 key_type = CKK_EC; |
|
1625 switch (keyUsage & (KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT)) { |
|
1626 case KU_DIGITAL_SIGNATURE: |
|
1627 usage = ecUsage; |
|
1628 usageCount = 1; |
|
1629 break; |
|
1630 case KU_KEY_AGREEMENT: |
|
1631 usage = &ecUsage[1]; |
|
1632 usageCount = 1; |
|
1633 break; |
|
1634 case KU_DIGITAL_SIGNATURE|KU_KEY_AGREEMENT: |
|
1635 default: /* default to everything */ |
|
1636 usage = ecUsage; |
|
1637 usageCount = 2; |
|
1638 break; |
|
1639 } |
|
1640 break; |
|
1641 } |
|
1642 |
|
1643 try_faulty_3des: |
|
1644 |
|
1645 key = PK11_PBEKeyGen(slot, &epki->algorithm, pwitem, faulty3DES, wincx); |
|
1646 if (key == NULL) { |
|
1647 rv = SECFailure; |
|
1648 goto done; |
|
1649 } |
|
1650 cryptoMechType = pk11_GetPBECryptoMechanism(&epki->algorithm, |
|
1651 &crypto_param, pwitem, faulty3DES); |
|
1652 if (cryptoMechType == CKM_INVALID_MECHANISM) { |
|
1653 rv = SECFailure; |
|
1654 goto done; |
|
1655 } |
|
1656 |
|
1657 |
|
1658 cryptoMechType = PK11_GetPadMechanism(cryptoMechType); |
|
1659 |
|
1660 PORT_Assert(usage != NULL); |
|
1661 PORT_Assert(usageCount != 0); |
|
1662 privKey = PK11_UnwrapPrivKey(slot, key, cryptoMechType, |
|
1663 crypto_param, &epki->encryptedData, |
|
1664 nickname, publicValue, isPerm, isPrivate, |
|
1665 key_type, usage, usageCount, wincx); |
|
1666 if(privKey) { |
|
1667 if (privk) { |
|
1668 *privk = privKey; |
|
1669 } else { |
|
1670 SECKEY_DestroyPrivateKey(privKey); |
|
1671 } |
|
1672 privKey = NULL; |
|
1673 rv = SECSuccess; |
|
1674 goto done; |
|
1675 } |
|
1676 |
|
1677 /* if we are unable to import the key and the pbeMechType is |
|
1678 * CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, then it is possible that |
|
1679 * the encrypted blob was created with a buggy key generation method |
|
1680 * which is described in the PKCS 12 implementation notes. So we |
|
1681 * need to try importing via that method. |
|
1682 */ |
|
1683 if((pbeMechType == CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC) && (!faulty3DES)) { |
|
1684 /* clean up after ourselves before redoing the key generation. */ |
|
1685 |
|
1686 PK11_FreeSymKey(key); |
|
1687 key = NULL; |
|
1688 |
|
1689 if(crypto_param) { |
|
1690 SECITEM_ZfreeItem(crypto_param, PR_TRUE); |
|
1691 crypto_param = NULL; |
|
1692 } |
|
1693 |
|
1694 faulty3DES = PR_TRUE; |
|
1695 goto try_faulty_3des; |
|
1696 } |
|
1697 |
|
1698 /* key import really did fail */ |
|
1699 rv = SECFailure; |
|
1700 |
|
1701 done: |
|
1702 if(crypto_param != NULL) { |
|
1703 SECITEM_ZfreeItem(crypto_param, PR_TRUE); |
|
1704 } |
|
1705 |
|
1706 if(key != NULL) { |
|
1707 PK11_FreeSymKey(key); |
|
1708 } |
|
1709 |
|
1710 return rv; |
|
1711 } |
|
1712 |
|
1713 SECKEYPrivateKeyInfo * |
|
1714 PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx) |
|
1715 { |
|
1716 SECKEYPrivateKeyInfo *pki = NULL; |
|
1717 SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); |
|
1718 if (pk != NULL) { |
|
1719 pki = PK11_ExportPrivKeyInfo(pk, wincx); |
|
1720 SECKEY_DestroyPrivateKey(pk); |
|
1721 } |
|
1722 return pki; |
|
1723 } |
|
1724 |
|
1725 SECKEYEncryptedPrivateKeyInfo * |
|
1726 PK11_ExportEncryptedPrivKeyInfo( |
|
1727 PK11SlotInfo *slot, /* optional, encrypt key in this slot */ |
|
1728 SECOidTag algTag, /* encrypt key with this algorithm */ |
|
1729 SECItem *pwitem, /* password for PBE encryption */ |
|
1730 SECKEYPrivateKey *pk, /* encrypt this private key */ |
|
1731 int iteration, /* interations for PBE alg */ |
|
1732 void *wincx) /* context for password callback ? */ |
|
1733 { |
|
1734 SECKEYEncryptedPrivateKeyInfo *epki = NULL; |
|
1735 PLArenaPool *arena = NULL; |
|
1736 SECAlgorithmID *algid; |
|
1737 SECOidTag pbeAlgTag = SEC_OID_UNKNOWN; |
|
1738 SECItem *crypto_param = NULL; |
|
1739 PK11SymKey *key = NULL; |
|
1740 SECKEYPrivateKey *tmpPK = NULL; |
|
1741 SECStatus rv = SECSuccess; |
|
1742 CK_RV crv; |
|
1743 CK_ULONG encBufLen; |
|
1744 CK_MECHANISM_TYPE pbeMechType; |
|
1745 CK_MECHANISM_TYPE cryptoMechType; |
|
1746 CK_MECHANISM cryptoMech; |
|
1747 |
|
1748 if (!pwitem || !pk) { |
|
1749 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
1750 return NULL; |
|
1751 } |
|
1752 |
|
1753 algid = sec_pkcs5CreateAlgorithmID(algTag, SEC_OID_UNKNOWN, SEC_OID_UNKNOWN, |
|
1754 &pbeAlgTag, 0, NULL, iteration); |
|
1755 if (algid == NULL) { |
|
1756 return NULL; |
|
1757 } |
|
1758 |
|
1759 arena = PORT_NewArena(2048); |
|
1760 if (arena) |
|
1761 epki = PORT_ArenaZNew(arena, SECKEYEncryptedPrivateKeyInfo); |
|
1762 if(epki == NULL) { |
|
1763 rv = SECFailure; |
|
1764 goto loser; |
|
1765 } |
|
1766 epki->arena = arena; |
|
1767 |
|
1768 |
|
1769 /* if we didn't specify a slot, use the slot the private key was in */ |
|
1770 if (!slot) { |
|
1771 slot = pk->pkcs11Slot; |
|
1772 } |
|
1773 |
|
1774 /* if we specified a different slot, and the private key slot can do the |
|
1775 * pbe key gen, generate the key in the private key slot so we don't have |
|
1776 * to move it later */ |
|
1777 pbeMechType = PK11_AlgtagToMechanism(pbeAlgTag); |
|
1778 if (slot != pk->pkcs11Slot) { |
|
1779 if (PK11_DoesMechanism(pk->pkcs11Slot,pbeMechType)) { |
|
1780 slot = pk->pkcs11Slot; |
|
1781 } |
|
1782 } |
|
1783 key = PK11_PBEKeyGen(slot, algid, pwitem, PR_FALSE, wincx); |
|
1784 if (key == NULL) { |
|
1785 rv = SECFailure; |
|
1786 goto loser; |
|
1787 } |
|
1788 |
|
1789 cryptoMechType = PK11_GetPBECryptoMechanism(algid, &crypto_param, pwitem); |
|
1790 if (cryptoMechType == CKM_INVALID_MECHANISM) { |
|
1791 rv = SECFailure; |
|
1792 goto loser; |
|
1793 } |
|
1794 |
|
1795 cryptoMech.mechanism = PK11_GetPadMechanism(cryptoMechType); |
|
1796 cryptoMech.pParameter = crypto_param ? crypto_param->data : NULL; |
|
1797 cryptoMech.ulParameterLen = crypto_param ? crypto_param->len : 0; |
|
1798 |
|
1799 /* If the key isn't in the private key slot, move it */ |
|
1800 if (key->slot != pk->pkcs11Slot) { |
|
1801 PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot, |
|
1802 key->type, CKA_WRAP, key); |
|
1803 if (newkey == NULL) { |
|
1804 /* couldn't import the wrapping key, try exporting the |
|
1805 * private key */ |
|
1806 tmpPK = pk11_loadPrivKey(key->slot, pk, NULL, PR_FALSE, PR_TRUE); |
|
1807 if (tmpPK == NULL) { |
|
1808 rv = SECFailure; |
|
1809 goto loser; |
|
1810 } |
|
1811 pk = tmpPK; |
|
1812 } else { |
|
1813 /* free the old key and use the new key */ |
|
1814 PK11_FreeSymKey(key); |
|
1815 key = newkey; |
|
1816 } |
|
1817 } |
|
1818 |
|
1819 /* we are extracting an encrypted privateKey structure. |
|
1820 * which needs to be freed along with the buffer into which it is |
|
1821 * returned. eventually, we should retrieve an encrypted key using |
|
1822 * pkcs8/pkcs5. |
|
1823 */ |
|
1824 encBufLen = 0; |
|
1825 PK11_EnterSlotMonitor(pk->pkcs11Slot); |
|
1826 crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, |
|
1827 &cryptoMech, key->objectID, pk->pkcs11ID, NULL, |
|
1828 &encBufLen); |
|
1829 PK11_ExitSlotMonitor(pk->pkcs11Slot); |
|
1830 if (crv != CKR_OK) { |
|
1831 rv = SECFailure; |
|
1832 goto loser; |
|
1833 } |
|
1834 epki->encryptedData.data = PORT_ArenaAlloc(arena, encBufLen); |
|
1835 if (!epki->encryptedData.data) { |
|
1836 rv = SECFailure; |
|
1837 goto loser; |
|
1838 } |
|
1839 PK11_EnterSlotMonitor(pk->pkcs11Slot); |
|
1840 crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, |
|
1841 &cryptoMech, key->objectID, pk->pkcs11ID, |
|
1842 epki->encryptedData.data, &encBufLen); |
|
1843 PK11_ExitSlotMonitor(pk->pkcs11Slot); |
|
1844 epki->encryptedData.len = (unsigned int) encBufLen; |
|
1845 if(crv != CKR_OK) { |
|
1846 rv = SECFailure; |
|
1847 goto loser; |
|
1848 } |
|
1849 |
|
1850 if(!epki->encryptedData.len) { |
|
1851 rv = SECFailure; |
|
1852 goto loser; |
|
1853 } |
|
1854 |
|
1855 rv = SECOID_CopyAlgorithmID(arena, &epki->algorithm, algid); |
|
1856 |
|
1857 loser: |
|
1858 if(crypto_param != NULL) { |
|
1859 SECITEM_ZfreeItem(crypto_param, PR_TRUE); |
|
1860 crypto_param = NULL; |
|
1861 } |
|
1862 |
|
1863 if(key != NULL) { |
|
1864 PK11_FreeSymKey(key); |
|
1865 } |
|
1866 if (tmpPK != NULL) { |
|
1867 SECKEY_DestroyPrivateKey(tmpPK); |
|
1868 } |
|
1869 SECOID_DestroyAlgorithmID(algid, PR_TRUE); |
|
1870 |
|
1871 if(rv == SECFailure) { |
|
1872 if(arena != NULL) { |
|
1873 PORT_FreeArena(arena, PR_TRUE); |
|
1874 } |
|
1875 epki = NULL; |
|
1876 } |
|
1877 |
|
1878 return epki; |
|
1879 } |
|
1880 |
|
1881 SECKEYEncryptedPrivateKeyInfo * |
|
1882 PK11_ExportEncryptedPrivateKeyInfo( |
|
1883 PK11SlotInfo *slot, /* optional, encrypt key in this slot */ |
|
1884 SECOidTag algTag, /* encrypt key with this algorithm */ |
|
1885 SECItem *pwitem, /* password for PBE encryption */ |
|
1886 CERTCertificate *cert, /* wrap priv key for this user cert */ |
|
1887 int iteration, /* interations for PBE alg */ |
|
1888 void *wincx) /* context for password callback ? */ |
|
1889 { |
|
1890 SECKEYEncryptedPrivateKeyInfo *epki = NULL; |
|
1891 SECKEYPrivateKey *pk = PK11_FindKeyByAnyCert(cert, wincx); |
|
1892 if (pk != NULL) { |
|
1893 epki = PK11_ExportEncryptedPrivKeyInfo(slot, algTag, pwitem, pk, |
|
1894 iteration, wincx); |
|
1895 SECKEY_DestroyPrivateKey(pk); |
|
1896 } |
|
1897 return epki; |
|
1898 } |
|
1899 |
|
1900 SECItem* |
|
1901 PK11_DEREncodePublicKey(const SECKEYPublicKey *pubk) |
|
1902 { |
|
1903 return SECKEY_EncodeDERSubjectPublicKeyInfo(pubk); |
|
1904 } |
|
1905 |
|
1906 char * |
|
1907 PK11_GetPrivateKeyNickname(SECKEYPrivateKey *privKey) |
|
1908 { |
|
1909 return PK11_GetObjectNickname(privKey->pkcs11Slot,privKey->pkcs11ID); |
|
1910 } |
|
1911 |
|
1912 char * |
|
1913 PK11_GetPublicKeyNickname(SECKEYPublicKey *pubKey) |
|
1914 { |
|
1915 return PK11_GetObjectNickname(pubKey->pkcs11Slot,pubKey->pkcs11ID); |
|
1916 } |
|
1917 |
|
1918 SECStatus |
|
1919 PK11_SetPrivateKeyNickname(SECKEYPrivateKey *privKey, const char *nickname) |
|
1920 { |
|
1921 return PK11_SetObjectNickname(privKey->pkcs11Slot, |
|
1922 privKey->pkcs11ID,nickname); |
|
1923 } |
|
1924 |
|
1925 SECStatus |
|
1926 PK11_SetPublicKeyNickname(SECKEYPublicKey *pubKey, const char *nickname) |
|
1927 { |
|
1928 return PK11_SetObjectNickname(pubKey->pkcs11Slot, |
|
1929 pubKey->pkcs11ID,nickname); |
|
1930 } |
|
1931 |
|
1932 SECKEYPQGParams * |
|
1933 PK11_GetPQGParamsFromPrivateKey(SECKEYPrivateKey *privKey) |
|
1934 { |
|
1935 CK_ATTRIBUTE pTemplate[] = { |
|
1936 { CKA_PRIME, NULL, 0 }, |
|
1937 { CKA_SUBPRIME, NULL, 0 }, |
|
1938 { CKA_BASE, NULL, 0 }, |
|
1939 }; |
|
1940 int pTemplateLen = sizeof(pTemplate)/sizeof(pTemplate[0]); |
|
1941 PLArenaPool *arena = NULL; |
|
1942 SECKEYPQGParams *params; |
|
1943 CK_RV crv; |
|
1944 |
|
1945 |
|
1946 arena = PORT_NewArena(2048); |
|
1947 if (arena == NULL) { |
|
1948 goto loser; |
|
1949 } |
|
1950 params=(SECKEYPQGParams *)PORT_ArenaZAlloc(arena,sizeof(SECKEYPQGParams)); |
|
1951 if (params == NULL) { |
|
1952 goto loser; |
|
1953 } |
|
1954 |
|
1955 crv = PK11_GetAttributes(arena, privKey->pkcs11Slot, privKey->pkcs11ID, |
|
1956 pTemplate, pTemplateLen); |
|
1957 if (crv != CKR_OK) { |
|
1958 PORT_SetError( PK11_MapError(crv) ); |
|
1959 goto loser; |
|
1960 } |
|
1961 |
|
1962 params->arena = arena; |
|
1963 params->prime.data = pTemplate[0].pValue; |
|
1964 params->prime.len = pTemplate[0].ulValueLen; |
|
1965 params->subPrime.data = pTemplate[1].pValue; |
|
1966 params->subPrime.len = pTemplate[1].ulValueLen; |
|
1967 params->base.data = pTemplate[2].pValue; |
|
1968 params->base.len = pTemplate[2].ulValueLen; |
|
1969 |
|
1970 return params; |
|
1971 |
|
1972 loser: |
|
1973 if (arena != NULL) { |
|
1974 PORT_FreeArena(arena,PR_FALSE); |
|
1975 } |
|
1976 return NULL; |
|
1977 } |
|
1978 |
|
1979 SECKEYPrivateKey* |
|
1980 PK11_CopyTokenPrivKeyToSessionPrivKey(PK11SlotInfo *destSlot, |
|
1981 SECKEYPrivateKey *privKey) |
|
1982 { |
|
1983 CK_RV crv; |
|
1984 CK_OBJECT_HANDLE newKeyID; |
|
1985 |
|
1986 static const CK_BBOOL ckfalse = CK_FALSE; |
|
1987 static const CK_ATTRIBUTE template[1] = { |
|
1988 { CKA_TOKEN, (CK_BBOOL *)&ckfalse, sizeof ckfalse } |
|
1989 }; |
|
1990 |
|
1991 if (destSlot && destSlot != privKey->pkcs11Slot) { |
|
1992 SECKEYPrivateKey *newKey = |
|
1993 pk11_loadPrivKey(destSlot, |
|
1994 privKey, |
|
1995 NULL, /* pubKey */ |
|
1996 PR_FALSE, /* token */ |
|
1997 PR_FALSE);/* sensitive */ |
|
1998 if (newKey) |
|
1999 return newKey; |
|
2000 } |
|
2001 destSlot = privKey->pkcs11Slot; |
|
2002 PK11_Authenticate(destSlot, PR_TRUE, privKey->wincx); |
|
2003 PK11_EnterSlotMonitor(destSlot); |
|
2004 crv = PK11_GETTAB(destSlot)->C_CopyObject( destSlot->session, |
|
2005 privKey->pkcs11ID, |
|
2006 (CK_ATTRIBUTE *)template, |
|
2007 1, &newKeyID); |
|
2008 PK11_ExitSlotMonitor(destSlot); |
|
2009 |
|
2010 if (crv != CKR_OK) { |
|
2011 PORT_SetError( PK11_MapError(crv) ); |
|
2012 return NULL; |
|
2013 } |
|
2014 |
|
2015 return PK11_MakePrivKey(destSlot, privKey->keyType, PR_TRUE /*isTemp*/, |
|
2016 newKeyID, privKey->wincx); |
|
2017 } |
|
2018 |
|
2019 SECKEYPrivateKey* |
|
2020 PK11_ConvertSessionPrivKeyToTokenPrivKey(SECKEYPrivateKey *privk, void* wincx) |
|
2021 { |
|
2022 PK11SlotInfo* slot = privk->pkcs11Slot; |
|
2023 CK_ATTRIBUTE template[1]; |
|
2024 CK_ATTRIBUTE *attrs = template; |
|
2025 CK_BBOOL cktrue = CK_TRUE; |
|
2026 CK_RV crv; |
|
2027 CK_OBJECT_HANDLE newKeyID; |
|
2028 CK_SESSION_HANDLE rwsession; |
|
2029 |
|
2030 PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(cktrue)); attrs++; |
|
2031 |
|
2032 PK11_Authenticate(slot, PR_TRUE, wincx); |
|
2033 rwsession = PK11_GetRWSession(slot); |
|
2034 if (rwsession == CK_INVALID_SESSION) { |
|
2035 PORT_SetError(SEC_ERROR_BAD_DATA); |
|
2036 return NULL; |
|
2037 } |
|
2038 crv = PK11_GETTAB(slot)->C_CopyObject(rwsession, privk->pkcs11ID, |
|
2039 template, 1, &newKeyID); |
|
2040 PK11_RestoreROSession(slot, rwsession); |
|
2041 |
|
2042 if (crv != CKR_OK) { |
|
2043 PORT_SetError( PK11_MapError(crv) ); |
|
2044 return NULL; |
|
2045 } |
|
2046 |
|
2047 return PK11_MakePrivKey(slot, nullKey /*KeyType*/, PR_FALSE /*isTemp*/, |
|
2048 newKeyID, NULL /*wincx*/); |
|
2049 } |
|
2050 |
|
2051 /* |
|
2052 * destroy a private key if there are no matching certs. |
|
2053 * this function also frees the privKey structure. |
|
2054 */ |
|
2055 SECStatus |
|
2056 PK11_DeleteTokenPrivateKey(SECKEYPrivateKey *privKey, PRBool force) |
|
2057 { |
|
2058 CERTCertificate *cert=PK11_GetCertFromPrivateKey(privKey); |
|
2059 SECStatus rv = SECWouldBlock; |
|
2060 |
|
2061 if (!cert || force) { |
|
2062 /* now, then it's safe for the key to go away */ |
|
2063 rv = PK11_DestroyTokenObject(privKey->pkcs11Slot,privKey->pkcs11ID); |
|
2064 } |
|
2065 if (cert) { |
|
2066 CERT_DestroyCertificate(cert); |
|
2067 } |
|
2068 SECKEY_DestroyPrivateKey(privKey); |
|
2069 return rv; |
|
2070 } |
|
2071 |
|
2072 /* |
|
2073 * destroy a private key if there are no matching certs. |
|
2074 * this function also frees the privKey structure. |
|
2075 */ |
|
2076 SECStatus |
|
2077 PK11_DeleteTokenPublicKey(SECKEYPublicKey *pubKey) |
|
2078 { |
|
2079 /* now, then it's safe for the key to go away */ |
|
2080 if (pubKey->pkcs11Slot == NULL) { |
|
2081 return SECFailure; |
|
2082 } |
|
2083 PK11_DestroyTokenObject(pubKey->pkcs11Slot,pubKey->pkcs11ID); |
|
2084 SECKEY_DestroyPublicKey(pubKey); |
|
2085 return SECSuccess; |
|
2086 } |
|
2087 |
|
2088 /* |
|
2089 * key call back structure. |
|
2090 */ |
|
2091 typedef struct pk11KeyCallbackStr { |
|
2092 SECStatus (* callback)(SECKEYPrivateKey *,void *); |
|
2093 void *callbackArg; |
|
2094 void *wincx; |
|
2095 } pk11KeyCallback; |
|
2096 |
|
2097 /* |
|
2098 * callback to map Object Handles to Private Keys; |
|
2099 */ |
|
2100 SECStatus |
|
2101 pk11_DoKeys(PK11SlotInfo *slot, CK_OBJECT_HANDLE keyHandle, void *arg) |
|
2102 { |
|
2103 SECStatus rv = SECSuccess; |
|
2104 SECKEYPrivateKey *privKey; |
|
2105 pk11KeyCallback *keycb = (pk11KeyCallback *) arg; |
|
2106 if (!arg) { |
|
2107 return SECFailure; |
|
2108 } |
|
2109 |
|
2110 privKey = PK11_MakePrivKey(slot,nullKey,PR_TRUE,keyHandle,keycb->wincx); |
|
2111 |
|
2112 if (privKey == NULL) { |
|
2113 return SECFailure; |
|
2114 } |
|
2115 |
|
2116 if (keycb->callback) { |
|
2117 rv = (*keycb->callback)(privKey,keycb->callbackArg); |
|
2118 } |
|
2119 |
|
2120 SECKEY_DestroyPrivateKey(privKey); |
|
2121 return rv; |
|
2122 } |
|
2123 |
|
2124 /*********************************************************************** |
|
2125 * PK11_TraversePrivateKeysInSlot |
|
2126 * |
|
2127 * Traverses all the private keys on a slot. |
|
2128 * |
|
2129 * INPUTS |
|
2130 * slot |
|
2131 * The PKCS #11 slot whose private keys you want to traverse. |
|
2132 * callback |
|
2133 * A callback function that will be called for each key. |
|
2134 * arg |
|
2135 * An argument that will be passed to the callback function. |
|
2136 */ |
|
2137 SECStatus |
|
2138 PK11_TraversePrivateKeysInSlot( PK11SlotInfo *slot, |
|
2139 SECStatus(* callback)(SECKEYPrivateKey*, void*), void *arg) |
|
2140 { |
|
2141 pk11KeyCallback perKeyCB; |
|
2142 pk11TraverseSlot perObjectCB; |
|
2143 CK_OBJECT_CLASS privkClass = CKO_PRIVATE_KEY; |
|
2144 CK_BBOOL ckTrue = CK_TRUE; |
|
2145 CK_ATTRIBUTE theTemplate[2]; |
|
2146 int templateSize = 2; |
|
2147 |
|
2148 theTemplate[0].type = CKA_CLASS; |
|
2149 theTemplate[0].pValue = &privkClass; |
|
2150 theTemplate[0].ulValueLen = sizeof(privkClass); |
|
2151 theTemplate[1].type = CKA_TOKEN; |
|
2152 theTemplate[1].pValue = &ckTrue; |
|
2153 theTemplate[1].ulValueLen = sizeof(ckTrue); |
|
2154 |
|
2155 if(slot==NULL) { |
|
2156 return SECSuccess; |
|
2157 } |
|
2158 |
|
2159 perObjectCB.callback = pk11_DoKeys; |
|
2160 perObjectCB.callbackArg = &perKeyCB; |
|
2161 perObjectCB.findTemplate = theTemplate; |
|
2162 perObjectCB.templateCount = templateSize; |
|
2163 perKeyCB.callback = callback; |
|
2164 perKeyCB.callbackArg = arg; |
|
2165 perKeyCB.wincx = NULL; |
|
2166 |
|
2167 return PK11_TraverseSlot(slot, &perObjectCB); |
|
2168 } |
|
2169 |
|
2170 /* |
|
2171 * return the private key with the given ID |
|
2172 */ |
|
2173 CK_OBJECT_HANDLE |
|
2174 pk11_FindPrivateKeyFromCertID(PK11SlotInfo *slot, SECItem *keyID) |
|
2175 { |
|
2176 CK_OBJECT_CLASS privKey = CKO_PRIVATE_KEY; |
|
2177 CK_ATTRIBUTE theTemplate[] = { |
|
2178 { CKA_ID, NULL, 0 }, |
|
2179 { CKA_CLASS, NULL, 0 }, |
|
2180 }; |
|
2181 /* if you change the array, change the variable below as well */ |
|
2182 int tsize = sizeof(theTemplate)/sizeof(theTemplate[0]); |
|
2183 CK_ATTRIBUTE *attrs = theTemplate; |
|
2184 |
|
2185 PK11_SETATTRS(attrs, CKA_ID, keyID->data, keyID->len ); attrs++; |
|
2186 PK11_SETATTRS(attrs, CKA_CLASS, &privKey, sizeof(privKey)); |
|
2187 |
|
2188 return pk11_FindObjectByTemplate(slot,theTemplate,tsize); |
|
2189 } |
|
2190 |
|
2191 |
|
2192 SECKEYPrivateKey * |
|
2193 PK11_FindKeyByKeyID(PK11SlotInfo *slot, SECItem *keyID, void *wincx) |
|
2194 { |
|
2195 CK_OBJECT_HANDLE keyHandle; |
|
2196 SECKEYPrivateKey *privKey; |
|
2197 |
|
2198 keyHandle = pk11_FindPrivateKeyFromCertID(slot, keyID); |
|
2199 if (keyHandle == CK_INVALID_HANDLE) { |
|
2200 return NULL; |
|
2201 } |
|
2202 privKey = PK11_MakePrivKey(slot, nullKey, PR_TRUE, keyHandle, wincx); |
|
2203 return privKey; |
|
2204 } |
|
2205 |
|
2206 /* |
|
2207 * Generate a CKA_ID from the relevant public key data. The CKA_ID is generated |
|
2208 * from the pubKeyData by SHA1_Hashing it to produce a smaller CKA_ID (to make |
|
2209 * smart cards happy. |
|
2210 */ |
|
2211 SECItem * |
|
2212 PK11_MakeIDFromPubKey(SECItem *pubKeyData) |
|
2213 { |
|
2214 PK11Context *context; |
|
2215 SECItem *certCKA_ID; |
|
2216 SECStatus rv; |
|
2217 |
|
2218 if (pubKeyData->len <= SHA1_LENGTH) { |
|
2219 /* probably an already hashed value. The strongest known public |
|
2220 * key values <= 160 bits would be less than 40 bit symetric in |
|
2221 * strength. Don't hash them, just return the value. There are |
|
2222 * none at the time of this writing supported by previous versions |
|
2223 * of NSS, so change is binary compatible safe */ |
|
2224 return SECITEM_DupItem(pubKeyData); |
|
2225 } |
|
2226 |
|
2227 context = PK11_CreateDigestContext(SEC_OID_SHA1); |
|
2228 if (context == NULL) { |
|
2229 return NULL; |
|
2230 } |
|
2231 |
|
2232 rv = PK11_DigestBegin(context); |
|
2233 if (rv == SECSuccess) { |
|
2234 rv = PK11_DigestOp(context,pubKeyData->data,pubKeyData->len); |
|
2235 } |
|
2236 if (rv != SECSuccess) { |
|
2237 PK11_DestroyContext(context,PR_TRUE); |
|
2238 return NULL; |
|
2239 } |
|
2240 |
|
2241 certCKA_ID = (SECItem *)PORT_Alloc(sizeof(SECItem)); |
|
2242 if (certCKA_ID == NULL) { |
|
2243 PK11_DestroyContext(context,PR_TRUE); |
|
2244 return NULL; |
|
2245 } |
|
2246 |
|
2247 certCKA_ID->len = SHA1_LENGTH; |
|
2248 certCKA_ID->data = (unsigned char*)PORT_Alloc(certCKA_ID->len); |
|
2249 if (certCKA_ID->data == NULL) { |
|
2250 PORT_Free(certCKA_ID); |
|
2251 PK11_DestroyContext(context,PR_TRUE); |
|
2252 return NULL; |
|
2253 } |
|
2254 |
|
2255 rv = PK11_DigestFinal(context,certCKA_ID->data,&certCKA_ID->len, |
|
2256 SHA1_LENGTH); |
|
2257 PK11_DestroyContext(context,PR_TRUE); |
|
2258 if (rv != SECSuccess) { |
|
2259 SECITEM_FreeItem(certCKA_ID,PR_TRUE); |
|
2260 return NULL; |
|
2261 } |
|
2262 |
|
2263 return certCKA_ID; |
|
2264 } |
|
2265 |
|
2266 /* Looking for PK11_GetKeyIDFromPrivateKey? |
|
2267 * Call PK11_GetLowLevelKeyIDForPrivateKey instead. |
|
2268 */ |
|
2269 |
|
2270 |
|
2271 SECItem * |
|
2272 PK11_GetLowLevelKeyIDForPrivateKey(SECKEYPrivateKey *privKey) |
|
2273 { |
|
2274 return pk11_GetLowLevelKeyFromHandle(privKey->pkcs11Slot,privKey->pkcs11ID); |
|
2275 } |
|
2276 |
|
2277 static SECStatus |
|
2278 privateKeyListCallback(SECKEYPrivateKey *key, void *arg) |
|
2279 { |
|
2280 SECKEYPrivateKeyList *list = (SECKEYPrivateKeyList*)arg; |
|
2281 return SECKEY_AddPrivateKeyToListTail(list, SECKEY_CopyPrivateKey(key)); |
|
2282 } |
|
2283 |
|
2284 SECKEYPrivateKeyList* |
|
2285 PK11_ListPrivateKeysInSlot(PK11SlotInfo *slot) |
|
2286 { |
|
2287 SECStatus status; |
|
2288 SECKEYPrivateKeyList *keys; |
|
2289 |
|
2290 keys = SECKEY_NewPrivateKeyList(); |
|
2291 if(keys == NULL) return NULL; |
|
2292 |
|
2293 status = PK11_TraversePrivateKeysInSlot(slot, privateKeyListCallback, |
|
2294 (void*)keys); |
|
2295 |
|
2296 if( status != SECSuccess ) { |
|
2297 SECKEY_DestroyPrivateKeyList(keys); |
|
2298 keys = NULL; |
|
2299 } |
|
2300 |
|
2301 return keys; |
|
2302 } |
|
2303 |
|
2304 SECKEYPublicKeyList* |
|
2305 PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) |
|
2306 { |
|
2307 CK_ATTRIBUTE findTemp[4]; |
|
2308 CK_ATTRIBUTE *attrs; |
|
2309 CK_BBOOL ckTrue = CK_TRUE; |
|
2310 CK_OBJECT_CLASS keyclass = CKO_PUBLIC_KEY; |
|
2311 int tsize = 0; |
|
2312 int objCount = 0; |
|
2313 CK_OBJECT_HANDLE *key_ids; |
|
2314 SECKEYPublicKeyList *keys; |
|
2315 int i,len; |
|
2316 |
|
2317 |
|
2318 attrs = findTemp; |
|
2319 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; |
|
2320 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; |
|
2321 if (nickname) { |
|
2322 len = PORT_Strlen(nickname); |
|
2323 PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; |
|
2324 } |
|
2325 tsize = attrs - findTemp; |
|
2326 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); |
|
2327 |
|
2328 key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); |
|
2329 if (key_ids == NULL) { |
|
2330 return NULL; |
|
2331 } |
|
2332 keys = SECKEY_NewPublicKeyList(); |
|
2333 if (keys == NULL) { |
|
2334 PORT_Free(key_ids); |
|
2335 return NULL; |
|
2336 } |
|
2337 |
|
2338 for (i=0; i < objCount ; i++) { |
|
2339 SECKEYPublicKey *pubKey = |
|
2340 PK11_ExtractPublicKey(slot,nullKey,key_ids[i]); |
|
2341 if (pubKey) { |
|
2342 SECKEY_AddPublicKeyToListTail(keys, pubKey); |
|
2343 } |
|
2344 } |
|
2345 |
|
2346 PORT_Free(key_ids); |
|
2347 return keys; |
|
2348 } |
|
2349 |
|
2350 SECKEYPrivateKeyList* |
|
2351 PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) |
|
2352 { |
|
2353 CK_ATTRIBUTE findTemp[4]; |
|
2354 CK_ATTRIBUTE *attrs; |
|
2355 CK_BBOOL ckTrue = CK_TRUE; |
|
2356 CK_OBJECT_CLASS keyclass = CKO_PRIVATE_KEY; |
|
2357 int tsize = 0; |
|
2358 int objCount = 0; |
|
2359 CK_OBJECT_HANDLE *key_ids; |
|
2360 SECKEYPrivateKeyList *keys; |
|
2361 int i,len; |
|
2362 |
|
2363 |
|
2364 attrs = findTemp; |
|
2365 PK11_SETATTRS(attrs, CKA_CLASS, &keyclass, sizeof(keyclass)); attrs++; |
|
2366 PK11_SETATTRS(attrs, CKA_TOKEN, &ckTrue, sizeof(ckTrue)); attrs++; |
|
2367 if (nickname) { |
|
2368 len = PORT_Strlen(nickname); |
|
2369 PK11_SETATTRS(attrs, CKA_LABEL, nickname, len); attrs++; |
|
2370 } |
|
2371 tsize = attrs - findTemp; |
|
2372 PORT_Assert(tsize <= sizeof(findTemp)/sizeof(CK_ATTRIBUTE)); |
|
2373 |
|
2374 key_ids = pk11_FindObjectsByTemplate(slot,findTemp,tsize,&objCount); |
|
2375 if (key_ids == NULL) { |
|
2376 return NULL; |
|
2377 } |
|
2378 keys = SECKEY_NewPrivateKeyList(); |
|
2379 if (keys == NULL) { |
|
2380 PORT_Free(key_ids); |
|
2381 return NULL; |
|
2382 } |
|
2383 |
|
2384 for (i=0; i < objCount ; i++) { |
|
2385 SECKEYPrivateKey *privKey = |
|
2386 PK11_MakePrivKey(slot,nullKey,PR_TRUE,key_ids[i],wincx); |
|
2387 SECKEY_AddPrivateKeyToListTail(keys, privKey); |
|
2388 } |
|
2389 |
|
2390 PORT_Free(key_ids); |
|
2391 return keys; |
|
2392 } |
|
2393 |