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 #ifndef CKCAPI_H
6 #include "ckcapi.h"
7 #endif /* CKCAPI_H */
8
9 /*
10 * ckcapi/cfind.c
11 *
12 * This file implements the NSSCKMDFindObjects object for the
13 * "capi" cryptoki module.
14 */
15
16 struct ckcapiFOStr {
17 NSSArena *arena;
18 CK_ULONG n;
19 CK_ULONG i;
20 ckcapiInternalObject **objs;
21 };
22
23 static void
ckcapi_mdFindObjects_Final(NSSCKMDFindObjects * mdFindObjects,NSSCKFWFindObjects * fwFindObjects,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance)24 ckcapi_mdFindObjects_Final(
25 NSSCKMDFindObjects *mdFindObjects,
26 NSSCKFWFindObjects *fwFindObjects,
27 NSSCKMDSession *mdSession,
28 NSSCKFWSession *fwSession,
29 NSSCKMDToken *mdToken,
30 NSSCKFWToken *fwToken,
31 NSSCKMDInstance *mdInstance,
32 NSSCKFWInstance *fwInstance)
33 {
34 struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
35 NSSArena *arena = fo->arena;
36 PRUint32 i;
37
38 /* walk down an free the unused 'objs' */
39 for (i = fo->i; i < fo->n; i++) {
40 nss_ckcapi_DestroyInternalObject(fo->objs[i]);
41 }
42
43 nss_ZFreeIf(fo->objs);
44 nss_ZFreeIf(fo);
45 nss_ZFreeIf(mdFindObjects);
46 if ((NSSArena *)NULL != arena) {
47 NSSArena_Destroy(arena);
48 }
49
50 return;
51 }
52
53 static NSSCKMDObject *
ckcapi_mdFindObjects_Next(NSSCKMDFindObjects * mdFindObjects,NSSCKFWFindObjects * fwFindObjects,NSSCKMDSession * mdSession,NSSCKFWSession * fwSession,NSSCKMDToken * mdToken,NSSCKFWToken * fwToken,NSSCKMDInstance * mdInstance,NSSCKFWInstance * fwInstance,NSSArena * arena,CK_RV * pError)54 ckcapi_mdFindObjects_Next(
55 NSSCKMDFindObjects *mdFindObjects,
56 NSSCKFWFindObjects *fwFindObjects,
57 NSSCKMDSession *mdSession,
58 NSSCKFWSession *fwSession,
59 NSSCKMDToken *mdToken,
60 NSSCKFWToken *fwToken,
61 NSSCKMDInstance *mdInstance,
62 NSSCKFWInstance *fwInstance,
63 NSSArena *arena,
64 CK_RV *pError)
65 {
66 struct ckcapiFOStr *fo = (struct ckcapiFOStr *)mdFindObjects->etc;
67 ckcapiInternalObject *io;
68
69 if (fo->i == fo->n) {
70 *pError = CKR_OK;
71 return (NSSCKMDObject *)NULL;
72 }
73
74 io = fo->objs[fo->i];
75 fo->i++;
76
77 return nss_ckcapi_CreateMDObject(arena, io, pError);
78 }
79
80 static CK_BBOOL
ckcapi_attrmatch(CK_ATTRIBUTE_PTR a,ckcapiInternalObject * o)81 ckcapi_attrmatch(
82 CK_ATTRIBUTE_PTR a,
83 ckcapiInternalObject *o)
84 {
85 PRBool prb;
86 const NSSItem *b;
87
88 b = nss_ckcapi_FetchAttribute(o, a->type);
89 if (b == NULL) {
90 return CK_FALSE;
91 }
92
93 if (a->ulValueLen != b->size) {
94 /* match a decoded serial number */
95 if ((a->type == CKA_SERIAL_NUMBER) && (a->ulValueLen < b->size)) {
96 unsigned int len;
97 unsigned char *data;
98
99 data = nss_ckcapi_DERUnwrap(b->data, b->size, &len, NULL);
100 if ((len == a->ulValueLen) &&
101 nsslibc_memequal(a->pValue, data, len, (PRStatus *)NULL)) {
102 return CK_TRUE;
103 }
104 }
105 return CK_FALSE;
106 }
107
108 prb = nsslibc_memequal(a->pValue, b->data, b->size, (PRStatus *)NULL);
109
110 if (PR_TRUE == prb) {
111 return CK_TRUE;
112 } else {
113 return CK_FALSE;
114 }
115 }
116
117 static CK_BBOOL
ckcapi_match(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,ckcapiInternalObject * o)118 ckcapi_match(
119 CK_ATTRIBUTE_PTR pTemplate,
120 CK_ULONG ulAttributeCount,
121 ckcapiInternalObject *o)
122 {
123 CK_ULONG i;
124
125 for (i = 0; i < ulAttributeCount; i++) {
126 if (CK_FALSE == ckcapi_attrmatch(&pTemplate[i], o)) {
127 return CK_FALSE;
128 }
129 }
130
131 /* Every attribute passed */
132 return CK_TRUE;
133 }
134
135 #define CKAPI_ITEM_CHUNK 20
136
137 #define PUT_Object(obj, err) \
138 { \
139 if (count >= size) { \
140 *listp = *listp ? nss_ZREALLOCARRAY(*listp, ckcapiInternalObject *, \
141 (size + \
142 CKAPI_ITEM_CHUNK)) \
143 : nss_ZNEWARRAY(NULL, ckcapiInternalObject *, \
144 (size + \
145 CKAPI_ITEM_CHUNK)); \
146 if ((ckcapiInternalObject **)NULL == *listp) { \
147 err = CKR_HOST_MEMORY; \
148 goto loser; \
149 } \
150 size += CKAPI_ITEM_CHUNK; \
151 } \
152 (*listp)[count] = (obj); \
153 count++; \
154 }
155
156 /*
157 * pass parameters back through the callback.
158 */
159 typedef struct BareCollectParamsStr {
160 CK_OBJECT_CLASS objClass;
161 CK_ATTRIBUTE_PTR pTemplate;
162 CK_ULONG ulAttributeCount;
163 ckcapiInternalObject ***listp;
164 PRUint32 size;
165 PRUint32 count;
166 } BareCollectParams;
167
168 /* collect_bare's callback. Called for each object that
169 * supposedly has a PROVINDER_INFO property */
170 static BOOL WINAPI
doBareCollect(const CRYPT_HASH_BLOB * msKeyID,DWORD flags,void * reserved,void * args,DWORD cProp,DWORD * propID,void ** propData,DWORD * propSize)171 doBareCollect(
172 const CRYPT_HASH_BLOB *msKeyID,
173 DWORD flags,
174 void *reserved,
175 void *args,
176 DWORD cProp,
177 DWORD *propID,
178 void **propData,
179 DWORD *propSize)
180 {
181 BareCollectParams *bcp = (BareCollectParams *)args;
182 PRUint32 size = bcp->size;
183 PRUint32 count = bcp->count;
184 ckcapiInternalObject ***listp = bcp->listp;
185 ckcapiInternalObject *io = NULL;
186 DWORD i;
187 CRYPT_KEY_PROV_INFO *keyProvInfo = NULL;
188 void *idData;
189 CK_RV error;
190
191 /* make sure there is a Key Provider Info property */
192 for (i = 0; i < cProp; i++) {
193 if (CERT_KEY_PROV_INFO_PROP_ID == propID[i]) {
194 keyProvInfo = (CRYPT_KEY_PROV_INFO *)propData[i];
195 break;
196 }
197 }
198 if ((CRYPT_KEY_PROV_INFO *)NULL == keyProvInfo) {
199 return 1;
200 }
201
202 /* copy the key ID */
203 idData = nss_ZNEWARRAY(NULL, char, msKeyID->cbData);
204 if ((void *)NULL == idData) {
205 goto loser;
206 }
207 nsslibc_memcpy(idData, msKeyID->pbData, msKeyID->cbData);
208
209 /* build a bare internal object */
210 io = nss_ZNEW(NULL, ckcapiInternalObject);
211 if ((ckcapiInternalObject *)NULL == io) {
212 goto loser;
213 }
214 io->type = ckcapiBareKey;
215 io->objClass = bcp->objClass;
216 io->u.key.provInfo = *keyProvInfo;
217 io->u.key.provInfo.pwszContainerName =
218 nss_ckcapi_WideDup(keyProvInfo->pwszContainerName);
219 io->u.key.provInfo.pwszProvName =
220 nss_ckcapi_WideDup(keyProvInfo->pwszProvName);
221 io->u.key.provName = nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
222 io->u.key.containerName =
223 nss_ckcapi_WideToUTF8(keyProvInfo->pwszContainerName);
224 io->u.key.hProv = 0;
225 io->idData = idData;
226 io->id.data = idData;
227 io->id.size = msKeyID->cbData;
228 idData = NULL;
229
230 /* see if it matches */
231 if (CK_FALSE == ckcapi_match(bcp->pTemplate, bcp->ulAttributeCount, io)) {
232 goto loser;
233 }
234 PUT_Object(io, error);
235 bcp->size = size;
236 bcp->count = count;
237 return 1;
238
239 loser:
240 if (io) {
241 nss_ckcapi_DestroyInternalObject(io);
242 }
243 nss_ZFreeIf(idData);
244 return 1;
245 }
246
247 /*
248 * collect the bare keys running around
249 */
250 static PRUint32
collect_bare(CK_OBJECT_CLASS objClass,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,ckcapiInternalObject *** listp,PRUint32 * sizep,PRUint32 count,CK_RV * pError)251 collect_bare(
252 CK_OBJECT_CLASS objClass,
253 CK_ATTRIBUTE_PTR pTemplate,
254 CK_ULONG ulAttributeCount,
255 ckcapiInternalObject ***listp,
256 PRUint32 *sizep,
257 PRUint32 count,
258 CK_RV *pError)
259 {
260 BOOL rc;
261 BareCollectParams bareCollectParams;
262
263 bareCollectParams.objClass = objClass;
264 bareCollectParams.pTemplate = pTemplate;
265 bareCollectParams.ulAttributeCount = ulAttributeCount;
266 bareCollectParams.listp = listp;
267 bareCollectParams.size = *sizep;
268 bareCollectParams.count = count;
269
270 rc = CryptEnumKeyIdentifierProperties(NULL, CERT_KEY_PROV_INFO_PROP_ID, 0,
271 NULL, NULL, &bareCollectParams, doBareCollect);
272
273 *sizep = bareCollectParams.size;
274 return bareCollectParams.count;
275 }
276
277 /* find all the certs that represent the appropriate object (cert, priv key, or
278 * pub key) in the cert store.
279 */
280 static PRUint32
collect_class(CK_OBJECT_CLASS objClass,LPCSTR storeStr,PRBool hasID,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,ckcapiInternalObject *** listp,PRUint32 * sizep,PRUint32 count,CK_RV * pError)281 collect_class(
282 CK_OBJECT_CLASS objClass,
283 LPCSTR storeStr,
284 PRBool hasID,
285 CK_ATTRIBUTE_PTR pTemplate,
286 CK_ULONG ulAttributeCount,
287 ckcapiInternalObject ***listp,
288 PRUint32 *sizep,
289 PRUint32 count,
290 CK_RV *pError)
291 {
292 PRUint32 size = *sizep;
293 ckcapiInternalObject *next = NULL;
294 HCERTSTORE hStore;
295 PCCERT_CONTEXT certContext = NULL;
296 PRBool isKey =
297 (objClass == CKO_PUBLIC_KEY) | (objClass == CKO_PRIVATE_KEY);
298
299 hStore = CertOpenSystemStore((HCRYPTPROV)NULL, storeStr);
300 if (NULL == hStore) {
301 return count; /* none found does not imply an error */
302 }
303
304 /* FUTURE: use CertFindCertificateInStore to filter better -- so we don't
305 * have to enumerate all the certificates */
306 while ((PCERT_CONTEXT)NULL !=
307 (certContext = CertEnumCertificatesInStore(hStore, certContext))) {
308 /* first filter out non user certs if we are looking for keys */
309 if (isKey) {
310 /* make sure there is a Key Provider Info property */
311 CRYPT_KEY_PROV_INFO *keyProvInfo;
312 DWORD size = 0;
313 BOOL rv;
314 rv = CertGetCertificateContextProperty(certContext,
315 CERT_KEY_PROV_INFO_PROP_ID, NULL, &size);
316 if (!rv) {
317 int reason = GetLastError();
318 /* we only care if it exists, we don't really need to fetch it yet */
319 if (reason == CRYPT_E_NOT_FOUND) {
320 continue;
321 }
322 }
323 /* filter out the non-microsoft providers */
324 keyProvInfo = (CRYPT_KEY_PROV_INFO *)nss_ZAlloc(NULL, size);
325 if (keyProvInfo) {
326 rv = CertGetCertificateContextProperty(certContext,
327 CERT_KEY_PROV_INFO_PROP_ID, keyProvInfo, &size);
328 if (rv) {
329 char *provName =
330 nss_ckcapi_WideToUTF8(keyProvInfo->pwszProvName);
331 nss_ZFreeIf(keyProvInfo);
332
333 if (provName &&
334 (strncmp(provName, "Microsoft", sizeof("Microsoft") - 1) != 0)) {
335 continue;
336 }
337 } else {
338 int reason =
339 GetLastError();
340 /* we only care if it exists, we don't really need to fetch it yet */
341 nss_ZFreeIf(keyProvInfo);
342 if (reason ==
343 CRYPT_E_NOT_FOUND) {
344 continue;
345 }
346 }
347 }
348 }
349
350 if ((ckcapiInternalObject *)NULL == next) {
351 next = nss_ZNEW(NULL, ckcapiInternalObject);
352 if ((ckcapiInternalObject *)NULL == next) {
353 *pError = CKR_HOST_MEMORY;
354 goto loser;
355 }
356 }
357 next->type = ckcapiCert;
358 next->objClass = objClass;
359 next->u.cert.certContext = certContext;
360 next->u.cert.hasID = hasID;
361 next->u.cert.certStore = storeStr;
362 if (CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, next)) {
363 /* clear cached values that may be dependent on our old certContext */
364 memset(&next->u.cert, 0, sizeof(next->u.cert));
365 /* get a 'permanent' context */
366 next->u.cert.certContext = CertDuplicateCertificateContext(certContext);
367 next->objClass = objClass;
368 next->u.cert.certContext = certContext;
369 next->u.cert.hasID = hasID;
370 next->u.cert.certStore = storeStr;
371 PUT_Object(next, *pError);
372 next = NULL; /* need to allocate a new one now */
373 } else {
374 /* don't cache the values we just loaded */
375 memset(&next->u.cert, 0, sizeof(next->u.cert));
376 }
377 }
378 loser:
379 CertCloseStore(hStore, 0);
380 nss_ZFreeIf(next);
381 *sizep = size;
382 return count;
383 }
384
385 NSS_IMPLEMENT PRUint32
nss_ckcapi_collect_all_certs(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,ckcapiInternalObject *** listp,PRUint32 * sizep,PRUint32 count,CK_RV * pError)386 nss_ckcapi_collect_all_certs(
387 CK_ATTRIBUTE_PTR pTemplate,
388 CK_ULONG ulAttributeCount,
389 ckcapiInternalObject ***listp,
390 PRUint32 *sizep,
391 PRUint32 count,
392 CK_RV *pError)
393 {
394 count = collect_class(CKO_CERTIFICATE, "My", PR_TRUE, pTemplate,
395 ulAttributeCount, listp, sizep, count, pError);
396 /*count = collect_class(CKO_CERTIFICATE, "AddressBook", PR_FALSE, pTemplate,
397 ulAttributeCount, listp, sizep, count, pError); */
398 count = collect_class(CKO_CERTIFICATE, "CA", PR_FALSE, pTemplate,
399 ulAttributeCount, listp, sizep, count, pError);
400 count = collect_class(CKO_CERTIFICATE, "Root", PR_FALSE, pTemplate,
401 ulAttributeCount, listp, sizep, count, pError);
402 count = collect_class(CKO_CERTIFICATE, "Trust", PR_FALSE, pTemplate,
403 ulAttributeCount, listp, sizep, count, pError);
404 count = collect_class(CKO_CERTIFICATE, "TrustedPeople", PR_FALSE, pTemplate,
405 ulAttributeCount, listp, sizep, count, pError);
406 count = collect_class(CKO_CERTIFICATE, "AuthRoot", PR_FALSE, pTemplate,
407 ulAttributeCount, listp, sizep, count, pError);
408 return count;
409 }
410
411 CK_OBJECT_CLASS
ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount)412 ckcapi_GetObjectClass(CK_ATTRIBUTE_PTR pTemplate,
413 CK_ULONG ulAttributeCount)
414 {
415 CK_ULONG i;
416
417 for (i = 0; i < ulAttributeCount; i++) {
418 if (pTemplate[i].type == CKA_CLASS) {
419 return *(CK_OBJECT_CLASS *)pTemplate[i].pValue;
420 }
421 }
422 /* need to return a value that says 'fetch them all' */
423 return CK_INVALID_HANDLE;
424 }
425
426 static PRUint32
collect_objects(CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,ckcapiInternalObject *** listp,CK_RV * pError)427 collect_objects(
428 CK_ATTRIBUTE_PTR pTemplate,
429 CK_ULONG ulAttributeCount,
430 ckcapiInternalObject ***listp,
431 CK_RV *pError)
432 {
433 PRUint32 i;
434 PRUint32 count = 0;
435 PRUint32 size = 0;
436 CK_OBJECT_CLASS objClass;
437
438 /*
439 * first handle the static build in objects (if any)
440 */
441 for (i = 0; i < nss_ckcapi_nObjects; i++) {
442 ckcapiInternalObject *o = (ckcapiInternalObject *)&nss_ckcapi_data[i];
443
444 if (CK_TRUE == ckcapi_match(pTemplate, ulAttributeCount, o)) {
445 PUT_Object(o, *pError);
446 }
447 }
448
449 /*
450 * now handle the various object types
451 */
452 objClass = ckcapi_GetObjectClass(pTemplate, ulAttributeCount);
453 *pError = CKR_OK;
454 switch (objClass) {
455 case CKO_CERTIFICATE:
456 count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp,
457 &size, count, pError);
458 break;
459 case CKO_PUBLIC_KEY:
460 count = collect_class(objClass, "My", PR_TRUE, pTemplate,
461 ulAttributeCount, listp, &size, count, pError);
462 count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
463 &size, count, pError);
464 break;
465 case CKO_PRIVATE_KEY:
466 count = collect_class(objClass, "My", PR_TRUE, pTemplate,
467 ulAttributeCount, listp, &size, count, pError);
468 count = collect_bare(objClass, pTemplate, ulAttributeCount, listp,
469 &size, count, pError);
470 break;
471 /* all of them */
472 case CK_INVALID_HANDLE:
473 count = nss_ckcapi_collect_all_certs(pTemplate, ulAttributeCount, listp,
474 &size, count, pError);
475 count = collect_class(CKO_PUBLIC_KEY, "My", PR_TRUE, pTemplate,
476 ulAttributeCount, listp, &size, count, pError);
477 count = collect_bare(CKO_PUBLIC_KEY, pTemplate, ulAttributeCount, listp,
478 &size, count, pError);
479 count = collect_class(CKO_PRIVATE_KEY, "My", PR_TRUE, pTemplate,
480 ulAttributeCount, listp, &size, count, pError);
481 count = collect_bare(CKO_PRIVATE_KEY, pTemplate, ulAttributeCount, listp,
482 &size, count, pError);
483 break;
484 default:
485 goto done; /* no other object types we understand in this module */
486 }
487 if (CKR_OK != *pError) {
488 goto loser;
489 }
490
491 done:
492 return count;
493 loser:
494 nss_ZFreeIf(*listp);
495 return 0;
496 }
497
498 NSS_IMPLEMENT NSSCKMDFindObjects *
nss_ckcapi_FindObjectsInit(NSSCKFWSession * fwSession,CK_ATTRIBUTE_PTR pTemplate,CK_ULONG ulAttributeCount,CK_RV * pError)499 nss_ckcapi_FindObjectsInit(
500 NSSCKFWSession *fwSession,
501 CK_ATTRIBUTE_PTR pTemplate,
502 CK_ULONG ulAttributeCount,
503 CK_RV *pError)
504 {
505 /* This could be made more efficient. I'm rather rushed. */
506 NSSArena *arena;
507 NSSCKMDFindObjects *rv = (NSSCKMDFindObjects *)NULL;
508 struct ckcapiFOStr *fo = (struct ckcapiFOStr *)NULL;
509 ckcapiInternalObject **temp = (ckcapiInternalObject **)NULL;
510
511 arena = NSSArena_Create();
512 if ((NSSArena *)NULL == arena) {
513 goto loser;
514 }
515
516 rv = nss_ZNEW(arena, NSSCKMDFindObjects);
517 if ((NSSCKMDFindObjects *)NULL == rv) {
518 *pError = CKR_HOST_MEMORY;
519 goto loser;
520 }
521
522 fo = nss_ZNEW(arena, struct ckcapiFOStr);
523 if ((struct ckcapiFOStr *)NULL == fo) {
524 *pError = CKR_HOST_MEMORY;
525 goto loser;
526 }
527
528 fo->arena = arena;
529 /* fo->n and fo->i are already zero */
530
531 rv->etc = (void *)fo;
532 rv->Final = ckcapi_mdFindObjects_Final;
533 rv->Next = ckcapi_mdFindObjects_Next;
534 rv->null = (void *)NULL;
535
536 fo->n = collect_objects(pTemplate, ulAttributeCount, &temp, pError);
537 if (*pError != CKR_OK) {
538 goto loser;
539 }
540
541 fo->objs = nss_ZNEWARRAY(arena, ckcapiInternalObject *, fo->n);
542 if ((ckcapiInternalObject **)NULL == fo->objs) {
543 *pError = CKR_HOST_MEMORY;
544 goto loser;
545 }
546
547 (void)nsslibc_memcpy(fo->objs, temp, sizeof(ckcapiInternalObject *) * fo->n);
548 nss_ZFreeIf(temp);
549 temp = (ckcapiInternalObject **)NULL;
550
551 return rv;
552
553 loser:
554 nss_ZFreeIf(temp);
555 nss_ZFreeIf(fo);
556 nss_ZFreeIf(rv);
557 if ((NSSArena *)NULL != arena) {
558 NSSArena_Destroy(arena);
559 }
560 return (NSSCKMDFindObjects *)NULL;
561 }
562