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