~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/security/nss/lib/pki/tdcache.c

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * The contents of this file are subject to the Mozilla Public
 
3
 * License Version 1.1 (the "License"); you may not use this file
 
4
 * except in compliance with the License. You may obtain a copy of
 
5
 * the License at http://www.mozilla.org/MPL/
 
6
 * 
 
7
 * Software distributed under the License is distributed on an "AS
 
8
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 
9
 * implied. See the License for the specific language governing
 
10
 * rights and limitations under the License.
 
11
 * 
 
12
 * The Original Code is the Netscape security libraries.
 
13
 * 
 
14
 * The Initial Developer of the Original Code is Netscape
 
15
 * Communications Corporation.  Portions created by Netscape are 
 
16
 * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
 
17
 * Rights Reserved.
 
18
 * 
 
19
 * Contributor(s):
 
20
 * 
 
21
 * Alternatively, the contents of this file may be used under the
 
22
 * terms of the GNU General Public License Version 2 or later (the
 
23
 * "GPL"), in which case the provisions of the GPL are applicable 
 
24
 * instead of those above.  If you wish to allow use of your 
 
25
 * version of this file only under the terms of the GPL and not to
 
26
 * allow others to use your version of this file under the MPL,
 
27
 * indicate your decision by deleting the provisions above and
 
28
 * replace them with the notice and other provisions required by
 
29
 * the GPL.  If you do not delete the provisions above, a recipient
 
30
 * may use your version of this file under either the MPL or the
 
31
 * GPL.
 
32
 */
 
33
 
 
34
#ifdef DEBUG
 
35
static const char CVS_ID[] = "@(#) $RCSfile: tdcache.c,v $ $Revision: 1.38 $ $Date: 2003/12/19 22:33:12 $ $Name: FIREFOX_1_0_RELEASE $";
 
36
#endif /* DEBUG */
 
37
 
 
38
#ifndef PKIM_H
 
39
#include "pkim.h"
 
40
#endif /* PKIM_H */
 
41
 
 
42
#ifndef PKIT_H
 
43
#include "pkit.h"
 
44
#endif /* PKIT_H */
 
45
 
 
46
#ifndef NSSPKI_H
 
47
#include "nsspki.h"
 
48
#endif /* NSSPKI_H */
 
49
 
 
50
#ifndef PKI_H
 
51
#include "pki.h"
 
52
#endif /* PKI_H */
 
53
 
 
54
#ifndef NSSBASE_H
 
55
#include "nssbase.h"
 
56
#endif /* NSSBASE_H */
 
57
 
 
58
#ifndef BASE_H
 
59
#include "base.h"
 
60
#endif /* BASE_H */
 
61
 
 
62
#ifdef NSS_3_4_CODE
 
63
#include "cert.h"
 
64
#include "dev.h"
 
65
#include "pki3hack.h"
 
66
#endif
 
67
 
 
68
#ifdef DEBUG_CACHE
 
69
static PRLogModuleInfo *s_log = NULL;
 
70
#endif
 
71
 
 
72
#ifdef DEBUG_CACHE
 
73
static void log_item_dump(const char *msg, NSSItem *it)
 
74
{
 
75
    char buf[33];
 
76
    int i, j;
 
77
    for (i=0; i<10 && i<it->size; i++) {
 
78
        sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[i]);
 
79
    }
 
80
    if (it->size>10) {
 
81
        sprintf(&buf[2*i], "..");
 
82
        i += 1;
 
83
        for (j=it->size-1; i<=16 && j>10; i++, j--) {
 
84
            sprintf(&buf[2*i], "%02X", ((PRUint8 *)it->data)[j]);
 
85
        }
 
86
    }
 
87
    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg, buf));
 
88
}
 
89
#endif
 
90
 
 
91
#ifdef DEBUG_CACHE
 
92
static void log_cert_ref(const char *msg, NSSCertificate *c)
 
93
{
 
94
    PR_LOG(s_log, PR_LOG_DEBUG, ("%s: %s", msg,
 
95
                           (c->nickname) ? c->nickname : c->email));
 
96
    log_item_dump("\tserial", &c->serial);
 
97
    log_item_dump("\tsubject", &c->subject);
 
98
}
 
99
#endif
 
100
 
 
101
/* Certificate cache routines */
 
102
 
 
103
/* XXX
 
104
 * Locking is not handled well at all.  A single, global lock with sub-locks
 
105
 * in the collection types.  Cleanup needed.
 
106
 */
 
107
 
 
108
/* should it live in its own arena? */
 
109
struct nssTDCertificateCacheStr 
 
110
{
 
111
    PZLock *lock;
 
112
    NSSArena *arena;
 
113
    nssHash *issuerAndSN;
 
114
    nssHash *subject;
 
115
    nssHash *nickname;
 
116
    nssHash *email;
 
117
};
 
118
 
 
119
struct cache_entry_str 
 
120
{
 
121
    union {
 
122
        NSSCertificate *cert;
 
123
        nssList *list;
 
124
        void *value;
 
125
    } entry;
 
126
    PRUint32 hits;
 
127
    PRTime lastHit;
 
128
    NSSArena *arena;
 
129
    NSSUTF8 *nickname;
 
130
};
 
131
 
 
132
typedef struct cache_entry_str cache_entry;
 
133
 
 
134
static cache_entry *
 
135
new_cache_entry(NSSArena *arena, void *value, PRBool ownArena)
 
136
{
 
137
    cache_entry *ce = nss_ZNEW(arena, cache_entry);
 
138
    if (ce) {
 
139
        ce->entry.value = value;
 
140
        ce->hits = 1;
 
141
        ce->lastHit = PR_Now();
 
142
        if (ownArena) {
 
143
            ce->arena = arena;
 
144
        }
 
145
        ce->nickname = NULL;
 
146
    }
 
147
    return ce;
 
148
}
 
149
 
 
150
/* sort the subject list from newest to oldest */
 
151
static PRIntn subject_list_sort(void *v1, void *v2)
 
152
{
 
153
    NSSCertificate *c1 = (NSSCertificate *)v1;
 
154
    NSSCertificate *c2 = (NSSCertificate *)v2;
 
155
    nssDecodedCert *dc1 = nssCertificate_GetDecoding(c1);
 
156
    nssDecodedCert *dc2 = nssCertificate_GetDecoding(c2);
 
157
    if (dc1->isNewerThan(dc1, dc2)) {
 
158
        return -1;
 
159
    } else {
 
160
        return 1;
 
161
    }
 
162
}
 
163
 
 
164
/* this should not be exposed in a header, but is here to keep the above
 
165
 * types/functions static
 
166
 */
 
167
NSS_IMPLEMENT PRStatus
 
168
nssTrustDomain_InitializeCache (
 
169
  NSSTrustDomain *td,
 
170
  PRUint32 cacheSize
 
171
)
 
172
{
 
173
    NSSArena *arena;
 
174
    nssTDCertificateCache *cache = td->cache;
 
175
#ifdef DEBUG_CACHE
 
176
    s_log = PR_NewLogModule("nss_cache");
 
177
    PR_ASSERT(s_log);
 
178
#endif
 
179
    PR_ASSERT(!cache);
 
180
    arena = nssArena_Create();
 
181
    if (!arena) {
 
182
        return PR_FAILURE;
 
183
    }
 
184
    cache = nss_ZNEW(arena, nssTDCertificateCache);
 
185
    if (!cache) {
 
186
        nssArena_Destroy(arena);
 
187
        return PR_FAILURE;
 
188
    }
 
189
    cache->lock = PZ_NewLock(nssILockCache);
 
190
    if (!cache->lock) {
 
191
        nssArena_Destroy(arena);
 
192
        return PR_FAILURE;
 
193
    }
 
194
    /* Create the issuer and serial DER --> certificate hash */
 
195
    cache->issuerAndSN = nssHash_CreateCertificate(arena, cacheSize);
 
196
    if (!cache->issuerAndSN) {
 
197
        goto loser;
 
198
    }
 
199
    /* Create the subject DER --> subject list hash */
 
200
    cache->subject = nssHash_CreateItem(arena, cacheSize);
 
201
    if (!cache->subject) {
 
202
        goto loser;
 
203
    }
 
204
    /* Create the nickname --> subject list hash */
 
205
    cache->nickname = nssHash_CreateString(arena, cacheSize);
 
206
    if (!cache->nickname) {
 
207
        goto loser;
 
208
    }
 
209
    /* Create the email --> list of subject lists hash */
 
210
    cache->email = nssHash_CreateString(arena, cacheSize);
 
211
    if (!cache->email) {
 
212
        goto loser;
 
213
    }
 
214
    cache->arena = arena;
 
215
    td->cache = cache;
 
216
#ifdef DEBUG_CACHE
 
217
    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialized."));
 
218
#endif
 
219
    return PR_SUCCESS;
 
220
loser:
 
221
    PZ_DestroyLock(cache->lock);
 
222
    nssArena_Destroy(arena);
 
223
    td->cache = NULL;
 
224
#ifdef DEBUG_CACHE
 
225
    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache initialization failed."));
 
226
#endif
 
227
    return PR_FAILURE;
 
228
}
 
229
 
 
230
/* The entries of the hashtable are currently dependent on the certificate(s)
 
231
 * that produced them.  That is, the entries will be freed when the cert is
 
232
 * released from the cache.  If there are certs in the cache at any time,
 
233
 * including shutdown, the hash table entries will hold memory.  In order for
 
234
 * clean shutdown, it is necessary for there to be no certs in the cache.
 
235
 */
 
236
 
 
237
extern const NSSError NSS_ERROR_INTERNAL_ERROR;
 
238
extern const NSSError NSS_ERROR_BUSY;
 
239
 
 
240
NSS_IMPLEMENT PRStatus
 
241
nssTrustDomain_DestroyCache (
 
242
  NSSTrustDomain *td
 
243
)
 
244
{
 
245
    if (!td->cache) {
 
246
        nss_SetError(NSS_ERROR_INTERNAL_ERROR);
 
247
        return PR_FAILURE;
 
248
    }
 
249
    if (nssHash_Count(td->cache->issuerAndSN) > 0) {
 
250
        nss_SetError(NSS_ERROR_BUSY);
 
251
        return PR_FAILURE;
 
252
    }
 
253
    PZ_DestroyLock(td->cache->lock);
 
254
    nssHash_Destroy(td->cache->issuerAndSN);
 
255
    nssHash_Destroy(td->cache->subject);
 
256
    nssHash_Destroy(td->cache->nickname);
 
257
    nssHash_Destroy(td->cache->email);
 
258
    nssArena_Destroy(td->cache->arena);
 
259
    td->cache = NULL;
 
260
#ifdef DEBUG_CACHE
 
261
    PR_LOG(s_log, PR_LOG_DEBUG, ("Cache destroyed."));
 
262
#endif
 
263
    return PR_SUCCESS;
 
264
}
 
265
 
 
266
static PRStatus
 
267
remove_issuer_and_serial_entry (
 
268
  nssTDCertificateCache *cache,
 
269
  NSSCertificate *cert
 
270
)
 
271
{
 
272
    /* Remove the cert from the issuer/serial hash */
 
273
    nssHash_Remove(cache->issuerAndSN, cert);
 
274
#ifdef DEBUG_CACHE
 
275
    log_cert_ref("removed issuer/sn", cert);
 
276
#endif
 
277
    return PR_SUCCESS;
 
278
}
 
279
 
 
280
static PRStatus
 
281
remove_subject_entry (
 
282
  nssTDCertificateCache *cache,
 
283
  NSSCertificate *cert,
 
284
  nssList **subjectList,
 
285
  NSSUTF8 **nickname,
 
286
  NSSArena **arena
 
287
)
 
288
{
 
289
    PRStatus nssrv;
 
290
    cache_entry *ce;
 
291
    *subjectList = NULL;
 
292
    *arena = NULL;
 
293
    /* Get the subject list for the cert's subject */
 
294
    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
 
295
    if (ce) {
 
296
        /* Remove the cert from the subject hash */
 
297
        nssList_Remove(ce->entry.list, cert);
 
298
        *subjectList = ce->entry.list;
 
299
        *nickname = ce->nickname;
 
300
        *arena = ce->arena;
 
301
        nssrv = PR_SUCCESS;
 
302
#ifdef DEBUG_CACHE
 
303
        log_cert_ref("removed cert", cert);
 
304
        log_item_dump("from subject list", &cert->subject);
 
305
#endif
 
306
    } else {
 
307
        nssrv = PR_FAILURE;
 
308
    }
 
309
    return nssrv;
 
310
}
 
311
 
 
312
static PRStatus
 
313
remove_nickname_entry (
 
314
  nssTDCertificateCache *cache,
 
315
  NSSUTF8 *nickname,
 
316
  nssList *subjectList
 
317
)
 
318
{
 
319
    PRStatus nssrv;
 
320
    if (nickname) {
 
321
        nssHash_Remove(cache->nickname, nickname);
 
322
        nssrv = PR_SUCCESS;
 
323
#ifdef DEBUG_CACHE
 
324
        PR_LOG(s_log, PR_LOG_DEBUG, ("removed nickname %s", nickname));
 
325
#endif
 
326
    } else {
 
327
        nssrv = PR_FAILURE;
 
328
    }
 
329
    return nssrv;
 
330
}
 
331
 
 
332
static PRStatus
 
333
remove_email_entry (
 
334
  nssTDCertificateCache *cache,
 
335
  NSSCertificate *cert,
 
336
  nssList *subjectList
 
337
)
 
338
{
 
339
    PRStatus nssrv = PR_FAILURE;
 
340
    cache_entry *ce;
 
341
    /* Find the subject list in the email hash */
 
342
    if (cert->email) {
 
343
        ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
 
344
        if (ce) {
 
345
            nssList *subjects = ce->entry.list;
 
346
            /* Remove the subject list from the email hash */
 
347
            nssList_Remove(subjects, subjectList);
 
348
#ifdef DEBUG_CACHE
 
349
            log_item_dump("removed subject list", &cert->subject);
 
350
            PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
 
351
#endif
 
352
            if (nssList_Count(subjects) == 0) {
 
353
                /* No more subject lists for email, delete list and
 
354
                * remove hash entry
 
355
                */
 
356
                (void)nssList_Destroy(subjects);
 
357
                nssHash_Remove(cache->email, cert->email);
 
358
                /* there are no entries left for this address, free space
 
359
                 * used for email entries
 
360
                 */
 
361
                nssArena_Destroy(ce->arena);
 
362
#ifdef DEBUG_CACHE
 
363
                PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
 
364
#endif
 
365
            }
 
366
            nssrv = PR_SUCCESS;
 
367
        }
 
368
    }
 
369
    return nssrv;
 
370
}
 
371
 
 
372
NSS_IMPLEMENT void
 
373
nssTrustDomain_RemoveCertFromCacheLOCKED (
 
374
  NSSTrustDomain *td,
 
375
  NSSCertificate *cert
 
376
)
 
377
{
 
378
    nssList *subjectList;
 
379
    cache_entry *ce;
 
380
    NSSArena *arena;
 
381
    NSSUTF8 *nickname;
 
382
 
 
383
#ifdef DEBUG_CACHE
 
384
    log_cert_ref("attempt to remove cert", cert);
 
385
#endif
 
386
    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
 
387
    if (!ce || ce->entry.cert != cert) {
 
388
        /* If it's not in the cache, or a different cert is (this is really
 
389
         * for safety reasons, though it shouldn't happen), do nothing 
 
390
         */
 
391
#ifdef DEBUG_CACHE
 
392
        PR_LOG(s_log, PR_LOG_DEBUG, ("but it wasn't in the cache"));
 
393
#endif
 
394
        return;
 
395
    }
 
396
    (void)remove_issuer_and_serial_entry(td->cache, cert);
 
397
    (void)remove_subject_entry(td->cache, cert, &subjectList, 
 
398
                               &nickname, &arena);
 
399
    if (nssList_Count(subjectList) == 0) {
 
400
        (void)remove_nickname_entry(td->cache, nickname, subjectList);
 
401
        (void)remove_email_entry(td->cache, cert, subjectList);
 
402
        (void)nssList_Destroy(subjectList);
 
403
        nssHash_Remove(td->cache->subject, &cert->subject);
 
404
        /* there are no entries left for this subject, free the space used
 
405
         * for both the nickname and subject entries
 
406
         */
 
407
        if (arena) {
 
408
            nssArena_Destroy(arena);
 
409
        }
 
410
    }
 
411
}
 
412
 
 
413
NSS_IMPLEMENT void
 
414
nssTrustDomain_LockCertCache (
 
415
  NSSTrustDomain *td
 
416
)
 
417
{
 
418
    PZ_Lock(td->cache->lock);
 
419
}
 
420
 
 
421
NSS_IMPLEMENT void
 
422
nssTrustDomain_UnlockCertCache (
 
423
  NSSTrustDomain *td
 
424
)
 
425
{
 
426
    PZ_Unlock(td->cache->lock);
 
427
}
 
428
 
 
429
struct token_cert_dtor {
 
430
    NSSToken *token;
 
431
    nssTDCertificateCache *cache;
 
432
    NSSCertificate **certs;
 
433
    PRUint32 numCerts, arrSize;
 
434
};
 
435
 
 
436
static void 
 
437
remove_token_certs(const void *k, void *v, void *a)
 
438
{
 
439
    NSSCertificate *c = (NSSCertificate *)k;
 
440
    nssPKIObject *object = &c->object;
 
441
    struct token_cert_dtor *dtor = a;
 
442
    PRUint32 i;
 
443
    PZ_Lock(object->lock);
 
444
    for (i=0; i<object->numInstances; i++) {
 
445
        if (object->instances[i]->token == dtor->token) {
 
446
            nssCryptokiObject_Destroy(object->instances[i]);
 
447
            object->instances[i] = object->instances[object->numInstances-1];
 
448
            object->instances[object->numInstances-1] = NULL;
 
449
            object->numInstances--;
 
450
            dtor->certs[dtor->numCerts++] = c;
 
451
            if (dtor->numCerts == dtor->arrSize) {
 
452
                dtor->arrSize *= 2;
 
453
                dtor->certs = nss_ZREALLOCARRAY(dtor->certs, 
 
454
                                                NSSCertificate *,
 
455
                                                dtor->arrSize);
 
456
            }
 
457
            break;
 
458
        }
 
459
    }
 
460
    PZ_Unlock(object->lock);
 
461
    return;
 
462
}
 
463
 
 
464
/* 
 
465
 * Remove all certs for the given token from the cache.  This is
 
466
 * needed if the token is removed. 
 
467
 */
 
468
NSS_IMPLEMENT PRStatus
 
469
nssTrustDomain_RemoveTokenCertsFromCache (
 
470
  NSSTrustDomain *td,
 
471
  NSSToken *token
 
472
)
 
473
{
 
474
    NSSCertificate **certs;
 
475
    PRUint32 i, arrSize = 10;
 
476
    struct token_cert_dtor dtor;
 
477
    certs = nss_ZNEWARRAY(NULL, NSSCertificate *, arrSize);
 
478
    if (!certs) {
 
479
        return PR_FAILURE;
 
480
    }
 
481
    dtor.cache = td->cache;
 
482
    dtor.token = token;
 
483
    dtor.certs = certs;
 
484
    dtor.numCerts = 0;
 
485
    dtor.arrSize = arrSize;
 
486
    PZ_Lock(td->cache->lock);
 
487
    nssHash_Iterate(td->cache->issuerAndSN, remove_token_certs, (void *)&dtor);
 
488
    for (i=0; i<dtor.numCerts; i++) {
 
489
        if (dtor.certs[i]->object.numInstances == 0) {
 
490
            nssTrustDomain_RemoveCertFromCacheLOCKED(td, dtor.certs[i]);
 
491
            dtor.certs[i] = NULL;  /* skip this cert in the second for loop */
 
492
        }
 
493
    }
 
494
    PZ_Unlock(td->cache->lock);
 
495
    for (i=0; i<dtor.numCerts; i++) {
 
496
        if (dtor.certs[i]) {
 
497
            STAN_ForceCERTCertificateUpdate(dtor.certs[i]);
 
498
        }
 
499
    }
 
500
    nss_ZFreeIf(dtor.certs);
 
501
    return PR_SUCCESS;
 
502
}
 
503
 
 
504
NSS_IMPLEMENT PRStatus
 
505
nssTrustDomain_UpdateCachedTokenCerts (
 
506
  NSSTrustDomain *td,
 
507
  NSSToken *token
 
508
)
 
509
{
 
510
    NSSCertificate **cp, **cached = NULL;
 
511
    nssList *certList;
 
512
    PRUint32 count;
 
513
    certList = nssList_Create(NULL, PR_FALSE);
 
514
    if (!certList) return PR_FAILURE;
 
515
    (void *)nssTrustDomain_GetCertsFromCache(td, certList);
 
516
    count = nssList_Count(certList);
 
517
    if (count > 0) {
 
518
        cached = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
 
519
        if (!cached) {
 
520
            return PR_FAILURE;
 
521
        }
 
522
        nssList_GetArray(certList, (void **)cached, count);
 
523
        nssList_Destroy(certList);
 
524
        for (cp = cached; *cp; cp++) {
 
525
            nssCryptokiObject *instance;
 
526
            NSSCertificate *c = *cp;
 
527
            nssTokenSearchType tokenOnly = nssTokenSearchType_TokenOnly;
 
528
            instance = nssToken_FindCertificateByIssuerAndSerialNumber(
 
529
                                                               token,
 
530
                                                               NULL,
 
531
                                                               &c->issuer,
 
532
                                                               &c->serial,
 
533
                                                               tokenOnly,
 
534
                                                               NULL);
 
535
            if (instance) {
 
536
                nssPKIObject_AddInstance(&c->object, instance);
 
537
                STAN_ForceCERTCertificateUpdate(c);
 
538
            }
 
539
        }
 
540
        nssCertificateArray_Destroy(cached);
 
541
    }
 
542
    return PR_SUCCESS;
 
543
}
 
544
 
 
545
static PRStatus
 
546
add_issuer_and_serial_entry (
 
547
  NSSArena *arena,
 
548
  nssTDCertificateCache *cache, 
 
549
  NSSCertificate *cert
 
550
)
 
551
{
 
552
    cache_entry *ce;
 
553
    ce = new_cache_entry(arena, (void *)cert, PR_FALSE);
 
554
#ifdef DEBUG_CACHE
 
555
    log_cert_ref("added to issuer/sn", cert);
 
556
#endif
 
557
    return nssHash_Add(cache->issuerAndSN, cert, (void *)ce);
 
558
}
 
559
 
 
560
static PRStatus
 
561
add_subject_entry (
 
562
  NSSArena *arena,
 
563
  nssTDCertificateCache *cache, 
 
564
  NSSCertificate *cert,
 
565
  NSSUTF8 *nickname,
 
566
  nssList **subjectList
 
567
)
 
568
{
 
569
    PRStatus nssrv;
 
570
    nssList *list;
 
571
    cache_entry *ce;
 
572
    *subjectList = NULL;  /* this is only set if a new one is created */
 
573
    ce = (cache_entry *)nssHash_Lookup(cache->subject, &cert->subject);
 
574
    if (ce) {
 
575
        ce->hits++;
 
576
        ce->lastHit = PR_Now();
 
577
        /* The subject is already in, add this cert to the list */
 
578
        nssrv = nssList_AddUnique(ce->entry.list, cert);
 
579
#ifdef DEBUG_CACHE
 
580
        log_cert_ref("added to existing subject list", cert);
 
581
#endif
 
582
    } else {
 
583
        NSSDER *subject;
 
584
        /* Create a new subject list for the subject */
 
585
        list = nssList_Create(arena, PR_FALSE);
 
586
        if (!list) {
 
587
            return PR_FAILURE;
 
588
        }
 
589
        ce = new_cache_entry(arena, (void *)list, PR_TRUE);
 
590
        if (!ce) {
 
591
            return PR_FAILURE;
 
592
        }
 
593
        if (nickname) {
 
594
            ce->nickname = nssUTF8_Duplicate(nickname, arena);
 
595
        }
 
596
        nssList_SetSortFunction(list, subject_list_sort);
 
597
        /* Add the cert entry to this list of subjects */
 
598
        nssrv = nssList_AddUnique(list, cert);
 
599
        if (nssrv != PR_SUCCESS) {
 
600
            return nssrv;
 
601
        }
 
602
        /* Add the subject list to the cache */
 
603
        subject = nssItem_Duplicate(&cert->subject, arena, NULL);
 
604
        if (!subject) {
 
605
            return PR_FAILURE;
 
606
        }
 
607
        nssrv = nssHash_Add(cache->subject, subject, ce);
 
608
        if (nssrv != PR_SUCCESS) {
 
609
            return nssrv;
 
610
        }
 
611
        *subjectList = list;
 
612
#ifdef DEBUG_CACHE
 
613
        log_cert_ref("created subject list", cert);
 
614
#endif
 
615
    }
 
616
    return nssrv;
 
617
}
 
618
 
 
619
static PRStatus
 
620
add_nickname_entry (
 
621
  NSSArena *arena,
 
622
  nssTDCertificateCache *cache, 
 
623
  NSSUTF8 *certNickname,
 
624
  nssList *subjectList
 
625
)
 
626
{
 
627
    PRStatus nssrv = PR_SUCCESS;
 
628
    cache_entry *ce;
 
629
    ce = (cache_entry *)nssHash_Lookup(cache->nickname, certNickname);
 
630
    if (ce) {
 
631
        /* This is a collision.  A nickname entry already exists for this
 
632
         * subject, but a subject entry didn't.  This would imply there are
 
633
         * two subjects using the same nickname, which is not allowed.
 
634
         */
 
635
        return PR_FAILURE;
 
636
    } else {
 
637
        NSSUTF8 *nickname;
 
638
        ce = new_cache_entry(arena, subjectList, PR_FALSE);
 
639
        if (!ce) {
 
640
            return PR_FAILURE;
 
641
        }
 
642
        nickname = nssUTF8_Duplicate(certNickname, arena);
 
643
        if (!nickname) {
 
644
            return PR_FAILURE;
 
645
        }
 
646
        nssrv = nssHash_Add(cache->nickname, nickname, ce);
 
647
#ifdef DEBUG_CACHE
 
648
        log_cert_ref("created nickname for", cert);
 
649
#endif
 
650
    }
 
651
    return nssrv;
 
652
}
 
653
 
 
654
static PRStatus
 
655
add_email_entry (
 
656
  nssTDCertificateCache *cache, 
 
657
  NSSCertificate *cert,
 
658
  nssList *subjectList
 
659
)
 
660
{
 
661
    PRStatus nssrv = PR_SUCCESS;
 
662
    nssList *subjects;
 
663
    cache_entry *ce;
 
664
    ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
 
665
    if (ce) {
 
666
        /* Already have an entry for this email address, but not subject */
 
667
        subjects = ce->entry.list;
 
668
        nssrv = nssList_AddUnique(subjects, subjectList);
 
669
        ce->hits++;
 
670
        ce->lastHit = PR_Now();
 
671
#ifdef DEBUG_CACHE
 
672
        log_cert_ref("added subject to email for", cert);
 
673
#endif
 
674
    } else {
 
675
        NSSASCII7 *email;
 
676
        NSSArena *arena;
 
677
        arena = nssArena_Create();
 
678
        if (!arena) {
 
679
            return PR_FAILURE;
 
680
        }
 
681
        /* Create a new list of subject lists, add this subject */
 
682
        subjects = nssList_Create(arena, PR_TRUE);
 
683
        if (!subjects) {
 
684
            nssArena_Destroy(arena);
 
685
            return PR_FAILURE;
 
686
        }
 
687
        /* Add the new subject to the list */
 
688
        nssrv = nssList_AddUnique(subjects, subjectList);
 
689
        if (nssrv != PR_SUCCESS) {
 
690
            nssArena_Destroy(arena);
 
691
            return nssrv;
 
692
        }
 
693
        /* Add the new entry to the cache */
 
694
        ce = new_cache_entry(arena, (void *)subjects, PR_TRUE);
 
695
        if (!ce) {
 
696
            nssArena_Destroy(arena);
 
697
            return PR_FAILURE;
 
698
        }
 
699
        email = nssUTF8_Duplicate(cert->email, arena);
 
700
        if (!email) {
 
701
            nssArena_Destroy(arena);
 
702
            return PR_FAILURE;
 
703
        }
 
704
        nssrv = nssHash_Add(cache->email, email, ce);
 
705
        if (nssrv != PR_SUCCESS) {
 
706
            nssArena_Destroy(arena);
 
707
            return nssrv;
 
708
        }
 
709
#ifdef DEBUG_CACHE
 
710
        log_cert_ref("created email for", cert);
 
711
#endif
 
712
    }
 
713
    return nssrv;
 
714
}
 
715
 
 
716
extern const NSSError NSS_ERROR_CERTIFICATE_IN_CACHE;
 
717
 
 
718
static void
 
719
remove_object_instances (
 
720
  nssPKIObject *object,
 
721
  nssCryptokiObject **instances,
 
722
  int numInstances
 
723
)
 
724
{
 
725
    int i;
 
726
 
 
727
    for (i = 0; i < numInstances; i++) {
 
728
        nssPKIObject_RemoveInstanceForToken(object, instances[i]->token);
 
729
    }
 
730
}
 
731
 
 
732
static SECStatus
 
733
merge_object_instances (
 
734
  nssPKIObject *to,
 
735
  nssPKIObject *from
 
736
)
 
737
{
 
738
    nssCryptokiObject **instances, **ci;
 
739
    int i;
 
740
    SECStatus rv = SECSuccess;
 
741
 
 
742
    instances = nssPKIObject_GetInstances(from);
 
743
    if (instances == NULL) {
 
744
        return SECFailure;
 
745
    }
 
746
    for (ci = instances, i = 0; *ci; ci++, i++) {
 
747
        nssCryptokiObject *instance = nssCryptokiObject_Clone(*ci);
 
748
        if (instance) {
 
749
            if (nssPKIObject_AddInstance(to, instance) == SECSuccess) {
 
750
                continue;
 
751
            }
 
752
            nssCryptokiObject_Destroy(instance);
 
753
        }
 
754
        remove_object_instances(to, instances, i);
 
755
        rv = SECFailure;
 
756
        break;
 
757
    }
 
758
    nssCryptokiObjectArray_Destroy(instances);
 
759
    return rv;
 
760
}
 
761
 
 
762
static NSSCertificate *
 
763
add_cert_to_cache (
 
764
  NSSTrustDomain *td, 
 
765
  NSSCertificate *cert
 
766
)
 
767
{
 
768
    NSSArena *arena = NULL;
 
769
    nssList *subjectList = NULL;
 
770
    PRStatus nssrv;
 
771
    PRUint32 added = 0;
 
772
    cache_entry *ce;
 
773
    NSSCertificate *rvCert = NULL;
 
774
    NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
 
775
 
 
776
    PZ_Lock(td->cache->lock);
 
777
    /* If it exists in the issuer/serial hash, it's already in all */
 
778
    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, cert);
 
779
    if (ce) {
 
780
        ce->hits++;
 
781
        ce->lastHit = PR_Now();
 
782
        rvCert = nssCertificate_AddRef(ce->entry.cert);
 
783
#ifdef DEBUG_CACHE
 
784
        log_cert_ref("attempted to add cert already in cache", cert);
 
785
#endif
 
786
        PZ_Unlock(td->cache->lock);
 
787
        /* collision - somebody else already added the cert
 
788
         * to the cache before this thread got around to it.
 
789
         */
 
790
        /* merge the instances of the cert */
 
791
        if (merge_object_instances(&rvCert->object, &cert->object)
 
792
                                                        != SECSuccess) {
 
793
            nssCertificate_Destroy(rvCert);
 
794
            return NULL;
 
795
        }
 
796
        STAN_ForceCERTCertificateUpdate(rvCert);
 
797
        nssCertificate_Destroy(cert);
 
798
        return rvCert;
 
799
    }
 
800
    /* create a new cache entry for this cert within the cert's arena*/
 
801
    nssrv = add_issuer_and_serial_entry(cert->object.arena, td->cache, cert);
 
802
    if (nssrv != PR_SUCCESS) {
 
803
        goto loser;
 
804
    }
 
805
    added++;
 
806
    /* create an arena for the nickname and subject entries */
 
807
    arena = nssArena_Create();
 
808
    if (!arena) {
 
809
        goto loser;
 
810
    }
 
811
    /* create a new subject list for this cert, or add to existing */
 
812
    nssrv = add_subject_entry(arena, td->cache, cert, 
 
813
                                                certNickname, &subjectList);
 
814
    if (nssrv != PR_SUCCESS) {
 
815
        goto loser;
 
816
    }
 
817
    added++;
 
818
    /* If a new subject entry was created, also need nickname and/or email */
 
819
    if (subjectList != NULL) {
 
820
        PRBool handle = PR_FALSE;
 
821
        if (certNickname) {
 
822
            nssrv = add_nickname_entry(arena, td->cache, 
 
823
                                                certNickname, subjectList);
 
824
            if (nssrv != PR_SUCCESS) {
 
825
                goto loser;
 
826
            }
 
827
            handle = PR_TRUE;
 
828
            added++;
 
829
        }
 
830
        if (cert->email) {
 
831
            nssrv = add_email_entry(td->cache, cert, subjectList);
 
832
            if (nssrv != PR_SUCCESS) {
 
833
                goto loser;
 
834
            }
 
835
            handle = PR_TRUE;
 
836
            added += 2;
 
837
        }
 
838
#ifdef nodef
 
839
        /* I think either a nickname or email address must be associated
 
840
         * with the cert.  However, certs are passed to NewTemp without
 
841
         * either.  This worked in the old code, so it must work now.
 
842
         */
 
843
        if (!handle) {
 
844
            /* Require either nickname or email handle */
 
845
            nssrv = PR_FAILURE;
 
846
            goto loser;
 
847
        }
 
848
#endif
 
849
    }
 
850
    rvCert = cert;
 
851
    PZ_Unlock(td->cache->lock);
 
852
    return rvCert;
 
853
loser:
 
854
    /* Remove any handles that have been created */
 
855
    subjectList = NULL;
 
856
    if (added >= 1) {
 
857
        (void)remove_issuer_and_serial_entry(td->cache, cert);
 
858
    }
 
859
    if (added >= 2) {
 
860
        (void)remove_subject_entry(td->cache, cert, &subjectList, 
 
861
                                                &certNickname, &arena);
 
862
    }
 
863
    if (added == 3 || added == 5) {
 
864
        (void)remove_nickname_entry(td->cache, certNickname, subjectList);
 
865
    }
 
866
    if (added >= 4) {
 
867
        (void)remove_email_entry(td->cache, cert, subjectList);
 
868
    }
 
869
    if (subjectList) {
 
870
        nssHash_Remove(td->cache->subject, &cert->subject);
 
871
        nssList_Destroy(subjectList);
 
872
    }
 
873
    if (arena) {
 
874
        nssArena_Destroy(arena);
 
875
    }
 
876
    PZ_Unlock(td->cache->lock);
 
877
    return NULL;
 
878
}
 
879
 
 
880
NSS_IMPLEMENT PRStatus
 
881
nssTrustDomain_AddCertsToCache (
 
882
  NSSTrustDomain *td,
 
883
  NSSCertificate **certs,
 
884
  PRUint32 numCerts
 
885
)
 
886
{
 
887
    PRUint32 i;
 
888
    NSSCertificate *c;
 
889
    for (i=0; i<numCerts && certs[i]; i++) {
 
890
        c = add_cert_to_cache(td, certs[i]);
 
891
        if (c == NULL) {
 
892
            return PR_FAILURE;
 
893
        } else {
 
894
            certs[i] = c;
 
895
        }
 
896
    }
 
897
    return PR_SUCCESS;
 
898
}
 
899
 
 
900
static NSSCertificate **
 
901
collect_subject_certs (
 
902
  nssList *subjectList,
 
903
  nssList *rvCertListOpt
 
904
)
 
905
{
 
906
    NSSCertificate *c;
 
907
    NSSCertificate **rvArray = NULL;
 
908
    PRUint32 count;
 
909
    nssCertificateList_AddReferences(subjectList);
 
910
    if (rvCertListOpt) {
 
911
        nssListIterator *iter = nssList_CreateIterator(subjectList);
 
912
        for (c  = (NSSCertificate *)nssListIterator_Start(iter);
 
913
             c != (NSSCertificate *)NULL;
 
914
             c  = (NSSCertificate *)nssListIterator_Next(iter)) {
 
915
            nssList_Add(rvCertListOpt, c);
 
916
        }
 
917
        nssListIterator_Finish(iter);
 
918
        nssListIterator_Destroy(iter);
 
919
    } else {
 
920
        count = nssList_Count(subjectList);
 
921
        rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count + 1);
 
922
        if (!rvArray) {
 
923
            return (NSSCertificate **)NULL;
 
924
        }
 
925
        nssList_GetArray(subjectList, (void **)rvArray, count);
 
926
    }
 
927
    return rvArray;
 
928
}
 
929
 
 
930
/*
 
931
 * Find all cached certs with this subject.
 
932
 */
 
933
NSS_IMPLEMENT NSSCertificate **
 
934
nssTrustDomain_GetCertsForSubjectFromCache (
 
935
  NSSTrustDomain *td,
 
936
  NSSDER *subject,
 
937
  nssList *certListOpt
 
938
)
 
939
{
 
940
    NSSCertificate **rvArray = NULL;
 
941
    cache_entry *ce;
 
942
#ifdef DEBUG_CACHE
 
943
    log_item_dump("looking for cert by subject", subject);
 
944
#endif
 
945
    PZ_Lock(td->cache->lock);
 
946
    ce = (cache_entry *)nssHash_Lookup(td->cache->subject, subject);
 
947
    if (ce) {
 
948
        ce->hits++;
 
949
        ce->lastHit = PR_Now();
 
950
#ifdef DEBUG_CACHE
 
951
        PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
 
952
#endif
 
953
        rvArray = collect_subject_certs(ce->entry.list, certListOpt);
 
954
    }
 
955
    PZ_Unlock(td->cache->lock);
 
956
    return rvArray;
 
957
}
 
958
 
 
959
/*
 
960
 * Find all cached certs with this label.
 
961
 */
 
962
NSS_IMPLEMENT NSSCertificate **
 
963
nssTrustDomain_GetCertsForNicknameFromCache (
 
964
  NSSTrustDomain *td,
 
965
  NSSUTF8 *nickname,
 
966
  nssList *certListOpt
 
967
)
 
968
{
 
969
    NSSCertificate **rvArray = NULL;
 
970
    cache_entry *ce;
 
971
#ifdef DEBUG_CACHE
 
972
    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by nick %s", nickname));
 
973
#endif
 
974
    PZ_Lock(td->cache->lock);
 
975
    ce = (cache_entry *)nssHash_Lookup(td->cache->nickname, nickname);
 
976
    if (ce) {
 
977
        ce->hits++;
 
978
        ce->lastHit = PR_Now();
 
979
#ifdef DEBUG_CACHE
 
980
        PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
 
981
#endif
 
982
        rvArray = collect_subject_certs(ce->entry.list, certListOpt);
 
983
    }
 
984
    PZ_Unlock(td->cache->lock);
 
985
    return rvArray;
 
986
}
 
987
 
 
988
/*
 
989
 * Find all cached certs with this email address.
 
990
 */
 
991
NSS_IMPLEMENT NSSCertificate **
 
992
nssTrustDomain_GetCertsForEmailAddressFromCache (
 
993
  NSSTrustDomain *td,
 
994
  NSSASCII7 *email,
 
995
  nssList *certListOpt
 
996
)
 
997
{
 
998
    NSSCertificate **rvArray = NULL;
 
999
    cache_entry *ce;
 
1000
    nssList *collectList = NULL;
 
1001
    nssListIterator *iter = NULL;
 
1002
    nssList *subjectList;
 
1003
#ifdef DEBUG_CACHE
 
1004
    PR_LOG(s_log, PR_LOG_DEBUG, ("looking for cert by email %s", email));
 
1005
#endif
 
1006
    PZ_Lock(td->cache->lock);
 
1007
    ce = (cache_entry *)nssHash_Lookup(td->cache->email, email);
 
1008
    if (ce) {
 
1009
        ce->hits++;
 
1010
        ce->lastHit = PR_Now();
 
1011
#ifdef DEBUG_CACHE
 
1012
        PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
 
1013
#endif
 
1014
        /* loop over subject lists and get refs for certs */
 
1015
        if (certListOpt) {
 
1016
            collectList = certListOpt;
 
1017
        } else {
 
1018
            collectList = nssList_Create(NULL, PR_FALSE);
 
1019
            if (!collectList) {
 
1020
                PZ_Unlock(td->cache->lock);
 
1021
                return NULL;
 
1022
            }
 
1023
        }
 
1024
        iter = nssList_CreateIterator(ce->entry.list);
 
1025
        if (!iter) {
 
1026
            PZ_Unlock(td->cache->lock);
 
1027
            if (!certListOpt) {
 
1028
                nssList_Destroy(collectList);
 
1029
            }
 
1030
            return NULL;
 
1031
        }
 
1032
        for (subjectList  = (nssList *)nssListIterator_Start(iter);
 
1033
             subjectList != (nssList *)NULL;
 
1034
             subjectList  = (nssList *)nssListIterator_Next(iter)) {
 
1035
            (void)collect_subject_certs(subjectList, collectList);
 
1036
        }
 
1037
        nssListIterator_Finish(iter);
 
1038
        nssListIterator_Destroy(iter);
 
1039
    }
 
1040
    PZ_Unlock(td->cache->lock);
 
1041
    if (!certListOpt && collectList) {
 
1042
        PRUint32 count = nssList_Count(collectList);
 
1043
        rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
 
1044
        if (rvArray) {
 
1045
            nssList_GetArray(collectList, (void **)rvArray, count);
 
1046
        }
 
1047
        nssList_Destroy(collectList);
 
1048
    }
 
1049
    return rvArray;
 
1050
}
 
1051
 
 
1052
/*
 
1053
 * Look for a specific cert in the cache
 
1054
 */
 
1055
NSS_IMPLEMENT NSSCertificate *
 
1056
nssTrustDomain_GetCertForIssuerAndSNFromCache (
 
1057
  NSSTrustDomain *td,
 
1058
  NSSDER *issuer,
 
1059
  NSSDER *serial
 
1060
)
 
1061
{
 
1062
    NSSCertificate certkey;
 
1063
    NSSCertificate *rvCert = NULL;
 
1064
    cache_entry *ce;
 
1065
    certkey.issuer.data = issuer->data;
 
1066
    certkey.issuer.size = issuer->size;
 
1067
    certkey.serial.data = serial->data;
 
1068
    certkey.serial.size = serial->size;
 
1069
#ifdef DEBUG_CACHE
 
1070
    log_item_dump("looking for cert by issuer/sn, issuer", issuer);
 
1071
    log_item_dump("                               serial", serial);
 
1072
#endif
 
1073
    PZ_Lock(td->cache->lock);
 
1074
    ce = (cache_entry *)nssHash_Lookup(td->cache->issuerAndSN, &certkey);
 
1075
    if (ce) {
 
1076
        ce->hits++;
 
1077
        ce->lastHit = PR_Now();
 
1078
        rvCert = nssCertificate_AddRef(ce->entry.cert);
 
1079
#ifdef DEBUG_CACHE
 
1080
        PR_LOG(s_log, PR_LOG_DEBUG, ("... found, %d hits", ce->hits));
 
1081
#endif
 
1082
    }
 
1083
    PZ_Unlock(td->cache->lock);
 
1084
    return rvCert;
 
1085
}
 
1086
 
 
1087
#ifdef NSS_3_4_CODE
 
1088
static PRStatus
 
1089
issuer_and_serial_from_encoding (
 
1090
  NSSBER *encoding, 
 
1091
  NSSDER *issuer, 
 
1092
  NSSDER *serial
 
1093
)
 
1094
{
 
1095
    SECItem derCert, derIssuer, derSerial;
 
1096
    SECStatus secrv;
 
1097
    derCert.data = (unsigned char *)encoding->data;
 
1098
    derCert.len = encoding->size;
 
1099
    secrv = CERT_IssuerNameFromDERCert(&derCert, &derIssuer);
 
1100
    if (secrv != SECSuccess) {
 
1101
        return PR_FAILURE;
 
1102
    }
 
1103
    secrv = CERT_SerialNumberFromDERCert(&derCert, &derSerial);
 
1104
    if (secrv != SECSuccess) {
 
1105
        return PR_FAILURE;
 
1106
    }
 
1107
    issuer->data = derIssuer.data;
 
1108
    issuer->size = derIssuer.len;
 
1109
    serial->data = derSerial.data;
 
1110
    serial->size = derSerial.len;
 
1111
    return PR_SUCCESS;
 
1112
}
 
1113
#endif
 
1114
 
 
1115
/*
 
1116
 * Look for a specific cert in the cache
 
1117
 */
 
1118
NSS_IMPLEMENT NSSCertificate *
 
1119
nssTrustDomain_GetCertByDERFromCache (
 
1120
  NSSTrustDomain *td,
 
1121
  NSSDER *der
 
1122
)
 
1123
{
 
1124
    PRStatus nssrv = PR_FAILURE;
 
1125
    NSSDER issuer, serial;
 
1126
    NSSCertificate *rvCert;
 
1127
#ifdef NSS_3_4_CODE
 
1128
    nssrv = issuer_and_serial_from_encoding(der, &issuer, &serial);
 
1129
#endif
 
1130
    if (nssrv != PR_SUCCESS) {
 
1131
        return NULL;
 
1132
    }
 
1133
#ifdef DEBUG_CACHE
 
1134
    log_item_dump("looking for cert by DER", der);
 
1135
#endif
 
1136
    rvCert = nssTrustDomain_GetCertForIssuerAndSNFromCache(td, 
 
1137
                                                           &issuer, &serial);
 
1138
#ifdef NSS_3_4_CODE
 
1139
    PORT_Free(issuer.data);
 
1140
    PORT_Free(serial.data);
 
1141
#endif
 
1142
    return rvCert;
 
1143
}
 
1144
 
 
1145
static void cert_iter(const void *k, void *v, void *a)
 
1146
{
 
1147
    nssList *certList = (nssList *)a;
 
1148
    NSSCertificate *c = (NSSCertificate *)k;
 
1149
    nssList_Add(certList, nssCertificate_AddRef(c));
 
1150
}
 
1151
 
 
1152
NSS_EXTERN NSSCertificate **
 
1153
nssTrustDomain_GetCertsFromCache (
 
1154
  NSSTrustDomain *td,
 
1155
  nssList *certListOpt
 
1156
)
 
1157
{
 
1158
    NSSCertificate **rvArray = NULL;
 
1159
    nssList *certList;
 
1160
    if (certListOpt) {
 
1161
        certList = certListOpt;
 
1162
    } else {
 
1163
        certList = nssList_Create(NULL, PR_FALSE);
 
1164
    }
 
1165
    PZ_Lock(td->cache->lock);
 
1166
    nssHash_Iterate(td->cache->issuerAndSN, cert_iter, (void *)certList);
 
1167
    PZ_Unlock(td->cache->lock);
 
1168
    if (!certListOpt) {
 
1169
        PRUint32 count = nssList_Count(certList);
 
1170
        rvArray = nss_ZNEWARRAY(NULL, NSSCertificate *, count);
 
1171
        nssList_GetArray(certList, (void **)rvArray, count);
 
1172
        /* array takes the references */
 
1173
        nssList_Destroy(certList);
 
1174
    }
 
1175
    return rvArray;
 
1176
}
 
1177
 
 
1178
NSS_IMPLEMENT void
 
1179
nssTrustDomain_DumpCacheInfo (
 
1180
  NSSTrustDomain *td,
 
1181
  void (* cert_dump_iter)(const void *, void *, void *),
 
1182
  void *arg
 
1183
)
 
1184
{
 
1185
    PZ_Lock(td->cache->lock);
 
1186
    nssHash_Iterate(td->cache->issuerAndSN, cert_dump_iter, arg);
 
1187
    PZ_Unlock(td->cache->lock);
 
1188
}