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