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