security/nss/lib/pki/tdcache.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial