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 DEVM_H
6 #include "devm.h"
7 #endif /* DEVM_H */
8
9 #ifndef CKHELPER_H
10 #include "ckhelper.h"
11 #endif /* CKHELPER_H */
12
13 NSS_IMPLEMENT nssCryptokiObject *
nssCryptokiObject_Create(NSSToken * t,nssSession * session,CK_OBJECT_HANDLE h)14 nssCryptokiObject_Create(
15 NSSToken *t,
16 nssSession *session,
17 CK_OBJECT_HANDLE h)
18 {
19 PRStatus status;
20 NSSSlot *slot;
21 nssCryptokiObject *object;
22 CK_BBOOL *isTokenObject;
23 CK_ATTRIBUTE cert_template[] = {
24 { CKA_TOKEN, NULL, 0 },
25 { CKA_LABEL, NULL, 0 }
26 };
27 slot = nssToken_GetSlot(t);
28 status = nssCKObject_GetAttributes(h, cert_template, 2,
29 NULL, session, slot);
30 nssSlot_Destroy(slot);
31 if (status != PR_SUCCESS) {
32 /* a failure here indicates a device error */
33 return (nssCryptokiObject *)NULL;
34 }
35 if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) {
36 nss_ZFreeIf(cert_template[1].pValue);
37 return (nssCryptokiObject *)NULL;
38 }
39 object = nss_ZNEW(NULL, nssCryptokiObject);
40 if (!object) {
41 nss_ZFreeIf(cert_template[0].pValue);
42 nss_ZFreeIf(cert_template[1].pValue);
43 return (nssCryptokiObject *)NULL;
44 }
45 object->handle = h;
46 object->token = nssToken_AddRef(t);
47 isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
48 object->isTokenObject = *isTokenObject;
49 nss_ZFreeIf(cert_template[0].pValue);
50 NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
51 return object;
52 }
53
54 NSS_IMPLEMENT void
nssCryptokiObject_Destroy(nssCryptokiObject * object)55 nssCryptokiObject_Destroy(
56 nssCryptokiObject *object)
57 {
58 if (object) {
59 nssToken_Destroy(object->token);
60 nss_ZFreeIf(object->label);
61 nss_ZFreeIf(object);
62 }
63 }
64
65 NSS_IMPLEMENT nssCryptokiObject *
nssCryptokiObject_Clone(nssCryptokiObject * object)66 nssCryptokiObject_Clone(
67 nssCryptokiObject *object)
68 {
69 nssCryptokiObject *rvObject;
70 rvObject = nss_ZNEW(NULL, nssCryptokiObject);
71 if (rvObject) {
72 rvObject->handle = object->handle;
73 rvObject->token = nssToken_AddRef(object->token);
74 rvObject->isTokenObject = object->isTokenObject;
75 if (object->label) {
76 rvObject->label = nssUTF8_Duplicate(object->label, NULL);
77 }
78 }
79 return rvObject;
80 }
81
82 NSS_EXTERN PRBool
nssCryptokiObject_Equal(nssCryptokiObject * o1,nssCryptokiObject * o2)83 nssCryptokiObject_Equal(
84 nssCryptokiObject *o1,
85 nssCryptokiObject *o2)
86 {
87 return (o1->token == o2->token && o1->handle == o2->handle);
88 }
89
90 NSS_IMPLEMENT PRUint32
nssPKCS11String_Length(CK_CHAR * pkcs11Str,PRUint32 bufLen)91 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
92 {
93 PRInt32 i;
94 for (i = bufLen - 1; i >= 0;) {
95 if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0')
96 break;
97 --i;
98 }
99 return (PRUint32)(i + 1);
100 }
101
102 /*
103 * Slot arrays
104 */
105
106 NSS_IMPLEMENT NSSSlot **
nssSlotArray_Clone(NSSSlot ** slots)107 nssSlotArray_Clone(
108 NSSSlot **slots)
109 {
110 NSSSlot **rvSlots = NULL;
111 NSSSlot **sp = slots;
112 PRUint32 count = 0;
113 while (sp && *sp)
114 count++;
115 if (count > 0) {
116 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
117 if (rvSlots) {
118 for (sp = slots, count = 0; *sp; sp++) {
119 rvSlots[count++] = nssSlot_AddRef(*sp);
120 }
121 }
122 }
123 return rvSlots;
124 }
125
126 NSS_IMPLEMENT void
nssSlotArray_Destroy(NSSSlot ** slots)127 nssSlotArray_Destroy(
128 NSSSlot **slots)
129 {
130 if (slots) {
131 NSSSlot **slotp;
132 for (slotp = slots; *slotp; slotp++) {
133 nssSlot_Destroy(*slotp);
134 }
135 nss_ZFreeIf(slots);
136 }
137 }
138
139 NSS_IMPLEMENT void
NSSSlotArray_Destroy(NSSSlot ** slots)140 NSSSlotArray_Destroy(
141 NSSSlot **slots)
142 {
143 nssSlotArray_Destroy(slots);
144 }
145
146 NSS_IMPLEMENT void
nssTokenArray_Destroy(NSSToken ** tokens)147 nssTokenArray_Destroy(
148 NSSToken **tokens)
149 {
150 if (tokens) {
151 NSSToken **tokenp;
152 for (tokenp = tokens; *tokenp; tokenp++) {
153 nssToken_Destroy(*tokenp);
154 }
155 nss_ZFreeIf(tokens);
156 }
157 }
158
159 NSS_IMPLEMENT void
NSSTokenArray_Destroy(NSSToken ** tokens)160 NSSTokenArray_Destroy(
161 NSSToken **tokens)
162 {
163 nssTokenArray_Destroy(tokens);
164 }
165
166 NSS_IMPLEMENT void
nssCryptokiObjectArray_Destroy(nssCryptokiObject ** objects)167 nssCryptokiObjectArray_Destroy(
168 nssCryptokiObject **objects)
169 {
170 if (objects) {
171 nssCryptokiObject **op;
172 for (op = objects; *op; op++) {
173 nssCryptokiObject_Destroy(*op);
174 }
175 nss_ZFreeIf(objects);
176 }
177 }
178
179 /* object cache for token */
180
181 typedef struct
182 {
183 NSSArena *arena;
184 nssCryptokiObject *object;
185 CK_ATTRIBUTE_PTR attributes;
186 CK_ULONG numAttributes;
187 } nssCryptokiObjectAndAttributes;
188
189 enum {
190 cachedCerts = 0,
191 cachedTrust = 1,
192 cachedCRLs = 2
193 } cachedObjectType;
194
195 struct nssTokenObjectCacheStr {
196 NSSToken *token;
197 PZLock *lock;
198 PRBool loggedIn;
199 PRBool doObjectType[3];
200 PRBool searchedObjectType[3];
201 nssCryptokiObjectAndAttributes **objects[3];
202 };
203
204 NSS_IMPLEMENT nssTokenObjectCache *
nssTokenObjectCache_Create(NSSToken * token,PRBool cacheCerts,PRBool cacheTrust,PRBool cacheCRLs)205 nssTokenObjectCache_Create(
206 NSSToken *token,
207 PRBool cacheCerts,
208 PRBool cacheTrust,
209 PRBool cacheCRLs)
210 {
211 nssTokenObjectCache *rvCache;
212 rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
213 if (!rvCache) {
214 goto loser;
215 }
216 rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
217 if (!rvCache->lock) {
218 goto loser;
219 }
220 rvCache->doObjectType[cachedCerts] = cacheCerts;
221 rvCache->doObjectType[cachedTrust] = cacheTrust;
222 rvCache->doObjectType[cachedCRLs] = cacheCRLs;
223 rvCache->token = token; /* cache goes away with token */
224 return rvCache;
225 loser:
226 nssTokenObjectCache_Destroy(rvCache);
227 return (nssTokenObjectCache *)NULL;
228 }
229
230 static void
clear_cache(nssTokenObjectCache * cache)231 clear_cache(
232 nssTokenObjectCache *cache)
233 {
234 nssCryptokiObjectAndAttributes **oa;
235 PRUint32 objectType;
236 for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
237 cache->searchedObjectType[objectType] = PR_FALSE;
238 if (!cache->objects[objectType]) {
239 continue;
240 }
241 for (oa = cache->objects[objectType]; *oa; oa++) {
242 /* prevent the token from being destroyed */
243 (*oa)->object->token = NULL;
244 nssCryptokiObject_Destroy((*oa)->object);
245 nssArena_Destroy((*oa)->arena);
246 }
247 nss_ZFreeIf(cache->objects[objectType]);
248 cache->objects[objectType] = NULL;
249 }
250 }
251
252 NSS_IMPLEMENT void
nssTokenObjectCache_Clear(nssTokenObjectCache * cache)253 nssTokenObjectCache_Clear(
254 nssTokenObjectCache *cache)
255 {
256 if (cache) {
257 PZ_Lock(cache->lock);
258 clear_cache(cache);
259 PZ_Unlock(cache->lock);
260 }
261 }
262
263 NSS_IMPLEMENT void
nssTokenObjectCache_Destroy(nssTokenObjectCache * cache)264 nssTokenObjectCache_Destroy(
265 nssTokenObjectCache *cache)
266 {
267 if (cache) {
268 clear_cache(cache);
269 if (cache->lock) {
270 PZ_DestroyLock(cache->lock);
271 }
272 nss_ZFreeIf(cache);
273 }
274 }
275
276 NSS_IMPLEMENT PRBool
nssTokenObjectCache_HaveObjectClass(nssTokenObjectCache * cache,CK_OBJECT_CLASS objclass)277 nssTokenObjectCache_HaveObjectClass(
278 nssTokenObjectCache *cache,
279 CK_OBJECT_CLASS objclass)
280 {
281 PRBool haveIt;
282 PZ_Lock(cache->lock);
283 switch (objclass) {
284 case CKO_CERTIFICATE:
285 haveIt = cache->doObjectType[cachedCerts];
286 break;
287 case CKO_NSS_TRUST:
288 haveIt = cache->doObjectType[cachedTrust];
289 break;
290 case CKO_NSS_CRL:
291 haveIt = cache->doObjectType[cachedCRLs];
292 break;
293 default:
294 haveIt = PR_FALSE;
295 }
296 PZ_Unlock(cache->lock);
297 return haveIt;
298 }
299
300 static nssCryptokiObjectAndAttributes **
create_object_array(nssCryptokiObject ** objects,PRBool * doObjects,PRUint32 * numObjects,PRStatus * status)301 create_object_array(
302 nssCryptokiObject **objects,
303 PRBool *doObjects,
304 PRUint32 *numObjects,
305 PRStatus *status)
306 {
307 nssCryptokiObjectAndAttributes **rvOandA = NULL;
308 *numObjects = 0;
309 /* There are no objects for this type */
310 if (!objects || !*objects) {
311 *status = PR_SUCCESS;
312 return rvOandA;
313 }
314 while (*objects++)
315 (*numObjects)++;
316 if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
317 /* Hit the maximum allowed, so don't use a cache (there are
318 * too many objects to make caching worthwhile, presumably, if
319 * the token can handle that many objects, it can handle searching.
320 */
321 *doObjects = PR_FALSE;
322 *status = PR_FAILURE;
323 *numObjects = 0;
324 } else {
325 rvOandA = nss_ZNEWARRAY(NULL,
326 nssCryptokiObjectAndAttributes *,
327 *numObjects + 1);
328 *status = rvOandA ? PR_SUCCESS : PR_FAILURE;
329 }
330 return rvOandA;
331 }
332
333 static nssCryptokiObjectAndAttributes *
create_object(nssCryptokiObject * object,const CK_ATTRIBUTE_TYPE * types,PRUint32 numTypes,PRStatus * status)334 create_object(
335 nssCryptokiObject *object,
336 const CK_ATTRIBUTE_TYPE *types,
337 PRUint32 numTypes,
338 PRStatus *status)
339 {
340 PRUint32 j;
341 NSSArena *arena = NULL;
342 NSSSlot *slot = NULL;
343 nssSession *session = NULL;
344 nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
345
346 slot = nssToken_GetSlot(object->token);
347 if (!slot) {
348 nss_SetError(NSS_ERROR_INVALID_POINTER);
349 goto loser;
350 }
351 session = nssToken_GetDefaultSession(object->token);
352 if (!session) {
353 nss_SetError(NSS_ERROR_INVALID_POINTER);
354 goto loser;
355 }
356 arena = nssArena_Create();
357 if (!arena) {
358 goto loser;
359 }
360 rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
361 if (!rvCachedObject) {
362 goto loser;
363 }
364 rvCachedObject->arena = arena;
365 /* The cache is tied to the token, and therefore the objects
366 * in it should not hold references to the token.
367 */
368 nssToken_Destroy(object->token);
369 rvCachedObject->object = object;
370 rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
371 if (!rvCachedObject->attributes) {
372 goto loser;
373 }
374 for (j = 0; j < numTypes; j++) {
375 rvCachedObject->attributes[j].type = types[j];
376 }
377 *status = nssCKObject_GetAttributes(object->handle,
378 rvCachedObject->attributes,
379 numTypes,
380 arena,
381 session,
382 slot);
383 if (*status != PR_SUCCESS) {
384 goto loser;
385 }
386 rvCachedObject->numAttributes = numTypes;
387 *status = PR_SUCCESS;
388 nssSlot_Destroy(slot);
389
390 return rvCachedObject;
391 loser:
392 *status = PR_FAILURE;
393 if (slot) {
394 nssSlot_Destroy(slot);
395 }
396 if (arena)
397 nssArena_Destroy(arena);
398 return (nssCryptokiObjectAndAttributes *)NULL;
399 }
400
401 /*
402 *
403 * State diagram for cache:
404 *
405 * token !present token removed
406 * +-------------------------+<----------------------+
407 * | ^ |
408 * v | |
409 * +----------+ slot friendly | token present +----------+
410 * | cache | -----------------> % ---------------> | cache |
411 * | unloaded | | loaded |
412 * +----------+ +----------+
413 * ^ | ^ |
414 * | | slot !friendly slot logged in | |
415 * | +-----------------------> % ----------------------+ |
416 * | | |
417 * | slot logged out v slot !friendly |
418 * +-----------------------------+<--------------------------+
419 *
420 */
421
422 /* This function must not be called with cache->lock locked. */
423 static PRBool
token_is_present(nssTokenObjectCache * cache)424 token_is_present(
425 nssTokenObjectCache *cache)
426 {
427 NSSSlot *slot = nssToken_GetSlot(cache->token);
428 PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
429 nssSlot_Destroy(slot);
430 return tokenPresent;
431 }
432
433 static PRBool
search_for_objects(nssTokenObjectCache * cache)434 search_for_objects(
435 nssTokenObjectCache *cache)
436 {
437 PRBool doSearch = PR_FALSE;
438 NSSSlot *slot = nssToken_GetSlot(cache->token);
439 /* Handle non-friendly slots (slots which require login for objects) */
440 if (!nssSlot_IsFriendly(slot)) {
441 if (nssSlot_IsLoggedIn(slot)) {
442 /* Either no state change, or went from !logged in -> logged in */
443 cache->loggedIn = PR_TRUE;
444 doSearch = PR_TRUE;
445 } else {
446 if (cache->loggedIn) {
447 /* went from logged in -> !logged in, destroy cached objects */
448 clear_cache(cache);
449 cache->loggedIn = PR_FALSE;
450 } /* else no state change, still not logged in, so exit */
451 }
452 } else {
453 /* slot is friendly, thus always available for search */
454 doSearch = PR_TRUE;
455 }
456 nssSlot_Destroy(slot);
457 return doSearch;
458 }
459
460 static nssCryptokiObjectAndAttributes *
create_cert(nssCryptokiObject * object,PRStatus * status)461 create_cert(
462 nssCryptokiObject *object,
463 PRStatus *status)
464 {
465 static const CK_ATTRIBUTE_TYPE certAttr[] = {
466 CKA_CLASS,
467 CKA_TOKEN,
468 CKA_LABEL,
469 CKA_CERTIFICATE_TYPE,
470 CKA_ID,
471 CKA_VALUE,
472 CKA_ISSUER,
473 CKA_SERIAL_NUMBER,
474 CKA_SUBJECT,
475 CKA_NSS_EMAIL
476 };
477 static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
478 return create_object(object, certAttr, numCertAttr, status);
479 }
480
481 static nssCryptokiObjectAndAttributes *
create_trust(nssCryptokiObject * object,PRStatus * status)482 create_trust(
483 nssCryptokiObject *object,
484 PRStatus *status)
485 {
486 static const CK_ATTRIBUTE_TYPE trustAttr[] = {
487 CKA_CLASS,
488 CKA_TOKEN,
489 CKA_LABEL,
490 CKA_CERT_SHA1_HASH,
491 CKA_CERT_MD5_HASH,
492 CKA_ISSUER,
493 CKA_SUBJECT,
494 CKA_TRUST_SERVER_AUTH,
495 CKA_TRUST_CLIENT_AUTH,
496 CKA_TRUST_EMAIL_PROTECTION,
497 CKA_TRUST_CODE_SIGNING
498 };
499 static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
500 return create_object(object, trustAttr, numTrustAttr, status);
501 }
502
503 static nssCryptokiObjectAndAttributes *
create_crl(nssCryptokiObject * object,PRStatus * status)504 create_crl(
505 nssCryptokiObject *object,
506 PRStatus *status)
507 {
508 static const CK_ATTRIBUTE_TYPE crlAttr[] = {
509 CKA_CLASS,
510 CKA_TOKEN,
511 CKA_LABEL,
512 CKA_VALUE,
513 CKA_SUBJECT,
514 CKA_NSS_KRL,
515 CKA_NSS_URL
516 };
517 static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
518 return create_object(object, crlAttr, numCRLAttr, status);
519 }
520
521 /* Dispatch to the create function for the object type */
522 static nssCryptokiObjectAndAttributes *
create_object_of_type(nssCryptokiObject * object,PRUint32 objectType,PRStatus * status)523 create_object_of_type(
524 nssCryptokiObject *object,
525 PRUint32 objectType,
526 PRStatus *status)
527 {
528 if (objectType == cachedCerts) {
529 return create_cert(object, status);
530 }
531 if (objectType == cachedTrust) {
532 return create_trust(object, status);
533 }
534 if (objectType == cachedCRLs) {
535 return create_crl(object, status);
536 }
537 return (nssCryptokiObjectAndAttributes *)NULL;
538 }
539
540 static PRStatus
get_token_objects_for_cache(nssTokenObjectCache * cache,PRUint32 objectType,CK_OBJECT_CLASS objclass)541 get_token_objects_for_cache(
542 nssTokenObjectCache *cache,
543 PRUint32 objectType,
544 CK_OBJECT_CLASS objclass)
545 {
546 PRStatus status;
547 nssCryptokiObject **objects;
548 PRBool *doIt = &cache->doObjectType[objectType];
549 PRUint32 i, numObjects;
550
551 if (!search_for_objects(cache) ||
552 cache->searchedObjectType[objectType] ||
553 !cache->doObjectType[objectType]) {
554 /* Either there was a state change that prevents a search
555 * (token logged out), or the search was already done,
556 * or objects of this type are not being cached.
557 */
558 return PR_SUCCESS;
559 }
560 objects = nssToken_FindObjects(cache->token, NULL, objclass,
561 nssTokenSearchType_TokenForced,
562 MAX_LOCAL_CACHE_OBJECTS, &status);
563 if (status != PR_SUCCESS) {
564 return status;
565 }
566 cache->objects[objectType] = create_object_array(objects,
567 doIt,
568 &numObjects,
569 &status);
570 if (status != PR_SUCCESS) {
571 nss_ZFreeIf(objects);
572 return status;
573 }
574 for (i = 0; i < numObjects; i++) {
575 cache->objects[objectType][i] = create_object_of_type(objects[i],
576 objectType,
577 &status);
578 if (status != PR_SUCCESS) {
579 break;
580 }
581 }
582 if (status == PR_SUCCESS) {
583 nss_ZFreeIf(objects);
584 } else {
585 PRUint32 j;
586 for (j = 0; j < i; j++) {
587 /* sigh */
588 nssToken_AddRef(cache->objects[objectType][j]->object->token);
589 nssArena_Destroy(cache->objects[objectType][j]->arena);
590 }
591 nss_ZFreeIf(cache->objects[objectType]);
592 cache->objects[objectType] = NULL;
593 nssCryptokiObjectArray_Destroy(objects);
594 }
595 cache->searchedObjectType[objectType] = PR_TRUE;
596 return status;
597 }
598
599 static CK_ATTRIBUTE_PTR
find_attribute_in_object(nssCryptokiObjectAndAttributes * obj,CK_ATTRIBUTE_TYPE attrType)600 find_attribute_in_object(
601 nssCryptokiObjectAndAttributes *obj,
602 CK_ATTRIBUTE_TYPE attrType)
603 {
604 PRUint32 j;
605 for (j = 0; j < obj->numAttributes; j++) {
606 if (attrType == obj->attributes[j].type) {
607 return &obj->attributes[j];
608 }
609 }
610 return (CK_ATTRIBUTE_PTR)NULL;
611 }
612
613 /* Find all objects in the array that match the supplied template */
614 static nssCryptokiObject **
find_objects_in_array(nssCryptokiObjectAndAttributes ** objArray,CK_ATTRIBUTE_PTR ot,CK_ULONG otlen,PRUint32 maximumOpt)615 find_objects_in_array(
616 nssCryptokiObjectAndAttributes **objArray,
617 CK_ATTRIBUTE_PTR ot,
618 CK_ULONG otlen,
619 PRUint32 maximumOpt)
620 {
621 PRIntn oi = 0;
622 PRUint32 i;
623 NSSArena *arena;
624 PRUint32 size = 8;
625 PRUint32 numMatches = 0;
626 nssCryptokiObject **objects = NULL;
627 nssCryptokiObjectAndAttributes **matches = NULL;
628 CK_ATTRIBUTE_PTR attr;
629
630 if (!objArray) {
631 return (nssCryptokiObject **)NULL;
632 }
633 arena = nssArena_Create();
634 if (!arena) {
635 return (nssCryptokiObject **)NULL;
636 }
637 matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
638 if (!matches) {
639 goto loser;
640 }
641 if (maximumOpt == 0)
642 maximumOpt = ~0;
643 /* loop over the cached objects */
644 for (; *objArray && numMatches < maximumOpt; objArray++) {
645 nssCryptokiObjectAndAttributes *obj = *objArray;
646 /* loop over the test template */
647 for (i = 0; i < otlen; i++) {
648 /* see if the object has the attribute */
649 attr = find_attribute_in_object(obj, ot[i].type);
650 if (!attr) {
651 /* nope, match failed */
652 break;
653 }
654 /* compare the attribute against the test value */
655 if (ot[i].ulValueLen != attr->ulValueLen ||
656 !nsslibc_memequal(ot[i].pValue,
657 attr->pValue,
658 attr->ulValueLen, NULL)) {
659 /* nope, match failed */
660 break;
661 }
662 }
663 if (i == otlen) {
664 /* all of the attributes in the test template were found
665 * in the object's template, and they all matched
666 */
667 matches[numMatches++] = obj;
668 if (numMatches == size) {
669 size *= 2;
670 matches = nss_ZREALLOCARRAY(matches,
671 nssCryptokiObjectAndAttributes *,
672 size);
673 if (!matches) {
674 goto loser;
675 }
676 }
677 }
678 }
679 if (numMatches > 0) {
680 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
681 if (!objects) {
682 goto loser;
683 }
684 for (oi = 0; oi < (PRIntn)numMatches; oi++) {
685 objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
686 if (!objects[oi]) {
687 goto loser;
688 }
689 }
690 }
691 nssArena_Destroy(arena);
692 return objects;
693 loser:
694 nssCryptokiObjectArray_Destroy(objects);
695 nssArena_Destroy(arena);
696 return (nssCryptokiObject **)NULL;
697 }
698
699 NSS_IMPLEMENT nssCryptokiObject **
nssTokenObjectCache_FindObjectsByTemplate(nssTokenObjectCache * cache,CK_OBJECT_CLASS objclass,CK_ATTRIBUTE_PTR otemplate,CK_ULONG otlen,PRUint32 maximumOpt,PRStatus * statusOpt)700 nssTokenObjectCache_FindObjectsByTemplate(
701 nssTokenObjectCache *cache,
702 CK_OBJECT_CLASS objclass,
703 CK_ATTRIBUTE_PTR otemplate,
704 CK_ULONG otlen,
705 PRUint32 maximumOpt,
706 PRStatus *statusOpt)
707 {
708 PRStatus status = PR_FAILURE;
709 nssCryptokiObject **rvObjects = NULL;
710 PRUint32 objectType;
711 if (!token_is_present(cache)) {
712 status = PR_SUCCESS;
713 goto finish;
714 }
715 switch (objclass) {
716 case CKO_CERTIFICATE:
717 objectType = cachedCerts;
718 break;
719 case CKO_NSS_TRUST:
720 objectType = cachedTrust;
721 break;
722 case CKO_NSS_CRL:
723 objectType = cachedCRLs;
724 break;
725 default:
726 goto finish;
727 }
728 PZ_Lock(cache->lock);
729 if (cache->doObjectType[objectType]) {
730 status = get_token_objects_for_cache(cache, objectType, objclass);
731 if (status == PR_SUCCESS) {
732 rvObjects = find_objects_in_array(cache->objects[objectType],
733 otemplate, otlen, maximumOpt);
734 }
735 }
736 PZ_Unlock(cache->lock);
737 finish:
738 if (statusOpt) {
739 *statusOpt = status;
740 }
741 return rvObjects;
742 }
743
744 static PRBool
cache_available_for_object_type(nssTokenObjectCache * cache,PRUint32 objectType)745 cache_available_for_object_type(
746 nssTokenObjectCache *cache,
747 PRUint32 objectType)
748 {
749 if (!cache->doObjectType[objectType]) {
750 /* not caching this object kind */
751 return PR_FALSE;
752 }
753 if (!cache->searchedObjectType[objectType]) {
754 /* objects are not cached yet */
755 return PR_FALSE;
756 }
757 if (!search_for_objects(cache)) {
758 /* not logged in */
759 return PR_FALSE;
760 }
761 return PR_TRUE;
762 }
763
764 NSS_IMPLEMENT PRStatus
nssTokenObjectCache_GetObjectAttributes(nssTokenObjectCache * cache,NSSArena * arenaOpt,nssCryptokiObject * object,CK_OBJECT_CLASS objclass,CK_ATTRIBUTE_PTR atemplate,CK_ULONG atlen)765 nssTokenObjectCache_GetObjectAttributes(
766 nssTokenObjectCache *cache,
767 NSSArena *arenaOpt,
768 nssCryptokiObject *object,
769 CK_OBJECT_CLASS objclass,
770 CK_ATTRIBUTE_PTR atemplate,
771 CK_ULONG atlen)
772 {
773 PRUint32 i, j;
774 NSSArena *arena = NULL;
775 nssArenaMark *mark = NULL;
776 nssCryptokiObjectAndAttributes *cachedOA = NULL;
777 nssCryptokiObjectAndAttributes **oa = NULL;
778 PRUint32 objectType;
779 if (!token_is_present(cache)) {
780 return PR_FAILURE;
781 }
782 PZ_Lock(cache->lock);
783 switch (objclass) {
784 case CKO_CERTIFICATE:
785 objectType = cachedCerts;
786 break;
787 case CKO_NSS_TRUST:
788 objectType = cachedTrust;
789 break;
790 case CKO_NSS_CRL:
791 objectType = cachedCRLs;
792 break;
793 default:
794 goto loser;
795 }
796 if (!cache_available_for_object_type(cache, objectType)) {
797 goto loser;
798 }
799 oa = cache->objects[objectType];
800 if (!oa) {
801 goto loser;
802 }
803 for (; *oa; oa++) {
804 if (nssCryptokiObject_Equal((*oa)->object, object)) {
805 cachedOA = *oa;
806 break;
807 }
808 }
809 if (!cachedOA) {
810 goto loser; /* don't have this object */
811 }
812 if (arenaOpt) {
813 arena = arenaOpt;
814 mark = nssArena_Mark(arena);
815 }
816 for (i = 0; i < atlen; i++) {
817 for (j = 0; j < cachedOA->numAttributes; j++) {
818 if (atemplate[i].type == cachedOA->attributes[j].type) {
819 CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
820 if (cachedOA->attributes[j].ulValueLen == 0 ||
821 cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1) {
822 break; /* invalid attribute */
823 }
824 if (atemplate[i].ulValueLen > 0) {
825 if (atemplate[i].pValue == NULL ||
826 atemplate[i].ulValueLen < attr->ulValueLen) {
827 goto loser;
828 }
829 } else {
830 atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
831 if (!atemplate[i].pValue) {
832 goto loser;
833 }
834 }
835 nsslibc_memcpy(atemplate[i].pValue,
836 attr->pValue, attr->ulValueLen);
837 atemplate[i].ulValueLen = attr->ulValueLen;
838 break;
839 }
840 }
841 if (j == cachedOA->numAttributes) {
842 atemplate[i].ulValueLen = (CK_ULONG)-1;
843 }
844 }
845 PZ_Unlock(cache->lock);
846 if (mark) {
847 nssArena_Unmark(arena, mark);
848 }
849 return PR_SUCCESS;
850 loser:
851 PZ_Unlock(cache->lock);
852 if (mark) {
853 nssArena_Release(arena, mark);
854 }
855 return PR_FAILURE;
856 }
857
858 NSS_IMPLEMENT PRStatus
nssTokenObjectCache_ImportObject(nssTokenObjectCache * cache,nssCryptokiObject * object,CK_OBJECT_CLASS objclass,CK_ATTRIBUTE_PTR ot,CK_ULONG otlen)859 nssTokenObjectCache_ImportObject(
860 nssTokenObjectCache *cache,
861 nssCryptokiObject *object,
862 CK_OBJECT_CLASS objclass,
863 CK_ATTRIBUTE_PTR ot,
864 CK_ULONG otlen)
865 {
866 PRStatus status = PR_SUCCESS;
867 PRUint32 count;
868 nssCryptokiObjectAndAttributes **oa, ***otype;
869 PRUint32 objectType;
870 PRBool haveIt = PR_FALSE;
871
872 if (!token_is_present(cache)) {
873 return PR_SUCCESS; /* cache not active, ignored */
874 }
875 PZ_Lock(cache->lock);
876 switch (objclass) {
877 case CKO_CERTIFICATE:
878 objectType = cachedCerts;
879 break;
880 case CKO_NSS_TRUST:
881 objectType = cachedTrust;
882 break;
883 case CKO_NSS_CRL:
884 objectType = cachedCRLs;
885 break;
886 default:
887 PZ_Unlock(cache->lock);
888 return PR_SUCCESS; /* don't need to import it here */
889 }
890 if (!cache_available_for_object_type(cache, objectType)) {
891 PZ_Unlock(cache->lock);
892 return PR_SUCCESS; /* cache not active, ignored */
893 }
894 count = 0;
895 otype = &cache->objects[objectType]; /* index into array of types */
896 oa = *otype; /* the array of objects for this type */
897 while (oa && *oa) {
898 if (nssCryptokiObject_Equal((*oa)->object, object)) {
899 haveIt = PR_TRUE;
900 break;
901 }
902 count++;
903 oa++;
904 }
905 if (haveIt) {
906 /* Destroy the old entry */
907 (*oa)->object->token = NULL;
908 nssCryptokiObject_Destroy((*oa)->object);
909 nssArena_Destroy((*oa)->arena);
910 } else {
911 /* Create space for a new entry */
912 if (count > 0) {
913 *otype = nss_ZREALLOCARRAY(*otype,
914 nssCryptokiObjectAndAttributes *,
915 count + 2);
916 } else {
917 *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
918 }
919 }
920 if (*otype) {
921 nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
922 (*otype)[count] = create_object_of_type(copyObject, objectType,
923 &status);
924 } else {
925 status = PR_FAILURE;
926 }
927 PZ_Unlock(cache->lock);
928 return status;
929 }
930
931 NSS_IMPLEMENT void
nssTokenObjectCache_RemoveObject(nssTokenObjectCache * cache,nssCryptokiObject * object)932 nssTokenObjectCache_RemoveObject(
933 nssTokenObjectCache *cache,
934 nssCryptokiObject *object)
935 {
936 PRUint32 oType;
937 nssCryptokiObjectAndAttributes **oa, **swp = NULL;
938 if (!token_is_present(cache)) {
939 return;
940 }
941 PZ_Lock(cache->lock);
942 for (oType = 0; oType < 3; oType++) {
943 if (!cache_available_for_object_type(cache, oType) ||
944 !cache->objects[oType]) {
945 continue;
946 }
947 for (oa = cache->objects[oType]; *oa; oa++) {
948 if (nssCryptokiObject_Equal((*oa)->object, object)) {
949 swp = oa; /* the entry to remove */
950 while (oa[1])
951 oa++; /* go to the tail */
952 (*swp)->object->token = NULL;
953 nssCryptokiObject_Destroy((*swp)->object);
954 nssArena_Destroy((*swp)->arena); /* destroy it */
955 *swp = *oa; /* swap the last with the removed */
956 *oa = NULL; /* null-terminate the array */
957 break;
958 }
959 }
960 if (swp) {
961 break;
962 }
963 }
964 if ((oType < 3) &&
965 cache->objects[oType] && cache->objects[oType][0] == NULL) {
966 nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
967 cache->objects[oType] = NULL;
968 }
969 PZ_Unlock(cache->lock);
970 }
971
972 /* These two hash algorithms are presently sufficient.
973 ** They are used for fingerprints of certs which are stored as the
974 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
975 ** We don't need to add SHAxxx to these now.
976 */
977 /* XXX of course this doesn't belong here */
978 NSS_IMPLEMENT NSSAlgorithmAndParameters *
NSSAlgorithmAndParameters_CreateSHA1Digest(NSSArena * arenaOpt)979 NSSAlgorithmAndParameters_CreateSHA1Digest(
980 NSSArena *arenaOpt)
981 {
982 NSSAlgorithmAndParameters *rvAP = NULL;
983 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
984 if (rvAP) {
985 rvAP->mechanism.mechanism = CKM_SHA_1;
986 rvAP->mechanism.pParameter = NULL;
987 rvAP->mechanism.ulParameterLen = 0;
988 }
989 return rvAP;
990 }
991
992 NSS_IMPLEMENT NSSAlgorithmAndParameters *
NSSAlgorithmAndParameters_CreateMD5Digest(NSSArena * arenaOpt)993 NSSAlgorithmAndParameters_CreateMD5Digest(
994 NSSArena *arenaOpt)
995 {
996 NSSAlgorithmAndParameters *rvAP = NULL;
997 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
998 if (rvAP) {
999 rvAP->mechanism.mechanism = CKM_MD5;
1000 rvAP->mechanism.pParameter = NULL;
1001 rvAP->mechanism.ulParameterLen = 0;
1002 }
1003 return rvAP;
1004 }
1005