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