Coverage Report

Created: 2024-11-21 07:03

/src/nss-nspr/nss/lib/certdb/crl.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
/*
6
 * Moved from secpkcs7.c
7
 */
8
9
#include "cert.h"
10
#include "certi.h"
11
#include "secder.h"
12
#include "secasn1.h"
13
#include "secoid.h"
14
#include "certdb.h"
15
#include "certxutl.h"
16
#include "prtime.h"
17
#include "secerr.h"
18
#include "pk11func.h"
19
#include "dev.h"
20
#include "dev3hack.h"
21
#include "nssbase.h"
22
#if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
23
#include "nssrwlk.h"
24
#endif
25
#include "pk11priv.h"
26
27
const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
28
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCertExtension) },
29
    { SEC_ASN1_OBJECT_ID, offsetof(CERTCertExtension, id) },
30
    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN, /* XXX DER_DEFAULT */
31
      offsetof(CERTCertExtension, critical) },
32
    { SEC_ASN1_OCTET_STRING, offsetof(CERTCertExtension, value) },
33
    { 0 }
34
};
35
36
static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
37
    { SEC_ASN1_SEQUENCE_OF, 0, SEC_CERTExtensionTemplate }
38
};
39
40
/*
41
 * XXX Also, these templates need to be tested; Lisa did the obvious
42
 * translation but they still should be verified.
43
 */
44
45
const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
46
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTIssuerAndSN) },
47
    { SEC_ASN1_SAVE, offsetof(CERTIssuerAndSN, derIssuer) },
48
    { SEC_ASN1_INLINE, offsetof(CERTIssuerAndSN, issuer), CERT_NameTemplate },
49
    { SEC_ASN1_INTEGER, offsetof(CERTIssuerAndSN, serialNumber) },
50
    { 0 }
51
};
52
53
SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
54
SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
55
56
static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
57
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrlKey) },
58
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey, dummy) },
59
    { SEC_ASN1_SKIP },
60
    { SEC_ASN1_ANY, offsetof(CERTCrlKey, derName) },
61
    { SEC_ASN1_SKIP_REST },
62
    { 0 }
63
};
64
65
static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
66
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrlEntry) },
67
    { SEC_ASN1_INTEGER, offsetof(CERTCrlEntry, serialNumber) },
68
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrlEntry, revocationDate),
69
      SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
70
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
71
      offsetof(CERTCrlEntry, extensions), SEC_CERTExtensionTemplate },
72
    { 0 }
73
};
74
75
const SEC_ASN1Template CERT_CrlTemplate[] = {
76
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) },
77
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrl, version) },
78
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, signatureAlg),
79
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
80
    { SEC_ASN1_SAVE, offsetof(CERTCrl, derName) },
81
    { SEC_ASN1_INLINE, offsetof(CERTCrl, name), CERT_NameTemplate },
82
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, lastUpdate),
83
      SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
84
    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
85
      offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
86
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF, offsetof(CERTCrl, entries),
87
      cert_CrlEntryTemplate },
88
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
89
          SEC_ASN1_EXPLICIT | 0,
90
      offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate },
91
    { 0 }
92
};
93
94
const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
95
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) },
96
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrl, version) },
97
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, signatureAlg),
98
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
99
    { SEC_ASN1_SAVE, offsetof(CERTCrl, derName) },
100
    { SEC_ASN1_INLINE, offsetof(CERTCrl, name), CERT_NameTemplate },
101
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN, offsetof(CERTCrl, lastUpdate),
102
      SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
103
    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
104
      offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
105
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
106
      SEC_ASN1_SKIP }, /* skip entries */
107
    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
108
          SEC_ASN1_EXPLICIT | 0,
109
      offsetof(CERTCrl, extensions), SEC_CERTExtensionsTemplate },
110
    { 0 }
111
};
112
113
const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
114
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTCrl) },
115
    { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
116
    { SEC_ASN1_SKIP },
117
    { SEC_ASN1_SKIP },
118
    { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_XTRN,
119
      offsetof(CERTCrl, lastUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
120
    { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
121
      offsetof(CERTCrl, nextUpdate), SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
122
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF, offsetof(CERTCrl, entries),
123
      cert_CrlEntryTemplate }, /* decode entries */
124
    { SEC_ASN1_SKIP_REST },
125
    { 0 }
126
};
127
128
const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
129
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTSignedCrl) },
130
    { SEC_ASN1_SAVE, offsetof(CERTSignedCrl, signatureWrap.data) },
131
    { SEC_ASN1_INLINE, offsetof(CERTSignedCrl, crl), CERT_CrlTemplate },
132
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
133
      offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm),
134
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
135
    { SEC_ASN1_BIT_STRING, offsetof(CERTSignedCrl, signatureWrap.signature) },
136
    { 0 }
137
};
138
139
static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
140
    { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(CERTSignedCrl) },
141
    { SEC_ASN1_SAVE, offsetof(CERTSignedCrl, signatureWrap.data) },
142
    { SEC_ASN1_INLINE, offsetof(CERTSignedCrl, crl),
143
      CERT_CrlTemplateNoEntries },
144
    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
145
      offsetof(CERTSignedCrl, signatureWrap.signatureAlgorithm),
146
      SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
147
    { SEC_ASN1_BIT_STRING, offsetof(CERTSignedCrl, signatureWrap.signature) },
148
    { 0 }
149
};
150
151
const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
152
    { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
153
};
154
155
/* get CRL version */
156
int
157
cert_get_crl_version(CERTCrl* crl)
158
0
{
159
    /* CRL version is defaulted to v1 */
160
0
    int version = SEC_CRL_VERSION_1;
161
0
    if (crl && crl->version.data != 0) {
162
0
        version = (int)DER_GetUInteger(&crl->version);
163
0
    }
164
0
    return version;
165
0
}
166
167
/* check the entries in the CRL */
168
SECStatus
169
cert_check_crl_entries(CERTCrl* crl)
170
0
{
171
0
    CERTCrlEntry** entries;
172
0
    CERTCrlEntry* entry;
173
0
    PRBool hasCriticalExten = PR_FALSE;
174
0
    SECStatus rv = SECSuccess;
175
176
0
    if (!crl) {
177
0
        return SECFailure;
178
0
    }
179
180
0
    if (crl->entries == NULL) {
181
        /* CRLs with no entries are valid */
182
0
        return (SECSuccess);
183
0
    }
184
185
    /* Look in the crl entry extensions.  If there is a critical extension,
186
       then the crl version must be v2; otherwise, it should be v1.
187
     */
188
0
    entries = crl->entries;
189
0
    while (*entries) {
190
0
        entry = *entries;
191
0
        if (entry->extensions) {
192
            /* If there is a critical extension in the entries, then the
193
               CRL must be of version 2.  If we already saw a critical
194
               extension,
195
               there is no need to check the version again.
196
            */
197
0
            if (hasCriticalExten == PR_FALSE) {
198
0
                hasCriticalExten = cert_HasCriticalExtension(entry->extensions);
199
0
                if (hasCriticalExten) {
200
0
                    if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) {
201
                        /* only CRL v2 critical extensions are supported */
202
0
                        PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
203
0
                        rv = SECFailure;
204
0
                        break;
205
0
                    }
206
0
                }
207
0
            }
208
209
            /* For each entry, make sure that it does not contain an unknown
210
               critical extension.  If it does, we must reject the CRL since
211
               we don't know how to process the extension.
212
            */
213
0
            if (cert_HasUnknownCriticalExten(entry->extensions) == PR_TRUE) {
214
0
                PORT_SetError(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
215
0
                rv = SECFailure;
216
0
                break;
217
0
            }
218
0
        }
219
0
        ++entries;
220
0
    }
221
0
    return (rv);
222
0
}
223
224
/* Check the version of the CRL.  If there is a critical extension in the crl
225
   or crl entry, then the version must be v2. Otherwise, it should be v1. If
226
   the crl contains critical extension(s), then we must recognized the
227
   extension's OID.
228
   */
229
SECStatus
230
cert_check_crl_version(CERTCrl* crl)
231
0
{
232
0
    PRBool hasCriticalExten = PR_FALSE;
233
0
    int version = cert_get_crl_version(crl);
234
235
0
    if (version > SEC_CRL_VERSION_2) {
236
0
        PORT_SetError(SEC_ERROR_CRL_INVALID_VERSION);
237
0
        return (SECFailure);
238
0
    }
239
240
    /* Check the crl extensions for a critial extension.  If one is found,
241
       and the version is not v2, then we are done.
242
     */
243
0
    if (crl->extensions) {
244
0
        hasCriticalExten = cert_HasCriticalExtension(crl->extensions);
245
0
        if (hasCriticalExten) {
246
0
            if (version != SEC_CRL_VERSION_2) {
247
                /* only CRL v2 critical extensions are supported */
248
0
                PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
249
0
                return (SECFailure);
250
0
            }
251
            /* make sure that there is no unknown critical extension */
252
0
            if (cert_HasUnknownCriticalExten(crl->extensions) == PR_TRUE) {
253
0
                PORT_SetError(SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
254
0
                return (SECFailure);
255
0
            }
256
0
        }
257
0
    }
258
259
0
    return (SECSuccess);
260
0
}
261
262
/*
263
 * Generate a database key, based on the issuer name from a
264
 * DER crl.
265
 */
266
SECStatus
267
CERT_KeyFromDERCrl(PLArenaPool* arena, SECItem* derCrl, SECItem* key)
268
0
{
269
0
    SECStatus rv;
270
0
    CERTSignedData sd;
271
0
    CERTCrlKey crlkey;
272
0
    PLArenaPool* myArena;
273
274
0
    if (!arena) {
275
        /* arena needed for QuickDER */
276
0
        myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
277
0
    } else {
278
0
        myArena = arena;
279
0
    }
280
0
    PORT_Memset(&sd, 0, sizeof(sd));
281
0
    rv = SEC_QuickDERDecodeItem(myArena, &sd, CERT_SignedDataTemplate, derCrl);
282
0
    if (SECSuccess == rv) {
283
0
        PORT_Memset(&crlkey, 0, sizeof(crlkey));
284
0
        rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate,
285
0
                                    &sd.data);
286
0
    }
287
288
    /* make a copy so the data doesn't point to memory inside derCrl, which
289
       may be temporary */
290
0
    if (SECSuccess == rv) {
291
0
        rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
292
0
    }
293
294
0
    if (myArena != arena) {
295
0
        PORT_FreeArena(myArena, PR_FALSE);
296
0
    }
297
298
0
    return rv;
299
0
}
300
301
0
#define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
302
303
SECStatus
304
CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
305
0
{
306
0
    SECStatus rv = SECSuccess;
307
0
    SECItem* crldata = NULL;
308
0
    OpaqueCRLFields* extended = NULL;
309
310
0
    if ((!crl) || (!(extended = (OpaqueCRLFields*)crl->opaque)) ||
311
0
        (PR_TRUE == extended->decodingError)) {
312
0
        rv = SECFailure;
313
0
    } else {
314
0
        if (PR_FALSE == extended->partial) {
315
            /* the CRL has already been fully decoded */
316
0
            return SECSuccess;
317
0
        }
318
0
        if (PR_TRUE == extended->badEntries) {
319
            /* the entries decoding already failed */
320
0
            return SECFailure;
321
0
        }
322
0
        crldata = &crl->signatureWrap.data;
323
0
        if (!crldata) {
324
0
            rv = SECFailure;
325
0
        }
326
0
    }
327
328
0
    if (SECSuccess == rv) {
329
0
        rv = SEC_QuickDERDecodeItem(crl->arena, &crl->crl,
330
0
                                    CERT_CrlTemplateEntriesOnly, crldata);
331
0
        if (SECSuccess == rv) {
332
0
            extended->partial = PR_FALSE; /* successful decode, avoid
333
                decoding again */
334
0
        } else {
335
0
            extended->decodingError = PR_TRUE;
336
0
            extended->badEntries = PR_TRUE;
337
            /* cache the decoding failure. If it fails the first time,
338
               it will fail again, which will grow the arena and leak
339
               memory, so we want to avoid it */
340
0
        }
341
0
        rv = cert_check_crl_entries(&crl->crl);
342
0
        if (rv != SECSuccess) {
343
0
            extended->badExtensions = PR_TRUE;
344
0
        }
345
0
    }
346
0
    return rv;
347
0
}
348
349
/*
350
 * take a DER CRL and decode it into a CRL structure
351
 * allow reusing the input DER without making a copy
352
 */
353
CERTSignedCrl*
354
CERT_DecodeDERCrlWithFlags(PLArenaPool* narena, SECItem* derSignedCrl, int type,
355
                           PRInt32 options)
356
0
{
357
0
    PLArenaPool* arena;
358
0
    CERTSignedCrl* crl;
359
0
    SECStatus rv;
360
0
    OpaqueCRLFields* extended = NULL;
361
0
    const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
362
0
    PRInt32 testOptions = options;
363
364
0
    PORT_Assert(derSignedCrl);
365
0
    if (!derSignedCrl) {
366
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
367
0
        return NULL;
368
0
    }
369
370
    /* Adopting DER requires not copying it.  Code that sets ADOPT flag
371
     * but doesn't set DONT_COPY probably doesn't know What it is doing.
372
     * That condition is a programming error in the caller.
373
     */
374
0
    testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
375
0
    PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
376
0
    if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
377
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
378
0
        return NULL;
379
0
    }
380
381
    /* make a new arena if needed */
382
0
    if (narena == NULL) {
383
0
        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
384
0
        if (!arena) {
385
0
            return NULL;
386
0
        }
387
0
    } else {
388
0
        arena = narena;
389
0
    }
390
391
    /* allocate the CRL structure */
392
0
    crl = (CERTSignedCrl*)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
393
0
    if (!crl) {
394
0
        PORT_SetError(SEC_ERROR_NO_MEMORY);
395
0
        goto loser;
396
0
    }
397
398
0
    crl->arena = arena;
399
400
    /* allocate opaque fields */
401
0
    crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
402
0
    if (!crl->opaque) {
403
0
        goto loser;
404
0
    }
405
0
    extended = (OpaqueCRLFields*)crl->opaque;
406
0
    if (options & CRL_DECODE_ADOPT_HEAP_DER) {
407
0
        extended->heapDER = PR_TRUE;
408
0
    }
409
0
    if (options & CRL_DECODE_DONT_COPY_DER) {
410
0
        crl->derCrl = derSignedCrl; /* DER is not copied . The application
411
                                       must keep derSignedCrl until it
412
                                       destroys the CRL */
413
0
    } else {
414
0
        crl->derCrl = (SECItem*)PORT_ArenaZAlloc(arena, sizeof(SECItem));
415
0
        if (crl->derCrl == NULL) {
416
0
            goto loser;
417
0
        }
418
0
        rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
419
0
        if (rv != SECSuccess) {
420
0
            goto loser;
421
0
        }
422
0
    }
423
424
    /* Save the arena in the inner crl for CRL extensions support */
425
0
    crl->crl.arena = arena;
426
0
    if (options & CRL_DECODE_SKIP_ENTRIES) {
427
0
        crlTemplate = cert_SignedCrlTemplateNoEntries;
428
0
        extended->partial = PR_TRUE;
429
0
    }
430
431
    /* decode the CRL info */
432
0
    switch (type) {
433
0
        case SEC_CRL_TYPE:
434
0
            rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
435
0
            if (rv != SECSuccess) {
436
0
                extended->badDER = PR_TRUE;
437
0
                break;
438
0
            }
439
            /* check for critical extensions */
440
0
            rv = cert_check_crl_version(&crl->crl);
441
0
            if (rv != SECSuccess) {
442
0
                extended->badExtensions = PR_TRUE;
443
0
                break;
444
0
            }
445
446
0
            if (PR_TRUE == extended->partial) {
447
                /* partial decoding, don't verify entries */
448
0
                break;
449
0
            }
450
451
0
            rv = cert_check_crl_entries(&crl->crl);
452
0
            if (rv != SECSuccess) {
453
0
                extended->badExtensions = PR_TRUE;
454
0
            }
455
456
0
            break;
457
458
0
        default:
459
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
460
0
            rv = SECFailure;
461
0
            break;
462
0
    }
463
464
0
    if (rv != SECSuccess) {
465
0
        goto loser;
466
0
    }
467
468
0
    crl->referenceCount = 1;
469
470
0
    return (crl);
471
472
0
loser:
473
0
    if (options & CRL_DECODE_KEEP_BAD_CRL) {
474
0
        if (extended) {
475
0
            extended->decodingError = PR_TRUE;
476
0
        }
477
0
        if (crl) {
478
0
            crl->referenceCount = 1;
479
0
            return (crl);
480
0
        }
481
0
    }
482
483
0
    if ((narena == NULL) && arena) {
484
0
        PORT_FreeArena(arena, PR_FALSE);
485
0
    }
486
487
0
    return (0);
488
0
}
489
490
/*
491
 * take a DER CRL and decode it into a CRL structure
492
 */
493
CERTSignedCrl*
494
CERT_DecodeDERCrl(PLArenaPool* narena, SECItem* derSignedCrl, int type)
495
0
{
496
0
    return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
497
0
                                      CRL_DECODE_DEFAULT_OPTIONS);
498
0
}
499
500
/*
501
 * Lookup a CRL in the databases. We mirror the same fast caching data base
502
 *  caching stuff used by certificates....?
503
 * return values :
504
 *
505
 * SECSuccess means we got a valid decodable DER CRL, or no CRL at all.
506
 * Caller may distinguish those cases by the value returned in "decoded".
507
 * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
508
 *
509
 * SECFailure means we got a fatal error - most likely, we found a CRL,
510
 * and it failed decoding, or there was an out of memory error. Do NOT ignore
511
 * it and specifically do NOT treat it the same as having no CRL, as this
512
 * can compromise security !!! Ideally, you should treat this case as if you
513
 * received a "catch-all" CRL where all certs you were looking up are
514
 * considered to be revoked
515
 */
516
static SECStatus
517
SEC_FindCrlByKeyOnSlot(PK11SlotInfo* slot, SECItem* crlKey, int type,
518
                       CERTSignedCrl** decoded, PRInt32 decodeoptions)
519
0
{
520
0
    SECStatus rv = SECSuccess;
521
0
    CERTSignedCrl* crl = NULL;
522
0
    SECItem* derCrl = NULL;
523
0
    CK_OBJECT_HANDLE crlHandle = 0;
524
0
    char* url = NULL;
525
526
0
    PORT_Assert(decoded);
527
0
    if (!decoded) {
528
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
529
0
        return SECFailure;
530
0
    }
531
532
0
    derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
533
0
    if (derCrl == NULL) {
534
        /* if we had a problem other than the CRL just didn't exist, return
535
         * a failure to the upper level */
536
0
        int nsserror = PORT_GetError();
537
0
        if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
538
0
            rv = SECFailure;
539
0
        }
540
0
        goto loser;
541
0
    }
542
0
    PORT_Assert(crlHandle != CK_INVALID_HANDLE);
543
    /* PK11_FindCrlByName obtained a slot reference. */
544
545
    /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
546
       Force adoption of the DER CRL from the heap - this will cause it
547
       to be automatically freed when SEC_DestroyCrl is invoked */
548
0
    decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
549
550
0
    crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
551
0
    if (crl) {
552
0
        crl->slot = slot;
553
0
        slot = NULL;   /* adopt it */
554
0
        derCrl = NULL; /* adopted by the crl struct */
555
0
        crl->pkcs11ID = crlHandle;
556
0
        if (url) {
557
0
            crl->url = PORT_ArenaStrdup(crl->arena, url);
558
0
        }
559
0
    } else {
560
0
        rv = SECFailure;
561
0
    }
562
563
0
    if (url) {
564
0
        PORT_Free(url);
565
0
    }
566
567
0
    if (slot) {
568
0
        PK11_FreeSlot(slot);
569
0
    }
570
571
0
loser:
572
0
    if (derCrl) {
573
0
        SECITEM_FreeItem(derCrl, PR_TRUE);
574
0
    }
575
576
0
    *decoded = crl;
577
578
0
    return rv;
579
0
}
580
581
CERTSignedCrl*
582
crl_storeCRL(PK11SlotInfo* slot, char* url, CERTSignedCrl* newCrl,
583
             SECItem* derCrl, int type)
584
0
{
585
0
    CERTSignedCrl *oldCrl = NULL, *crl = NULL;
586
0
    PRBool deleteOldCrl = PR_FALSE;
587
0
    CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
588
589
0
    PORT_Assert(newCrl);
590
0
    PORT_Assert(derCrl);
591
0
    PORT_Assert(type == SEC_CRL_TYPE);
592
593
0
    if (type != SEC_CRL_TYPE) {
594
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
595
0
        return NULL;
596
0
    }
597
598
    /* we can't use the cache here because we must look in the same
599
       token */
600
0
    (void)SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type, &oldCrl,
601
0
                                 CRL_DECODE_SKIP_ENTRIES);
602
    /* if there is an old crl on the token, make sure the one we are
603
       installing is newer. If not, exit out, otherwise delete the
604
       old crl.
605
     */
606
0
    if (oldCrl != NULL) {
607
        /* if it's already there, quietly continue */
608
0
        if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) == SECEqual) {
609
0
            crl = newCrl;
610
0
            crl->slot = PK11_ReferenceSlot(slot);
611
0
            crl->pkcs11ID = oldCrl->pkcs11ID;
612
0
            if (oldCrl->url && !url)
613
0
                url = oldCrl->url;
614
0
            if (url)
615
0
                crl->url = PORT_ArenaStrdup(crl->arena, url);
616
0
            goto done;
617
0
        }
618
0
        if (!SEC_CrlIsNewer(&newCrl->crl, &oldCrl->crl)) {
619
0
            PORT_SetError(SEC_ERROR_OLD_CRL);
620
0
            goto done;
621
0
        }
622
623
        /* if we have a url in the database, use that one */
624
0
        if (oldCrl->url && !url) {
625
0
            url = oldCrl->url;
626
0
        }
627
628
        /* really destroy this crl */
629
        /* first drum it out of the permanment Data base */
630
0
        deleteOldCrl = PR_TRUE;
631
0
    }
632
633
    /* invalidate CRL cache for this issuer */
634
0
    CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
635
    /* Write the new entry into the data base */
636
0
    crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
637
0
    if (crlHandle != CK_INVALID_HANDLE) {
638
0
        crl = newCrl;
639
0
        crl->slot = PK11_ReferenceSlot(slot);
640
0
        crl->pkcs11ID = crlHandle;
641
0
        if (url) {
642
0
            crl->url = PORT_ArenaStrdup(crl->arena, url);
643
0
        }
644
0
    }
645
646
0
done:
647
0
    if (oldCrl) {
648
0
        if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
649
0
            SEC_DeletePermCRL(oldCrl);
650
0
        }
651
0
        SEC_DestroyCrl(oldCrl);
652
0
    }
653
654
0
    return crl;
655
0
}
656
657
/*
658
 *
659
 * create a new CRL from DER material.
660
 *
661
 * The signature on this CRL must be checked before you
662
 * load it. ???
663
 */
664
CERTSignedCrl*
665
SEC_NewCrl(CERTCertDBHandle* handle, char* url, SECItem* derCrl, int type)
666
0
{
667
0
    CERTSignedCrl* retCrl = NULL;
668
0
    PK11SlotInfo* slot = PK11_GetInternalKeySlot();
669
0
    retCrl =
670
0
        PK11_ImportCRL(slot, derCrl, url, type, NULL, CRL_IMPORT_BYPASS_CHECKS,
671
0
                       NULL, CRL_DECODE_DEFAULT_OPTIONS);
672
0
    PK11_FreeSlot(slot);
673
674
0
    return retCrl;
675
0
}
676
677
CERTSignedCrl*
678
SEC_FindCrlByDERCert(CERTCertDBHandle* handle, SECItem* derCrl, int type)
679
0
{
680
0
    PLArenaPool* arena;
681
0
    SECItem crlKey;
682
0
    SECStatus rv;
683
0
    CERTSignedCrl* crl = NULL;
684
685
    /* create a scratch arena */
686
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
687
0
    if (arena == NULL) {
688
0
        return (NULL);
689
0
    }
690
691
    /* extract the database key from the cert */
692
0
    rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
693
0
    if (rv != SECSuccess) {
694
0
        goto loser;
695
0
    }
696
697
    /* find the crl */
698
0
    crl = SEC_FindCrlByName(handle, &crlKey, type);
699
700
0
loser:
701
0
    PORT_FreeArena(arena, PR_FALSE);
702
0
    return (crl);
703
0
}
704
705
CERTSignedCrl*
706
SEC_DupCrl(CERTSignedCrl* acrl)
707
0
{
708
0
    if (acrl) {
709
0
        PR_ATOMIC_INCREMENT(&acrl->referenceCount);
710
0
        return acrl;
711
0
    }
712
0
    return NULL;
713
0
}
714
715
SECStatus
716
SEC_DestroyCrl(CERTSignedCrl* crl)
717
0
{
718
0
    if (crl) {
719
0
        if (PR_ATOMIC_DECREMENT(&crl->referenceCount) < 1) {
720
0
            if (crl->slot) {
721
0
                PK11_FreeSlot(crl->slot);
722
0
            }
723
0
            if (GetOpaqueCRLFields(crl) &&
724
0
                PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
725
0
                SECITEM_FreeItem(crl->derCrl, PR_TRUE);
726
0
            }
727
0
            if (crl->arena) {
728
0
                PORT_FreeArena(crl->arena, PR_FALSE);
729
0
            }
730
0
        }
731
0
        return SECSuccess;
732
0
    } else {
733
0
        return SECFailure;
734
0
    }
735
0
}
736
737
SECStatus
738
SEC_LookupCrls(CERTCertDBHandle* handle, CERTCrlHeadNode** nodes, int type)
739
0
{
740
0
    CERTCrlHeadNode* head;
741
0
    PLArenaPool* arena = NULL;
742
0
    SECStatus rv;
743
744
0
    *nodes = NULL;
745
746
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
747
0
    if (arena == NULL) {
748
0
        return SECFailure;
749
0
    }
750
751
    /* build a head structure */
752
0
    head = (CERTCrlHeadNode*)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
753
0
    head->arena = arena;
754
0
    head->first = NULL;
755
0
    head->last = NULL;
756
0
    head->dbhandle = handle;
757
758
    /* Look up the proper crl types */
759
0
    *nodes = head;
760
761
0
    rv = PK11_LookupCrls(head, type, NULL);
762
763
0
    if (rv != SECSuccess) {
764
0
        if (arena) {
765
0
            PORT_FreeArena(arena, PR_FALSE);
766
0
            *nodes = NULL;
767
0
        }
768
0
    }
769
770
0
    return rv;
771
0
}
772
773
/* These functions simply return the address of the above-declared templates.
774
** This is necessary for Windows DLLs.  Sigh.
775
*/
776
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
777
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
778
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
779
SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
780
781
/* CRL cache code starts here */
782
783
/* constructor */
784
static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
785
                                  CRLOrigin origin);
786
/* destructor */
787
static SECStatus CachedCrl_Destroy(CachedCrl* crl);
788
789
/* create hash table of CRL entries */
790
static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
791
792
/* empty the cache content */
793
static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
794
795
/* are these CRLs the same, as far as the cache is concerned ?
796
   Or are they the same token object, but with different DER ? */
797
798
static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
799
                                   PRBool* isUpdated);
800
801
/* create a DPCache object */
802
static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
803
                                const SECItem* subject, SECItem* dp);
804
805
/* destructor for CRL DPCache object */
806
static SECStatus DPCache_Destroy(CRLDPCache* cache);
807
808
/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
809
   returns the cached CRL object . Needs write access to DPCache. */
810
static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
811
                                PRBool* added);
812
813
/* fetch the CRL for this DP from the PKCS#11 tokens */
814
static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
815
                                         void* wincx);
816
817
/* update the content of the CRL cache, including fetching of CRLs, and
818
   reprocessing with specified issuer and date */
819
static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
820
                                     PRBool readlocked, PRTime vfdate,
821
                                     void* wincx);
822
823
/* returns true if there are CRLs from PKCS#11 slots */
824
static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
825
826
/* remove CRL at offset specified */
827
static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
828
829
/* Pick best CRL to use . needs write access */
830
static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
831
832
/* create an issuer cache object (per CA subject ) */
833
static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
834
                                    CERTCertificate* issuer,
835
                                    const SECItem* subject, const SECItem* dp);
836
837
/* destructor for CRL IssuerCache object */
838
SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
839
840
/* add a DPCache to the issuer cache */
841
static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
842
                                   CERTCertificate* issuer,
843
                                   const SECItem* subject, const SECItem* dp,
844
                                   CRLDPCache** newdpc);
845
846
/* get a particular DPCache object from an IssuerCache */
847
static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache,
848
                                          const SECItem* dp);
849
850
/*
851
** Pre-allocator hash allocator ops.
852
*/
853
854
/* allocate memory for hash table */
855
static void* PR_CALLBACK
856
PreAllocTable(void* pool, PRSize size)
857
0
{
858
0
    PreAllocator* alloc = (PreAllocator*)pool;
859
0
    PORT_Assert(alloc);
860
0
    if (!alloc) {
861
        /* no allocator, or buffer full */
862
0
        return NULL;
863
0
    }
864
0
    if (size > (alloc->len - alloc->used)) {
865
        /* initial buffer full, let's use the arena */
866
0
        alloc->extra += size;
867
0
        return PORT_ArenaAlloc(alloc->arena, size);
868
0
    }
869
    /* use the initial buffer */
870
0
    alloc->used += size;
871
0
    return (char*)alloc->data + alloc->used - size;
872
0
}
873
874
/* free hash table memory.
875
   Individual PreAllocator elements cannot be freed, so this is a no-op. */
876
static void PR_CALLBACK
877
PreFreeTable(void* pool, void* item)
878
0
{
879
0
}
880
881
/* allocate memory for hash table */
882
static PLHashEntry* PR_CALLBACK
883
PreAllocEntry(void* pool, const void* key)
884
0
{
885
0
    return PreAllocTable(pool, sizeof(PLHashEntry));
886
0
}
887
888
/* free hash table entry.
889
   Individual PreAllocator elements cannot be freed, so this is a no-op. */
890
static void PR_CALLBACK
891
PreFreeEntry(void* pool, PLHashEntry* he, PRUintn flag)
892
0
{
893
0
}
894
895
/* methods required for PL hash table functions */
896
static PLHashAllocOps preAllocOps = { PreAllocTable, PreFreeTable,
897
                                      PreAllocEntry, PreFreeEntry };
898
899
/* destructor for PreAllocator object */
900
void
901
PreAllocator_Destroy(PreAllocator* allocator)
902
0
{
903
0
    if (!allocator) {
904
0
        return;
905
0
    }
906
0
    if (allocator->arena) {
907
0
        PORT_FreeArena(allocator->arena, PR_TRUE);
908
0
    }
909
0
}
910
911
/* constructor for PreAllocator object */
912
PreAllocator*
913
PreAllocator_Create(PRSize size)
914
0
{
915
0
    PLArenaPool* arena = NULL;
916
0
    PreAllocator* prebuffer = NULL;
917
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
918
0
    if (!arena) {
919
0
        return NULL;
920
0
    }
921
0
    prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena, sizeof(PreAllocator));
922
0
    if (!prebuffer) {
923
0
        PORT_FreeArena(arena, PR_TRUE);
924
0
        return NULL;
925
0
    }
926
0
    prebuffer->arena = arena;
927
928
0
    if (size) {
929
0
        prebuffer->len = size;
930
0
        prebuffer->data = PORT_ArenaAlloc(arena, size);
931
0
        if (!prebuffer->data) {
932
0
            PORT_FreeArena(arena, PR_TRUE);
933
0
            return NULL;
934
0
        }
935
0
    }
936
0
    return prebuffer;
937
0
}
938
939
/* global Named CRL cache object */
940
static NamedCRLCache namedCRLCache = { NULL, NULL };
941
942
/* global CRL cache object */
943
static CRLCache crlcache = { NULL, NULL };
944
945
/* initial state is off */
946
static PRBool crlcache_initialized = PR_FALSE;
947
948
PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
949
    to query the tokens for CRL objects, in order to discover new objects, if
950
    the cache does not contain any token CRLs . In microseconds */
951
952
PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000; /* how often
953
   to query the tokens for CRL objects, in order to discover new objects, if
954
   the cache already contains token CRLs In microseconds */
955
956
PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
957
    if a token CRL object still exists. In microseconds */
958
959
/* this function is called at NSS initialization time */
960
SECStatus
961
InitCRLCache(void)
962
2
{
963
2
    if (PR_FALSE == crlcache_initialized) {
964
2
        PORT_Assert(NULL == crlcache.lock);
965
2
        PORT_Assert(NULL == crlcache.issuers);
966
2
        PORT_Assert(NULL == namedCRLCache.lock);
967
2
        PORT_Assert(NULL == namedCRLCache.entries);
968
2
        if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
969
2
            namedCRLCache.entries) {
970
            /* CRL cache already partially initialized */
971
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
972
0
            return SECFailure;
973
0
        }
974
#ifdef GLOBAL_RWLOCK
975
        crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
976
#else
977
2
        crlcache.lock = PR_NewLock();
978
2
#endif
979
2
        namedCRLCache.lock = PR_NewLock();
980
2
        crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
981
2
                                           PL_CompareValues, NULL, NULL);
982
2
        namedCRLCache.entries = PL_NewHashTable(
983
2
            0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, NULL, NULL);
984
2
        if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
985
2
            !namedCRLCache.entries) {
986
0
            if (crlcache.lock) {
987
#ifdef GLOBAL_RWLOCK
988
                NSSRWLock_Destroy(crlcache.lock);
989
#else
990
0
                PR_DestroyLock(crlcache.lock);
991
0
#endif
992
0
                crlcache.lock = NULL;
993
0
            }
994
0
            if (namedCRLCache.lock) {
995
0
                PR_DestroyLock(namedCRLCache.lock);
996
0
                namedCRLCache.lock = NULL;
997
0
            }
998
0
            if (crlcache.issuers) {
999
0
                PL_HashTableDestroy(crlcache.issuers);
1000
0
                crlcache.issuers = NULL;
1001
0
            }
1002
0
            if (namedCRLCache.entries) {
1003
0
                PL_HashTableDestroy(namedCRLCache.entries);
1004
0
                namedCRLCache.entries = NULL;
1005
0
            }
1006
1007
0
            return SECFailure;
1008
0
        }
1009
2
        crlcache_initialized = PR_TRUE;
1010
2
        return SECSuccess;
1011
2
    } else {
1012
0
        PORT_Assert(crlcache.lock);
1013
0
        PORT_Assert(crlcache.issuers);
1014
0
        if ((NULL == crlcache.lock) || (NULL == crlcache.issuers)) {
1015
            /* CRL cache not fully initialized */
1016
0
            return SECFailure;
1017
0
        } else {
1018
            /* CRL cache already initialized */
1019
0
            return SECSuccess;
1020
0
        }
1021
0
    }
1022
2
}
1023
1024
/* destructor for CRL DPCache object */
1025
static SECStatus
1026
DPCache_Destroy(CRLDPCache* cache)
1027
0
{
1028
0
    PRUint32 i = 0;
1029
0
    PORT_Assert(cache);
1030
0
    if (!cache) {
1031
0
        PORT_Assert(0);
1032
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1033
0
        return SECFailure;
1034
0
    }
1035
0
    if (cache->lock) {
1036
0
#ifdef DPC_RWLOCK
1037
0
        NSSRWLock_Destroy(cache->lock);
1038
#else
1039
        PR_DestroyLock(cache->lock);
1040
#endif
1041
0
    } else {
1042
0
        PORT_Assert(0);
1043
0
        return SECFailure;
1044
0
    }
1045
    /* destroy all our CRL objects */
1046
0
    for (i = 0; i < cache->ncrls; i++) {
1047
0
        if (!cache->crls || !cache->crls[i] ||
1048
0
            SECSuccess != CachedCrl_Destroy(cache->crls[i])) {
1049
0
            return SECFailure;
1050
0
        }
1051
0
    }
1052
    /* free the array of CRLs */
1053
0
    if (cache->crls) {
1054
0
        PORT_Free(cache->crls);
1055
0
    }
1056
    /* destroy the cert */
1057
0
    if (cache->issuerDERCert) {
1058
0
        SECITEM_FreeItem(cache->issuerDERCert, PR_TRUE);
1059
0
    }
1060
    /* free the subject */
1061
0
    if (cache->subject) {
1062
0
        SECITEM_FreeItem(cache->subject, PR_TRUE);
1063
0
    }
1064
    /* free the distribution points */
1065
0
    if (cache->distributionPoint) {
1066
0
        SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
1067
0
    }
1068
0
    PORT_Free(cache);
1069
0
    return SECSuccess;
1070
0
}
1071
1072
/* destructor for CRL IssuerCache object */
1073
SECStatus
1074
IssuerCache_Destroy(CRLIssuerCache* cache)
1075
0
{
1076
0
    PORT_Assert(cache);
1077
0
    if (!cache) {
1078
0
        PORT_Assert(0);
1079
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1080
0
        return SECFailure;
1081
0
    }
1082
#ifdef XCRL
1083
    if (cache->lock) {
1084
        NSSRWLock_Destroy(cache->lock);
1085
    } else {
1086
        PORT_Assert(0);
1087
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1088
        return SECFailure;
1089
    }
1090
    if (cache->issuer) {
1091
        CERT_DestroyCertificate(cache->issuer);
1092
    }
1093
#endif
1094
    /* free the subject */
1095
0
    if (cache->subject) {
1096
0
        SECITEM_FreeItem(cache->subject, PR_TRUE);
1097
0
    }
1098
0
    if (SECSuccess != DPCache_Destroy(cache->dpp)) {
1099
0
        PORT_Assert(0);
1100
0
        return SECFailure;
1101
0
    }
1102
0
    PORT_Free(cache);
1103
0
    return SECSuccess;
1104
0
}
1105
1106
/* create a named CRL entry object */
1107
static SECStatus
1108
NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
1109
0
{
1110
0
    NamedCRLCacheEntry* entry = NULL;
1111
0
    if (!returned) {
1112
0
        PORT_Assert(0);
1113
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1114
0
        return SECFailure;
1115
0
    }
1116
0
    *returned = NULL;
1117
0
    entry = (NamedCRLCacheEntry*)PORT_ZAlloc(sizeof(NamedCRLCacheEntry));
1118
0
    if (!entry) {
1119
0
        return SECFailure;
1120
0
    }
1121
0
    *returned = entry;
1122
0
    return SECSuccess;
1123
0
}
1124
1125
/* destroy a named CRL entry object */
1126
static SECStatus
1127
NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
1128
0
{
1129
0
    if (!entry) {
1130
0
        PORT_Assert(0);
1131
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1132
0
        return SECFailure;
1133
0
    }
1134
0
    if (entry->crl) {
1135
        /* named CRL cache owns DER memory */
1136
0
        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
1137
0
    }
1138
0
    if (entry->canonicalizedName) {
1139
0
        SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE);
1140
0
    }
1141
0
    PORT_Free(entry);
1142
0
    return SECSuccess;
1143
0
}
1144
1145
/* callback function used in hash table destructor */
1146
static PRIntn PR_CALLBACK
1147
FreeIssuer(PLHashEntry* he, PRIntn i, void* arg)
1148
0
{
1149
0
    CRLIssuerCache* issuer = NULL;
1150
0
    SECStatus* rv = (SECStatus*)arg;
1151
1152
0
    PORT_Assert(he);
1153
0
    if (!he) {
1154
0
        return HT_ENUMERATE_NEXT;
1155
0
    }
1156
0
    issuer = (CRLIssuerCache*)he->value;
1157
0
    PORT_Assert(issuer);
1158
0
    if (issuer) {
1159
0
        if (SECSuccess != IssuerCache_Destroy(issuer)) {
1160
0
            PORT_Assert(rv);
1161
0
            if (rv) {
1162
0
                *rv = SECFailure;
1163
0
            }
1164
0
            return HT_ENUMERATE_NEXT;
1165
0
        }
1166
0
    }
1167
0
    return HT_ENUMERATE_NEXT;
1168
0
}
1169
1170
/* callback function used in hash table destructor */
1171
static PRIntn PR_CALLBACK
1172
FreeNamedEntries(PLHashEntry* he, PRIntn i, void* arg)
1173
0
{
1174
0
    NamedCRLCacheEntry* entry = NULL;
1175
0
    SECStatus* rv = (SECStatus*)arg;
1176
1177
0
    PORT_Assert(he);
1178
0
    if (!he) {
1179
0
        return HT_ENUMERATE_NEXT;
1180
0
    }
1181
0
    entry = (NamedCRLCacheEntry*)he->value;
1182
0
    PORT_Assert(entry);
1183
0
    if (entry) {
1184
0
        if (SECSuccess != NamedCRLCacheEntry_Destroy(entry)) {
1185
0
            PORT_Assert(rv);
1186
0
            if (rv) {
1187
0
                *rv = SECFailure;
1188
0
            }
1189
0
            return HT_ENUMERATE_NEXT;
1190
0
        }
1191
0
    }
1192
0
    return HT_ENUMERATE_NEXT;
1193
0
}
1194
1195
/* needs to be called at NSS shutdown time
1196
   This will destroy the global CRL cache, including
1197
   - the hash table of issuer cache objects
1198
   - the issuer cache objects
1199
   - DPCache objects in issuer cache objects */
1200
SECStatus
1201
ShutdownCRLCache(void)
1202
0
{
1203
0
    SECStatus rv = SECSuccess;
1204
0
    if (PR_FALSE == crlcache_initialized && !crlcache.lock &&
1205
0
        !crlcache.issuers) {
1206
        /* CRL cache has already been shut down */
1207
0
        return SECSuccess;
1208
0
    }
1209
0
    if (PR_TRUE == crlcache_initialized &&
1210
0
        (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
1211
0
         !namedCRLCache.entries)) {
1212
        /* CRL cache has partially been shut down */
1213
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1214
0
        return SECFailure;
1215
0
    }
1216
    /* empty the CRL cache */
1217
    /* free the issuers */
1218
0
    PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
1219
    /* free the hash table of issuers */
1220
0
    PL_HashTableDestroy(crlcache.issuers);
1221
0
    crlcache.issuers = NULL;
1222
/* free the global lock */
1223
#ifdef GLOBAL_RWLOCK
1224
    NSSRWLock_Destroy(crlcache.lock);
1225
#else
1226
0
    PR_DestroyLock(crlcache.lock);
1227
0
#endif
1228
0
    crlcache.lock = NULL;
1229
1230
    /* empty the named CRL cache. This must be done after freeing the CRL
1231
     * cache, since some CRLs in this cache are in the memory for the other  */
1232
    /* free the entries */
1233
0
    PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
1234
    /* free the hash table of issuers */
1235
0
    PL_HashTableDestroy(namedCRLCache.entries);
1236
0
    namedCRLCache.entries = NULL;
1237
    /* free the global lock */
1238
0
    PR_DestroyLock(namedCRLCache.lock);
1239
0
    namedCRLCache.lock = NULL;
1240
1241
0
    crlcache_initialized = PR_FALSE;
1242
0
    return rv;
1243
0
}
1244
1245
/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
1246
   returns the cached CRL object . Needs write access to DPCache. */
1247
static SECStatus
1248
DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl, PRBool* added)
1249
0
{
1250
0
    CachedCrl** newcrls = NULL;
1251
0
    PRUint32 i = 0;
1252
0
    PORT_Assert(cache);
1253
0
    PORT_Assert(newcrl);
1254
0
    PORT_Assert(added);
1255
0
    if (!cache || !newcrl || !added) {
1256
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1257
0
        return SECFailure;
1258
0
    }
1259
1260
0
    *added = PR_FALSE;
1261
    /* before adding a new CRL, check if it is a duplicate */
1262
0
    for (i = 0; i < cache->ncrls; i++) {
1263
0
        CachedCrl* existing = NULL;
1264
0
        SECStatus rv = SECSuccess;
1265
0
        PRBool dupe = PR_FALSE, updated = PR_FALSE;
1266
0
        if (!cache->crls) {
1267
0
            PORT_Assert(0);
1268
0
            return SECFailure;
1269
0
        }
1270
0
        existing = cache->crls[i];
1271
0
        if (!existing) {
1272
0
            PORT_Assert(0);
1273
0
            return SECFailure;
1274
0
        }
1275
0
        rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
1276
0
        if (SECSuccess != rv) {
1277
0
            PORT_Assert(0);
1278
0
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1279
0
            return SECFailure;
1280
0
        }
1281
0
        if (PR_TRUE == dupe) {
1282
            /* dupe */
1283
0
            PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
1284
0
            return SECSuccess;
1285
0
        }
1286
0
        if (PR_TRUE == updated) {
1287
            /* this token CRL is in the same slot and has the same object ID,
1288
               but different content. We need to remove the old object */
1289
0
            if (SECSuccess != DPCache_RemoveCRL(cache, i)) {
1290
0
                PORT_Assert(0);
1291
0
                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1292
0
                return PR_FALSE;
1293
0
            }
1294
0
        }
1295
0
    }
1296
1297
0
    newcrls = (CachedCrl**)PORT_Realloc(cache->crls, (cache->ncrls + 1) * sizeof(CachedCrl*));
1298
0
    if (!newcrls) {
1299
0
        return SECFailure;
1300
0
    }
1301
0
    cache->crls = newcrls;
1302
0
    cache->ncrls++;
1303
0
    cache->crls[cache->ncrls - 1] = newcrl;
1304
0
    *added = PR_TRUE;
1305
0
    return SECSuccess;
1306
0
}
1307
1308
/* remove CRL at offset specified */
1309
static SECStatus
1310
DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
1311
0
{
1312
0
    CachedCrl* acrl = NULL;
1313
0
    PORT_Assert(cache);
1314
0
    if (!cache || (!cache->crls) || (!(offset < cache->ncrls))) {
1315
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1316
0
        return SECFailure;
1317
0
    }
1318
0
    acrl = cache->crls[offset];
1319
0
    PORT_Assert(acrl);
1320
0
    if (!acrl) {
1321
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1322
0
        return SECFailure;
1323
0
    }
1324
0
    cache->crls[offset] = cache->crls[cache->ncrls - 1];
1325
0
    cache->crls[cache->ncrls - 1] = NULL;
1326
0
    cache->ncrls--;
1327
0
    if (cache->selected == acrl) {
1328
0
        cache->selected = NULL;
1329
0
    }
1330
0
    if (SECSuccess != CachedCrl_Destroy(acrl)) {
1331
0
        PORT_Assert(0);
1332
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1333
0
        return SECFailure;
1334
0
    }
1335
0
    return SECSuccess;
1336
0
}
1337
1338
/* check whether a CRL object stored in a PKCS#11 token still exists in
1339
   that token . This has to be efficient (the entire CRL value cannot be
1340
   transferred accross the token boundaries), so this is accomplished by
1341
   simply fetching the subject attribute and making sure it hasn't changed .
1342
   Note that technically, the CRL object could have been replaced with a new
1343
   PKCS#11 object of the same ID and subject (which actually happens in
1344
   softoken), but this function has no way of knowing that the object
1345
   value changed, since CKA_VALUE isn't checked. */
1346
static PRBool
1347
TokenCRLStillExists(CERTSignedCrl* crl)
1348
0
{
1349
0
    NSSItem newsubject;
1350
0
    SECItem subject;
1351
0
    CK_ULONG crl_class;
1352
0
    PRStatus status;
1353
0
    PK11SlotInfo* slot = NULL;
1354
0
    nssCryptokiObject instance;
1355
0
    NSSArena* arena;
1356
0
    PRBool xstatus = PR_TRUE;
1357
0
    SECItem* oldSubject = NULL;
1358
1359
0
    PORT_Assert(crl);
1360
0
    if (!crl) {
1361
0
        return PR_FALSE;
1362
0
    }
1363
0
    slot = crl->slot;
1364
0
    PORT_Assert(crl->slot);
1365
0
    if (!slot) {
1366
0
        return PR_FALSE;
1367
0
    }
1368
0
    oldSubject = &crl->crl.derName;
1369
0
    PORT_Assert(oldSubject);
1370
0
    if (!oldSubject) {
1371
0
        return PR_FALSE;
1372
0
    }
1373
1374
    /* query subject and type attributes in order to determine if the
1375
       object has been deleted */
1376
1377
    /* first, make an nssCryptokiObject */
1378
0
    instance.handle = crl->pkcs11ID;
1379
0
    PORT_Assert(instance.handle);
1380
0
    if (!instance.handle) {
1381
0
        return PR_FALSE;
1382
0
    }
1383
0
    instance.token = PK11Slot_GetNSSToken(slot);
1384
0
    PORT_Assert(instance.token);
1385
0
    if (!instance.token) {
1386
0
        return PR_FALSE;
1387
0
    }
1388
0
    instance.isTokenObject = PR_TRUE;
1389
0
    instance.label = NULL;
1390
1391
0
    arena = NSSArena_Create();
1392
0
    PORT_Assert(arena);
1393
0
    if (!arena) {
1394
0
        (void)nssToken_Destroy(instance.token);
1395
0
        return PR_FALSE;
1396
0
    }
1397
1398
0
    status =
1399
0
        nssCryptokiCRL_GetAttributes(&instance, NULL,          /* XXX sessionOpt */
1400
0
                                     arena, NULL, &newsubject, /* subject */
1401
0
                                     &crl_class,               /* class */
1402
0
                                     NULL, NULL);
1403
0
    if (PR_SUCCESS == status) {
1404
0
        subject.data = newsubject.data;
1405
0
        subject.len = newsubject.size;
1406
0
        if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual) {
1407
0
            xstatus = PR_FALSE;
1408
0
        }
1409
0
        if (CKO_NSS_CRL != crl_class) {
1410
0
            xstatus = PR_FALSE;
1411
0
        }
1412
0
    } else {
1413
0
        xstatus = PR_FALSE;
1414
0
    }
1415
0
    NSSArena_Destroy(arena);
1416
0
    (void)nssToken_Destroy(instance.token);
1417
0
    return xstatus;
1418
0
}
1419
1420
/* verify the signature of a CRL against its issuer at a given date */
1421
static SECStatus
1422
CERT_VerifyCRL(CERTSignedCrl* crlobject, CERTCertificate* issuer, PRTime vfdate,
1423
               void* wincx)
1424
0
{
1425
0
    return CERT_VerifySignedData(&crlobject->signatureWrap, issuer, vfdate,
1426
0
                                 wincx);
1427
0
}
1428
1429
/* verify a CRL and update cache state */
1430
static SECStatus
1431
CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject, PRTime vfdate,
1432
                 void* wincx)
1433
0
{
1434
    /*  Check if it is an invalid CRL
1435
        if we got a bad CRL, we want to cache it in order to avoid
1436
        subsequent fetches of this same identical bad CRL. We set
1437
        the cache to the invalid state to ensure that all certs on this
1438
        DP are considered to have unknown status from now on. The cache
1439
        object will remain in this state until the bad CRL object
1440
        is removed from the token it was fetched from. If the cause
1441
        of the failure is that we didn't have the issuer cert to
1442
        verify the signature, this state can be cleared when
1443
        the issuer certificate becomes available if that causes the
1444
        signature to verify */
1445
1446
0
    if (!cache || !crlobject) {
1447
0
        PORT_Assert(0);
1448
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1449
0
        return SECFailure;
1450
0
    }
1451
0
    if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError) {
1452
0
        crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
1453
            with bogus DER. Mark it checked so we won't try again */
1454
0
        PORT_SetError(SEC_ERROR_BAD_DER);
1455
0
        return SECSuccess;
1456
0
    } else {
1457
0
        SECStatus signstatus = SECFailure;
1458
0
        if (cache->issuerDERCert) {
1459
0
            CERTCertificate* issuer = CERT_NewTempCertificate(
1460
0
                cache->dbHandle, cache->issuerDERCert, NULL, PR_FALSE, PR_TRUE);
1461
1462
0
            if (issuer) {
1463
0
                signstatus =
1464
0
                    CERT_VerifyCRL(crlobject->crl, issuer, vfdate, wincx);
1465
0
                CERT_DestroyCertificate(issuer);
1466
0
            }
1467
0
        }
1468
0
        if (SECSuccess != signstatus) {
1469
0
            if (!cache->issuerDERCert) {
1470
                /* we tried to verify without an issuer cert . This is
1471
                   because this CRL came through a call to SEC_FindCrlByName.
1472
                   So, we don't cache this verification failure. We'll try
1473
                   to verify the CRL again when a certificate from that issuer
1474
                   becomes available */
1475
0
            } else {
1476
0
                crlobject->sigChecked = PR_TRUE;
1477
0
            }
1478
0
            PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
1479
0
            return SECSuccess;
1480
0
        } else {
1481
0
            crlobject->sigChecked = PR_TRUE;
1482
0
            crlobject->sigValid = PR_TRUE;
1483
0
        }
1484
0
    }
1485
1486
0
    return SECSuccess;
1487
0
}
1488
1489
/* fetch the CRLs for this DP from the PKCS#11 tokens */
1490
static SECStatus
1491
DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx)
1492
0
{
1493
0
    SECStatus rv = SECSuccess;
1494
0
    CERTCrlHeadNode head;
1495
0
    if (!cache) {
1496
0
        PORT_Assert(0);
1497
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1498
0
        return SECFailure;
1499
0
    }
1500
    /* first, initialize list */
1501
0
    memset(&head, 0, sizeof(head));
1502
0
    head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1503
0
    rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
1504
1505
    /* if this function fails, something very wrong happened, such as an out
1506
       of memory error during CRL decoding. We don't want to proceed and must
1507
       mark the cache object invalid */
1508
0
    if (SECFailure == rv) {
1509
        /* fetch failed, add error bit */
1510
0
        cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1511
0
    } else {
1512
        /* fetch was successful, clear this error bit */
1513
0
        cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
1514
0
    }
1515
1516
    /* add any CRLs found to our array */
1517
0
    if (SECSuccess == rv) {
1518
0
        CERTCrlNode* crlNode = NULL;
1519
1520
0
        for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1521
0
            CachedCrl* returned = NULL;
1522
0
            CERTSignedCrl* crlobject = crlNode->crl;
1523
0
            if (!crlobject) {
1524
0
                PORT_Assert(0);
1525
0
                continue;
1526
0
            }
1527
0
            rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
1528
0
            if (SECSuccess == rv) {
1529
0
                PRBool added = PR_FALSE;
1530
0
                rv = DPCache_AddCRL(cache, returned, &added);
1531
0
                if (PR_TRUE != added) {
1532
0
                    rv = CachedCrl_Destroy(returned);
1533
0
                    returned = NULL;
1534
0
                } else if (vfdate) {
1535
0
                    rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
1536
0
                }
1537
0
            } else {
1538
                /* not enough memory to add the CRL to the cache. mark it
1539
                   invalid so we will try again . */
1540
0
                cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1541
0
            }
1542
0
            if (SECFailure == rv) {
1543
0
                break;
1544
0
            }
1545
0
        }
1546
0
    }
1547
1548
0
    if (head.arena) {
1549
0
        CERTCrlNode* crlNode = NULL;
1550
        /* clean up the CRL list in case we got a partial one
1551
           during a failed fetch */
1552
0
        for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1553
0
            if (crlNode->crl) {
1554
0
                SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
1555
                   added to the cache and the refcount got bumped, or not, and
1556
                   thus we need to free its RAM */
1557
0
            }
1558
0
        }
1559
0
        PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
1560
0
    }
1561
1562
0
    return rv;
1563
0
}
1564
1565
static SECStatus
1566
CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn, CERTCrlEntry** returned)
1567
0
{
1568
0
    CERTCrlEntry* acrlEntry;
1569
1570
0
    PORT_Assert(crl);
1571
0
    PORT_Assert(crl->entries);
1572
0
    PORT_Assert(sn);
1573
0
    PORT_Assert(returned);
1574
0
    if (!crl || !sn || !returned || !crl->entries) {
1575
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1576
0
        return SECFailure;
1577
0
    }
1578
0
    acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
1579
0
    if (acrlEntry) {
1580
0
        *returned = acrlEntry;
1581
0
    } else {
1582
0
        *returned = NULL;
1583
0
    }
1584
0
    return SECSuccess;
1585
0
}
1586
1587
/* check if a particular SN is in the CRL cache and return its entry */
1588
dpcacheStatus
1589
DPCache_Lookup(CRLDPCache* cache, const SECItem* sn, CERTCrlEntry** returned)
1590
0
{
1591
0
    SECStatus rv;
1592
0
    if (!cache || !sn || !returned) {
1593
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1594
        /* no cache or SN to look up, or no way to return entry */
1595
0
        return dpcacheCallerError;
1596
0
    }
1597
0
    *returned = NULL;
1598
0
    if (0 != cache->invalid) {
1599
        /* the cache contains a bad CRL, or there was a CRL fetching error. */
1600
0
        PORT_SetError(SEC_ERROR_CRL_INVALID);
1601
0
        return dpcacheInvalidCacheError;
1602
0
    }
1603
0
    if (!cache->selected) {
1604
        /* no CRL means no entry to return. This is OK, except for
1605
         * NIST policy */
1606
0
        return dpcacheEmpty;
1607
0
    }
1608
0
    rv = CachedCrl_GetEntry(cache->selected, sn, returned);
1609
0
    if (SECSuccess != rv) {
1610
0
        return dpcacheLookupError;
1611
0
    } else {
1612
0
        if (*returned) {
1613
0
            return dpcacheFoundEntry;
1614
0
        } else {
1615
0
            return dpcacheNoEntry;
1616
0
        }
1617
0
    }
1618
0
}
1619
1620
#if defined(DPC_RWLOCK)
1621
1622
#define DPCache_LockWrite()                    \
1623
0
    {                                          \
1624
0
        if (readlocked) {                      \
1625
0
            NSSRWLock_UnlockRead(cache->lock); \
1626
0
        }                                      \
1627
0
        NSSRWLock_LockWrite(cache->lock);      \
1628
0
    }
1629
1630
#define DPCache_UnlockWrite()                \
1631
0
    {                                        \
1632
0
        if (readlocked) {                    \
1633
0
            NSSRWLock_LockRead(cache->lock); \
1634
0
        }                                    \
1635
0
        NSSRWLock_UnlockWrite(cache->lock);  \
1636
0
    }
1637
1638
#else
1639
1640
/* with a global lock, we are always locked for read before we need write
1641
   access, so do nothing */
1642
1643
#define DPCache_LockWrite() \
1644
    {                       \
1645
    }
1646
1647
#define DPCache_UnlockWrite() \
1648
    {                         \
1649
    }
1650
1651
#endif
1652
1653
/* update the content of the CRL cache, including fetching of CRLs, and
1654
   reprocessing with specified issuer and date . We are always holding
1655
   either the read or write lock on DPCache upon entry. */
1656
static SECStatus
1657
DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
1658
                    PRBool readlocked, PRTime vfdate, void* wincx)
1659
0
{
1660
    /* Update the CRLDPCache now. We don't cache token CRL lookup misses
1661
       yet, as we have no way of getting notified of new PKCS#11 object
1662
       creation that happens in a token  */
1663
0
    SECStatus rv = SECSuccess;
1664
0
    PRUint32 i = 0;
1665
0
    PRBool forcedrefresh = PR_FALSE;
1666
0
    PRBool dirty = PR_FALSE; /* whether something was changed in the
1667
                                cache state during this update cycle */
1668
0
    PRBool hastokenCRLs = PR_FALSE;
1669
0
    PRTime now = 0;
1670
0
    PRTime lastfetch = 0;
1671
0
    PRBool mustunlock = PR_FALSE;
1672
1673
0
    if (!cache) {
1674
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1675
0
        return SECFailure;
1676
0
    }
1677
1678
    /* first, make sure we have obtained all the CRLs we need.
1679
       We do an expensive token fetch in the following cases :
1680
       1) cache is empty because no fetch was ever performed yet
1681
       2) cache is explicitly set to refresh state
1682
       3) cache is in invalid state because last fetch failed
1683
       4) cache contains no token CRLs, and it's been more than one minute
1684
          since the last fetch
1685
       5) cache contains token CRLs, and it's been more than 10 minutes since
1686
          the last fetch
1687
    */
1688
0
    forcedrefresh = cache->refresh;
1689
0
    lastfetch = cache->lastfetch;
1690
0
    if (PR_TRUE != forcedrefresh &&
1691
0
        (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED))) {
1692
0
        now = PR_Now();
1693
0
        hastokenCRLs = DPCache_HasTokenCRLs(cache);
1694
0
    }
1695
0
    if ((0 == lastfetch) ||
1696
1697
0
        (PR_TRUE == forcedrefresh) ||
1698
1699
0
        (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
1700
1701
0
        ((PR_FALSE == hastokenCRLs) &&
1702
0
         ((now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
1703
0
          (now < cache->lastfetch))) ||
1704
1705
0
        ((PR_TRUE == hastokenCRLs) &&
1706
0
         ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
1707
0
          (now < cache->lastfetch)))) {
1708
        /* the cache needs to be refreshed, and/or we had zero CRL for this
1709
           DP. Try to get one from PKCS#11 tokens */
1710
0
        DPCache_LockWrite();
1711
        /* check if another thread updated before us, and skip update if so */
1712
0
        if (lastfetch == cache->lastfetch) {
1713
            /* we are the first */
1714
0
            rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
1715
0
            if (PR_TRUE == cache->refresh) {
1716
0
                cache->refresh = PR_FALSE; /* clear refresh state */
1717
0
            }
1718
0
            dirty = PR_TRUE;
1719
0
            cache->lastfetch = PR_Now();
1720
0
        }
1721
0
        DPCache_UnlockWrite();
1722
0
    }
1723
1724
    /* now, make sure we have no extraneous CRLs (deleted token objects)
1725
       we'll do this inexpensive existence check either
1726
       1) if there was a token object fetch
1727
       2) every minute */
1728
0
    if ((PR_TRUE != dirty) && (!now)) {
1729
0
        now = PR_Now();
1730
0
    }
1731
0
    if ((PR_TRUE == dirty) ||
1732
0
        ((now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
1733
0
         (now < cache->lastcheck))) {
1734
0
        PRTime lastcheck = cache->lastcheck;
1735
0
        mustunlock = PR_FALSE;
1736
        /* check if all CRLs still exist */
1737
0
        for (i = 0; (i < cache->ncrls); i++) {
1738
0
            CachedCrl* savcrl = cache->crls[i];
1739
0
            if ((!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin)) {
1740
                /* we only want to check token CRLs */
1741
0
                continue;
1742
0
            }
1743
0
            if ((PR_TRUE != TokenCRLStillExists(savcrl->crl))) {
1744
1745
                /* this CRL is gone */
1746
0
                if (PR_TRUE != mustunlock) {
1747
0
                    DPCache_LockWrite();
1748
0
                    mustunlock = PR_TRUE;
1749
0
                }
1750
                /* first, we need to check if another thread did an update
1751
                   before we did */
1752
0
                if (lastcheck == cache->lastcheck) {
1753
                    /* the CRL is gone. And we are the one to do the update */
1754
0
                    DPCache_RemoveCRL(cache, i);
1755
0
                    dirty = PR_TRUE;
1756
0
                }
1757
                /* stay locked here intentionally so we do all the other
1758
                   updates in this thread for the remaining CRLs */
1759
0
            }
1760
0
        }
1761
0
        if (PR_TRUE == mustunlock) {
1762
0
            cache->lastcheck = PR_Now();
1763
0
            DPCache_UnlockWrite();
1764
0
            mustunlock = PR_FALSE;
1765
0
        }
1766
0
    }
1767
1768
    /* add issuer certificate if it was previously unavailable */
1769
0
    if (issuer && (NULL == cache->issuerDERCert) &&
1770
0
        (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN))) {
1771
        /* if we didn't have a valid issuer cert yet, but we do now. add it */
1772
0
        DPCache_LockWrite();
1773
0
        if (!cache->issuerDERCert) {
1774
0
            dirty = PR_TRUE;
1775
0
            cache->dbHandle = issuer->dbhandle;
1776
0
            cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert);
1777
0
        }
1778
0
        DPCache_UnlockWrite();
1779
0
    }
1780
1781
    /* verify CRLs that couldn't be checked when inserted into the cache
1782
       because the issuer cert or a verification date was unavailable.
1783
       These are CRLs that were inserted into the cache through
1784
       SEC_FindCrlByName, or through manual insertion, rather than through a
1785
       certificate verification (CERT_CheckCRL) */
1786
1787
0
    if (cache->issuerDERCert && vfdate) {
1788
0
        mustunlock = PR_FALSE;
1789
        /* re-process all unverified CRLs */
1790
0
        for (i = 0; i < cache->ncrls; i++) {
1791
0
            CachedCrl* savcrl = cache->crls[i];
1792
0
            if (!savcrl) {
1793
0
                continue;
1794
0
            }
1795
0
            if (PR_TRUE != savcrl->sigChecked) {
1796
0
                if (!mustunlock) {
1797
0
                    DPCache_LockWrite();
1798
0
                    mustunlock = PR_TRUE;
1799
0
                }
1800
                /* first, we need to check if another thread updated
1801
                   it before we did, and abort if it has been modified since
1802
                   we acquired the lock. Make sure first that the CRL is still
1803
                   in the array at the same position */
1804
0
                if ((i < cache->ncrls) && (savcrl == cache->crls[i]) &&
1805
0
                    (PR_TRUE != savcrl->sigChecked)) {
1806
                    /* the CRL is still there, unverified. Do it */
1807
0
                    CachedCrl_Verify(cache, savcrl, vfdate, wincx);
1808
0
                    dirty = PR_TRUE;
1809
0
                }
1810
                /* stay locked here intentionally so we do all the other
1811
                   updates in this thread for the remaining CRLs */
1812
0
            }
1813
0
            if (mustunlock && !dirty) {
1814
0
                DPCache_UnlockWrite();
1815
0
                mustunlock = PR_FALSE;
1816
0
            }
1817
0
        }
1818
0
    }
1819
1820
0
    if (dirty || cache->mustchoose) {
1821
        /* changes to the content of the CRL cache necessitate examining all
1822
           CRLs for selection of the most appropriate one to cache */
1823
0
        if (!mustunlock) {
1824
0
            DPCache_LockWrite();
1825
0
            mustunlock = PR_TRUE;
1826
0
        }
1827
0
        DPCache_SelectCRL(cache);
1828
0
        cache->mustchoose = PR_FALSE;
1829
0
    }
1830
0
    if (mustunlock)
1831
0
        DPCache_UnlockWrite();
1832
1833
0
    return rv;
1834
0
}
1835
1836
/* callback for qsort to sort by thisUpdate */
1837
static int
1838
SortCRLsByThisUpdate(const void* arg1, const void* arg2)
1839
0
{
1840
0
    PRTime timea, timeb;
1841
0
    SECStatus rv = SECSuccess;
1842
0
    CachedCrl *a, *b;
1843
1844
0
    a = *(CachedCrl**)arg1;
1845
0
    b = *(CachedCrl**)arg2;
1846
1847
0
    if (!a || !b) {
1848
0
        PORT_Assert(0);
1849
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1850
0
        rv = SECFailure;
1851
0
    }
1852
1853
0
    if (SECSuccess == rv) {
1854
0
        rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
1855
0
    }
1856
0
    if (SECSuccess == rv) {
1857
0
        rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
1858
0
    }
1859
0
    if (SECSuccess == rv) {
1860
0
        if (timea > timeb) {
1861
0
            return 1; /* a is better than b */
1862
0
        }
1863
0
        if (timea < timeb) {
1864
0
            return -1; /* a is not as good as b */
1865
0
        }
1866
0
    }
1867
1868
    /* if they are equal, or if all else fails, use pointer differences */
1869
0
    PORT_Assert(a != b); /* they should never be equal */
1870
0
    return a > b ? 1 : -1;
1871
0
}
1872
1873
/* callback for qsort to sort a set of disparate CRLs, some of which are
1874
   invalid DER or failed signature check.
1875
1876
   Validated CRLs are differentiated by thisUpdate .
1877
   Validated CRLs are preferred over non-validated CRLs .
1878
   Proper DER CRLs are preferred over non-DER data .
1879
*/
1880
static int
1881
SortImperfectCRLs(const void* arg1, const void* arg2)
1882
0
{
1883
0
    CachedCrl *a, *b;
1884
1885
0
    a = *(CachedCrl**)arg1;
1886
0
    b = *(CachedCrl**)arg2;
1887
1888
0
    if (!a || !b) {
1889
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1890
0
        PORT_Assert(0);
1891
0
    } else {
1892
0
        PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
1893
0
        if ((PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid)) {
1894
            /* both CRLs have been validated, choose the latest one */
1895
0
            return SortCRLsByThisUpdate(arg1, arg2);
1896
0
        }
1897
0
        if (PR_TRUE == a->sigValid) {
1898
0
            return 1; /* a is greater than b */
1899
0
        }
1900
0
        if (PR_TRUE == b->sigValid) {
1901
0
            return -1; /* a is not as good as b */
1902
0
        }
1903
0
        aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
1904
0
        bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
1905
        /* neither CRL had its signature check pass */
1906
0
        if ((PR_FALSE == aDecoded) && (PR_FALSE == bDecoded)) {
1907
            /* both CRLs are proper DER, choose the latest one */
1908
0
            return SortCRLsByThisUpdate(arg1, arg2);
1909
0
        }
1910
0
        if (PR_FALSE == aDecoded) {
1911
0
            return 1; /* a is better than b */
1912
0
        }
1913
0
        if (PR_FALSE == bDecoded) {
1914
0
            return -1; /* a is not as good as b */
1915
0
        }
1916
        /* both are invalid DER. sigh. */
1917
0
    }
1918
    /* if they are equal, or if all else fails, use pointer differences */
1919
0
    PORT_Assert(a != b); /* they should never be equal */
1920
0
    return a > b ? 1 : -1;
1921
0
}
1922
1923
/* Pick best CRL to use . needs write access */
1924
static SECStatus
1925
DPCache_SelectCRL(CRLDPCache* cache)
1926
0
{
1927
0
    PRUint32 i;
1928
0
    PRBool valid = PR_TRUE;
1929
0
    CachedCrl* selected = NULL;
1930
1931
0
    PORT_Assert(cache);
1932
0
    if (!cache) {
1933
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1934
0
        return SECFailure;
1935
0
    }
1936
    /* if any invalid CRL is present, then the CRL cache is
1937
       considered invalid, for security reasons */
1938
0
    for (i = 0; i < cache->ncrls; i++) {
1939
0
        if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
1940
0
            !cache->crls[i]->sigValid) {
1941
0
            valid = PR_FALSE;
1942
0
            break;
1943
0
        }
1944
0
    }
1945
0
    if (PR_TRUE == valid) {
1946
        /* all CRLs are valid, clear this error */
1947
0
        cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
1948
0
    } else {
1949
        /* some CRLs are invalid, set this error */
1950
0
        cache->invalid |= CRL_CACHE_INVALID_CRLS;
1951
0
    }
1952
1953
0
    if (cache->invalid) {
1954
        /* cache is in an invalid state, so reset it */
1955
0
        if (cache->selected) {
1956
0
            cache->selected = NULL;
1957
0
        }
1958
        /* also sort the CRLs imperfectly */
1959
0
        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortImperfectCRLs);
1960
0
        return SECSuccess;
1961
0
    }
1962
1963
0
    if (cache->ncrls) {
1964
        /* all CRLs are good, sort them by thisUpdate */
1965
0
        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortCRLsByThisUpdate);
1966
1967
        /* pick the newest CRL */
1968
0
        selected = cache->crls[cache->ncrls - 1];
1969
1970
        /* and populate the cache */
1971
0
        if (SECSuccess != CachedCrl_Populate(selected)) {
1972
0
            return SECFailure;
1973
0
        }
1974
0
    }
1975
1976
0
    cache->selected = selected;
1977
1978
0
    return SECSuccess;
1979
0
}
1980
1981
/* initialize a DPCache object */
1982
static SECStatus
1983
DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
1984
               const SECItem* subject, SECItem* dp)
1985
0
{
1986
0
    CRLDPCache* cache = NULL;
1987
0
    PORT_Assert(returned);
1988
    /* issuer and dp are allowed to be NULL */
1989
0
    if (!returned || !subject) {
1990
0
        PORT_Assert(0);
1991
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1992
0
        return SECFailure;
1993
0
    }
1994
0
    *returned = NULL;
1995
0
    cache = PORT_ZAlloc(sizeof(CRLDPCache));
1996
0
    if (!cache) {
1997
0
        return SECFailure;
1998
0
    }
1999
0
#ifdef DPC_RWLOCK
2000
0
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2001
#else
2002
    cache->lock = PR_NewLock();
2003
#endif
2004
0
    if (!cache->lock) {
2005
0
        PORT_Free(cache);
2006
0
        return SECFailure;
2007
0
    }
2008
0
    if (issuer) {
2009
0
        cache->dbHandle = issuer->dbhandle;
2010
0
        cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert);
2011
0
    }
2012
0
    cache->distributionPoint = SECITEM_DupItem(dp);
2013
0
    cache->subject = SECITEM_DupItem(subject);
2014
0
    cache->lastfetch = 0;
2015
0
    cache->lastcheck = 0;
2016
0
    *returned = cache;
2017
0
    return SECSuccess;
2018
0
}
2019
2020
/* create an issuer cache object (per CA subject ) */
2021
static SECStatus
2022
IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer,
2023
                   const SECItem* subject, const SECItem* dp)
2024
0
{
2025
0
    SECStatus rv = SECSuccess;
2026
0
    CRLIssuerCache* cache = NULL;
2027
0
    PORT_Assert(returned);
2028
0
    PORT_Assert(subject);
2029
    /* issuer and dp are allowed to be NULL */
2030
0
    if (!returned || !subject) {
2031
0
        PORT_Assert(0);
2032
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2033
0
        return SECFailure;
2034
0
    }
2035
0
    *returned = NULL;
2036
0
    cache = (CRLIssuerCache*)PORT_ZAlloc(sizeof(CRLIssuerCache));
2037
0
    if (!cache) {
2038
0
        return SECFailure;
2039
0
    }
2040
0
    cache->subject = SECITEM_DupItem(subject);
2041
#ifdef XCRL
2042
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2043
    if (!cache->lock) {
2044
        rv = SECFailure;
2045
    }
2046
    if (SECSuccess == rv && issuer) {
2047
        cache->issuer = CERT_DupCertificate(issuer);
2048
        if (!cache->issuer) {
2049
            rv = SECFailure;
2050
        }
2051
    }
2052
#endif
2053
0
    if (SECSuccess != rv) {
2054
0
        PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
2055
0
        return SECFailure;
2056
0
    }
2057
0
    *returned = cache;
2058
0
    return SECSuccess;
2059
0
}
2060
2061
/* add a DPCache to the issuer cache */
2062
static SECStatus
2063
IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
2064
                  const SECItem* subject, const SECItem* dp,
2065
                  CRLDPCache** newdpc)
2066
0
{
2067
    /* now create the required DP cache object */
2068
0
    if (!cache || !subject || !newdpc) {
2069
0
        PORT_Assert(0);
2070
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2071
0
        return SECFailure;
2072
0
    }
2073
0
    if (!dp) {
2074
        /* default distribution point */
2075
0
        SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
2076
0
        if (SECSuccess == rv) {
2077
0
            *newdpc = cache->dpp;
2078
0
            return SECSuccess;
2079
0
        }
2080
0
    } else {
2081
        /* we should never hit this until we support multiple DPs */
2082
0
        PORT_Assert(dp);
2083
        /* XCRL allocate a new distribution point cache object, initialize it,
2084
           and add it to the hash table of DPs */
2085
0
    }
2086
0
    return SECFailure;
2087
0
}
2088
2089
/* add an IssuerCache to the global hash table of issuers */
2090
static SECStatus
2091
CRLCache_AddIssuer(CRLIssuerCache* issuer)
2092
0
{
2093
0
    PORT_Assert(issuer);
2094
0
    PORT_Assert(crlcache.issuers);
2095
0
    if (!issuer || !crlcache.issuers) {
2096
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2097
0
        return SECFailure;
2098
0
    }
2099
0
    if (NULL == PL_HashTableAdd(crlcache.issuers, (void*)issuer->subject,
2100
0
                                (void*)issuer)) {
2101
0
        return SECFailure;
2102
0
    }
2103
0
    return SECSuccess;
2104
0
}
2105
2106
/* retrieve the issuer cache object for a given issuer subject */
2107
static SECStatus
2108
CRLCache_GetIssuerCache(CRLCache* cache, const SECItem* subject,
2109
                        CRLIssuerCache** returned)
2110
0
{
2111
    /* we need to look up the issuer in the hash table */
2112
0
    SECStatus rv = SECSuccess;
2113
0
    PORT_Assert(cache);
2114
0
    PORT_Assert(subject);
2115
0
    PORT_Assert(returned);
2116
0
    PORT_Assert(crlcache.issuers);
2117
0
    if (!cache || !subject || !returned || !crlcache.issuers) {
2118
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2119
0
        rv = SECFailure;
2120
0
    }
2121
2122
0
    if (SECSuccess == rv) {
2123
0
        *returned = (CRLIssuerCache*)PL_HashTableLookup(crlcache.issuers,
2124
0
                                                        (void*)subject);
2125
0
    }
2126
2127
0
    return rv;
2128
0
}
2129
2130
/* retrieve the full CRL object that best matches the content of a DPCache */
2131
static CERTSignedCrl*
2132
GetBestCRL(CRLDPCache* cache, PRBool entries)
2133
0
{
2134
0
    CachedCrl* acrl = NULL;
2135
2136
0
    PORT_Assert(cache);
2137
0
    if (!cache) {
2138
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2139
0
        return NULL;
2140
0
    }
2141
2142
0
    if (0 == cache->ncrls) {
2143
        /* empty cache*/
2144
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2145
0
        return NULL;
2146
0
    }
2147
2148
    /* if we have a valid full CRL selected, return it */
2149
0
    if (cache->selected) {
2150
0
        return SEC_DupCrl(cache->selected->crl);
2151
0
    }
2152
2153
    /* otherwise, use latest valid DER CRL */
2154
0
    acrl = cache->crls[cache->ncrls - 1];
2155
2156
0
    if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError)) {
2157
0
        SECStatus rv = SECSuccess;
2158
0
        if (PR_TRUE == entries) {
2159
0
            rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
2160
0
        }
2161
0
        if (SECSuccess == rv) {
2162
0
            return SEC_DupCrl(acrl->crl);
2163
0
        }
2164
0
    }
2165
2166
0
    PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2167
0
    return NULL;
2168
0
}
2169
2170
/* get a particular DPCache object from an IssuerCache */
2171
static CRLDPCache*
2172
IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
2173
0
{
2174
0
    CRLDPCache* dpp = NULL;
2175
0
    PORT_Assert(cache);
2176
    /* XCRL for now we only support the "default" DP, ie. the
2177
       full CRL. So we can return the global one without locking. In
2178
       the future we will have a lock */
2179
0
    PORT_Assert(NULL == dp);
2180
0
    if (!cache || dp) {
2181
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2182
0
        return NULL;
2183
0
    }
2184
#ifdef XCRL
2185
    NSSRWLock_LockRead(cache->lock);
2186
#endif
2187
0
    dpp = cache->dpp;
2188
#ifdef XCRL
2189
    NSSRWLock_UnlockRead(cache->lock);
2190
#endif
2191
0
    return dpp;
2192
0
}
2193
2194
/* get a DPCache object for the given issuer subject and dp
2195
   Automatically creates the cache object if it doesn't exist yet.
2196
   */
2197
SECStatus
2198
AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
2199
               const SECItem* dp, PRTime t, void* wincx, CRLDPCache** dpcache,
2200
               PRBool* writeLocked)
2201
0
{
2202
0
    SECStatus rv = SECSuccess;
2203
0
    CRLIssuerCache* issuercache = NULL;
2204
#ifdef GLOBAL_RWLOCK
2205
    PRBool globalwrite = PR_FALSE;
2206
#endif
2207
0
    PORT_Assert(crlcache.lock);
2208
0
    if (!crlcache.lock) {
2209
        /* CRL cache is not initialized */
2210
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2211
0
        return SECFailure;
2212
0
    }
2213
#ifdef GLOBAL_RWLOCK
2214
    NSSRWLock_LockRead(crlcache.lock);
2215
#else
2216
0
    PR_Lock(crlcache.lock);
2217
0
#endif
2218
0
    rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
2219
0
    if (SECSuccess != rv) {
2220
#ifdef GLOBAL_RWLOCK
2221
        NSSRWLock_UnlockRead(crlcache.lock);
2222
#else
2223
0
        PR_Unlock(crlcache.lock);
2224
0
#endif
2225
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2226
0
        return SECFailure;
2227
0
    }
2228
0
    if (!issuercache) {
2229
        /* there is no cache for this issuer yet. This means this is the
2230
           first time we look up a cert from that issuer, and we need to
2231
           create the cache. */
2232
2233
0
        rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
2234
0
        if (SECSuccess == rv && !issuercache) {
2235
0
            PORT_Assert(issuercache);
2236
0
            rv = SECFailure;
2237
0
        }
2238
2239
0
        if (SECSuccess == rv) {
2240
            /* This is the first time we look up a cert of this issuer.
2241
               Create the DPCache for this DP . */
2242
0
            rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
2243
0
        }
2244
2245
0
        if (SECSuccess == rv) {
2246
            /* lock the DPCache for write to ensure the update happens in this
2247
               thread */
2248
0
            *writeLocked = PR_TRUE;
2249
0
#ifdef DPC_RWLOCK
2250
0
            NSSRWLock_LockWrite((*dpcache)->lock);
2251
#else
2252
            PR_Lock((*dpcache)->lock);
2253
#endif
2254
0
        }
2255
2256
0
        if (SECSuccess == rv) {
2257
/* now add the new issuer cache to the global hash table of
2258
   issuers */
2259
#ifdef GLOBAL_RWLOCK
2260
            CRLIssuerCache* existing = NULL;
2261
            NSSRWLock_UnlockRead(crlcache.lock);
2262
            /* when using a r/w lock for the global cache, check if the issuer
2263
               already exists before adding to the hash table */
2264
            NSSRWLock_LockWrite(crlcache.lock);
2265
            globalwrite = PR_TRUE;
2266
            rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
2267
            if (!existing) {
2268
#endif
2269
0
                rv = CRLCache_AddIssuer(issuercache);
2270
0
                if (SECSuccess != rv) {
2271
                    /* failure */
2272
0
                    rv = SECFailure;
2273
0
                }
2274
#ifdef GLOBAL_RWLOCK
2275
            } else {
2276
                /* somebody else updated before we did */
2277
                IssuerCache_Destroy(issuercache); /* destroy the new object */
2278
                issuercache = existing;           /* use the existing one */
2279
                *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2280
            }
2281
#endif
2282
0
        }
2283
2284
/* now unlock the global cache. We only want to lock the issuer hash
2285
   table addition. Holding it longer would hurt scalability */
2286
#ifdef GLOBAL_RWLOCK
2287
        if (PR_TRUE == globalwrite) {
2288
            NSSRWLock_UnlockWrite(crlcache.lock);
2289
            globalwrite = PR_FALSE;
2290
        } else {
2291
            NSSRWLock_UnlockRead(crlcache.lock);
2292
        }
2293
#else
2294
0
        PR_Unlock(crlcache.lock);
2295
0
#endif
2296
2297
        /* if there was a failure adding an issuer cache object, destroy it */
2298
0
        if (SECSuccess != rv && issuercache) {
2299
0
            if (PR_TRUE == *writeLocked) {
2300
0
#ifdef DPC_RWLOCK
2301
0
                NSSRWLock_UnlockWrite((*dpcache)->lock);
2302
#else
2303
                PR_Unlock((*dpcache)->lock);
2304
#endif
2305
0
            }
2306
0
            IssuerCache_Destroy(issuercache);
2307
0
            issuercache = NULL;
2308
0
        }
2309
2310
0
        if (SECSuccess != rv) {
2311
0
            return SECFailure;
2312
0
        }
2313
0
    } else {
2314
#ifdef GLOBAL_RWLOCK
2315
        NSSRWLock_UnlockRead(crlcache.lock);
2316
#else
2317
0
        PR_Unlock(crlcache.lock);
2318
0
#endif
2319
0
        *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2320
0
    }
2321
    /* we now have a DPCache that we can use for lookups */
2322
    /* lock it for read, unless we already locked for write */
2323
0
    if (PR_FALSE == *writeLocked) {
2324
0
#ifdef DPC_RWLOCK
2325
0
        NSSRWLock_LockRead((*dpcache)->lock);
2326
#else
2327
        PR_Lock((*dpcache)->lock);
2328
#endif
2329
0
    }
2330
2331
0
    if (SECSuccess == rv) {
2332
        /* currently there is always one and only one DPCache per issuer */
2333
0
        PORT_Assert(*dpcache);
2334
0
        if (*dpcache) {
2335
            /* make sure the DP cache is up to date before using it */
2336
0
            rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
2337
0
                                     t, wincx);
2338
0
        } else {
2339
0
            rv = SECFailure;
2340
0
        }
2341
0
    }
2342
0
    return rv;
2343
0
}
2344
2345
/* unlock access to the DPCache */
2346
void
2347
ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
2348
0
{
2349
0
    if (!dpcache) {
2350
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2351
0
        return;
2352
0
    }
2353
0
#ifdef DPC_RWLOCK
2354
0
    if (PR_TRUE == writeLocked) {
2355
0
        NSSRWLock_UnlockWrite(dpcache->lock);
2356
0
    } else {
2357
0
        NSSRWLock_UnlockRead(dpcache->lock);
2358
0
    }
2359
#else
2360
    PR_Unlock(dpcache->lock);
2361
#endif
2362
0
}
2363
2364
SECStatus
2365
cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
2366
                               const SECItem* dp, PRTime t, void* wincx,
2367
                               CERTRevocationStatus* revStatus,
2368
                               CERTCRLEntryReasonCode* revReason)
2369
0
{
2370
0
    PRBool lockedwrite = PR_FALSE;
2371
0
    SECStatus rv = SECSuccess;
2372
0
    CRLDPCache* dpcache = NULL;
2373
0
    CERTRevocationStatus status = certRevocationStatusRevoked;
2374
0
    CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
2375
0
    CERTCrlEntry* entry = NULL;
2376
0
    dpcacheStatus ds;
2377
2378
0
    if (!cert || !issuer) {
2379
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2380
0
        return SECFailure;
2381
0
    }
2382
2383
0
    if (revStatus) {
2384
0
        *revStatus = status;
2385
0
    }
2386
0
    if (revReason) {
2387
0
        *revReason = reason;
2388
0
    }
2389
2390
0
    if (t &&
2391
0
        secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE)) {
2392
        /* we won't be able to check the CRL's signature if the issuer cert
2393
           is expired as of the time we are verifying. This may cause a valid
2394
           CRL to be cached as bad. short-circuit to avoid this case. */
2395
0
        PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
2396
0
        return SECFailure;
2397
0
    }
2398
2399
0
    rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
2400
0
                        &lockedwrite);
2401
0
    PORT_Assert(SECSuccess == rv);
2402
0
    if (SECSuccess != rv) {
2403
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2404
0
        return SECFailure;
2405
0
    }
2406
    /* now look up the certificate SN in the DP cache's CRL */
2407
0
    ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
2408
0
    switch (ds) {
2409
0
        case dpcacheFoundEntry:
2410
0
            PORT_Assert(entry);
2411
            /* check the time if we have one */
2412
0
            if (entry->revocationDate.data && entry->revocationDate.len) {
2413
0
                PRTime revocationDate = 0;
2414
0
                if (SECSuccess ==
2415
0
                    DER_DecodeTimeChoice(&revocationDate,
2416
0
                                         &entry->revocationDate)) {
2417
                    /* we got a good revocation date, only consider the
2418
                       certificate revoked if the time we are inquiring about
2419
                       is past the revocation date */
2420
0
                    if (t >= revocationDate) {
2421
0
                        rv = SECFailure;
2422
0
                    } else {
2423
0
                        status = certRevocationStatusValid;
2424
0
                    }
2425
0
                } else {
2426
                    /* invalid revocation date, consider the certificate
2427
                       permanently revoked */
2428
0
                    rv = SECFailure;
2429
0
                }
2430
0
            } else {
2431
                /* no revocation date, certificate is permanently revoked */
2432
0
                rv = SECFailure;
2433
0
            }
2434
0
            if (SECFailure == rv) {
2435
0
                (void)CERT_FindCRLEntryReasonExten(entry, &reason);
2436
0
                PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
2437
0
            }
2438
0
            break;
2439
2440
0
        case dpcacheEmpty:
2441
            /* useful for NIST policy */
2442
0
            status = certRevocationStatusUnknown;
2443
0
            break;
2444
2445
0
        case dpcacheNoEntry:
2446
0
            status = certRevocationStatusValid;
2447
0
            break;
2448
2449
0
        case dpcacheInvalidCacheError:
2450
            /* treat it as unknown and let the caller decide based on
2451
               the policy */
2452
0
            status = certRevocationStatusUnknown;
2453
0
            break;
2454
2455
0
        default:
2456
            /* leave status as revoked */
2457
0
            break;
2458
0
    }
2459
2460
0
    ReleaseDPCache(dpcache, lockedwrite);
2461
0
    if (revStatus) {
2462
0
        *revStatus = status;
2463
0
    }
2464
0
    if (revReason) {
2465
0
        *revReason = reason;
2466
0
    }
2467
0
    return rv;
2468
0
}
2469
2470
/* check CRL revocation status of given certificate and issuer */
2471
SECStatus
2472
CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, const SECItem* dp,
2473
              PRTime t, void* wincx)
2474
0
{
2475
0
    return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx, NULL,
2476
0
                                          NULL);
2477
0
}
2478
2479
/* retrieve full CRL object that best matches the cache status */
2480
CERTSignedCrl*
2481
SEC_FindCrlByName(CERTCertDBHandle* handle, SECItem* crlKey, int type)
2482
0
{
2483
0
    CERTSignedCrl* acrl = NULL;
2484
0
    CRLDPCache* dpcache = NULL;
2485
0
    SECStatus rv = SECSuccess;
2486
0
    PRBool writeLocked = PR_FALSE;
2487
2488
0
    if (!crlKey) {
2489
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2490
0
        return NULL;
2491
0
    }
2492
2493
0
    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
2494
0
    if (SECSuccess == rv) {
2495
0
        acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
2496
        SEC_FindCrlByName always returned fully decoded CRLs in the past */
2497
0
        ReleaseDPCache(dpcache, writeLocked);
2498
0
    }
2499
0
    return acrl;
2500
0
}
2501
2502
/* invalidate the CRL cache for a given issuer, which forces a refetch of
2503
   CRL objects from PKCS#11 tokens */
2504
void
2505
CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
2506
0
{
2507
0
    CRLDPCache* cache = NULL;
2508
0
    SECStatus rv = SECSuccess;
2509
0
    PRBool writeLocked = PR_FALSE;
2510
0
    PRBool readlocked;
2511
2512
0
    (void)dbhandle; /* silence compiler warnings */
2513
2514
    /* XCRL we will need to refresh all the DPs of the issuer in the future,
2515
            not just the default one */
2516
0
    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
2517
0
    if (SECSuccess != rv) {
2518
0
        return;
2519
0
    }
2520
    /* we need to invalidate the DPCache here */
2521
0
    readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2522
0
    DPCache_LockWrite();
2523
0
    cache->refresh = PR_TRUE;
2524
0
    DPCache_UnlockWrite();
2525
0
    ReleaseDPCache(cache, writeLocked);
2526
0
    return;
2527
0
}
2528
2529
/* add the specified RAM CRL object to the cache */
2530
SECStatus
2531
CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
2532
0
{
2533
0
    CRLDPCache* cache = NULL;
2534
0
    SECStatus rv = SECSuccess;
2535
0
    PRBool writeLocked = PR_FALSE;
2536
0
    PRBool readlocked;
2537
0
    CachedCrl* returned = NULL;
2538
0
    PRBool added = PR_FALSE;
2539
0
    CERTSignedCrl* newcrl = NULL;
2540
0
    int realerror = 0;
2541
2542
0
    if (!dbhandle || !newdercrl) {
2543
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2544
0
        return SECFailure;
2545
0
    }
2546
2547
    /* first decode the DER CRL to make sure it's OK */
2548
0
    newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
2549
0
                                        CRL_DECODE_DONT_COPY_DER |
2550
0
                                            CRL_DECODE_SKIP_ENTRIES);
2551
2552
0
    if (!newcrl) {
2553
0
        return SECFailure;
2554
0
    }
2555
2556
    /* XXX check if it has IDP extension. If so, do not proceed and set error */
2557
2558
0
    rv = AcquireDPCache(NULL, &newcrl->crl.derName, NULL, 0, NULL, &cache,
2559
0
                        &writeLocked);
2560
0
    if (SECSuccess == rv) {
2561
0
        readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2562
2563
0
        rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
2564
0
        if (SECSuccess == rv && returned) {
2565
0
            DPCache_LockWrite();
2566
0
            rv = DPCache_AddCRL(cache, returned, &added);
2567
0
            if (PR_TRUE != added) {
2568
0
                realerror = PORT_GetError();
2569
0
                CachedCrl_Destroy(returned);
2570
0
                returned = NULL;
2571
0
            }
2572
0
            DPCache_UnlockWrite();
2573
0
        }
2574
2575
0
        ReleaseDPCache(cache, writeLocked);
2576
2577
0
        if (!added) {
2578
0
            rv = SECFailure;
2579
0
        }
2580
0
    }
2581
0
    SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
2582
        and the refcount got bumped, or not, and thus we need to free its
2583
        RAM */
2584
0
    if (realerror) {
2585
0
        PORT_SetError(realerror);
2586
0
    }
2587
0
    return rv;
2588
0
}
2589
2590
/* remove the specified RAM CRL object from the cache */
2591
SECStatus
2592
CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
2593
0
{
2594
0
    CRLDPCache* cache = NULL;
2595
0
    SECStatus rv = SECSuccess;
2596
0
    PRBool writeLocked = PR_FALSE;
2597
0
    PRBool readlocked;
2598
0
    PRBool removed = PR_FALSE;
2599
0
    PRUint32 i;
2600
0
    CERTSignedCrl* oldcrl = NULL;
2601
2602
0
    if (!dbhandle || !olddercrl) {
2603
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2604
0
        return SECFailure;
2605
0
    }
2606
2607
    /* first decode the DER CRL to make sure it's OK */
2608
0
    oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
2609
0
                                        CRL_DECODE_DONT_COPY_DER |
2610
0
                                            CRL_DECODE_SKIP_ENTRIES);
2611
2612
0
    if (!oldcrl) {
2613
        /* if this DER CRL can't decode, it can't be in the cache */
2614
0
        return SECFailure;
2615
0
    }
2616
2617
0
    rv = AcquireDPCache(NULL, &oldcrl->crl.derName, NULL, 0, NULL, &cache,
2618
0
                        &writeLocked);
2619
0
    if (SECSuccess == rv) {
2620
0
        CachedCrl* returned = NULL;
2621
2622
0
        readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2623
2624
0
        rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
2625
0
        if (SECSuccess == rv && returned) {
2626
0
            DPCache_LockWrite();
2627
0
            for (i = 0; i < cache->ncrls; i++) {
2628
0
                PRBool dupe = PR_FALSE, updated = PR_FALSE;
2629
0
                rv = CachedCrl_Compare(returned, cache->crls[i], &dupe,
2630
0
                                       &updated);
2631
0
                if (SECSuccess != rv) {
2632
0
                    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2633
0
                    break;
2634
0
                }
2635
0
                if (PR_TRUE == dupe) {
2636
0
                    rv = DPCache_RemoveCRL(cache, i); /* got a match */
2637
0
                    if (SECSuccess == rv) {
2638
0
                        cache->mustchoose = PR_TRUE;
2639
0
                        removed = PR_TRUE;
2640
0
                    }
2641
0
                    break;
2642
0
                }
2643
0
            }
2644
2645
0
            DPCache_UnlockWrite();
2646
2647
0
            if (SECSuccess != CachedCrl_Destroy(returned)) {
2648
0
                rv = SECFailure;
2649
0
            }
2650
0
        }
2651
2652
0
        ReleaseDPCache(cache, writeLocked);
2653
0
    }
2654
0
    if (SECSuccess != SEC_DestroyCrl(oldcrl)) {
2655
        /* need to do this because object is refcounted */
2656
0
        rv = SECFailure;
2657
0
    }
2658
0
    if (SECSuccess == rv && PR_TRUE != removed) {
2659
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2660
0
    }
2661
0
    return rv;
2662
0
}
2663
2664
SECStatus
2665
cert_AcquireNamedCRLCache(NamedCRLCache** returned)
2666
0
{
2667
0
    PORT_Assert(returned);
2668
0
    if (!namedCRLCache.lock) {
2669
0
        PORT_Assert(0);
2670
0
        return SECFailure;
2671
0
    }
2672
0
    PR_Lock(namedCRLCache.lock);
2673
0
    *returned = &namedCRLCache;
2674
0
    return SECSuccess;
2675
0
}
2676
2677
/* This must be called only while cache is acquired, and the entry is only
2678
 * valid until cache is released.
2679
 */
2680
SECStatus
2681
cert_FindCRLByGeneralName(NamedCRLCache* ncc, const SECItem* canonicalizedName,
2682
                          NamedCRLCacheEntry** retEntry)
2683
0
{
2684
0
    if (!ncc || !canonicalizedName || !retEntry) {
2685
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2686
0
        return SECFailure;
2687
0
    }
2688
0
    *retEntry = (NamedCRLCacheEntry*)PL_HashTableLookup(
2689
0
        namedCRLCache.entries, (void*)canonicalizedName);
2690
0
    return SECSuccess;
2691
0
}
2692
2693
SECStatus
2694
cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
2695
0
{
2696
0
    if (!ncc) {
2697
0
        return SECFailure;
2698
0
    }
2699
0
    if (!ncc->lock) {
2700
0
        PORT_Assert(0);
2701
0
        return SECFailure;
2702
0
    }
2703
0
    PR_Unlock(namedCRLCache.lock);
2704
0
    return SECSuccess;
2705
0
}
2706
2707
/* creates new named cache entry from CRL, and tries to add it to CRL cache */
2708
static SECStatus
2709
addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
2710
              const SECItem* canonicalizedName, NamedCRLCacheEntry** newEntry)
2711
0
{
2712
0
    SECStatus rv = SECSuccess;
2713
0
    NamedCRLCacheEntry* entry = NULL;
2714
2715
    /* create new named entry */
2716
0
    if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry) {
2717
        /* no need to keep unused CRL around */
2718
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2719
0
        return SECFailure;
2720
0
    }
2721
0
    entry = *newEntry;
2722
0
    entry->crl = crl; /* named CRL cache owns DER */
2723
0
    entry->lastAttemptTime = PR_Now();
2724
0
    entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
2725
0
    if (!entry->canonicalizedName) {
2726
0
        rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
2727
0
        PORT_Assert(SECSuccess == rv);
2728
0
        return SECFailure;
2729
0
    }
2730
    /* now, attempt to insert CRL into CRL cache */
2731
0
    if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl)) {
2732
0
        entry->inCRLCache = PR_TRUE;
2733
0
        entry->successfulInsertionTime = entry->lastAttemptTime;
2734
0
    } else {
2735
0
        switch (PR_GetError()) {
2736
0
            case SEC_ERROR_CRL_ALREADY_EXISTS:
2737
0
                entry->dupe = PR_TRUE;
2738
0
                break;
2739
2740
0
            case SEC_ERROR_BAD_DER:
2741
0
                entry->badDER = PR_TRUE;
2742
0
                break;
2743
2744
            /* all other reasons */
2745
0
            default:
2746
0
                entry->unsupported = PR_TRUE;
2747
0
                break;
2748
0
        }
2749
0
        rv = SECFailure;
2750
        /* no need to keep unused CRL around */
2751
0
        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
2752
0
        entry->crl = NULL;
2753
0
    }
2754
0
    return rv;
2755
0
}
2756
2757
/* take ownership of CRL, and insert it into the named CRL cache
2758
 * and indexed CRL cache
2759
 */
2760
SECStatus
2761
cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
2762
                           const SECItem* canonicalizedName)
2763
0
{
2764
0
    NamedCRLCacheEntry *oldEntry, *newEntry = NULL;
2765
0
    NamedCRLCache* ncc = NULL;
2766
0
    SECStatus rv = SECSuccess;
2767
2768
0
    PORT_Assert(namedCRLCache.lock);
2769
0
    PORT_Assert(namedCRLCache.entries);
2770
2771
0
    if (!crl || !canonicalizedName) {
2772
0
        PORT_Assert(0);
2773
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2774
0
        return SECFailure;
2775
0
    }
2776
2777
0
    rv = cert_AcquireNamedCRLCache(&ncc);
2778
0
    PORT_Assert(SECSuccess == rv);
2779
0
    if (SECSuccess != rv) {
2780
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2781
0
        return SECFailure;
2782
0
    }
2783
0
    rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
2784
0
    PORT_Assert(SECSuccess == rv);
2785
0
    if (SECSuccess != rv) {
2786
0
        (void)cert_ReleaseNamedCRLCache(ncc);
2787
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2788
0
        return SECFailure;
2789
0
    }
2790
0
    if (SECSuccess ==
2791
0
        addCRLToCache(dbhandle, crl, canonicalizedName, &newEntry)) {
2792
0
        if (!oldEntry) {
2793
            /* add new good entry to the hash table */
2794
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2795
0
                                        (void*)newEntry->canonicalizedName,
2796
0
                                        (void*)newEntry)) {
2797
0
                PORT_Assert(0);
2798
0
                NamedCRLCacheEntry_Destroy(newEntry);
2799
0
                rv = SECFailure;
2800
0
            }
2801
0
        } else {
2802
0
            PRBool removed;
2803
            /* remove the old CRL from the cache if needed */
2804
0
            if (oldEntry->inCRLCache) {
2805
0
                rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
2806
0
                PORT_Assert(SECSuccess == rv);
2807
0
            }
2808
0
            removed = PL_HashTableRemove(namedCRLCache.entries,
2809
0
                                         (void*)oldEntry->canonicalizedName);
2810
0
            PORT_Assert(removed);
2811
0
            if (!removed) {
2812
0
                rv = SECFailure;
2813
                /* leak old entry since we couldn't remove it from the hash
2814
                 * table */
2815
0
            } else {
2816
0
                PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry));
2817
0
            }
2818
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2819
0
                                        (void*)newEntry->canonicalizedName,
2820
0
                                        (void*)newEntry)) {
2821
0
                PORT_Assert(0);
2822
0
                rv = SECFailure;
2823
0
            }
2824
0
        }
2825
0
    } else {
2826
        /* error adding new CRL to cache */
2827
0
        if (!newEntry) {
2828
            // allocation failure in addCRLToCache
2829
0
            rv = SECFailure;
2830
0
        } else if (!oldEntry) {
2831
            /* no old cache entry, use the new one even though it's bad */
2832
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2833
0
                                        (void*)newEntry->canonicalizedName,
2834
0
                                        (void*)newEntry)) {
2835
0
                PORT_Assert(0);
2836
0
                rv = SECFailure;
2837
0
            }
2838
0
        } else {
2839
0
            if (oldEntry->inCRLCache) {
2840
                /* previous cache entry was good, keep it and update time */
2841
0
                oldEntry->lastAttemptTime = newEntry->lastAttemptTime;
2842
                /* throw away new bad entry */
2843
0
                rv = NamedCRLCacheEntry_Destroy(newEntry);
2844
0
                PORT_Assert(SECSuccess == rv);
2845
0
            } else {
2846
                /* previous cache entry was bad, just replace it */
2847
0
                PRBool removed = PL_HashTableRemove(
2848
0
                    namedCRLCache.entries, (void*)oldEntry->canonicalizedName);
2849
0
                PORT_Assert(removed);
2850
0
                if (!removed) {
2851
                    /* leak old entry since we couldn't remove it from the hash
2852
                     * table */
2853
0
                    rv = SECFailure;
2854
0
                } else {
2855
0
                    PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry));
2856
0
                }
2857
0
                if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2858
0
                                            (void*)newEntry->canonicalizedName,
2859
0
                                            (void*)newEntry)) {
2860
0
                    PORT_Assert(0);
2861
0
                    rv = SECFailure;
2862
0
                }
2863
0
            }
2864
0
        }
2865
0
    }
2866
0
    PORT_CheckSuccess(cert_ReleaseNamedCRLCache(ncc));
2867
2868
0
    return rv;
2869
0
}
2870
2871
static SECStatus
2872
CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, CRLOrigin origin)
2873
0
{
2874
0
    CachedCrl* newcrl = NULL;
2875
0
    if (!returned) {
2876
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2877
0
        return SECFailure;
2878
0
    }
2879
0
    newcrl = PORT_ZAlloc(sizeof(CachedCrl));
2880
0
    if (!newcrl) {
2881
0
        return SECFailure;
2882
0
    }
2883
0
    newcrl->crl = SEC_DupCrl(crl);
2884
0
    newcrl->origin = origin;
2885
0
    *returned = newcrl;
2886
0
    return SECSuccess;
2887
0
}
2888
2889
/* empty the cache content */
2890
static SECStatus
2891
CachedCrl_Depopulate(CachedCrl* crl)
2892
0
{
2893
0
    if (!crl) {
2894
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2895
0
        return SECFailure;
2896
0
    }
2897
    /* destroy the hash table */
2898
0
    if (crl->entries) {
2899
0
        PL_HashTableDestroy(crl->entries);
2900
0
        crl->entries = NULL;
2901
0
    }
2902
2903
    /* free the pre buffer */
2904
0
    if (crl->prebuffer) {
2905
0
        PreAllocator_Destroy(crl->prebuffer);
2906
0
        crl->prebuffer = NULL;
2907
0
    }
2908
0
    return SECSuccess;
2909
0
}
2910
2911
static SECStatus
2912
CachedCrl_Destroy(CachedCrl* crl)
2913
0
{
2914
0
    if (!crl) {
2915
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2916
0
        return SECFailure;
2917
0
    }
2918
0
    CachedCrl_Depopulate(crl);
2919
0
    SEC_DestroyCrl(crl->crl);
2920
0
    PORT_Free(crl);
2921
0
    return SECSuccess;
2922
0
}
2923
2924
/* create hash table of CRL entries */
2925
static SECStatus
2926
CachedCrl_Populate(CachedCrl* crlobject)
2927
0
{
2928
0
    SECStatus rv = SECFailure;
2929
0
    CERTCrlEntry** crlEntry = NULL;
2930
0
    PRUint32 numEntries = 0;
2931
2932
0
    if (!crlobject) {
2933
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2934
0
        return SECFailure;
2935
0
    }
2936
    /* complete the entry decoding . XXX thread-safety of CRL object */
2937
0
    rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
2938
0
    if (SECSuccess != rv) {
2939
0
        crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
2940
0
        return SECFailure;
2941
0
    }
2942
2943
0
    if (crlobject->entries && crlobject->prebuffer) {
2944
        /* cache is already built */
2945
0
        return SECSuccess;
2946
0
    }
2947
2948
    /* build the hash table from the full CRL */
2949
    /* count CRL entries so we can pre-allocate space for hash table entries */
2950
0
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2951
0
         crlEntry++) {
2952
0
        numEntries++;
2953
0
    }
2954
0
    crlobject->prebuffer =
2955
0
        PreAllocator_Create(numEntries * sizeof(PLHashEntry));
2956
0
    PORT_Assert(crlobject->prebuffer);
2957
0
    if (!crlobject->prebuffer) {
2958
0
        return SECFailure;
2959
0
    }
2960
    /* create a new hash table */
2961
0
    crlobject->entries =
2962
0
        PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues,
2963
0
                        &preAllocOps, crlobject->prebuffer);
2964
0
    PORT_Assert(crlobject->entries);
2965
0
    if (!crlobject->entries) {
2966
0
        return SECFailure;
2967
0
    }
2968
    /* add all serial numbers to the hash table */
2969
0
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2970
0
         crlEntry++) {
2971
0
        PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
2972
0
                        *crlEntry);
2973
0
    }
2974
2975
0
    return SECSuccess;
2976
0
}
2977
2978
/* returns true if there are CRLs from PKCS#11 slots */
2979
static PRBool
2980
DPCache_HasTokenCRLs(CRLDPCache* cache)
2981
0
{
2982
0
    PRBool answer = PR_FALSE;
2983
0
    PRUint32 i;
2984
0
    for (i = 0; i < cache->ncrls; i++) {
2985
0
        if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin)) {
2986
0
            answer = PR_TRUE;
2987
0
            break;
2988
0
        }
2989
0
    }
2990
0
    return answer;
2991
0
}
2992
2993
/* are these CRLs the same, as far as the cache is concerned ? */
2994
/* are these CRLs the same token object but with different DER ?
2995
   This can happen if the DER CRL got updated in the token, but the PKCS#11
2996
   object ID did not change. NSS softoken has the unfortunate property to
2997
   never change the object ID for CRL objects. */
2998
static SECStatus
2999
CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, PRBool* isUpdated)
3000
0
{
3001
0
    PORT_Assert(a);
3002
0
    PORT_Assert(b);
3003
0
    PORT_Assert(isDupe);
3004
0
    PORT_Assert(isUpdated);
3005
0
    if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl) {
3006
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3007
0
        return SECFailure;
3008
0
    }
3009
3010
0
    *isDupe = *isUpdated = PR_FALSE;
3011
3012
0
    if (a == b) {
3013
        /* dupe */
3014
0
        *isDupe = PR_TRUE;
3015
0
        *isUpdated = PR_FALSE;
3016
0
        return SECSuccess;
3017
0
    }
3018
0
    if (b->origin != a->origin) {
3019
        /* CRLs of different origins are not considered dupes,
3020
           and can't be updated either */
3021
0
        return SECSuccess;
3022
0
    }
3023
0
    if (CRL_OriginToken == b->origin) {
3024
        /* for token CRLs, slot and PKCS#11 object handle must match for CRL
3025
           to truly be a dupe */
3026
0
        if ((b->crl->slot == a->crl->slot) &&
3027
0
            (b->crl->pkcs11ID == a->crl->pkcs11ID)) {
3028
            /* ASN.1 DER needs to match for dupe check */
3029
            /* could optimize by just checking a few fields like thisUpdate */
3030
0
            if (SECEqual ==
3031
0
                SECITEM_CompareItem(b->crl->derCrl, a->crl->derCrl)) {
3032
0
                *isDupe = PR_TRUE;
3033
0
            } else {
3034
0
                *isUpdated = PR_TRUE;
3035
0
            }
3036
0
        }
3037
0
        return SECSuccess;
3038
0
    }
3039
0
    if (CRL_OriginExplicit == b->origin) {
3040
        /* We need to make sure this is the same object that the user provided
3041
           to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
3042
           just do a pointer comparison here.
3043
        */
3044
0
        if (b->crl->derCrl == a->crl->derCrl) {
3045
0
            *isDupe = PR_TRUE;
3046
0
        }
3047
0
    }
3048
0
    return SECSuccess;
3049
0
}