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 DEV_H
6 #include "dev.h"
7 #endif /* DEV_H */
8 
9 #ifndef PKIM_H
10 #include "pkim.h"
11 #endif /* PKIM_H */
12 
13 #include "pki3hack.h"
14 
15 extern const NSSError NSS_ERROR_NOT_FOUND;
16 
17 NSS_IMPLEMENT void
nssPKIObject_Lock(nssPKIObject * object)18 nssPKIObject_Lock(nssPKIObject *object)
19 {
20     switch (object->lockType) {
21         case nssPKIMonitor:
22             PZ_EnterMonitor(object->sync.mlock);
23             break;
24         case nssPKILock:
25             PZ_Lock(object->sync.lock);
26             break;
27         default:
28             PORT_Assert(0);
29     }
30 }
31 
32 NSS_IMPLEMENT void
nssPKIObject_Unlock(nssPKIObject * object)33 nssPKIObject_Unlock(nssPKIObject *object)
34 {
35     switch (object->lockType) {
36         case nssPKIMonitor:
37             PZ_ExitMonitor(object->sync.mlock);
38             break;
39         case nssPKILock:
40             PZ_Unlock(object->sync.lock);
41             break;
42         default:
43             PORT_Assert(0);
44     }
45 }
46 
47 NSS_IMPLEMENT PRStatus
nssPKIObject_NewLock(nssPKIObject * object,nssPKILockType lockType)48 nssPKIObject_NewLock(nssPKIObject *object, nssPKILockType lockType)
49 {
50     object->lockType = lockType;
51     switch (lockType) {
52         case nssPKIMonitor:
53             object->sync.mlock = PZ_NewMonitor(nssILockSSL);
54             return (object->sync.mlock ? PR_SUCCESS : PR_FAILURE);
55         case nssPKILock:
56             object->sync.lock = PZ_NewLock(nssILockSSL);
57             return (object->sync.lock ? PR_SUCCESS : PR_FAILURE);
58         default:
59             PORT_Assert(0);
60             return PR_FAILURE;
61     }
62 }
63 
64 NSS_IMPLEMENT void
nssPKIObject_DestroyLock(nssPKIObject * object)65 nssPKIObject_DestroyLock(nssPKIObject *object)
66 {
67     switch (object->lockType) {
68         case nssPKIMonitor:
69             PZ_DestroyMonitor(object->sync.mlock);
70             object->sync.mlock = NULL;
71             break;
72         case nssPKILock:
73             PZ_DestroyLock(object->sync.lock);
74             object->sync.lock = NULL;
75             break;
76         default:
77             PORT_Assert(0);
78     }
79 }
80 
81 NSS_IMPLEMENT nssPKIObject *
nssPKIObject_Create(NSSArena * arenaOpt,nssCryptokiObject * instanceOpt,NSSTrustDomain * td,NSSCryptoContext * cc,nssPKILockType lockType)82 nssPKIObject_Create(
83     NSSArena *arenaOpt,
84     nssCryptokiObject *instanceOpt,
85     NSSTrustDomain *td,
86     NSSCryptoContext *cc,
87     nssPKILockType lockType)
88 {
89     NSSArena *arena;
90     nssArenaMark *mark = NULL;
91     nssPKIObject *object;
92     if (arenaOpt) {
93         arena = arenaOpt;
94         mark = nssArena_Mark(arena);
95     } else {
96         arena = nssArena_Create();
97         if (!arena) {
98             return (nssPKIObject *)NULL;
99         }
100     }
101     object = nss_ZNEW(arena, nssPKIObject);
102     if (!object) {
103         goto loser;
104     }
105     object->arena = arena;
106     object->trustDomain = td; /* XXX */
107     object->cryptoContext = cc;
108     if (PR_SUCCESS != nssPKIObject_NewLock(object, lockType)) {
109         goto loser;
110     }
111     if (instanceOpt) {
112         if (nssPKIObject_AddInstance(object, instanceOpt) != PR_SUCCESS) {
113             goto loser;
114         }
115     }
116     PR_ATOMIC_INCREMENT(&object->refCount);
117     if (mark) {
118         nssArena_Unmark(arena, mark);
119     }
120     return object;
121 loser:
122     if (mark) {
123         nssArena_Release(arena, mark);
124     } else {
125         nssArena_Destroy(arena);
126     }
127     return (nssPKIObject *)NULL;
128 }
129 
130 NSS_IMPLEMENT PRBool
nssPKIObject_Destroy(nssPKIObject * object)131 nssPKIObject_Destroy(
132     nssPKIObject *object)
133 {
134     PRUint32 i;
135     PR_ASSERT(object->refCount > 0);
136     if (PR_ATOMIC_DECREMENT(&object->refCount) == 0) {
137         for (i = 0; i < object->numInstances; i++) {
138             nssCryptokiObject_Destroy(object->instances[i]);
139         }
140         nssPKIObject_DestroyLock(object);
141         nssArena_Destroy(object->arena);
142         return PR_TRUE;
143     }
144     return PR_FALSE;
145 }
146 
147 NSS_IMPLEMENT nssPKIObject *
nssPKIObject_AddRef(nssPKIObject * object)148 nssPKIObject_AddRef(
149     nssPKIObject *object)
150 {
151     PR_ATOMIC_INCREMENT(&object->refCount);
152     return object;
153 }
154 
155 NSS_IMPLEMENT PRStatus
nssPKIObject_AddInstance(nssPKIObject * object,nssCryptokiObject * instance)156 nssPKIObject_AddInstance(
157     nssPKIObject *object,
158     nssCryptokiObject *instance)
159 {
160     nssCryptokiObject **newInstances = NULL;
161 
162     nssPKIObject_Lock(object);
163     if (object->numInstances == 0) {
164         newInstances = nss_ZNEWARRAY(object->arena,
165                                      nssCryptokiObject *,
166                                      object->numInstances + 1);
167     } else {
168         PRBool found = PR_FALSE;
169         PRUint32 i;
170         for (i = 0; i < object->numInstances; i++) {
171             if (nssCryptokiObject_Equal(object->instances[i], instance)) {
172                 found = PR_TRUE;
173                 break;
174             }
175         }
176         if (found) {
177             /* The new instance is identical to one in the array, except
178              * perhaps that the label may be different.  So replace
179              * the label in the array instance with the label from the
180              * new instance, and discard the new instance.
181              */
182             nss_ZFreeIf(object->instances[i]->label);
183             object->instances[i]->label = instance->label;
184             nssPKIObject_Unlock(object);
185             instance->label = NULL;
186             nssCryptokiObject_Destroy(instance);
187             return PR_SUCCESS;
188         }
189         newInstances = nss_ZREALLOCARRAY(object->instances,
190                                          nssCryptokiObject *,
191                                          object->numInstances + 1);
192     }
193     if (newInstances) {
194         object->instances = newInstances;
195         newInstances[object->numInstances++] = instance;
196     }
197     nssPKIObject_Unlock(object);
198     return (newInstances ? PR_SUCCESS : PR_FAILURE);
199 }
200 
201 NSS_IMPLEMENT PRBool
nssPKIObject_HasInstance(nssPKIObject * object,nssCryptokiObject * instance)202 nssPKIObject_HasInstance(
203     nssPKIObject *object,
204     nssCryptokiObject *instance)
205 {
206     PRUint32 i;
207     PRBool hasIt = PR_FALSE;
208     ;
209     nssPKIObject_Lock(object);
210     for (i = 0; i < object->numInstances; i++) {
211         if (nssCryptokiObject_Equal(object->instances[i], instance)) {
212             hasIt = PR_TRUE;
213             break;
214         }
215     }
216     nssPKIObject_Unlock(object);
217     return hasIt;
218 }
219 
220 NSS_IMPLEMENT PRStatus
nssPKIObject_RemoveInstanceForToken(nssPKIObject * object,NSSToken * token)221 nssPKIObject_RemoveInstanceForToken(
222     nssPKIObject *object,
223     NSSToken *token)
224 {
225     PRUint32 i;
226     nssCryptokiObject *instanceToRemove = NULL;
227     nssPKIObject_Lock(object);
228     if (object->numInstances == 0) {
229         nssPKIObject_Unlock(object);
230         return PR_SUCCESS;
231     }
232     for (i = 0; i < object->numInstances; i++) {
233         if (object->instances[i]->token == token) {
234             instanceToRemove = object->instances[i];
235             object->instances[i] = object->instances[object->numInstances - 1];
236             object->instances[object->numInstances - 1] = NULL;
237             break;
238         }
239     }
240     if (--object->numInstances > 0) {
241         nssCryptokiObject **instances = nss_ZREALLOCARRAY(object->instances,
242                                                           nssCryptokiObject *,
243                                                           object->numInstances);
244         if (instances) {
245             object->instances = instances;
246         }
247     } else {
248         nss_ZFreeIf(object->instances);
249     }
250     nssCryptokiObject_Destroy(instanceToRemove);
251     nssPKIObject_Unlock(object);
252     return PR_SUCCESS;
253 }
254 
255 /* this needs more thought on what will happen when there are multiple
256  * instances
257  */
258 NSS_IMPLEMENT PRStatus
nssPKIObject_DeleteStoredObject(nssPKIObject * object,NSSCallback * uhh,PRBool isFriendly)259 nssPKIObject_DeleteStoredObject(
260     nssPKIObject *object,
261     NSSCallback *uhh,
262     PRBool isFriendly)
263 {
264     PRUint32 i, numNotDestroyed;
265     PRStatus status = PR_SUCCESS;
266     numNotDestroyed = 0;
267     nssPKIObject_Lock(object);
268     for (i = 0; i < object->numInstances; i++) {
269         nssCryptokiObject *instance = object->instances[i];
270         status = nssToken_DeleteStoredObject(instance);
271         object->instances[i] = NULL;
272         if (status == PR_SUCCESS) {
273             nssCryptokiObject_Destroy(instance);
274         } else {
275             object->instances[numNotDestroyed++] = instance;
276         }
277     }
278     if (numNotDestroyed == 0) {
279         nss_ZFreeIf(object->instances);
280         object->numInstances = 0;
281     } else {
282         object->numInstances = numNotDestroyed;
283     }
284     nssPKIObject_Unlock(object);
285     return status;
286 }
287 
288 NSS_IMPLEMENT NSSToken **
nssPKIObject_GetTokens(nssPKIObject * object,PRStatus * statusOpt)289 nssPKIObject_GetTokens(
290     nssPKIObject *object,
291     PRStatus *statusOpt)
292 {
293     NSSToken **tokens = NULL;
294     nssPKIObject_Lock(object);
295     if (object->numInstances > 0) {
296         tokens = nss_ZNEWARRAY(NULL, NSSToken *, object->numInstances + 1);
297         if (tokens) {
298             PRUint32 i;
299             for (i = 0; i < object->numInstances; i++) {
300                 tokens[i] = nssToken_AddRef(object->instances[i]->token);
301             }
302         }
303     }
304     nssPKIObject_Unlock(object);
305     if (statusOpt)
306         *statusOpt = PR_SUCCESS; /* until more logic here */
307     return tokens;
308 }
309 
310 NSS_IMPLEMENT NSSUTF8 *
nssPKIObject_GetNicknameForToken(nssPKIObject * object,NSSToken * tokenOpt)311 nssPKIObject_GetNicknameForToken(
312     nssPKIObject *object,
313     NSSToken *tokenOpt)
314 {
315     PRUint32 i;
316     NSSUTF8 *nickname = NULL;
317     nssPKIObject_Lock(object);
318     for (i = 0; i < object->numInstances; i++) {
319         if ((!tokenOpt && object->instances[i]->label) ||
320             (object->instances[i]->token == tokenOpt)) {
321             /* Must copy, see bug 745548 */
322             nickname = nssUTF8_Duplicate(object->instances[i]->label, NULL);
323             break;
324         }
325     }
326     nssPKIObject_Unlock(object);
327     return nickname;
328 }
329 
330 NSS_IMPLEMENT nssCryptokiObject **
nssPKIObject_GetInstances(nssPKIObject * object)331 nssPKIObject_GetInstances(
332     nssPKIObject *object)
333 {
334     nssCryptokiObject **instances = NULL;
335     PRUint32 i;
336     if (object->numInstances == 0) {
337         return (nssCryptokiObject **)NULL;
338     }
339     nssPKIObject_Lock(object);
340     instances = nss_ZNEWARRAY(NULL, nssCryptokiObject *,
341                               object->numInstances + 1);
342     if (instances) {
343         for (i = 0; i < object->numInstances; i++) {
344             instances[i] = nssCryptokiObject_Clone(object->instances[i]);
345         }
346     }
347     nssPKIObject_Unlock(object);
348     return instances;
349 }
350 
351 NSS_IMPLEMENT void
nssCertificateArray_Destroy(NSSCertificate ** certs)352 nssCertificateArray_Destroy(
353     NSSCertificate **certs)
354 {
355     if (certs) {
356         NSSCertificate **certp;
357         for (certp = certs; *certp; certp++) {
358             if ((*certp)->decoding) {
359                 CERTCertificate *cc = STAN_GetCERTCertificate(*certp);
360                 if (cc) {
361                     CERT_DestroyCertificate(cc);
362                 }
363                 continue;
364             }
365             nssCertificate_Destroy(*certp);
366         }
367         nss_ZFreeIf(certs);
368     }
369 }
370 
371 NSS_IMPLEMENT void
NSSCertificateArray_Destroy(NSSCertificate ** certs)372 NSSCertificateArray_Destroy(
373     NSSCertificate **certs)
374 {
375     nssCertificateArray_Destroy(certs);
376 }
377 
378 NSS_IMPLEMENT NSSCertificate **
nssCertificateArray_Join(NSSCertificate ** certs1,NSSCertificate ** certs2)379 nssCertificateArray_Join(
380     NSSCertificate **certs1,
381     NSSCertificate **certs2)
382 {
383     if (certs1 && certs2) {
384         NSSCertificate **certs, **cp;
385         PRUint32 count = 0;
386         PRUint32 count1 = 0;
387         cp = certs1;
388         while (*cp++)
389             count1++;
390         count = count1;
391         cp = certs2;
392         while (*cp++)
393             count++;
394         certs = nss_ZREALLOCARRAY(certs1, NSSCertificate *, count + 1);
395         if (!certs) {
396             nss_ZFreeIf(certs1);
397             nss_ZFreeIf(certs2);
398             return (NSSCertificate **)NULL;
399         }
400         for (cp = certs2; *cp; cp++, count1++) {
401             certs[count1] = *cp;
402         }
403         nss_ZFreeIf(certs2);
404         return certs;
405     } else if (certs1) {
406         return certs1;
407     } else {
408         return certs2;
409     }
410 }
411 
412 NSS_IMPLEMENT NSSCertificate *
nssCertificateArray_FindBestCertificate(NSSCertificate ** certs,NSSTime * timeOpt,const NSSUsage * usage,NSSPolicies * policiesOpt)413 nssCertificateArray_FindBestCertificate(
414     NSSCertificate **certs,
415     NSSTime *timeOpt,
416     const NSSUsage *usage,
417     NSSPolicies *policiesOpt)
418 {
419     NSSCertificate *bestCert = NULL;
420     nssDecodedCert *bestdc = NULL;
421     NSSTime *time, sTime;
422     PRBool bestCertMatches = PR_FALSE;
423     PRBool thisCertMatches;
424     PRBool bestCertIsValidAtTime = PR_FALSE;
425     PRBool bestCertIsTrusted = PR_FALSE;
426 
427     if (timeOpt) {
428         time = timeOpt;
429     } else {
430         NSSTime_Now(&sTime);
431         time = &sTime;
432     }
433     if (!certs) {
434         return (NSSCertificate *)NULL;
435     }
436     for (; *certs; certs++) {
437         nssDecodedCert *dc;
438         NSSCertificate *c = *certs;
439         dc = nssCertificate_GetDecoding(c);
440         if (!dc)
441             continue;
442         thisCertMatches = dc->matchUsage(dc, usage);
443         if (!bestCert) {
444             /* always take the first cert, but remember whether or not
445              * the usage matched
446              */
447             bestCert = nssCertificate_AddRef(c);
448             bestCertMatches = thisCertMatches;
449             bestdc = dc;
450             continue;
451         } else {
452             if (bestCertMatches && !thisCertMatches) {
453                 /* if already have a cert for this usage, and if this cert
454                  * doesn't have the correct usage, continue
455                  */
456                 continue;
457             } else if (!bestCertMatches && thisCertMatches) {
458                 /* this one does match usage, replace the other */
459                 nssCertificate_Destroy(bestCert);
460                 bestCert = nssCertificate_AddRef(c);
461                 bestCertMatches = thisCertMatches;
462                 bestdc = dc;
463                 continue;
464             }
465             /* this cert match as well as any cert we've found so far,
466              * defer to time/policies
467              * */
468         }
469         /* time */
470         if (bestCertIsValidAtTime || bestdc->isValidAtTime(bestdc, time)) {
471             /* The current best cert is valid at time */
472             bestCertIsValidAtTime = PR_TRUE;
473             if (!dc->isValidAtTime(dc, time)) {
474                 /* If the new cert isn't valid at time, it's not better */
475                 continue;
476             }
477         } else {
478             /* The current best cert is not valid at time */
479             if (dc->isValidAtTime(dc, time)) {
480                 /* If the new cert is valid at time, it's better */
481                 nssCertificate_Destroy(bestCert);
482                 bestCert = nssCertificate_AddRef(c);
483                 bestdc = dc;
484                 bestCertIsValidAtTime = PR_TRUE;
485                 continue;
486             }
487         }
488         /* Either they are both valid at time, or neither valid.
489          * If only one is trusted for this usage, take it.
490          */
491         if (bestCertIsTrusted || bestdc->isTrustedForUsage(bestdc, usage)) {
492             bestCertIsTrusted = PR_TRUE;
493             if (!dc->isTrustedForUsage(dc, usage)) {
494                 continue;
495             }
496         } else {
497             /* The current best cert is not trusted */
498             if (dc->isTrustedForUsage(dc, usage)) {
499                 /* If the new cert is trusted, it's better */
500                 nssCertificate_Destroy(bestCert);
501                 bestCert = nssCertificate_AddRef(c);
502                 bestdc = dc;
503                 bestCertIsTrusted = PR_TRUE;
504                 continue;
505             }
506         }
507         /* Otherwise, take the newer one. */
508         if (!bestdc->isNewerThan(bestdc, dc)) {
509             nssCertificate_Destroy(bestCert);
510             bestCert = nssCertificate_AddRef(c);
511             bestdc = dc;
512             continue;
513         }
514         /* policies */
515         /* XXX later -- defer to policies */
516     }
517     return bestCert;
518 }
519 
520 NSS_IMPLEMENT PRStatus
nssCertificateArray_Traverse(NSSCertificate ** certs,PRStatus (* callback)(NSSCertificate * c,void * arg),void * arg)521 nssCertificateArray_Traverse(
522     NSSCertificate **certs,
523     PRStatus (*callback)(NSSCertificate *c, void *arg),
524     void *arg)
525 {
526     PRStatus status = PR_SUCCESS;
527     if (certs) {
528         NSSCertificate **certp;
529         for (certp = certs; *certp; certp++) {
530             status = (*callback)(*certp, arg);
531             if (status != PR_SUCCESS) {
532                 break;
533             }
534         }
535     }
536     return status;
537 }
538 
539 NSS_IMPLEMENT void
nssCRLArray_Destroy(NSSCRL ** crls)540 nssCRLArray_Destroy(
541     NSSCRL **crls)
542 {
543     if (crls) {
544         NSSCRL **crlp;
545         for (crlp = crls; *crlp; crlp++) {
546             nssCRL_Destroy(*crlp);
547         }
548         nss_ZFreeIf(crls);
549     }
550 }
551 
552 /*
553  * Object collections
554  */
555 
556 typedef enum {
557     pkiObjectType_Certificate = 0,
558     pkiObjectType_CRL = 1,
559     pkiObjectType_PrivateKey = 2,
560     pkiObjectType_PublicKey = 3
561 } pkiObjectType;
562 
563 /* Each object is defined by a set of items that uniquely identify it.
564  * Here are the uid sets:
565  *
566  * NSSCertificate ==>  { issuer, serial }
567  * NSSPrivateKey
568  *         (RSA) ==> { modulus, public exponent }
569  *
570  */
571 #define MAX_ITEMS_FOR_UID 2
572 
573 /* pkiObjectCollectionNode
574  *
575  * A node in the collection is the set of unique identifiers for a single
576  * object, along with either the actual object or a proto-object.
577  */
578 typedef struct
579 {
580     PRCList link;
581     PRBool haveObject;
582     nssPKIObject *object;
583     NSSItem uid[MAX_ITEMS_FOR_UID];
584 } pkiObjectCollectionNode;
585 
586 /* nssPKIObjectCollection
587  *
588  * The collection is the set of all objects, plus the interfaces needed
589  * to manage the objects.
590  *
591  */
592 struct nssPKIObjectCollectionStr {
593     NSSArena *arena;
594     NSSTrustDomain *td;
595     NSSCryptoContext *cc;
596     PRCList head; /* list of pkiObjectCollectionNode's */
597     PRUint32 size;
598     pkiObjectType objectType;
599     void (*destroyObject)(nssPKIObject *o);
600     PRStatus (*getUIDFromObject)(nssPKIObject *o, NSSItem *uid);
601     PRStatus (*getUIDFromInstance)(nssCryptokiObject *co, NSSItem *uid,
602                                    NSSArena *arena);
603     nssPKIObject *(*createObject)(nssPKIObject *o);
604     nssPKILockType lockType; /* type of lock to use for new proto-objects */
605 };
606 
607 static nssPKIObjectCollection *
nssPKIObjectCollection_Create(NSSTrustDomain * td,NSSCryptoContext * ccOpt,nssPKILockType lockType)608 nssPKIObjectCollection_Create(
609     NSSTrustDomain *td,
610     NSSCryptoContext *ccOpt,
611     nssPKILockType lockType)
612 {
613     NSSArena *arena;
614     nssPKIObjectCollection *rvCollection = NULL;
615     arena = nssArena_Create();
616     if (!arena) {
617         return (nssPKIObjectCollection *)NULL;
618     }
619     rvCollection = nss_ZNEW(arena, nssPKIObjectCollection);
620     if (!rvCollection) {
621         goto loser;
622     }
623     PR_INIT_CLIST(&rvCollection->head);
624     rvCollection->arena = arena;
625     rvCollection->td = td; /* XXX */
626     rvCollection->cc = ccOpt;
627     rvCollection->lockType = lockType;
628     return rvCollection;
629 loser:
630     nssArena_Destroy(arena);
631     return (nssPKIObjectCollection *)NULL;
632 }
633 
634 NSS_IMPLEMENT void
nssPKIObjectCollection_Destroy(nssPKIObjectCollection * collection)635 nssPKIObjectCollection_Destroy(
636     nssPKIObjectCollection *collection)
637 {
638     if (collection) {
639         PRCList *link;
640         pkiObjectCollectionNode *node;
641         /* first destroy any objects in the collection */
642         link = PR_NEXT_LINK(&collection->head);
643         while (link != &collection->head) {
644             node = (pkiObjectCollectionNode *)link;
645             if (node->haveObject) {
646                 (*collection->destroyObject)(node->object);
647             } else {
648                 nssPKIObject_Destroy(node->object);
649             }
650             link = PR_NEXT_LINK(link);
651         }
652         /* then destroy it */
653         nssArena_Destroy(collection->arena);
654     }
655 }
656 
657 NSS_IMPLEMENT PRUint32
nssPKIObjectCollection_Count(nssPKIObjectCollection * collection)658 nssPKIObjectCollection_Count(
659     nssPKIObjectCollection *collection)
660 {
661     return collection->size;
662 }
663 
664 NSS_IMPLEMENT PRStatus
nssPKIObjectCollection_AddObject(nssPKIObjectCollection * collection,nssPKIObject * object)665 nssPKIObjectCollection_AddObject(
666     nssPKIObjectCollection *collection,
667     nssPKIObject *object)
668 {
669     pkiObjectCollectionNode *node;
670     node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
671     if (!node) {
672         return PR_FAILURE;
673     }
674     node->haveObject = PR_TRUE;
675     node->object = nssPKIObject_AddRef(object);
676     (*collection->getUIDFromObject)(object, node->uid);
677     PR_INIT_CLIST(&node->link);
678     PR_INSERT_BEFORE(&node->link, &collection->head);
679     collection->size++;
680     return PR_SUCCESS;
681 }
682 
683 static pkiObjectCollectionNode *
find_instance_in_collection(nssPKIObjectCollection * collection,nssCryptokiObject * instance)684 find_instance_in_collection(
685     nssPKIObjectCollection *collection,
686     nssCryptokiObject *instance)
687 {
688     PRCList *link;
689     pkiObjectCollectionNode *node;
690     link = PR_NEXT_LINK(&collection->head);
691     while (link != &collection->head) {
692         node = (pkiObjectCollectionNode *)link;
693         if (nssPKIObject_HasInstance(node->object, instance)) {
694             return node;
695         }
696         link = PR_NEXT_LINK(link);
697     }
698     return (pkiObjectCollectionNode *)NULL;
699 }
700 
701 static pkiObjectCollectionNode *
find_object_in_collection(nssPKIObjectCollection * collection,NSSItem * uid)702 find_object_in_collection(
703     nssPKIObjectCollection *collection,
704     NSSItem *uid)
705 {
706     PRUint32 i;
707     PRStatus status;
708     PRCList *link;
709     pkiObjectCollectionNode *node;
710     link = PR_NEXT_LINK(&collection->head);
711     while (link != &collection->head) {
712         node = (pkiObjectCollectionNode *)link;
713         for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
714             if (!nssItem_Equal(&node->uid[i], &uid[i], &status)) {
715                 break;
716             }
717         }
718         if (i == MAX_ITEMS_FOR_UID) {
719             return node;
720         }
721         link = PR_NEXT_LINK(link);
722     }
723     return (pkiObjectCollectionNode *)NULL;
724 }
725 
726 static pkiObjectCollectionNode *
add_object_instance(nssPKIObjectCollection * collection,nssCryptokiObject * instance,PRBool * foundIt)727 add_object_instance(
728     nssPKIObjectCollection *collection,
729     nssCryptokiObject *instance,
730     PRBool *foundIt)
731 {
732     PRUint32 i;
733     PRStatus status;
734     pkiObjectCollectionNode *node;
735     nssArenaMark *mark = NULL;
736     NSSItem uid[MAX_ITEMS_FOR_UID];
737     nsslibc_memset(uid, 0, sizeof uid);
738     /* The list is traversed twice, first (here) looking to match the
739      * { token, handle } tuple, and if that is not found, below a search
740      * for unique identifier is done.  Here, a match means this exact object
741      * instance is already in the collection, and we have nothing to do.
742      */
743     *foundIt = PR_FALSE;
744     node = find_instance_in_collection(collection, instance);
745     if (node) {
746         /* The collection is assumed to take over the instance.  Since we
747          * are not using it, it must be destroyed.
748          */
749         nssCryptokiObject_Destroy(instance);
750         *foundIt = PR_TRUE;
751         return node;
752     }
753     mark = nssArena_Mark(collection->arena);
754     if (!mark) {
755         goto loser;
756     }
757     status = (*collection->getUIDFromInstance)(instance, uid,
758                                                collection->arena);
759     if (status != PR_SUCCESS) {
760         goto loser;
761     }
762     /* Search for unique identifier.  A match here means the object exists
763      * in the collection, but does not have this instance, so the instance
764      * needs to be added.
765      */
766     node = find_object_in_collection(collection, uid);
767     if (node) {
768         /* This is an object with multiple instances */
769         status = nssPKIObject_AddInstance(node->object, instance);
770     } else {
771         /* This is a completely new object.  Create a node for it. */
772         node = nss_ZNEW(collection->arena, pkiObjectCollectionNode);
773         if (!node) {
774             goto loser;
775         }
776         node->object = nssPKIObject_Create(NULL, instance,
777                                            collection->td, collection->cc,
778                                            collection->lockType);
779         if (!node->object) {
780             goto loser;
781         }
782         for (i = 0; i < MAX_ITEMS_FOR_UID; i++) {
783             node->uid[i] = uid[i];
784         }
785         node->haveObject = PR_FALSE;
786         PR_INIT_CLIST(&node->link);
787         PR_INSERT_BEFORE(&node->link, &collection->head);
788         collection->size++;
789         status = PR_SUCCESS;
790     }
791     nssArena_Unmark(collection->arena, mark);
792     return node;
793 loser:
794     if (mark) {
795         nssArena_Release(collection->arena, mark);
796     }
797     nssCryptokiObject_Destroy(instance);
798     return (pkiObjectCollectionNode *)NULL;
799 }
800 
801 NSS_IMPLEMENT PRStatus
nssPKIObjectCollection_AddInstances(nssPKIObjectCollection * collection,nssCryptokiObject ** instances,PRUint32 numInstances)802 nssPKIObjectCollection_AddInstances(
803     nssPKIObjectCollection *collection,
804     nssCryptokiObject **instances,
805     PRUint32 numInstances)
806 {
807     PRStatus status = PR_SUCCESS;
808     PRUint32 i = 0;
809     PRBool foundIt;
810     pkiObjectCollectionNode *node;
811     if (instances) {
812         while ((!numInstances || i < numInstances) && *instances) {
813             if (status == PR_SUCCESS) {
814                 node = add_object_instance(collection, *instances, &foundIt);
815                 if (node == NULL) {
816                     /* add_object_instance freed the current instance */
817                     /* free the remaining instances */
818                     status = PR_FAILURE;
819                 }
820             } else {
821                 nssCryptokiObject_Destroy(*instances);
822             }
823             instances++;
824             i++;
825         }
826     }
827     return status;
828 }
829 
830 static void
nssPKIObjectCollection_RemoveNode(nssPKIObjectCollection * collection,pkiObjectCollectionNode * node)831 nssPKIObjectCollection_RemoveNode(
832     nssPKIObjectCollection *collection,
833     pkiObjectCollectionNode *node)
834 {
835     PR_REMOVE_LINK(&node->link);
836     collection->size--;
837 }
838 
839 static PRStatus
nssPKIObjectCollection_GetObjects(nssPKIObjectCollection * collection,nssPKIObject ** rvObjects,PRUint32 rvSize)840 nssPKIObjectCollection_GetObjects(
841     nssPKIObjectCollection *collection,
842     nssPKIObject **rvObjects,
843     PRUint32 rvSize)
844 {
845     PRUint32 i = 0;
846     PRCList *link = PR_NEXT_LINK(&collection->head);
847     pkiObjectCollectionNode *node;
848     int error = 0;
849     while ((i < rvSize) && (link != &collection->head)) {
850         node = (pkiObjectCollectionNode *)link;
851         if (!node->haveObject) {
852             /* Convert the proto-object to an object */
853             node->object = (*collection->createObject)(node->object);
854             if (!node->object) {
855                 link = PR_NEXT_LINK(link);
856                 /*remove bogus object from list*/
857                 nssPKIObjectCollection_RemoveNode(collection, node);
858                 error++;
859                 continue;
860             }
861             node->haveObject = PR_TRUE;
862         }
863         rvObjects[i++] = nssPKIObject_AddRef(node->object);
864         link = PR_NEXT_LINK(link);
865     }
866     if (!error && *rvObjects == NULL) {
867         nss_SetError(NSS_ERROR_NOT_FOUND);
868     }
869     return PR_SUCCESS;
870 }
871 
872 NSS_IMPLEMENT PRStatus
nssPKIObjectCollection_Traverse(nssPKIObjectCollection * collection,nssPKIObjectCallback * callback)873 nssPKIObjectCollection_Traverse(
874     nssPKIObjectCollection *collection,
875     nssPKIObjectCallback *callback)
876 {
877     PRCList *link = PR_NEXT_LINK(&collection->head);
878     pkiObjectCollectionNode *node;
879     while (link != &collection->head) {
880         node = (pkiObjectCollectionNode *)link;
881         if (!node->haveObject) {
882             node->object = (*collection->createObject)(node->object);
883             if (!node->object) {
884                 link = PR_NEXT_LINK(link);
885                 /*remove bogus object from list*/
886                 nssPKIObjectCollection_RemoveNode(collection, node);
887                 continue;
888             }
889             node->haveObject = PR_TRUE;
890         }
891         switch (collection->objectType) {
892             case pkiObjectType_Certificate:
893                 (void)(*callback->func.cert)((NSSCertificate *)node->object,
894                                              callback->arg);
895                 break;
896             case pkiObjectType_CRL:
897                 (void)(*callback->func.crl)((NSSCRL *)node->object,
898                                             callback->arg);
899                 break;
900             case pkiObjectType_PrivateKey:
901                 (void)(*callback->func.pvkey)((NSSPrivateKey *)node->object,
902                                               callback->arg);
903                 break;
904             case pkiObjectType_PublicKey:
905                 (void)(*callback->func.pbkey)((NSSPublicKey *)node->object,
906                                               callback->arg);
907                 break;
908         }
909         link = PR_NEXT_LINK(link);
910     }
911     return PR_SUCCESS;
912 }
913 
914 NSS_IMPLEMENT PRStatus
nssPKIObjectCollection_AddInstanceAsObject(nssPKIObjectCollection * collection,nssCryptokiObject * instance)915 nssPKIObjectCollection_AddInstanceAsObject(
916     nssPKIObjectCollection *collection,
917     nssCryptokiObject *instance)
918 {
919     pkiObjectCollectionNode *node;
920     PRBool foundIt;
921     node = add_object_instance(collection, instance, &foundIt);
922     if (node == NULL) {
923         return PR_FAILURE;
924     }
925     if (!node->haveObject) {
926         node->object = (*collection->createObject)(node->object);
927         if (!node->object) {
928             /*remove bogus object from list*/
929             nssPKIObjectCollection_RemoveNode(collection, node);
930             return PR_FAILURE;
931         }
932         node->haveObject = PR_TRUE;
933     } else if (!foundIt) {
934         /* The instance was added to a pre-existing node.  This
935          * function is *only* being used for certificates, and having
936          * multiple instances of certs in 3.X requires updating the
937          * CERTCertificate.
938          * But only do it if it was a new instance!!!  If the same instance
939          * is encountered, we set *foundIt to true.  Detect that here and
940          * ignore it.
941          */
942         STAN_ForceCERTCertificateUpdate((NSSCertificate *)node->object);
943     }
944     return PR_SUCCESS;
945 }
946 
947 /*
948  * Certificate collections
949  */
950 
951 static void
cert_destroyObject(nssPKIObject * o)952 cert_destroyObject(nssPKIObject *o)
953 {
954     NSSCertificate *c = (NSSCertificate *)o;
955     if (c->decoding) {
956         CERTCertificate *cc = STAN_GetCERTCertificate(c);
957         if (cc) {
958             CERT_DestroyCertificate(cc);
959             return;
960         } /* else destroy it as NSSCertificate below */
961     }
962     nssCertificate_Destroy(c);
963 }
964 
965 static PRStatus
cert_getUIDFromObject(nssPKIObject * o,NSSItem * uid)966 cert_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
967 {
968     NSSCertificate *c = (NSSCertificate *)o;
969     /* The builtins are still returning decoded serial numbers.  Until
970      * this compatibility issue is resolved, use the full DER of the
971      * cert to uniquely identify it.
972      */
973     NSSDER *derCert;
974     derCert = nssCertificate_GetEncoding(c);
975     uid[0].data = NULL;
976     uid[0].size = 0;
977     uid[1].data = NULL;
978     uid[1].size = 0;
979     if (derCert != NULL) {
980         uid[0] = *derCert;
981     }
982     return PR_SUCCESS;
983 }
984 
985 static PRStatus
cert_getUIDFromInstance(nssCryptokiObject * instance,NSSItem * uid,NSSArena * arena)986 cert_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
987                         NSSArena *arena)
988 {
989     /* The builtins are still returning decoded serial numbers.  Until
990      * this compatibility issue is resolved, use the full DER of the
991      * cert to uniquely identify it.
992      */
993     uid[1].data = NULL;
994     uid[1].size = 0;
995     return nssCryptokiCertificate_GetAttributes(instance,
996                                                 NULL,    /* XXX sessionOpt */
997                                                 arena,   /* arena    */
998                                                 NULL,    /* type     */
999                                                 NULL,    /* id       */
1000                                                 &uid[0], /* encoding */
1001                                                 NULL,    /* issuer   */
1002                                                 NULL,    /* serial   */
1003                                                 NULL);   /* subject  */
1004 }
1005 
1006 static nssPKIObject *
cert_createObject(nssPKIObject * o)1007 cert_createObject(nssPKIObject *o)
1008 {
1009     NSSCertificate *cert;
1010     cert = nssCertificate_Create(o);
1011     /*    if (STAN_GetCERTCertificate(cert) == NULL) {
1012         nssCertificate_Destroy(cert);
1013         return (nssPKIObject *)NULL;
1014     } */
1015     /* In 3.4, have to maintain uniqueness of cert pointers by caching all
1016      * certs.  Cache the cert here, before returning.  If it is already
1017      * cached, take the cached entry.
1018      */
1019     {
1020         NSSTrustDomain *td = o->trustDomain;
1021         nssTrustDomain_AddCertsToCache(td, &cert, 1);
1022     }
1023     return (nssPKIObject *)cert;
1024 }
1025 
1026 NSS_IMPLEMENT nssPKIObjectCollection *
nssCertificateCollection_Create(NSSTrustDomain * td,NSSCertificate ** certsOpt)1027 nssCertificateCollection_Create(
1028     NSSTrustDomain *td,
1029     NSSCertificate **certsOpt)
1030 {
1031     nssPKIObjectCollection *collection;
1032     collection = nssPKIObjectCollection_Create(td, NULL, nssPKIMonitor);
1033     if (!collection) {
1034         return NULL;
1035     }
1036     collection->objectType = pkiObjectType_Certificate;
1037     collection->destroyObject = cert_destroyObject;
1038     collection->getUIDFromObject = cert_getUIDFromObject;
1039     collection->getUIDFromInstance = cert_getUIDFromInstance;
1040     collection->createObject = cert_createObject;
1041     if (certsOpt) {
1042         for (; *certsOpt; certsOpt++) {
1043             nssPKIObject *object = (nssPKIObject *)(*certsOpt);
1044             (void)nssPKIObjectCollection_AddObject(collection, object);
1045         }
1046     }
1047     return collection;
1048 }
1049 
1050 NSS_IMPLEMENT NSSCertificate **
nssPKIObjectCollection_GetCertificates(nssPKIObjectCollection * collection,NSSCertificate ** rvOpt,PRUint32 maximumOpt,NSSArena * arenaOpt)1051 nssPKIObjectCollection_GetCertificates(
1052     nssPKIObjectCollection *collection,
1053     NSSCertificate **rvOpt,
1054     PRUint32 maximumOpt,
1055     NSSArena *arenaOpt)
1056 {
1057     PRStatus status;
1058     PRUint32 rvSize;
1059     PRBool allocated = PR_FALSE;
1060     if (collection->size == 0) {
1061         return (NSSCertificate **)NULL;
1062     }
1063     if (maximumOpt == 0) {
1064         rvSize = collection->size;
1065     } else {
1066         rvSize = PR_MIN(collection->size, maximumOpt);
1067     }
1068     if (!rvOpt) {
1069         rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, rvSize + 1);
1070         if (!rvOpt) {
1071             return (NSSCertificate **)NULL;
1072         }
1073         allocated = PR_TRUE;
1074     }
1075     status = nssPKIObjectCollection_GetObjects(collection,
1076                                                (nssPKIObject **)rvOpt,
1077                                                rvSize);
1078     if (status != PR_SUCCESS) {
1079         if (allocated) {
1080             nss_ZFreeIf(rvOpt);
1081         }
1082         return (NSSCertificate **)NULL;
1083     }
1084     return rvOpt;
1085 }
1086 
1087 /*
1088  * CRL/KRL collections
1089  */
1090 
1091 static void
crl_destroyObject(nssPKIObject * o)1092 crl_destroyObject(nssPKIObject *o)
1093 {
1094     NSSCRL *crl = (NSSCRL *)o;
1095     nssCRL_Destroy(crl);
1096 }
1097 
1098 static PRStatus
crl_getUIDFromObject(nssPKIObject * o,NSSItem * uid)1099 crl_getUIDFromObject(nssPKIObject *o, NSSItem *uid)
1100 {
1101     NSSCRL *crl = (NSSCRL *)o;
1102     NSSDER *encoding;
1103     encoding = nssCRL_GetEncoding(crl);
1104     if (!encoding) {
1105         nss_SetError(NSS_ERROR_INVALID_ARGUMENT);
1106         return PR_FALSE;
1107     }
1108     uid[0] = *encoding;
1109     uid[1].data = NULL;
1110     uid[1].size = 0;
1111     return PR_SUCCESS;
1112 }
1113 
1114 static PRStatus
crl_getUIDFromInstance(nssCryptokiObject * instance,NSSItem * uid,NSSArena * arena)1115 crl_getUIDFromInstance(nssCryptokiObject *instance, NSSItem *uid,
1116                        NSSArena *arena)
1117 {
1118     return nssCryptokiCRL_GetAttributes(instance,
1119                                         NULL,    /* XXX sessionOpt */
1120                                         arena,   /* arena    */
1121                                         &uid[0], /* encoding */
1122                                         NULL,    /* subject  */
1123                                         NULL,    /* class    */
1124                                         NULL,    /* url      */
1125                                         NULL);   /* isKRL    */
1126 }
1127 
1128 static nssPKIObject *
crl_createObject(nssPKIObject * o)1129 crl_createObject(nssPKIObject *o)
1130 {
1131     return (nssPKIObject *)nssCRL_Create(o);
1132 }
1133 
1134 NSS_IMPLEMENT nssPKIObjectCollection *
nssCRLCollection_Create(NSSTrustDomain * td,NSSCRL ** crlsOpt)1135 nssCRLCollection_Create(
1136     NSSTrustDomain *td,
1137     NSSCRL **crlsOpt)
1138 {
1139     nssPKIObjectCollection *collection;
1140     collection = nssPKIObjectCollection_Create(td, NULL, nssPKILock);
1141     if (!collection) {
1142         return NULL;
1143     }
1144     collection->objectType = pkiObjectType_CRL;
1145     collection->destroyObject = crl_destroyObject;
1146     collection->getUIDFromObject = crl_getUIDFromObject;
1147     collection->getUIDFromInstance = crl_getUIDFromInstance;
1148     collection->createObject = crl_createObject;
1149     if (crlsOpt) {
1150         for (; *crlsOpt; crlsOpt++) {
1151             nssPKIObject *object = (nssPKIObject *)(*crlsOpt);
1152             (void)nssPKIObjectCollection_AddObject(collection, object);
1153         }
1154     }
1155     return collection;
1156 }
1157 
1158 NSS_IMPLEMENT NSSCRL **
nssPKIObjectCollection_GetCRLs(nssPKIObjectCollection * collection,NSSCRL ** rvOpt,PRUint32 maximumOpt,NSSArena * arenaOpt)1159 nssPKIObjectCollection_GetCRLs(
1160     nssPKIObjectCollection *collection,
1161     NSSCRL **rvOpt,
1162     PRUint32 maximumOpt,
1163     NSSArena *arenaOpt)
1164 {
1165     PRStatus status;
1166     PRUint32 rvSize;
1167     PRBool allocated = PR_FALSE;
1168     if (collection->size == 0) {
1169         return (NSSCRL **)NULL;
1170     }
1171     if (maximumOpt == 0) {
1172         rvSize = collection->size;
1173     } else {
1174         rvSize = PR_MIN(collection->size, maximumOpt);
1175     }
1176     if (!rvOpt) {
1177         rvOpt = nss_ZNEWARRAY(arenaOpt, NSSCRL *, rvSize + 1);
1178         if (!rvOpt) {
1179             return (NSSCRL **)NULL;
1180         }
1181         allocated = PR_TRUE;
1182     }
1183     status = nssPKIObjectCollection_GetObjects(collection,
1184                                                (nssPKIObject **)rvOpt,
1185                                                rvSize);
1186     if (status != PR_SUCCESS) {
1187         if (allocated) {
1188             nss_ZFreeIf(rvOpt);
1189         }
1190         return (NSSCRL **)NULL;
1191     }
1192     return rvOpt;
1193 }
1194 
1195 /* how bad would it be to have a static now sitting around, updated whenever
1196  * this was called?  would avoid repeated allocs...
1197  */
1198 NSS_IMPLEMENT NSSTime *
NSSTime_Now(NSSTime * timeOpt)1199 NSSTime_Now(NSSTime *timeOpt)
1200 {
1201     return NSSTime_SetPRTime(timeOpt, PR_Now());
1202 }
1203 
1204 NSS_IMPLEMENT NSSTime *
NSSTime_SetPRTime(NSSTime * timeOpt,PRTime prTime)1205 NSSTime_SetPRTime(
1206     NSSTime *timeOpt,
1207     PRTime prTime)
1208 {
1209     NSSTime *rvTime;
1210     rvTime = (timeOpt) ? timeOpt : nss_ZNEW(NULL, NSSTime);
1211     if (rvTime) {
1212         rvTime->prTime = prTime;
1213     }
1214     return rvTime;
1215 }
1216 
1217 NSS_IMPLEMENT PRTime
NSSTime_GetPRTime(NSSTime * time)1218 NSSTime_GetPRTime(
1219     NSSTime *time)
1220 {
1221     return time->prTime;
1222 }
1223