| OLD | NEW |
| (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 } | |
| OLD | NEW |