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