Back to index

lightning-sunbird  0.9+nobinonly
pkistore.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: pkistore.c,v $ $Revision: 1.26.2.3 $ $Date: 2007/11/16 05:25:08 $";
00039 #endif /* DEBUG */
00040 
00041 #ifndef PKIM_H
00042 #include "pkim.h"
00043 #endif /* PKIM_H */
00044 
00045 #ifndef PKI_H
00046 #include "pki.h"
00047 #endif /* PKI_H */
00048 
00049 #ifndef NSSPKI_H
00050 #include "nsspki.h"
00051 #endif /* NSSPKI_H */
00052 
00053 #ifndef BASE_H
00054 #include "base.h"
00055 #endif /* BASE_H */
00056 
00057 #ifndef PKISTORE_H
00058 #include "pkistore.h"
00059 #endif /* PKISTORE_H */
00060 
00061 #include "cert.h"
00062 
00063 /* 
00064  * Certificate Store
00065  *
00066  * This differs from the cache in that it is a true storage facility.  Items
00067  * stay in until they are explicitly removed.  It is only used by crypto
00068  * contexts at this time, but may be more generally useful...
00069  *
00070  */
00071 
00072 struct nssCertificateStoreStr 
00073 {
00074     PRBool i_alloced_arena;
00075     NSSArena *arena;
00076     PZLock *lock;
00077     nssHash *subject;
00078     nssHash *issuer_and_serial;
00079 };
00080 
00081 typedef struct certificate_hash_entry_str certificate_hash_entry;
00082 
00083 struct certificate_hash_entry_str
00084 {
00085     NSSCertificate *cert;
00086     NSSTrust *trust;
00087     nssSMIMEProfile *profile;
00088 };
00089 
00090 /* forward static declarations */
00091 static NSSCertificate *
00092 nssCertStore_FindCertByIssuerAndSerialNumberLocked (
00093   nssCertificateStore *store,
00094   NSSDER *issuer,
00095   NSSDER *serial
00096 );
00097 
00098 NSS_IMPLEMENT nssCertificateStore *
00099 nssCertificateStore_Create (
00100   NSSArena *arenaOpt
00101 )
00102 {
00103     NSSArena *arena;
00104     nssCertificateStore *store;
00105     PRBool i_alloced_arena;
00106     if (arenaOpt) {
00107        arena = arenaOpt;
00108        i_alloced_arena = PR_FALSE;
00109     } else {
00110        arena = nssArena_Create();
00111        if (!arena) {
00112            return NULL;
00113        }
00114        i_alloced_arena = PR_TRUE;
00115     }
00116     store = nss_ZNEW(arena, nssCertificateStore);
00117     if (!store) {
00118        goto loser;
00119     }
00120     store->lock = PZ_NewLock(nssILockOther);
00121     if (!store->lock) {
00122        goto loser;
00123     }
00124     /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */
00125     store->issuer_and_serial = nssHash_CreateCertificate(arena, 0);
00126     if (!store->issuer_and_serial) {
00127        goto loser;
00128     }
00129     /* Create the subject DER --> subject list hash */
00130     store->subject = nssHash_CreateItem(arena, 0);
00131     if (!store->subject) {
00132        goto loser;
00133     }
00134     store->arena = arena;
00135     store->i_alloced_arena = i_alloced_arena;
00136     return store;
00137 loser:
00138     if (store) {
00139        if (store->lock) {
00140            PZ_DestroyLock(store->lock);
00141        }
00142        if (store->issuer_and_serial) {
00143            nssHash_Destroy(store->issuer_and_serial);
00144        }
00145        if (store->subject) {
00146            nssHash_Destroy(store->subject);
00147        }
00148     }
00149     if (i_alloced_arena) {
00150        nssArena_Destroy(arena);
00151     }
00152     return NULL;
00153 }
00154 
00155 extern const NSSError NSS_ERROR_BUSY;
00156 
00157 NSS_IMPLEMENT PRStatus
00158 nssCertificateStore_Destroy (
00159   nssCertificateStore *store
00160 )
00161 {
00162     if (nssHash_Count(store->issuer_and_serial) > 0) {
00163        nss_SetError(NSS_ERROR_BUSY);
00164        return PR_FAILURE;
00165     }
00166     PZ_DestroyLock(store->lock);
00167     nssHash_Destroy(store->issuer_and_serial);
00168     nssHash_Destroy(store->subject);
00169     if (store->i_alloced_arena) {
00170        nssArena_Destroy(store->arena);
00171     } else {
00172        nss_ZFreeIf(store);
00173     }
00174     return PR_SUCCESS;
00175 }
00176 
00177 static PRStatus
00178 add_certificate_entry (
00179   nssCertificateStore *store,
00180   NSSCertificate *cert
00181 )
00182 {
00183     PRStatus nssrv;
00184     certificate_hash_entry *entry;
00185     entry = nss_ZNEW(cert->object.arena, certificate_hash_entry);
00186     if (!entry) {
00187        return PR_FAILURE;
00188     }
00189     entry->cert = cert;
00190     nssrv = nssHash_Add(store->issuer_and_serial, cert, entry);
00191     if (nssrv != PR_SUCCESS) {
00192        nss_ZFreeIf(entry);
00193     }
00194     return nssrv;
00195 }
00196 
00197 static PRStatus
00198 add_subject_entry (
00199   nssCertificateStore *store,
00200   NSSCertificate *cert
00201 )
00202 {
00203     PRStatus nssrv;
00204     nssList *subjectList;
00205     subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
00206     if (subjectList) {
00207        /* The subject is already in, add this cert to the list */
00208        nssrv = nssList_AddUnique(subjectList, cert);
00209     } else {
00210        /* Create a new subject list for the subject */
00211        subjectList = nssList_Create(NULL, PR_FALSE);
00212        if (!subjectList) {
00213            return PR_FAILURE;
00214        }
00215        nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort);
00216        /* Add the cert entry to this list of subjects */
00217        nssrv = nssList_Add(subjectList, cert);
00218        if (nssrv != PR_SUCCESS) {
00219            return nssrv;
00220        }
00221        /* Add the subject list to the cache */
00222        nssrv = nssHash_Add(store->subject, &cert->subject, subjectList);
00223     }
00224     return nssrv;
00225 }
00226 
00227 /* declared below */
00228 static void
00229 remove_certificate_entry (
00230   nssCertificateStore *store,
00231   NSSCertificate *cert
00232 );
00233 
00234 /* Caller must hold store->lock */
00235 static PRStatus
00236 nssCertificateStore_AddLocked (
00237   nssCertificateStore *store,
00238   NSSCertificate *cert
00239 )
00240 {
00241     PRStatus nssrv = add_certificate_entry(store, cert);
00242     if (nssrv == PR_SUCCESS) {
00243        nssrv = add_subject_entry(store, cert);
00244        if (nssrv == PR_FAILURE) {
00245            remove_certificate_entry(store, cert);
00246        }
00247     }
00248     return nssrv;
00249 }
00250 
00251 
00252 NSS_IMPLEMENT NSSCertificate *
00253 nssCertificateStore_FindOrAdd (
00254   nssCertificateStore *store,
00255   NSSCertificate *c
00256 )
00257 {
00258     PRStatus nssrv;
00259     NSSCertificate *rvCert = NULL;
00260 
00261     PZ_Lock(store->lock);
00262     rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked(
00263                                       store, &c->issuer, &c->serial);
00264     if (!rvCert) {
00265        nssrv = nssCertificateStore_AddLocked(store, c);
00266        if (PR_SUCCESS == nssrv) {
00267            rvCert = nssCertificate_AddRef(c);
00268        }
00269     }
00270     PZ_Unlock(store->lock);
00271     return rvCert;
00272 }
00273 
00274 static void
00275 remove_certificate_entry (
00276   nssCertificateStore *store,
00277   NSSCertificate *cert
00278 )
00279 {
00280     certificate_hash_entry *entry;
00281     entry = (certificate_hash_entry *)
00282                              nssHash_Lookup(store->issuer_and_serial, cert);
00283     if (entry) {
00284        nssHash_Remove(store->issuer_and_serial, cert);
00285        if (entry->trust) {
00286            nssTrust_Destroy(entry->trust);
00287        }
00288        if (entry->profile) {
00289            nssSMIMEProfile_Destroy(entry->profile);
00290        }
00291        nss_ZFreeIf(entry);
00292     }
00293 }
00294 
00295 static void
00296 remove_subject_entry (
00297   nssCertificateStore *store,
00298   NSSCertificate *cert
00299 )
00300 {
00301     nssList *subjectList;
00302     /* Get the subject list for the cert's subject */
00303     subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
00304     if (subjectList) {
00305        /* Remove the cert from the subject hash */
00306        nssList_Remove(subjectList, cert);
00307        nssHash_Remove(store->subject, &cert->subject);
00308        if (nssList_Count(subjectList) == 0) {
00309            nssList_Destroy(subjectList);
00310        } else {
00311            /* The cert being released may have keyed the subject entry.
00312             * Since there are still subject certs around, get another and
00313             * rekey the entry just in case.
00314             */
00315            NSSCertificate *subjectCert;
00316            (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1);
00317            nssHash_Add(store->subject, &subjectCert->subject, subjectList);
00318        }
00319     }
00320 }
00321 
00322 NSS_IMPLEMENT void
00323 nssCertificateStore_RemoveCertLOCKED (
00324   nssCertificateStore *store,
00325   NSSCertificate *cert
00326 )
00327 {
00328     certificate_hash_entry *entry;
00329     entry = (certificate_hash_entry *)
00330                               nssHash_Lookup(store->issuer_and_serial, cert);
00331     if (entry && entry->cert == cert) {
00332        remove_certificate_entry(store, cert);
00333        remove_subject_entry(store, cert);
00334     }
00335 }
00336 
00337 NSS_IMPLEMENT void
00338 nssCertificateStore_Lock (
00339   nssCertificateStore *store, nssCertificateStoreTrace* out
00340 )
00341 {
00342 #ifdef DEBUG
00343     PORT_Assert(out);
00344     out->store = store;
00345     out->lock = store->lock;
00346     out->locked = PR_TRUE;
00347     PZ_Lock(out->lock);
00348 #else
00349     PZ_Lock(store->lock);
00350 #endif
00351 }
00352 
00353 NSS_IMPLEMENT void
00354 nssCertificateStore_Unlock (
00355   nssCertificateStore *store, nssCertificateStoreTrace* in,
00356   nssCertificateStoreTrace* out
00357 )
00358 {
00359 #ifdef DEBUG
00360     PORT_Assert(in);
00361     PORT_Assert(out);
00362     out->store = store;
00363     out->lock = store->lock;
00364     out->unlocked = PR_TRUE;
00365 
00366     PORT_Assert(in->store == out->store);
00367     PORT_Assert(in->lock == out->lock);
00368     PORT_Assert(in->locked);
00369 
00370     PZ_Unlock(out->lock);
00371 #else
00372     PZ_Unlock(store->lock);
00373 #endif
00374 }
00375 
00376 static NSSCertificate **
00377 get_array_from_list (
00378   nssList *certList,
00379   NSSCertificate *rvOpt[],
00380   PRUint32 maximumOpt,
00381   NSSArena *arenaOpt
00382 )
00383 {
00384     PRUint32 count;
00385     NSSCertificate **rvArray = NULL;
00386     count = nssList_Count(certList);
00387     if (count == 0) {
00388        return NULL;
00389     }
00390     if (maximumOpt > 0) {
00391        count = PR_MIN(maximumOpt, count);
00392     }
00393     if (rvOpt) {
00394        nssList_GetArray(certList, (void **)rvOpt, count);
00395     } else {
00396        rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1);
00397        if (rvArray) {
00398            nssList_GetArray(certList, (void **)rvArray, count);
00399        }
00400     }
00401     return rvArray;
00402 }
00403 
00404 NSS_IMPLEMENT NSSCertificate **
00405 nssCertificateStore_FindCertificatesBySubject (
00406   nssCertificateStore *store,
00407   NSSDER *subject,
00408   NSSCertificate *rvOpt[],
00409   PRUint32 maximumOpt,
00410   NSSArena *arenaOpt
00411 )
00412 {
00413     NSSCertificate **rvArray = NULL;
00414     nssList *subjectList;
00415     PZ_Lock(store->lock);
00416     subjectList = (nssList *)nssHash_Lookup(store->subject, subject);
00417     if (subjectList) {
00418        nssCertificateList_AddReferences(subjectList);
00419        rvArray = get_array_from_list(subjectList, 
00420                                      rvOpt, maximumOpt, arenaOpt);
00421     }
00422     PZ_Unlock(store->lock);
00423     return rvArray;
00424 }
00425 
00426 /* Because only subject indexing is implemented, all other lookups require
00427  * full traversal (unfortunately, PLHashTable doesn't allow you to exit
00428  * early from the enumeration).  The assumptions are that 1) lookups by 
00429  * fields other than subject will be rare, and 2) the hash will not have
00430  * a large number of entries.  These assumptions will be tested.
00431  *
00432  * XXX
00433  * For NSS 3.4, it is worth consideration to do all forms of indexing,
00434  * because the only crypto context is global and persistent.
00435  */
00436 
00437 struct nickname_template_str
00438 {
00439     NSSUTF8 *nickname;
00440     nssList *subjectList;
00441 };
00442 
00443 static void match_nickname(const void *k, void *v, void *a)
00444 {
00445     PRStatus nssrv;
00446     NSSCertificate *c;
00447     NSSUTF8 *nickname;
00448     nssList *subjectList = (nssList *)v;
00449     struct nickname_template_str *nt = (struct nickname_template_str *)a;
00450     nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
00451     nickname = nssCertificate_GetNickname(c, NULL);
00452     if (nssrv == PR_SUCCESS && nickname &&
00453          nssUTF8_Equal(nickname, nt->nickname, &nssrv)) 
00454     {
00455        nt->subjectList = subjectList;
00456     }
00457 }
00458 
00459 /*
00460  * Find all cached certs with this label.
00461  */
00462 NSS_IMPLEMENT NSSCertificate **
00463 nssCertificateStore_FindCertificatesByNickname (
00464   nssCertificateStore *store,
00465   NSSUTF8 *nickname,
00466   NSSCertificate *rvOpt[],
00467   PRUint32 maximumOpt,
00468   NSSArena *arenaOpt
00469 )
00470 {
00471     NSSCertificate **rvArray = NULL;
00472     struct nickname_template_str nt;
00473     nt.nickname = nickname;
00474     nt.subjectList = NULL;
00475     PZ_Lock(store->lock);
00476     nssHash_Iterate(store->subject, match_nickname, &nt);
00477     if (nt.subjectList) {
00478        nssCertificateList_AddReferences(nt.subjectList);
00479        rvArray = get_array_from_list(nt.subjectList, 
00480                                      rvOpt, maximumOpt, arenaOpt);
00481     }
00482     PZ_Unlock(store->lock);
00483     return rvArray;
00484 }
00485 
00486 struct email_template_str
00487 {
00488     NSSASCII7 *email;
00489     nssList *emailList;
00490 };
00491 
00492 static void match_email(const void *k, void *v, void *a)
00493 {
00494     PRStatus nssrv;
00495     NSSCertificate *c;
00496     nssList *subjectList = (nssList *)v;
00497     struct email_template_str *et = (struct email_template_str *)a;
00498     nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
00499     if (nssrv == PR_SUCCESS && 
00500          nssUTF8_Equal(c->email, et->email, &nssrv)) 
00501     {
00502        nssListIterator *iter = nssList_CreateIterator(subjectList);
00503        if (iter) {
00504            for (c  = (NSSCertificate *)nssListIterator_Start(iter);
00505                 c != (NSSCertificate *)NULL;
00506                 c  = (NSSCertificate *)nssListIterator_Next(iter))
00507            {
00508               nssList_Add(et->emailList, c);
00509            }
00510            nssListIterator_Finish(iter);
00511            nssListIterator_Destroy(iter);
00512        }
00513     }
00514 }
00515 
00516 /*
00517  * Find all cached certs with this email address.
00518  */
00519 NSS_IMPLEMENT NSSCertificate **
00520 nssCertificateStore_FindCertificatesByEmail (
00521   nssCertificateStore *store,
00522   NSSASCII7 *email,
00523   NSSCertificate *rvOpt[],
00524   PRUint32 maximumOpt,
00525   NSSArena *arenaOpt
00526 )
00527 {
00528     NSSCertificate **rvArray = NULL;
00529     struct email_template_str et;
00530     et.email = email;
00531     et.emailList = nssList_Create(NULL, PR_FALSE);
00532     if (!et.emailList) {
00533        return NULL;
00534     }
00535     PZ_Lock(store->lock);
00536     nssHash_Iterate(store->subject, match_email, &et);
00537     if (et.emailList) {
00538        /* get references before leaving the store's lock protection */
00539        nssCertificateList_AddReferences(et.emailList);
00540     }
00541     PZ_Unlock(store->lock);
00542     if (et.emailList) {
00543        rvArray = get_array_from_list(et.emailList, 
00544                                      rvOpt, maximumOpt, arenaOpt);
00545        nssList_Destroy(et.emailList);
00546     }
00547     return rvArray;
00548 }
00549 
00550 /* Caller holds store->lock */
00551 static NSSCertificate *
00552 nssCertStore_FindCertByIssuerAndSerialNumberLocked (
00553   nssCertificateStore *store,
00554   NSSDER *issuer,
00555   NSSDER *serial
00556 )
00557 {
00558     certificate_hash_entry *entry;
00559     NSSCertificate *rvCert = NULL;
00560     NSSCertificate index;
00561 
00562     index.issuer = *issuer;
00563     index.serial = *serial;
00564     entry = (certificate_hash_entry *)
00565                            nssHash_Lookup(store->issuer_and_serial, &index);
00566     if (entry) {
00567        rvCert = nssCertificate_AddRef(entry->cert);
00568     }
00569     return rvCert;
00570 }
00571 
00572 NSS_IMPLEMENT NSSCertificate *
00573 nssCertificateStore_FindCertificateByIssuerAndSerialNumber (
00574   nssCertificateStore *store,
00575   NSSDER *issuer,
00576   NSSDER *serial
00577 )
00578 {
00579     NSSCertificate *rvCert = NULL;
00580 
00581     PZ_Lock(store->lock);
00582     rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked (
00583                            store, issuer, serial);
00584     PZ_Unlock(store->lock);
00585     return rvCert;
00586 }
00587 
00588 static PRStatus
00589 issuer_and_serial_from_encoding (
00590   NSSBER *encoding, 
00591   NSSDER *issuer, 
00592   NSSDER *serial
00593 )
00594 {
00595     SECItem derCert, derIssuer, derSerial;
00596     SECStatus secrv;
00597     derCert.data = (unsigned char *)encoding->data;
00598     derCert.len = encoding->size;
00599     secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
00600     if (secrv != SECSuccess) {
00601        return PR_FAILURE;
00602     }
00603     secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
00604     if (secrv != SECSuccess) {
00605        PORT_Free(derIssuer.data);
00606        return PR_FAILURE;
00607     }
00608     issuer->data = derIssuer.data;
00609     issuer->size = derIssuer.len;
00610     serial->data = derSerial.data;
00611     serial->size = derSerial.len;
00612     return PR_SUCCESS;
00613 }
00614 
00615 NSS_IMPLEMENT NSSCertificate *
00616 nssCertificateStore_FindCertificateByEncodedCertificate (
00617   nssCertificateStore *store,
00618   NSSDER *encoding
00619 )
00620 {
00621     PRStatus nssrv = PR_FAILURE;
00622     NSSDER issuer, serial;
00623     NSSCertificate *rvCert = NULL;
00624     nssrv = issuer_and_serial_from_encoding(encoding, &issuer, &serial);
00625     if (nssrv != PR_SUCCESS) {
00626        return NULL;
00627     }
00628     rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store, 
00629                                                                      &issuer, 
00630                                                                      &serial);
00631     PORT_Free(issuer.data);
00632     PORT_Free(serial.data);
00633     return rvCert;
00634 }
00635 
00636 NSS_EXTERN PRStatus
00637 nssCertificateStore_AddTrust (
00638   nssCertificateStore *store,
00639   NSSTrust *trust
00640 )
00641 {
00642     NSSCertificate *cert;
00643     certificate_hash_entry *entry;
00644     cert = trust->certificate;
00645     PZ_Lock(store->lock);
00646     entry = (certificate_hash_entry *)
00647                               nssHash_Lookup(store->issuer_and_serial, cert);
00648     if (entry) {
00649        entry->trust = nssTrust_AddRef(trust);
00650     }
00651     PZ_Unlock(store->lock);
00652     return (entry) ? PR_SUCCESS : PR_FAILURE;
00653 }
00654 
00655 NSS_IMPLEMENT NSSTrust *
00656 nssCertificateStore_FindTrustForCertificate (
00657   nssCertificateStore *store,
00658   NSSCertificate *cert
00659 )
00660 {
00661     certificate_hash_entry *entry;
00662     NSSTrust *rvTrust = NULL;
00663     PZ_Lock(store->lock);
00664     entry = (certificate_hash_entry *)
00665                               nssHash_Lookup(store->issuer_and_serial, cert);
00666     if (entry && entry->trust) {
00667        rvTrust = nssTrust_AddRef(entry->trust);
00668     }
00669     PZ_Unlock(store->lock);
00670     return rvTrust;
00671 }
00672 
00673 NSS_EXTERN PRStatus
00674 nssCertificateStore_AddSMIMEProfile (
00675   nssCertificateStore *store,
00676   nssSMIMEProfile *profile
00677 )
00678 {
00679     NSSCertificate *cert;
00680     certificate_hash_entry *entry;
00681     cert = profile->certificate;
00682     PZ_Lock(store->lock);
00683     entry = (certificate_hash_entry *)
00684                               nssHash_Lookup(store->issuer_and_serial, cert);
00685     if (entry) {
00686        entry->profile = nssSMIMEProfile_AddRef(profile);
00687     }
00688     PZ_Unlock(store->lock);
00689     return (entry) ? PR_SUCCESS : PR_FAILURE;
00690 }
00691 
00692 NSS_IMPLEMENT nssSMIMEProfile *
00693 nssCertificateStore_FindSMIMEProfileForCertificate (
00694   nssCertificateStore *store,
00695   NSSCertificate *cert
00696 )
00697 {
00698     certificate_hash_entry *entry;
00699     nssSMIMEProfile *rvProfile = NULL;
00700     PZ_Lock(store->lock);
00701     entry = (certificate_hash_entry *)
00702                               nssHash_Lookup(store->issuer_and_serial, cert);
00703     if (entry && entry->profile) {
00704        rvProfile = nssSMIMEProfile_AddRef(entry->profile);
00705     }
00706     PZ_Unlock(store->lock);
00707     return rvProfile;
00708 }
00709 
00710 /* XXX this is also used by cache and should be somewhere else */
00711 
00712 static PLHashNumber
00713 nss_certificate_hash (
00714   const void *key
00715 )
00716 {
00717     unsigned int i;
00718     PLHashNumber h;
00719     NSSCertificate *c = (NSSCertificate *)key;
00720     h = 0;
00721     for (i=0; i<c->issuer.size; i++)
00722        h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)c->issuer.data)[i];
00723     for (i=0; i<c->serial.size; i++)
00724        h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)c->serial.data)[i];
00725     return h;
00726 }
00727 
00728 static int
00729 nss_compare_certs(const void *v1, const void *v2)
00730 {
00731     PRStatus ignore;
00732     NSSCertificate *c1 = (NSSCertificate *)v1;
00733     NSSCertificate *c2 = (NSSCertificate *)v2;
00734     return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) &&
00735                  nssItem_Equal(&c1->serial, &c2->serial, &ignore));
00736 }
00737 
00738 NSS_IMPLEMENT nssHash *
00739 nssHash_CreateCertificate (
00740   NSSArena *arenaOpt,
00741   PRUint32 numBuckets
00742 )
00743 {
00744     return nssHash_Create(arenaOpt, 
00745                           numBuckets, 
00746                           nss_certificate_hash, 
00747                           nss_compare_certs, 
00748                           PL_CompareValues);
00749 }
00750 
00751 NSS_IMPLEMENT void
00752 nssCertificateStore_DumpStoreInfo (
00753   nssCertificateStore *store,
00754   void (* cert_dump_iter)(const void *, void *, void *),
00755   void *arg
00756 )
00757 {
00758     PZ_Lock(store->lock);
00759     nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg);
00760     PZ_Unlock(store->lock);
00761 }
00762