security/nss/lib/ckfw/nssmkey/mobject.c

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:61cfdd1039b3
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 }

mercurial