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