Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / dev / devutil.c
blobd662b403815cf9bd4b0b592a995f76d14b7d4443
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: devutil.c,v $ $Revision: 1.28 $ $Date: 2006/10/31 00:21:24 $";
39 #endif /* DEBUG */
41 #ifndef DEVM_H
42 #include "devm.h"
43 #endif /* DEVM_H */
45 #ifndef CKHELPER_H
46 #include "ckhelper.h"
47 #endif /* CKHELPER_H */
49 NSS_IMPLEMENT nssCryptokiObject *
50 nssCryptokiObject_Create (
51 NSSToken *t,
52 nssSession *session,
53 CK_OBJECT_HANDLE h
56 PRStatus status;
57 NSSSlot *slot;
58 nssCryptokiObject *object;
59 CK_BBOOL *isTokenObject;
60 CK_ATTRIBUTE cert_template[] = {
61 { CKA_TOKEN, NULL, 0 },
62 { CKA_LABEL, NULL, 0 }
64 slot = nssToken_GetSlot(t);
65 status = nssCKObject_GetAttributes(h, cert_template, 2,
66 NULL, session, slot);
67 nssSlot_Destroy(slot);
68 if (status != PR_SUCCESS) {
69 /* a failure here indicates a device error */
70 return (nssCryptokiObject *)NULL;
72 object = nss_ZNEW(NULL, nssCryptokiObject);
73 if (!object) {
74 return (nssCryptokiObject *)NULL;
76 object->handle = h;
77 object->token = nssToken_AddRef(t);
78 isTokenObject = (CK_BBOOL *)cert_template[0].pValue;
79 object->isTokenObject = *isTokenObject;
80 nss_ZFreeIf(isTokenObject);
81 NSS_CK_ATTRIBUTE_TO_UTF8(&cert_template[1], object->label);
82 return object;
85 NSS_IMPLEMENT void
86 nssCryptokiObject_Destroy (
87 nssCryptokiObject *object
90 if (object) {
91 nssToken_Destroy(object->token);
92 nss_ZFreeIf(object->label);
93 nss_ZFreeIf(object);
97 NSS_IMPLEMENT nssCryptokiObject *
98 nssCryptokiObject_Clone (
99 nssCryptokiObject *object
102 nssCryptokiObject *rvObject;
103 rvObject = nss_ZNEW(NULL, nssCryptokiObject);
104 if (rvObject) {
105 rvObject->handle = object->handle;
106 rvObject->token = nssToken_AddRef(object->token);
107 rvObject->isTokenObject = object->isTokenObject;
108 if (object->label) {
109 rvObject->label = nssUTF8_Duplicate(object->label, NULL);
112 return rvObject;
115 NSS_EXTERN PRBool
116 nssCryptokiObject_Equal (
117 nssCryptokiObject *o1,
118 nssCryptokiObject *o2
121 return (o1->token == o2->token && o1->handle == o2->handle);
124 NSS_IMPLEMENT PRUint32
125 nssPKCS11String_Length(CK_CHAR *pkcs11Str, PRUint32 bufLen)
127 PRInt32 i;
128 for (i = bufLen - 1; i>=0; ) {
129 if (pkcs11Str[i] != ' ' && pkcs11Str[i] != '\0') break;
130 --i;
132 return (PRUint32)(i + 1);
136 * Slot arrays
139 NSS_IMPLEMENT NSSSlot **
140 nssSlotArray_Clone (
141 NSSSlot **slots
144 NSSSlot **rvSlots = NULL;
145 NSSSlot **sp = slots;
146 PRUint32 count = 0;
147 while (sp && *sp) count++;
148 if (count > 0) {
149 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, count + 1);
150 if (rvSlots) {
151 sp = slots;
152 count = 0;
153 for (sp = slots; *sp; sp++) {
154 rvSlots[count++] = nssSlot_AddRef(*sp);
158 return rvSlots;
161 #ifdef PURE_STAN_BUILD
162 NSS_IMPLEMENT void
163 nssModuleArray_Destroy (
164 NSSModule **modules
167 if (modules) {
168 NSSModule **mp;
169 for (mp = modules; *mp; mp++) {
170 nssModule_Destroy(*mp);
172 nss_ZFreeIf(modules);
175 #endif
177 NSS_IMPLEMENT void
178 nssSlotArray_Destroy (
179 NSSSlot **slots
182 if (slots) {
183 NSSSlot **slotp;
184 for (slotp = slots; *slotp; slotp++) {
185 nssSlot_Destroy(*slotp);
187 nss_ZFreeIf(slots);
191 NSS_IMPLEMENT void
192 NSSSlotArray_Destroy (
193 NSSSlot **slots
196 nssSlotArray_Destroy(slots);
199 NSS_IMPLEMENT void
200 nssTokenArray_Destroy (
201 NSSToken **tokens
204 if (tokens) {
205 NSSToken **tokenp;
206 for (tokenp = tokens; *tokenp; tokenp++) {
207 nssToken_Destroy(*tokenp);
209 nss_ZFreeIf(tokens);
213 NSS_IMPLEMENT void
214 NSSTokenArray_Destroy (
215 NSSToken **tokens
218 nssTokenArray_Destroy(tokens);
221 NSS_IMPLEMENT void
222 nssCryptokiObjectArray_Destroy (
223 nssCryptokiObject **objects
226 if (objects) {
227 nssCryptokiObject **op;
228 for (op = objects; *op; op++) {
229 nssCryptokiObject_Destroy(*op);
231 nss_ZFreeIf(objects);
235 #ifdef PURE_STAN_BUILD
237 * Slot lists
240 struct nssSlotListNodeStr
242 PRCList link;
243 NSSSlot *slot;
244 PRUint32 order;
247 /* XXX separate slots with non-present tokens? */
248 struct nssSlotListStr
250 NSSArena *arena;
251 PRBool i_allocated_arena;
252 PZLock *lock;
253 PRCList head;
254 PRUint32 count;
257 NSS_IMPLEMENT nssSlotList *
258 nssSlotList_Create (
259 NSSArena *arenaOpt
262 nssSlotList *rvList;
263 NSSArena *arena;
264 nssArenaMark *mark;
265 if (arenaOpt) {
266 arena = arenaOpt;
267 mark = nssArena_Mark(arena);
268 if (!mark) {
269 return (nssSlotList *)NULL;
271 } else {
272 arena = nssArena_Create();
273 if (!arena) {
274 return (nssSlotList *)NULL;
277 rvList = nss_ZNEW(arena, nssSlotList);
278 if (!rvList) {
279 goto loser;
281 rvList->lock = PZ_NewLock(nssILockOther); /* XXX */
282 if (!rvList->lock) {
283 goto loser;
285 PR_INIT_CLIST(&rvList->head);
286 rvList->arena = arena;
287 rvList->i_allocated_arena = (arenaOpt == NULL);
288 nssArena_Unmark(arena, mark);
289 return rvList;
290 loser:
291 if (arenaOpt) {
292 nssArena_Release(arena, mark);
293 } else {
294 nssArena_Destroy(arena);
296 return (nssSlotList *)NULL;
299 NSS_IMPLEMENT void
300 nssSlotList_Destroy (
301 nssSlotList *slotList
304 PRCList *link;
305 struct nssSlotListNodeStr *node;
306 if (slotList) {
307 link = PR_NEXT_LINK(&slotList->head);
308 while (link != &slotList->head) {
309 node = (struct nssSlotListNodeStr *)link;
310 nssSlot_Destroy(node->slot);
311 link = PR_NEXT_LINK(link);
313 if (slotList->i_allocated_arena) {
314 nssArena_Destroy(slotList->arena);
319 /* XXX should do allocs outside of lock */
320 NSS_IMPLEMENT PRStatus
321 nssSlotList_Add (
322 nssSlotList *slotList,
323 NSSSlot *slot,
324 PRUint32 order
327 PRCList *link;
328 struct nssSlotListNodeStr *node;
329 PZ_Lock(slotList->lock);
330 link = PR_NEXT_LINK(&slotList->head);
331 while (link != &slotList->head) {
332 node = (struct nssSlotListNodeStr *)link;
333 if (order < node->order) {
334 break;
336 link = PR_NEXT_LINK(link);
338 node = nss_ZNEW(slotList->arena, struct nssSlotListNodeStr);
339 if (!node) {
340 return PR_FAILURE;
342 PR_INIT_CLIST(&node->link);
343 node->slot = nssSlot_AddRef(slot);
344 node->order = order;
345 PR_INSERT_AFTER(&node->link, link);
346 slotList->count++;
347 PZ_Unlock(slotList->lock);
348 return PR_SUCCESS;
351 NSS_IMPLEMENT PRStatus
352 nssSlotList_AddModuleSlots (
353 nssSlotList *slotList,
354 NSSModule *module,
355 PRUint32 order
358 nssArenaMark *mark = NULL;
359 NSSSlot **sp, **slots = NULL;
360 PRCList *link;
361 struct nssSlotListNodeStr *node;
362 PZ_Lock(slotList->lock);
363 link = PR_NEXT_LINK(&slotList->head);
364 while (link != &slotList->head) {
365 node = (struct nssSlotListNodeStr *)link;
366 if (order < node->order) {
367 break;
369 link = PR_NEXT_LINK(link);
371 slots = nssModule_GetSlots(module);
372 if (!slots) {
373 PZ_Unlock(slotList->lock);
374 return PR_SUCCESS;
376 mark = nssArena_Mark(slotList->arena);
377 if (!mark) {
378 goto loser;
380 for (sp = slots; *sp; sp++) {
381 node = nss_ZNEW(slotList->arena, struct nssSlotListNodeStr);
382 if (!node) {
383 goto loser;
385 PR_INIT_CLIST(&node->link);
386 node->slot = *sp; /* have ref from nssModule_GetSlots */
387 node->order = order;
388 PR_INSERT_AFTER(&node->link, link);
389 slotList->count++;
391 PZ_Unlock(slotList->lock);
392 nssArena_Unmark(slotList->arena, mark);
393 return PR_SUCCESS;
394 loser:
395 PZ_Unlock(slotList->lock);
396 if (mark) {
397 nssArena_Release(slotList->arena, mark);
399 if (slots) {
400 nssSlotArray_Destroy(slots);
402 return PR_FAILURE;
405 NSS_IMPLEMENT NSSSlot **
406 nssSlotList_GetSlots (
407 nssSlotList *slotList
410 PRUint32 i;
411 PRCList *link;
412 struct nssSlotListNodeStr *node;
413 NSSSlot **rvSlots = NULL;
414 PZ_Lock(slotList->lock);
415 rvSlots = nss_ZNEWARRAY(NULL, NSSSlot *, slotList->count + 1);
416 if (!rvSlots) {
417 PZ_Unlock(slotList->lock);
418 return (NSSSlot **)NULL;
420 i = 0;
421 link = PR_NEXT_LINK(&slotList->head);
422 while (link != &slotList->head) {
423 node = (struct nssSlotListNodeStr *)link;
424 rvSlots[i] = nssSlot_AddRef(node->slot);
425 link = PR_NEXT_LINK(link);
426 i++;
428 PZ_Unlock(slotList->lock);
429 return rvSlots;
432 #if 0
433 NSS_IMPLEMENT NSSSlot *
434 nssSlotList_GetBestSlotForAlgorithmAndParameters (
435 nssSlotList *slotList,
436 NSSAlgorithmAndParameters *ap
439 PRCList *link;
440 struct nssSlotListNodeStr *node;
441 NSSSlot *rvSlot = NULL;
442 PZ_Lock(slotList->lock);
443 link = PR_NEXT_LINK(&slotList->head);
444 while (link != &slotList->head) {
445 node = (struct nssSlotListNodeStr *)link;
446 if (nssSlot_DoesAlgorithmAndParameters(ap)) {
447 rvSlot = nssSlot_AddRef(node->slot); /* XXX check isPresent? */
449 link = PR_NEXT_LINK(link);
451 PZ_Unlock(slotList->lock);
452 return rvSlot;
454 #endif
456 NSS_IMPLEMENT NSSSlot *
457 nssSlotList_GetBestSlot (
458 nssSlotList *slotList
461 PRCList *link;
462 struct nssSlotListNodeStr *node;
463 NSSSlot *rvSlot = NULL;
464 PZ_Lock(slotList->lock);
465 if (PR_CLIST_IS_EMPTY(&slotList->head)) {
466 PZ_Unlock(slotList->lock);
467 return (NSSSlot *)NULL;
469 link = PR_NEXT_LINK(&slotList->head);
470 node = (struct nssSlotListNodeStr *)link;
471 rvSlot = nssSlot_AddRef(node->slot); /* XXX check isPresent? */
472 PZ_Unlock(slotList->lock);
473 return rvSlot;
476 NSS_IMPLEMENT NSSSlot *
477 nssSlotList_FindSlotByName (
478 nssSlotList *slotList,
479 NSSUTF8 *slotName
482 PRCList *link;
483 struct nssSlotListNodeStr *node;
484 NSSSlot *rvSlot = NULL;
485 PZ_Lock(slotList->lock);
486 link = PR_NEXT_LINK(&slotList->head);
487 while (link != &slotList->head) {
488 NSSUTF8 *sName;
489 node = (struct nssSlotListNodeStr *)link;
490 sName = nssSlot_GetName(node->slot);
491 if (nssUTF8_Equal(sName, slotName, NULL)) {
492 rvSlot = nssSlot_AddRef(node->slot);
493 break;
495 link = PR_NEXT_LINK(link);
497 PZ_Unlock(slotList->lock);
498 return rvSlot;
501 NSS_IMPLEMENT NSSToken *
502 nssSlotList_FindTokenByName (
503 nssSlotList *slotList,
504 NSSUTF8 *tokenName
507 PRCList *link;
508 struct nssSlotListNodeStr *node;
509 NSSToken *rvToken = NULL;
510 PZ_Lock(slotList->lock);
511 link = PR_NEXT_LINK(&slotList->head);
512 while (link != &slotList->head) {
513 NSSUTF8 *tName;
514 node = (struct nssSlotListNodeStr *)link;
515 tName = nssSlot_GetTokenName(node->slot);
516 if (nssUTF8_Equal(tName, tokenName, NULL)) {
517 rvToken = nssSlot_GetToken(node->slot);
518 break;
520 link = PR_NEXT_LINK(link);
522 PZ_Unlock(slotList->lock);
523 return rvToken;
525 #endif /* PURE_STAN_BUILD */
527 /* object cache for token */
529 typedef struct
531 NSSArena *arena;
532 nssCryptokiObject *object;
533 CK_ATTRIBUTE_PTR attributes;
534 CK_ULONG numAttributes;
536 nssCryptokiObjectAndAttributes;
538 enum {
539 cachedCerts = 0,
540 cachedTrust = 1,
541 cachedCRLs = 2
542 } cachedObjectType;
544 struct nssTokenObjectCacheStr
546 NSSToken *token;
547 PZLock *lock;
548 PRBool loggedIn;
549 PRBool doObjectType[3];
550 PRBool searchedObjectType[3];
551 nssCryptokiObjectAndAttributes **objects[3];
554 NSS_IMPLEMENT nssTokenObjectCache *
555 nssTokenObjectCache_Create (
556 NSSToken *token,
557 PRBool cacheCerts,
558 PRBool cacheTrust,
559 PRBool cacheCRLs
562 nssTokenObjectCache *rvCache;
563 rvCache = nss_ZNEW(NULL, nssTokenObjectCache);
564 if (!rvCache) {
565 goto loser;
567 rvCache->lock = PZ_NewLock(nssILockOther); /* XXX */
568 if (!rvCache->lock) {
569 goto loser;
571 rvCache->doObjectType[cachedCerts] = cacheCerts;
572 rvCache->doObjectType[cachedTrust] = cacheTrust;
573 rvCache->doObjectType[cachedCRLs] = cacheCRLs;
574 rvCache->token = token; /* cache goes away with token */
575 return rvCache;
576 loser:
577 return (nssTokenObjectCache *)NULL;
580 static void
581 clear_cache (
582 nssTokenObjectCache *cache
585 nssCryptokiObjectAndAttributes **oa;
586 PRUint32 objectType;
587 for (objectType = cachedCerts; objectType <= cachedCRLs; objectType++) {
588 cache->searchedObjectType[objectType] = PR_FALSE;
589 if (!cache->objects[objectType]) {
590 continue;
592 for (oa = cache->objects[objectType]; *oa; oa++) {
593 /* prevent the token from being destroyed */
594 (*oa)->object->token = NULL;
595 nssCryptokiObject_Destroy((*oa)->object);
596 nssArena_Destroy((*oa)->arena);
598 nss_ZFreeIf(cache->objects[objectType]);
599 cache->objects[objectType] = NULL;
603 NSS_IMPLEMENT void
604 nssTokenObjectCache_Clear (
605 nssTokenObjectCache *cache
608 if (cache) {
609 PZ_Lock(cache->lock);
610 clear_cache(cache);
611 PZ_Unlock(cache->lock);
615 NSS_IMPLEMENT void
616 nssTokenObjectCache_Destroy (
617 nssTokenObjectCache *cache
620 if (cache) {
621 clear_cache(cache);
622 PZ_DestroyLock(cache->lock);
623 nss_ZFreeIf(cache);
627 NSS_IMPLEMENT PRBool
628 nssTokenObjectCache_HaveObjectClass (
629 nssTokenObjectCache *cache,
630 CK_OBJECT_CLASS objclass
633 PRBool haveIt;
634 PZ_Lock(cache->lock);
635 switch (objclass) {
636 case CKO_CERTIFICATE: haveIt = cache->doObjectType[cachedCerts]; break;
637 case CKO_NETSCAPE_TRUST: haveIt = cache->doObjectType[cachedTrust]; break;
638 case CKO_NETSCAPE_CRL: haveIt = cache->doObjectType[cachedCRLs]; break;
639 default: haveIt = PR_FALSE;
641 PZ_Unlock(cache->lock);
642 return haveIt;
645 static nssCryptokiObjectAndAttributes **
646 create_object_array (
647 nssCryptokiObject **objects,
648 PRBool *doObjects,
649 PRUint32 *numObjects,
650 PRStatus *status
653 nssCryptokiObjectAndAttributes **rvOandA = NULL;
654 *numObjects = 0;
655 /* There are no objects for this type */
656 if (!objects || !*objects) {
657 *status = PR_SUCCESS;
658 return rvOandA;
660 while (*objects++) (*numObjects)++;
661 if (*numObjects >= MAX_LOCAL_CACHE_OBJECTS) {
662 /* Hit the maximum allowed, so don't use a cache (there are
663 * too many objects to make caching worthwhile, presumably, if
664 * the token can handle that many objects, it can handle searching.
666 *doObjects = PR_FALSE;
667 *status = PR_FAILURE;
668 *numObjects = 0;
669 } else {
670 rvOandA = nss_ZNEWARRAY(NULL,
671 nssCryptokiObjectAndAttributes *,
672 *numObjects + 1);
673 *status = rvOandA ? PR_SUCCESS : PR_FAILURE;
675 return rvOandA;
678 static nssCryptokiObjectAndAttributes *
679 create_object (
680 nssCryptokiObject *object,
681 const CK_ATTRIBUTE_TYPE *types,
682 PRUint32 numTypes,
683 PRStatus *status
686 PRUint32 j;
687 NSSArena *arena;
688 NSSSlot *slot = NULL;
689 nssSession *session = NULL;
690 nssCryptokiObjectAndAttributes *rvCachedObject = NULL;
692 slot = nssToken_GetSlot(object->token);
693 if (!slot) {
694 nss_SetError(NSS_ERROR_INVALID_POINTER);
695 goto loser;
697 session = nssToken_GetDefaultSession(object->token);
699 arena = nssArena_Create();
700 if (!arena) {
701 goto loser;
703 rvCachedObject = nss_ZNEW(arena, nssCryptokiObjectAndAttributes);
704 if (!rvCachedObject) {
705 goto loser;
707 rvCachedObject->arena = arena;
708 /* The cache is tied to the token, and therefore the objects
709 * in it should not hold references to the token.
711 nssToken_Destroy(object->token);
712 rvCachedObject->object = object;
713 rvCachedObject->attributes = nss_ZNEWARRAY(arena, CK_ATTRIBUTE, numTypes);
714 if (!rvCachedObject->attributes) {
715 goto loser;
717 for (j=0; j<numTypes; j++) {
718 rvCachedObject->attributes[j].type = types[j];
720 *status = nssCKObject_GetAttributes(object->handle,
721 rvCachedObject->attributes,
722 numTypes,
723 arena,
724 session,
725 slot);
726 if (*status != PR_SUCCESS) {
727 goto loser;
729 rvCachedObject->numAttributes = numTypes;
730 *status = PR_SUCCESS;
731 nssSlot_Destroy(slot);
733 return rvCachedObject;
734 loser:
735 *status = PR_FAILURE;
736 if (slot) {
737 nssSlot_Destroy(slot);
739 if (arena)
740 nssArena_Destroy(arena);
741 return (nssCryptokiObjectAndAttributes *)NULL;
746 * State diagram for cache:
748 * token !present token removed
749 * +-------------------------+<----------------------+
750 * | ^ |
751 * v | |
752 * +----------+ slot friendly | token present +----------+
753 * | cache | -----------------> % ---------------> | cache |
754 * | unloaded | | loaded |
755 * +----------+ +----------+
756 * ^ | ^ |
757 * | | slot !friendly slot logged in | |
758 * | +-----------------------> % ----------------------+ |
759 * | | |
760 * | slot logged out v slot !friendly |
761 * +-----------------------------+<--------------------------+
765 /* This function must not be called with cache->lock locked. */
766 static PRBool
767 token_is_present (
768 nssTokenObjectCache *cache
771 NSSSlot *slot = nssToken_GetSlot(cache->token);
772 PRBool tokenPresent = nssSlot_IsTokenPresent(slot);
773 nssSlot_Destroy(slot);
774 return tokenPresent;
777 static PRBool
778 search_for_objects (
779 nssTokenObjectCache *cache
782 PRBool doSearch = PR_FALSE;
783 NSSSlot *slot = nssToken_GetSlot(cache->token);
784 /* Handle non-friendly slots (slots which require login for objects) */
785 if (!nssSlot_IsFriendly(slot)) {
786 if (nssSlot_IsLoggedIn(slot)) {
787 /* Either no state change, or went from !logged in -> logged in */
788 cache->loggedIn = PR_TRUE;
789 doSearch = PR_TRUE;
790 } else {
791 if (cache->loggedIn) {
792 /* went from logged in -> !logged in, destroy cached objects */
793 clear_cache(cache);
794 cache->loggedIn = PR_FALSE;
795 } /* else no state change, still not logged in, so exit */
797 } else {
798 /* slot is friendly, thus always available for search */
799 doSearch = PR_TRUE;
801 nssSlot_Destroy(slot);
802 return doSearch;
805 static nssCryptokiObjectAndAttributes *
806 create_cert (
807 nssCryptokiObject *object,
808 PRStatus *status
811 static const CK_ATTRIBUTE_TYPE certAttr[] = {
812 CKA_CLASS,
813 CKA_TOKEN,
814 CKA_LABEL,
815 CKA_CERTIFICATE_TYPE,
816 CKA_ID,
817 CKA_VALUE,
818 CKA_ISSUER,
819 CKA_SERIAL_NUMBER,
820 CKA_SUBJECT,
821 CKA_NETSCAPE_EMAIL
823 static const PRUint32 numCertAttr = sizeof(certAttr) / sizeof(certAttr[0]);
824 return create_object(object, certAttr, numCertAttr, status);
827 static PRStatus
828 get_token_certs_for_cache (
829 nssTokenObjectCache *cache
832 PRStatus status;
833 nssCryptokiObject **objects;
834 PRBool *doIt = &cache->doObjectType[cachedCerts];
835 PRUint32 i, numObjects;
837 if (!search_for_objects(cache) ||
838 cache->searchedObjectType[cachedCerts] ||
839 !cache->doObjectType[cachedCerts])
841 /* Either there was a state change that prevents a search
842 * (token logged out), or the search was already done,
843 * or certs are not being cached.
845 return PR_SUCCESS;
847 objects = nssToken_FindCertificates(cache->token, NULL,
848 nssTokenSearchType_TokenForced,
849 MAX_LOCAL_CACHE_OBJECTS, &status);
850 if (status != PR_SUCCESS) {
851 return status;
853 cache->objects[cachedCerts] = create_object_array(objects,
854 doIt,
855 &numObjects,
856 &status);
857 if (status != PR_SUCCESS) {
858 return status;
860 for (i=0; i<numObjects; i++) {
861 cache->objects[cachedCerts][i] = create_cert(objects[i], &status);
862 if (status != PR_SUCCESS) {
863 break;
866 if (status == PR_SUCCESS) {
867 nss_ZFreeIf(objects);
868 } else {
869 PRUint32 j;
870 for (j=0; j<i; j++) {
871 /* sigh */
872 nssToken_AddRef(cache->objects[cachedCerts][j]->object->token);
873 nssArena_Destroy(cache->objects[cachedCerts][j]->arena);
875 nssCryptokiObjectArray_Destroy(objects);
877 cache->searchedObjectType[cachedCerts] = PR_TRUE;
878 return status;
881 static nssCryptokiObjectAndAttributes *
882 create_trust (
883 nssCryptokiObject *object,
884 PRStatus *status
887 static const CK_ATTRIBUTE_TYPE trustAttr[] = {
888 CKA_CLASS,
889 CKA_TOKEN,
890 CKA_LABEL,
891 CKA_CERT_SHA1_HASH,
892 CKA_CERT_MD5_HASH,
893 CKA_ISSUER,
894 CKA_SUBJECT,
895 CKA_TRUST_SERVER_AUTH,
896 CKA_TRUST_CLIENT_AUTH,
897 CKA_TRUST_EMAIL_PROTECTION,
898 CKA_TRUST_CODE_SIGNING
900 static const PRUint32 numTrustAttr = sizeof(trustAttr) / sizeof(trustAttr[0]);
901 return create_object(object, trustAttr, numTrustAttr, status);
904 static PRStatus
905 get_token_trust_for_cache (
906 nssTokenObjectCache *cache
909 PRStatus status;
910 nssCryptokiObject **objects;
911 PRBool *doIt = &cache->doObjectType[cachedTrust];
912 PRUint32 i, numObjects;
914 if (!search_for_objects(cache) ||
915 cache->searchedObjectType[cachedTrust] ||
916 !cache->doObjectType[cachedTrust])
918 /* Either there was a state change that prevents a search
919 * (token logged out), or the search was already done,
920 * or trust is not being cached.
922 return PR_SUCCESS;
924 objects = nssToken_FindTrustObjects(cache->token, NULL,
925 nssTokenSearchType_TokenForced,
926 MAX_LOCAL_CACHE_OBJECTS, &status);
927 if (status != PR_SUCCESS) {
928 return status;
930 cache->objects[cachedTrust] = create_object_array(objects,
931 doIt,
932 &numObjects,
933 &status);
934 if (status != PR_SUCCESS) {
935 return status;
937 for (i=0; i<numObjects; i++) {
938 cache->objects[cachedTrust][i] = create_trust(objects[i], &status);
939 if (status != PR_SUCCESS) {
940 break;
943 if (status == PR_SUCCESS) {
944 nss_ZFreeIf(objects);
945 } else {
946 PRUint32 j;
947 for (j=0; j<i; j++) {
948 /* sigh */
949 nssToken_AddRef(cache->objects[cachedTrust][j]->object->token);
950 nssArena_Destroy(cache->objects[cachedTrust][j]->arena);
952 nssCryptokiObjectArray_Destroy(objects);
954 cache->searchedObjectType[cachedTrust] = PR_TRUE;
955 return status;
958 static nssCryptokiObjectAndAttributes *
959 create_crl (
960 nssCryptokiObject *object,
961 PRStatus *status
964 static const CK_ATTRIBUTE_TYPE crlAttr[] = {
965 CKA_CLASS,
966 CKA_TOKEN,
967 CKA_LABEL,
968 CKA_VALUE,
969 CKA_SUBJECT,
970 CKA_NETSCAPE_KRL,
971 CKA_NETSCAPE_URL
973 static const PRUint32 numCRLAttr = sizeof(crlAttr) / sizeof(crlAttr[0]);
974 return create_object(object, crlAttr, numCRLAttr, status);
977 static PRStatus
978 get_token_crls_for_cache (
979 nssTokenObjectCache *cache
982 PRStatus status;
983 nssCryptokiObject **objects;
984 PRBool *doIt = &cache->doObjectType[cachedCRLs];
985 PRUint32 i, numObjects;
987 if (!search_for_objects(cache) ||
988 cache->searchedObjectType[cachedCRLs] ||
989 !cache->doObjectType[cachedCRLs])
991 /* Either there was a state change that prevents a search
992 * (token logged out), or the search was already done,
993 * or CRLs are not being cached.
995 return PR_SUCCESS;
997 objects = nssToken_FindCRLs(cache->token, NULL,
998 nssTokenSearchType_TokenForced,
999 MAX_LOCAL_CACHE_OBJECTS, &status);
1000 if (status != PR_SUCCESS) {
1001 return status;
1003 cache->objects[cachedCRLs] = create_object_array(objects,
1004 doIt,
1005 &numObjects,
1006 &status);
1007 if (status != PR_SUCCESS) {
1008 return status;
1010 for (i=0; i<numObjects; i++) {
1011 cache->objects[cachedCRLs][i] = create_crl(objects[i], &status);
1012 if (status != PR_SUCCESS) {
1013 break;
1016 if (status == PR_SUCCESS) {
1017 nss_ZFreeIf(objects);
1018 } else {
1019 PRUint32 j;
1020 for (j=0; j<i; j++) {
1021 /* sigh */
1022 nssToken_AddRef(cache->objects[cachedCRLs][j]->object->token);
1023 nssArena_Destroy(cache->objects[cachedCRLs][j]->arena);
1025 nssCryptokiObjectArray_Destroy(objects);
1027 cache->searchedObjectType[cachedCRLs] = PR_TRUE;
1028 return status;
1031 static CK_ATTRIBUTE_PTR
1032 find_attribute_in_object (
1033 nssCryptokiObjectAndAttributes *obj,
1034 CK_ATTRIBUTE_TYPE attrType
1037 PRUint32 j;
1038 for (j=0; j<obj->numAttributes; j++) {
1039 if (attrType == obj->attributes[j].type) {
1040 return &obj->attributes[j];
1043 return (CK_ATTRIBUTE_PTR)NULL;
1046 /* Find all objects in the array that match the supplied template */
1047 static nssCryptokiObject **
1048 find_objects_in_array (
1049 nssCryptokiObjectAndAttributes **objArray,
1050 CK_ATTRIBUTE_PTR ot,
1051 CK_ULONG otlen,
1052 PRUint32 maximumOpt
1055 PRIntn oi = 0;
1056 PRUint32 i;
1057 NSSArena *arena;
1058 PRUint32 size = 8;
1059 PRUint32 numMatches = 0;
1060 nssCryptokiObject **objects = NULL;
1061 nssCryptokiObjectAndAttributes **matches = NULL;
1062 CK_ATTRIBUTE_PTR attr;
1064 if (!objArray) {
1065 return (nssCryptokiObject **)NULL;
1067 arena = nssArena_Create();
1068 if (!arena) {
1069 return (nssCryptokiObject **)NULL;
1071 matches = nss_ZNEWARRAY(arena, nssCryptokiObjectAndAttributes *, size);
1072 if (!matches) {
1073 goto loser;
1075 if (maximumOpt == 0) maximumOpt = ~0;
1076 /* loop over the cached objects */
1077 for (; *objArray && numMatches < maximumOpt; objArray++) {
1078 nssCryptokiObjectAndAttributes *obj = *objArray;
1079 /* loop over the test template */
1080 for (i=0; i<otlen; i++) {
1081 /* see if the object has the attribute */
1082 attr = find_attribute_in_object(obj, ot[i].type);
1083 if (!attr) {
1084 /* nope, match failed */
1085 break;
1087 /* compare the attribute against the test value */
1088 if (ot[i].ulValueLen != attr->ulValueLen ||
1089 !nsslibc_memequal(ot[i].pValue,
1090 attr->pValue,
1091 attr->ulValueLen, NULL))
1093 /* nope, match failed */
1094 break;
1097 if (i == otlen) {
1098 /* all of the attributes in the test template were found
1099 * in the object's template, and they all matched
1101 matches[numMatches++] = obj;
1102 if (numMatches == size) {
1103 size *= 2;
1104 matches = nss_ZREALLOCARRAY(matches,
1105 nssCryptokiObjectAndAttributes *,
1106 size);
1107 if (!matches) {
1108 goto loser;
1113 if (numMatches > 0) {
1114 objects = nss_ZNEWARRAY(NULL, nssCryptokiObject *, numMatches + 1);
1115 if (!objects) {
1116 goto loser;
1118 for (oi=0; oi<(PRIntn)numMatches; oi++) {
1119 objects[oi] = nssCryptokiObject_Clone(matches[oi]->object);
1120 if (!objects[oi]) {
1121 goto loser;
1125 nssArena_Destroy(arena);
1126 return objects;
1127 loser:
1128 if (objects) {
1129 for (--oi; oi>=0; --oi) {
1130 nssCryptokiObject_Destroy(objects[oi]);
1133 nssArena_Destroy(arena);
1134 return (nssCryptokiObject **)NULL;
1137 NSS_IMPLEMENT nssCryptokiObject **
1138 nssTokenObjectCache_FindObjectsByTemplate (
1139 nssTokenObjectCache *cache,
1140 CK_OBJECT_CLASS objclass,
1141 CK_ATTRIBUTE_PTR otemplate,
1142 CK_ULONG otlen,
1143 PRUint32 maximumOpt,
1144 PRStatus *statusOpt
1147 PRStatus status = PR_FAILURE;
1148 nssCryptokiObject **rvObjects = NULL;
1149 if (!token_is_present(cache)) {
1150 status = PR_SUCCESS;
1151 goto finish;
1153 PZ_Lock(cache->lock);
1154 switch (objclass) {
1155 case CKO_CERTIFICATE:
1156 if (cache->doObjectType[cachedCerts]) {
1157 status = get_token_certs_for_cache(cache);
1158 if (status != PR_SUCCESS) {
1159 goto unlock;
1161 rvObjects = find_objects_in_array(cache->objects[cachedCerts],
1162 otemplate, otlen, maximumOpt);
1164 break;
1165 case CKO_NETSCAPE_TRUST:
1166 if (cache->doObjectType[cachedTrust]) {
1167 status = get_token_trust_for_cache(cache);
1168 if (status != PR_SUCCESS) {
1169 goto unlock;
1171 rvObjects = find_objects_in_array(cache->objects[cachedTrust],
1172 otemplate, otlen, maximumOpt);
1174 break;
1175 case CKO_NETSCAPE_CRL:
1176 if (cache->doObjectType[cachedCRLs]) {
1177 status = get_token_crls_for_cache(cache);
1178 if (status != PR_SUCCESS) {
1179 goto unlock;
1181 rvObjects = find_objects_in_array(cache->objects[cachedCRLs],
1182 otemplate, otlen, maximumOpt);
1184 break;
1185 default: break;
1187 unlock:
1188 PZ_Unlock(cache->lock);
1189 finish:
1190 if (statusOpt) {
1191 *statusOpt = status;
1193 return rvObjects;
1196 static PRBool
1197 cache_available_for_object_type (
1198 nssTokenObjectCache *cache,
1199 PRUint32 objectType
1202 if (!cache->doObjectType[objectType]) {
1203 /* not caching this object kind */
1204 return PR_FALSE;
1206 if (!cache->searchedObjectType[objectType]) {
1207 /* objects are not cached yet */
1208 return PR_FALSE;
1210 if (!search_for_objects(cache)) {
1211 /* not logged in */
1212 return PR_FALSE;
1214 return PR_TRUE;
1217 NSS_IMPLEMENT PRStatus
1218 nssTokenObjectCache_GetObjectAttributes (
1219 nssTokenObjectCache *cache,
1220 NSSArena *arenaOpt,
1221 nssCryptokiObject *object,
1222 CK_OBJECT_CLASS objclass,
1223 CK_ATTRIBUTE_PTR atemplate,
1224 CK_ULONG atlen
1227 PRUint32 i, j;
1228 NSSArena *arena = NULL;
1229 nssArenaMark *mark = NULL;
1230 nssCryptokiObjectAndAttributes *cachedOA = NULL;
1231 nssCryptokiObjectAndAttributes **oa = NULL;
1232 PRUint32 objectType;
1233 if (!token_is_present(cache)) {
1234 return PR_FAILURE;
1236 PZ_Lock(cache->lock);
1237 switch (objclass) {
1238 case CKO_CERTIFICATE: objectType = cachedCerts; break;
1239 case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
1240 case CKO_NETSCAPE_CRL: objectType = cachedCRLs; break;
1241 default: goto loser;
1243 if (!cache_available_for_object_type(cache, objectType)) {
1244 goto loser;
1246 oa = cache->objects[objectType];
1247 if (!oa) {
1248 goto loser;
1250 for (; *oa; oa++) {
1251 if (nssCryptokiObject_Equal((*oa)->object, object)) {
1252 cachedOA = *oa;
1253 break;
1256 if (!cachedOA) {
1257 goto loser; /* don't have this object */
1259 if (arenaOpt) {
1260 arena = arenaOpt;
1261 mark = nssArena_Mark(arena);
1263 for (i=0; i<atlen; i++) {
1264 for (j=0; j<cachedOA->numAttributes; j++) {
1265 if (atemplate[i].type == cachedOA->attributes[j].type) {
1266 CK_ATTRIBUTE_PTR attr = &cachedOA->attributes[j];
1267 if (cachedOA->attributes[j].ulValueLen == 0 ||
1268 cachedOA->attributes[j].ulValueLen == (CK_ULONG)-1)
1270 break; /* invalid attribute */
1272 if (atemplate[i].ulValueLen > 0) {
1273 if (atemplate[i].pValue == NULL ||
1274 atemplate[i].ulValueLen < attr->ulValueLen)
1276 goto loser;
1278 } else {
1279 atemplate[i].pValue = nss_ZAlloc(arena, attr->ulValueLen);
1280 if (!atemplate[i].pValue) {
1281 goto loser;
1284 nsslibc_memcpy(atemplate[i].pValue,
1285 attr->pValue, attr->ulValueLen);
1286 atemplate[i].ulValueLen = attr->ulValueLen;
1287 break;
1290 if (j == cachedOA->numAttributes) {
1291 atemplate[i].ulValueLen = (CK_ULONG)-1;
1294 PZ_Unlock(cache->lock);
1295 if (mark) {
1296 nssArena_Unmark(arena, mark);
1298 return PR_SUCCESS;
1299 loser:
1300 PZ_Unlock(cache->lock);
1301 if (mark) {
1302 nssArena_Release(arena, mark);
1304 return PR_FAILURE;
1307 NSS_IMPLEMENT PRStatus
1308 nssTokenObjectCache_ImportObject (
1309 nssTokenObjectCache *cache,
1310 nssCryptokiObject *object,
1311 CK_OBJECT_CLASS objclass,
1312 CK_ATTRIBUTE_PTR ot,
1313 CK_ULONG otlen
1316 PRStatus status = PR_SUCCESS;
1317 PRUint32 count;
1318 nssCryptokiObjectAndAttributes **oa, ***otype;
1319 PRUint32 objectType;
1320 PRBool haveIt = PR_FALSE;
1322 if (!token_is_present(cache)) {
1323 return PR_SUCCESS; /* cache not active, ignored */
1325 PZ_Lock(cache->lock);
1326 switch (objclass) {
1327 case CKO_CERTIFICATE: objectType = cachedCerts; break;
1328 case CKO_NETSCAPE_TRUST: objectType = cachedTrust; break;
1329 case CKO_NETSCAPE_CRL: objectType = cachedCRLs; break;
1330 default:
1331 PZ_Unlock(cache->lock);
1332 return PR_SUCCESS; /* don't need to import it here */
1334 if (!cache_available_for_object_type(cache, objectType)) {
1335 PZ_Unlock(cache->lock);
1336 return PR_SUCCESS; /* cache not active, ignored */
1338 count = 0;
1339 otype = &cache->objects[objectType]; /* index into array of types */
1340 oa = *otype; /* the array of objects for this type */
1341 while (oa && *oa) {
1342 if (nssCryptokiObject_Equal((*oa)->object, object)) {
1343 haveIt = PR_TRUE;
1344 break;
1346 count++;
1347 oa++;
1349 if (haveIt) {
1350 /* Destroy the old entry */
1351 (*oa)->object->token = NULL;
1352 nssCryptokiObject_Destroy((*oa)->object);
1353 nssArena_Destroy((*oa)->arena);
1354 } else {
1355 /* Create space for a new entry */
1356 if (count > 0) {
1357 *otype = nss_ZREALLOCARRAY(*otype,
1358 nssCryptokiObjectAndAttributes *,
1359 count + 2);
1360 } else {
1361 *otype = nss_ZNEWARRAY(NULL, nssCryptokiObjectAndAttributes *, 2);
1364 if (*otype) {
1365 nssCryptokiObject *copyObject = nssCryptokiObject_Clone(object);
1366 if (objectType == cachedCerts) {
1367 (*otype)[count] = create_cert(copyObject, &status);
1368 } else if (objectType == cachedTrust) {
1369 (*otype)[count] = create_trust(copyObject, &status);
1370 } else if (objectType == cachedCRLs) {
1371 (*otype)[count] = create_crl(copyObject, &status);
1373 } else {
1374 status = PR_FAILURE;
1376 PZ_Unlock(cache->lock);
1377 return status;
1380 NSS_IMPLEMENT void
1381 nssTokenObjectCache_RemoveObject (
1382 nssTokenObjectCache *cache,
1383 nssCryptokiObject *object
1386 PRUint32 oType;
1387 nssCryptokiObjectAndAttributes **oa, **swp = NULL;
1388 if (!token_is_present(cache)) {
1389 return;
1391 PZ_Lock(cache->lock);
1392 for (oType=0; oType<3; oType++) {
1393 if (!cache_available_for_object_type(cache, oType) ||
1394 !cache->objects[oType])
1396 continue;
1398 for (oa = cache->objects[oType]; *oa; oa++) {
1399 if (nssCryptokiObject_Equal((*oa)->object, object)) {
1400 swp = oa; /* the entry to remove */
1401 while (oa[1]) oa++; /* go to the tail */
1402 (*swp)->object->token = NULL;
1403 nssCryptokiObject_Destroy((*swp)->object);
1404 nssArena_Destroy((*swp)->arena); /* destroy it */
1405 *swp = *oa; /* swap the last with the removed */
1406 *oa = NULL; /* null-terminate the array */
1407 break;
1410 if (swp) {
1411 break;
1414 if ((oType <3) &&
1415 cache->objects[oType] && cache->objects[oType][0] == NULL) {
1416 nss_ZFreeIf(cache->objects[oType]); /* no entries remaining */
1417 cache->objects[oType] = NULL;
1419 PZ_Unlock(cache->lock);
1422 /* These two hash algorithms are presently sufficient.
1423 ** They are used for fingerprints of certs which are stored as the
1424 ** CKA_CERT_SHA1_HASH and CKA_CERT_MD5_HASH attributes.
1425 ** We don't need to add SHAxxx to these now.
1427 /* XXX of course this doesn't belong here */
1428 NSS_IMPLEMENT NSSAlgorithmAndParameters *
1429 NSSAlgorithmAndParameters_CreateSHA1Digest (
1430 NSSArena *arenaOpt
1433 NSSAlgorithmAndParameters *rvAP = NULL;
1434 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
1435 if (rvAP) {
1436 rvAP->mechanism.mechanism = CKM_SHA_1;
1437 rvAP->mechanism.pParameter = NULL;
1438 rvAP->mechanism.ulParameterLen = 0;
1440 return rvAP;
1443 NSS_IMPLEMENT NSSAlgorithmAndParameters *
1444 NSSAlgorithmAndParameters_CreateMD5Digest (
1445 NSSArena *arenaOpt
1448 NSSAlgorithmAndParameters *rvAP = NULL;
1449 rvAP = nss_ZNEW(arenaOpt, NSSAlgorithmAndParameters);
1450 if (rvAP) {
1451 rvAP->mechanism.mechanism = CKM_MD5;
1452 rvAP->mechanism.pParameter = NULL;
1453 rvAP->mechanism.ulParameterLen = 0;
1455 return rvAP;