|
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 #include "ckmk.h" |
|
6 #include "nssbase.h" |
|
7 |
|
8 #include "secdert.h" /* for DER_INTEGER */ |
|
9 #include "string.h" |
|
10 |
|
11 /* asn1 encoder (to build pkcs#8 blobs) */ |
|
12 #include <seccomon.h> |
|
13 #include <secitem.h> |
|
14 #include <blapit.h> |
|
15 #include <secoid.h> |
|
16 #include <secasn1.h> |
|
17 |
|
18 /* for importing the keys */ |
|
19 #include <CoreFoundation/CoreFoundation.h> |
|
20 #include <security/SecImportExport.h> |
|
21 |
|
22 /* |
|
23 * nssmkey/mobject.c |
|
24 * |
|
25 * This file implements the NSSCKMDObject object for the |
|
26 * "nssmkey" cryptoki module. |
|
27 */ |
|
28 |
|
29 const CK_ATTRIBUTE_TYPE certAttrs[] = { |
|
30 CKA_CLASS, |
|
31 CKA_TOKEN, |
|
32 CKA_PRIVATE, |
|
33 CKA_MODIFIABLE, |
|
34 CKA_LABEL, |
|
35 CKA_CERTIFICATE_TYPE, |
|
36 CKA_SUBJECT, |
|
37 CKA_ISSUER, |
|
38 CKA_SERIAL_NUMBER, |
|
39 CKA_VALUE |
|
40 }; |
|
41 const PRUint32 certAttrsCount = NSS_CKMK_ARRAY_SIZE(certAttrs); |
|
42 |
|
43 /* private keys, for now only support RSA */ |
|
44 const CK_ATTRIBUTE_TYPE privKeyAttrs[] = { |
|
45 CKA_CLASS, |
|
46 CKA_TOKEN, |
|
47 CKA_PRIVATE, |
|
48 CKA_MODIFIABLE, |
|
49 CKA_LABEL, |
|
50 CKA_KEY_TYPE, |
|
51 CKA_DERIVE, |
|
52 CKA_LOCAL, |
|
53 CKA_SUBJECT, |
|
54 CKA_SENSITIVE, |
|
55 CKA_DECRYPT, |
|
56 CKA_SIGN, |
|
57 CKA_SIGN_RECOVER, |
|
58 CKA_UNWRAP, |
|
59 CKA_EXTRACTABLE, |
|
60 CKA_ALWAYS_SENSITIVE, |
|
61 CKA_NEVER_EXTRACTABLE, |
|
62 CKA_MODULUS, |
|
63 CKA_PUBLIC_EXPONENT, |
|
64 }; |
|
65 const PRUint32 privKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(privKeyAttrs); |
|
66 |
|
67 /* public keys, for now only support RSA */ |
|
68 const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = { |
|
69 CKA_CLASS, |
|
70 CKA_TOKEN, |
|
71 CKA_PRIVATE, |
|
72 CKA_MODIFIABLE, |
|
73 CKA_LABEL, |
|
74 CKA_KEY_TYPE, |
|
75 CKA_DERIVE, |
|
76 CKA_LOCAL, |
|
77 CKA_SUBJECT, |
|
78 CKA_ENCRYPT, |
|
79 CKA_VERIFY, |
|
80 CKA_VERIFY_RECOVER, |
|
81 CKA_WRAP, |
|
82 CKA_MODULUS, |
|
83 CKA_PUBLIC_EXPONENT, |
|
84 }; |
|
85 const PRUint32 pubKeyAttrsCount = NSS_CKMK_ARRAY_SIZE(pubKeyAttrs); |
|
86 static const CK_BBOOL ck_true = CK_TRUE; |
|
87 static const CK_BBOOL ck_false = CK_FALSE; |
|
88 static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509; |
|
89 static const CK_KEY_TYPE ckk_rsa = CKK_RSA; |
|
90 static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE; |
|
91 static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY; |
|
92 static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY; |
|
93 static const NSSItem ckmk_trueItem = { |
|
94 (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL) }; |
|
95 static const NSSItem ckmk_falseItem = { |
|
96 (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL) }; |
|
97 static const NSSItem ckmk_x509Item = { |
|
98 (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE) }; |
|
99 static const NSSItem ckmk_rsaItem = { |
|
100 (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE) }; |
|
101 static const NSSItem ckmk_certClassItem = { |
|
102 (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS) }; |
|
103 static const NSSItem ckmk_privKeyClassItem = { |
|
104 (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; |
|
105 static const NSSItem ckmk_pubKeyClassItem = { |
|
106 (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS) }; |
|
107 static const NSSItem ckmk_emptyItem = { |
|
108 (void *)&ck_true, 0}; |
|
109 |
|
110 /* |
|
111 * these are utilities. The chould be moved to a new utilities file. |
|
112 */ |
|
113 #ifdef DEBUG |
|
114 static void |
|
115 itemdump(char *str, void *data, int size, CK_RV error) |
|
116 { |
|
117 unsigned char *ptr = (unsigned char *)data; |
|
118 int i; |
|
119 fprintf(stderr,str); |
|
120 for (i=0; i < size; i++) { |
|
121 fprintf(stderr,"%02x ",(unsigned int) ptr[i]); |
|
122 } |
|
123 fprintf(stderr," (error = %d)\n", (int ) error); |
|
124 } |
|
125 #endif |
|
126 |
|
127 /* |
|
128 * unwrap a single DER value |
|
129 * now that we have util linked in, we should probably use |
|
130 * the ANS1_Decoder for this work... |
|
131 */ |
|
132 unsigned char * |
|
133 nss_ckmk_DERUnwrap |
|
134 ( |
|
135 unsigned char *src, |
|
136 int size, |
|
137 int *outSize, |
|
138 unsigned char **next |
|
139 ) |
|
140 { |
|
141 unsigned char *start = src; |
|
142 unsigned int len = 0; |
|
143 |
|
144 /* initialize error condition return values */ |
|
145 *outSize = 0; |
|
146 if (next) { |
|
147 *next = src; |
|
148 } |
|
149 |
|
150 if (size < 2) { |
|
151 return start; |
|
152 } |
|
153 src ++ ; /* skip the tag -- should check it against an expected value! */ |
|
154 len = (unsigned) *src++; |
|
155 if (len & 0x80) { |
|
156 int count = len & 0x7f; |
|
157 len =0; |
|
158 |
|
159 if (count+2 > size) { |
|
160 return start; |
|
161 } |
|
162 while (count-- > 0) { |
|
163 len = (len << 8) | (unsigned) *src++; |
|
164 } |
|
165 } |
|
166 if (len + (src-start) > (unsigned int)size) { |
|
167 return start; |
|
168 } |
|
169 if (next) { |
|
170 *next = src+len; |
|
171 } |
|
172 *outSize = len; |
|
173 |
|
174 return src; |
|
175 } |
|
176 |
|
177 /* |
|
178 * get an attribute from a template. Value is returned in NSS item. |
|
179 * data for the item is owned by the template. |
|
180 */ |
|
181 CK_RV |
|
182 nss_ckmk_GetAttribute |
|
183 ( |
|
184 CK_ATTRIBUTE_TYPE type, |
|
185 CK_ATTRIBUTE *template, |
|
186 CK_ULONG templateSize, |
|
187 NSSItem *item |
|
188 ) |
|
189 { |
|
190 CK_ULONG i; |
|
191 |
|
192 for (i=0; i < templateSize; i++) { |
|
193 if (template[i].type == type) { |
|
194 item->data = template[i].pValue; |
|
195 item->size = template[i].ulValueLen; |
|
196 return CKR_OK; |
|
197 } |
|
198 } |
|
199 return CKR_TEMPLATE_INCOMPLETE; |
|
200 } |
|
201 |
|
202 /* |
|
203 * get an attribute which is type CK_ULONG. |
|
204 */ |
|
205 CK_ULONG |
|
206 nss_ckmk_GetULongAttribute |
|
207 ( |
|
208 CK_ATTRIBUTE_TYPE type, |
|
209 CK_ATTRIBUTE *template, |
|
210 CK_ULONG templateSize, |
|
211 CK_RV *pError |
|
212 ) |
|
213 { |
|
214 NSSItem item; |
|
215 |
|
216 *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); |
|
217 if (CKR_OK != *pError) { |
|
218 return (CK_ULONG) 0; |
|
219 } |
|
220 if (item.size != sizeof(CK_ULONG)) { |
|
221 *pError = CKR_ATTRIBUTE_VALUE_INVALID; |
|
222 return (CK_ULONG) 0; |
|
223 } |
|
224 return *(CK_ULONG *)item.data; |
|
225 } |
|
226 |
|
227 /* |
|
228 * get an attribute which is type CK_BBOOL. |
|
229 */ |
|
230 CK_BBOOL |
|
231 nss_ckmk_GetBoolAttribute |
|
232 ( |
|
233 CK_ATTRIBUTE_TYPE type, |
|
234 CK_ATTRIBUTE *template, |
|
235 CK_ULONG templateSize, |
|
236 CK_BBOOL defaultBool |
|
237 ) |
|
238 { |
|
239 NSSItem item; |
|
240 CK_RV error; |
|
241 |
|
242 error = nss_ckmk_GetAttribute(type, template, templateSize, &item); |
|
243 if (CKR_OK != error) { |
|
244 return defaultBool; |
|
245 } |
|
246 if (item.size != sizeof(CK_BBOOL)) { |
|
247 return defaultBool; |
|
248 } |
|
249 return *(CK_BBOOL *)item.data; |
|
250 } |
|
251 |
|
252 /* |
|
253 * get an attribute as a NULL terminated string. Caller is responsible to |
|
254 * free the string. |
|
255 */ |
|
256 char * |
|
257 nss_ckmk_GetStringAttribute |
|
258 ( |
|
259 CK_ATTRIBUTE_TYPE type, |
|
260 CK_ATTRIBUTE *template, |
|
261 CK_ULONG templateSize, |
|
262 CK_RV *pError |
|
263 ) |
|
264 { |
|
265 NSSItem item; |
|
266 char *str; |
|
267 |
|
268 /* get the attribute */ |
|
269 *pError = nss_ckmk_GetAttribute(type, template, templateSize, &item); |
|
270 if (CKR_OK != *pError) { |
|
271 return (char *)NULL; |
|
272 } |
|
273 /* make sure it is null terminated */ |
|
274 str = nss_ZNEWARRAY(NULL, char, item.size+1); |
|
275 if ((char *)NULL == str) { |
|
276 *pError = CKR_HOST_MEMORY; |
|
277 return (char *)NULL; |
|
278 } |
|
279 |
|
280 nsslibc_memcpy(str, item.data, item.size); |
|
281 str[item.size] = 0; |
|
282 |
|
283 return str; |
|
284 } |
|
285 |
|
286 /* |
|
287 * Apple doesn't seem to have a public interface to the DER encoder, |
|
288 * wip out a quick one for integers only (anything more complicated, |
|
289 * we should use one of the 3 in lib/util). -- especially since we |
|
290 * now link with it. |
|
291 */ |
|
292 static CK_RV |
|
293 ckmk_encodeInt(NSSItem *dest, void *src, int srcLen) |
|
294 { |
|
295 int dataLen = srcLen; |
|
296 int lenLen = 1; |
|
297 int encLen; |
|
298 int isSigned = 0; |
|
299 int offset = 0; |
|
300 unsigned char *data = NULL; |
|
301 int i; |
|
302 |
|
303 if (*(unsigned char *)src & 0x80) { |
|
304 dataLen++; |
|
305 isSigned = 1; |
|
306 } |
|
307 |
|
308 /* calculate the length of the length specifier */ |
|
309 /* (NOTE: destroys dataLen value) */ |
|
310 if (dataLen > 0x7f) { |
|
311 do { |
|
312 lenLen++; |
|
313 dataLen >>= 8; |
|
314 } while (dataLen); |
|
315 } |
|
316 |
|
317 /* calculate our total length */ |
|
318 dataLen = isSigned + srcLen; |
|
319 encLen = 1 + lenLen + dataLen; |
|
320 data = nss_ZNEWARRAY(NULL, unsigned char, encLen); |
|
321 if ((unsigned char *)NULL == data) { |
|
322 return CKR_HOST_MEMORY; |
|
323 } |
|
324 data[0] = DER_INTEGER; |
|
325 if (1 == lenLen) { |
|
326 data[1] = dataLen; |
|
327 } else { |
|
328 data[1] = 0x80 + lenLen; |
|
329 for (i=0; i < lenLen; i++) { |
|
330 data[i+1] = ((dataLen >> ((lenLen-i-1)*8)) & 0xff); |
|
331 } |
|
332 } |
|
333 offset = lenLen+1; |
|
334 |
|
335 if (isSigned) { |
|
336 data[offset++] = 0; |
|
337 } |
|
338 nsslibc_memcpy(&data[offset], src, srcLen); |
|
339 dest->data = data; |
|
340 dest->size = encLen; |
|
341 return CKR_OK; |
|
342 } |
|
343 |
|
344 |
|
345 /* |
|
346 * Get a Keyring attribute. If content is set to true, then we get the |
|
347 * content, not the attribute. |
|
348 */ |
|
349 static CK_RV |
|
350 ckmk_GetCommonAttribute |
|
351 ( |
|
352 ckmkInternalObject *io, |
|
353 SecItemAttr itemAttr, |
|
354 PRBool content, |
|
355 NSSItem *item, |
|
356 char *dbString |
|
357 ) |
|
358 { |
|
359 SecKeychainAttributeList *attrList = NULL; |
|
360 SecKeychainAttributeInfo attrInfo; |
|
361 PRUint32 len = 0; |
|
362 PRUint32 dataLen = 0; |
|
363 PRUint32 attrFormat = 0; |
|
364 void *dataVal = 0; |
|
365 void *out = NULL; |
|
366 CK_RV error = CKR_OK; |
|
367 OSStatus macErr; |
|
368 |
|
369 attrInfo.count = 1; |
|
370 attrInfo.tag = &itemAttr; |
|
371 attrInfo.format = &attrFormat; |
|
372 |
|
373 macErr = SecKeychainItemCopyAttributesAndData(io->u.item.itemRef, |
|
374 &attrInfo, NULL, &attrList, &len, &out); |
|
375 if (noErr != macErr) { |
|
376 CKMK_MACERR(dbString, macErr); |
|
377 return CKR_ATTRIBUTE_TYPE_INVALID; |
|
378 } |
|
379 dataLen = content ? len : attrList->attr->length; |
|
380 dataVal = content ? out : attrList->attr->data; |
|
381 |
|
382 /* Apple's documentation says this value is DER Encoded, but it clearly isn't |
|
383 * der encode it before we ship it back off to NSS |
|
384 */ |
|
385 if ( kSecSerialNumberItemAttr == itemAttr ) { |
|
386 error = ckmk_encodeInt(item, dataVal, dataLen); |
|
387 goto loser; /* logically 'done' if error == CKR_OK */ |
|
388 } |
|
389 item->data = nss_ZNEWARRAY(NULL, char, dataLen); |
|
390 if (NULL == item->data) { |
|
391 error = CKR_HOST_MEMORY; |
|
392 goto loser; |
|
393 } |
|
394 nsslibc_memcpy(item->data, dataVal, dataLen); |
|
395 item->size = dataLen; |
|
396 |
|
397 loser: |
|
398 SecKeychainItemFreeAttributesAndData(attrList, out); |
|
399 return error; |
|
400 } |
|
401 |
|
402 /* |
|
403 * change an attribute (does not operate on the content). |
|
404 */ |
|
405 static CK_RV |
|
406 ckmk_updateAttribute |
|
407 ( |
|
408 SecKeychainItemRef itemRef, |
|
409 SecItemAttr itemAttr, |
|
410 void *data, |
|
411 PRUint32 len, |
|
412 char *dbString |
|
413 ) |
|
414 { |
|
415 SecKeychainAttributeList attrList; |
|
416 SecKeychainAttribute attrAttr; |
|
417 OSStatus macErr; |
|
418 CK_RV error = CKR_OK; |
|
419 |
|
420 attrList.count = 1; |
|
421 attrList.attr = &attrAttr; |
|
422 attrAttr.tag = itemAttr; |
|
423 attrAttr.data = data; |
|
424 attrAttr.length = len; |
|
425 macErr = SecKeychainItemModifyAttributesAndData(itemRef, &attrList, 0, NULL); |
|
426 if (noErr != macErr) { |
|
427 CKMK_MACERR(dbString, macErr); |
|
428 error = CKR_ATTRIBUTE_TYPE_INVALID; |
|
429 } |
|
430 return error; |
|
431 } |
|
432 |
|
433 /* |
|
434 * get an attribute (does not operate on the content) |
|
435 */ |
|
436 static CK_RV |
|
437 ckmk_GetDataAttribute |
|
438 ( |
|
439 ckmkInternalObject *io, |
|
440 SecItemAttr itemAttr, |
|
441 NSSItem *item, |
|
442 char *dbString |
|
443 ) |
|
444 { |
|
445 return ckmk_GetCommonAttribute(io, itemAttr, PR_FALSE, item, dbString); |
|
446 } |
|
447 |
|
448 /* |
|
449 * get an attribute we know is a BOOL. |
|
450 */ |
|
451 static CK_RV |
|
452 ckmk_GetBoolAttribute |
|
453 ( |
|
454 ckmkInternalObject *io, |
|
455 SecItemAttr itemAttr, |
|
456 NSSItem *item, |
|
457 char *dbString |
|
458 ) |
|
459 { |
|
460 SecKeychainAttribute attr; |
|
461 SecKeychainAttributeList attrList; |
|
462 CK_BBOOL *boolp = NULL; |
|
463 PRUint32 len = 0;; |
|
464 void *out = NULL; |
|
465 CK_RV error = CKR_OK; |
|
466 OSStatus macErr; |
|
467 |
|
468 attr.tag = itemAttr; |
|
469 attr.length = 0; |
|
470 attr.data = NULL; |
|
471 attrList.count = 1; |
|
472 attrList.attr = &attr; |
|
473 |
|
474 boolp = nss_ZNEW(NULL, CK_BBOOL); |
|
475 if ((CK_BBOOL *)NULL == boolp) { |
|
476 error = CKR_HOST_MEMORY; |
|
477 goto loser; |
|
478 } |
|
479 |
|
480 macErr = SecKeychainItemCopyContent(io->u.item.itemRef, NULL, |
|
481 &attrList, &len, &out); |
|
482 if (noErr != macErr) { |
|
483 CKMK_MACERR(dbString, macErr); |
|
484 error = CKR_ATTRIBUTE_TYPE_INVALID; |
|
485 goto loser; |
|
486 } |
|
487 if (sizeof(PRUint32) != attr.length) { |
|
488 error = CKR_ATTRIBUTE_TYPE_INVALID; |
|
489 goto loser; |
|
490 } |
|
491 *boolp = *(PRUint32 *)attr.data ? 1 : 0; |
|
492 item->data = boolp; |
|
493 boolp = NULL; |
|
494 item->size = sizeof(CK_BBOOL); |
|
495 |
|
496 loser: |
|
497 nss_ZFreeIf(boolp); |
|
498 SecKeychainItemFreeContent(&attrList, out); |
|
499 return error; |
|
500 } |
|
501 |
|
502 |
|
503 /* |
|
504 * macros for fetching attributes into a cache and returning the |
|
505 * appropriate value. These operate inside switch statements |
|
506 */ |
|
507 #define CKMK_HANDLE_ITEM(func, io, type, loc, item, error, str) \ |
|
508 if (0 == (item)->loc.size) { \ |
|
509 error = func(io, type, &(item)->loc, str); \ |
|
510 } \ |
|
511 return (CKR_OK == (error)) ? &(item)->loc : NULL; |
|
512 |
|
513 #define CKMK_HANDLE_OPT_ITEM(func, io, type, loc, item, error, str) \ |
|
514 if (0 == (item)->loc.size) { \ |
|
515 (void) func(io, type, &(item)->loc, str); \ |
|
516 } \ |
|
517 return &(item)->loc ; |
|
518 |
|
519 #define CKMK_HANDLE_BOOL_ITEM(io, type, loc, item, error, str) \ |
|
520 CKMK_HANDLE_ITEM(ckmk_GetBoolAttribute, io, type, loc, item, error, str) |
|
521 #define CKMK_HANDLE_DATA_ITEM(io, type, loc, item, error, str) \ |
|
522 CKMK_HANDLE_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) |
|
523 #define CKMK_HANDLE_OPT_DATA_ITEM(io, type, loc, item, error, str) \ |
|
524 CKMK_HANDLE_OPT_ITEM(ckmk_GetDataAttribute, io, type, loc, item, error, str) |
|
525 |
|
526 /* |
|
527 * fetch the unique identifier for each object type. |
|
528 */ |
|
529 static void |
|
530 ckmk_FetchHashKey |
|
531 ( |
|
532 ckmkInternalObject *io |
|
533 ) |
|
534 { |
|
535 NSSItem *key = &io->hashKey; |
|
536 |
|
537 if (io->objClass == CKO_CERTIFICATE) { |
|
538 ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, |
|
539 PR_TRUE, key, "Fetching HashKey (cert)"); |
|
540 } else { |
|
541 ckmk_GetCommonAttribute(io, kSecKeyLabel, |
|
542 PR_FALSE, key, "Fetching HashKey (key)"); |
|
543 } |
|
544 } |
|
545 |
|
546 /* |
|
547 * Apple mucks with the actual subject and issuer, so go fetch |
|
548 * the real ones ourselves. |
|
549 */ |
|
550 static void |
|
551 ckmk_fetchCert |
|
552 ( |
|
553 ckmkInternalObject *io |
|
554 ) |
|
555 { |
|
556 CK_RV error; |
|
557 unsigned char * cert, *next; |
|
558 int certSize, thisEntrySize; |
|
559 |
|
560 error = ckmk_GetCommonAttribute(io, kSecCertEncodingItemAttr, PR_TRUE, |
|
561 &io->u.item.derCert, "Fetching Value (cert)"); |
|
562 if (CKR_OK != error) { |
|
563 return; |
|
564 } |
|
565 /* unwrap the cert bundle */ |
|
566 cert = nss_ckmk_DERUnwrap((unsigned char *)io->u.item.derCert.data, |
|
567 io->u.item.derCert.size, |
|
568 &certSize, NULL); |
|
569 /* unwrap the cert itself */ |
|
570 /* cert == certdata */ |
|
571 cert = nss_ckmk_DERUnwrap(cert, certSize, &certSize, NULL); |
|
572 |
|
573 /* skip the optional version */ |
|
574 if ((cert[0] & 0xa0) == 0xa0) { |
|
575 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
576 certSize -= next - cert; |
|
577 cert = next; |
|
578 } |
|
579 /* skip the serial number */ |
|
580 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
581 certSize -= next - cert; |
|
582 cert = next; |
|
583 |
|
584 /* skip the OID */ |
|
585 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
586 certSize -= next - cert; |
|
587 cert = next; |
|
588 |
|
589 /* save the (wrapped) issuer */ |
|
590 io->u.item.issuer.data = cert; |
|
591 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
592 io->u.item.issuer.size = next - cert; |
|
593 certSize -= io->u.item.issuer.size; |
|
594 cert = next; |
|
595 |
|
596 /* skip the OID */ |
|
597 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
598 certSize -= next - cert; |
|
599 cert = next; |
|
600 |
|
601 /* save the (wrapped) subject */ |
|
602 io->u.item.subject.data = cert; |
|
603 nss_ckmk_DERUnwrap(cert, certSize, &thisEntrySize, &next); |
|
604 io->u.item.subject.size = next - cert; |
|
605 certSize -= io->u.item.subject.size; |
|
606 cert = next; |
|
607 } |
|
608 |
|
609 static void |
|
610 ckmk_fetchModulus |
|
611 ( |
|
612 ckmkInternalObject *io |
|
613 ) |
|
614 { |
|
615 NSSItem item; |
|
616 PRInt32 modLen; |
|
617 CK_RV error; |
|
618 |
|
619 /* we can't reliably get the modulus for private keys through CSSM (sigh). |
|
620 * For NSS this is OK because we really only use this to get the modulus |
|
621 * length (unless we are trying to get a public key from a private keys, |
|
622 * something CSSM ALSO does not do!). |
|
623 */ |
|
624 error = ckmk_GetDataAttribute(io, kSecKeyKeySizeInBits, &item, |
|
625 "Key Fetch Modulus"); |
|
626 if (CKR_OK != error) { |
|
627 return; |
|
628 } |
|
629 |
|
630 modLen = *(PRInt32 *)item.data; |
|
631 modLen = modLen/8; /* convert from bits to bytes */ |
|
632 |
|
633 nss_ZFreeIf(item.data); |
|
634 io->u.item.modulus.data = nss_ZNEWARRAY(NULL, char, modLen); |
|
635 if (NULL == io->u.item.modulus.data) { |
|
636 return; |
|
637 } |
|
638 *(char *)io->u.item.modulus.data = 0x80; /* fake NSS out or it will |
|
639 * drop the first byte */ |
|
640 io->u.item.modulus.size = modLen; |
|
641 return; |
|
642 } |
|
643 |
|
644 const NSSItem * |
|
645 ckmk_FetchCertAttribute |
|
646 ( |
|
647 ckmkInternalObject *io, |
|
648 CK_ATTRIBUTE_TYPE type, |
|
649 CK_RV *pError |
|
650 ) |
|
651 { |
|
652 ckmkItemObject *item = &io->u.item; |
|
653 *pError = CKR_OK; |
|
654 switch(type) { |
|
655 case CKA_CLASS: |
|
656 return &ckmk_certClassItem; |
|
657 case CKA_TOKEN: |
|
658 case CKA_MODIFIABLE: |
|
659 return &ckmk_trueItem; |
|
660 case CKA_PRIVATE: |
|
661 return &ckmk_falseItem; |
|
662 case CKA_CERTIFICATE_TYPE: |
|
663 return &ckmk_x509Item; |
|
664 case CKA_LABEL: |
|
665 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecLabelItemAttr, label, item, *pError, |
|
666 "Cert:Label attr") |
|
667 case CKA_SUBJECT: |
|
668 /* OK, well apple does provide an subject and issuer attribute, but they |
|
669 * decided to cannonicalize that value. Probably a good move for them, |
|
670 * but makes it useless for most users of PKCS #11.. Get the real subject |
|
671 * from the certificate */ |
|
672 if (0 == item->derCert.size) { |
|
673 ckmk_fetchCert(io); |
|
674 } |
|
675 return &item->subject; |
|
676 case CKA_ISSUER: |
|
677 if (0 == item->derCert.size) { |
|
678 ckmk_fetchCert(io); |
|
679 } |
|
680 return &item->issuer; |
|
681 case CKA_SERIAL_NUMBER: |
|
682 CKMK_HANDLE_DATA_ITEM(io, kSecSerialNumberItemAttr, serial, item, *pError, |
|
683 "Cert:Serial Number attr") |
|
684 case CKA_VALUE: |
|
685 if (0 == item->derCert.size) { |
|
686 ckmk_fetchCert(io); |
|
687 } |
|
688 return &item->derCert; |
|
689 case CKA_ID: |
|
690 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecPublicKeyHashItemAttr, id, item, *pError, |
|
691 "Cert:ID attr") |
|
692 default: |
|
693 *pError = CKR_ATTRIBUTE_TYPE_INVALID; |
|
694 break; |
|
695 } |
|
696 return NULL; |
|
697 } |
|
698 |
|
699 const NSSItem * |
|
700 ckmk_FetchPubKeyAttribute |
|
701 ( |
|
702 ckmkInternalObject *io, |
|
703 CK_ATTRIBUTE_TYPE type, |
|
704 CK_RV *pError |
|
705 ) |
|
706 { |
|
707 ckmkItemObject *item = &io->u.item; |
|
708 *pError = CKR_OK; |
|
709 |
|
710 switch(type) { |
|
711 case CKA_CLASS: |
|
712 return &ckmk_pubKeyClassItem; |
|
713 case CKA_TOKEN: |
|
714 case CKA_LOCAL: |
|
715 return &ckmk_trueItem; |
|
716 case CKA_KEY_TYPE: |
|
717 return &ckmk_rsaItem; |
|
718 case CKA_LABEL: |
|
719 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, |
|
720 "PubKey:Label attr") |
|
721 case CKA_ENCRYPT: |
|
722 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyEncrypt, encrypt, item, *pError, |
|
723 "PubKey:Encrypt attr") |
|
724 case CKA_VERIFY: |
|
725 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerify, verify, item, *pError, |
|
726 "PubKey:Verify attr") |
|
727 case CKA_VERIFY_RECOVER: |
|
728 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyVerifyRecover, verifyRecover, |
|
729 item, *pError, "PubKey:VerifyRecover attr") |
|
730 case CKA_PRIVATE: |
|
731 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, |
|
732 "PubKey:Private attr") |
|
733 case CKA_MODIFIABLE: |
|
734 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, |
|
735 "PubKey:Modify attr") |
|
736 case CKA_DERIVE: |
|
737 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, |
|
738 "PubKey:Derive attr") |
|
739 case CKA_WRAP: |
|
740 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyWrap, wrap, item, *pError, |
|
741 "PubKey:Wrap attr") |
|
742 case CKA_SUBJECT: |
|
743 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, |
|
744 "PubKey:Subect attr") |
|
745 case CKA_MODULUS: |
|
746 return &ckmk_emptyItem; |
|
747 case CKA_PUBLIC_EXPONENT: |
|
748 return &ckmk_emptyItem; |
|
749 case CKA_ID: |
|
750 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, |
|
751 "PubKey:ID attr") |
|
752 default: |
|
753 *pError = CKR_ATTRIBUTE_TYPE_INVALID; |
|
754 break; |
|
755 } |
|
756 return NULL; |
|
757 } |
|
758 |
|
759 const NSSItem * |
|
760 ckmk_FetchPrivKeyAttribute |
|
761 ( |
|
762 ckmkInternalObject *io, |
|
763 CK_ATTRIBUTE_TYPE type, |
|
764 CK_RV *pError |
|
765 ) |
|
766 { |
|
767 ckmkItemObject *item = &io->u.item; |
|
768 *pError = CKR_OK; |
|
769 |
|
770 switch(type) { |
|
771 case CKA_CLASS: |
|
772 return &ckmk_privKeyClassItem; |
|
773 case CKA_TOKEN: |
|
774 case CKA_LOCAL: |
|
775 return &ckmk_trueItem; |
|
776 case CKA_SENSITIVE: |
|
777 case CKA_EXTRACTABLE: /* will probably move in the future */ |
|
778 case CKA_ALWAYS_SENSITIVE: |
|
779 case CKA_NEVER_EXTRACTABLE: |
|
780 return &ckmk_falseItem; |
|
781 case CKA_KEY_TYPE: |
|
782 return &ckmk_rsaItem; |
|
783 case CKA_LABEL: |
|
784 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyPrintName, label, item, *pError, |
|
785 "PrivateKey:Label attr") |
|
786 case CKA_DECRYPT: |
|
787 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDecrypt, decrypt, item, *pError, |
|
788 "PrivateKey:Decrypt attr") |
|
789 case CKA_SIGN: |
|
790 CKMK_HANDLE_BOOL_ITEM(io, kSecKeySign, sign, item, *pError, |
|
791 "PrivateKey:Sign attr") |
|
792 case CKA_SIGN_RECOVER: |
|
793 CKMK_HANDLE_BOOL_ITEM(io, kSecKeySignRecover, signRecover, item, *pError, |
|
794 "PrivateKey:Sign Recover attr") |
|
795 case CKA_PRIVATE: |
|
796 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyPrivate, private, item, *pError, |
|
797 "PrivateKey:Private attr") |
|
798 case CKA_MODIFIABLE: |
|
799 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyModifiable, modify, item, *pError, |
|
800 "PrivateKey:Modify attr") |
|
801 case CKA_DERIVE: |
|
802 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyDerive, derive, item, *pError, |
|
803 "PrivateKey:Derive attr") |
|
804 case CKA_UNWRAP: |
|
805 CKMK_HANDLE_BOOL_ITEM(io, kSecKeyUnwrap, unwrap, item, *pError, |
|
806 "PrivateKey:Unwrap attr") |
|
807 case CKA_SUBJECT: |
|
808 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecSubjectItemAttr, subject, item, *pError, |
|
809 "PrivateKey:Subject attr") |
|
810 case CKA_MODULUS: |
|
811 if (0 == item->modulus.size) { |
|
812 ckmk_fetchModulus(io); |
|
813 } |
|
814 return &item->modulus; |
|
815 case CKA_PUBLIC_EXPONENT: |
|
816 return &ckmk_emptyItem; |
|
817 #ifdef notdef |
|
818 /* the following are sensitive attributes. We could implement them for |
|
819 * sensitive keys using the key export function, but it's better to |
|
820 * just support wrap through this token. That will more reliably allow us |
|
821 * to export any private key that is truly exportable. |
|
822 */ |
|
823 case CKA_PRIVATE_EXPONENT: |
|
824 CKMK_HANDLE_DATA_ITEM(io, kSecPrivateExponentItemAttr, privateExponent, |
|
825 item, *pError) |
|
826 case CKA_PRIME_1: |
|
827 CKMK_HANDLE_DATA_ITEM(io, kSecPrime1ItemAttr, prime1, item, *pError) |
|
828 case CKA_PRIME_2: |
|
829 CKMK_HANDLE_DATA_ITEM(io, kSecPrime2ItemAttr, prime2, item, *pError) |
|
830 case CKA_EXPONENT_1: |
|
831 CKMK_HANDLE_DATA_ITEM(io, kSecExponent1ItemAttr, exponent1, item, *pError) |
|
832 case CKA_EXPONENT_2: |
|
833 CKMK_HANDLE_DATA_ITEM(io, kSecExponent2ItemAttr, exponent2, item, *pError) |
|
834 case CKA_COEFFICIENT: |
|
835 CKMK_HANDLE_DATA_ITEM(io, kSecCoefficientItemAttr, coefficient, |
|
836 item, *pError) |
|
837 #endif |
|
838 case CKA_ID: |
|
839 CKMK_HANDLE_OPT_DATA_ITEM(io, kSecKeyLabel, id, item, *pError, |
|
840 "PrivateKey:ID attr") |
|
841 default: |
|
842 *pError = CKR_ATTRIBUTE_TYPE_INVALID; |
|
843 return NULL; |
|
844 } |
|
845 } |
|
846 |
|
847 const NSSItem * |
|
848 nss_ckmk_FetchAttribute |
|
849 ( |
|
850 ckmkInternalObject *io, |
|
851 CK_ATTRIBUTE_TYPE type, |
|
852 CK_RV *pError |
|
853 ) |
|
854 { |
|
855 CK_ULONG i; |
|
856 const NSSItem * value = NULL; |
|
857 |
|
858 if (io->type == ckmkRaw) { |
|
859 for( i = 0; i < io->u.raw.n; i++ ) { |
|
860 if( type == io->u.raw.types[i] ) { |
|
861 return &io->u.raw.items[i]; |
|
862 } |
|
863 } |
|
864 *pError = CKR_ATTRIBUTE_TYPE_INVALID; |
|
865 return NULL; |
|
866 } |
|
867 /* deal with the common attributes */ |
|
868 switch (io->objClass) { |
|
869 case CKO_CERTIFICATE: |
|
870 value = ckmk_FetchCertAttribute(io, type, pError); |
|
871 break; |
|
872 case CKO_PRIVATE_KEY: |
|
873 value = ckmk_FetchPrivKeyAttribute(io, type, pError); |
|
874 break; |
|
875 case CKO_PUBLIC_KEY: |
|
876 value = ckmk_FetchPubKeyAttribute(io, type, pError); |
|
877 break; |
|
878 default: |
|
879 *pError = CKR_OBJECT_HANDLE_INVALID; |
|
880 return NULL; |
|
881 } |
|
882 |
|
883 #ifdef DEBUG |
|
884 if (CKA_ID == type) { |
|
885 itemdump("id: ", value->data, value->size, *pError); |
|
886 } |
|
887 #endif |
|
888 return value; |
|
889 } |
|
890 |
|
891 static void |
|
892 ckmk_removeObjectFromHash |
|
893 ( |
|
894 ckmkInternalObject *io |
|
895 ); |
|
896 |
|
897 /* |
|
898 * |
|
899 * These are the MSObject functions we need to implement |
|
900 * |
|
901 * Finalize - unneeded (actually we should clean up the hashtables) |
|
902 * Destroy |
|
903 * IsTokenObject - CK_TRUE |
|
904 * GetAttributeCount |
|
905 * GetAttributeTypes |
|
906 * GetAttributeSize |
|
907 * GetAttribute |
|
908 * SetAttribute |
|
909 * GetObjectSize |
|
910 */ |
|
911 |
|
912 static CK_RV |
|
913 ckmk_mdObject_Destroy |
|
914 ( |
|
915 NSSCKMDObject *mdObject, |
|
916 NSSCKFWObject *fwObject, |
|
917 NSSCKMDSession *mdSession, |
|
918 NSSCKFWSession *fwSession, |
|
919 NSSCKMDToken *mdToken, |
|
920 NSSCKFWToken *fwToken, |
|
921 NSSCKMDInstance *mdInstance, |
|
922 NSSCKFWInstance *fwInstance |
|
923 ) |
|
924 { |
|
925 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
926 OSStatus macErr; |
|
927 |
|
928 if (ckmkRaw == io->type) { |
|
929 /* there is not 'object write protected' error, use the next best thing */ |
|
930 return CKR_TOKEN_WRITE_PROTECTED; |
|
931 } |
|
932 |
|
933 /* This API is done well. The following 4 lines are the complete apple |
|
934 * specific part of this implementation */ |
|
935 macErr = SecKeychainItemDelete(io->u.item.itemRef); |
|
936 if (noErr != macErr) { |
|
937 CKMK_MACERR("Delete object", macErr); |
|
938 } |
|
939 |
|
940 /* remove it from the hash */ |
|
941 ckmk_removeObjectFromHash(io); |
|
942 |
|
943 /* free the puppy.. */ |
|
944 nss_ckmk_DestroyInternalObject(io); |
|
945 |
|
946 return CKR_OK; |
|
947 } |
|
948 |
|
949 static CK_BBOOL |
|
950 ckmk_mdObject_IsTokenObject |
|
951 ( |
|
952 NSSCKMDObject *mdObject, |
|
953 NSSCKFWObject *fwObject, |
|
954 NSSCKMDSession *mdSession, |
|
955 NSSCKFWSession *fwSession, |
|
956 NSSCKMDToken *mdToken, |
|
957 NSSCKFWToken *fwToken, |
|
958 NSSCKMDInstance *mdInstance, |
|
959 NSSCKFWInstance *fwInstance |
|
960 ) |
|
961 { |
|
962 return CK_TRUE; |
|
963 } |
|
964 |
|
965 static CK_ULONG |
|
966 ckmk_mdObject_GetAttributeCount |
|
967 ( |
|
968 NSSCKMDObject *mdObject, |
|
969 NSSCKFWObject *fwObject, |
|
970 NSSCKMDSession *mdSession, |
|
971 NSSCKFWSession *fwSession, |
|
972 NSSCKMDToken *mdToken, |
|
973 NSSCKFWToken *fwToken, |
|
974 NSSCKMDInstance *mdInstance, |
|
975 NSSCKFWInstance *fwInstance, |
|
976 CK_RV *pError |
|
977 ) |
|
978 { |
|
979 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
980 |
|
981 if (ckmkRaw == io->type) { |
|
982 return io->u.raw.n; |
|
983 } |
|
984 switch (io->objClass) { |
|
985 case CKO_CERTIFICATE: |
|
986 return certAttrsCount; |
|
987 case CKO_PUBLIC_KEY: |
|
988 return pubKeyAttrsCount; |
|
989 case CKO_PRIVATE_KEY: |
|
990 return privKeyAttrsCount; |
|
991 default: |
|
992 break; |
|
993 } |
|
994 return 0; |
|
995 } |
|
996 |
|
997 static CK_RV |
|
998 ckmk_mdObject_GetAttributeTypes |
|
999 ( |
|
1000 NSSCKMDObject *mdObject, |
|
1001 NSSCKFWObject *fwObject, |
|
1002 NSSCKMDSession *mdSession, |
|
1003 NSSCKFWSession *fwSession, |
|
1004 NSSCKMDToken *mdToken, |
|
1005 NSSCKFWToken *fwToken, |
|
1006 NSSCKMDInstance *mdInstance, |
|
1007 NSSCKFWInstance *fwInstance, |
|
1008 CK_ATTRIBUTE_TYPE_PTR typeArray, |
|
1009 CK_ULONG ulCount |
|
1010 ) |
|
1011 { |
|
1012 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
1013 CK_ULONG i; |
|
1014 CK_RV error = CKR_OK; |
|
1015 const CK_ATTRIBUTE_TYPE *attrs = NULL; |
|
1016 CK_ULONG size = ckmk_mdObject_GetAttributeCount( |
|
1017 mdObject, fwObject, mdSession, fwSession, |
|
1018 mdToken, fwToken, mdInstance, fwInstance, &error); |
|
1019 |
|
1020 if( size != ulCount ) { |
|
1021 return CKR_BUFFER_TOO_SMALL; |
|
1022 } |
|
1023 if (io->type == ckmkRaw) { |
|
1024 attrs = io->u.raw.types; |
|
1025 } else switch(io->objClass) { |
|
1026 case CKO_CERTIFICATE: |
|
1027 attrs = certAttrs; |
|
1028 break; |
|
1029 case CKO_PUBLIC_KEY: |
|
1030 attrs = pubKeyAttrs; |
|
1031 break; |
|
1032 case CKO_PRIVATE_KEY: |
|
1033 attrs = privKeyAttrs; |
|
1034 break; |
|
1035 default: |
|
1036 return CKR_OK; |
|
1037 } |
|
1038 |
|
1039 for( i = 0; i < size; i++) { |
|
1040 typeArray[i] = attrs[i]; |
|
1041 } |
|
1042 |
|
1043 return CKR_OK; |
|
1044 } |
|
1045 |
|
1046 static CK_ULONG |
|
1047 ckmk_mdObject_GetAttributeSize |
|
1048 ( |
|
1049 NSSCKMDObject *mdObject, |
|
1050 NSSCKFWObject *fwObject, |
|
1051 NSSCKMDSession *mdSession, |
|
1052 NSSCKFWSession *fwSession, |
|
1053 NSSCKMDToken *mdToken, |
|
1054 NSSCKFWToken *fwToken, |
|
1055 NSSCKMDInstance *mdInstance, |
|
1056 NSSCKFWInstance *fwInstance, |
|
1057 CK_ATTRIBUTE_TYPE attribute, |
|
1058 CK_RV *pError |
|
1059 ) |
|
1060 { |
|
1061 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
1062 |
|
1063 const NSSItem *b; |
|
1064 |
|
1065 b = nss_ckmk_FetchAttribute(io, attribute, pError); |
|
1066 |
|
1067 if ((const NSSItem *)NULL == b) { |
|
1068 return 0; |
|
1069 } |
|
1070 return b->size; |
|
1071 } |
|
1072 |
|
1073 static CK_RV |
|
1074 ckmk_mdObject_SetAttribute |
|
1075 ( |
|
1076 NSSCKMDObject *mdObject, |
|
1077 NSSCKFWObject *fwObject, |
|
1078 NSSCKMDSession *mdSession, |
|
1079 NSSCKFWSession *fwSession, |
|
1080 NSSCKMDToken *mdToken, |
|
1081 NSSCKFWToken *fwToken, |
|
1082 NSSCKMDInstance *mdInstance, |
|
1083 NSSCKFWInstance *fwInstance, |
|
1084 CK_ATTRIBUTE_TYPE attribute, |
|
1085 NSSItem *value |
|
1086 ) |
|
1087 { |
|
1088 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
1089 SecKeychainItemRef itemRef; |
|
1090 |
|
1091 if (io->type == ckmkRaw) { |
|
1092 return CKR_TOKEN_WRITE_PROTECTED; |
|
1093 } |
|
1094 itemRef = io->u.item.itemRef; |
|
1095 |
|
1096 switch (io->objClass) { |
|
1097 case CKO_PRIVATE_KEY: |
|
1098 case CKO_PUBLIC_KEY: |
|
1099 switch (attribute) { |
|
1100 case CKA_ID: |
|
1101 ckmk_updateAttribute(itemRef, kSecKeyLabel, |
|
1102 value->data, value->size, "Set Attr Key ID"); |
|
1103 #ifdef DEBUG |
|
1104 itemdump("key id: ", value->data, value->size, CKR_OK); |
|
1105 #endif |
|
1106 break; |
|
1107 case CKA_LABEL: |
|
1108 ckmk_updateAttribute(itemRef, kSecKeyPrintName, value->data, |
|
1109 value->size, "Set Attr Key Label"); |
|
1110 break; |
|
1111 default: |
|
1112 break; |
|
1113 } |
|
1114 break; |
|
1115 |
|
1116 case CKO_CERTIFICATE: |
|
1117 switch (attribute) { |
|
1118 case CKA_ID: |
|
1119 ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, |
|
1120 value->data, value->size, "Set Attr Cert ID"); |
|
1121 break; |
|
1122 case CKA_LABEL: |
|
1123 ckmk_updateAttribute(itemRef, kSecLabelItemAttr, value->data, |
|
1124 value->size, "Set Attr Cert Label"); |
|
1125 break; |
|
1126 default: |
|
1127 break; |
|
1128 } |
|
1129 break; |
|
1130 |
|
1131 default: |
|
1132 break; |
|
1133 } |
|
1134 return CKR_OK; |
|
1135 } |
|
1136 |
|
1137 static NSSCKFWItem |
|
1138 ckmk_mdObject_GetAttribute |
|
1139 ( |
|
1140 NSSCKMDObject *mdObject, |
|
1141 NSSCKFWObject *fwObject, |
|
1142 NSSCKMDSession *mdSession, |
|
1143 NSSCKFWSession *fwSession, |
|
1144 NSSCKMDToken *mdToken, |
|
1145 NSSCKFWToken *fwToken, |
|
1146 NSSCKMDInstance *mdInstance, |
|
1147 NSSCKFWInstance *fwInstance, |
|
1148 CK_ATTRIBUTE_TYPE attribute, |
|
1149 CK_RV *pError |
|
1150 ) |
|
1151 { |
|
1152 NSSCKFWItem mdItem; |
|
1153 ckmkInternalObject *io = (ckmkInternalObject *)mdObject->etc; |
|
1154 |
|
1155 mdItem.needsFreeing = PR_FALSE; |
|
1156 mdItem.item = (NSSItem*)nss_ckmk_FetchAttribute(io, attribute, pError); |
|
1157 |
|
1158 |
|
1159 return mdItem; |
|
1160 } |
|
1161 |
|
1162 static CK_ULONG |
|
1163 ckmk_mdObject_GetObjectSize |
|
1164 ( |
|
1165 NSSCKMDObject *mdObject, |
|
1166 NSSCKFWObject *fwObject, |
|
1167 NSSCKMDSession *mdSession, |
|
1168 NSSCKFWSession *fwSession, |
|
1169 NSSCKMDToken *mdToken, |
|
1170 NSSCKFWToken *fwToken, |
|
1171 NSSCKMDInstance *mdInstance, |
|
1172 NSSCKFWInstance *fwInstance, |
|
1173 CK_RV *pError |
|
1174 ) |
|
1175 { |
|
1176 CK_ULONG rv = 1; |
|
1177 |
|
1178 /* size is irrelevant to this token */ |
|
1179 return rv; |
|
1180 } |
|
1181 |
|
1182 static const NSSCKMDObject |
|
1183 ckmk_prototype_mdObject = { |
|
1184 (void *)NULL, /* etc */ |
|
1185 NULL, /* Finalize */ |
|
1186 ckmk_mdObject_Destroy, |
|
1187 ckmk_mdObject_IsTokenObject, |
|
1188 ckmk_mdObject_GetAttributeCount, |
|
1189 ckmk_mdObject_GetAttributeTypes, |
|
1190 ckmk_mdObject_GetAttributeSize, |
|
1191 ckmk_mdObject_GetAttribute, |
|
1192 NULL, /* FreeAttribute */ |
|
1193 ckmk_mdObject_SetAttribute, |
|
1194 ckmk_mdObject_GetObjectSize, |
|
1195 (void *)NULL /* null terminator */ |
|
1196 }; |
|
1197 |
|
1198 static nssHash *ckmkInternalObjectHash = NULL; |
|
1199 |
|
1200 NSS_IMPLEMENT NSSCKMDObject * |
|
1201 nss_ckmk_CreateMDObject |
|
1202 ( |
|
1203 NSSArena *arena, |
|
1204 ckmkInternalObject *io, |
|
1205 CK_RV *pError |
|
1206 ) |
|
1207 { |
|
1208 if ((nssHash *)NULL == ckmkInternalObjectHash) { |
|
1209 ckmkInternalObjectHash = nssHash_CreateItem(NULL, 10); |
|
1210 } |
|
1211 if (ckmkItem == io->type) { |
|
1212 /* the hash key, not a cryptographic key */ |
|
1213 NSSItem *key = &io->hashKey; |
|
1214 ckmkInternalObject *old_o = NULL; |
|
1215 |
|
1216 if (key->size == 0) { |
|
1217 ckmk_FetchHashKey(io); |
|
1218 } |
|
1219 old_o = (ckmkInternalObject *) |
|
1220 nssHash_Lookup(ckmkInternalObjectHash, key); |
|
1221 if (!old_o) { |
|
1222 nssHash_Add(ckmkInternalObjectHash, key, io); |
|
1223 } else if (old_o != io) { |
|
1224 nss_ckmk_DestroyInternalObject(io); |
|
1225 io = old_o; |
|
1226 } |
|
1227 } |
|
1228 |
|
1229 if ( (void*)NULL == io->mdObject.etc) { |
|
1230 (void) nsslibc_memcpy(&io->mdObject,&ckmk_prototype_mdObject, |
|
1231 sizeof(ckmk_prototype_mdObject)); |
|
1232 io->mdObject.etc = (void *)io; |
|
1233 } |
|
1234 return &io->mdObject; |
|
1235 } |
|
1236 |
|
1237 static void |
|
1238 ckmk_removeObjectFromHash |
|
1239 ( |
|
1240 ckmkInternalObject *io |
|
1241 ) |
|
1242 { |
|
1243 NSSItem *key = &io->hashKey; |
|
1244 |
|
1245 if ((nssHash *)NULL == ckmkInternalObjectHash) { |
|
1246 return; |
|
1247 } |
|
1248 if (key->size == 0) { |
|
1249 ckmk_FetchHashKey(io); |
|
1250 } |
|
1251 nssHash_Remove(ckmkInternalObjectHash, key); |
|
1252 return; |
|
1253 } |
|
1254 |
|
1255 |
|
1256 void |
|
1257 nss_ckmk_DestroyInternalObject |
|
1258 ( |
|
1259 ckmkInternalObject *io |
|
1260 ) |
|
1261 { |
|
1262 switch (io->type) { |
|
1263 case ckmkRaw: |
|
1264 return; |
|
1265 case ckmkItem: |
|
1266 nss_ZFreeIf(io->u.item.modify.data); |
|
1267 nss_ZFreeIf(io->u.item.private.data); |
|
1268 nss_ZFreeIf(io->u.item.encrypt.data); |
|
1269 nss_ZFreeIf(io->u.item.decrypt.data); |
|
1270 nss_ZFreeIf(io->u.item.derive.data); |
|
1271 nss_ZFreeIf(io->u.item.sign.data); |
|
1272 nss_ZFreeIf(io->u.item.signRecover.data); |
|
1273 nss_ZFreeIf(io->u.item.verify.data); |
|
1274 nss_ZFreeIf(io->u.item.verifyRecover.data); |
|
1275 nss_ZFreeIf(io->u.item.wrap.data); |
|
1276 nss_ZFreeIf(io->u.item.unwrap.data); |
|
1277 nss_ZFreeIf(io->u.item.label.data); |
|
1278 /*nss_ZFreeIf(io->u.item.subject.data); */ |
|
1279 /*nss_ZFreeIf(io->u.item.issuer.data); */ |
|
1280 nss_ZFreeIf(io->u.item.serial.data); |
|
1281 nss_ZFreeIf(io->u.item.modulus.data); |
|
1282 nss_ZFreeIf(io->u.item.exponent.data); |
|
1283 nss_ZFreeIf(io->u.item.privateExponent.data); |
|
1284 nss_ZFreeIf(io->u.item.prime1.data); |
|
1285 nss_ZFreeIf(io->u.item.prime2.data); |
|
1286 nss_ZFreeIf(io->u.item.exponent1.data); |
|
1287 nss_ZFreeIf(io->u.item.exponent2.data); |
|
1288 nss_ZFreeIf(io->u.item.coefficient.data); |
|
1289 break; |
|
1290 } |
|
1291 nss_ZFreeIf(io); |
|
1292 return; |
|
1293 } |
|
1294 |
|
1295 |
|
1296 static ckmkInternalObject * |
|
1297 nss_ckmk_NewInternalObject |
|
1298 ( |
|
1299 CK_OBJECT_CLASS objClass, |
|
1300 SecKeychainItemRef itemRef, |
|
1301 SecItemClass itemClass, |
|
1302 CK_RV *pError |
|
1303 ) |
|
1304 { |
|
1305 ckmkInternalObject *io = nss_ZNEW(NULL, ckmkInternalObject); |
|
1306 |
|
1307 if ((ckmkInternalObject *)NULL == io) { |
|
1308 *pError = CKR_HOST_MEMORY; |
|
1309 return io; |
|
1310 } |
|
1311 io->type = ckmkItem; |
|
1312 io->objClass = objClass; |
|
1313 io->u.item.itemRef = itemRef; |
|
1314 io->u.item.itemClass = itemClass; |
|
1315 return io; |
|
1316 } |
|
1317 |
|
1318 /* |
|
1319 * Apple doesn't alway have a default keyChain set by the OS, use the |
|
1320 * SearchList to try to find one. |
|
1321 */ |
|
1322 static CK_RV |
|
1323 ckmk_GetSafeDefaultKeychain |
|
1324 ( |
|
1325 SecKeychainRef *keychainRef |
|
1326 ) |
|
1327 { |
|
1328 OSStatus macErr; |
|
1329 CFArrayRef searchList = 0; |
|
1330 CK_RV error = CKR_OK; |
|
1331 |
|
1332 macErr = SecKeychainCopyDefault(keychainRef); |
|
1333 if (noErr != macErr) { |
|
1334 int searchCount = 0; |
|
1335 if (errSecNoDefaultKeychain != macErr) { |
|
1336 CKMK_MACERR("Getting default key chain", macErr); |
|
1337 error = CKR_GENERAL_ERROR; |
|
1338 goto loser; |
|
1339 } |
|
1340 /* ok, we don't have a default key chain, find one */ |
|
1341 macErr = SecKeychainCopySearchList(&searchList); |
|
1342 if (noErr != macErr) { |
|
1343 CKMK_MACERR("failed to find a keyring searchList", macErr); |
|
1344 error = CKR_DEVICE_REMOVED; |
|
1345 goto loser; |
|
1346 } |
|
1347 searchCount = CFArrayGetCount(searchList); |
|
1348 if (searchCount < 1) { |
|
1349 error = CKR_DEVICE_REMOVED; |
|
1350 goto loser; |
|
1351 } |
|
1352 *keychainRef = |
|
1353 (SecKeychainRef)CFRetain(CFArrayGetValueAtIndex(searchList, 0)); |
|
1354 if (0 == *keychainRef) { |
|
1355 error = CKR_DEVICE_REMOVED; |
|
1356 goto loser; |
|
1357 } |
|
1358 /* should we set it as default? */ |
|
1359 } |
|
1360 loser: |
|
1361 if (0 != searchList) { |
|
1362 CFRelease(searchList); |
|
1363 } |
|
1364 return error; |
|
1365 } |
|
1366 static ckmkInternalObject * |
|
1367 nss_ckmk_CreateCertificate |
|
1368 ( |
|
1369 NSSCKFWSession *fwSession, |
|
1370 CK_ATTRIBUTE_PTR pTemplate, |
|
1371 CK_ULONG ulAttributeCount, |
|
1372 CK_RV *pError |
|
1373 ) |
|
1374 { |
|
1375 NSSItem value; |
|
1376 ckmkInternalObject *io = NULL; |
|
1377 OSStatus macErr; |
|
1378 SecCertificateRef certRef; |
|
1379 SecKeychainItemRef itemRef; |
|
1380 SecKeychainRef keychainRef; |
|
1381 CSSM_DATA certData; |
|
1382 |
|
1383 *pError = nss_ckmk_GetAttribute(CKA_VALUE, pTemplate, |
|
1384 ulAttributeCount, &value); |
|
1385 if (CKR_OK != *pError) { |
|
1386 goto loser; |
|
1387 } |
|
1388 |
|
1389 certData.Data = value.data; |
|
1390 certData.Length = value.size; |
|
1391 macErr = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, |
|
1392 CSSM_CERT_ENCODING_BER, &certRef); |
|
1393 if (noErr != macErr) { |
|
1394 CKMK_MACERR("Create cert from data Failed", macErr); |
|
1395 *pError = CKR_GENERAL_ERROR; /* need to map macErr */ |
|
1396 goto loser; |
|
1397 } |
|
1398 |
|
1399 *pError = ckmk_GetSafeDefaultKeychain(&keychainRef); |
|
1400 if (CKR_OK != *pError) { |
|
1401 goto loser; |
|
1402 } |
|
1403 |
|
1404 macErr = SecCertificateAddToKeychain( certRef, keychainRef); |
|
1405 itemRef = (SecKeychainItemRef) certRef; |
|
1406 if (errSecDuplicateItem != macErr) { |
|
1407 NSSItem keyID = { NULL, 0 }; |
|
1408 char *nickname = NULL; |
|
1409 CK_RV dummy; |
|
1410 |
|
1411 if (noErr != macErr) { |
|
1412 CKMK_MACERR("Add cert to keychain Failed", macErr); |
|
1413 *pError = CKR_GENERAL_ERROR; /* need to map macErr */ |
|
1414 goto loser; |
|
1415 } |
|
1416 /* these two are optional */ |
|
1417 nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, |
|
1418 ulAttributeCount, &dummy); |
|
1419 /* we've added a new one, update the attributes in the key ring */ |
|
1420 if (nickname) { |
|
1421 ckmk_updateAttribute(itemRef, kSecLabelItemAttr, nickname, |
|
1422 strlen(nickname)+1, "Modify Cert Label"); |
|
1423 nss_ZFreeIf(nickname); |
|
1424 } |
|
1425 dummy = nss_ckmk_GetAttribute(CKA_ID, pTemplate, |
|
1426 ulAttributeCount, &keyID); |
|
1427 if (CKR_OK == dummy) { |
|
1428 dummy = ckmk_updateAttribute(itemRef, kSecPublicKeyHashItemAttr, |
|
1429 keyID.data, keyID.size, "Modify Cert ID"); |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 io = nss_ckmk_NewInternalObject(CKO_CERTIFICATE, itemRef, |
|
1434 kSecCertificateItemClass, pError); |
|
1435 if ((ckmkInternalObject *)NULL != io) { |
|
1436 itemRef = 0; |
|
1437 } |
|
1438 |
|
1439 loser: |
|
1440 if (0 != itemRef) { |
|
1441 CFRelease(itemRef); |
|
1442 } |
|
1443 if (0 != keychainRef) { |
|
1444 CFRelease(keychainRef); |
|
1445 } |
|
1446 |
|
1447 return io; |
|
1448 } |
|
1449 |
|
1450 /* |
|
1451 * PKCS #8 attributes |
|
1452 */ |
|
1453 struct ckmk_AttributeStr { |
|
1454 SECItem attrType; |
|
1455 SECItem *attrValue; |
|
1456 }; |
|
1457 typedef struct ckmk_AttributeStr ckmk_Attribute; |
|
1458 |
|
1459 /* |
|
1460 ** A PKCS#8 private key info object |
|
1461 */ |
|
1462 struct PrivateKeyInfoStr { |
|
1463 PLArenaPool *arena; |
|
1464 SECItem version; |
|
1465 SECAlgorithmID algorithm; |
|
1466 SECItem privateKey; |
|
1467 ckmk_Attribute **attributes; |
|
1468 }; |
|
1469 typedef struct PrivateKeyInfoStr PrivateKeyInfo; |
|
1470 |
|
1471 const SEC_ASN1Template ckmk_RSAPrivateKeyTemplate[] = { |
|
1472 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(RSAPrivateKey) }, |
|
1473 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,version) }, |
|
1474 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,modulus) }, |
|
1475 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,publicExponent) }, |
|
1476 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,privateExponent) }, |
|
1477 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime1) }, |
|
1478 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,prime2) }, |
|
1479 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent1) }, |
|
1480 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,exponent2) }, |
|
1481 { SEC_ASN1_INTEGER, offsetof(RSAPrivateKey,coefficient) }, |
|
1482 { 0 } |
|
1483 }; |
|
1484 |
|
1485 const SEC_ASN1Template ckmk_AttributeTemplate[] = { |
|
1486 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(ckmk_Attribute) }, |
|
1487 { SEC_ASN1_OBJECT_ID, offsetof(ckmk_Attribute, attrType) }, |
|
1488 { SEC_ASN1_SET_OF, offsetof(ckmk_Attribute, attrValue), |
|
1489 SEC_AnyTemplate }, |
|
1490 { 0 } |
|
1491 }; |
|
1492 |
|
1493 const SEC_ASN1Template ckmk_SetOfAttributeTemplate[] = { |
|
1494 { SEC_ASN1_SET_OF, 0, ckmk_AttributeTemplate }, |
|
1495 }; |
|
1496 |
|
1497 SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate) |
|
1498 |
|
1499 /* ASN1 Templates for new decoder/encoder */ |
|
1500 const SEC_ASN1Template ckmk_PrivateKeyInfoTemplate[] = { |
|
1501 { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(PrivateKeyInfo) }, |
|
1502 { SEC_ASN1_INTEGER, offsetof(PrivateKeyInfo,version) }, |
|
1503 { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(PrivateKeyInfo,algorithm), |
|
1504 SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) }, |
|
1505 { SEC_ASN1_OCTET_STRING, offsetof(PrivateKeyInfo,privateKey) }, |
|
1506 { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC | 0, |
|
1507 offsetof(PrivateKeyInfo, attributes), ckmk_SetOfAttributeTemplate }, |
|
1508 { 0 } |
|
1509 }; |
|
1510 |
|
1511 #define CKMK_PRIVATE_KEY_INFO_VERSION 0 |
|
1512 static CK_RV |
|
1513 ckmk_CreateRSAKeyBlob |
|
1514 ( |
|
1515 RSAPrivateKey *lk, |
|
1516 NSSItem *keyBlob |
|
1517 ) |
|
1518 { |
|
1519 PrivateKeyInfo *pki = NULL; |
|
1520 PLArenaPool *arena = NULL; |
|
1521 SECOidTag algorithm = SEC_OID_UNKNOWN; |
|
1522 void *dummy; |
|
1523 SECStatus rv; |
|
1524 SECItem *encodedKey = NULL; |
|
1525 CK_RV error = CKR_OK; |
|
1526 |
|
1527 arena = PORT_NewArena(2048); /* XXX different size? */ |
|
1528 if(!arena) { |
|
1529 error = CKR_HOST_MEMORY; |
|
1530 goto loser; |
|
1531 } |
|
1532 |
|
1533 pki = (PrivateKeyInfo*)PORT_ArenaZAlloc(arena, sizeof(PrivateKeyInfo)); |
|
1534 if(!pki) { |
|
1535 error = CKR_HOST_MEMORY; |
|
1536 goto loser; |
|
1537 } |
|
1538 pki->arena = arena; |
|
1539 |
|
1540 dummy = SEC_ASN1EncodeItem(arena, &pki->privateKey, lk, |
|
1541 ckmk_RSAPrivateKeyTemplate); |
|
1542 algorithm = SEC_OID_PKCS1_RSA_ENCRYPTION; |
|
1543 |
|
1544 if (!dummy) { |
|
1545 error = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
|
1546 goto loser; |
|
1547 } |
|
1548 |
|
1549 rv = SECOID_SetAlgorithmID(arena, &pki->algorithm, algorithm, |
|
1550 (SECItem*)NULL); |
|
1551 if (rv != SECSuccess) { |
|
1552 error = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
|
1553 goto loser; |
|
1554 } |
|
1555 |
|
1556 dummy = SEC_ASN1EncodeInteger(arena, &pki->version, |
|
1557 CKMK_PRIVATE_KEY_INFO_VERSION); |
|
1558 if (!dummy) { |
|
1559 error = CKR_DEVICE_ERROR; /* should map NSS SECError */ |
|
1560 goto loser; |
|
1561 } |
|
1562 |
|
1563 encodedKey = SEC_ASN1EncodeItem(NULL, NULL, pki, |
|
1564 ckmk_PrivateKeyInfoTemplate); |
|
1565 if (!encodedKey) { |
|
1566 error = CKR_DEVICE_ERROR; |
|
1567 goto loser; |
|
1568 } |
|
1569 |
|
1570 keyBlob->data = nss_ZNEWARRAY(NULL, char, encodedKey->len); |
|
1571 if (NULL == keyBlob->data) { |
|
1572 error = CKR_HOST_MEMORY; |
|
1573 goto loser; |
|
1574 } |
|
1575 nsslibc_memcpy(keyBlob->data, encodedKey->data, encodedKey->len); |
|
1576 keyBlob->size = encodedKey->len; |
|
1577 |
|
1578 loser: |
|
1579 if(arena) { |
|
1580 PORT_FreeArena(arena, PR_TRUE); |
|
1581 } |
|
1582 if (encodedKey) { |
|
1583 SECITEM_FreeItem(encodedKey, PR_TRUE); |
|
1584 } |
|
1585 |
|
1586 return error; |
|
1587 } |
|
1588 /* |
|
1589 * There MUST be a better way to do this. For now, find the key based on the |
|
1590 * default name Apple gives it once we import. |
|
1591 */ |
|
1592 #define IMPORTED_NAME "Imported Private Key" |
|
1593 static CK_RV |
|
1594 ckmk_FindImportedKey |
|
1595 ( |
|
1596 SecKeychainRef keychainRef, |
|
1597 SecItemClass itemClass, |
|
1598 SecKeychainItemRef *outItemRef |
|
1599 ) |
|
1600 { |
|
1601 OSStatus macErr; |
|
1602 SecKeychainSearchRef searchRef = 0; |
|
1603 SecKeychainItemRef newItemRef; |
|
1604 |
|
1605 macErr = SecKeychainSearchCreateFromAttributes(keychainRef, itemClass, |
|
1606 NULL, &searchRef); |
|
1607 if (noErr != macErr) { |
|
1608 CKMK_MACERR("Can't search for Key", macErr); |
|
1609 return CKR_GENERAL_ERROR; |
|
1610 } |
|
1611 while (noErr == SecKeychainSearchCopyNext(searchRef, &newItemRef)) { |
|
1612 SecKeychainAttributeList *attrList = NULL; |
|
1613 SecKeychainAttributeInfo attrInfo; |
|
1614 SecItemAttr itemAttr = kSecKeyPrintName; |
|
1615 PRUint32 attrFormat = 0; |
|
1616 OSStatus macErr; |
|
1617 |
|
1618 attrInfo.count = 1; |
|
1619 attrInfo.tag = &itemAttr; |
|
1620 attrInfo.format = &attrFormat; |
|
1621 |
|
1622 macErr = SecKeychainItemCopyAttributesAndData(newItemRef, |
|
1623 &attrInfo, NULL, &attrList, NULL, NULL); |
|
1624 if (noErr == macErr) { |
|
1625 if (nsslibc_memcmp(attrList->attr->data, IMPORTED_NAME, |
|
1626 attrList->attr->length, NULL) == 0) { |
|
1627 *outItemRef = newItemRef; |
|
1628 CFRelease (searchRef); |
|
1629 SecKeychainItemFreeAttributesAndData(attrList, NULL); |
|
1630 return CKR_OK; |
|
1631 } |
|
1632 SecKeychainItemFreeAttributesAndData(attrList, NULL); |
|
1633 } |
|
1634 CFRelease(newItemRef); |
|
1635 } |
|
1636 CFRelease (searchRef); |
|
1637 return CKR_GENERAL_ERROR; /* we can come up with something better! */ |
|
1638 } |
|
1639 |
|
1640 static ckmkInternalObject * |
|
1641 nss_ckmk_CreatePrivateKey |
|
1642 ( |
|
1643 NSSCKFWSession *fwSession, |
|
1644 CK_ATTRIBUTE_PTR pTemplate, |
|
1645 CK_ULONG ulAttributeCount, |
|
1646 CK_RV *pError |
|
1647 ) |
|
1648 { |
|
1649 NSSItem attribute; |
|
1650 RSAPrivateKey lk; |
|
1651 NSSItem keyID; |
|
1652 char *nickname = NULL; |
|
1653 ckmkInternalObject *io = NULL; |
|
1654 CK_KEY_TYPE keyType; |
|
1655 OSStatus macErr; |
|
1656 SecKeychainItemRef itemRef = 0; |
|
1657 NSSItem keyBlob = { NULL, 0 }; |
|
1658 CFDataRef dataRef = 0; |
|
1659 SecExternalFormat inputFormat = kSecFormatBSAFE; |
|
1660 /*SecExternalFormat inputFormat = kSecFormatOpenSSL; */ |
|
1661 SecExternalItemType itemType = kSecItemTypePrivateKey; |
|
1662 SecKeyImportExportParameters keyParams ; |
|
1663 SecKeychainRef targetKeychain = 0; |
|
1664 unsigned char zero = 0; |
|
1665 CK_RV error; |
|
1666 |
|
1667 keyParams.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; |
|
1668 keyParams.flags = 0; |
|
1669 keyParams.passphrase = 0; |
|
1670 keyParams.alertTitle = 0; |
|
1671 keyParams.alertPrompt = 0; |
|
1672 keyParams.accessRef = 0; /* default */ |
|
1673 keyParams.keyUsage = 0; /* will get filled in */ |
|
1674 keyParams.keyAttributes = CSSM_KEYATTR_PERMANENT; /* will get filled in */ |
|
1675 keyType = nss_ckmk_GetULongAttribute |
|
1676 (CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError); |
|
1677 if (CKR_OK != *pError) { |
|
1678 return (ckmkInternalObject *)NULL; |
|
1679 } |
|
1680 if (CKK_RSA != keyType) { |
|
1681 *pError = CKR_ATTRIBUTE_VALUE_INVALID; |
|
1682 return (ckmkInternalObject *)NULL; |
|
1683 } |
|
1684 if (nss_ckmk_GetBoolAttribute(CKA_DECRYPT, |
|
1685 pTemplate, ulAttributeCount, CK_TRUE)) { |
|
1686 keyParams.keyUsage |= CSSM_KEYUSE_DECRYPT; |
|
1687 } |
|
1688 if (nss_ckmk_GetBoolAttribute(CKA_UNWRAP, |
|
1689 pTemplate, ulAttributeCount, CK_TRUE)) { |
|
1690 keyParams.keyUsage |= CSSM_KEYUSE_UNWRAP; |
|
1691 } |
|
1692 if (nss_ckmk_GetBoolAttribute(CKA_SIGN, |
|
1693 pTemplate, ulAttributeCount, CK_TRUE)) { |
|
1694 keyParams.keyUsage |= CSSM_KEYUSE_SIGN; |
|
1695 } |
|
1696 if (nss_ckmk_GetBoolAttribute(CKA_DERIVE, |
|
1697 pTemplate, ulAttributeCount, CK_FALSE)) { |
|
1698 keyParams.keyUsage |= CSSM_KEYUSE_DERIVE; |
|
1699 } |
|
1700 if (nss_ckmk_GetBoolAttribute(CKA_SENSITIVE, |
|
1701 pTemplate, ulAttributeCount, CK_TRUE)) { |
|
1702 keyParams.keyAttributes |= CSSM_KEYATTR_SENSITIVE; |
|
1703 } |
|
1704 if (nss_ckmk_GetBoolAttribute(CKA_EXTRACTABLE, |
|
1705 pTemplate, ulAttributeCount, CK_TRUE)) { |
|
1706 keyParams.keyAttributes |= CSSM_KEYATTR_EXTRACTABLE; |
|
1707 } |
|
1708 |
|
1709 lk.version.type = siUnsignedInteger; |
|
1710 lk.version.data = &zero; |
|
1711 lk.version.len = 1; |
|
1712 |
|
1713 *pError = nss_ckmk_GetAttribute(CKA_MODULUS, pTemplate, |
|
1714 ulAttributeCount, &attribute); |
|
1715 if (CKR_OK != *pError) { |
|
1716 return (ckmkInternalObject *)NULL; |
|
1717 } |
|
1718 lk.modulus.type = siUnsignedInteger; |
|
1719 lk.modulus.data = attribute.data; |
|
1720 lk.modulus.len = attribute.size; |
|
1721 |
|
1722 *pError = nss_ckmk_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate, |
|
1723 ulAttributeCount, &attribute); |
|
1724 if (CKR_OK != *pError) { |
|
1725 return (ckmkInternalObject *)NULL; |
|
1726 } |
|
1727 lk.publicExponent.type = siUnsignedInteger; |
|
1728 lk.publicExponent.data = attribute.data; |
|
1729 lk.publicExponent.len = attribute.size; |
|
1730 |
|
1731 *pError = nss_ckmk_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate, |
|
1732 ulAttributeCount, &attribute); |
|
1733 if (CKR_OK != *pError) { |
|
1734 return (ckmkInternalObject *)NULL; |
|
1735 } |
|
1736 lk.privateExponent.type = siUnsignedInteger; |
|
1737 lk.privateExponent.data = attribute.data; |
|
1738 lk.privateExponent.len = attribute.size; |
|
1739 |
|
1740 *pError = nss_ckmk_GetAttribute(CKA_PRIME_1, pTemplate, |
|
1741 ulAttributeCount, &attribute); |
|
1742 if (CKR_OK != *pError) { |
|
1743 return (ckmkInternalObject *)NULL; |
|
1744 } |
|
1745 lk.prime1.type = siUnsignedInteger; |
|
1746 lk.prime1.data = attribute.data; |
|
1747 lk.prime1.len = attribute.size; |
|
1748 |
|
1749 *pError = nss_ckmk_GetAttribute(CKA_PRIME_2, pTemplate, |
|
1750 ulAttributeCount, &attribute); |
|
1751 if (CKR_OK != *pError) { |
|
1752 return (ckmkInternalObject *)NULL; |
|
1753 } |
|
1754 lk.prime2.type = siUnsignedInteger; |
|
1755 lk.prime2.data = attribute.data; |
|
1756 lk.prime2.len = attribute.size; |
|
1757 |
|
1758 *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_1, pTemplate, |
|
1759 ulAttributeCount, &attribute); |
|
1760 if (CKR_OK != *pError) { |
|
1761 return (ckmkInternalObject *)NULL; |
|
1762 } |
|
1763 lk.exponent1.type = siUnsignedInteger; |
|
1764 lk.exponent1.data = attribute.data; |
|
1765 lk.exponent1.len = attribute.size; |
|
1766 |
|
1767 *pError = nss_ckmk_GetAttribute(CKA_EXPONENT_2, pTemplate, |
|
1768 ulAttributeCount, &attribute); |
|
1769 if (CKR_OK != *pError) { |
|
1770 return (ckmkInternalObject *)NULL; |
|
1771 } |
|
1772 lk.exponent2.type = siUnsignedInteger; |
|
1773 lk.exponent2.data = attribute.data; |
|
1774 lk.exponent2.len = attribute.size; |
|
1775 |
|
1776 *pError = nss_ckmk_GetAttribute(CKA_COEFFICIENT, pTemplate, |
|
1777 ulAttributeCount, &attribute); |
|
1778 if (CKR_OK != *pError) { |
|
1779 return (ckmkInternalObject *)NULL; |
|
1780 } |
|
1781 lk.coefficient.type = siUnsignedInteger; |
|
1782 lk.coefficient.data = attribute.data; |
|
1783 lk.coefficient.len = attribute.size; |
|
1784 |
|
1785 /* ASN1 Encode the pkcs8 structure... look at softoken to see how this |
|
1786 * is done... */ |
|
1787 error = ckmk_CreateRSAKeyBlob(&lk, &keyBlob); |
|
1788 if (CKR_OK != error) { |
|
1789 goto loser; |
|
1790 } |
|
1791 |
|
1792 dataRef = CFDataCreate(NULL, (UInt8 *)keyBlob.data, keyBlob.size); |
|
1793 if (0 == dataRef) { |
|
1794 *pError = CKR_HOST_MEMORY; |
|
1795 goto loser; |
|
1796 } |
|
1797 |
|
1798 *pError == ckmk_GetSafeDefaultKeychain(&targetKeychain); |
|
1799 if (CKR_OK != *pError) { |
|
1800 goto loser; |
|
1801 } |
|
1802 |
|
1803 |
|
1804 /* the itemArray that is returned is useless. the item does not |
|
1805 * is 'not on the key chain' so none of the modify calls work on it. |
|
1806 * It also has a key that isn't the same key as the one in the actual |
|
1807 * key chain. In short it isn't the item we want, and it gives us zero |
|
1808 * information about the item we want, so don't even bother with it... |
|
1809 */ |
|
1810 macErr = SecKeychainItemImport(dataRef, NULL, &inputFormat, &itemType, 0, |
|
1811 &keyParams, targetKeychain, NULL); |
|
1812 if (noErr != macErr) { |
|
1813 CKMK_MACERR("Import Private Key", macErr); |
|
1814 *pError = CKR_GENERAL_ERROR; |
|
1815 goto loser; |
|
1816 } |
|
1817 |
|
1818 *pError = ckmk_FindImportedKey(targetKeychain, |
|
1819 CSSM_DL_DB_RECORD_PRIVATE_KEY, |
|
1820 &itemRef); |
|
1821 if (CKR_OK != *pError) { |
|
1822 #ifdef DEBUG |
|
1823 fprintf(stderr,"couldn't find key in keychain \n"); |
|
1824 #endif |
|
1825 goto loser; |
|
1826 } |
|
1827 |
|
1828 |
|
1829 /* set the CKA_ID and the CKA_LABEL */ |
|
1830 error = nss_ckmk_GetAttribute(CKA_ID, pTemplate, |
|
1831 ulAttributeCount, &keyID); |
|
1832 if (CKR_OK == error) { |
|
1833 error = ckmk_updateAttribute(itemRef, kSecKeyLabel, |
|
1834 keyID.data, keyID.size, "Modify Key ID"); |
|
1835 #ifdef DEBUG |
|
1836 itemdump("key id: ", keyID.data, keyID.size, error); |
|
1837 #endif |
|
1838 } |
|
1839 nickname = nss_ckmk_GetStringAttribute(CKA_LABEL, pTemplate, |
|
1840 ulAttributeCount, &error); |
|
1841 if (nickname) { |
|
1842 ckmk_updateAttribute(itemRef, kSecKeyPrintName, nickname, |
|
1843 strlen(nickname)+1, "Modify Key Label"); |
|
1844 } else { |
|
1845 #define DEFAULT_NICKNAME "NSS Imported Key" |
|
1846 ckmk_updateAttribute(itemRef, kSecKeyPrintName, DEFAULT_NICKNAME, |
|
1847 sizeof(DEFAULT_NICKNAME), "Modify Key Label"); |
|
1848 } |
|
1849 |
|
1850 io = nss_ckmk_NewInternalObject(CKO_PRIVATE_KEY, itemRef, |
|
1851 CSSM_DL_DB_RECORD_PRIVATE_KEY, pError); |
|
1852 if ((ckmkInternalObject *)NULL == io) { |
|
1853 CFRelease(itemRef); |
|
1854 } |
|
1855 |
|
1856 return io; |
|
1857 |
|
1858 loser: |
|
1859 /* free the key blob */ |
|
1860 if (keyBlob.data) { |
|
1861 nss_ZFreeIf(keyBlob.data); |
|
1862 } |
|
1863 if (0 != targetKeychain) { |
|
1864 CFRelease(targetKeychain); |
|
1865 } |
|
1866 if (0 != dataRef) { |
|
1867 CFRelease(dataRef); |
|
1868 } |
|
1869 return io; |
|
1870 } |
|
1871 |
|
1872 |
|
1873 NSS_EXTERN NSSCKMDObject * |
|
1874 nss_ckmk_CreateObject |
|
1875 ( |
|
1876 NSSCKFWSession *fwSession, |
|
1877 CK_ATTRIBUTE_PTR pTemplate, |
|
1878 CK_ULONG ulAttributeCount, |
|
1879 CK_RV *pError |
|
1880 ) |
|
1881 { |
|
1882 CK_OBJECT_CLASS objClass; |
|
1883 ckmkInternalObject *io; |
|
1884 CK_BBOOL isToken; |
|
1885 |
|
1886 /* |
|
1887 * only create token objects |
|
1888 */ |
|
1889 isToken = nss_ckmk_GetBoolAttribute(CKA_TOKEN, pTemplate, |
|
1890 ulAttributeCount, CK_FALSE); |
|
1891 if (!isToken) { |
|
1892 *pError = CKR_ATTRIBUTE_VALUE_INVALID; |
|
1893 return (NSSCKMDObject *) NULL; |
|
1894 } |
|
1895 |
|
1896 /* |
|
1897 * only create keys and certs. |
|
1898 */ |
|
1899 objClass = nss_ckmk_GetULongAttribute(CKA_CLASS, pTemplate, |
|
1900 ulAttributeCount, pError); |
|
1901 if (CKR_OK != *pError) { |
|
1902 return (NSSCKMDObject *) NULL; |
|
1903 } |
|
1904 #ifdef notdef |
|
1905 if (objClass == CKO_PUBLIC_KEY) { |
|
1906 return CKR_OK; /* fake public key creation, happens as a side effect of |
|
1907 * private key creation */ |
|
1908 } |
|
1909 #endif |
|
1910 if (objClass == CKO_CERTIFICATE) { |
|
1911 io = nss_ckmk_CreateCertificate(fwSession, pTemplate, |
|
1912 ulAttributeCount, pError); |
|
1913 } else if (objClass == CKO_PRIVATE_KEY) { |
|
1914 io = nss_ckmk_CreatePrivateKey(fwSession, pTemplate, |
|
1915 ulAttributeCount, pError); |
|
1916 } else { |
|
1917 *pError = CKR_ATTRIBUTE_VALUE_INVALID; |
|
1918 } |
|
1919 |
|
1920 if ((ckmkInternalObject *)NULL == io) { |
|
1921 return (NSSCKMDObject *) NULL; |
|
1922 } |
|
1923 return nss_ckmk_CreateMDObject(NULL, io, pError); |
|
1924 } |