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