security/nss/lib/pki/pkistore.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #ifndef PKIM_H
     6 #include "pkim.h"
     7 #endif /* PKIM_H */
     9 #ifndef PKI_H
    10 #include "pki.h"
    11 #endif /* PKI_H */
    13 #ifndef NSSPKI_H
    14 #include "nsspki.h"
    15 #endif /* NSSPKI_H */
    17 #ifndef BASE_H
    18 #include "base.h"
    19 #endif /* BASE_H */
    21 #ifndef PKISTORE_H
    22 #include "pkistore.h"
    23 #endif /* PKISTORE_H */
    25 #include "cert.h"
    27 #include "prbit.h"
    29 /* 
    30  * Certificate Store
    31  *
    32  * This differs from the cache in that it is a true storage facility.  Items
    33  * stay in until they are explicitly removed.  It is only used by crypto
    34  * contexts at this time, but may be more generally useful...
    35  *
    36  */
    38 struct nssCertificateStoreStr 
    39 {
    40     PRBool i_alloced_arena;
    41     NSSArena *arena;
    42     PZLock *lock;
    43     nssHash *subject;
    44     nssHash *issuer_and_serial;
    45 };
    47 typedef struct certificate_hash_entry_str certificate_hash_entry;
    49 struct certificate_hash_entry_str
    50 {
    51     NSSCertificate *cert;
    52     NSSTrust *trust;
    53     nssSMIMEProfile *profile;
    54 };
    56 /* forward static declarations */
    57 static NSSCertificate *
    58 nssCertStore_FindCertByIssuerAndSerialNumberLocked (
    59   nssCertificateStore *store,
    60   NSSDER *issuer,
    61   NSSDER *serial
    62 );
    64 NSS_IMPLEMENT nssCertificateStore *
    65 nssCertificateStore_Create (
    66   NSSArena *arenaOpt
    67 )
    68 {
    69     NSSArena *arena;
    70     nssCertificateStore *store;
    71     PRBool i_alloced_arena;
    72     if (arenaOpt) {
    73 	arena = arenaOpt;
    74 	i_alloced_arena = PR_FALSE;
    75     } else {
    76 	arena = nssArena_Create();
    77 	if (!arena) {
    78 	    return NULL;
    79 	}
    80 	i_alloced_arena = PR_TRUE;
    81     }
    82     store = nss_ZNEW(arena, nssCertificateStore);
    83     if (!store) {
    84 	goto loser;
    85     }
    86     store->lock = PZ_NewLock(nssILockOther);
    87     if (!store->lock) {
    88 	goto loser;
    89     }
    90     /* Create the issuer/serial --> {cert, trust, S/MIME profile } hash */
    91     store->issuer_and_serial = nssHash_CreateCertificate(arena, 0);
    92     if (!store->issuer_and_serial) {
    93 	goto loser;
    94     }
    95     /* Create the subject DER --> subject list hash */
    96     store->subject = nssHash_CreateItem(arena, 0);
    97     if (!store->subject) {
    98 	goto loser;
    99     }
   100     store->arena = arena;
   101     store->i_alloced_arena = i_alloced_arena;
   102     return store;
   103 loser:
   104     if (store) {
   105 	if (store->lock) {
   106 	    PZ_DestroyLock(store->lock);
   107 	}
   108 	if (store->issuer_and_serial) {
   109 	    nssHash_Destroy(store->issuer_and_serial);
   110 	}
   111 	if (store->subject) {
   112 	    nssHash_Destroy(store->subject);
   113 	}
   114     }
   115     if (i_alloced_arena) {
   116 	nssArena_Destroy(arena);
   117     }
   118     return NULL;
   119 }
   121 extern const NSSError NSS_ERROR_BUSY;
   123 NSS_IMPLEMENT PRStatus
   124 nssCertificateStore_Destroy (
   125   nssCertificateStore *store
   126 )
   127 {
   128     if (nssHash_Count(store->issuer_and_serial) > 0) {
   129 	nss_SetError(NSS_ERROR_BUSY);
   130 	return PR_FAILURE;
   131     }
   132     PZ_DestroyLock(store->lock);
   133     nssHash_Destroy(store->issuer_and_serial);
   134     nssHash_Destroy(store->subject);
   135     if (store->i_alloced_arena) {
   136 	nssArena_Destroy(store->arena);
   137     } else {
   138 	nss_ZFreeIf(store);
   139     }
   140     return PR_SUCCESS;
   141 }
   143 static PRStatus
   144 add_certificate_entry (
   145   nssCertificateStore *store,
   146   NSSCertificate *cert
   147 )
   148 {
   149     PRStatus nssrv;
   150     certificate_hash_entry *entry;
   151     entry = nss_ZNEW(cert->object.arena, certificate_hash_entry);
   152     if (!entry) {
   153 	return PR_FAILURE;
   154     }
   155     entry->cert = cert;
   156     nssrv = nssHash_Add(store->issuer_and_serial, cert, entry);
   157     if (nssrv != PR_SUCCESS) {
   158 	nss_ZFreeIf(entry);
   159     }
   160     return nssrv;
   161 }
   163 static PRStatus
   164 add_subject_entry (
   165   nssCertificateStore *store,
   166   NSSCertificate *cert
   167 )
   168 {
   169     PRStatus nssrv;
   170     nssList *subjectList;
   171     subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
   172     if (subjectList) {
   173 	/* The subject is already in, add this cert to the list */
   174 	nssrv = nssList_AddUnique(subjectList, cert);
   175     } else {
   176 	/* Create a new subject list for the subject */
   177 	subjectList = nssList_Create(NULL, PR_FALSE);
   178 	if (!subjectList) {
   179 	    return PR_FAILURE;
   180 	}
   181 	nssList_SetSortFunction(subjectList, nssCertificate_SubjectListSort);
   182 	/* Add the cert entry to this list of subjects */
   183 	nssrv = nssList_Add(subjectList, cert);
   184 	if (nssrv != PR_SUCCESS) {
   185 	    return nssrv;
   186 	}
   187 	/* Add the subject list to the cache */
   188 	nssrv = nssHash_Add(store->subject, &cert->subject, subjectList);
   189     }
   190     return nssrv;
   191 }
   193 /* declared below */
   194 static void
   195 remove_certificate_entry (
   196   nssCertificateStore *store,
   197   NSSCertificate *cert
   198 );
   200 /* Caller must hold store->lock */
   201 static PRStatus
   202 nssCertificateStore_AddLocked (
   203   nssCertificateStore *store,
   204   NSSCertificate *cert
   205 )
   206 {
   207     PRStatus nssrv = add_certificate_entry(store, cert);
   208     if (nssrv == PR_SUCCESS) {
   209 	nssrv = add_subject_entry(store, cert);
   210 	if (nssrv == PR_FAILURE) {
   211 	    remove_certificate_entry(store, cert);
   212 	}
   213     }
   214     return nssrv;
   215 }
   218 NSS_IMPLEMENT NSSCertificate *
   219 nssCertificateStore_FindOrAdd (
   220   nssCertificateStore *store,
   221   NSSCertificate *c
   222 )
   223 {
   224     PRStatus nssrv;
   225     NSSCertificate *rvCert = NULL;
   227     PZ_Lock(store->lock);
   228     rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked(
   229 					   store, &c->issuer, &c->serial);
   230     if (!rvCert) {
   231 	nssrv = nssCertificateStore_AddLocked(store, c);
   232 	if (PR_SUCCESS == nssrv) {
   233 	    rvCert = nssCertificate_AddRef(c);
   234 	}
   235     }
   236     PZ_Unlock(store->lock);
   237     return rvCert;
   238 }
   240 static void
   241 remove_certificate_entry (
   242   nssCertificateStore *store,
   243   NSSCertificate *cert
   244 )
   245 {
   246     certificate_hash_entry *entry;
   247     entry = (certificate_hash_entry *)
   248                              nssHash_Lookup(store->issuer_and_serial, cert);
   249     if (entry) {
   250 	nssHash_Remove(store->issuer_and_serial, cert);
   251 	if (entry->trust) {
   252 	    nssTrust_Destroy(entry->trust);
   253 	}
   254 	if (entry->profile) {
   255 	    nssSMIMEProfile_Destroy(entry->profile);
   256 	}
   257 	nss_ZFreeIf(entry);
   258     }
   259 }
   261 static void
   262 remove_subject_entry (
   263   nssCertificateStore *store,
   264   NSSCertificate *cert
   265 )
   266 {
   267     nssList *subjectList;
   268     /* Get the subject list for the cert's subject */
   269     subjectList = (nssList *)nssHash_Lookup(store->subject, &cert->subject);
   270     if (subjectList) {
   271 	/* Remove the cert from the subject hash */
   272 	nssList_Remove(subjectList, cert);
   273 	nssHash_Remove(store->subject, &cert->subject);
   274 	if (nssList_Count(subjectList) == 0) {
   275 	    nssList_Destroy(subjectList);
   276 	} else {
   277 	    /* The cert being released may have keyed the subject entry.
   278 	     * Since there are still subject certs around, get another and
   279 	     * rekey the entry just in case.
   280 	     */
   281 	    NSSCertificate *subjectCert;
   282 	    (void)nssList_GetArray(subjectList, (void **)&subjectCert, 1);
   283 	    nssHash_Add(store->subject, &subjectCert->subject, subjectList);
   284 	}
   285     }
   286 }
   288 NSS_IMPLEMENT void
   289 nssCertificateStore_RemoveCertLOCKED (
   290   nssCertificateStore *store,
   291   NSSCertificate *cert
   292 )
   293 {
   294     certificate_hash_entry *entry;
   295     entry = (certificate_hash_entry *)
   296                               nssHash_Lookup(store->issuer_and_serial, cert);
   297     if (entry && entry->cert == cert) {
   298 	remove_certificate_entry(store, cert);
   299 	remove_subject_entry(store, cert);
   300     }
   301 }
   303 NSS_IMPLEMENT void
   304 nssCertificateStore_Lock (
   305   nssCertificateStore *store, nssCertificateStoreTrace* out
   306 )
   307 {
   308 #ifdef DEBUG
   309     PORT_Assert(out);
   310     out->store = store;
   311     out->lock = store->lock;
   312     out->locked = PR_TRUE;
   313     PZ_Lock(out->lock);
   314 #else
   315     PZ_Lock(store->lock);
   316 #endif
   317 }
   319 NSS_IMPLEMENT void
   320 nssCertificateStore_Unlock (
   321   nssCertificateStore *store, const nssCertificateStoreTrace* in,
   322   nssCertificateStoreTrace* out
   323 )
   324 {
   325 #ifdef DEBUG
   326     PORT_Assert(in);
   327     PORT_Assert(out);
   328     out->store = store;
   329     out->lock = store->lock;
   330     PORT_Assert(!out->locked);
   331     out->unlocked = PR_TRUE;
   333     PORT_Assert(in->store == out->store);
   334     PORT_Assert(in->lock == out->lock);
   335     PORT_Assert(in->locked);
   336     PORT_Assert(!in->unlocked);
   338     PZ_Unlock(out->lock);
   339 #else
   340     PZ_Unlock(store->lock);
   341 #endif
   342 }
   344 static NSSCertificate **
   345 get_array_from_list (
   346   nssList *certList,
   347   NSSCertificate *rvOpt[],
   348   PRUint32 maximumOpt,
   349   NSSArena *arenaOpt
   350 )
   351 {
   352     PRUint32 count;
   353     NSSCertificate **rvArray = NULL;
   354     count = nssList_Count(certList);
   355     if (count == 0) {
   356 	return NULL;
   357     }
   358     if (maximumOpt > 0) {
   359 	count = PR_MIN(maximumOpt, count);
   360     }
   361     if (rvOpt) {
   362 	nssList_GetArray(certList, (void **)rvOpt, count);
   363     } else {
   364 	rvArray = nss_ZNEWARRAY(arenaOpt, NSSCertificate *, count + 1);
   365 	if (rvArray) {
   366 	    nssList_GetArray(certList, (void **)rvArray, count);
   367 	}
   368     }
   369     return rvArray;
   370 }
   372 NSS_IMPLEMENT NSSCertificate **
   373 nssCertificateStore_FindCertificatesBySubject (
   374   nssCertificateStore *store,
   375   NSSDER *subject,
   376   NSSCertificate *rvOpt[],
   377   PRUint32 maximumOpt,
   378   NSSArena *arenaOpt
   379 )
   380 {
   381     NSSCertificate **rvArray = NULL;
   382     nssList *subjectList;
   383     PZ_Lock(store->lock);
   384     subjectList = (nssList *)nssHash_Lookup(store->subject, subject);
   385     if (subjectList) {
   386 	nssCertificateList_AddReferences(subjectList);
   387 	rvArray = get_array_from_list(subjectList, 
   388 	                              rvOpt, maximumOpt, arenaOpt);
   389     }
   390     PZ_Unlock(store->lock);
   391     return rvArray;
   392 }
   394 /* Because only subject indexing is implemented, all other lookups require
   395  * full traversal (unfortunately, PLHashTable doesn't allow you to exit
   396  * early from the enumeration).  The assumptions are that 1) lookups by 
   397  * fields other than subject will be rare, and 2) the hash will not have
   398  * a large number of entries.  These assumptions will be tested.
   399  *
   400  * XXX
   401  * For NSS 3.4, it is worth consideration to do all forms of indexing,
   402  * because the only crypto context is global and persistent.
   403  */
   405 struct nickname_template_str
   406 {
   407     NSSUTF8 *nickname;
   408     nssList *subjectList;
   409 };
   411 static void match_nickname(const void *k, void *v, void *a)
   412 {
   413     PRStatus nssrv;
   414     NSSCertificate *c;
   415     NSSUTF8 *nickname;
   416     nssList *subjectList = (nssList *)v;
   417     struct nickname_template_str *nt = (struct nickname_template_str *)a;
   418     nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
   419     nickname = nssCertificate_GetNickname(c, NULL);
   420     if (nssrv == PR_SUCCESS && nickname &&
   421          nssUTF8_Equal(nickname, nt->nickname, &nssrv)) 
   422     {
   423 	nt->subjectList = subjectList;
   424     }
   425     nss_ZFreeIf(nickname);
   426 }
   428 /*
   429  * Find all cached certs with this label.
   430  */
   431 NSS_IMPLEMENT NSSCertificate **
   432 nssCertificateStore_FindCertificatesByNickname (
   433   nssCertificateStore *store,
   434   const NSSUTF8 *nickname,
   435   NSSCertificate *rvOpt[],
   436   PRUint32 maximumOpt,
   437   NSSArena *arenaOpt
   438 )
   439 {
   440     NSSCertificate **rvArray = NULL;
   441     struct nickname_template_str nt;
   442     nt.nickname = (char*) nickname;
   443     nt.subjectList = NULL;
   444     PZ_Lock(store->lock);
   445     nssHash_Iterate(store->subject, match_nickname, &nt);
   446     if (nt.subjectList) {
   447 	nssCertificateList_AddReferences(nt.subjectList);
   448 	rvArray = get_array_from_list(nt.subjectList, 
   449 	                              rvOpt, maximumOpt, arenaOpt);
   450     }
   451     PZ_Unlock(store->lock);
   452     return rvArray;
   453 }
   455 struct email_template_str
   456 {
   457     NSSASCII7 *email;
   458     nssList *emailList;
   459 };
   461 static void match_email(const void *k, void *v, void *a)
   462 {
   463     PRStatus nssrv;
   464     NSSCertificate *c;
   465     nssList *subjectList = (nssList *)v;
   466     struct email_template_str *et = (struct email_template_str *)a;
   467     nssrv = nssList_GetArray(subjectList, (void **)&c, 1);
   468     if (nssrv == PR_SUCCESS && 
   469          nssUTF8_Equal(c->email, et->email, &nssrv)) 
   470     {
   471 	nssListIterator *iter = nssList_CreateIterator(subjectList);
   472 	if (iter) {
   473 	    for (c  = (NSSCertificate *)nssListIterator_Start(iter);
   474 	         c != (NSSCertificate *)NULL;
   475 	         c  = (NSSCertificate *)nssListIterator_Next(iter))
   476 	    {
   477 		nssList_Add(et->emailList, c);
   478 	    }
   479 	    nssListIterator_Finish(iter);
   480 	    nssListIterator_Destroy(iter);
   481 	}
   482     }
   483 }
   485 /*
   486  * Find all cached certs with this email address.
   487  */
   488 NSS_IMPLEMENT NSSCertificate **
   489 nssCertificateStore_FindCertificatesByEmail (
   490   nssCertificateStore *store,
   491   NSSASCII7 *email,
   492   NSSCertificate *rvOpt[],
   493   PRUint32 maximumOpt,
   494   NSSArena *arenaOpt
   495 )
   496 {
   497     NSSCertificate **rvArray = NULL;
   498     struct email_template_str et;
   499     et.email = email;
   500     et.emailList = nssList_Create(NULL, PR_FALSE);
   501     if (!et.emailList) {
   502 	return NULL;
   503     }
   504     PZ_Lock(store->lock);
   505     nssHash_Iterate(store->subject, match_email, &et);
   506     if (et.emailList) {
   507 	/* get references before leaving the store's lock protection */
   508 	nssCertificateList_AddReferences(et.emailList);
   509     }
   510     PZ_Unlock(store->lock);
   511     if (et.emailList) {
   512 	rvArray = get_array_from_list(et.emailList, 
   513 	                              rvOpt, maximumOpt, arenaOpt);
   514 	nssList_Destroy(et.emailList);
   515     }
   516     return rvArray;
   517 }
   519 /* Caller holds store->lock */
   520 static NSSCertificate *
   521 nssCertStore_FindCertByIssuerAndSerialNumberLocked (
   522   nssCertificateStore *store,
   523   NSSDER *issuer,
   524   NSSDER *serial
   525 )
   526 {
   527     certificate_hash_entry *entry;
   528     NSSCertificate *rvCert = NULL;
   529     NSSCertificate index;
   531     index.issuer = *issuer;
   532     index.serial = *serial;
   533     entry = (certificate_hash_entry *)
   534                            nssHash_Lookup(store->issuer_and_serial, &index);
   535     if (entry) {
   536 	rvCert = nssCertificate_AddRef(entry->cert);
   537     }
   538     return rvCert;
   539 }
   541 NSS_IMPLEMENT NSSCertificate *
   542 nssCertificateStore_FindCertificateByIssuerAndSerialNumber (
   543   nssCertificateStore *store,
   544   NSSDER *issuer,
   545   NSSDER *serial
   546 )
   547 {
   548     NSSCertificate *rvCert = NULL;
   550     PZ_Lock(store->lock);
   551     rvCert = nssCertStore_FindCertByIssuerAndSerialNumberLocked (
   552                            store, issuer, serial);
   553     PZ_Unlock(store->lock);
   554     return rvCert;
   555 }
   557 static PRStatus
   558 issuer_and_serial_from_encoding (
   559   NSSBER *encoding, 
   560   NSSDER *issuer, 
   561   NSSDER *serial
   562 )
   563 {
   564     SECItem derCert, derIssuer, derSerial;
   565     SECStatus secrv;
   566     derCert.data = (unsigned char *)encoding->data;
   567     derCert.len = encoding->size;
   568     secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
   569     if (secrv != SECSuccess) {
   570 	return PR_FAILURE;
   571     }
   572     secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
   573     if (secrv != SECSuccess) {
   574 	PORT_Free(derIssuer.data);
   575 	return PR_FAILURE;
   576     }
   577     issuer->data = derIssuer.data;
   578     issuer->size = derIssuer.len;
   579     serial->data = derSerial.data;
   580     serial->size = derSerial.len;
   581     return PR_SUCCESS;
   582 }
   584 NSS_IMPLEMENT NSSCertificate *
   585 nssCertificateStore_FindCertificateByEncodedCertificate (
   586   nssCertificateStore *store,
   587   NSSDER *encoding
   588 )
   589 {
   590     PRStatus nssrv = PR_FAILURE;
   591     NSSDER issuer, serial;
   592     NSSCertificate *rvCert = NULL;
   593     nssrv = issuer_and_serial_from_encoding(encoding, &issuer, &serial);
   594     if (nssrv != PR_SUCCESS) {
   595 	return NULL;
   596     }
   597     rvCert = nssCertificateStore_FindCertificateByIssuerAndSerialNumber(store, 
   598                                                                      &issuer, 
   599                                                                      &serial);
   600     PORT_Free(issuer.data);
   601     PORT_Free(serial.data);
   602     return rvCert;
   603 }
   605 NSS_EXTERN PRStatus
   606 nssCertificateStore_AddTrust (
   607   nssCertificateStore *store,
   608   NSSTrust *trust
   609 )
   610 {
   611     NSSCertificate *cert;
   612     certificate_hash_entry *entry;
   613     cert = trust->certificate;
   614     PZ_Lock(store->lock);
   615     entry = (certificate_hash_entry *)
   616                               nssHash_Lookup(store->issuer_and_serial, cert);
   617     if (entry) {
   618 	NSSTrust* newTrust = nssTrust_AddRef(trust);
   619 	if (entry->trust) {
   620 	    nssTrust_Destroy(entry->trust);
   621 	}
   622 	entry->trust = newTrust;
   623     }
   624     PZ_Unlock(store->lock);
   625     return (entry) ? PR_SUCCESS : PR_FAILURE;
   626 }
   628 NSS_IMPLEMENT NSSTrust *
   629 nssCertificateStore_FindTrustForCertificate (
   630   nssCertificateStore *store,
   631   NSSCertificate *cert
   632 )
   633 {
   634     certificate_hash_entry *entry;
   635     NSSTrust *rvTrust = NULL;
   636     PZ_Lock(store->lock);
   637     entry = (certificate_hash_entry *)
   638                               nssHash_Lookup(store->issuer_and_serial, cert);
   639     if (entry && entry->trust) {
   640 	rvTrust = nssTrust_AddRef(entry->trust);
   641     }
   642     PZ_Unlock(store->lock);
   643     return rvTrust;
   644 }
   646 NSS_EXTERN PRStatus
   647 nssCertificateStore_AddSMIMEProfile (
   648   nssCertificateStore *store,
   649   nssSMIMEProfile *profile
   650 )
   651 {
   652     NSSCertificate *cert;
   653     certificate_hash_entry *entry;
   654     cert = profile->certificate;
   655     PZ_Lock(store->lock);
   656     entry = (certificate_hash_entry *)
   657                               nssHash_Lookup(store->issuer_and_serial, cert);
   658     if (entry) {
   659 	nssSMIMEProfile* newProfile = nssSMIMEProfile_AddRef(profile);
   660 	if (entry->profile) {
   661 	    nssSMIMEProfile_Destroy(entry->profile);
   662 	}
   663 	entry->profile = newProfile;
   664     }
   665     PZ_Unlock(store->lock);
   666     return (entry) ? PR_SUCCESS : PR_FAILURE;
   667 }
   669 NSS_IMPLEMENT nssSMIMEProfile *
   670 nssCertificateStore_FindSMIMEProfileForCertificate (
   671   nssCertificateStore *store,
   672   NSSCertificate *cert
   673 )
   674 {
   675     certificate_hash_entry *entry;
   676     nssSMIMEProfile *rvProfile = NULL;
   677     PZ_Lock(store->lock);
   678     entry = (certificate_hash_entry *)
   679                               nssHash_Lookup(store->issuer_and_serial, cert);
   680     if (entry && entry->profile) {
   681 	rvProfile = nssSMIMEProfile_AddRef(entry->profile);
   682     }
   683     PZ_Unlock(store->lock);
   684     return rvProfile;
   685 }
   687 /* XXX this is also used by cache and should be somewhere else */
   689 static PLHashNumber
   690 nss_certificate_hash (
   691   const void *key
   692 )
   693 {
   694     unsigned int i;
   695     PLHashNumber h;
   696     NSSCertificate *c = (NSSCertificate *)key;
   697     h = 0;
   698     for (i=0; i<c->issuer.size; i++)
   699 	h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->issuer.data)[i];
   700     for (i=0; i<c->serial.size; i++)
   701 	h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)c->serial.data)[i];
   702     return h;
   703 }
   705 static int
   706 nss_compare_certs(const void *v1, const void *v2)
   707 {
   708     PRStatus ignore;
   709     NSSCertificate *c1 = (NSSCertificate *)v1;
   710     NSSCertificate *c2 = (NSSCertificate *)v2;
   711     return (int)(nssItem_Equal(&c1->issuer, &c2->issuer, &ignore) &&
   712                  nssItem_Equal(&c1->serial, &c2->serial, &ignore));
   713 }
   715 NSS_IMPLEMENT nssHash *
   716 nssHash_CreateCertificate (
   717   NSSArena *arenaOpt,
   718   PRUint32 numBuckets
   719 )
   720 {
   721     return nssHash_Create(arenaOpt, 
   722                           numBuckets, 
   723                           nss_certificate_hash, 
   724                           nss_compare_certs, 
   725                           PL_CompareValues);
   726 }
   728 NSS_IMPLEMENT void
   729 nssCertificateStore_DumpStoreInfo (
   730   nssCertificateStore *store,
   731   void (* cert_dump_iter)(const void *, void *, void *),
   732   void *arg
   733 )
   734 {
   735     PZ_Lock(store->lock);
   736     nssHash_Iterate(store->issuer_and_serial, cert_dump_iter, arg);
   737     PZ_Unlock(store->lock);
   738 }

mercurial