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