security/nss/lib/pki/tdcache.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/pki/tdcache.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1147 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#ifndef PKIM_H
     1.9 +#include "pkim.h"
    1.10 +#endif /* PKIM_H */
    1.11 +
    1.12 +#ifndef PKIT_H
    1.13 +#include "pkit.h"
    1.14 +#endif /* PKIT_H */
    1.15 +
    1.16 +#ifndef NSSPKI_H
    1.17 +#include "nsspki.h"
    1.18 +#endif /* NSSPKI_H */
    1.19 +
    1.20 +#ifndef PKI_H
    1.21 +#include "pki.h"
    1.22 +#endif /* PKI_H */
    1.23 +
    1.24 +#ifndef NSSBASE_H
    1.25 +#include "nssbase.h"
    1.26 +#endif /* NSSBASE_H */
    1.27 +
    1.28 +#ifndef BASE_H
    1.29 +#include "base.h"
    1.30 +#endif /* BASE_H */
    1.31 +
    1.32 +#include "cert.h"
    1.33 +#include "dev.h"
    1.34 +#include "pki3hack.h"
    1.35 +
    1.36 +#ifdef DEBUG_CACHE
    1.37 +static PRLogModuleInfo *s_log = NULL;
    1.38 +#endif
    1.39 +
    1.40 +#ifdef DEBUG_CACHE
    1.41 +static void log_item_dump(const char *msg, NSSItem *it)
    1.42 +{
    1.43 +    char buf[33];
    1.44 +    int i, j;
    1.45 +    for (i=0; i<10 && i<it->size; i++) {
    1.46 +	sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]);
    1.47 +    }
    1.48 +    if (it->size>10) {
    1.49 +	sprintf(&buf[2*i], "..");
    1.50 +	i += 1;
    1.51 +	for (j=it->size-1; i<=16 && j>10; i++, j--) {
    1.52 +	    sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]);
    1.53 +	}
    1.54 +    }
    1.55 +    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
    1.56 +}
    1.57 +#endif
    1.58 +
    1.59 +#ifdef DEBUG_CACHE
    1.60 +static void log_cert_ref(const char *msg, NSSCertificate *c)
    1.61 +{
    1.62 +    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg,
    1.63 +                           (c->nickname) ? c->nickname : c->email));
    1.64 +    log_item_dump("\tserial", &c->serial);
    1.65 +    log_item_dump("\tsubject", &c->subject);
    1.66 +}
    1.67 +#endif
    1.68 +
    1.69 +/* Certificate cache routines */
    1.70 +
    1.71 +/* XXX
    1.72 + * Locking is not handled well at all.  A single, global lock with sub-locks
    1.73 + * in the collection types.  Cleanup needed.
    1.74 + */
    1.75 +
    1.76 +/* should it live in its own arena? */
    1.77 +struct nssTDCertificateCacheStr 
    1.78 +{
    1.79 +    PZLock *lock;
    1.80 +    NSSArena *arena;
    1.81 +    nssHash *issuerAndSN;
    1.82 +    nssHash *subject;
    1.83 +    nssHash *nickname;
    1.84 +    nssHash *email;
    1.85 +};
    1.86 +
    1.87 +struct cache_entry_str 
    1.88 +{
    1.89 +    union {
    1.90 +	NSSCertificate *cert;
    1.91 +	nssList *list;
    1.92 +	void *value;
    1.93 +    } entry;
    1.94 +    PRUint32 hits;
    1.95 +    PRTime lastHit;
    1.96 +    NSSArena *arena;
    1.97 +    NSSUTF8 *nickname;
    1.98 +};
    1.99 +
   1.100 +typedef struct cache_entry_str cache_entry;
   1.101 +
   1.102 +static cache_entry *
   1.103 +new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
   1.104 +{
   1.105 +    cache_entry *ce = nss_ZNEW(arena, cache_entry);
   1.106 +    if (ce) {
   1.107 +	ce->entry.value = value;
   1.108 +	ce->hits = 1;
   1.109 +	ce->lastHit = PR_Now();
   1.110 +	if (ownArena) {
   1.111 +	    ce->arena = arena;
   1.112 +	}
   1.113 +	ce->nickname = NULL;
   1.114 +    }
   1.115 +    return ce;
   1.116 +}
   1.117 +
   1.118 +/* this should not be exposed in a header, but is here to keep the above
   1.119 + * types/functions static
   1.120 + */
   1.121 +NSS_IMPLEMENT PRStatus
   1.122 +nssTrustDomain_InitializeCache (
   1.123 +  NSSTrustDomain *td,
   1.124 +  PRUint32 cacheSize
   1.125 +)
   1.126 +{
   1.127 +    NSSArena *arena;
   1.128 +    nssTDCertificateCache *cache = td->cache;
   1.129 +#ifdef DEBUG_CACHE
   1.130 +    s_log = PR_NewLogModule("nss_cache");
   1.131 +    PR_ASSERT(s_log);
   1.132 +#endif
   1.133 +    PR_ASSERT(!cache);
   1.134 +    arena = nssArena_Create();
   1.135 +    if (!arena) {
   1.136 +	return PR_FAILURE;
   1.137 +    }
   1.138 +    cache = nss_ZNEW(arena, nssTDCertificateCache);
   1.139 +    if (!cache) {
   1.140 +	nssArena_Destroy(arena);
   1.141 +	return PR_FAILURE;
   1.142 +    }
   1.143 +    cache->lock = PZ_NewLock(nssILockCache);
   1.144 +    if (!cache->lock) {
   1.145 +	nssArena_Destroy(arena);
   1.146 +	return PR_FAILURE;
   1.147 +    }
   1.148 +    /* Create the issuer and serial DER --> certificate hash */
   1.149 +    cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
   1.150 +    if (!cache->issuerAndSN) {
   1.151 +	goto loser;
   1.152 +    }
   1.153 +    /* Create the subject DER --> subject list hash */
   1.154 +    cache->subject = nssHash_CreateItem(arena, cacheSize);
   1.155 +    if (!cache->subject) {
   1.156 +	goto loser;
   1.157 +    }
   1.158 +    /* Create the nickname --> subject list hash */
   1.159 +    cache->nickname = nssHash_CreateString(arena, cacheSize);
   1.160 +    if (!cache->nickname) {
   1.161 +	goto loser;
   1.162 +    }
   1.163 +    /* Create the email --> list of subject lists hash */
   1.164 +    cache->email = nssHash_CreateString(arena, cacheSize);
   1.165 +    if (!cache->email) {
   1.166 +	goto loser;
   1.167 +    }
   1.168 +    cache->arena = arena;
   1.169 +    td->cache = cache;
   1.170 +#ifdef DEBUG_CACHE
   1.171 +    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
   1.172 +#endif
   1.173 +    return PR_SUCCESS;
   1.174 +loser:
   1.175 +    PZ_DestroyLock(cache->lock);
   1.176 +    nssArena_Destroy(arena);
   1.177 +    td->cache = NULL;
   1.178 +#ifdef DEBUG_CACHE
   1.179 +    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
   1.180 +#endif
   1.181 +    return PR_FAILURE;
   1.182 +}
   1.183 +
   1.184 +/* The entries of the hashtable are currently dependent on the certificate(s)
   1.185 + * that produced them.  That is, the entries will be freed when the cert is
   1.186 + * released from the cache.  If there are certs in the cache at any time,
   1.187 + * including shutdown, the hash table entries will hold memory.  In order for
   1.188 + * clean shutdown, it is necessary for there to be no certs in the cache.
   1.189 + */
   1.190 +
   1.191 +extern const NSSError NSS_ERROR_INTERNAL_ERROR;
   1.192 +extern const NSSError NSS_ERROR_BUSY;
   1.193 +
   1.194 +NSS_IMPLEMENT PRStatus
   1.195 +nssTrustDomain_DestroyCache (
   1.196 +  NSSTrustDomain *td
   1.197 +)
   1.198 +{
   1.199 +    if (!td->cache) {
   1.200 +	nss_SetError(NSS_ERROR_INTERNAL_ERROR);
   1.201 +	return PR_FAILURE;
   1.202 +    }
   1.203 +    if (nssHash_Count(td->cache->issuerAndSN) > 0) {
   1.204 +	nss_SetError(NSS_ERROR_BUSY);
   1.205 +	return PR_FAILURE;
   1.206 +    }
   1.207 +    PZ_DestroyLock(td->cache->lock);
   1.208 +    nssHash_Destroy(td->cache->issuerAndSN);
   1.209 +    nssHash_Destroy(td->cache->subject);
   1.210 +    nssHash_Destroy(td->cache->nickname);
   1.211 +    nssHash_Destroy(td->cache->email);
   1.212 +    nssArena_Destroy(td->cache->arena);
   1.213 +    td->cache = NULL;
   1.214 +#ifdef DEBUG_CACHE
   1.215 +    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
   1.216 +#endif
   1.217 +    return PR_SUCCESS;
   1.218 +}
   1.219 +
   1.220 +static PRStatus
   1.221 +remove_issuer_and_serial_entry (
   1.222 +  nssTDCertificateCache *cache,
   1.223 +  NSSCertificate *cert
   1.224 +)
   1.225 +{
   1.226 +    /* Remove the cert from the issuer/serial hash */
   1.227 +    nssHash_Remove(cache->issuerAndSN, cert);
   1.228 +#ifdef DEBUG_CACHE
   1.229 +    log_cert_ref("removed issuer/sn", cert);
   1.230 +#endif
   1.231 +    return PR_SUCCESS;
   1.232 +}
   1.233 +
   1.234 +static PRStatus
   1.235 +remove_subject_entry (
   1.236 +  nssTDCertificateCache *cache,
   1.237 +  NSSCertificate *cert,
   1.238 +  nssList **subjectList,
   1.239 +  NSSUTF8 **nickname,
   1.240 +  NSSArena **arena
   1.241 +)
   1.242 +{
   1.243 +    PRStatus nssrv;
   1.244 +    cache_entry *ce;
   1.245 +    *subjectList = NULL;
   1.246 +    *arena = NULL;
   1.247 +    /* Get the subject list for the cert's subject */
   1.248 +    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
   1.249 +    if (ce) {
   1.250 +	/* Remove the cert from the subject hash */
   1.251 +	nssList_Remove(ce->entry.list, cert);
   1.252 +	*subjectList = ce->entry.list;
   1.253 +	*nickname = ce->nickname;
   1.254 +	*arena = ce->arena;
   1.255 +	nssrv = PR_SUCCESS;
   1.256 +#ifdef DEBUG_CACHE
   1.257 +	log_cert_ref("removed cert", cert);
   1.258 +	log_item_dump("from subject list", &cert->subject);
   1.259 +#endif
   1.260 +    } else {
   1.261 +	nssrv = PR_FAILURE;
   1.262 +    }
   1.263 +    return nssrv;
   1.264 +}
   1.265 +
   1.266 +static PRStatus
   1.267 +remove_nickname_entry (
   1.268 +  nssTDCertificateCache *cache,
   1.269 +  NSSUTF8 *nickname,
   1.270 +  nssList *subjectList
   1.271 +)
   1.272 +{
   1.273 +    PRStatus nssrv;
   1.274 +    if (nickname) {
   1.275 +	nssHash_Remove(cache->nickname, nickname);
   1.276 +	nssrv = PR_SUCCESS;
   1.277 +#ifdef DEBUG_CACHE
   1.278 +	PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
   1.279 +#endif
   1.280 +    } else {
   1.281 +	nssrv = PR_FAILURE;
   1.282 +    }
   1.283 +    return nssrv;
   1.284 +}
   1.285 +
   1.286 +static PRStatus
   1.287 +remove_email_entry (
   1.288 +  nssTDCertificateCache *cache,
   1.289 +  NSSCertificate *cert,
   1.290 +  nssList *subjectList
   1.291 +)
   1.292 +{
   1.293 +    PRStatus nssrv = PR_FAILURE;
   1.294 +    cache_entry *ce;
   1.295 +    /* Find the subject list in the email hash */
   1.296 +    if (cert->email) {
   1.297 +	ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
   1.298 +	if (ce) {
   1.299 +	    nssList *subjects = ce->entry.list;
   1.300 +	    /* Remove the subject list from the email hash */
   1.301 +	    nssList_Remove(subjects, subjectList);
   1.302 +#ifdef DEBUG_CACHE
   1.303 +	    log_item_dump("removed subject list", &cert->subject);
   1.304 +	    PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
   1.305 +#endif
   1.306 +	    if (nssList_Count(subjects) == 0) {
   1.307 +		/* No more subject lists for email, delete list and
   1.308 +		* remove hash entry
   1.309 +		*/
   1.310 +		(void)nssList_Destroy(subjects);
   1.311 +		nssHash_Remove(cache->email, cert->email);
   1.312 +		/* there are no entries left for this address, free space
   1.313 +		 * used for email entries
   1.314 +		 */
   1.315 +		nssArena_Destroy(ce->arena);
   1.316 +#ifdef DEBUG_CACHE
   1.317 +		PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
   1.318 +#endif
   1.319 +	    }
   1.320 +	    nssrv = PR_SUCCESS;
   1.321 +	}
   1.322 +    }
   1.323 +    return nssrv;
   1.324 +}
   1.325 +
   1.326 +NSS_IMPLEMENT void
   1.327 +nssTrustDomain_RemoveCertFromCacheLOCKED (
   1.328 +  NSSTrustDomain *td,
   1.329 +  NSSCertificate *cert
   1.330 +)
   1.331 +{
   1.332 +    nssList *subjectList;
   1.333 +    cache_entry *ce;
   1.334 +    NSSArena *arena;
   1.335 +    NSSUTF8 *nickname;
   1.336 +
   1.337 +#ifdef DEBUG_CACHE
   1.338 +    log_cert_ref("attempt to remove cert", cert);
   1.339 +#endif
   1.340 +    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
   1.341 +    if (!ce || ce->entry.cert != cert) {
   1.342 +	/* If it's not in the cache, or a different cert is (this is really
   1.343 +	 * for safety reasons, though it shouldn't happen), do nothing 
   1.344 +	 */
   1.345 +#ifdef DEBUG_CACHE
   1.346 +	PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
   1.347 +#endif
   1.348 +	return;
   1.349 +    }
   1.350 +    (void)remove_issuer_and_serial_entry(td->cache, cert);
   1.351 +    (void)remove_subject_entry(td->cache, cert, &subjectList, 
   1.352 +                               &nickname, &arena);
   1.353 +    if (nssList_Count(subjectList) == 0) {
   1.354 +	(void)remove_nickname_entry(td->cache, nickname, subjectList);
   1.355 +	(void)remove_email_entry(td->cache, cert, subjectList);
   1.356 +	(void)nssList_Destroy(subjectList);
   1.357 +	nssHash_Remove(td->cache->subject, &cert->subject);
   1.358 +	/* there are no entries left for this subject, free the space used
   1.359 +	 * for both the nickname and subject entries
   1.360 +	 */
   1.361 +	if (arena) {
   1.362 +	    nssArena_Destroy(arena);
   1.363 +	}
   1.364 +    }
   1.365 +}
   1.366 +
   1.367 +NSS_IMPLEMENT void
   1.368 +nssTrustDomain_LockCertCache (
   1.369 +  NSSTrustDomain *td
   1.370 +)
   1.371 +{
   1.372 +    PZ_Lock(td->cache->lock);
   1.373 +}
   1.374 +
   1.375 +NSS_IMPLEMENT void
   1.376 +nssTrustDomain_UnlockCertCache (
   1.377 +  NSSTrustDomain *td
   1.378 +)
   1.379 +{
   1.380 +    PZ_Unlock(td->cache->lock);
   1.381 +}
   1.382 +
   1.383 +struct token_cert_dtor {
   1.384 +    NSSToken *token;
   1.385 +    nssTDCertificateCache *cache;
   1.386 +    NSSCertificate **certs;
   1.387 +    PRUint32 numCerts, arrSize;
   1.388 +};
   1.389 +
   1.390 +static void 
   1.391 +remove_token_certs(const void *k, void *v, void *a)
   1.392 +{
   1.393 +    NSSCertificate *c = (NSSCertificate *)k;
   1.394 +    nssPKIObject *object = &c->object;
   1.395 +    struct token_cert_dtor *dtor = a;
   1.396 +    PRUint32 i;
   1.397 +    nssPKIObject_Lock(object);
   1.398 +    for (i=0; i<object->numInstances; i++) {
   1.399 +	if (object->instances[i]->token == dtor->token) {
   1.400 +	    nssCryptokiObject_Destroy(object->instances[i]);
   1.401 +	    object->instances[i] = object->instances[object->numInstances-1];
   1.402 +	    object->instances[object->numInstances-1] = NULL;
   1.403 +	    object->numInstances--;
   1.404 +	    dtor->certs[dtor->numCerts++] = c;
   1.405 +	    if (dtor->numCerts == dtor->arrSize) {
   1.406 +		dtor->arrSize *= 2;
   1.407 +		dtor->certs = nss_ZREALLOCARRAY(dtor->certs, 
   1.408 +		                                NSSCertificate *,
   1.409 +		                                dtor->arrSize);
   1.410 +	    }
   1.411 +	    break;
   1.412 +	}
   1.413 +    }
   1.414 +    nssPKIObject_Unlock(object);
   1.415 +    return;
   1.416 +}
   1.417 +
   1.418 +/* 
   1.419 + * Remove all certs for the given token from the cache.  This is
   1.420 + * needed if the token is removed. 
   1.421 + */
   1.422 +NSS_IMPLEMENT PRStatus
   1.423 +nssTrustDomain_RemoveTokenCertsFromCache (
   1.424 +  NSSTrustDomain *td,
   1.425 +  NSSToken *token
   1.426 +)
   1.427 +{
   1.428 +    NSSCertificate **certs;
   1.429 +    PRUint32 i, arrSize = 10;
   1.430 +    struct token_cert_dtor dtor;
   1.431 +    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
   1.432 +    if (!certs) {
   1.433 +	return PR_FAILURE;
   1.434 +    }
   1.435 +    dtor.cache = td->cache;
   1.436 +    dtor.token = token;
   1.437 +    dtor.certs = certs;
   1.438 +    dtor.numCerts = 0;
   1.439 +    dtor.arrSize = arrSize;
   1.440 +    PZ_Lock(td->cache->lock);
   1.441 +    nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, (void *)&dtor);
   1.442 +    for (i=0; i<dtor.numCerts; i++) {
   1.443 +	if (dtor.certs[i]->object.numInstances == 0) {
   1.444 +	    nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
   1.445 +	    dtor.certs[i] = NULL;  /* skip this cert in the second for loop */
   1.446 +	}
   1.447 +    }
   1.448 +    PZ_Unlock(td->cache->lock);
   1.449 +    for (i=0; i<dtor.numCerts; i++) {
   1.450 +	if (dtor.certs[i]) {
   1.451 +	    STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
   1.452 +	}
   1.453 +    }
   1.454 +    nss_ZFreeIf(dtor.certs);
   1.455 +    return PR_SUCCESS;
   1.456 +}
   1.457 +
   1.458 +NSS_IMPLEMENT PRStatus
   1.459 +nssTrustDomain_UpdateCachedTokenCerts (
   1.460 +  NSSTrustDomain *td,
   1.461 +  NSSToken *token
   1.462 +)
   1.463 +{
   1.464 +    NSSCertificate **cp, **cached = NULL;
   1.465 +    nssList *certList;
   1.466 +    PRUint32 count;
   1.467 +    certList = nssList_Create(NULL, PR_FALSE);
   1.468 +    if (!certList) return PR_FAILURE;
   1.469 +    (void)nssTrustDomain_GetCertsFromCache(td, certList);
   1.470 +    count = nssList_Count(certList);
   1.471 +    if (count > 0) {
   1.472 +	cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
   1.473 +	if (!cached) {
   1.474 +	    nssList_Destroy(certList);
   1.475 +	    return PR_FAILURE;
   1.476 +	}
   1.477 +	nssList_GetArray(certList, (void **)cached, count);
   1.478 +	for (cp = cached; *cp; cp++) {
   1.479 +	    nssCryptokiObject *instance;
   1.480 +	    NSSCertificate *c = *cp;
   1.481 +	    nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
   1.482 +	    instance = nssToken_FindCertificateByIssuerAndSerialNumber(
   1.483 +	                                                       token,
   1.484 +                                                               NULL,
   1.485 +                                                               &c->issuer,
   1.486 +                                                               &c->serial,
   1.487 +                                                               tokenOnly,
   1.488 +                                                               NULL);
   1.489 +	    if (instance) {
   1.490 +		nssPKIObject_AddInstance(&c->object, instance);
   1.491 +		STAN_ForceCERTCertificateUpdate(c);
   1.492 +	    }
   1.493 +	}
   1.494 +	nssCertificateArray_Destroy(cached);
   1.495 +    }
   1.496 +    nssList_Destroy(certList);
   1.497 +    return PR_SUCCESS;
   1.498 +}
   1.499 +
   1.500 +static PRStatus
   1.501 +add_issuer_and_serial_entry (
   1.502 +  NSSArena *arena,
   1.503 +  nssTDCertificateCache *cache, 
   1.504 +  NSSCertificate *cert
   1.505 +)
   1.506 +{
   1.507 +    cache_entry *ce;
   1.508 +    ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
   1.509 +#ifdef DEBUG_CACHE
   1.510 +    log_cert_ref("added to issuer/sn", cert);
   1.511 +#endif
   1.512 +    return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
   1.513 +}
   1.514 +
   1.515 +static PRStatus
   1.516 +add_subject_entry (
   1.517 +  NSSArena *arena,
   1.518 +  nssTDCertificateCache *cache, 
   1.519 +  NSSCertificate *cert,
   1.520 +  NSSUTF8 *nickname,
   1.521 +  nssList **subjectList
   1.522 +)
   1.523 +{
   1.524 +    PRStatus nssrv;
   1.525 +    nssList *list;
   1.526 +    cache_entry *ce;
   1.527 +    *subjectList = NULL;  /* this is only set if a new one is created */
   1.528 +    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
   1.529 +    if (ce) {
   1.530 +	ce->hits++;
   1.531 +	ce->lastHit = PR_Now();
   1.532 +	/* The subject is already in, add this cert to the list */
   1.533 +	nssrv = nssList_AddUnique(ce->entry.list, cert);
   1.534 +#ifdef DEBUG_CACHE
   1.535 +	log_cert_ref("added to existing subject list", cert);
   1.536 +#endif
   1.537 +    } else {
   1.538 +	NSSDER *subject;
   1.539 +	/* Create a new subject list for the subject */
   1.540 +	list = nssList_Create(arena, PR_FALSE);
   1.541 +	if (!list) {
   1.542 +	    return PR_FAILURE;
   1.543 +	}
   1.544 +	ce = new_cache_entry(arena, (void *)list, PR_TRUE);
   1.545 +	if (!ce) {
   1.546 +	    return PR_FAILURE;
   1.547 +	}
   1.548 +	if (nickname) {
   1.549 +	    ce->nickname = nssUTF8_Duplicate(nickname, arena);
   1.550 +	}
   1.551 +	nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
   1.552 +	/* Add the cert entry to this list of subjects */
   1.553 +	nssrv = nssList_AddUnique(list, cert);
   1.554 +	if (nssrv != PR_SUCCESS) {
   1.555 +	    return nssrv;
   1.556 +	}
   1.557 +	/* Add the subject list to the cache */
   1.558 +	subject = nssItem_Duplicate(&cert->subject, arena, NULL);
   1.559 +	if (!subject) {
   1.560 +	    return PR_FAILURE;
   1.561 +	}
   1.562 +	nssrv = nssHash_Add(cache->subject, subject, ce);
   1.563 +	if (nssrv != PR_SUCCESS) {
   1.564 +	    return nssrv;
   1.565 +	}
   1.566 +	*subjectList = list;
   1.567 +#ifdef DEBUG_CACHE
   1.568 +	log_cert_ref("created subject list", cert);
   1.569 +#endif
   1.570 +    }
   1.571 +    return nssrv;
   1.572 +}
   1.573 +
   1.574 +static PRStatus
   1.575 +add_nickname_entry (
   1.576 +  NSSArena *arena,
   1.577 +  nssTDCertificateCache *cache, 
   1.578 +  NSSUTF8 *certNickname,
   1.579 +  nssList *subjectList
   1.580 +)
   1.581 +{
   1.582 +    PRStatus nssrv = PR_SUCCESS;
   1.583 +    cache_entry *ce;
   1.584 +    ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
   1.585 +    if (ce) {
   1.586 +	/* This is a collision.  A nickname entry already exists for this
   1.587 +	 * subject, but a subject entry didn't.  This would imply there are
   1.588 +	 * two subjects using the same nickname, which is not allowed.
   1.589 +	 */
   1.590 +	return PR_FAILURE;
   1.591 +    } else {
   1.592 +	NSSUTF8 *nickname;
   1.593 +	ce = new_cache_entry(arena, subjectList, PR_FALSE);
   1.594 +	if (!ce) {
   1.595 +	    return PR_FAILURE;
   1.596 +	}
   1.597 +	nickname = nssUTF8_Duplicate(certNickname, arena);
   1.598 +	if (!nickname) {
   1.599 +	    return PR_FAILURE;
   1.600 +	}
   1.601 +	nssrv = nssHash_Add(cache->nickname, nickname, ce);
   1.602 +#ifdef DEBUG_CACHE
   1.603 +	log_cert_ref("created nickname for", cert);
   1.604 +#endif
   1.605 +    }
   1.606 +    return nssrv;
   1.607 +}
   1.608 +
   1.609 +static PRStatus
   1.610 +add_email_entry (
   1.611 +  nssTDCertificateCache *cache, 
   1.612 +  NSSCertificate *cert,
   1.613 +  nssList *subjectList
   1.614 +)
   1.615 +{
   1.616 +    PRStatus nssrv = PR_SUCCESS;
   1.617 +    nssList *subjects;
   1.618 +    cache_entry *ce;
   1.619 +    ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
   1.620 +    if (ce) {
   1.621 +	/* Already have an entry for this email address, but not subject */
   1.622 +	subjects = ce->entry.list;
   1.623 +	nssrv = nssList_AddUnique(subjects, subjectList);
   1.624 +	ce->hits++;
   1.625 +	ce->lastHit = PR_Now();
   1.626 +#ifdef DEBUG_CACHE
   1.627 +	log_cert_ref("added subject to email for", cert);
   1.628 +#endif
   1.629 +    } else {
   1.630 +	NSSASCII7 *email;
   1.631 +	NSSArena *arena;
   1.632 +	arena = nssArena_Create();
   1.633 +	if (!arena) {
   1.634 +	    return PR_FAILURE;
   1.635 +	}
   1.636 +	/* Create a new list of subject lists, add this subject */
   1.637 +	subjects = nssList_Create(arena, PR_TRUE);
   1.638 +	if (!subjects) {
   1.639 +	    nssArena_Destroy(arena);
   1.640 +	    return PR_FAILURE;
   1.641 +	}
   1.642 +	/* Add the new subject to the list */
   1.643 +	nssrv = nssList_AddUnique(subjects, subjectList);
   1.644 +	if (nssrv != PR_SUCCESS) {
   1.645 +	    nssArena_Destroy(arena);
   1.646 +	    return nssrv;
   1.647 +	}
   1.648 +	/* Add the new entry to the cache */
   1.649 +	ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
   1.650 +	if (!ce) {
   1.651 +	    nssArena_Destroy(arena);
   1.652 +	    return PR_FAILURE;
   1.653 +	}
   1.654 +	email = nssUTF8_Duplicate(cert->email, arena);
   1.655 +	if (!email) {
   1.656 +	    nssArena_Destroy(arena);
   1.657 +	    return PR_FAILURE;
   1.658 +	}
   1.659 +	nssrv = nssHash_Add(cache->email, email, ce);
   1.660 +	if (nssrv != PR_SUCCESS) {
   1.661 +	    nssArena_Destroy(arena);
   1.662 +	    return nssrv;
   1.663 +	}
   1.664 +#ifdef DEBUG_CACHE
   1.665 +	log_cert_ref("created email for", cert);
   1.666 +#endif
   1.667 +    }
   1.668 +    return nssrv;
   1.669 +}
   1.670 +
   1.671 +extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
   1.672 +
   1.673 +static void
   1.674 +remove_object_instances (
   1.675 +  nssPKIObject *object,
   1.676 +  nssCryptokiObject **instances,
   1.677 +  int numInstances
   1.678 +)
   1.679 +{
   1.680 +    int i;
   1.681 +
   1.682 +    for (i = 0; i < numInstances; i++) {
   1.683 +	nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
   1.684 +    }
   1.685 +}
   1.686 +
   1.687 +static SECStatus
   1.688 +merge_object_instances (
   1.689 +  nssPKIObject *to,
   1.690 +  nssPKIObject *from
   1.691 +)
   1.692 +{
   1.693 +    nssCryptokiObject **instances, **ci;
   1.694 +    int i;
   1.695 +    SECStatus rv = SECSuccess;
   1.696 +
   1.697 +    instances = nssPKIObject_GetInstances(from);
   1.698 +    if (instances == NULL) {
   1.699 +	return SECFailure;
   1.700 +    }
   1.701 +    for (ci = instances, i = 0; *ci; ci++, i++) {
   1.702 +	nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
   1.703 +	if (instance) {
   1.704 +	    if (nssPKIObject_AddInstance(to, instance) == PR_SUCCESS) {
   1.705 +		continue;
   1.706 +	    }
   1.707 +	    nssCryptokiObject_Destroy(instance);
   1.708 +	}
   1.709 +	remove_object_instances(to, instances, i);
   1.710 +	rv = SECFailure;
   1.711 +	break;
   1.712 +    }
   1.713 +    nssCryptokiObjectArray_Destroy(instances);
   1.714 +    return rv;
   1.715 +}
   1.716 +
   1.717 +static NSSCertificate *
   1.718 +add_cert_to_cache (
   1.719 +  NSSTrustDomain *td, 
   1.720 +  NSSCertificate *cert
   1.721 +)
   1.722 +{
   1.723 +    NSSArena *arena = NULL;
   1.724 +    nssList *subjectList = NULL;
   1.725 +    PRStatus nssrv;
   1.726 +    PRUint32 added = 0;
   1.727 +    cache_entry *ce;
   1.728 +    NSSCertificate *rvCert = NULL;
   1.729 +    NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
   1.730 +
   1.731 +    PZ_Lock(td->cache->lock);
   1.732 +    /* If it exists in the issuer/serial hash, it's already in all */
   1.733 +    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
   1.734 +    if (ce) {
   1.735 +	ce->hits++;
   1.736 +	ce->lastHit = PR_Now();
   1.737 +	rvCert = nssCertificate_AddRef(ce->entry.cert);
   1.738 +#ifdef DEBUG_CACHE
   1.739 +	log_cert_ref("attempted to add cert already in cache", cert);
   1.740 +#endif
   1.741 +	PZ_Unlock(td->cache->lock);
   1.742 +        nss_ZFreeIf(certNickname);
   1.743 +	/* collision - somebody else already added the cert
   1.744 +	 * to the cache before this thread got around to it.
   1.745 +	 */
   1.746 +	/* merge the instances of the cert */
   1.747 +	if (merge_object_instances(&rvCert->object, &cert->object)
   1.748 +							!= SECSuccess) {
   1.749 +	    nssCertificate_Destroy(rvCert);
   1.750 +	    return NULL;
   1.751 +	}
   1.752 +	STAN_ForceCERTCertificateUpdate(rvCert);
   1.753 +	nssCertificate_Destroy(cert);
   1.754 +	return rvCert;
   1.755 +    }
   1.756 +    /* create a new cache entry for this cert within the cert's arena*/
   1.757 +    nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
   1.758 +    if (nssrv != PR_SUCCESS) {
   1.759 +	goto loser;
   1.760 +    }
   1.761 +    added++;
   1.762 +    /* create an arena for the nickname and subject entries */
   1.763 +    arena = nssArena_Create();
   1.764 +    if (!arena) {
   1.765 +	goto loser;
   1.766 +    }
   1.767 +    /* create a new subject list for this cert, or add to existing */
   1.768 +    nssrv = add_subject_entry(arena, td->cache, cert, 
   1.769 +						certNickname, &subjectList);
   1.770 +    if (nssrv != PR_SUCCESS) {
   1.771 +	goto loser;
   1.772 +    }
   1.773 +    added++;
   1.774 +    /* If a new subject entry was created, also need nickname and/or email */
   1.775 +    if (subjectList != NULL) {
   1.776 +	PRBool handle = PR_FALSE;
   1.777 +	if (certNickname) {
   1.778 +	    nssrv = add_nickname_entry(arena, td->cache, 
   1.779 +						certNickname, subjectList);
   1.780 +	    if (nssrv != PR_SUCCESS) {
   1.781 +		goto loser;
   1.782 +	    }
   1.783 +	    handle = PR_TRUE;
   1.784 +	    added++;
   1.785 +	}
   1.786 +	if (cert->email) {
   1.787 +	    nssrv = add_email_entry(td->cache, cert, subjectList);
   1.788 +	    if (nssrv != PR_SUCCESS) {
   1.789 +		goto loser;
   1.790 +	    }
   1.791 +	    handle = PR_TRUE;
   1.792 +	    added += 2;
   1.793 +	}
   1.794 +#ifdef nodef
   1.795 +	/* I think either a nickname or email address must be associated
   1.796 +	 * with the cert.  However, certs are passed to NewTemp without
   1.797 +	 * either.  This worked in the old code, so it must work now.
   1.798 +	 */
   1.799 +	if (!handle) {
   1.800 +	    /* Require either nickname or email handle */
   1.801 +	    nssrv = PR_FAILURE;
   1.802 +	    goto loser;
   1.803 +	}
   1.804 +#endif
   1.805 +    } else {
   1.806 +    	/* A new subject entry was not created.  arena is unused. */
   1.807 +	nssArena_Destroy(arena);
   1.808 +    }
   1.809 +    rvCert = cert;
   1.810 +    PZ_Unlock(td->cache->lock);
   1.811 +    nss_ZFreeIf(certNickname);
   1.812 +    return rvCert;
   1.813 +loser:
   1.814 +    nss_ZFreeIf(certNickname);
   1.815 +    certNickname = NULL;
   1.816 +    /* Remove any handles that have been created */
   1.817 +    subjectList = NULL;
   1.818 +    if (added >= 1) {
   1.819 +	(void)remove_issuer_and_serial_entry(td->cache, cert);
   1.820 +    }
   1.821 +    if (added >= 2) {
   1.822 +	(void)remove_subject_entry(td->cache, cert, &subjectList, 
   1.823 +						&certNickname, &arena);
   1.824 +    }
   1.825 +    if (added == 3 || added == 5) {
   1.826 +	(void)remove_nickname_entry(td->cache, certNickname, subjectList);
   1.827 +    }
   1.828 +    if (added >= 4) {
   1.829 +	(void)remove_email_entry(td->cache, cert, subjectList);
   1.830 +    }
   1.831 +    if (subjectList) {
   1.832 +	nssHash_Remove(td->cache->subject, &cert->subject);
   1.833 +	nssList_Destroy(subjectList);
   1.834 +    }
   1.835 +    if (arena) {
   1.836 +	nssArena_Destroy(arena);
   1.837 +    }
   1.838 +    PZ_Unlock(td->cache->lock);
   1.839 +    return NULL;
   1.840 +}
   1.841 +
   1.842 +NSS_IMPLEMENT PRStatus
   1.843 +nssTrustDomain_AddCertsToCache (
   1.844 +  NSSTrustDomain *td,
   1.845 +  NSSCertificate **certs,
   1.846 +  PRUint32 numCerts
   1.847 +)
   1.848 +{
   1.849 +    PRUint32 i;
   1.850 +    NSSCertificate *c;
   1.851 +    for (i=0; i<numCerts && certs[i]; i++) {
   1.852 +	c = add_cert_to_cache(td, certs[i]);
   1.853 +	if (c == NULL) {
   1.854 +	    return PR_FAILURE;
   1.855 +	} else {
   1.856 +	    certs[i] = c;
   1.857 +	}
   1.858 +    }
   1.859 +    return PR_SUCCESS;
   1.860 +}
   1.861 +
   1.862 +static NSSCertificate **
   1.863 +collect_subject_certs (
   1.864 +  nssList *subjectList,
   1.865 +  nssList *rvCertListOpt
   1.866 +)
   1.867 +{
   1.868 +    NSSCertificate *c;
   1.869 +    NSSCertificate **rvArray = NULL;
   1.870 +    PRUint32 count;
   1.871 +    nssCertificateList_AddReferences(subjectList);
   1.872 +    if (rvCertListOpt) {
   1.873 +	nssListIterator *iter = nssList_CreateIterator(subjectList);
   1.874 +	if (!iter) {
   1.875 +	    return (NSSCertificate **)NULL;
   1.876 +	}
   1.877 +	for (c  = (NSSCertificate *)nssListIterator_Start(iter);
   1.878 +	     c != (NSSCertificate *)NULL;
   1.879 +	     c  = (NSSCertificate *)nssListIterator_Next(iter)) {
   1.880 +	    nssList_Add(rvCertListOpt, c);
   1.881 +	}
   1.882 +	nssListIterator_Finish(iter);
   1.883 +	nssListIterator_Destroy(iter);
   1.884 +    } else {
   1.885 +	count = nssList_Count(subjectList);
   1.886 +	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
   1.887 +	if (!rvArray) {
   1.888 +	    return (NSSCertificate **)NULL;
   1.889 +	}
   1.890 +	nssList_GetArray(subjectList, (void **)rvArray, count);
   1.891 +    }
   1.892 +    return rvArray;
   1.893 +}
   1.894 +
   1.895 +/*
   1.896 + * Find all cached certs with this subject.
   1.897 + */
   1.898 +NSS_IMPLEMENT NSSCertificate **
   1.899 +nssTrustDomain_GetCertsForSubjectFromCache (
   1.900 +  NSSTrustDomain *td,
   1.901 +  NSSDER *subject,
   1.902 +  nssList *certListOpt
   1.903 +)
   1.904 +{
   1.905 +    NSSCertificate **rvArray = NULL;
   1.906 +    cache_entry *ce;
   1.907 +#ifdef DEBUG_CACHE
   1.908 +    log_item_dump("looking for cert by subject", subject);
   1.909 +#endif
   1.910 +    PZ_Lock(td->cache->lock);
   1.911 +    ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
   1.912 +    if (ce) {
   1.913 +	ce->hits++;
   1.914 +	ce->lastHit = PR_Now();
   1.915 +#ifdef DEBUG_CACHE
   1.916 +	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
   1.917 +#endif
   1.918 +	rvArray = collect_subject_certs(ce->entry.list, certListOpt);
   1.919 +    }
   1.920 +    PZ_Unlock(td->cache->lock);
   1.921 +    return rvArray;
   1.922 +}
   1.923 +
   1.924 +/*
   1.925 + * Find all cached certs with this label.
   1.926 + */
   1.927 +NSS_IMPLEMENT NSSCertificate **
   1.928 +nssTrustDomain_GetCertsForNicknameFromCache (
   1.929 +  NSSTrustDomain *td,
   1.930 +  const NSSUTF8 *nickname,
   1.931 +  nssList *certListOpt
   1.932 +)
   1.933 +{
   1.934 +    NSSCertificate **rvArray = NULL;
   1.935 +    cache_entry *ce;
   1.936 +#ifdef DEBUG_CACHE
   1.937 +    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
   1.938 +#endif
   1.939 +    PZ_Lock(td->cache->lock);
   1.940 +    ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
   1.941 +    if (ce) {
   1.942 +	ce->hits++;
   1.943 +	ce->lastHit = PR_Now();
   1.944 +#ifdef DEBUG_CACHE
   1.945 +	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
   1.946 +#endif
   1.947 +	rvArray = collect_subject_certs(ce->entry.list, certListOpt);
   1.948 +    }
   1.949 +    PZ_Unlock(td->cache->lock);
   1.950 +    return rvArray;
   1.951 +}
   1.952 +
   1.953 +/*
   1.954 + * Find all cached certs with this email address.
   1.955 + */
   1.956 +NSS_IMPLEMENT NSSCertificate **
   1.957 +nssTrustDomain_GetCertsForEmailAddressFromCache (
   1.958 +  NSSTrustDomain *td,
   1.959 +  NSSASCII7 *email,
   1.960 +  nssList *certListOpt
   1.961 +)
   1.962 +{
   1.963 +    NSSCertificate **rvArray = NULL;
   1.964 +    cache_entry *ce;
   1.965 +    nssList *collectList = NULL;
   1.966 +    nssListIterator *iter = NULL;
   1.967 +    nssList *subjectList;
   1.968 +#ifdef DEBUG_CACHE
   1.969 +    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
   1.970 +#endif
   1.971 +    PZ_Lock(td->cache->lock);
   1.972 +    ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
   1.973 +    if (ce) {
   1.974 +	ce->hits++;
   1.975 +	ce->lastHit = PR_Now();
   1.976 +#ifdef DEBUG_CACHE
   1.977 +	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
   1.978 +#endif
   1.979 +	/* loop over subject lists and get refs for certs */
   1.980 +	if (certListOpt) {
   1.981 +	    collectList = certListOpt;
   1.982 +	} else {
   1.983 +	    collectList = nssList_Create(NULL, PR_FALSE);
   1.984 +	    if (!collectList) {
   1.985 +		PZ_Unlock(td->cache->lock);
   1.986 +		return NULL;
   1.987 +	    }
   1.988 +	}
   1.989 +	iter = nssList_CreateIterator(ce->entry.list);
   1.990 +	if (!iter) {
   1.991 +	    PZ_Unlock(td->cache->lock);
   1.992 +	    if (!certListOpt) {
   1.993 +		nssList_Destroy(collectList);
   1.994 +	    }
   1.995 +	    return NULL;
   1.996 +	}
   1.997 +	for (subjectList  = (nssList *)nssListIterator_Start(iter);
   1.998 +	     subjectList != (nssList *)NULL;
   1.999 +	     subjectList  = (nssList *)nssListIterator_Next(iter)) {
  1.1000 +	    (void)collect_subject_certs(subjectList, collectList);
  1.1001 +	}
  1.1002 +	nssListIterator_Finish(iter);
  1.1003 +	nssListIterator_Destroy(iter);
  1.1004 +    }
  1.1005 +    PZ_Unlock(td->cache->lock);
  1.1006 +    if (!certListOpt && collectList) {
  1.1007 +	PRUint32 count = nssList_Count(collectList);
  1.1008 +	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
  1.1009 +	if (rvArray) {
  1.1010 +	    nssList_GetArray(collectList, (void **)rvArray, count);
  1.1011 +	}
  1.1012 +	nssList_Destroy(collectList);
  1.1013 +    }
  1.1014 +    return rvArray;
  1.1015 +}
  1.1016 +
  1.1017 +/*
  1.1018 + * Look for a specific cert in the cache
  1.1019 + */
  1.1020 +NSS_IMPLEMENT NSSCertificate *
  1.1021 +nssTrustDomain_GetCertForIssuerAndSNFromCache (
  1.1022 +  NSSTrustDomain *td,
  1.1023 +  NSSDER *issuer,
  1.1024 +  NSSDER *serial
  1.1025 +)
  1.1026 +{
  1.1027 +    NSSCertificate certkey;
  1.1028 +    NSSCertificate *rvCert = NULL;
  1.1029 +    cache_entry *ce;
  1.1030 +    certkey.issuer.data = issuer->data;
  1.1031 +    certkey.issuer.size = issuer->size;
  1.1032 +    certkey.serial.data = serial->data;
  1.1033 +    certkey.serial.size = serial->size;
  1.1034 +#ifdef DEBUG_CACHE
  1.1035 +    log_item_dump("looking for cert by issuer/sn, issuer", issuer);
  1.1036 +    log_item_dump("                               serial", serial);
  1.1037 +#endif
  1.1038 +    PZ_Lock(td->cache->lock);
  1.1039 +    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
  1.1040 +    if (ce) {
  1.1041 +	ce->hits++;
  1.1042 +	ce->lastHit = PR_Now();
  1.1043 +	rvCert = nssCertificate_AddRef(ce->entry.cert);
  1.1044 +#ifdef DEBUG_CACHE
  1.1045 +	PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
  1.1046 +#endif
  1.1047 +    }
  1.1048 +    PZ_Unlock(td->cache->lock);
  1.1049 +    return rvCert;
  1.1050 +}
  1.1051 +
  1.1052 +static PRStatus
  1.1053 +issuer_and_serial_from_encoding (
  1.1054 +  NSSBER *encoding, 
  1.1055 +  NSSDER *issuer, 
  1.1056 +  NSSDER *serial
  1.1057 +)
  1.1058 +{
  1.1059 +    SECItem derCert, derIssuer, derSerial;
  1.1060 +    SECStatus secrv;
  1.1061 +    derCert.data = (unsigned char *)encoding->data;
  1.1062 +    derCert.len = encoding->size;
  1.1063 +    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
  1.1064 +    if (secrv != SECSuccess) {
  1.1065 +	return PR_FAILURE;
  1.1066 +    }
  1.1067 +    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
  1.1068 +    if (secrv != SECSuccess) {
  1.1069 +	return PR_FAILURE;
  1.1070 +    }
  1.1071 +    issuer->data = derIssuer.data;
  1.1072 +    issuer->size = derIssuer.len;
  1.1073 +    serial->data = derSerial.data;
  1.1074 +    serial->size = derSerial.len;
  1.1075 +    return PR_SUCCESS;
  1.1076 +}
  1.1077 +
  1.1078 +/*
  1.1079 + * Look for a specific cert in the cache
  1.1080 + */
  1.1081 +NSS_IMPLEMENT NSSCertificate *
  1.1082 +nssTrustDomain_GetCertByDERFromCache (
  1.1083 +  NSSTrustDomain *td,
  1.1084 +  NSSDER *der
  1.1085 +)
  1.1086 +{
  1.1087 +    PRStatus nssrv = PR_FAILURE;
  1.1088 +    NSSDER issuer, serial;
  1.1089 +    NSSCertificate *rvCert;
  1.1090 +    nssrv = issuer_and_serial_from_encoding(der, &issuer, &serial);
  1.1091 +    if (nssrv != PR_SUCCESS) {
  1.1092 +	return NULL;
  1.1093 +    }
  1.1094 +#ifdef DEBUG_CACHE
  1.1095 +    log_item_dump("looking for cert by DER", der);
  1.1096 +#endif
  1.1097 +    rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, 
  1.1098 +                                                           &issuer, &serial);
  1.1099 +    PORT_Free(issuer.data);
  1.1100 +    PORT_Free(serial.data);
  1.1101 +    return rvCert;
  1.1102 +}
  1.1103 +
  1.1104 +static void cert_iter(const void *k, void *v, void *a)
  1.1105 +{
  1.1106 +    nssList *certList = (nssList *)a;
  1.1107 +    NSSCertificate *c = (NSSCertificate *)k;
  1.1108 +    nssList_Add(certList, nssCertificate_AddRef(c));
  1.1109 +}
  1.1110 +
  1.1111 +NSS_EXTERN NSSCertificate **
  1.1112 +nssTrustDomain_GetCertsFromCache (
  1.1113 +  NSSTrustDomain *td,
  1.1114 +  nssList *certListOpt
  1.1115 +)
  1.1116 +{
  1.1117 +    NSSCertificate **rvArray = NULL;
  1.1118 +    nssList *certList;
  1.1119 +    if (certListOpt) {
  1.1120 +	certList = certListOpt;
  1.1121 +    } else {
  1.1122 +	certList = nssList_Create(NULL, PR_FALSE);
  1.1123 +	if (!certList) {
  1.1124 +	    return NULL;
  1.1125 +	}
  1.1126 +    }
  1.1127 +    PZ_Lock(td->cache->lock);
  1.1128 +    nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
  1.1129 +    PZ_Unlock(td->cache->lock);
  1.1130 +    if (!certListOpt) {
  1.1131 +	PRUint32 count = nssList_Count(certList);
  1.1132 +	rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
  1.1133 +	nssList_GetArray(certList, (void **)rvArray, count);
  1.1134 +	/* array takes the references */
  1.1135 +	nssList_Destroy(certList);
  1.1136 +    }
  1.1137 +    return rvArray;
  1.1138 +}
  1.1139 +
  1.1140 +NSS_IMPLEMENT void
  1.1141 +nssTrustDomain_DumpCacheInfo (
  1.1142 +  NSSTrustDomain *td,
  1.1143 +  void (* cert_dump_iter)(const void *, void *, void *),
  1.1144 +  void *arg
  1.1145 +)
  1.1146 +{
  1.1147 +    PZ_Lock(td->cache->lock);
  1.1148 +    nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
  1.1149 +    PZ_Unlock(td->cache->lock);
  1.1150 +}

mercurial