Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1328)

Side by Side Diff: mozilla/security/nss/lib/pki/tdcache.c

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

Powered by Google App Engine
This is Rietveld 408576698