| Index: nss/lib/pki/tdcache.c
|
| diff --git a/nss/lib/pki/tdcache.c b/nss/lib/pki/tdcache.c
|
| deleted file mode 100644
|
| index 5f9dfdd5c20481237a815278d8992b3f342d87e1..0000000000000000000000000000000000000000
|
| --- a/nss/lib/pki/tdcache.c
|
| +++ /dev/null
|
| @@ -1,1133 +0,0 @@
|
| -/* This Source Code Form is subject to the terms of the Mozilla Public
|
| - * License, v. 2.0. If a copy of the MPL was not distributed with this
|
| - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
| -
|
| -#ifndef PKIM_H
|
| -#include "pkim.h"
|
| -#endif /* PKIM_H */
|
| -
|
| -#ifndef PKIT_H
|
| -#include "pkit.h"
|
| -#endif /* PKIT_H */
|
| -
|
| -#ifndef NSSPKI_H
|
| -#include "nsspki.h"
|
| -#endif /* NSSPKI_H */
|
| -
|
| -#ifndef PKI_H
|
| -#include "pki.h"
|
| -#endif /* PKI_H */
|
| -
|
| -#ifndef NSSBASE_H
|
| -#include "nssbase.h"
|
| -#endif /* NSSBASE_H */
|
| -
|
| -#ifndef BASE_H
|
| -#include "base.h"
|
| -#endif /* BASE_H */
|
| -
|
| -#include "cert.h"
|
| -#include "dev.h"
|
| -#include "pki3hack.h"
|
| -
|
| -#ifdef DEBUG_CACHE
|
| -static PRLogModuleInfo *s_log = NULL;
|
| -#endif
|
| -
|
| -#ifdef DEBUG_CACHE
|
| -static void log_item_dump(const char *msg, NSSItem *it)
|
| -{
|
| - char buf[33];
|
| - int i, j;
|
| - for (i=0; i<10 && i<it->size; i++) {
|
| - sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]);
|
| - }
|
| - if (it->size>10) {
|
| - sprintf(&buf[2*i], "..");
|
| - i += 1;
|
| - for (j=it->size-1; i<=16 && j>10; i++, j--) {
|
| - sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]);
|
| - }
|
| - }
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
|
| -}
|
| -#endif
|
| -
|
| -#ifdef DEBUG_CACHE
|
| -static void log_cert_ref(const char *msg, NSSCertificate *c)
|
| -{
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg,
|
| - (c->nickname) ? c->nickname : c->email));
|
| - log_item_dump("\tserial", &c->serial);
|
| - log_item_dump("\tsubject", &c->subject);
|
| -}
|
| -#endif
|
| -
|
| -/* Certificate cache routines */
|
| -
|
| -/* XXX
|
| - * Locking is not handled well at all. A single, global lock with sub-locks
|
| - * in the collection types. Cleanup needed.
|
| - */
|
| -
|
| -/* should it live in its own arena? */
|
| -struct nssTDCertificateCacheStr
|
| -{
|
| - PZLock *lock;
|
| - NSSArena *arena;
|
| - nssHash *issuerAndSN;
|
| - nssHash *subject;
|
| - nssHash *nickname;
|
| - nssHash *email;
|
| -};
|
| -
|
| -struct cache_entry_str
|
| -{
|
| - union {
|
| - NSSCertificate *cert;
|
| - nssList *list;
|
| - void *value;
|
| - } entry;
|
| - PRUint32 hits;
|
| - PRTime lastHit;
|
| - NSSArena *arena;
|
| - NSSUTF8 *nickname;
|
| -};
|
| -
|
| -typedef struct cache_entry_str cache_entry;
|
| -
|
| -static cache_entry *
|
| -new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
|
| -{
|
| - cache_entry *ce = nss_ZNEW(arena, cache_entry);
|
| - if (ce) {
|
| - ce->entry.value = value;
|
| - ce->hits = 1;
|
| - ce->lastHit = PR_Now();
|
| - if (ownArena) {
|
| - ce->arena = arena;
|
| - }
|
| - ce->nickname = NULL;
|
| - }
|
| - return ce;
|
| -}
|
| -
|
| -/* this should not be exposed in a header, but is here to keep the above
|
| - * types/functions static
|
| - */
|
| -NSS_IMPLEMENT PRStatus
|
| -nssTrustDomain_InitializeCache (
|
| - NSSTrustDomain *td,
|
| - PRUint32 cacheSize
|
| -)
|
| -{
|
| - NSSArena *arena;
|
| - nssTDCertificateCache *cache = td->cache;
|
| -#ifdef DEBUG_CACHE
|
| - s_log = PR_NewLogModule("nss_cache");
|
| - PR_ASSERT(s_log);
|
| -#endif
|
| - PR_ASSERT(!cache);
|
| - arena = nssArena_Create();
|
| - if (!arena) {
|
| - return PR_FAILURE;
|
| - }
|
| - cache = nss_ZNEW(arena, nssTDCertificateCache);
|
| - if (!cache) {
|
| - nssArena_Destroy(arena);
|
| - return PR_FAILURE;
|
| - }
|
| - cache->lock = PZ_NewLock(nssILockCache);
|
| - if (!cache->lock) {
|
| - nssArena_Destroy(arena);
|
| - return PR_FAILURE;
|
| - }
|
| - /* Create the issuer and serial DER --> certificate hash */
|
| - cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
|
| - if (!cache->issuerAndSN) {
|
| - goto loser;
|
| - }
|
| - /* Create the subject DER --> subject list hash */
|
| - cache->subject = nssHash_CreateItem(arena, cacheSize);
|
| - if (!cache->subject) {
|
| - goto loser;
|
| - }
|
| - /* Create the nickname --> subject list hash */
|
| - cache->nickname = nssHash_CreateString(arena, cacheSize);
|
| - if (!cache->nickname) {
|
| - goto loser;
|
| - }
|
| - /* Create the email --> list of subject lists hash */
|
| - cache->email = nssHash_CreateString(arena, cacheSize);
|
| - if (!cache->email) {
|
| - goto loser;
|
| - }
|
| - cache->arena = arena;
|
| - td->cache = cache;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
|
| -#endif
|
| - return PR_SUCCESS;
|
| -loser:
|
| - PZ_DestroyLock(cache->lock);
|
| - nssArena_Destroy(arena);
|
| - td->cache = NULL;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
|
| -#endif
|
| - return PR_FAILURE;
|
| -}
|
| -
|
| -/* The entries of the hashtable are currently dependent on the certificate(s)
|
| - * that produced them. That is, the entries will be freed when the cert is
|
| - * released from the cache. If there are certs in the cache at any time,
|
| - * including shutdown, the hash table entries will hold memory. In order for
|
| - * clean shutdown, it is necessary for there to be no certs in the cache.
|
| - */
|
| -
|
| -extern const NSSError NSS_ERROR_INTERNAL_ERROR;
|
| -extern const NSSError NSS_ERROR_BUSY;
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nssTrustDomain_DestroyCache (
|
| - NSSTrustDomain *td
|
| -)
|
| -{
|
| - if (!td->cache) {
|
| - nss_SetError(NSS_ERROR_INTERNAL_ERROR);
|
| - return PR_FAILURE;
|
| - }
|
| - if (nssHash_Count(td->cache->issuerAndSN) > 0) {
|
| - nss_SetError(NSS_ERROR_BUSY);
|
| - return PR_FAILURE;
|
| - }
|
| - PZ_DestroyLock(td->cache->lock);
|
| - nssHash_Destroy(td->cache->issuerAndSN);
|
| - nssHash_Destroy(td->cache->subject);
|
| - nssHash_Destroy(td->cache->nickname);
|
| - nssHash_Destroy(td->cache->email);
|
| - nssArena_Destroy(td->cache->arena);
|
| - td->cache = NULL;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
|
| -#endif
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -static PRStatus
|
| -remove_issuer_and_serial_entry (
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert
|
| -)
|
| -{
|
| - /* Remove the cert from the issuer/serial hash */
|
| - nssHash_Remove(cache->issuerAndSN, cert);
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("removed issuer/sn", cert);
|
| -#endif
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -static PRStatus
|
| -remove_subject_entry (
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert,
|
| - nssList **subjectList,
|
| - NSSUTF8 **nickname,
|
| - NSSArena **arena
|
| -)
|
| -{
|
| - PRStatus nssrv;
|
| - cache_entry *ce;
|
| - *subjectList = NULL;
|
| - *arena = NULL;
|
| - /* Get the subject list for the cert's subject */
|
| - ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
|
| - if (ce) {
|
| - /* Remove the cert from the subject hash */
|
| - nssList_Remove(ce->entry.list, cert);
|
| - *subjectList = ce->entry.list;
|
| - *nickname = ce->nickname;
|
| - *arena = ce->arena;
|
| - nssrv = PR_SUCCESS;
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("removed cert", cert);
|
| - log_item_dump("from subject list", &cert->subject);
|
| -#endif
|
| - } else {
|
| - nssrv = PR_FAILURE;
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -static PRStatus
|
| -remove_nickname_entry (
|
| - nssTDCertificateCache *cache,
|
| - NSSUTF8 *nickname,
|
| - nssList *subjectList
|
| -)
|
| -{
|
| - PRStatus nssrv;
|
| - if (nickname) {
|
| - nssHash_Remove(cache->nickname, nickname);
|
| - nssrv = PR_SUCCESS;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
|
| -#endif
|
| - } else {
|
| - nssrv = PR_FAILURE;
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -static PRStatus
|
| -remove_email_entry (
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert,
|
| - nssList *subjectList
|
| -)
|
| -{
|
| - PRStatus nssrv = PR_FAILURE;
|
| - cache_entry *ce;
|
| - /* Find the subject list in the email hash */
|
| - if (cert->email) {
|
| - ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
|
| - if (ce) {
|
| - nssList *subjects = ce->entry.list;
|
| - /* Remove the subject list from the email hash */
|
| - nssList_Remove(subjects, subjectList);
|
| -#ifdef DEBUG_CACHE
|
| - log_item_dump("removed subject list", &cert->subject);
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
|
| -#endif
|
| - if (nssList_Count(subjects) == 0) {
|
| - /* No more subject lists for email, delete list and
|
| - * remove hash entry
|
| - */
|
| - (void)nssList_Destroy(subjects);
|
| - nssHash_Remove(cache->email, cert->email);
|
| - /* there are no entries left for this address, free space
|
| - * used for email entries
|
| - */
|
| - nssArena_Destroy(ce->arena);
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
|
| -#endif
|
| - }
|
| - nssrv = PR_SUCCESS;
|
| - }
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -NSS_IMPLEMENT void
|
| -nssTrustDomain_RemoveCertFromCacheLOCKED (
|
| - NSSTrustDomain *td,
|
| - NSSCertificate *cert
|
| -)
|
| -{
|
| - nssList *subjectList;
|
| - cache_entry *ce;
|
| - NSSArena *arena;
|
| - NSSUTF8 *nickname = NULL;
|
| -
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("attempt to remove cert", cert);
|
| -#endif
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
|
| - if (!ce || ce->entry.cert != cert) {
|
| - /* If it's not in the cache, or a different cert is (this is really
|
| - * for safety reasons, though it shouldn't happen), do nothing
|
| - */
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
|
| -#endif
|
| - return;
|
| - }
|
| - (void)remove_issuer_and_serial_entry(td->cache, cert);
|
| - (void)remove_subject_entry(td->cache, cert, &subjectList,
|
| - &nickname, &arena);
|
| - if (nssList_Count(subjectList) == 0) {
|
| - (void)remove_nickname_entry(td->cache, nickname, subjectList);
|
| - (void)remove_email_entry(td->cache, cert, subjectList);
|
| - (void)nssList_Destroy(subjectList);
|
| - nssHash_Remove(td->cache->subject, &cert->subject);
|
| - /* there are no entries left for this subject, free the space used
|
| - * for both the nickname and subject entries
|
| - */
|
| - if (arena) {
|
| - nssArena_Destroy(arena);
|
| - }
|
| - }
|
| -}
|
| -
|
| -NSS_IMPLEMENT void
|
| -nssTrustDomain_LockCertCache (
|
| - NSSTrustDomain *td
|
| -)
|
| -{
|
| - PZ_Lock(td->cache->lock);
|
| -}
|
| -
|
| -NSS_IMPLEMENT void
|
| -nssTrustDomain_UnlockCertCache (
|
| - NSSTrustDomain *td
|
| -)
|
| -{
|
| - PZ_Unlock(td->cache->lock);
|
| -}
|
| -
|
| -struct token_cert_dtor {
|
| - NSSToken *token;
|
| - nssTDCertificateCache *cache;
|
| - NSSCertificate **certs;
|
| - PRUint32 numCerts, arrSize;
|
| -};
|
| -
|
| -static void
|
| -remove_token_certs(const void *k, void *v, void *a)
|
| -{
|
| - NSSCertificate *c = (NSSCertificate *)k;
|
| - nssPKIObject *object = &c->object;
|
| - struct token_cert_dtor *dtor = a;
|
| - PRUint32 i;
|
| - nssPKIObject_AddRef(object);
|
| - nssPKIObject_Lock(object);
|
| - for (i=0; i<object->numInstances; i++) {
|
| - if (object->instances[i]->token == dtor->token) {
|
| - nssCryptokiObject_Destroy(object->instances[i]);
|
| - object->instances[i] = object->instances[object->numInstances-1];
|
| - object->instances[object->numInstances-1] = NULL;
|
| - object->numInstances--;
|
| - dtor->certs[dtor->numCerts++] = c;
|
| - if (dtor->numCerts == dtor->arrSize) {
|
| - dtor->arrSize *= 2;
|
| - dtor->certs = nss_ZREALLOCARRAY(dtor->certs,
|
| - NSSCertificate *,
|
| - dtor->arrSize);
|
| - }
|
| - break;
|
| - }
|
| - }
|
| - nssPKIObject_Unlock(object);
|
| - nssPKIObject_Destroy(object);
|
| - return;
|
| -}
|
| -
|
| -/*
|
| - * Remove all certs for the given token from the cache. This is
|
| - * needed if the token is removed.
|
| - */
|
| -NSS_IMPLEMENT PRStatus
|
| -nssTrustDomain_RemoveTokenCertsFromCache (
|
| - NSSTrustDomain *td,
|
| - NSSToken *token
|
| -)
|
| -{
|
| - NSSCertificate **certs;
|
| - PRUint32 i, arrSize = 10;
|
| - struct token_cert_dtor dtor;
|
| - certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
|
| - if (!certs) {
|
| - return PR_FAILURE;
|
| - }
|
| - dtor.cache = td->cache;
|
| - dtor.token = token;
|
| - dtor.certs = certs;
|
| - dtor.numCerts = 0;
|
| - dtor.arrSize = arrSize;
|
| - PZ_Lock(td->cache->lock);
|
| - nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, &dtor);
|
| - for (i=0; i<dtor.numCerts; i++) {
|
| - if (dtor.certs[i]->object.numInstances == 0) {
|
| - nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
|
| - dtor.certs[i] = NULL; /* skip this cert in the second for loop */
|
| - } else {
|
| - /* make sure it doesn't disappear on us before we finish */
|
| - nssCertificate_AddRef(dtor.certs[i]);
|
| - }
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - for (i=0; i<dtor.numCerts; i++) {
|
| - if (dtor.certs[i]) {
|
| - STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
|
| - nssCertificate_Destroy(dtor.certs[i]);
|
| - }
|
| - }
|
| - nss_ZFreeIf(dtor.certs);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nssTrustDomain_UpdateCachedTokenCerts (
|
| - NSSTrustDomain *td,
|
| - NSSToken *token
|
| -)
|
| -{
|
| - NSSCertificate **cp, **cached = NULL;
|
| - nssList *certList;
|
| - PRUint32 count;
|
| - certList = nssList_Create(NULL, PR_FALSE);
|
| - if (!certList) return PR_FAILURE;
|
| - (void)nssTrustDomain_GetCertsFromCache(td, certList);
|
| - count = nssList_Count(certList);
|
| - if (count > 0) {
|
| - cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
|
| - if (!cached) {
|
| - nssList_Destroy(certList);
|
| - return PR_FAILURE;
|
| - }
|
| - nssList_GetArray(certList, (void **)cached, count);
|
| - for (cp = cached; *cp; cp++) {
|
| - nssCryptokiObject *instance;
|
| - NSSCertificate *c = *cp;
|
| - nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
|
| - instance = nssToken_FindCertificateByIssuerAndSerialNumber(
|
| - token,
|
| - NULL,
|
| - &c->issuer,
|
| - &c->serial,
|
| - tokenOnly,
|
| - NULL);
|
| - if (instance) {
|
| - nssPKIObject_AddInstance(&c->object, instance);
|
| - STAN_ForceCERTCertificateUpdate(c);
|
| - }
|
| - }
|
| - nssCertificateArray_Destroy(cached);
|
| - }
|
| - nssList_Destroy(certList);
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -static PRStatus
|
| -add_issuer_and_serial_entry (
|
| - NSSArena *arena,
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert
|
| -)
|
| -{
|
| - cache_entry *ce;
|
| - ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("added to issuer/sn", cert);
|
| -#endif
|
| - return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
|
| -}
|
| -
|
| -static PRStatus
|
| -add_subject_entry (
|
| - NSSArena *arena,
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert,
|
| - NSSUTF8 *nickname,
|
| - nssList **subjectList
|
| -)
|
| -{
|
| - PRStatus nssrv;
|
| - nssList *list;
|
| - cache_entry *ce;
|
| - *subjectList = NULL; /* this is only set if a new one is created */
|
| - ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| - /* The subject is already in, add this cert to the list */
|
| - nssrv = nssList_AddUnique(ce->entry.list, cert);
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("added to existing subject list", cert);
|
| -#endif
|
| - } else {
|
| - NSSDER *subject;
|
| - /* Create a new subject list for the subject */
|
| - list = nssList_Create(arena, PR_FALSE);
|
| - if (!list) {
|
| - return PR_FAILURE;
|
| - }
|
| - ce = new_cache_entry(arena, (void *)list, PR_TRUE);
|
| - if (!ce) {
|
| - return PR_FAILURE;
|
| - }
|
| - if (nickname) {
|
| - ce->nickname = nssUTF8_Duplicate(nickname, arena);
|
| - }
|
| - nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
|
| - /* Add the cert entry to this list of subjects */
|
| - nssrv = nssList_AddUnique(list, cert);
|
| - if (nssrv != PR_SUCCESS) {
|
| - return nssrv;
|
| - }
|
| - /* Add the subject list to the cache */
|
| - subject = nssItem_Duplicate(&cert->subject, arena, NULL);
|
| - if (!subject) {
|
| - return PR_FAILURE;
|
| - }
|
| - nssrv = nssHash_Add(cache->subject, subject, ce);
|
| - if (nssrv != PR_SUCCESS) {
|
| - return nssrv;
|
| - }
|
| - *subjectList = list;
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("created subject list", cert);
|
| -#endif
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -static PRStatus
|
| -add_nickname_entry (
|
| - NSSArena *arena,
|
| - nssTDCertificateCache *cache,
|
| - NSSUTF8 *certNickname,
|
| - nssList *subjectList
|
| -)
|
| -{
|
| - PRStatus nssrv = PR_SUCCESS;
|
| - cache_entry *ce;
|
| - ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
|
| - if (ce) {
|
| - /* This is a collision. A nickname entry already exists for this
|
| - * subject, but a subject entry didn't. This would imply there are
|
| - * two subjects using the same nickname, which is not allowed.
|
| - */
|
| - return PR_FAILURE;
|
| - } else {
|
| - NSSUTF8 *nickname;
|
| - ce = new_cache_entry(arena, subjectList, PR_FALSE);
|
| - if (!ce) {
|
| - return PR_FAILURE;
|
| - }
|
| - nickname = nssUTF8_Duplicate(certNickname, arena);
|
| - if (!nickname) {
|
| - return PR_FAILURE;
|
| - }
|
| - nssrv = nssHash_Add(cache->nickname, nickname, ce);
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("created nickname for", cert);
|
| -#endif
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -static PRStatus
|
| -add_email_entry (
|
| - nssTDCertificateCache *cache,
|
| - NSSCertificate *cert,
|
| - nssList *subjectList
|
| -)
|
| -{
|
| - PRStatus nssrv = PR_SUCCESS;
|
| - nssList *subjects;
|
| - cache_entry *ce;
|
| - ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
|
| - if (ce) {
|
| - /* Already have an entry for this email address, but not subject */
|
| - subjects = ce->entry.list;
|
| - nssrv = nssList_AddUnique(subjects, subjectList);
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("added subject to email for", cert);
|
| -#endif
|
| - } else {
|
| - NSSASCII7 *email;
|
| - NSSArena *arena;
|
| - arena = nssArena_Create();
|
| - if (!arena) {
|
| - return PR_FAILURE;
|
| - }
|
| - /* Create a new list of subject lists, add this subject */
|
| - subjects = nssList_Create(arena, PR_TRUE);
|
| - if (!subjects) {
|
| - nssArena_Destroy(arena);
|
| - return PR_FAILURE;
|
| - }
|
| - /* Add the new subject to the list */
|
| - nssrv = nssList_AddUnique(subjects, subjectList);
|
| - if (nssrv != PR_SUCCESS) {
|
| - nssArena_Destroy(arena);
|
| - return nssrv;
|
| - }
|
| - /* Add the new entry to the cache */
|
| - ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
|
| - if (!ce) {
|
| - nssArena_Destroy(arena);
|
| - return PR_FAILURE;
|
| - }
|
| - email = nssUTF8_Duplicate(cert->email, arena);
|
| - if (!email) {
|
| - nssArena_Destroy(arena);
|
| - return PR_FAILURE;
|
| - }
|
| - nssrv = nssHash_Add(cache->email, email, ce);
|
| - if (nssrv != PR_SUCCESS) {
|
| - nssArena_Destroy(arena);
|
| - return nssrv;
|
| - }
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("created email for", cert);
|
| -#endif
|
| - }
|
| - return nssrv;
|
| -}
|
| -
|
| -extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
|
| -
|
| -static void
|
| -remove_object_instances (
|
| - nssPKIObject *object,
|
| - nssCryptokiObject **instances,
|
| - int numInstances
|
| -)
|
| -{
|
| - int i;
|
| -
|
| - for (i = 0; i < numInstances; i++) {
|
| - nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
|
| - }
|
| -}
|
| -
|
| -static SECStatus
|
| -merge_object_instances (
|
| - nssPKIObject *to,
|
| - nssPKIObject *from
|
| -)
|
| -{
|
| - nssCryptokiObject **instances, **ci;
|
| - int i;
|
| - SECStatus rv = SECSuccess;
|
| -
|
| - instances = nssPKIObject_GetInstances(from);
|
| - if (instances == NULL) {
|
| - return SECFailure;
|
| - }
|
| - for (ci = instances, i = 0; *ci; ci++, i++) {
|
| - nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
|
| - if (instance) {
|
| - if (nssPKIObject_AddInstance(to, instance) == PR_SUCCESS) {
|
| - continue;
|
| - }
|
| - nssCryptokiObject_Destroy(instance);
|
| - }
|
| - remove_object_instances(to, instances, i);
|
| - rv = SECFailure;
|
| - break;
|
| - }
|
| - nssCryptokiObjectArray_Destroy(instances);
|
| - return rv;
|
| -}
|
| -
|
| -static NSSCertificate *
|
| -add_cert_to_cache (
|
| - NSSTrustDomain *td,
|
| - NSSCertificate *cert
|
| -)
|
| -{
|
| - NSSArena *arena = NULL;
|
| - nssList *subjectList = NULL;
|
| - PRStatus nssrv;
|
| - PRUint32 added = 0;
|
| - cache_entry *ce;
|
| - NSSCertificate *rvCert = NULL;
|
| - NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
|
| -
|
| - PZ_Lock(td->cache->lock);
|
| - /* If it exists in the issuer/serial hash, it's already in all */
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| - rvCert = nssCertificate_AddRef(ce->entry.cert);
|
| -#ifdef DEBUG_CACHE
|
| - log_cert_ref("attempted to add cert already in cache", cert);
|
| -#endif
|
| - PZ_Unlock(td->cache->lock);
|
| - nss_ZFreeIf(certNickname);
|
| - /* collision - somebody else already added the cert
|
| - * to the cache before this thread got around to it.
|
| - */
|
| - /* merge the instances of the cert */
|
| - if (merge_object_instances(&rvCert->object, &cert->object)
|
| - != SECSuccess) {
|
| - nssCertificate_Destroy(rvCert);
|
| - return NULL;
|
| - }
|
| - STAN_ForceCERTCertificateUpdate(rvCert);
|
| - nssCertificate_Destroy(cert);
|
| - return rvCert;
|
| - }
|
| - /* create a new cache entry for this cert within the cert's arena*/
|
| - nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
|
| - if (nssrv != PR_SUCCESS) {
|
| - goto loser;
|
| - }
|
| - added++;
|
| - /* create an arena for the nickname and subject entries */
|
| - arena = nssArena_Create();
|
| - if (!arena) {
|
| - goto loser;
|
| - }
|
| - /* create a new subject list for this cert, or add to existing */
|
| - nssrv = add_subject_entry(arena, td->cache, cert,
|
| - certNickname, &subjectList);
|
| - if (nssrv != PR_SUCCESS) {
|
| - goto loser;
|
| - }
|
| - added++;
|
| - /* If a new subject entry was created, also need nickname and/or email */
|
| - if (subjectList != NULL) {
|
| -#ifdef nodef
|
| - PRBool handle = PR_FALSE;
|
| -#endif
|
| - if (certNickname) {
|
| - nssrv = add_nickname_entry(arena, td->cache,
|
| - certNickname, subjectList);
|
| - if (nssrv != PR_SUCCESS) {
|
| - goto loser;
|
| - }
|
| -#ifdef nodef
|
| - handle = PR_TRUE;
|
| -#endif
|
| - added++;
|
| - }
|
| - if (cert->email) {
|
| - nssrv = add_email_entry(td->cache, cert, subjectList);
|
| - if (nssrv != PR_SUCCESS) {
|
| - goto loser;
|
| - }
|
| -#ifdef nodef
|
| - handle = PR_TRUE;
|
| -#endif
|
| - added += 2;
|
| - }
|
| -#ifdef nodef
|
| - /* I think either a nickname or email address must be associated
|
| - * with the cert. However, certs are passed to NewTemp without
|
| - * either. This worked in the old code, so it must work now.
|
| - */
|
| - if (!handle) {
|
| - /* Require either nickname or email handle */
|
| - nssrv = PR_FAILURE;
|
| - goto loser;
|
| - }
|
| -#endif
|
| - } else {
|
| - /* A new subject entry was not created. arena is unused. */
|
| - nssArena_Destroy(arena);
|
| - }
|
| - rvCert = cert;
|
| - PZ_Unlock(td->cache->lock);
|
| - nss_ZFreeIf(certNickname);
|
| - return rvCert;
|
| -loser:
|
| - nss_ZFreeIf(certNickname);
|
| - certNickname = NULL;
|
| - /* Remove any handles that have been created */
|
| - subjectList = NULL;
|
| - if (added >= 1) {
|
| - (void)remove_issuer_and_serial_entry(td->cache, cert);
|
| - }
|
| - if (added >= 2) {
|
| - (void)remove_subject_entry(td->cache, cert, &subjectList,
|
| - &certNickname, &arena);
|
| - }
|
| - if (added == 3 || added == 5) {
|
| - (void)remove_nickname_entry(td->cache, certNickname, subjectList);
|
| - }
|
| - if (added >= 4) {
|
| - (void)remove_email_entry(td->cache, cert, subjectList);
|
| - }
|
| - if (subjectList) {
|
| - nssHash_Remove(td->cache->subject, &cert->subject);
|
| - nssList_Destroy(subjectList);
|
| - }
|
| - if (arena) {
|
| - nssArena_Destroy(arena);
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - return NULL;
|
| -}
|
| -
|
| -NSS_IMPLEMENT PRStatus
|
| -nssTrustDomain_AddCertsToCache (
|
| - NSSTrustDomain *td,
|
| - NSSCertificate **certs,
|
| - PRUint32 numCerts
|
| -)
|
| -{
|
| - PRUint32 i;
|
| - NSSCertificate *c;
|
| - for (i=0; i<numCerts && certs[i]; i++) {
|
| - c = add_cert_to_cache(td, certs[i]);
|
| - if (c == NULL) {
|
| - return PR_FAILURE;
|
| - } else {
|
| - certs[i] = c;
|
| - }
|
| - }
|
| - return PR_SUCCESS;
|
| -}
|
| -
|
| -static NSSCertificate **
|
| -collect_subject_certs (
|
| - nssList *subjectList,
|
| - nssList *rvCertListOpt
|
| -)
|
| -{
|
| - NSSCertificate *c;
|
| - NSSCertificate **rvArray = NULL;
|
| - PRUint32 count;
|
| - nssCertificateList_AddReferences(subjectList);
|
| - if (rvCertListOpt) {
|
| - nssListIterator *iter = nssList_CreateIterator(subjectList);
|
| - if (!iter) {
|
| - return (NSSCertificate **)NULL;
|
| - }
|
| - for (c = (NSSCertificate *)nssListIterator_Start(iter);
|
| - c != (NSSCertificate *)NULL;
|
| - c = (NSSCertificate *)nssListIterator_Next(iter)) {
|
| - nssList_Add(rvCertListOpt, c);
|
| - }
|
| - nssListIterator_Finish(iter);
|
| - nssListIterator_Destroy(iter);
|
| - } else {
|
| - count = nssList_Count(subjectList);
|
| - rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
|
| - if (!rvArray) {
|
| - return (NSSCertificate **)NULL;
|
| - }
|
| - nssList_GetArray(subjectList, (void **)rvArray, count);
|
| - }
|
| - return rvArray;
|
| -}
|
| -
|
| -/*
|
| - * Find all cached certs with this subject.
|
| - */
|
| -NSS_IMPLEMENT NSSCertificate **
|
| -nssTrustDomain_GetCertsForSubjectFromCache (
|
| - NSSTrustDomain *td,
|
| - NSSDER *subject,
|
| - nssList *certListOpt
|
| -)
|
| -{
|
| - NSSCertificate **rvArray = NULL;
|
| - cache_entry *ce;
|
| -#ifdef DEBUG_CACHE
|
| - log_item_dump("looking for cert by subject", subject);
|
| -#endif
|
| - PZ_Lock(td->cache->lock);
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
|
| -#endif
|
| - rvArray = collect_subject_certs(ce->entry.list, certListOpt);
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - return rvArray;
|
| -}
|
| -
|
| -/*
|
| - * Find all cached certs with this label.
|
| - */
|
| -NSS_IMPLEMENT NSSCertificate **
|
| -nssTrustDomain_GetCertsForNicknameFromCache (
|
| - NSSTrustDomain *td,
|
| - const NSSUTF8 *nickname,
|
| - nssList *certListOpt
|
| -)
|
| -{
|
| - NSSCertificate **rvArray = NULL;
|
| - cache_entry *ce;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
|
| -#endif
|
| - PZ_Lock(td->cache->lock);
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
|
| -#endif
|
| - rvArray = collect_subject_certs(ce->entry.list, certListOpt);
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - return rvArray;
|
| -}
|
| -
|
| -/*
|
| - * Find all cached certs with this email address.
|
| - */
|
| -NSS_IMPLEMENT NSSCertificate **
|
| -nssTrustDomain_GetCertsForEmailAddressFromCache (
|
| - NSSTrustDomain *td,
|
| - NSSASCII7 *email,
|
| - nssList *certListOpt
|
| -)
|
| -{
|
| - NSSCertificate **rvArray = NULL;
|
| - cache_entry *ce;
|
| - nssList *collectList = NULL;
|
| - nssListIterator *iter = NULL;
|
| - nssList *subjectList;
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
|
| -#endif
|
| - PZ_Lock(td->cache->lock);
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
|
| -#endif
|
| - /* loop over subject lists and get refs for certs */
|
| - if (certListOpt) {
|
| - collectList = certListOpt;
|
| - } else {
|
| - collectList = nssList_Create(NULL, PR_FALSE);
|
| - if (!collectList) {
|
| - PZ_Unlock(td->cache->lock);
|
| - return NULL;
|
| - }
|
| - }
|
| - iter = nssList_CreateIterator(ce->entry.list);
|
| - if (!iter) {
|
| - PZ_Unlock(td->cache->lock);
|
| - if (!certListOpt) {
|
| - nssList_Destroy(collectList);
|
| - }
|
| - return NULL;
|
| - }
|
| - for (subjectList = (nssList *)nssListIterator_Start(iter);
|
| - subjectList != (nssList *)NULL;
|
| - subjectList = (nssList *)nssListIterator_Next(iter)) {
|
| - (void)collect_subject_certs(subjectList, collectList);
|
| - }
|
| - nssListIterator_Finish(iter);
|
| - nssListIterator_Destroy(iter);
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - if (!certListOpt && collectList) {
|
| - PRUint32 count = nssList_Count(collectList);
|
| - rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
|
| - if (rvArray) {
|
| - nssList_GetArray(collectList, (void **)rvArray, count);
|
| - }
|
| - nssList_Destroy(collectList);
|
| - }
|
| - return rvArray;
|
| -}
|
| -
|
| -/*
|
| - * Look for a specific cert in the cache
|
| - */
|
| -NSS_IMPLEMENT NSSCertificate *
|
| -nssTrustDomain_GetCertForIssuerAndSNFromCache (
|
| - NSSTrustDomain *td,
|
| - NSSDER *issuer,
|
| - NSSDER *serial
|
| -)
|
| -{
|
| - NSSCertificate certkey;
|
| - NSSCertificate *rvCert = NULL;
|
| - cache_entry *ce;
|
| - certkey.issuer.data = issuer->data;
|
| - certkey.issuer.size = issuer->size;
|
| - certkey.serial.data = serial->data;
|
| - certkey.serial.size = serial->size;
|
| -#ifdef DEBUG_CACHE
|
| - log_item_dump("looking for cert by issuer/sn, issuer", issuer);
|
| - log_item_dump(" serial", serial);
|
| -#endif
|
| - PZ_Lock(td->cache->lock);
|
| - ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
|
| - if (ce) {
|
| - ce->hits++;
|
| - ce->lastHit = PR_Now();
|
| - rvCert = nssCertificate_AddRef(ce->entry.cert);
|
| -#ifdef DEBUG_CACHE
|
| - PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
|
| -#endif
|
| - }
|
| - PZ_Unlock(td->cache->lock);
|
| - return rvCert;
|
| -}
|
| -
|
| -/*
|
| - * Look for a specific cert in the cache
|
| - */
|
| -NSS_IMPLEMENT NSSCertificate *
|
| -nssTrustDomain_GetCertByDERFromCache (
|
| - NSSTrustDomain *td,
|
| - NSSDER *der
|
| -)
|
| -{
|
| - PRStatus nssrv = PR_FAILURE;
|
| - NSSDER issuer, serial;
|
| - NSSCertificate *rvCert;
|
| - nssrv = nssPKIX509_GetIssuerAndSerialFromDER(der, &issuer, &serial);
|
| - if (nssrv != PR_SUCCESS) {
|
| - return NULL;
|
| - }
|
| -#ifdef DEBUG_CACHE
|
| - log_item_dump("looking for cert by DER", der);
|
| -#endif
|
| - rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td,
|
| - &issuer, &serial);
|
| - PORT_Free(issuer.data);
|
| - PORT_Free(serial.data);
|
| - return rvCert;
|
| -}
|
| -
|
| -static void cert_iter(const void *k, void *v, void *a)
|
| -{
|
| - nssList *certList = (nssList *)a;
|
| - NSSCertificate *c = (NSSCertificate *)k;
|
| - nssList_Add(certList, nssCertificate_AddRef(c));
|
| -}
|
| -
|
| -NSS_EXTERN NSSCertificate **
|
| -nssTrustDomain_GetCertsFromCache (
|
| - NSSTrustDomain *td,
|
| - nssList *certListOpt
|
| -)
|
| -{
|
| - NSSCertificate **rvArray = NULL;
|
| - nssList *certList;
|
| - if (certListOpt) {
|
| - certList = certListOpt;
|
| - } else {
|
| - certList = nssList_Create(NULL, PR_FALSE);
|
| - if (!certList) {
|
| - return NULL;
|
| - }
|
| - }
|
| - PZ_Lock(td->cache->lock);
|
| - nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
|
| - PZ_Unlock(td->cache->lock);
|
| - if (!certListOpt) {
|
| - PRUint32 count = nssList_Count(certList);
|
| - rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
|
| - nssList_GetArray(certList, (void **)rvArray, count);
|
| - /* array takes the references */
|
| - nssList_Destroy(certList);
|
| - }
|
| - return rvArray;
|
| -}
|
| -
|
| -NSS_IMPLEMENT void
|
| -nssTrustDomain_DumpCacheInfo (
|
| - NSSTrustDomain *td,
|
| - void (* cert_dump_iter)(const void *, void *, void *),
|
| - void *arg
|
| -)
|
| -{
|
| - PZ_Lock(td->cache->lock);
|
| - nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
|
| - PZ_Unlock(td->cache->lock);
|
| -}
|
|
|