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