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