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