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