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