Coverage Report

Created: 2024-11-21 07:03

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