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 "ckcapi.h"
6 #include "nssbase.h"
7
8 /*
9 * ckcapi/cobject.c
10 *
11 * This file implements the NSSCKMDObject object for the
12 * "nss to capi objects" cryptoki module.
13 */
14
15 const CK_ATTRIBUTE_TYPE certAttrs[] = {
16 CKA_CLASS,
17 CKA_TOKEN,
18 CKA_PRIVATE,
19 CKA_MODIFIABLE,
20 CKA_LABEL,
21 CKA_CERTIFICATE_TYPE,
22 CKA_SUBJECT,
23 CKA_ISSUER,
24 CKA_SERIAL_NUMBER,
25 CKA_VALUE
26 };
27 const PRUint32 certAttrsCount = NSS_CKCAPI_ARRAY_SIZE(certAttrs);
28
29 /* private keys, for now only support RSA */
30 const CK_ATTRIBUTE_TYPE privKeyAttrs[] = {
31 CKA_CLASS,
32 CKA_TOKEN,
33 CKA_PRIVATE,
34 CKA_MODIFIABLE,
35 CKA_LABEL,
36 CKA_KEY_TYPE,
37 CKA_DERIVE,
38 CKA_LOCAL,
39 CKA_SUBJECT,
40 CKA_SENSITIVE,
41 CKA_DECRYPT,
42 CKA_SIGN,
43 CKA_SIGN_RECOVER,
44 CKA_UNWRAP,
45 CKA_EXTRACTABLE,
46 CKA_ALWAYS_SENSITIVE,
47 CKA_NEVER_EXTRACTABLE,
48 CKA_MODULUS,
49 CKA_PUBLIC_EXPONENT,
50 };
51 const PRUint32 privKeyAttrsCount = NSS_CKCAPI_ARRAY_SIZE(privKeyAttrs);
52
53 /* public keys, for now only support RSA */
54 const CK_ATTRIBUTE_TYPE pubKeyAttrs[] = {
55 CKA_CLASS,
56 CKA_TOKEN,
57 CKA_PRIVATE,
58 CKA_MODIFIABLE,
59 CKA_LABEL,
60 CKA_KEY_TYPE,
61 CKA_DERIVE,
62 CKA_LOCAL,
63 CKA_SUBJECT,
64 CKA_ENCRYPT,
65 CKA_VERIFY,
66 CKA_VERIFY_RECOVER,
67 CKA_WRAP,
68 CKA_MODULUS,
69 CKA_PUBLIC_EXPONENT,
70 };
71 const PRUint32 pubKeyAttrsCount = NSS_CKCAPI_ARRAY_SIZE(pubKeyAttrs);
72 static const CK_BBOOL ck_true = CK_TRUE;
73 static const CK_BBOOL ck_false = CK_FALSE;
74 static const CK_CERTIFICATE_TYPE ckc_x509 = CKC_X_509;
75 static const CK_KEY_TYPE ckk_rsa = CKK_RSA;
76 static const CK_OBJECT_CLASS cko_certificate = CKO_CERTIFICATE;
77 static const CK_OBJECT_CLASS cko_private_key = CKO_PRIVATE_KEY;
78 static const CK_OBJECT_CLASS cko_public_key = CKO_PUBLIC_KEY;
79 static const NSSItem ckcapi_trueItem = {
80 (void *)&ck_true, (PRUint32)sizeof(CK_BBOOL)
81 };
82 static const NSSItem ckcapi_falseItem = {
83 (void *)&ck_false, (PRUint32)sizeof(CK_BBOOL)
84 };
85 static const NSSItem ckcapi_x509Item = {
86 (void *)&ckc_x509, (PRUint32)sizeof(CK_CERTIFICATE_TYPE)
87 };
88 static const NSSItem ckcapi_rsaItem = {
89 (void *)&ckk_rsa, (PRUint32)sizeof(CK_KEY_TYPE)
90 };
91 static const NSSItem ckcapi_certClassItem = {
92 (void *)&cko_certificate, (PRUint32)sizeof(CK_OBJECT_CLASS)
93 };
94 static const NSSItem ckcapi_privKeyClassItem = {
95 (void *)&cko_private_key, (PRUint32)sizeof(CK_OBJECT_CLASS)
96 };
97 static const NSSItem ckcapi_pubKeyClassItem = {
98 (void *)&cko_public_key, (PRUint32)sizeof(CK_OBJECT_CLASS)
99 };
100 static const NSSItem ckcapi_emptyItem = {
101 (void *)&ck_true, 0
102 };
103
104 /*
105 * these are utilities. The chould be moved to a new utilities file.
106 */
107
108 /*
109 * unwrap a single DER value
110 */
111 unsigned char *
nss_ckcapi_DERUnwrap(unsigned char * src,unsigned int size,unsigned int * outSize,unsigned char ** next)112 nss_ckcapi_DERUnwrap(
113 unsigned char *src,
114 unsigned int size,
115 unsigned int *outSize,
116 unsigned char **next)
117 {
118 unsigned char *start = src;
119 unsigned char *end = src + size;
120 unsigned int len = 0;
121
122 /* initialize error condition return values */
123 *outSize = 0;
124 if (next) {
125 *next = src;
126 }
127
128 if (size < 2) {
129 return start;
130 }
131 src++; /* skip the tag -- should check it against an expected value! */
132 len = (unsigned)*src++;
133 if (len & 0x80) {
134 unsigned int count = len & 0x7f;
135 len = 0;
136
137 if (count + 2 > size) {
138 return start;
139 }
140 while (count-- > 0) {
141 len = (len << 8) | (unsigned)*src++;
142 }
143 }
144 if (len + (src - start) > size) {
145 return start;
146 }
147 if (next) {
148 *next = src + len;
149 }
150 *outSize = len;
151
152 return src;
153 }
154
155 /*
156 * convert a PKCS #11 bytestrin into a CK_ULONG, the byte stream must be
157 * less than sizeof (CK_ULONG).
158 */
159 CK_ULONG
nss_ckcapi_DataToInt(NSSItem * data,CK_RV * pError)160 nss_ckcapi_DataToInt(
161 NSSItem *data,
162 CK_RV *pError)
163 {
164 CK_ULONG value = 0;
165 unsigned long count = data->size;
166 unsigned char *dataPtr = data->data;
167 unsigned long size = 0;
168
169 *pError = CKR_OK;
170
171 while (count--) {
172 value = value << 8;
173 value = value + *dataPtr++;
174 if (size || value) {
175 size++;
176 }
177 }
178 if (size > sizeof(CK_ULONG)) {
179 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
180 }
181 return value;
182 }
183
184 /*
185 * convert a CK_ULONG to a bytestream. Data is stored in the buffer 'buf'
186 * and must be at least CK_ULONG. Caller must provide buf.
187 */
188 CK_ULONG
nss_ckcapi_IntToData(CK_ULONG value,NSSItem * data,unsigned char * dataPtr,CK_RV * pError)189 nss_ckcapi_IntToData(
190 CK_ULONG value,
191 NSSItem *data,
192 unsigned char *dataPtr,
193 CK_RV *pError)
194 {
195 unsigned long count = 0;
196 unsigned long i;
197 #define SHIFT ((sizeof(CK_ULONG) - 1) * 8)
198 PRBool first = 0;
199
200 *pError = CKR_OK;
201
202 data->data = dataPtr;
203 for (i = 0; i < sizeof(CK_ULONG); i++) {
204 unsigned char digit = (unsigned char)((value >> SHIFT) & 0xff);
205
206 value = value << 8;
207
208 /* drop leading zero bytes */
209 if (first && (0 == digit)) {
210 continue;
211 }
212 *dataPtr++ = digit;
213 count++;
214 }
215 data->size = count;
216 return count;
217 }
218
219 /*
220 * get an attribute from a template. Value is returned in NSS item.
221 * data for the item is owned by the template.
222 */
223 CK_RV
nss_ckcapi_GetAttribute(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE * template,CK_ULONG templateSize,NSSItem * item)224 nss_ckcapi_GetAttribute(
225 CK_ATTRIBUTE_TYPE type,
226 CK_ATTRIBUTE *template,
227 CK_ULONG templateSize,
228 NSSItem *item)
229 {
230 CK_ULONG i;
231
232 for (i = 0; i < templateSize; i++) {
233 if (template[i].type == type) {
234 item->data = template[i].pValue;
235 item->size = template[i].ulValueLen;
236 return CKR_OK;
237 }
238 }
239 return CKR_TEMPLATE_INCOMPLETE;
240 }
241
242 /*
243 * get an attribute which is type CK_ULONG.
244 */
245 CK_ULONG
nss_ckcapi_GetULongAttribute(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE * template,CK_ULONG templateSize,CK_RV * pError)246 nss_ckcapi_GetULongAttribute(
247 CK_ATTRIBUTE_TYPE type,
248 CK_ATTRIBUTE *template,
249 CK_ULONG templateSize,
250 CK_RV *pError)
251 {
252 NSSItem item;
253
254 *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
255 if (CKR_OK != *pError) {
256 return (CK_ULONG)0;
257 }
258 if (item.size != sizeof(CK_ULONG)) {
259 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
260 return (CK_ULONG)0;
261 }
262 return *(CK_ULONG *)item.data;
263 }
264
265 /*
266 * get an attribute which is type CK_BBOOL.
267 */
268 CK_BBOOL
nss_ckcapi_GetBoolAttribute(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE * template,CK_ULONG templateSize,CK_RV * pError)269 nss_ckcapi_GetBoolAttribute(
270 CK_ATTRIBUTE_TYPE type,
271 CK_ATTRIBUTE *template,
272 CK_ULONG templateSize,
273 CK_RV *pError)
274 {
275 NSSItem item;
276
277 *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
278 if (CKR_OK != *pError) {
279 return (CK_BBOOL)0;
280 }
281 if (item.size != sizeof(CK_BBOOL)) {
282 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
283 return (CK_BBOOL)0;
284 }
285 return *(CK_BBOOL *)item.data;
286 }
287
288 /*
289 * get an attribute which is type CK_BBOOL.
290 */
291 char *
nss_ckcapi_GetStringAttribute(CK_ATTRIBUTE_TYPE type,CK_ATTRIBUTE * template,CK_ULONG templateSize,CK_RV * pError)292 nss_ckcapi_GetStringAttribute(
293 CK_ATTRIBUTE_TYPE type,
294 CK_ATTRIBUTE *template,
295 CK_ULONG templateSize,
296 CK_RV *pError)
297 {
298 NSSItem item;
299 char *str;
300
301 /* get the attribute */
302 *pError = nss_ckcapi_GetAttribute(type, template, templateSize, &item);
303 if (CKR_OK != *pError) {
304 return (char *)NULL;
305 }
306 /* make sure it is null terminated */
307 str = nss_ZNEWARRAY(NULL, char, item.size + 1);
308 if ((char *)NULL == str) {
309 *pError = CKR_HOST_MEMORY;
310 return (char *)NULL;
311 }
312
313 nsslibc_memcpy(str, item.data, item.size);
314 str[item.size] = 0;
315
316 return str;
317 }
318
319 /*
320 * Return the size in bytes of a wide string, including the terminating null
321 * character
322 */
323 int
nss_ckcapi_WideSize(LPCWSTR wide)324 nss_ckcapi_WideSize(
325 LPCWSTR wide)
326 {
327 DWORD size;
328
329 if ((LPWSTR)NULL == wide) {
330 return 0;
331 }
332 size = wcslen(wide) + 1;
333 return size * sizeof(WCHAR);
334 }
335
336 /*
337 * Covert a Unicode wide character string to a UTF8 string
338 */
339 char *
nss_ckcapi_WideToUTF8(LPCWSTR wide)340 nss_ckcapi_WideToUTF8(
341 LPCWSTR wide)
342 {
343 DWORD size;
344 char *buf;
345
346 if ((LPWSTR)NULL == wide) {
347 return (char *)NULL;
348 }
349
350 size = WideCharToMultiByte(CP_UTF8, 0, wide, -1, NULL, 0, NULL, 0);
351 if (size == 0) {
352 return (char *)NULL;
353 }
354 buf = nss_ZNEWARRAY(NULL, char, size);
355 size = WideCharToMultiByte(CP_UTF8, 0, wide, -1, buf, size, NULL, 0);
356 if (size == 0) {
357 nss_ZFreeIf(buf);
358 return (char *)NULL;
359 }
360 return buf;
361 }
362
363 /*
364 * Return a Wide String duplicated with nss allocated memory.
365 */
366 LPWSTR
nss_ckcapi_WideDup(LPCWSTR wide)367 nss_ckcapi_WideDup(
368 LPCWSTR wide)
369 {
370 DWORD len;
371 LPWSTR buf;
372
373 if ((LPWSTR)NULL == wide) {
374 return (LPWSTR)NULL;
375 }
376
377 len = wcslen(wide) + 1;
378
379 buf = nss_ZNEWARRAY(NULL, WCHAR, len);
380 if ((LPWSTR)NULL == buf) {
381 return buf;
382 }
383 nsslibc_memcpy(buf, wide, len * sizeof(WCHAR));
384 return buf;
385 }
386
387 /*
388 * Covert a UTF8 string to Unicode wide character
389 */
390 LPWSTR
nss_ckcapi_UTF8ToWide(char * buf)391 nss_ckcapi_UTF8ToWide(
392 char *buf)
393 {
394 DWORD size;
395 LPWSTR wide;
396
397 if ((char *)NULL == buf) {
398 return (LPWSTR)NULL;
399 }
400
401 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0);
402 if (size == 0) {
403 return (LPWSTR)NULL;
404 }
405 wide = nss_ZNEWARRAY(NULL, WCHAR, size);
406 size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size);
407 if (size == 0) {
408 nss_ZFreeIf(wide);
409 return (LPWSTR)NULL;
410 }
411 return wide;
412 }
413
414 /*
415 * keep all the knowlege of how the internalObject is laid out in this function
416 *
417 * nss_ckcapi_FetchKeyContainer
418 *
419 * fetches the Provider container and info as well as a key handle for a
420 * private key. If something other than a private key is passed in,
421 * this function fails with CKR_KEY_TYPE_INCONSISTENT
422 */
423 NSS_EXTERN CK_RV
nss_ckcapi_FetchKeyContainer(ckcapiInternalObject * iKey,HCRYPTPROV * hProv,DWORD * keySpec,HCRYPTKEY * hKey)424 nss_ckcapi_FetchKeyContainer(
425 ckcapiInternalObject *iKey,
426 HCRYPTPROV *hProv,
427 DWORD *keySpec,
428 HCRYPTKEY *hKey)
429 {
430 ckcapiCertObject *co;
431 ckcapiKeyObject *ko;
432 BOOL rc, dummy;
433 DWORD msError;
434
435 switch (iKey->type) {
436 default:
437 case ckcapiRaw:
438 /* can't have raw private keys */
439 return CKR_KEY_TYPE_INCONSISTENT;
440 case ckcapiCert:
441 if (iKey->objClass != CKO_PRIVATE_KEY) {
442 /* Only private keys have private key provider handles */
443 return CKR_KEY_TYPE_INCONSISTENT;
444 }
445 co = &iKey->u.cert;
446
447 /* OK, get the Provider */
448 rc = CryptAcquireCertificatePrivateKey(co->certContext,
449 CRYPT_ACQUIRE_CACHE_FLAG |
450 CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
451 NULL, hProv,
452 keySpec, &dummy);
453 if (!rc) {
454 goto loser;
455 }
456 break;
457 case ckcapiBareKey:
458 if (iKey->objClass != CKO_PRIVATE_KEY) {
459 /* Only private keys have private key provider handles */
460 return CKR_KEY_TYPE_INCONSISTENT;
461 }
462 ko = &iKey->u.key;
463
464 /* OK, get the Provider */
465 if (0 == ko->hProv) {
466 rc =
467 CryptAcquireContext(hProv,
468 ko->containerName,
469 ko->provName,
470 ko->provInfo.dwProvType, 0);
471 if (!rc) {
472 goto loser;
473 }
474 } else {
475 *hProv =
476 ko->hProv;
477 }
478 *keySpec = ko->provInfo.dwKeySpec;
479 break;
480 }
481
482 /* and get the crypto handle */
483 rc = CryptGetUserKey(*hProv, *keySpec, hKey);
484 if (!rc) {
485 goto loser;
486 }
487 return CKR_OK;
488 loser:
489 /* map the microsoft error before leaving */
490 msError = GetLastError();
491 switch (msError) {
492 case ERROR_INVALID_HANDLE:
493 case ERROR_INVALID_PARAMETER:
494 case NTE_BAD_KEY:
495 case NTE_NO_KEY:
496 case NTE_BAD_PUBLIC_KEY:
497 case NTE_BAD_KEYSET:
498 case NTE_KEYSET_NOT_DEF:
499 return CKR_KEY_TYPE_INCONSISTENT;
500 case NTE_BAD_UID:
501 case NTE_KEYSET_ENTRY_BAD:
502 return CKR_DEVICE_ERROR;
503 }
504 return CKR_GENERAL_ERROR;
505 }
506
507 /*
508 * take a DER PUBLIC Key block and return the modulus and exponent
509 */
510 static void
ckcapi_CertPopulateModulusExponent(ckcapiInternalObject * io)511 ckcapi_CertPopulateModulusExponent(
512 ckcapiInternalObject *io)
513 {
514 ckcapiKeyParams *kp = &io->u.cert.key;
515 PCCERT_CONTEXT certContext = io->u.cert.certContext;
516 unsigned char *pkData =
517 certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.pbData;
518 unsigned int size =
519 certContext->pCertInfo->SubjectPublicKeyInfo.PublicKey.cbData;
520 unsigned int newSize;
521 unsigned char *ptr, *newptr;
522
523 /* find the start of the modulus -- this will not give good results if
524 * the key isn't an rsa key! */
525 ptr = nss_ckcapi_DERUnwrap(pkData, size, &newSize, NULL);
526 kp->modulus.data = nss_ckcapi_DERUnwrap(ptr, newSize,
527 &kp->modulus.size, &newptr);
528 /* changed from signed to unsigned int */
529 if (0 == *(char *)kp->modulus.data) {
530 kp->modulus.data = ((char *)kp->modulus.data) + 1;
531 kp->modulus.size = kp->modulus.size - 1;
532 }
533 /* changed from signed to unsigned int */
534 kp->exponent.data = nss_ckcapi_DERUnwrap(newptr, (newptr - ptr) + newSize,
535 &kp->exponent.size, NULL);
536 if (0 == *(char *)kp->exponent.data) {
537 kp->exponent.data = ((char *)kp->exponent.data) + 1;
538 kp->exponent.size = kp->exponent.size - 1;
539 }
540 return;
541 }
542
543 typedef struct _CAPI_RSA_KEY_BLOB {
544 PUBLICKEYSTRUC header;
545 RSAPUBKEY rsa;
546 char data[1];
547 } CAPI_RSA_KEY_BLOB;
548
549 #define CAPI_MODULUS_OFFSET(modSize) 0
550 #define CAPI_PRIME_1_OFFSET(modSize) (modSize)
551 #define CAPI_PRIME_2_OFFSET(modSize) ((modSize) + (modSize) / 2)
552 #define CAPI_EXPONENT_1_OFFSET(modSize) ((modSize)*2)
553 #define CAPI_EXPONENT_2_OFFSET(modSize) ((modSize)*2 + (modSize) / 2)
554 #define CAPI_COEFFICIENT_OFFSET(modSize) ((modSize)*3)
555 #define CAPI_PRIVATE_EXP_OFFSET(modSize) ((modSize)*3 + (modSize) / 2)
556
557 void
ckcapi_FetchPublicKey(ckcapiInternalObject * io)558 ckcapi_FetchPublicKey(
559 ckcapiInternalObject *io)
560 {
561 ckcapiKeyParams *kp;
562 HCRYPTPROV hProv;
563 DWORD keySpec;
564 HCRYPTKEY hKey = 0;
565 CK_RV error;
566 DWORD bufLen;
567 BOOL rc;
568 unsigned long modulus;
569 char *buf = NULL;
570 CAPI_RSA_KEY_BLOB *blob;
571
572 error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey);
573 if (CKR_OK != error) {
574 goto loser;
575 }
576 kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key;
577
578 rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
579 if (!rc) {
580 goto loser;
581 }
582 buf = nss_ZNEWARRAY(NULL, char, bufLen);
583 rc = CryptExportKey(hKey, 0, PUBLICKEYBLOB, 0, buf, &bufLen);
584 if (!rc) {
585 goto loser;
586 }
587 /* validate the blob */
588 blob = (CAPI_RSA_KEY_BLOB *)buf;
589 if ((PUBLICKEYBLOB != blob->header.bType) ||
590 (0x02 != blob->header.bVersion) ||
591 (0x31415352 != blob->rsa.magic)) {
592 goto loser;
593 }
594 modulus = blob->rsa.bitlen / 8;
595 kp->pubKey = buf;
596 buf = NULL;
597
598 kp->modulus.data = &blob->data[CAPI_MODULUS_OFFSET(modulus)];
599 kp->modulus.size = modulus;
600 ckcapi_ReverseData(&kp->modulus);
601 nss_ckcapi_IntToData(blob->rsa.pubexp, &kp->exponent,
602 kp->publicExponentData, &error);
603
604 loser:
605 nss_ZFreeIf(buf);
606 if (0 != hKey) {
607 CryptDestroyKey(hKey);
608 }
609 return;
610 }
611
612 void
ckcapi_FetchPrivateKey(ckcapiInternalObject * io)613 ckcapi_FetchPrivateKey(
614 ckcapiInternalObject *io)
615 {
616 ckcapiKeyParams *kp;
617 HCRYPTPROV hProv;
618 DWORD keySpec;
619 HCRYPTKEY hKey = 0;
620 CK_RV error;
621 DWORD bufLen;
622 BOOL rc;
623 unsigned long modulus;
624 char *buf = NULL;
625 CAPI_RSA_KEY_BLOB *blob;
626
627 error = nss_ckcapi_FetchKeyContainer(io, &hProv, &keySpec, &hKey);
628 if (CKR_OK != error) {
629 goto loser;
630 }
631 kp = (ckcapiCert == io->type) ? &io->u.cert.key : &io->u.key.key;
632
633 rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen);
634 if (!rc) {
635 goto loser;
636 }
637 buf = nss_ZNEWARRAY(NULL, char, bufLen);
638 rc = CryptExportKey(hKey, 0, PRIVATEKEYBLOB, 0, buf, &bufLen);
639 if (!rc) {
640 goto loser;
641 }
642 /* validate the blob */
643 blob = (CAPI_RSA_KEY_BLOB *)buf;
644 if ((PRIVATEKEYBLOB != blob->header.bType) ||
645 (0x02 != blob->header.bVersion) ||
646 (0x32415352 != blob->rsa.magic)) {
647 goto loser;
648 }
649 modulus = blob->rsa.bitlen / 8;
650 kp->privateKey = buf;
651 buf = NULL;
652
653 kp->privateExponent.data = &blob->data[CAPI_PRIVATE_EXP_OFFSET(modulus)];
654 kp->privateExponent.size = modulus;
655 ckcapi_ReverseData(&kp->privateExponent);
656 kp->prime1.data = &blob->data[CAPI_PRIME_1_OFFSET(modulus)];
657 kp->prime1.size = modulus / 2;
658 ckcapi_ReverseData(&kp->prime1);
659 kp->prime2.data = &blob->data[CAPI_PRIME_2_OFFSET(modulus)];
660 kp->prime2.size = modulus / 2;
661 ckcapi_ReverseData(&kp->prime2);
662 kp->exponent1.data = &blob->data[CAPI_EXPONENT_1_OFFSET(modulus)];
663 kp->exponent1.size = modulus / 2;
664 ckcapi_ReverseData(&kp->exponent1);
665 kp->exponent2.data = &blob->data[CAPI_EXPONENT_2_OFFSET(modulus)];
666 kp->exponent2.size = modulus / 2;
667 ckcapi_ReverseData(&kp->exponent2);
668 kp->coefficient.data = &blob->data[CAPI_COEFFICIENT_OFFSET(modulus)];
669 kp->coefficient.size = modulus / 2;
670 ckcapi_ReverseData(&kp->coefficient);
671
672 loser:
673 nss_ZFreeIf(buf);
674 if (0 != hKey) {
675 CryptDestroyKey(hKey);
676 }
677 return;
678 }
679
680 void
ckcapi_PopulateModulusExponent(ckcapiInternalObject * io)681 ckcapi_PopulateModulusExponent(
682 ckcapiInternalObject *io)
683 {
684 if (ckcapiCert == io->type) {
685 ckcapi_CertPopulateModulusExponent(io);
686 } else {
687 ckcapi_FetchPublicKey(io);
688 }
689 return;
690 }
691
692 /*
693 * fetch the friendly name attribute.
694 * can only be called with ckcapiCert type objects!
695 */
696 void
ckcapi_FetchLabel(ckcapiInternalObject * io)697 ckcapi_FetchLabel(
698 ckcapiInternalObject *io)
699 {
700 ckcapiCertObject *co = &io->u.cert;
701 char *label;
702 PCCERT_CONTEXT certContext = io->u.cert.certContext;
703 char labelDataUTF16[128];
704 DWORD size = sizeof(labelDataUTF16);
705 DWORD size8 = sizeof(co->labelData);
706 BOOL rv;
707
708 rv = CertGetCertificateContextProperty(certContext,
709 CERT_FRIENDLY_NAME_PROP_ID, labelDataUTF16, &size);
710 if (rv) {
711 co->labelData = nss_ckcapi_WideToUTF8((LPCWSTR)labelDataUTF16);
712 if ((CHAR *)NULL == co->labelData) {
713 rv = 0;
714 } else {
715 size = strlen(co->labelData);
716 }
717 }
718 label = co->labelData;
719 /* we are presuming a user cert, make sure it has a nickname, even if
720 * Microsoft never gave it one */
721 if (!rv && co->hasID) {
722 DWORD mserror = GetLastError();
723 #define DEFAULT_NICKNAME "no Microsoft nickname"
724 label = DEFAULT_NICKNAME;
725 size = sizeof(DEFAULT_NICKNAME);
726 rv = 1;
727 }
728
729 if (rv) {
730 co->label.data = label;
731 co->label.size = size;
732 }
733 return;
734 }
735
736 void
ckcapi_FetchSerial(ckcapiInternalObject * io)737 ckcapi_FetchSerial(
738 ckcapiInternalObject *io)
739 {
740 ckcapiCertObject *co = &io->u.cert;
741 PCCERT_CONTEXT certContext = io->u.cert.certContext;
742 DWORD size = sizeof(co->derSerial);
743
744 BOOL rc = CryptEncodeObject(X509_ASN_ENCODING,
745 X509_MULTI_BYTE_INTEGER,
746 &certContext->pCertInfo->SerialNumber,
747 co->derSerial,
748 &size);
749 if (rc) {
750 co->serial.data = co->derSerial;
751 co->serial.size = size;
752 }
753 return;
754 }
755
756 /*
757 * fetch the key ID.
758 */
759 void
ckcapi_FetchID(ckcapiInternalObject * io)760 ckcapi_FetchID(
761 ckcapiInternalObject *io)
762 {
763 PCCERT_CONTEXT certContext = io->u.cert.certContext;
764 DWORD size = 0;
765 BOOL rc;
766
767 rc = CertGetCertificateContextProperty(certContext,
768 CERT_KEY_IDENTIFIER_PROP_ID, NULL, &size);
769 if (!rc) {
770 return;
771 }
772 io->idData = nss_ZNEWARRAY(NULL, char, size);
773 if (io->idData == NULL) {
774 return;
775 }
776
777 rc = CertGetCertificateContextProperty(certContext,
778 CERT_KEY_IDENTIFIER_PROP_ID, io->idData, &size);
779 if (!rc) {
780 nss_ZFreeIf(io->idData);
781 io->idData = NULL;
782 return;
783 }
784 io->id.data = io->idData;
785 io->id.size = size;
786 return;
787 }
788
789 /*
790 * fetch the hash key.
791 */
792 void
ckcapi_CertFetchHashKey(ckcapiInternalObject * io)793 ckcapi_CertFetchHashKey(
794 ckcapiInternalObject *io)
795 {
796 ckcapiCertObject *co = &io->u.cert;
797 PCCERT_CONTEXT certContext = io->u.cert.certContext;
798 DWORD size = certContext->cbCertEncoded;
799 DWORD max = sizeof(io->hashKeyData) - 1;
800 DWORD offset = 0;
801
802 /* make sure we don't over flow. NOTE: cutting the top of a cert is
803 * not a big issue because the signature for will be unique for the cert */
804 if (size > max) {
805 offset = size - max;
806 size = max;
807 }
808
809 nsslibc_memcpy(io->hashKeyData, certContext->pbCertEncoded + offset, size);
810 io->hashKeyData[size] = (char)(io->objClass & 0xff);
811
812 io->hashKey.data = io->hashKeyData;
813 io->hashKey.size = size + 1;
814 return;
815 }
816
817 /*
818 * fetch the hash key.
819 */
820 void
ckcapi_KeyFetchHashKey(ckcapiInternalObject * io)821 ckcapi_KeyFetchHashKey(
822 ckcapiInternalObject *io)
823 {
824 ckcapiKeyObject *ko = &io->u.key;
825 DWORD size;
826 DWORD max = sizeof(io->hashKeyData) - 2;
827 DWORD offset = 0;
828 DWORD provLen = strlen(ko->provName);
829 DWORD containerLen = strlen(ko->containerName);
830
831 size = provLen + containerLen;
832
833 /* make sure we don't overflow, try to keep things unique */
834 if (size > max) {
835 DWORD diff = ((size - max) + 1) / 2;
836 provLen -= diff;
837 containerLen -= diff;
838 size = provLen + containerLen;
839 }
840
841 nsslibc_memcpy(io->hashKeyData, ko->provName, provLen);
842 nsslibc_memcpy(&io->hashKeyData[provLen],
843 ko->containerName,
844 containerLen);
845 io->hashKeyData[size] = (char)(io->objClass & 0xff);
846 io->hashKeyData[size + 1] = (char)(ko->provInfo.dwKeySpec & 0xff);
847
848 io->hashKey.data = io->hashKeyData;
849 io->hashKey.size = size + 2;
850 return;
851 }
852
853 /*
854 * fetch the hash key.
855 */
856 void
ckcapi_FetchHashKey(ckcapiInternalObject * io)857 ckcapi_FetchHashKey(
858 ckcapiInternalObject *io)
859 {
860 if (ckcapiCert == io->type) {
861 ckcapi_CertFetchHashKey(io);
862 } else {
863 ckcapi_KeyFetchHashKey(io);
864 }
865 return;
866 }
867
868 const NSSItem *
ckcapi_FetchCertAttribute(ckcapiInternalObject * io,CK_ATTRIBUTE_TYPE type)869 ckcapi_FetchCertAttribute(
870 ckcapiInternalObject *io,
871 CK_ATTRIBUTE_TYPE type)
872 {
873 PCCERT_CONTEXT certContext = io->u.cert.certContext;
874 switch (type) {
875 case CKA_CLASS:
876 return &ckcapi_certClassItem;
877 case CKA_TOKEN:
878 return &ckcapi_trueItem;
879 case CKA_MODIFIABLE:
880 case CKA_PRIVATE:
881 return &ckcapi_falseItem;
882 case CKA_CERTIFICATE_TYPE:
883 return &ckcapi_x509Item;
884 case CKA_LABEL:
885 if (0 == io->u.cert.label.size) {
886 ckcapi_FetchLabel(io);
887 }
888 return &io->u.cert.label;
889 case CKA_SUBJECT:
890 if (0 == io->u.cert.subject.size) {
891 io->u.cert.subject.data =
892 certContext->pCertInfo->Subject.pbData;
893 io->u.cert.subject.size =
894 certContext->pCertInfo->Subject.cbData;
895 }
896 return &io->u.cert.subject;
897 case CKA_ISSUER:
898 if (0 == io->u.cert.issuer.size) {
899 io->u.cert.issuer.data =
900 certContext->pCertInfo->Issuer.pbData;
901 io->u.cert.issuer.size =
902 certContext->pCertInfo->Issuer.cbData;
903 }
904 return &io->u.cert.issuer;
905 case CKA_SERIAL_NUMBER:
906 if (0 == io->u.cert.serial.size) {
907 /* not exactly right. This should be the encoded serial number, but
908 * it's the decoded serial number! */
909 ckcapi_FetchSerial(io);
910 }
911 return &io->u.cert.serial;
912 case CKA_VALUE:
913 if (0 == io->u.cert.derCert.size) {
914 io->u.cert.derCert.data =
915 io->u.cert.certContext->pbCertEncoded;
916 io->u.cert.derCert.size =
917 io->u.cert.certContext->cbCertEncoded;
918 }
919 return &io->u.cert.derCert;
920 case CKA_ID:
921 if (!io->u.cert.hasID) {
922 return NULL;
923 }
924 if (0 == io->id.size) {
925 ckcapi_FetchID(io);
926 }
927 return &io->id;
928 default:
929 break;
930 }
931 return NULL;
932 }
933
934 const NSSItem *
ckcapi_FetchPubKeyAttribute(ckcapiInternalObject * io,CK_ATTRIBUTE_TYPE type)935 ckcapi_FetchPubKeyAttribute(
936 ckcapiInternalObject *io,
937 CK_ATTRIBUTE_TYPE type)
938 {
939 PRBool isCertType = (ckcapiCert == io->type);
940 ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
941
942 switch (type) {
943 case CKA_CLASS:
944 return &ckcapi_pubKeyClassItem;
945 case CKA_TOKEN:
946 case CKA_LOCAL:
947 case CKA_ENCRYPT:
948 case CKA_VERIFY:
949 case CKA_VERIFY_RECOVER:
950 return &ckcapi_trueItem;
951 case CKA_PRIVATE:
952 case CKA_MODIFIABLE:
953 case CKA_DERIVE:
954 case CKA_WRAP:
955 return &ckcapi_falseItem;
956 case CKA_KEY_TYPE:
957 return &ckcapi_rsaItem;
958 case CKA_LABEL:
959 if (!isCertType) {
960 return &ckcapi_emptyItem;
961 }
962 if (0 == io->u.cert.label.size) {
963 ckcapi_FetchLabel(io);
964 }
965 return &io->u.cert.label;
966 case CKA_SUBJECT:
967 if (!isCertType) {
968 return &ckcapi_emptyItem;
969 }
970 if (0 == io->u.cert.subject.size) {
971 PCCERT_CONTEXT certContext =
972 io->u.cert.certContext;
973 io->u.cert.subject.data =
974 certContext->pCertInfo->Subject.pbData;
975 io->u.cert.subject.size =
976 certContext->pCertInfo->Subject.cbData;
977 }
978 return &io->u.cert.subject;
979 case CKA_MODULUS:
980 if (0 == kp->modulus.size) {
981 ckcapi_PopulateModulusExponent(io);
982 }
983 return &kp->modulus;
984 case CKA_PUBLIC_EXPONENT:
985 if (0 == kp->modulus.size) {
986 ckcapi_PopulateModulusExponent(io);
987 }
988 return &kp->exponent;
989 case CKA_ID:
990 if (0 == io->id.size) {
991 ckcapi_FetchID(io);
992 }
993 return &io->id;
994 default:
995 break;
996 }
997 return NULL;
998 }
999
1000 const NSSItem *
ckcapi_FetchPrivKeyAttribute(ckcapiInternalObject * io,CK_ATTRIBUTE_TYPE type)1001 ckcapi_FetchPrivKeyAttribute(
1002 ckcapiInternalObject *io,
1003 CK_ATTRIBUTE_TYPE type)
1004 {
1005 PRBool isCertType = (ckcapiCert == io->type);
1006 ckcapiKeyParams *kp = isCertType ? &io->u.cert.key : &io->u.key.key;
1007
1008 switch (type) {
1009 case CKA_CLASS:
1010 return &ckcapi_privKeyClassItem;
1011 case CKA_TOKEN:
1012 case CKA_LOCAL:
1013 case CKA_SIGN:
1014 case CKA_DECRYPT:
1015 case CKA_SIGN_RECOVER:
1016 return &ckcapi_trueItem;
1017 case CKA_SENSITIVE:
1018 case CKA_PRIVATE: /* should move in the future */
1019 case CKA_MODIFIABLE:
1020 case CKA_DERIVE:
1021 case CKA_UNWRAP:
1022 case CKA_EXTRACTABLE: /* will probably move in the future */
1023 case CKA_ALWAYS_SENSITIVE:
1024 case CKA_NEVER_EXTRACTABLE:
1025 return &ckcapi_falseItem;
1026 case CKA_KEY_TYPE:
1027 return &ckcapi_rsaItem;
1028 case CKA_LABEL:
1029 if (!isCertType) {
1030 return &ckcapi_emptyItem;
1031 }
1032 if (0 == io->u.cert.label.size) {
1033 ckcapi_FetchLabel(io);
1034 }
1035 return &io->u.cert.label;
1036 case CKA_SUBJECT:
1037 if (!isCertType) {
1038 return &ckcapi_emptyItem;
1039 }
1040 if (0 == io->u.cert.subject.size) {
1041 PCCERT_CONTEXT certContext =
1042 io->u.cert.certContext;
1043 io->u.cert.subject.data =
1044 certContext->pCertInfo->Subject.pbData;
1045 io->u.cert.subject.size =
1046 certContext->pCertInfo->Subject.cbData;
1047 }
1048 return &io->u.cert.subject;
1049 case CKA_MODULUS:
1050 if (0 == kp->modulus.size) {
1051 ckcapi_PopulateModulusExponent(io);
1052 }
1053 return &kp->modulus;
1054 case CKA_PUBLIC_EXPONENT:
1055 if (0 == kp->modulus.size) {
1056 ckcapi_PopulateModulusExponent(io);
1057 }
1058 return &kp->exponent;
1059 case CKA_PRIVATE_EXPONENT:
1060 if (0 == kp->privateExponent.size) {
1061 ckcapi_FetchPrivateKey(io);
1062 }
1063 return &kp->privateExponent;
1064 case CKA_PRIME_1:
1065 if (0 == kp->privateExponent.size) {
1066 ckcapi_FetchPrivateKey(io);
1067 }
1068 return &kp->prime1;
1069 case CKA_PRIME_2:
1070 if (0 == kp->privateExponent.size) {
1071 ckcapi_FetchPrivateKey(io);
1072 }
1073 return &kp->prime2;
1074 case CKA_EXPONENT_1:
1075 if (0 == kp->privateExponent.size) {
1076 ckcapi_FetchPrivateKey(io);
1077 }
1078 return &kp->exponent1;
1079 case CKA_EXPONENT_2:
1080 if (0 == kp->privateExponent.size) {
1081 ckcapi_FetchPrivateKey(io);
1082 }
1083 return &kp->exponent2;
1084 case CKA_COEFFICIENT:
1085 if (0 == kp->privateExponent.size) {
1086 ckcapi_FetchPrivateKey(io);
1087 }
1088 return &kp->coefficient;
1089 case CKA_ID:
1090 if (0 == io->id.size) {
1091 ckcapi_FetchID(io);
1092 }
1093 return &io->id;
1094 default:
1095 return NULL;
1096 }
1097 }
1098
1099 const NSSItem *
nss_ckcapi_FetchAttribute(ckcapiInternalObject * io,CK_ATTRIBUTE_TYPE type)1100 nss_ckcapi_FetchAttribute(
1101 ckcapiInternalObject *io,
1102 CK_ATTRIBUTE_TYPE type)
1103 {
1104 CK_ULONG i;
1105
1106 if (io->type == ckcapiRaw) {
1107 for (i = 0; i < io->u.raw.n; i++) {
1108 if (type == io->u.raw.types[i]) {
1109 return &io->u.raw.items[i];
1110 }
1111 }
1112 return NULL;
1113 }
1114 /* deal with the common attributes */
1115 switch (io->objClass) {
1116 case CKO_CERTIFICATE:
1117 return ckcapi_FetchCertAttribute(io, type);
1118 case CKO_PRIVATE_KEY:
1119 return ckcapi_FetchPrivKeyAttribute(io, type);
1120 case CKO_PUBLIC_KEY:
1121 return ckcapi_FetchPubKeyAttribute(io, type);
1122 }
1123 return NULL;
1124 }
1125
1126 /*
1127 * check to see if the certificate already exists
1128 */
1129 static PRBool
ckcapi_cert_exists(NSSItem * value,ckcapiInternalObject ** io)1130 ckcapi_cert_exists(
1131 NSSItem *value,
1132 ckcapiInternalObject **io)
1133 {
1134 int count, i;
1135 PRUint32 size = 0;
1136 ckcapiInternalObject **listp = NULL;
1137 CK_ATTRIBUTE myTemplate[2];
1138 CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
1139 CK_ULONG templateCount = 2;
1140 CK_RV error;
1141 PRBool found = PR_FALSE;
1142
1143 myTemplate[0].type = CKA_CLASS;
1144 myTemplate[0].pValue = &cert_class;
1145 myTemplate[0].ulValueLen = sizeof(cert_class);
1146 myTemplate[1].type = CKA_VALUE;
1147 myTemplate[1].pValue = value->data;
1148 myTemplate[1].ulValueLen = value->size;
1149
1150 count = nss_ckcapi_collect_all_certs(myTemplate, templateCount, &listp,
1151 &size, 0, &error);
1152
1153 /* free them */
1154 if (count > 1) {
1155 *io = listp[0];
1156 found = PR_TRUE;
1157 }
1158
1159 for (i = 1; i < count; i++) {
1160 nss_ckcapi_DestroyInternalObject(listp[i]);
1161 }
1162 nss_ZFreeIf(listp);
1163 return found;
1164 }
1165
1166 static PRBool
ckcapi_cert_hasEmail(PCCERT_CONTEXT certContext)1167 ckcapi_cert_hasEmail(
1168 PCCERT_CONTEXT certContext)
1169 {
1170 int count;
1171
1172 count = CertGetNameString(certContext, CERT_NAME_EMAIL_TYPE,
1173 0, NULL, NULL, 0);
1174
1175 return count > 1 ? PR_TRUE : PR_FALSE;
1176 }
1177
1178 static PRBool
ckcapi_cert_isRoot(PCCERT_CONTEXT certContext)1179 ckcapi_cert_isRoot(
1180 PCCERT_CONTEXT certContext)
1181 {
1182 return CertCompareCertificateName(certContext->dwCertEncodingType,
1183 &certContext->pCertInfo->Issuer, &certContext->pCertInfo->Subject);
1184 }
1185
1186 static PRBool
ckcapi_cert_isCA(PCCERT_CONTEXT certContext)1187 ckcapi_cert_isCA(
1188 PCCERT_CONTEXT certContext)
1189 {
1190 PCERT_EXTENSION extension;
1191 CERT_BASIC_CONSTRAINTS2_INFO basicInfo;
1192 DWORD size = sizeof(basicInfo);
1193 BOOL rc;
1194
1195 extension = CertFindExtension(szOID_BASIC_CONSTRAINTS,
1196 certContext->pCertInfo->cExtension,
1197 certContext->pCertInfo->rgExtension);
1198 if ((PCERT_EXTENSION)NULL == extension) {
1199 return PR_FALSE;
1200 }
1201 rc = CryptDecodeObject(X509_ASN_ENCODING, szOID_BASIC_CONSTRAINTS2,
1202 extension->Value.pbData, extension->Value.cbData,
1203 0, &basicInfo, &size);
1204 if (!rc) {
1205 return PR_FALSE;
1206 }
1207 return (PRBool)basicInfo.fCA;
1208 }
1209
1210 static CRYPT_KEY_PROV_INFO *
ckcapi_cert_getPrivateKeyInfo(PCCERT_CONTEXT certContext,NSSItem * keyID)1211 ckcapi_cert_getPrivateKeyInfo(
1212 PCCERT_CONTEXT certContext,
1213 NSSItem *keyID)
1214 {
1215 BOOL rc;
1216 CRYPT_HASH_BLOB msKeyID;
1217 DWORD size = 0;
1218 CRYPT_KEY_PROV_INFO *prov = NULL;
1219
1220 msKeyID.cbData = keyID->size;
1221 msKeyID.pbData = keyID->data;
1222
1223 rc = CryptGetKeyIdentifierProperty(
1224 &msKeyID,
1225 CERT_KEY_PROV_INFO_PROP_ID,
1226 0, NULL, NULL, NULL, &size);
1227 if (!rc) {
1228 return (CRYPT_KEY_PROV_INFO *)NULL;
1229 }
1230 prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
1231 if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
1232 return (CRYPT_KEY_PROV_INFO *)NULL;
1233 }
1234 rc = CryptGetKeyIdentifierProperty(
1235 &msKeyID,
1236 CERT_KEY_PROV_INFO_PROP_ID,
1237 0, NULL, NULL, prov, &size);
1238 if (!rc) {
1239 nss_ZFreeIf(prov);
1240 return (CRYPT_KEY_PROV_INFO *)NULL;
1241 }
1242
1243 return prov;
1244 }
1245
1246 static CRYPT_KEY_PROV_INFO *
ckcapi_cert_getProvInfo(ckcapiInternalObject * io)1247 ckcapi_cert_getProvInfo(
1248 ckcapiInternalObject *io)
1249 {
1250 BOOL rc;
1251 DWORD size = 0;
1252 CRYPT_KEY_PROV_INFO *prov = NULL;
1253
1254 rc = CertGetCertificateContextProperty(
1255 io->u.cert.certContext,
1256 CERT_KEY_PROV_INFO_PROP_ID,
1257 NULL, &size);
1258 if (!rc) {
1259 return (CRYPT_KEY_PROV_INFO *)NULL;
1260 }
1261 prov = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
1262 if ((CRYPT_KEY_PROV_INFO *)prov == NULL) {
1263 return (CRYPT_KEY_PROV_INFO *)NULL;
1264 }
1265 rc = CertGetCertificateContextProperty(
1266 io->u.cert.certContext,
1267 CERT_KEY_PROV_INFO_PROP_ID,
1268 prov, &size);
1269 if (!rc) {
1270 nss_ZFreeIf(prov);
1271 return (CRYPT_KEY_PROV_INFO *)NULL;
1272 }
1273
1274 return prov;
1275 }
1276
1277 /* forward declaration */
1278 static void
1279 ckcapi_removeObjectFromHash(
1280 ckcapiInternalObject *io);
1281
1282 /*
1283 * Finalize - unneeded
1284 * Destroy
1285 * IsTokenObject - CK_TRUE
1286 * GetAttributeCount
1287 * GetAttributeTypes
1288 * GetAttributeSize
1289 * GetAttribute
1290 * SetAttribute
1291 * GetObjectSize
1292 */
1293
1294 static CK_RV
ckcapi_mdObject_Destroy(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)1295 ckcapi_mdObject_Destroy(
1296 NSSCKMDObject *mdObject,
1297 NSSCKFWObject *fwObject,
1298 NSSCKMDSession *mdSession,
1299 NSSCKFWSession *fwSession,
1300 NSSCKMDToken *mdToken,
1301 NSSCKFWToken *fwToken,
1302 NSSCKMDInstance *mdInstance,
1303 NSSCKFWInstance *fwInstance)
1304 {
1305 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1306 CK_OBJECT_CLASS objClass;
1307 BOOL rc;
1308 DWORD provType;
1309 DWORD msError;
1310 PRBool isCertType = (PRBool)(ckcapiCert == io->type);
1311 HCERTSTORE hStore = 0;
1312
1313 if (ckcapiRaw == io->type) {
1314 /* there is not 'object write protected' error, use the next best thing */
1315 return CKR_TOKEN_WRITE_PROTECTED;
1316 }
1317
1318 objClass = io->objClass;
1319 if (CKO_CERTIFICATE == objClass) {
1320 PCCERT_CONTEXT certContext;
1321
1322 /* get the store */
1323 hStore = CertOpenSystemStore(0, io->u.cert.certStore);
1324 if (0 == hStore) {
1325 rc = 0;
1326 goto loser;
1327 }
1328 certContext = CertFindCertificateInStore(hStore, X509_ASN_ENCODING, 0,
1329 CERT_FIND_EXISTING, io->u.cert.certContext, NULL);
1330 if ((PCCERT_CONTEXT)NULL == certContext) {
1331 rc = 0;
1332 goto loser;
1333 }
1334 rc = CertDeleteCertificateFromStore(certContext);
1335 } else {
1336 char *provName = NULL;
1337 char *containerName = NULL;
1338 HCRYPTPROV hProv;
1339 CRYPT_HASH_BLOB msKeyID;
1340
1341 if (0 == io->id.size) {
1342 ckcapi_FetchID(io);
1343 }
1344
1345 if (isCertType) {
1346 CRYPT_KEY_PROV_INFO *provInfo = ckcapi_cert_getProvInfo(io);
1347 provName = nss_ckcapi_WideToUTF8(provInfo->pwszProvName);
1348 containerName = nss_ckcapi_WideToUTF8(provInfo->pwszContainerName);
1349 provType = provInfo->dwProvType;
1350 nss_ZFreeIf(provInfo);
1351 } else {
1352 provName = io->u.key.provName;
1353 containerName = io->u.key.containerName;
1354 provType = io->u.key.provInfo.dwProvType;
1355 io->u.key.provName = NULL;
1356 io->u.key.containerName = NULL;
1357 }
1358 /* first remove the key id pointer */
1359 msKeyID.cbData = io->id.size;
1360 msKeyID.pbData = io->id.data;
1361 rc = CryptSetKeyIdentifierProperty(&msKeyID,
1362 CERT_KEY_PROV_INFO_PROP_ID, CRYPT_KEYID_DELETE_FLAG, NULL, NULL, NULL);
1363 if (rc) {
1364 rc = CryptAcquireContext(&hProv, containerName, provName, provType,
1365 CRYPT_DELETEKEYSET);
1366 }
1367 nss_ZFreeIf(provName);
1368 nss_ZFreeIf(containerName);
1369 }
1370 loser:
1371
1372 if (hStore) {
1373 CertCloseStore(hStore, 0);
1374 }
1375 if (!rc) {
1376 msError = GetLastError();
1377 return CKR_GENERAL_ERROR;
1378 }
1379
1380 /* remove it from the hash */
1381 ckcapi_removeObjectFromHash(io);
1382
1383 /* free the puppy.. */
1384 nss_ckcapi_DestroyInternalObject(io);
1385 return CKR_OK;
1386 }
1387
1388 static CK_BBOOL
ckcapi_mdObject_IsTokenObject(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)1389 ckcapi_mdObject_IsTokenObject(
1390 NSSCKMDObject *mdObject,
1391 NSSCKFWObject *fwObject,
1392 NSSCKMDSession *mdSession,
1393 NSSCKFWSession *fwSession,
1394 NSSCKMDToken *mdToken,
1395 NSSCKFWToken *fwToken,
1396 NSSCKMDInstance *mdInstance,
1397 NSSCKFWInstance *fwInstance)
1398 {
1399 return CK_TRUE;
1400 }
1401
1402 static CK_ULONG
ckcapi_mdObject_GetAttributeCount(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_RV * pError)1403 ckcapi_mdObject_GetAttributeCount(
1404 NSSCKMDObject *mdObject,
1405 NSSCKFWObject *fwObject,
1406 NSSCKMDSession *mdSession,
1407 NSSCKFWSession *fwSession,
1408 NSSCKMDToken *mdToken,
1409 NSSCKFWToken *fwToken,
1410 NSSCKMDInstance *mdInstance,
1411 NSSCKFWInstance *fwInstance,
1412 CK_RV *pError)
1413 {
1414 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1415
1416 if (ckcapiRaw == io->type) {
1417 return io->u.raw.n;
1418 }
1419 switch (io->objClass) {
1420 case CKO_CERTIFICATE:
1421 return certAttrsCount;
1422 case CKO_PUBLIC_KEY:
1423 return pubKeyAttrsCount;
1424 case CKO_PRIVATE_KEY:
1425 return privKeyAttrsCount;
1426 default:
1427 break;
1428 }
1429 return 0;
1430 }
1431
1432 static CK_RV
ckcapi_mdObject_GetAttributeTypes(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE_PTR typeArray,CK_ULONG ulCount)1433 ckcapi_mdObject_GetAttributeTypes(
1434 NSSCKMDObject *mdObject,
1435 NSSCKFWObject *fwObject,
1436 NSSCKMDSession *mdSession,
1437 NSSCKFWSession *fwSession,
1438 NSSCKMDToken *mdToken,
1439 NSSCKFWToken *fwToken,
1440 NSSCKMDInstance *mdInstance,
1441 NSSCKFWInstance *fwInstance,
1442 CK_ATTRIBUTE_TYPE_PTR typeArray,
1443 CK_ULONG ulCount)
1444 {
1445 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1446 CK_ULONG i;
1447 CK_RV error = CKR_OK;
1448 const CK_ATTRIBUTE_TYPE *attrs = NULL;
1449 CK_ULONG size = ckcapi_mdObject_GetAttributeCount(
1450 mdObject, fwObject, mdSession, fwSession,
1451 mdToken, fwToken, mdInstance, fwInstance, &error);
1452
1453 if (size != ulCount) {
1454 return CKR_BUFFER_TOO_SMALL;
1455 }
1456 if (io->type == ckcapiRaw) {
1457 attrs = io->u.raw.types;
1458 } else
1459 switch (io->objClass) {
1460 case CKO_CERTIFICATE:
1461 attrs =
1462 certAttrs;
1463 break;
1464 case CKO_PUBLIC_KEY:
1465 attrs =
1466 pubKeyAttrs;
1467 break;
1468 case CKO_PRIVATE_KEY:
1469 attrs =
1470 privKeyAttrs;
1471 break;
1472 default:
1473 return CKR_OK;
1474 }
1475
1476 for (i = 0; i < size; i++) {
1477 typeArray[i] = attrs[i];
1478 }
1479
1480 return CKR_OK;
1481 }
1482
1483 static CK_ULONG
ckcapi_mdObject_GetAttributeSize(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,CK_RV * pError)1484 ckcapi_mdObject_GetAttributeSize(
1485 NSSCKMDObject *mdObject,
1486 NSSCKFWObject *fwObject,
1487 NSSCKMDSession *mdSession,
1488 NSSCKFWSession *fwSession,
1489 NSSCKMDToken *mdToken,
1490 NSSCKFWToken *fwToken,
1491 NSSCKMDInstance *mdInstance,
1492 NSSCKFWInstance *fwInstance,
1493 CK_ATTRIBUTE_TYPE attribute,
1494 CK_RV *pError)
1495 {
1496 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1497
1498 const NSSItem *b;
1499
1500 b = nss_ckcapi_FetchAttribute(io, attribute);
1501
1502 if ((const NSSItem *)NULL == b) {
1503 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
1504 return 0;
1505 }
1506 return b->size;
1507 }
1508
1509 static CK_RV
ckcapi_mdObject_SetAttribute(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,NSSItem * value)1510 ckcapi_mdObject_SetAttribute(
1511 NSSCKMDObject *mdObject,
1512 NSSCKFWObject *fwObject,
1513 NSSCKMDSession *mdSession,
1514 NSSCKFWSession *fwSession,
1515 NSSCKMDToken *mdToken,
1516 NSSCKFWToken *fwToken,
1517 NSSCKMDInstance *mdInstance,
1518 NSSCKFWInstance *fwInstance,
1519 CK_ATTRIBUTE_TYPE attribute,
1520 NSSItem *value)
1521 {
1522 return CKR_OK;
1523 }
1524
1525 static NSSCKFWItem
ckcapi_mdObject_GetAttribute(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_ATTRIBUTE_TYPE attribute,CK_RV * pError)1526 ckcapi_mdObject_GetAttribute(
1527 NSSCKMDObject *mdObject,
1528 NSSCKFWObject *fwObject,
1529 NSSCKMDSession *mdSession,
1530 NSSCKFWSession *fwSession,
1531 NSSCKMDToken *mdToken,
1532 NSSCKFWToken *fwToken,
1533 NSSCKMDInstance *mdInstance,
1534 NSSCKFWInstance *fwInstance,
1535 CK_ATTRIBUTE_TYPE attribute,
1536 CK_RV *pError)
1537 {
1538 NSSCKFWItem mdItem;
1539 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1540
1541 mdItem.needsFreeing = PR_FALSE;
1542 mdItem.item = (NSSItem *)nss_ckcapi_FetchAttribute(io, attribute);
1543
1544 if ((NSSItem *)NULL == mdItem.item) {
1545 *pError = CKR_ATTRIBUTE_TYPE_INVALID;
1546 }
1547
1548 return mdItem;
1549 }
1550
1551 static CK_ULONG
ckcapi_mdObject_GetObjectSize(NSSCKMDObject * mdObject,NSSCKFWObject * fwObject,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,CK_RV * pError)1552 ckcapi_mdObject_GetObjectSize(
1553 NSSCKMDObject *mdObject,
1554 NSSCKFWObject *fwObject,
1555 NSSCKMDSession *mdSession,
1556 NSSCKFWSession *fwSession,
1557 NSSCKMDToken *mdToken,
1558 NSSCKFWToken *fwToken,
1559 NSSCKMDInstance *mdInstance,
1560 NSSCKFWInstance *fwInstance,
1561 CK_RV *pError)
1562 {
1563 ckcapiInternalObject *io = (ckcapiInternalObject *)mdObject->etc;
1564 CK_ULONG rv = 1;
1565
1566 /* size is irrelevant to this token */
1567 return rv;
1568 }
1569
1570 static const NSSCKMDObject
1571 ckcapi_prototype_mdObject = {
1572 (void *)NULL, /* etc */
1573 NULL, /* Finalize */
1574 ckcapi_mdObject_Destroy,
1575 ckcapi_mdObject_IsTokenObject,
1576 ckcapi_mdObject_GetAttributeCount,
1577 ckcapi_mdObject_GetAttributeTypes,
1578 ckcapi_mdObject_GetAttributeSize,
1579 ckcapi_mdObject_GetAttribute,
1580 NULL, /* FreeAttribute */
1581 ckcapi_mdObject_SetAttribute,
1582 ckcapi_mdObject_GetObjectSize,
1583 (void *)NULL /* null terminator */
1584 };
1585
1586 static nssHash *ckcapiInternalObjectHash = NULL;
1587
1588 NSS_IMPLEMENT NSSCKMDObject *
nss_ckcapi_CreateMDObject(NSSArena * arena,ckcapiInternalObject * io,CK_RV * pError)1589 nss_ckcapi_CreateMDObject(
1590 NSSArena *arena,
1591 ckcapiInternalObject *io,
1592 CK_RV *pError)
1593 {
1594 if ((nssHash *)NULL == ckcapiInternalObjectHash) {
1595 ckcapiInternalObjectHash = nssHash_CreateItem(NULL, 10);
1596 }
1597 if (ckcapiCert == io->type) {
1598 /* the hash key, not a cryptographic key */
1599 NSSItem *key = &io->hashKey;
1600 ckcapiInternalObject *old_o = NULL;
1601
1602 if (key->size == 0) {
1603 ckcapi_FetchHashKey(io);
1604 }
1605 old_o = (ckcapiInternalObject *)
1606 nssHash_Lookup(ckcapiInternalObjectHash, key);
1607 if (!old_o) {
1608 nssHash_Add(ckcapiInternalObjectHash, key, io);
1609 } else if (old_o != io) {
1610 nss_ckcapi_DestroyInternalObject(io);
1611 io = old_o;
1612 }
1613 }
1614
1615 if ((void *)NULL == io->mdObject.etc) {
1616 (void)nsslibc_memcpy(&io->mdObject, &ckcapi_prototype_mdObject,
1617 sizeof(ckcapi_prototype_mdObject));
1618 io->mdObject.etc = (void *)io;
1619 }
1620 return &io->mdObject;
1621 }
1622
1623 static void
ckcapi_removeObjectFromHash(ckcapiInternalObject * io)1624 ckcapi_removeObjectFromHash(
1625 ckcapiInternalObject *io)
1626 {
1627 NSSItem *key = &io->hashKey;
1628
1629 if ((nssHash *)NULL == ckcapiInternalObjectHash) {
1630 return;
1631 }
1632 if (key->size == 0) {
1633 ckcapi_FetchHashKey(io);
1634 }
1635 nssHash_Remove(ckcapiInternalObjectHash, key);
1636 return;
1637 }
1638
1639 void
nss_ckcapi_DestroyInternalObject(ckcapiInternalObject * io)1640 nss_ckcapi_DestroyInternalObject(
1641 ckcapiInternalObject *io)
1642 {
1643 switch (io->type) {
1644 case ckcapiRaw:
1645 return;
1646 case ckcapiCert:
1647 CertFreeCertificateContext(io->u.cert.certContext);
1648 nss_ZFreeIf(io->u.cert.labelData);
1649 nss_ZFreeIf(io->u.cert.key.privateKey);
1650 nss_ZFreeIf(io->u.cert.key.pubKey);
1651 nss_ZFreeIf(io->idData);
1652 break;
1653 case ckcapiBareKey:
1654 nss_ZFreeIf(io->u.key.provInfo.pwszContainerName);
1655 nss_ZFreeIf(io->u.key.provInfo.pwszProvName);
1656 nss_ZFreeIf(io->u.key.provName);
1657 nss_ZFreeIf(io->u.key.containerName);
1658 nss_ZFreeIf(io->u.key.key.privateKey);
1659 nss_ZFreeIf(io->u.key.key.pubKey);
1660 if (0 != io->u.key.hProv) {
1661 CryptReleaseContext(io->u.key.hProv, 0);
1662 }
1663 nss_ZFreeIf(io->idData);
1664 break;
1665 }
1666 nss_ZFreeIf(io);
1667 return;
1668 }
1669
1670 static ckcapiInternalObject *
nss_ckcapi_CreateCertificate(NSSCKFWSession * fwSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_RV * pError)1671 nss_ckcapi_CreateCertificate(
1672 NSSCKFWSession *fwSession,
1673 CK_ATTRIBUTE_PTR pTemplate,
1674 CK_ULONG ulAttributeCount,
1675 CK_RV *pError)
1676 {
1677 NSSItem value;
1678 NSSItem keyID;
1679 char *storeStr;
1680 ckcapiInternalObject *io = NULL;
1681 PCCERT_CONTEXT certContext = NULL;
1682 PCCERT_CONTEXT storedCertContext = NULL;
1683 CRYPT_KEY_PROV_INFO *prov_info = NULL;
1684 char *nickname = NULL;
1685 HCERTSTORE hStore = 0;
1686 DWORD msError = 0;
1687 PRBool hasID;
1688 CK_RV dummy;
1689 BOOL rc;
1690
1691 *pError = nss_ckcapi_GetAttribute(CKA_VALUE, pTemplate,
1692 ulAttributeCount, &value);
1693
1694 if (CKR_OK != *pError) {
1695 return (ckcapiInternalObject *)NULL;
1696 }
1697
1698 *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate,
1699 ulAttributeCount, &keyID);
1700
1701 if (CKR_OK != *pError) {
1702 return (ckcapiInternalObject *)NULL;
1703 }
1704
1705 if (ckcapi_cert_exists(&value, &io)) {
1706 return io;
1707 }
1708
1709 /* OK, we are creating a new one, figure out what store it belongs to..
1710 * first get a certContext handle.. */
1711 certContext = CertCreateCertificateContext(X509_ASN_ENCODING,
1712 value.data, value.size);
1713 if ((PCCERT_CONTEXT)NULL == certContext) {
1714 msError = GetLastError();
1715 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
1716 goto loser;
1717 }
1718
1719 /* do we have a private key laying around... */
1720 prov_info = ckcapi_cert_getPrivateKeyInfo(certContext, &keyID);
1721 if (prov_info) {
1722 CRYPT_DATA_BLOB msKeyID;
1723 storeStr = "My";
1724 hasID = PR_TRUE;
1725 rc = CertSetCertificateContextProperty(certContext,
1726 CERT_KEY_PROV_INFO_PROP_ID,
1727 0, prov_info);
1728 nss_ZFreeIf(prov_info);
1729 if (!rc) {
1730 msError = GetLastError();
1731 *pError = CKR_DEVICE_ERROR;
1732 goto loser;
1733 }
1734 msKeyID.cbData = keyID.size;
1735 msKeyID.pbData = keyID.data;
1736 rc = CertSetCertificateContextProperty(certContext,
1737 CERT_KEY_IDENTIFIER_PROP_ID,
1738 0, &msKeyID);
1739 if (!rc) {
1740 msError = GetLastError();
1741 *pError = CKR_DEVICE_ERROR;
1742 goto loser;
1743 }
1744
1745 /* does it look like a CA */
1746 } else if (ckcapi_cert_isCA(certContext)) {
1747 storeStr = ckcapi_cert_isRoot(certContext) ? "CA" : "Root";
1748 /* does it look like an S/MIME cert */
1749 } else if (ckcapi_cert_hasEmail(certContext)) {
1750 storeStr = "AddressBook";
1751 } else {
1752 /* just pick a store */
1753 storeStr = "CA";
1754 }
1755
1756 /* get the nickname, not an error if we can't find it */
1757 nickname = nss_ckcapi_GetStringAttribute(CKA_LABEL, pTemplate,
1758 ulAttributeCount, &dummy);
1759 if (nickname) {
1760 LPWSTR nicknameUTF16 = NULL;
1761 CRYPT_DATA_BLOB nicknameBlob;
1762
1763 nicknameUTF16 = nss_ckcapi_UTF8ToWide(nickname);
1764 nss_ZFreeIf(nickname);
1765 nickname = NULL;
1766 if ((LPWSTR)NULL == nicknameUTF16) {
1767 *pError = CKR_HOST_MEMORY;
1768 goto loser;
1769 }
1770 nicknameBlob.cbData = nss_ckcapi_WideSize(nicknameUTF16);
1771 nicknameBlob.pbData = (BYTE *)nicknameUTF16;
1772 rc = CertSetCertificateContextProperty(certContext,
1773 CERT_FRIENDLY_NAME_PROP_ID, 0, &nicknameBlob);
1774 nss_ZFreeIf(nicknameUTF16);
1775 if (!rc) {
1776 msError = GetLastError();
1777 *pError = CKR_DEVICE_ERROR;
1778 goto loser;
1779 }
1780 }
1781
1782 hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
1783 if (0 == hStore) {
1784 msError = GetLastError();
1785 *pError = CKR_DEVICE_ERROR;
1786 goto loser;
1787 }
1788
1789 rc = CertAddCertificateContextToStore(hStore, certContext,
1790 CERT_STORE_ADD_REPLACE_EXISTING_INHERIT_PROPERTIES, &storedCertContext);
1791 CertFreeCertificateContext(certContext);
1792 certContext = NULL;
1793 CertCloseStore(hStore, 0);
1794 hStore = 0;
1795 if (!rc) {
1796 msError = GetLastError();
1797 *pError = CKR_DEVICE_ERROR;
1798 goto loser;
1799 }
1800
1801 io = nss_ZNEW(NULL, ckcapiInternalObject);
1802 if ((ckcapiInternalObject *)NULL == io) {
1803 *pError = CKR_HOST_MEMORY;
1804 goto loser;
1805 }
1806 io->type = ckcapiCert;
1807 io->objClass = CKO_CERTIFICATE;
1808 io->u.cert.certContext = storedCertContext;
1809 io->u.cert.hasID = hasID;
1810 return io;
1811
1812 loser:
1813 if (certContext) {
1814 CertFreeCertificateContext(certContext);
1815 certContext = NULL;
1816 }
1817 if (storedCertContext) {
1818 CertFreeCertificateContext(storedCertContext);
1819 storedCertContext = NULL;
1820 }
1821 if (0 != hStore) {
1822 CertCloseStore(hStore, 0);
1823 }
1824 return (ckcapiInternalObject *)NULL;
1825 }
1826
1827 static char *
ckcapi_getDefaultProvider(CK_RV * pError)1828 ckcapi_getDefaultProvider(
1829 CK_RV *pError)
1830 {
1831 char *name = NULL;
1832 BOOL rc;
1833 DWORD nameLength = 0;
1834
1835 rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, NULL,
1836 &nameLength);
1837 if (!rc) {
1838 return (char *)NULL;
1839 }
1840
1841 name = nss_ZNEWARRAY(NULL, char, nameLength);
1842 if ((char *)NULL == name) {
1843 return (char *)NULL;
1844 }
1845 rc = CryptGetDefaultProvider(PROV_RSA_FULL, NULL, CRYPT_USER_DEFAULT, name,
1846 &nameLength);
1847 if (!rc) {
1848 nss_ZFreeIf(name);
1849 return (char *)NULL;
1850 }
1851
1852 return name;
1853 }
1854
1855 static char *
ckcapi_getContainer(CK_RV * pError,NSSItem * id)1856 ckcapi_getContainer(
1857 CK_RV *pError,
1858 NSSItem *id)
1859 {
1860 RPC_STATUS rstat;
1861 UUID uuid;
1862 char *uuidStr;
1863 char *container;
1864
1865 rstat = UuidCreate(&uuid);
1866 rstat = UuidToString(&uuid, &uuidStr);
1867
1868 /* convert it from rcp memory to our own */
1869 container = nssUTF8_Duplicate(uuidStr, NULL);
1870 RpcStringFree(&uuidStr);
1871
1872 return container;
1873 }
1874
1875 static CK_RV
ckcapi_buildPrivateKeyBlob(NSSItem * keyBlob,NSSItem * modulus,NSSItem * publicExponent,NSSItem * privateExponent,NSSItem * prime1,NSSItem * prime2,NSSItem * exponent1,NSSItem * exponent2,NSSItem * coefficient,PRBool isKeyExchange)1876 ckcapi_buildPrivateKeyBlob(
1877 NSSItem *keyBlob,
1878 NSSItem *modulus,
1879 NSSItem *publicExponent,
1880 NSSItem *privateExponent,
1881 NSSItem *prime1,
1882 NSSItem *prime2,
1883 NSSItem *exponent1,
1884 NSSItem *exponent2,
1885 NSSItem *coefficient,
1886 PRBool isKeyExchange)
1887 {
1888 CAPI_RSA_KEY_BLOB *keyBlobData = NULL;
1889 unsigned char *target;
1890 unsigned long modSize = modulus->size;
1891 unsigned long dataSize;
1892 CK_RV error = CKR_OK;
1893
1894 /* validate extras */
1895 if (privateExponent->size != modSize) {
1896 error = CKR_ATTRIBUTE_VALUE_INVALID;
1897 goto loser;
1898 }
1899 if (prime1->size != modSize / 2) {
1900 error = CKR_ATTRIBUTE_VALUE_INVALID;
1901 goto loser;
1902 }
1903 if (prime2->size != modSize / 2) {
1904 error = CKR_ATTRIBUTE_VALUE_INVALID;
1905 goto loser;
1906 }
1907 if (exponent1->size != modSize / 2) {
1908 error = CKR_ATTRIBUTE_VALUE_INVALID;
1909 goto loser;
1910 }
1911 if (exponent2->size != modSize / 2) {
1912 error = CKR_ATTRIBUTE_VALUE_INVALID;
1913 goto loser;
1914 }
1915 if (coefficient->size != modSize / 2) {
1916 error = CKR_ATTRIBUTE_VALUE_INVALID;
1917 goto loser;
1918 }
1919 dataSize = (modSize * 4) + (modSize / 2) + sizeof(CAPI_RSA_KEY_BLOB);
1920 keyBlobData = (CAPI_RSA_KEY_BLOB *)nss_ZAlloc(NULL, dataSize);
1921 if ((CAPI_RSA_KEY_BLOB *)NULL == keyBlobData) {
1922 error = CKR_HOST_MEMORY;
1923 goto loser;
1924 }
1925
1926 keyBlobData->header.bType = PRIVATEKEYBLOB;
1927 keyBlobData->header.bVersion = 0x02;
1928 keyBlobData->header.reserved = 0x00;
1929 keyBlobData->header.aiKeyAlg = isKeyExchange ? CALG_RSA_KEYX : CALG_RSA_SIGN;
1930 keyBlobData->rsa.magic = 0x32415352;
1931 keyBlobData->rsa.bitlen = modSize * 8;
1932 keyBlobData->rsa.pubexp = nss_ckcapi_DataToInt(publicExponent, &error);
1933 if (CKR_OK != error) {
1934 goto loser;
1935 }
1936
1937 target = &keyBlobData->data[CAPI_MODULUS_OFFSET(modSize)];
1938 nsslibc_memcpy(target, modulus->data, modulus->size);
1939 modulus->data = target;
1940 ckcapi_ReverseData(modulus);
1941
1942 target = &keyBlobData->data[CAPI_PRIVATE_EXP_OFFSET(modSize)];
1943 nsslibc_memcpy(target, privateExponent->data, privateExponent->size);
1944 privateExponent->data = target;
1945 ckcapi_ReverseData(privateExponent);
1946
1947 target = &keyBlobData->data[CAPI_PRIME_1_OFFSET(modSize)];
1948 nsslibc_memcpy(target, prime1->data, prime1->size);
1949 prime1->data = target;
1950 ckcapi_ReverseData(prime1);
1951
1952 target = &keyBlobData->data[CAPI_PRIME_2_OFFSET(modSize)];
1953 nsslibc_memcpy(target, prime2->data, prime2->size);
1954 prime2->data = target;
1955 ckcapi_ReverseData(prime2);
1956
1957 target = &keyBlobData->data[CAPI_EXPONENT_1_OFFSET(modSize)];
1958 nsslibc_memcpy(target, exponent1->data, exponent1->size);
1959 exponent1->data = target;
1960 ckcapi_ReverseData(exponent1);
1961
1962 target = &keyBlobData->data[CAPI_EXPONENT_2_OFFSET(modSize)];
1963 nsslibc_memcpy(target, exponent2->data, exponent2->size);
1964 exponent2->data = target;
1965 ckcapi_ReverseData(exponent2);
1966
1967 target = &keyBlobData->data[CAPI_COEFFICIENT_OFFSET(modSize)];
1968 nsslibc_memcpy(target, coefficient->data, coefficient->size);
1969 coefficient->data = target;
1970 ckcapi_ReverseData(coefficient);
1971
1972 keyBlob->data = keyBlobData;
1973 keyBlob->size = dataSize;
1974
1975 return CKR_OK;
1976
1977 loser:
1978 nss_ZFreeIf(keyBlobData);
1979 return error;
1980 }
1981
1982 static ckcapiInternalObject *
nss_ckcapi_CreatePrivateKey(NSSCKFWSession * fwSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_RV * pError)1983 nss_ckcapi_CreatePrivateKey(
1984 NSSCKFWSession *fwSession,
1985 CK_ATTRIBUTE_PTR pTemplate,
1986 CK_ULONG ulAttributeCount,
1987 CK_RV *pError)
1988 {
1989 NSSItem modulus;
1990 NSSItem publicExponent;
1991 NSSItem privateExponent;
1992 NSSItem exponent1;
1993 NSSItem exponent2;
1994 NSSItem prime1;
1995 NSSItem prime2;
1996 NSSItem coefficient;
1997 NSSItem keyID;
1998 NSSItem keyBlob;
1999 ckcapiInternalObject *io = NULL;
2000 char *providerName = NULL;
2001 char *containerName = NULL;
2002 char *idData = NULL;
2003 CRYPT_KEY_PROV_INFO provInfo;
2004 CRYPT_HASH_BLOB msKeyID;
2005 CK_KEY_TYPE keyType;
2006 HCRYPTPROV hProv = 0;
2007 HCRYPTKEY hKey = 0;
2008 PRBool decrypt;
2009 DWORD keySpec;
2010 DWORD msError;
2011 BOOL rc;
2012
2013 keyType = nss_ckcapi_GetULongAttribute(CKA_KEY_TYPE, pTemplate, ulAttributeCount, pError);
2014 if (CKR_OK != *pError) {
2015 return (ckcapiInternalObject *)NULL;
2016 }
2017 if (CKK_RSA != keyType) {
2018 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
2019 return (ckcapiInternalObject *)NULL;
2020 }
2021
2022 decrypt = nss_ckcapi_GetBoolAttribute(CKA_DECRYPT,
2023 pTemplate, ulAttributeCount, pError);
2024 if (CKR_TEMPLATE_INCOMPLETE == *pError) {
2025 decrypt = PR_TRUE; /* default to true */
2026 }
2027 decrypt = decrypt || nss_ckcapi_GetBoolAttribute(CKA_UNWRAP,
2028 pTemplate, ulAttributeCount, pError);
2029 if (CKR_TEMPLATE_INCOMPLETE == *pError) {
2030 decrypt = PR_TRUE; /* default to true */
2031 }
2032 keySpec = decrypt ? AT_KEYEXCHANGE : AT_SIGNATURE;
2033
2034 *pError = nss_ckcapi_GetAttribute(CKA_MODULUS, pTemplate,
2035 ulAttributeCount, &modulus);
2036 if (CKR_OK != *pError) {
2037 return (ckcapiInternalObject *)NULL;
2038 }
2039 *pError = nss_ckcapi_GetAttribute(CKA_PUBLIC_EXPONENT, pTemplate,
2040 ulAttributeCount, &publicExponent);
2041 if (CKR_OK != *pError) {
2042 return (ckcapiInternalObject *)NULL;
2043 }
2044 *pError = nss_ckcapi_GetAttribute(CKA_PRIVATE_EXPONENT, pTemplate,
2045 ulAttributeCount, &privateExponent);
2046 if (CKR_OK != *pError) {
2047 return (ckcapiInternalObject *)NULL;
2048 }
2049 *pError = nss_ckcapi_GetAttribute(CKA_PRIME_1, pTemplate,
2050 ulAttributeCount, &prime1);
2051 if (CKR_OK != *pError) {
2052 return (ckcapiInternalObject *)NULL;
2053 }
2054 *pError = nss_ckcapi_GetAttribute(CKA_PRIME_2, pTemplate,
2055 ulAttributeCount, &prime2);
2056 if (CKR_OK != *pError) {
2057 return (ckcapiInternalObject *)NULL;
2058 }
2059 *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_1, pTemplate,
2060 ulAttributeCount, &exponent1);
2061 if (CKR_OK != *pError) {
2062 return (ckcapiInternalObject *)NULL;
2063 }
2064 *pError = nss_ckcapi_GetAttribute(CKA_EXPONENT_2, pTemplate,
2065 ulAttributeCount, &exponent2);
2066 if (CKR_OK != *pError) {
2067 return (ckcapiInternalObject *)NULL;
2068 }
2069 *pError = nss_ckcapi_GetAttribute(CKA_COEFFICIENT, pTemplate,
2070 ulAttributeCount, &coefficient);
2071 if (CKR_OK != *pError) {
2072 return (ckcapiInternalObject *)NULL;
2073 }
2074 *pError = nss_ckcapi_GetAttribute(CKA_ID, pTemplate,
2075 ulAttributeCount, &keyID);
2076 if (CKR_OK != *pError) {
2077 return (ckcapiInternalObject *)NULL;
2078 }
2079 providerName = ckcapi_getDefaultProvider(pError);
2080 if ((char *)NULL == providerName) {
2081 return (ckcapiInternalObject *)NULL;
2082 }
2083 containerName = ckcapi_getContainer(pError, &keyID);
2084 if ((char *)NULL == containerName) {
2085 goto loser;
2086 }
2087 rc = CryptAcquireContext(&hProv, containerName, providerName,
2088 PROV_RSA_FULL, CRYPT_NEWKEYSET);
2089 if (!rc) {
2090 msError = GetLastError();
2091 *pError = CKR_DEVICE_ERROR;
2092 goto loser;
2093 }
2094
2095 *pError = ckcapi_buildPrivateKeyBlob(
2096 &keyBlob,
2097 &modulus,
2098 &publicExponent,
2099 &privateExponent,
2100 &prime1,
2101 &prime2,
2102 &exponent1,
2103 &exponent2,
2104 &coefficient,
2105 decrypt);
2106 if (CKR_OK != *pError) {
2107 goto loser;
2108 }
2109
2110 rc = CryptImportKey(hProv, keyBlob.data, keyBlob.size,
2111 0, CRYPT_EXPORTABLE, &hKey);
2112 if (!rc) {
2113 msError = GetLastError();
2114 *pError = CKR_DEVICE_ERROR;
2115 goto loser;
2116 }
2117
2118 idData = nss_ZNEWARRAY(NULL, char, keyID.size);
2119 if ((void *)NULL == idData) {
2120 *pError = CKR_HOST_MEMORY;
2121 goto loser;
2122 }
2123 nsslibc_memcpy(idData, keyID.data, keyID.size);
2124
2125 provInfo.pwszContainerName = nss_ckcapi_UTF8ToWide(containerName);
2126 provInfo.pwszProvName = nss_ckcapi_UTF8ToWide(providerName);
2127 provInfo.dwProvType = PROV_RSA_FULL;
2128 provInfo.dwFlags = 0;
2129 provInfo.cProvParam = 0;
2130 provInfo.rgProvParam = NULL;
2131 provInfo.dwKeySpec = keySpec;
2132
2133 msKeyID.cbData = keyID.size;
2134 msKeyID.pbData = keyID.data;
2135
2136 rc = CryptSetKeyIdentifierProperty(&msKeyID, CERT_KEY_PROV_INFO_PROP_ID,
2137 0, NULL, NULL, &provInfo);
2138 if (!rc) {
2139 goto loser;
2140 }
2141
2142 /* handle error here */
2143 io = nss_ZNEW(NULL, ckcapiInternalObject);
2144 if ((ckcapiInternalObject *)NULL == io) {
2145 *pError = CKR_HOST_MEMORY;
2146 goto loser;
2147 }
2148 io->type = ckcapiBareKey;
2149 io->objClass = CKO_PRIVATE_KEY;
2150 io->u.key.provInfo = provInfo;
2151 io->u.key.provName = providerName;
2152 io->u.key.containerName = containerName;
2153 io->u.key.hProv = hProv; /* save the handle */
2154 io->idData = idData;
2155 io->id.data = idData;
2156 io->id.size = keyID.size;
2157 /* done with the key handle */
2158 CryptDestroyKey(hKey);
2159 return io;
2160
2161 loser:
2162 nss_ZFreeIf(containerName);
2163 nss_ZFreeIf(providerName);
2164 nss_ZFreeIf(idData);
2165 if (0 != hProv) {
2166 CryptReleaseContext(hProv, 0);
2167 }
2168 if (0 != hKey) {
2169 CryptDestroyKey(hKey);
2170 }
2171 return (ckcapiInternalObject *)NULL;
2172 }
2173
2174 NSS_EXTERN NSSCKMDObject *
nss_ckcapi_CreateObject(NSSCKFWSession * fwSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_RV * pError)2175 nss_ckcapi_CreateObject(
2176 NSSCKFWSession *fwSession,
2177 CK_ATTRIBUTE_PTR pTemplate,
2178 CK_ULONG ulAttributeCount,
2179 CK_RV *pError)
2180 {
2181 CK_OBJECT_CLASS objClass;
2182 ckcapiInternalObject *io = NULL;
2183 CK_BBOOL isToken;
2184
2185 /*
2186 * only create token objects
2187 */
2188 isToken = nss_ckcapi_GetBoolAttribute(CKA_TOKEN, pTemplate,
2189 ulAttributeCount, pError);
2190 if (CKR_OK != *pError) {
2191 return (NSSCKMDObject *)NULL;
2192 }
2193 if (!isToken) {
2194 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
2195 return (NSSCKMDObject *)NULL;
2196 }
2197
2198 /*
2199 * only create keys and certs.
2200 */
2201 objClass = nss_ckcapi_GetULongAttribute(CKA_CLASS, pTemplate,
2202 ulAttributeCount, pError);
2203 if (CKR_OK != *pError) {
2204 return (NSSCKMDObject *)NULL;
2205 }
2206 #ifdef notdef
2207 if (objClass == CKO_PUBLIC_KEY) {
2208 return CKR_OK; /* fake public key creation, happens as a side effect of
2209 * private key creation */
2210 }
2211 #endif
2212 if (objClass == CKO_CERTIFICATE) {
2213 io = nss_ckcapi_CreateCertificate(fwSession, pTemplate,
2214 ulAttributeCount, pError);
2215 } else if (objClass == CKO_PRIVATE_KEY) {
2216 io = nss_ckcapi_CreatePrivateKey(fwSession, pTemplate,
2217 ulAttributeCount, pError);
2218 } else {
2219 *pError = CKR_ATTRIBUTE_VALUE_INVALID;
2220 }
2221
2222 if ((ckcapiInternalObject *)NULL == io) {
2223 return (NSSCKMDObject *)NULL;
2224 }
2225 return nss_ckcapi_CreateMDObject(NULL, io, pError);
2226 }
2227