comparison nss/lib/pki/tdcache.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 PKIM_H
6 #include "pkim.h"
7 #endif /* PKIM_H */
8
9 #ifndef PKIT_H
10 #include "pkit.h"
11 #endif /* PKIT_H */
12
13 #ifndef NSSPKI_H
14 #include "nsspki.h"
15 #endif /* NSSPKI_H */
16
17 #ifndef PKI_H
18 #include "pki.h"
19 #endif /* PKI_H */
20
21 #ifndef NSSBASE_H
22 #include "nssbase.h"
23 #endif /* NSSBASE_H */
24
25 #ifndef BASE_H
26 #include "base.h"
27 #endif /* BASE_H */
28
29 #include "cert.h"
30 #include "dev.h"
31 #include "pki3hack.h"
32
33 #ifdef DEBUG_CACHE
34 static PRLogModuleInfo *s_log = NULL;
35 #endif
36
37 #ifdef DEBUG_CACHE
38 static void log_item_dump(const char *msg, NSSItem *it)
39 {
40 char buf[33];
41 int i, j;
42 for (i=0; i<10 && i<it->size; i++) {
43 sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]);
44 }
45 if (it->size>10) {
46 sprintf(&buf[2*i], "..");
47 i += 1;
48 for (j=it->size-1; i<=16 && j>10; i++, j--) {
49 sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]);
50 }
51 }
52 PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
53 }
54 #endif
55
56 #ifdef DEBUG_CACHE
57 static void log_cert_ref(const char *msg, NSSCertificate *c)
58 {
59 PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg,
60 (c->nickname) ? c->nickname : c->email));
61 log_item_dump("\tserial", &c->serial);
62 log_item_dump("\tsubject", &c->subject);
63 }
64 #endif
65
66 /* Certificate cache routines */
67
68 /* XXX
69 * Locking is not handled well at all. A single, global lock with sub-locks
70 * in the collection types. Cleanup needed.
71 */
72
73 /* should it live in its own arena? */
74 struct nssTDCertificateCacheStr
75 {
76 PZLock *lock;
77 NSSArena *arena;
78 nssHash *issuerAndSN;
79 nssHash *subject;
80 nssHash *nickname;
81 nssHash *email;
82 };
83
84 struct cache_entry_str
85 {
86 union {
87 NSSCertificate *cert;
88 nssList *list;
89 void *value;
90 } entry;
91 PRUint32 hits;
92 PRTime lastHit;
93 NSSArena *arena;
94 NSSUTF8 *nickname;
95 };
96
97 typedef struct cache_entry_str cache_entry;
98
99 static cache_entry *
100 new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
101 {
102 cache_entry *ce = nss_ZNEW(arena, cache_entry);
103 if (ce) {
104 ce->entry.value = value;
105 ce->hits = 1;
106 ce->lastHit = PR_Now();
107 if (ownArena) {
108 ce->arena = arena;
109 }
110 ce->nickname = NULL;
111 }
112 return ce;
113 }
114
115 /* this should not be exposed in a header, but is here to keep the above
116 * types/functions static
117 */
118 NSS_IMPLEMENT PRStatus
119 nssTrustDomain_InitializeCache (
120 NSSTrustDomain *td,
121 PRUint32 cacheSize
122 )
123 {
124 NSSArena *arena;
125 nssTDCertificateCache *cache = td->cache;
126 #ifdef DEBUG_CACHE
127 s_log = PR_NewLogModule("nss_cache");
128 PR_ASSERT(s_log);
129 #endif
130 PR_ASSERT(!cache);
131 arena = nssArena_Create();
132 if (!arena) {
133 return PR_FAILURE;
134 }
135 cache = nss_ZNEW(arena, nssTDCertificateCache);
136 if (!cache) {
137 nssArena_Destroy(arena);
138 return PR_FAILURE;
139 }
140 cache->lock = PZ_NewLock(nssILockCache);
141 if (!cache->lock) {
142 nssArena_Destroy(arena);
143 return PR_FAILURE;
144 }
145 /* Create the issuer and serial DER --> certificate hash */
146 cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
147 if (!cache->issuerAndSN) {
148 goto loser;
149 }
150 /* Create the subject DER --> subject list hash */
151 cache->subject = nssHash_CreateItem(arena, cacheSize);
152 if (!cache->subject) {
153 goto loser;
154 }
155 /* Create the nickname --> subject list hash */
156 cache->nickname = nssHash_CreateString(arena, cacheSize);
157 if (!cache->nickname) {
158 goto loser;
159 }
160 /* Create the email --> list of subject lists hash */
161 cache->email = nssHash_CreateString(arena, cacheSize);
162 if (!cache->email) {
163 goto loser;
164 }
165 cache->arena = arena;
166 td->cache = cache;
167 #ifdef DEBUG_CACHE
168 PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
169 #endif
170 return PR_SUCCESS;
171 loser:
172 PZ_DestroyLock(cache->lock);
173 nssArena_Destroy(arena);
174 td->cache = NULL;
175 #ifdef DEBUG_CACHE
176 PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
177 #endif
178 return PR_FAILURE;
179 }
180
181 /* The entries of the hashtable are currently dependent on the certificate(s)
182 * that produced them. That is, the entries will be freed when the cert is
183 * released from the cache. If there are certs in the cache at any time,
184 * including shutdown, the hash table entries will hold memory. In order for
185 * clean shutdown, it is necessary for there to be no certs in the cache.
186 */
187
188 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
189 extern const NSSError NSS_ERROR_BUSY;
190
191 NSS_IMPLEMENT PRStatus
192 nssTrustDomain_DestroyCache (
193 NSSTrustDomain *td
194 )
195 {
196 if (!td->cache) {
197 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
198 return PR_FAILURE;
199 }
200 if (nssHash_Count(td->cache->issuerAndSN) > 0) {
201 nss_SetError(NSS_ERROR_BUSY);
202 return PR_FAILURE;
203 }
204 PZ_DestroyLock(td->cache->lock);
205 nssHash_Destroy(td->cache->issuerAndSN);
206 nssHash_Destroy(td->cache->subject);
207 nssHash_Destroy(td->cache->nickname);
208 nssHash_Destroy(td->cache->email);
209 nssArena_Destroy(td->cache->arena);
210 td->cache = NULL;
211 #ifdef DEBUG_CACHE
212 PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
213 #endif
214 return PR_SUCCESS;
215 }
216
217 static PRStatus
218 remove_issuer_and_serial_entry (
219 nssTDCertificateCache *cache,
220 NSSCertificate *cert
221 )
222 {
223 /* Remove the cert from the issuer/serial hash */
224 nssHash_Remove(cache->issuerAndSN, cert);
225 #ifdef DEBUG_CACHE
226 log_cert_ref("removed issuer/sn", cert);
227 #endif
228 return PR_SUCCESS;
229 }
230
231 static PRStatus
232 remove_subject_entry (
233 nssTDCertificateCache *cache,
234 NSSCertificate *cert,
235 nssList **subjectList,
236 NSSUTF8 **nickname,
237 NSSArena **arena
238 )
239 {
240 PRStatus nssrv;
241 cache_entry *ce;
242 *subjectList = NULL;
243 *arena = NULL;
244 /* Get the subject list for the cert's subject */
245 ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
246 if (ce) {
247 /* Remove the cert from the subject hash */
248 nssList_Remove(ce->entry.list, cert);
249 *subjectList = ce->entry.list;
250 *nickname = ce->nickname;
251 *arena = ce->arena;
252 nssrv = PR_SUCCESS;
253 #ifdef DEBUG_CACHE
254 log_cert_ref("removed cert", cert);
255 log_item_dump("from subject list", &cert->subject);
256 #endif
257 } else {
258 nssrv = PR_FAILURE;
259 }
260 return nssrv;
261 }
262
263 static PRStatus
264 remove_nickname_entry (
265 nssTDCertificateCache *cache,
266 NSSUTF8 *nickname,
267 nssList *subjectList
268 )
269 {
270 PRStatus nssrv;
271 if (nickname) {
272 nssHash_Remove(cache->nickname, nickname);
273 nssrv = PR_SUCCESS;
274 #ifdef DEBUG_CACHE
275 PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
276 #endif
277 } else {
278 nssrv = PR_FAILURE;
279 }
280 return nssrv;
281 }
282
283 static PRStatus
284 remove_email_entry (
285 nssTDCertificateCache *cache,
286 NSSCertificate *cert,
287 nssList *subjectList
288 )
289 {
290 PRStatus nssrv = PR_FAILURE;
291 cache_entry *ce;
292 /* Find the subject list in the email hash */
293 if (cert->email) {
294 ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
295 if (ce) {
296 nssList *subjects = ce->entry.list;
297 /* Remove the subject list from the email hash */
298 nssList_Remove(subjects, subjectList);
299 #ifdef DEBUG_CACHE
300 log_item_dump("removed subject list", &cert->subject);
301 PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
302 #endif
303 if (nssList_Count(subjects) == 0) {
304 /* No more subject lists for email, delete list and
305 * remove hash entry
306 */
307 (void)nssList_Destroy(subjects);
308 nssHash_Remove(cache->email, cert->email);
309 /* there are no entries left for this address, free space
310 * used for email entries
311 */
312 nssArena_Destroy(ce->arena);
313 #ifdef DEBUG_CACHE
314 PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
315 #endif
316 }
317 nssrv = PR_SUCCESS;
318 }
319 }
320 return nssrv;
321 }
322
323 NSS_IMPLEMENT void
324 nssTrustDomain_RemoveCertFromCacheLOCKED (
325 NSSTrustDomain *td,
326 NSSCertificate *cert
327 )
328 {
329 nssList *subjectList;
330 cache_entry *ce;
331 NSSArena *arena;
332 NSSUTF8 *nickname;
333
334 #ifdef DEBUG_CACHE
335 log_cert_ref("attempt to remove cert", cert);
336 #endif
337 ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
338 if (!ce || ce->entry.cert != cert) {
339 /* If it's not in the cache, or a different cert is (this is really
340 * for safety reasons, though it shouldn't happen), do nothing
341 */
342 #ifdef DEBUG_CACHE
343 PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
344 #endif
345 return;
346 }
347 (void)remove_issuer_and_serial_entry(td->cache, cert);
348 (void)remove_subject_entry(td->cache, cert, &subjectList,
349 &nickname, &arena);
350 if (nssList_Count(subjectList) == 0) {
351 (void)remove_nickname_entry(td->cache, nickname, subjectList);
352 (void)remove_email_entry(td->cache, cert, subjectList);
353 (void)nssList_Destroy(subjectList);
354 nssHash_Remove(td->cache->subject, &cert->subject);
355 /* there are no entries left for this subject, free the space used
356 * for both the nickname and subject entries
357 */
358 if (arena) {
359 nssArena_Destroy(arena);
360 }
361 }
362 }
363
364 NSS_IMPLEMENT void
365 nssTrustDomain_LockCertCache (
366 NSSTrustDomain *td
367 )
368 {
369 PZ_Lock(td->cache->lock);
370 }
371
372 NSS_IMPLEMENT void
373 nssTrustDomain_UnlockCertCache (
374 NSSTrustDomain *td
375 )
376 {
377 PZ_Unlock(td->cache->lock);
378 }
379
380 struct token_cert_dtor {
381 NSSToken *token;
382 nssTDCertificateCache *cache;
383 NSSCertificate **certs;
384 PRUint32 numCerts, arrSize;
385 };
386
387 static void
388 remove_token_certs(const void *k, void *v, void *a)
389 {
390 NSSCertificate *c = (NSSCertificate *)k;
391 nssPKIObject *object = &c->object;
392 struct token_cert_dtor *dtor = a;
393 PRUint32 i;
394 nssPKIObject_Lock(object);
395 for (i=0; i<object->numInstances; i++) {
396 if (object->instances[i]->token == dtor->token) {
397 nssCryptokiObject_Destroy(object->instances[i]);
398 object->instances[i] = object->instances[object->numInstances-1];
399 object->instances[object->numInstances-1] = NULL;
400 object->numInstances--;
401 dtor->certs[dtor->numCerts++] = c;
402 if (dtor->numCerts == dtor->arrSize) {
403 dtor->arrSize *= 2;
404 dtor->certs = nss_ZREALLOCARRAY(dtor->certs,
405 NSSCertificate *,
406 dtor->arrSize);
407 }
408 break;
409 }
410 }
411 nssPKIObject_Unlock(object);
412 return;
413 }
414
415 /*
416 * Remove all certs for the given token from the cache. This is
417 * needed if the token is removed.
418 */
419 NSS_IMPLEMENT PRStatus
420 nssTrustDomain_RemoveTokenCertsFromCache (
421 NSSTrustDomain *td,
422 NSSToken *token
423 )
424 {
425 NSSCertificate **certs;
426 PRUint32 i, arrSize = 10;
427 struct token_cert_dtor dtor;
428 certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
429 if (!certs) {
430 return PR_FAILURE;
431 }
432 dtor.cache = td->cache;
433 dtor.token = token;
434 dtor.certs = certs;
435 dtor.numCerts = 0;
436 dtor.arrSize = arrSize;
437 PZ_Lock(td->cache->lock);
438 nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, (void *)&dtor);
439 for (i=0; i<dtor.numCerts; i++) {
440 if (dtor.certs[i]->object.numInstances == 0) {
441 nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
442 dtor.certs[i] = NULL; /* skip this cert in the second for loop */
443 }
444 }
445 PZ_Unlock(td->cache->lock);
446 for (i=0; i<dtor.numCerts; i++) {
447 if (dtor.certs[i]) {
448 STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
449 }
450 }
451 nss_ZFreeIf(dtor.certs);
452 return PR_SUCCESS;
453 }
454
455 NSS_IMPLEMENT PRStatus
456 nssTrustDomain_UpdateCachedTokenCerts (
457 NSSTrustDomain *td,
458 NSSToken *token
459 )
460 {
461 NSSCertificate **cp, **cached = NULL;
462 nssList *certList;
463 PRUint32 count;
464 certList = nssList_Create(NULL, PR_FALSE);
465 if (!certList) return PR_FAILURE;
466 (void)nssTrustDomain_GetCertsFromCache(td, certList);
467 count = nssList_Count(certList);
468 if (count > 0) {
469 cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
470 if (!cached) {
471 nssList_Destroy(certList);
472 return PR_FAILURE;
473 }
474 nssList_GetArray(certList, (void **)cached, count);
475 for (cp = cached; *cp; cp++) {
476 nssCryptokiObject *instance;
477 NSSCertificate *c = *cp;
478 nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
479 instance = nssToken_FindCertificateByIssuerAndSerialNumber(
480 token,
481 NULL,
482 &c->issuer,
483 &c->serial,
484 tokenOnly,
485 NULL);
486 if (instance) {
487 nssPKIObject_AddInstance(&c->object, instance);
488 STAN_ForceCERTCertificateUpdate(c);
489 }
490 }
491 nssCertificateArray_Destroy(cached);
492 }
493 nssList_Destroy(certList);
494 return PR_SUCCESS;
495 }
496
497 static PRStatus
498 add_issuer_and_serial_entry (
499 NSSArena *arena,
500 nssTDCertificateCache *cache,
501 NSSCertificate *cert
502 )
503 {
504 cache_entry *ce;
505 ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
506 #ifdef DEBUG_CACHE
507 log_cert_ref("added to issuer/sn", cert);
508 #endif
509 return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
510 }
511
512 static PRStatus
513 add_subject_entry (
514 NSSArena *arena,
515 nssTDCertificateCache *cache,
516 NSSCertificate *cert,
517 NSSUTF8 *nickname,
518 nssList **subjectList
519 )
520 {
521 PRStatus nssrv;
522 nssList *list;
523 cache_entry *ce;
524 *subjectList = NULL; /* this is only set if a new one is created */
525 ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
526 if (ce) {
527 ce->hits++;
528 ce->lastHit = PR_Now();
529 /* The subject is already in, add this cert to the list */
530 nssrv = nssList_AddUnique(ce->entry.list, cert);
531 #ifdef DEBUG_CACHE
532 log_cert_ref("added to existing subject list", cert);
533 #endif
534 } else {
535 NSSDER *subject;
536 /* Create a new subject list for the subject */
537 list = nssList_Create(arena, PR_FALSE);
538 if (!list) {
539 return PR_FAILURE;
540 }
541 ce = new_cache_entry(arena, (void *)list, PR_TRUE);
542 if (!ce) {
543 return PR_FAILURE;
544 }
545 if (nickname) {
546 ce->nickname = nssUTF8_Duplicate(nickname, arena);
547 }
548 nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
549 /* Add the cert entry to this list of subjects */
550 nssrv = nssList_AddUnique(list, cert);
551 if (nssrv != PR_SUCCESS) {
552 return nssrv;
553 }
554 /* Add the subject list to the cache */
555 subject = nssItem_Duplicate(&cert->subject, arena, NULL);
556 if (!subject) {
557 return PR_FAILURE;
558 }
559 nssrv = nssHash_Add(cache->subject, subject, ce);
560 if (nssrv != PR_SUCCESS) {
561 return nssrv;
562 }
563 *subjectList = list;
564 #ifdef DEBUG_CACHE
565 log_cert_ref("created subject list", cert);
566 #endif
567 }
568 return nssrv;
569 }
570
571 static PRStatus
572 add_nickname_entry (
573 NSSArena *arena,
574 nssTDCertificateCache *cache,
575 NSSUTF8 *certNickname,
576 nssList *subjectList
577 )
578 {
579 PRStatus nssrv = PR_SUCCESS;
580 cache_entry *ce;
581 ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
582 if (ce) {
583 /* This is a collision. A nickname entry already exists for this
584 * subject, but a subject entry didn't. This would imply there are
585 * two subjects using the same nickname, which is not allowed.
586 */
587 return PR_FAILURE;
588 } else {
589 NSSUTF8 *nickname;
590 ce = new_cache_entry(arena, subjectList, PR_FALSE);
591 if (!ce) {
592 return PR_FAILURE;
593 }
594 nickname = nssUTF8_Duplicate(certNickname, arena);
595 if (!nickname) {
596 return PR_FAILURE;
597 }
598 nssrv = nssHash_Add(cache->nickname, nickname, ce);
599 #ifdef DEBUG_CACHE
600 log_cert_ref("created nickname for", cert);
601 #endif
602 }
603 return nssrv;
604 }
605
606 static PRStatus
607 add_email_entry (
608 nssTDCertificateCache *cache,
609 NSSCertificate *cert,
610 nssList *subjectList
611 )
612 {
613 PRStatus nssrv = PR_SUCCESS;
614 nssList *subjects;
615 cache_entry *ce;
616 ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
617 if (ce) {
618 /* Already have an entry for this email address, but not subject */
619 subjects = ce->entry.list;
620 nssrv = nssList_AddUnique(subjects, subjectList);
621 ce->hits++;
622 ce->lastHit = PR_Now();
623 #ifdef DEBUG_CACHE
624 log_cert_ref("added subject to email for", cert);
625 #endif
626 } else {
627 NSSASCII7 *email;
628 NSSArena *arena;
629 arena = nssArena_Create();
630 if (!arena) {
631 return PR_FAILURE;
632 }
633 /* Create a new list of subject lists, add this subject */
634 subjects = nssList_Create(arena, PR_TRUE);
635 if (!subjects) {
636 nssArena_Destroy(arena);
637 return PR_FAILURE;
638 }
639 /* Add the new subject to the list */
640 nssrv = nssList_AddUnique(subjects, subjectList);
641 if (nssrv != PR_SUCCESS) {
642 nssArena_Destroy(arena);
643 return nssrv;
644 }
645 /* Add the new entry to the cache */
646 ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
647 if (!ce) {
648 nssArena_Destroy(arena);
649 return PR_FAILURE;
650 }
651 email = nssUTF8_Duplicate(cert->email, arena);
652 if (!email) {
653 nssArena_Destroy(arena);
654 return PR_FAILURE;
655 }
656 nssrv = nssHash_Add(cache->email, email, ce);
657 if (nssrv != PR_SUCCESS) {
658 nssArena_Destroy(arena);
659 return nssrv;
660 }
661 #ifdef DEBUG_CACHE
662 log_cert_ref("created email for", cert);
663 #endif
664 }
665 return nssrv;
666 }
667
668 extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
669
670 static void
671 remove_object_instances (
672 nssPKIObject *object,
673 nssCryptokiObject **instances,
674 int numInstances
675 )
676 {
677 int i;
678
679 for (i = 0; i < numInstances; i++) {
680 nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
681 }
682 }
683
684 static SECStatus
685 merge_object_instances (
686 nssPKIObject *to,
687 nssPKIObject *from
688 )
689 {
690 nssCryptokiObject **instances, **ci;
691 int i;
692 SECStatus rv = SECSuccess;
693
694 instances = nssPKIObject_GetInstances(from);
695 if (instances == NULL) {
696 return SECFailure;
697 }
698 for (ci = instances, i = 0; *ci; ci++, i++) {
699 nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
700 if (instance) {
701 if (nssPKIObject_AddInstance(to, instance) == PR_SUCCESS) {
702 continue;
703 }
704 nssCryptokiObject_Destroy(instance);
705 }
706 remove_object_instances(to, instances, i);
707 rv = SECFailure;
708 break;
709 }
710 nssCryptokiObjectArray_Destroy(instances);
711 return rv;
712 }
713
714 static NSSCertificate *
715 add_cert_to_cache (
716 NSSTrustDomain *td,
717 NSSCertificate *cert
718 )
719 {
720 NSSArena *arena = NULL;
721 nssList *subjectList = NULL;
722 PRStatus nssrv;
723 PRUint32 added = 0;
724 cache_entry *ce;
725 NSSCertificate *rvCert = NULL;
726 NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
727
728 PZ_Lock(td->cache->lock);
729 /* If it exists in the issuer/serial hash, it's already in all */
730 ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
731 if (ce) {
732 ce->hits++;
733 ce->lastHit = PR_Now();
734 rvCert = nssCertificate_AddRef(ce->entry.cert);
735 #ifdef DEBUG_CACHE
736 log_cert_ref("attempted to add cert already in cache", cert);
737 #endif
738 PZ_Unlock(td->cache->lock);
739 nss_ZFreeIf(certNickname);
740 /* collision - somebody else already added the cert
741 * to the cache before this thread got around to it.
742 */
743 /* merge the instances of the cert */
744 if (merge_object_instances(&rvCert->object, &cert->object)
745 != SECSuccess) {
746 nssCertificate_Destroy(rvCert);
747 return NULL;
748 }
749 STAN_ForceCERTCertificateUpdate(rvCert);
750 nssCertificate_Destroy(cert);
751 return rvCert;
752 }
753 /* create a new cache entry for this cert within the cert's arena*/
754 nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
755 if (nssrv != PR_SUCCESS) {
756 goto loser;
757 }
758 added++;
759 /* create an arena for the nickname and subject entries */
760 arena = nssArena_Create();
761 if (!arena) {
762 goto loser;
763 }
764 /* create a new subject list for this cert, or add to existing */
765 nssrv = add_subject_entry(arena, td->cache, cert,
766 certNickname, &subjectList);
767 if (nssrv != PR_SUCCESS) {
768 goto loser;
769 }
770 added++;
771 /* If a new subject entry was created, also need nickname and/or email */
772 if (subjectList != NULL) {
773 PRBool handle = PR_FALSE;
774 if (certNickname) {
775 nssrv = add_nickname_entry(arena, td->cache,
776 certNickname, subjectList);
777 if (nssrv != PR_SUCCESS) {
778 goto loser;
779 }
780 handle = PR_TRUE;
781 added++;
782 }
783 if (cert->email) {
784 nssrv = add_email_entry(td->cache, cert, subjectList);
785 if (nssrv != PR_SUCCESS) {
786 goto loser;
787 }
788 handle = PR_TRUE;
789 added += 2;
790 }
791 #ifdef nodef
792 /* I think either a nickname or email address must be associated
793 * with the cert. However, certs are passed to NewTemp without
794 * either. This worked in the old code, so it must work now.
795 */
796 if (!handle) {
797 /* Require either nickname or email handle */
798 nssrv = PR_FAILURE;
799 goto loser;
800 }
801 #endif
802 } else {
803 /* A new subject entry was not created. arena is unused. */
804 nssArena_Destroy(arena);
805 }
806 rvCert = cert;
807 PZ_Unlock(td->cache->lock);
808 nss_ZFreeIf(certNickname);
809 return rvCert;
810 loser:
811 nss_ZFreeIf(certNickname);
812 certNickname = NULL;
813 /* Remove any handles that have been created */
814 subjectList = NULL;
815 if (added >= 1) {
816 (void)remove_issuer_and_serial_entry(td->cache, cert);
817 }
818 if (added >= 2) {
819 (void)remove_subject_entry(td->cache, cert, &subjectList,
820 &certNickname, &arena);
821 }
822 if (added == 3 || added == 5) {
823 (void)remove_nickname_entry(td->cache, certNickname, subjectList);
824 }
825 if (added >= 4) {
826 (void)remove_email_entry(td->cache, cert, subjectList);
827 }
828 if (subjectList) {
829 nssHash_Remove(td->cache->subject, &cert->subject);
830 nssList_Destroy(subjectList);
831 }
832 if (arena) {
833 nssArena_Destroy(arena);
834 }
835 PZ_Unlock(td->cache->lock);
836 return NULL;
837 }
838
839 NSS_IMPLEMENT PRStatus
840 nssTrustDomain_AddCertsToCache (
841 NSSTrustDomain *td,
842 NSSCertificate **certs,
843 PRUint32 numCerts
844 )
845 {
846 PRUint32 i;
847 NSSCertificate *c;
848 for (i=0; i<numCerts && certs[i]; i++) {
849 c = add_cert_to_cache(td, certs[i]);
850 if (c == NULL) {
851 return PR_FAILURE;
852 } else {
853 certs[i] = c;
854 }
855 }
856 return PR_SUCCESS;
857 }
858
859 static NSSCertificate **
860 collect_subject_certs (
861 nssList *subjectList,
862 nssList *rvCertListOpt
863 )
864 {
865 NSSCertificate *c;
866 NSSCertificate **rvArray = NULL;
867 PRUint32 count;
868 nssCertificateList_AddReferences(subjectList);
869 if (rvCertListOpt) {
870 nssListIterator *iter = nssList_CreateIterator(subjectList);
871 if (!iter) {
872 return (NSSCertificate **)NULL;
873 }
874 for (c = (NSSCertificate *)nssListIterator_Start(iter);
875 c != (NSSCertificate *)NULL;
876 c = (NSSCertificate *)nssListIterator_Next(iter)) {
877 nssList_Add(rvCertListOpt, c);
878 }
879 nssListIterator_Finish(iter);
880 nssListIterator_Destroy(iter);
881 } else {
882 count = nssList_Count(subjectList);
883 rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
884 if (!rvArray) {
885 return (NSSCertificate **)NULL;
886 }
887 nssList_GetArray(subjectList, (void **)rvArray, count);
888 }
889 return rvArray;
890 }
891
892 /*
893 * Find all cached certs with this subject.
894 */
895 NSS_IMPLEMENT NSSCertificate **
896 nssTrustDomain_GetCertsForSubjectFromCache (
897 NSSTrustDomain *td,
898 NSSDER *subject,
899 nssList *certListOpt
900 )
901 {
902 NSSCertificate **rvArray = NULL;
903 cache_entry *ce;
904 #ifdef DEBUG_CACHE
905 log_item_dump("looking for cert by subject", subject);
906 #endif
907 PZ_Lock(td->cache->lock);
908 ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
909 if (ce) {
910 ce->hits++;
911 ce->lastHit = PR_Now();
912 #ifdef DEBUG_CACHE
913 PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
914 #endif
915 rvArray = collect_subject_certs(ce->entry.list, certListOpt);
916 }
917 PZ_Unlock(td->cache->lock);
918 return rvArray;
919 }
920
921 /*
922 * Find all cached certs with this label.
923 */
924 NSS_IMPLEMENT NSSCertificate **
925 nssTrustDomain_GetCertsForNicknameFromCache (
926 NSSTrustDomain *td,
927 const NSSUTF8 *nickname,
928 nssList *certListOpt
929 )
930 {
931 NSSCertificate **rvArray = NULL;
932 cache_entry *ce;
933 #ifdef DEBUG_CACHE
934 PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
935 #endif
936 PZ_Lock(td->cache->lock);
937 ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
938 if (ce) {
939 ce->hits++;
940 ce->lastHit = PR_Now();
941 #ifdef DEBUG_CACHE
942 PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
943 #endif
944 rvArray = collect_subject_certs(ce->entry.list, certListOpt);
945 }
946 PZ_Unlock(td->cache->lock);
947 return rvArray;
948 }
949
950 /*
951 * Find all cached certs with this email address.
952 */
953 NSS_IMPLEMENT NSSCertificate **
954 nssTrustDomain_GetCertsForEmailAddressFromCache (
955 NSSTrustDomain *td,
956 NSSASCII7 *email,
957 nssList *certListOpt
958 )
959 {
960 NSSCertificate **rvArray = NULL;
961 cache_entry *ce;
962 nssList *collectList = NULL;
963 nssListIterator *iter = NULL;
964 nssList *subjectList;
965 #ifdef DEBUG_CACHE
966 PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
967 #endif
968 PZ_Lock(td->cache->lock);
969 ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
970 if (ce) {
971 ce->hits++;
972 ce->lastHit = PR_Now();
973 #ifdef DEBUG_CACHE
974 PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
975 #endif
976 /* loop over subject lists and get refs for certs */
977 if (certListOpt) {
978 collectList = certListOpt;
979 } else {
980 collectList = nssList_Create(NULL, PR_FALSE);
981 if (!collectList) {
982 PZ_Unlock(td->cache->lock);
983 return NULL;
984 }
985 }
986 iter = nssList_CreateIterator(ce->entry.list);
987 if (!iter) {
988 PZ_Unlock(td->cache->lock);
989 if (!certListOpt) {
990 nssList_Destroy(collectList);
991 }
992 return NULL;
993 }
994 for (subjectList = (nssList *)nssListIterator_Start(iter);
995 subjectList != (nssList *)NULL;
996 subjectList = (nssList *)nssListIterator_Next(iter)) {
997 (void)collect_subject_certs(subjectList, collectList);
998 }
999 nssListIterator_Finish(iter);
1000 nssListIterator_Destroy(iter);
1001 }
1002 PZ_Unlock(td->cache->lock);
1003 if (!certListOpt && collectList) {
1004 PRUint32 count = nssList_Count(collectList);
1005 rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
1006 if (rvArray) {
1007 nssList_GetArray(collectList, (void **)rvArray, count);
1008 }
1009 nssList_Destroy(collectList);
1010 }
1011 return rvArray;
1012 }
1013
1014 /*
1015 * Look for a specific cert in the cache
1016 */
1017 NSS_IMPLEMENT NSSCertificate *
1018 nssTrustDomain_GetCertForIssuerAndSNFromCache (
1019 NSSTrustDomain *td,
1020 NSSDER *issuer,
1021 NSSDER *serial
1022 )
1023 {
1024 NSSCertificate certkey;
1025 NSSCertificate *rvCert = NULL;
1026 cache_entry *ce;
1027 certkey.issuer.data = issuer->data;
1028 certkey.issuer.size = issuer->size;
1029 certkey.serial.data = serial->data;
1030 certkey.serial.size = serial->size;
1031 #ifdef DEBUG_CACHE
1032 log_item_dump("looking for cert by issuer/sn, issuer", issuer);
1033 log_item_dump(" serial", serial);
1034 #endif
1035 PZ_Lock(td->cache->lock);
1036 ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
1037 if (ce) {
1038 ce->hits++;
1039 ce->lastHit = PR_Now();
1040 rvCert = nssCertificate_AddRef(ce->entry.cert);
1041 #ifdef DEBUG_CACHE
1042 PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
1043 #endif
1044 }
1045 PZ_Unlock(td->cache->lock);
1046 return rvCert;
1047 }
1048
1049 static PRStatus
1050 issuer_and_serial_from_encoding (
1051 NSSBER *encoding,
1052 NSSDER *issuer,
1053 NSSDER *serial
1054 )
1055 {
1056 SECItem derCert, derIssuer, derSerial;
1057 SECStatus secrv;
1058 derCert.data = (unsigned char *)encoding->data;
1059 derCert.len = encoding->size;
1060 secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
1061 if (secrv != SECSuccess) {
1062 return PR_FAILURE;
1063 }
1064 secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
1065 if (secrv != SECSuccess) {
1066 return PR_FAILURE;
1067 }
1068 issuer->data = derIssuer.data;
1069 issuer->size = derIssuer.len;
1070 serial->data = derSerial.data;
1071 serial->size = derSerial.len;
1072 return PR_SUCCESS;
1073 }
1074
1075 /*
1076 * Look for a specific cert in the cache
1077 */
1078 NSS_IMPLEMENT NSSCertificate *
1079 nssTrustDomain_GetCertByDERFromCache (
1080 NSSTrustDomain *td,
1081 NSSDER *der
1082 )
1083 {
1084 PRStatus nssrv = PR_FAILURE;
1085 NSSDER issuer, serial;
1086 NSSCertificate *rvCert;
1087 nssrv = issuer_and_serial_from_encoding(der, &issuer, &serial);
1088 if (nssrv != PR_SUCCESS) {
1089 return NULL;
1090 }
1091 #ifdef DEBUG_CACHE
1092 log_item_dump("looking for cert by DER", der);
1093 #endif
1094 rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td,
1095 &issuer, &serial);
1096 PORT_Free(issuer.data);
1097 PORT_Free(serial.data);
1098 return rvCert;
1099 }
1100
1101 static void cert_iter(const void *k, void *v, void *a)
1102 {
1103 nssList *certList = (nssList *)a;
1104 NSSCertificate *c = (NSSCertificate *)k;
1105 nssList_Add(certList, nssCertificate_AddRef(c));
1106 }
1107
1108 NSS_EXTERN NSSCertificate **
1109 nssTrustDomain_GetCertsFromCache (
1110 NSSTrustDomain *td,
1111 nssList *certListOpt
1112 )
1113 {
1114 NSSCertificate **rvArray = NULL;
1115 nssList *certList;
1116 if (certListOpt) {
1117 certList = certListOpt;
1118 } else {
1119 certList = nssList_Create(NULL, PR_FALSE);
1120 if (!certList) {
1121 return NULL;
1122 }
1123 }
1124 PZ_Lock(td->cache->lock);
1125 nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
1126 PZ_Unlock(td->cache->lock);
1127 if (!certListOpt) {
1128 PRUint32 count = nssList_Count(certList);
1129 rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
1130 nssList_GetArray(certList, (void **)rvArray, count);
1131 /* array takes the references */
1132 nssList_Destroy(certList);
1133 }
1134 return rvArray;
1135 }
1136
1137 NSS_IMPLEMENT void
1138 nssTrustDomain_DumpCacheInfo (
1139 NSSTrustDomain *td,
1140 void (* cert_dump_iter)(const void *, void *, void *),
1141 void *arg
1142 )
1143 {
1144 PZ_Lock(td->cache->lock);
1145 nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
1146 PZ_Unlock(td->cache->lock);
1147 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)