michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef PKIM_H michael@0: #include "pkim.h" michael@0: #endif /* PKIM_H */ michael@0: michael@0: #ifndef PKI_H michael@0: #include "pki.h" michael@0: #endif /* PKI_H */ michael@0: michael@0: #ifndef NSSPKI_H michael@0: #include "nsspki.h" michael@0: #endif /* NSSPKI_H */ michael@0: michael@0: #ifndef BASE_H michael@0: #include "base.h" michael@0: #endif /* BASE_H */ michael@0: michael@0: #ifndef PKISTORE_H michael@0: #include "pkistore.h" michael@0: #endif /* PKISTORE_H */ michael@0: michael@0: #include "cert.h" michael@0: michael@0: #include "prbit.h" michael@0: michael@0: /* michael@0: * Certificate Store michael@0: * michael@0: * This differs from the cache in that it is a true storage facility. Items michael@0: * stay in until they are explicitly removed. It is only used by crypto michael@0: * contexts at this time, but may be more generally useful... michael@0: * michael@0: */ michael@0: michael@0: struct nssCertificateStoreStr michael@0: { michael@0: PRBool i_alloced_arena; michael@0: NSSArena *arena; michael@0: PZLock *lock; michael@0: nssHash *subject; michael@0: nssHash *issuer_and_serial; michael@0: }; michael@0: michael@0: typedef struct certificate_hash_entry_str certificate_hash_entry; michael@0: michael@0: struct certificate_hash_entry_str michael@0: { michael@0: NSSCertificate *cert; michael@0: NSSTrust *trust; michael@0: nssSMIMEProfile *profile; michael@0: }; michael@0: michael@0: /* forward static declarations */ michael@0: static NSSCertificate * michael@0: nssCertStore_FindCertByIssuerAndSerialNumberLocked ( michael@0: nssCertificateStore *store, michael@0: NSSDER *issuer, michael@0: NSSDER *serial michael@0: ); michael@0: michael@0: NSS_IMPLEMENT nssCertificateStore * michael@0: nssCertificateStore_Create ( michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: NSSArena *arena; michael@0: nssCertificateStore *store; michael@0: PRBool i_alloced_arena; michael@0: if (arenaOpt) { michael@0: arena = arenaOpt; michael@0: i_alloced_arena = PR_FALSE; michael@0: } else { michael@0: arena = nssArena_Create(); michael@0: if (!arena) { michael@0: return NULL; michael@0: } michael@0: i_alloced_arena = PR_TRUE; michael@0: } michael@0: store = nss_ZNEW(arena, nssCertificateStore); michael@0: if (!store) { michael@0: goto loser; michael@0: } michael@0: store->lock = PZ_NewLock(nssILockOther); michael@0: if (!store->lock) { michael@0: goto loser; michael@0: } michael@0: /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */ michael@0: store->issuer_and_serial = nssHash_CreateCertificate(arena, 0); michael@0: if (!store->issuer_and_serial) { michael@0: goto loser; michael@0: } michael@0: /* Create the subject DER --> subject list hash */ michael@0: store->subject = nssHash_CreateItem(arena, 0); michael@0: if (!store->subject) { michael@0: goto loser; michael@0: } michael@0: store->arena = arena; michael@0: store->i_alloced_arena = i_alloced_arena; michael@0: return store; michael@0: loser: michael@0: if (store) { michael@0: if (store->lock) { michael@0: PZ_DestroyLock(store->lock); michael@0: } michael@0: if (store->issuer_and_serial) { michael@0: nssHash_Destroy(store->issuer_and_serial); michael@0: } michael@0: if (store->subject) { michael@0: nssHash_Destroy(store->subject); michael@0: } michael@0: } michael@0: if (i_alloced_arena) { michael@0: nssArena_Destroy(arena); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: extern const NSSError NSS_ERROR_BUSY; michael@0: michael@0: NSS_IMPLEMENT PRStatus michael@0: nssCertificateStore_Destroy ( michael@0: nssCertificateStore *store michael@0: ) michael@0: { michael@0: if (nssHash_Count(store->issuer_and_serial) > 0) { michael@0: nss_SetError(NSS_ERROR_BUSY); michael@0: return PR_FAILURE; michael@0: } michael@0: PZ_DestroyLock(store->lock); michael@0: nssHash_Destroy(store->issuer_and_serial); michael@0: nssHash_Destroy(store->subject); michael@0: if (store->i_alloced_arena) { michael@0: nssArena_Destroy(store->arena); michael@0: } else { michael@0: nss_ZFreeIf(store); michael@0: } michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: static PRStatus michael@0: add_certificate_entry ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: PRStatus nssrv; michael@0: certificate_hash_entry *entry; michael@0: entry = nss_ZNEW(cert->object.arena, certificate_hash_entry); michael@0: if (!entry) { michael@0: return PR_FAILURE; michael@0: } michael@0: entry->cert = cert; michael@0: nssrv = nssHash_Add(store->issuer_and_serial, cert, entry); michael@0: if (nssrv != PR_SUCCESS) { michael@0: nss_ZFreeIf(entry); michael@0: } michael@0: return nssrv; michael@0: } michael@0: michael@0: static PRStatus michael@0: add_subject_entry ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: PRStatus nssrv; michael@0: nssList *subjectList; michael@0: subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject); michael@0: if (subjectList) { michael@0: /* The subject is already in, add this cert to the list */ michael@0: nssrv = nssList_AddUnique(subjectList, cert); michael@0: } else { michael@0: /* Create a new subject list for the subject */ michael@0: subjectList = nssList_Create(NULL, PR_FALSE); michael@0: if (!subjectList) { michael@0: return PR_FAILURE; michael@0: } michael@0: nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort); michael@0: /* Add the cert entry to this list of subjects */ michael@0: nssrv = nssList_Add(subjectList, cert); michael@0: if (nssrv != PR_SUCCESS) { michael@0: return nssrv; michael@0: } michael@0: /* Add the subject list to the cache */ michael@0: nssrv = nssHash_Add(store->subject, &cert->subject, subjectList); michael@0: } michael@0: return nssrv; michael@0: } michael@0: michael@0: /* declared below */ michael@0: static void michael@0: remove_certificate_entry ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ); michael@0: michael@0: /* Caller must hold store->lock */ michael@0: static PRStatus michael@0: nssCertificateStore_AddLocked ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: PRStatus nssrv = add_certificate_entry(store, cert); michael@0: if (nssrv == PR_SUCCESS) { michael@0: nssrv = add_subject_entry(store, cert); michael@0: if (nssrv == PR_FAILURE) { michael@0: remove_certificate_entry(store, cert); michael@0: } michael@0: } michael@0: return nssrv; michael@0: } michael@0: michael@0: michael@0: NSS_IMPLEMENT NSSCertificate * michael@0: nssCertificateStore_FindOrAdd ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *c michael@0: ) michael@0: { michael@0: PRStatus nssrv; michael@0: NSSCertificate *rvCert = NULL; michael@0: michael@0: PZ_Lock(store->lock); michael@0: rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked( michael@0: store, &c->issuer, &c->serial); michael@0: if (!rvCert) { michael@0: nssrv = nssCertificateStore_AddLocked(store, c); michael@0: if (PR_SUCCESS == nssrv) { michael@0: rvCert = nssCertificate_AddRef(c); michael@0: } michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return rvCert; michael@0: } michael@0: michael@0: static void michael@0: remove_certificate_entry ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: certificate_hash_entry *entry; michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry) { michael@0: nssHash_Remove(store->issuer_and_serial, cert); michael@0: if (entry->trust) { michael@0: nssTrust_Destroy(entry->trust); michael@0: } michael@0: if (entry->profile) { michael@0: nssSMIMEProfile_Destroy(entry->profile); michael@0: } michael@0: nss_ZFreeIf(entry); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: remove_subject_entry ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: nssList *subjectList; michael@0: /* Get the subject list for the cert's subject */ michael@0: subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject); michael@0: if (subjectList) { michael@0: /* Remove the cert from the subject hash */ michael@0: nssList_Remove(subjectList, cert); michael@0: nssHash_Remove(store->subject, &cert->subject); michael@0: if (nssList_Count(subjectList) == 0) { michael@0: nssList_Destroy(subjectList); michael@0: } else { michael@0: /* The cert being released may have keyed the subject entry. michael@0: * Since there are still subject certs around, get another and michael@0: * rekey the entry just in case. michael@0: */ michael@0: NSSCertificate *subjectCert; michael@0: (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1); michael@0: nssHash_Add(store->subject, &subjectCert->subject, subjectList); michael@0: } michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssCertificateStore_RemoveCertLOCKED ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: certificate_hash_entry *entry; michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry && entry->cert == cert) { michael@0: remove_certificate_entry(store, cert); michael@0: remove_subject_entry(store, cert); michael@0: } michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssCertificateStore_Lock ( michael@0: nssCertificateStore *store, nssCertificateStoreTrace* out michael@0: ) michael@0: { michael@0: #ifdef DEBUG michael@0: PORT_Assert(out); michael@0: out->store = store; michael@0: out->lock = store->lock; michael@0: out->locked = PR_TRUE; michael@0: PZ_Lock(out->lock); michael@0: #else michael@0: PZ_Lock(store->lock); michael@0: #endif michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssCertificateStore_Unlock ( michael@0: nssCertificateStore *store, const nssCertificateStoreTrace* in, michael@0: nssCertificateStoreTrace* out michael@0: ) michael@0: { michael@0: #ifdef DEBUG michael@0: PORT_Assert(in); michael@0: PORT_Assert(out); michael@0: out->store = store; michael@0: out->lock = store->lock; michael@0: PORT_Assert(!out->locked); michael@0: out->unlocked = PR_TRUE; michael@0: michael@0: PORT_Assert(in->store == out->store); michael@0: PORT_Assert(in->lock == out->lock); michael@0: PORT_Assert(in->locked); michael@0: PORT_Assert(!in->unlocked); michael@0: michael@0: PZ_Unlock(out->lock); michael@0: #else michael@0: PZ_Unlock(store->lock); michael@0: #endif michael@0: } michael@0: michael@0: static NSSCertificate ** michael@0: get_array_from_list ( michael@0: nssList *certList, michael@0: NSSCertificate *rvOpt[], michael@0: PRUint32 maximumOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: PRUint32 count; michael@0: NSSCertificate **rvArray = NULL; michael@0: count = nssList_Count(certList); michael@0: if (count == 0) { michael@0: return NULL; michael@0: } michael@0: if (maximumOpt > 0) { michael@0: count = PR_MIN(maximumOpt, count); michael@0: } michael@0: if (rvOpt) { michael@0: nssList_GetArray(certList, (void **)rvOpt, count); michael@0: } else { michael@0: rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1); michael@0: if (rvArray) { michael@0: nssList_GetArray(certList, (void **)rvArray, count); michael@0: } michael@0: } michael@0: return rvArray; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCertificate ** michael@0: nssCertificateStore_FindCertificatesBySubject ( michael@0: nssCertificateStore *store, michael@0: NSSDER *subject, michael@0: NSSCertificate *rvOpt[], michael@0: PRUint32 maximumOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: NSSCertificate **rvArray = NULL; michael@0: nssList *subjectList; michael@0: PZ_Lock(store->lock); michael@0: subjectList = (nssList *)nssHash_Lookup(store->subject, subject); michael@0: if (subjectList) { michael@0: nssCertificateList_AddReferences(subjectList); michael@0: rvArray = get_array_from_list(subjectList, michael@0: rvOpt, maximumOpt, arenaOpt); michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return rvArray; michael@0: } michael@0: michael@0: /* Because only subject indexing is implemented, all other lookups require michael@0: * full traversal (unfortunately, PLHashTable doesn't allow you to exit michael@0: * early from the enumeration). The assumptions are that 1) lookups by michael@0: * fields other than subject will be rare, and 2) the hash will not have michael@0: * a large number of entries. These assumptions will be tested. michael@0: * michael@0: * XXX michael@0: * For NSS 3.4, it is worth consideration to do all forms of indexing, michael@0: * because the only crypto context is global and persistent. michael@0: */ michael@0: michael@0: struct nickname_template_str michael@0: { michael@0: NSSUTF8 *nickname; michael@0: nssList *subjectList; michael@0: }; michael@0: michael@0: static void match_nickname(const void *k, void *v, void *a) michael@0: { michael@0: PRStatus nssrv; michael@0: NSSCertificate *c; michael@0: NSSUTF8 *nickname; michael@0: nssList *subjectList = (nssList *)v; michael@0: struct nickname_template_str *nt = (struct nickname_template_str *)a; michael@0: nssrv = nssList_GetArray(subjectList, (void **)&c, 1); michael@0: nickname = nssCertificate_GetNickname(c, NULL); michael@0: if (nssrv == PR_SUCCESS && nickname && michael@0: nssUTF8_Equal(nickname, nt->nickname, &nssrv)) michael@0: { michael@0: nt->subjectList = subjectList; michael@0: } michael@0: nss_ZFreeIf(nickname); michael@0: } michael@0: michael@0: /* michael@0: * Find all cached certs with this label. michael@0: */ michael@0: NSS_IMPLEMENT NSSCertificate ** michael@0: nssCertificateStore_FindCertificatesByNickname ( michael@0: nssCertificateStore *store, michael@0: const NSSUTF8 *nickname, michael@0: NSSCertificate *rvOpt[], michael@0: PRUint32 maximumOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: NSSCertificate **rvArray = NULL; michael@0: struct nickname_template_str nt; michael@0: nt.nickname = (char*) nickname; michael@0: nt.subjectList = NULL; michael@0: PZ_Lock(store->lock); michael@0: nssHash_Iterate(store->subject, match_nickname, &nt); michael@0: if (nt.subjectList) { michael@0: nssCertificateList_AddReferences(nt.subjectList); michael@0: rvArray = get_array_from_list(nt.subjectList, michael@0: rvOpt, maximumOpt, arenaOpt); michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return rvArray; michael@0: } michael@0: michael@0: struct email_template_str michael@0: { michael@0: NSSASCII7 *email; michael@0: nssList *emailList; michael@0: }; michael@0: michael@0: static void match_email(const void *k, void *v, void *a) michael@0: { michael@0: PRStatus nssrv; michael@0: NSSCertificate *c; michael@0: nssList *subjectList = (nssList *)v; michael@0: struct email_template_str *et = (struct email_template_str *)a; michael@0: nssrv = nssList_GetArray(subjectList, (void **)&c, 1); michael@0: if (nssrv == PR_SUCCESS && michael@0: nssUTF8_Equal(c->email, et->email, &nssrv)) michael@0: { michael@0: nssListIterator *iter = nssList_CreateIterator(subjectList); michael@0: if (iter) { michael@0: for (c = (NSSCertificate *)nssListIterator_Start(iter); michael@0: c != (NSSCertificate *)NULL; michael@0: c = (NSSCertificate *)nssListIterator_Next(iter)) michael@0: { michael@0: nssList_Add(et->emailList, c); michael@0: } michael@0: nssListIterator_Finish(iter); michael@0: nssListIterator_Destroy(iter); michael@0: } michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Find all cached certs with this email address. michael@0: */ michael@0: NSS_IMPLEMENT NSSCertificate ** michael@0: nssCertificateStore_FindCertificatesByEmail ( michael@0: nssCertificateStore *store, michael@0: NSSASCII7 *email, michael@0: NSSCertificate *rvOpt[], michael@0: PRUint32 maximumOpt, michael@0: NSSArena *arenaOpt michael@0: ) michael@0: { michael@0: NSSCertificate **rvArray = NULL; michael@0: struct email_template_str et; michael@0: et.email = email; michael@0: et.emailList = nssList_Create(NULL, PR_FALSE); michael@0: if (!et.emailList) { michael@0: return NULL; michael@0: } michael@0: PZ_Lock(store->lock); michael@0: nssHash_Iterate(store->subject, match_email, &et); michael@0: if (et.emailList) { michael@0: /* get references before leaving the store's lock protection */ michael@0: nssCertificateList_AddReferences(et.emailList); michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: if (et.emailList) { michael@0: rvArray = get_array_from_list(et.emailList, michael@0: rvOpt, maximumOpt, arenaOpt); michael@0: nssList_Destroy(et.emailList); michael@0: } michael@0: return rvArray; michael@0: } michael@0: michael@0: /* Caller holds store->lock */ michael@0: static NSSCertificate * michael@0: nssCertStore_FindCertByIssuerAndSerialNumberLocked ( michael@0: nssCertificateStore *store, michael@0: NSSDER *issuer, michael@0: NSSDER *serial michael@0: ) michael@0: { michael@0: certificate_hash_entry *entry; michael@0: NSSCertificate *rvCert = NULL; michael@0: NSSCertificate index; michael@0: michael@0: index.issuer = *issuer; michael@0: index.serial = *serial; michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, &index); michael@0: if (entry) { michael@0: rvCert = nssCertificate_AddRef(entry->cert); michael@0: } michael@0: return rvCert; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCertificate * michael@0: nssCertificateStore_FindCertificateByIssuerAndSerialNumber ( michael@0: nssCertificateStore *store, michael@0: NSSDER *issuer, michael@0: NSSDER *serial michael@0: ) michael@0: { michael@0: NSSCertificate *rvCert = NULL; michael@0: michael@0: PZ_Lock(store->lock); michael@0: rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked ( michael@0: store, issuer, serial); michael@0: PZ_Unlock(store->lock); michael@0: return rvCert; michael@0: } michael@0: michael@0: static PRStatus michael@0: issuer_and_serial_from_encoding ( michael@0: NSSBER *encoding, michael@0: NSSDER *issuer, michael@0: NSSDER *serial michael@0: ) michael@0: { michael@0: SECItem derCert, derIssuer, derSerial; michael@0: SECStatus secrv; michael@0: derCert.data = (unsigned char *)encoding->data; michael@0: derCert.len = encoding->size; michael@0: secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer); michael@0: if (secrv != SECSuccess) { michael@0: return PR_FAILURE; michael@0: } michael@0: secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial); michael@0: if (secrv != SECSuccess) { michael@0: PORT_Free(derIssuer.data); michael@0: return PR_FAILURE; michael@0: } michael@0: issuer->data = derIssuer.data; michael@0: issuer->size = derIssuer.len; michael@0: serial->data = derSerial.data; michael@0: serial->size = derSerial.len; michael@0: return PR_SUCCESS; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSCertificate * michael@0: nssCertificateStore_FindCertificateByEncodedCertificate ( michael@0: nssCertificateStore *store, michael@0: NSSDER *encoding michael@0: ) michael@0: { michael@0: PRStatus nssrv = PR_FAILURE; michael@0: NSSDER issuer, serial; michael@0: NSSCertificate *rvCert = NULL; michael@0: nssrv = issuer_and_serial_from_encoding(encoding, &issuer, &serial); michael@0: if (nssrv != PR_SUCCESS) { michael@0: return NULL; michael@0: } michael@0: rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store, michael@0: &issuer, michael@0: &serial); michael@0: PORT_Free(issuer.data); michael@0: PORT_Free(serial.data); michael@0: return rvCert; michael@0: } michael@0: michael@0: NSS_EXTERN PRStatus michael@0: nssCertificateStore_AddTrust ( michael@0: nssCertificateStore *store, michael@0: NSSTrust *trust michael@0: ) michael@0: { michael@0: NSSCertificate *cert; michael@0: certificate_hash_entry *entry; michael@0: cert = trust->certificate; michael@0: PZ_Lock(store->lock); michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry) { michael@0: NSSTrust* newTrust = nssTrust_AddRef(trust); michael@0: if (entry->trust) { michael@0: nssTrust_Destroy(entry->trust); michael@0: } michael@0: entry->trust = newTrust; michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return (entry) ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT NSSTrust * michael@0: nssCertificateStore_FindTrustForCertificate ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: certificate_hash_entry *entry; michael@0: NSSTrust *rvTrust = NULL; michael@0: PZ_Lock(store->lock); michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry && entry->trust) { michael@0: rvTrust = nssTrust_AddRef(entry->trust); michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return rvTrust; michael@0: } michael@0: michael@0: NSS_EXTERN PRStatus michael@0: nssCertificateStore_AddSMIMEProfile ( michael@0: nssCertificateStore *store, michael@0: nssSMIMEProfile *profile michael@0: ) michael@0: { michael@0: NSSCertificate *cert; michael@0: certificate_hash_entry *entry; michael@0: cert = profile->certificate; michael@0: PZ_Lock(store->lock); michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry) { michael@0: nssSMIMEProfile* newProfile = nssSMIMEProfile_AddRef(profile); michael@0: if (entry->profile) { michael@0: nssSMIMEProfile_Destroy(entry->profile); michael@0: } michael@0: entry->profile = newProfile; michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return (entry) ? PR_SUCCESS : PR_FAILURE; michael@0: } michael@0: michael@0: NSS_IMPLEMENT nssSMIMEProfile * michael@0: nssCertificateStore_FindSMIMEProfileForCertificate ( michael@0: nssCertificateStore *store, michael@0: NSSCertificate *cert michael@0: ) michael@0: { michael@0: certificate_hash_entry *entry; michael@0: nssSMIMEProfile *rvProfile = NULL; michael@0: PZ_Lock(store->lock); michael@0: entry = (certificate_hash_entry *) michael@0: nssHash_Lookup(store->issuer_and_serial, cert); michael@0: if (entry && entry->profile) { michael@0: rvProfile = nssSMIMEProfile_AddRef(entry->profile); michael@0: } michael@0: PZ_Unlock(store->lock); michael@0: return rvProfile; michael@0: } michael@0: michael@0: /* XXX this is also used by cache and should be somewhere else */ michael@0: michael@0: static PLHashNumber michael@0: nss_certificate_hash ( michael@0: const void *key michael@0: ) michael@0: { michael@0: unsigned int i; michael@0: PLHashNumber h; michael@0: NSSCertificate *c = (NSSCertificate *)key; michael@0: h = 0; michael@0: for (i=0; iissuer.size; i++) michael@0: h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->issuer.data)[i]; michael@0: for (i=0; iserial.size; i++) michael@0: h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->serial.data)[i]; michael@0: return h; michael@0: } michael@0: michael@0: static int michael@0: nss_compare_certs(const void *v1, const void *v2) michael@0: { michael@0: PRStatus ignore; michael@0: NSSCertificate *c1 = (NSSCertificate *)v1; michael@0: NSSCertificate *c2 = (NSSCertificate *)v2; michael@0: return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) && michael@0: nssItem_Equal(&c1->serial, &c2->serial, &ignore)); michael@0: } michael@0: michael@0: NSS_IMPLEMENT nssHash * michael@0: nssHash_CreateCertificate ( michael@0: NSSArena *arenaOpt, michael@0: PRUint32 numBuckets michael@0: ) michael@0: { michael@0: return nssHash_Create(arenaOpt, michael@0: numBuckets, michael@0: nss_certificate_hash, michael@0: nss_compare_certs, michael@0: PL_CompareValues); michael@0: } michael@0: michael@0: NSS_IMPLEMENT void michael@0: nssCertificateStore_DumpStoreInfo ( michael@0: nssCertificateStore *store, michael@0: void (* cert_dump_iter)(const void *, void *, void *), michael@0: void *arg michael@0: ) michael@0: { michael@0: PZ_Lock(store->lock); michael@0: nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg); michael@0: PZ_Unlock(store->lock); michael@0: } michael@0: