Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/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
0
    /* 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
0
176
0
    if (!crl) {
177
0
        return SECFailure;
178
0
    }
179
0
180
0
    if (crl->entries == NULL) {
181
0
        /* CRLs with no entries are valid */
182
0
        return (SECSuccess);
183
0
    }
184
0
185
0
    /* Look in the crl entry extensions.  If there is a critical extension,
186
0
       then the crl version must be v2; otherwise, it should be v1.
187
0
     */
188
0
    entries = crl->entries;
189
0
    while (*entries) {
190
0
        entry = *entries;
191
0
        if (entry->extensions) {
192
0
            /* If there is a critical extension in the entries, then the
193
0
               CRL must be of version 2.  If we already saw a critical
194
0
               extension,
195
0
               there is no need to check the version again.
196
0
            */
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
0
                        /* 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
0
209
0
            /* For each entry, make sure that it does not contain an unknown
210
0
               critical extension.  If it does, we must reject the CRL since
211
0
               we don't know how to process the extension.
212
0
            */
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
0
235
0
    if (version > SEC_CRL_VERSION_2) {
236
0
        PORT_SetError(SEC_ERROR_CRL_INVALID_VERSION);
237
0
        return (SECFailure);
238
0
    }
239
0
240
0
    /* Check the crl extensions for a critial extension.  If one is found,
241
0
       and the version is not v2, then we are done.
242
0
     */
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
0
                /* only CRL v2 critical extensions are supported */
248
0
                PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
249
0
                return (SECFailure);
250
0
            }
251
0
            /* 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
0
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
0
274
0
    if (!arena) {
275
0
        /* 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
0
288
0
    /* make a copy so the data doesn't point to memory inside derCrl, which
289
0
       may be temporary */
290
0
    if (SECSuccess == rv) {
291
0
        rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
292
0
    }
293
0
294
0
    if (myArena != arena) {
295
0
        PORT_FreeArena(myArena, PR_FALSE);
296
0
    }
297
0
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
0
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
0
            /* the CRL has already been fully decoded */
316
0
            return SECSuccess;
317
0
        }
318
0
        if (PR_TRUE == extended->badEntries) {
319
0
            /* 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
0
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
0
                decoding again */
334
0
        } else {
335
0
            extended->decodingError = PR_TRUE;
336
0
            extended->badEntries = PR_TRUE;
337
0
            /* cache the decoding failure. If it fails the first time,
338
0
               it will fail again, which will grow the arena and leak
339
0
               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
0
364
0
    PORT_Assert(derSignedCrl);
365
0
    if (!derSignedCrl) {
366
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
367
0
        return NULL;
368
0
    }
369
0
370
0
    /* Adopting DER requires not copying it.  Code that sets ADOPT flag
371
0
     * but doesn't set DONT_COPY probably doesn't know What it is doing.
372
0
     * That condition is a programming error in the caller.
373
0
     */
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
0
381
0
    /* 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
0
391
0
    /* 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
0
398
0
    crl->arena = arena;
399
0
400
0
    /* 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
0
                                       must keep derSignedCrl until it
412
0
                                       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
0
424
0
    /* 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
0
431
0
    /* 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
0
            /* 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
0
446
0
            if (PR_TRUE == extended->partial) {
447
0
                /* partial decoding, don't verify entries */
448
0
                break;
449
0
            }
450
0
451
0
            rv = cert_check_crl_entries(&crl->crl);
452
0
            if (rv != SECSuccess) {
453
0
                extended->badExtensions = PR_TRUE;
454
0
            }
455
0
456
0
            break;
457
0
458
0
        default:
459
0
            PORT_SetError(SEC_ERROR_INVALID_ARGS);
460
0
            rv = SECFailure;
461
0
            break;
462
0
    }
463
0
464
0
    if (rv != SECSuccess) {
465
0
        goto loser;
466
0
    }
467
0
468
0
    crl->referenceCount = 1;
469
0
470
0
    return (crl);
471
0
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
0
483
0
    if ((narena == NULL) && arena) {
484
0
        PORT_FreeArena(arena, PR_FALSE);
485
0
    }
486
0
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
0
526
0
    PORT_Assert(decoded);
527
0
    if (!decoded) {
528
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
529
0
        return SECFailure;
530
0
    }
531
0
532
0
    derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
533
0
    if (derCrl == NULL) {
534
0
        /* if we had a problem other than the CRL just didn't exist, return
535
0
         * 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
0
    /* PK11_FindCrlByName obtained a slot reference. */
544
0
545
0
    /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
546
0
       Force adoption of the DER CRL from the heap - this will cause it
547
0
       to be automatically freed when SEC_DestroyCrl is invoked */
548
0
    decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
549
0
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
0
563
0
    if (url) {
564
0
        PORT_Free(url);
565
0
    }
566
0
567
0
    if (slot) {
568
0
        PK11_FreeSlot(slot);
569
0
    }
570
0
571
0
loser:
572
0
    if (derCrl) {
573
0
        SECITEM_FreeItem(derCrl, PR_TRUE);
574
0
    }
575
0
576
0
    *decoded = crl;
577
0
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
0
589
0
    PORT_Assert(newCrl);
590
0
    PORT_Assert(derCrl);
591
0
    PORT_Assert(type == SEC_CRL_TYPE);
592
0
593
0
    if (type != SEC_CRL_TYPE) {
594
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
595
0
        return NULL;
596
0
    }
597
0
598
0
    /* we can't use the cache here because we must look in the same
599
0
       token */
600
0
    (void)SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type, &oldCrl,
601
0
                                 CRL_DECODE_SKIP_ENTRIES);
602
0
    /* if there is an old crl on the token, make sure the one we are
603
0
       installing is newer. If not, exit out, otherwise delete the
604
0
       old crl.
605
0
     */
606
0
    if (oldCrl != NULL) {
607
0
        /* 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
0
623
0
        /* 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
0
628
0
        /* really destroy this crl */
629
0
        /* first drum it out of the permanment Data base */
630
0
        deleteOldCrl = PR_TRUE;
631
0
    }
632
0
633
0
    /* invalidate CRL cache for this issuer */
634
0
    CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
635
0
    /* 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
0
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
0
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
0
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
0
685
0
    /* create a scratch arena */
686
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
687
0
    if (arena == NULL) {
688
0
        return (NULL);
689
0
    }
690
0
691
0
    /* 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
0
697
0
    /* find the crl */
698
0
    crl = SEC_FindCrlByName(handle, &crlKey, type);
699
0
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
0
744
0
    *nodes = NULL;
745
0
746
0
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
747
0
    if (arena == NULL) {
748
0
        return SECFailure;
749
0
    }
750
0
751
0
    /* 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
0
758
0
    /* Look up the proper crl types */
759
0
    *nodes = head;
760
0
761
0
    rv = PK11_LookupCrls(head, type, NULL);
762
0
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
0
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
0
        /* no allocator, or buffer full */
862
0
        return NULL;
863
0
    }
864
0
    if (size > (alloc->len - alloc->used)) {
865
0
        /* initial buffer full, let's use the arena */
866
0
        alloc->extra += size;
867
0
        return PORT_ArenaAlloc(alloc->arena, size);
868
0
    }
869
0
    /* 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
0
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
0
{
963
0
    if (PR_FALSE == crlcache_initialized) {
964
0
        PORT_Assert(NULL == crlcache.lock);
965
0
        PORT_Assert(NULL == crlcache.issuers);
966
0
        PORT_Assert(NULL == namedCRLCache.lock);
967
0
        PORT_Assert(NULL == namedCRLCache.entries);
968
0
        if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
969
0
            namedCRLCache.entries) {
970
0
            /* 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
0
        crlcache.lock = PR_NewLock();
978
0
#endif
979
0
        namedCRLCache.lock = PR_NewLock();
980
0
        crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
981
0
                                           PL_CompareValues, NULL, NULL);
982
0
        namedCRLCache.entries = PL_NewHashTable(
983
0
            0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, NULL, NULL);
984
0
        if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
985
0
            !namedCRLCache.entries) {
986
0
            if (crlcache.lock) {
987
#ifdef GLOBAL_RWLOCK
988
                NSSRWLock_Destroy(crlcache.lock);
989
#else
990
                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
0
1007
0
            return SECFailure;
1008
0
        }
1009
0
        crlcache_initialized = PR_TRUE;
1010
0
        return SECSuccess;
1011
0
    } else {
1012
0
        PORT_Assert(crlcache.lock);
1013
0
        PORT_Assert(crlcache.issuers);
1014
0
        if ((NULL == crlcache.lock) || (NULL == crlcache.issuers)) {
1015
0
            /* CRL cache not fully initialized */
1016
0
            return SECFailure;
1017
0
        } else {
1018
0
            /* CRL cache already initialized */
1019
0
            return SECSuccess;
1020
0
        }
1021
0
    }
1022
0
}
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
0
    /* 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
0
    /* free the array of CRLs */
1053
0
    if (cache->crls) {
1054
0
        PORT_Free(cache->crls);
1055
0
    }
1056
0
    /* destroy the cert */
1057
0
    if (cache->issuerDERCert) {
1058
0
        SECITEM_FreeItem(cache->issuerDERCert, PR_TRUE);
1059
0
    }
1060
0
    /* free the subject */
1061
0
    if (cache->subject) {
1062
0
        SECITEM_FreeItem(cache->subject, PR_TRUE);
1063
0
    }
1064
0
    /* 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
0
        /* 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
0
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
0
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
0
        /* 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
0
        /* CRL cache has partially been shut down */
1213
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1214
0
        return SECFailure;
1215
0
    }
1216
0
    /* empty the CRL cache */
1217
0
    /* free the issuers */
1218
0
    PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
1219
0
    /* free the hash table of issuers */
1220
0
    PL_HashTableDestroy(crlcache.issuers);
1221
0
    crlcache.issuers = NULL;
1222
0
/* free the global lock */
1223
#ifdef GLOBAL_RWLOCK
1224
    NSSRWLock_Destroy(crlcache.lock);
1225
#else
1226
    PR_DestroyLock(crlcache.lock);
1227
0
#endif
1228
0
    crlcache.lock = NULL;
1229
0
1230
0
    /* empty the named CRL cache. This must be done after freeing the CRL
1231
0
     * cache, since some CRLs in this cache are in the memory for the other  */
1232
0
    /* free the entries */
1233
0
    PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
1234
0
    /* free the hash table of issuers */
1235
0
    PL_HashTableDestroy(namedCRLCache.entries);
1236
0
    namedCRLCache.entries = NULL;
1237
0
    /* free the global lock */
1238
0
    PR_DestroyLock(namedCRLCache.lock);
1239
0
    namedCRLCache.lock = NULL;
1240
0
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
0
1260
0
    *added = PR_FALSE;
1261
0
    /* 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
0
            /* dupe */
1283
0
            PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
1284
0
            return SECSuccess;
1285
0
        }
1286
0
        if (PR_TRUE == updated) {
1287
0
            /* this token CRL is in the same slot and has the same object ID,
1288
0
               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
0
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
0
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
0
1374
0
    /* query subject and type attributes in order to determine if the
1375
0
       object has been deleted */
1376
0
1377
0
    /* 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
0
1391
0
    arena = NSSArena_Create();
1392
0
    PORT_Assert(arena);
1393
0
    if (!arena) {
1394
0
        return PR_FALSE;
1395
0
    }
1396
0
1397
0
    status =
1398
0
        nssCryptokiCRL_GetAttributes(&instance, NULL,          /* XXX sessionOpt */
1399
0
                                     arena, NULL, &newsubject, /* subject */
1400
0
                                     &crl_class,               /* class */
1401
0
                                     NULL, NULL);
1402
0
    if (PR_SUCCESS == status) {
1403
0
        subject.data = newsubject.data;
1404
0
        subject.len = newsubject.size;
1405
0
        if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual) {
1406
0
            xstatus = PR_FALSE;
1407
0
        }
1408
0
        if (CKO_NETSCAPE_CRL != crl_class) {
1409
0
            xstatus = PR_FALSE;
1410
0
        }
1411
0
    } else {
1412
0
        xstatus = PR_FALSE;
1413
0
    }
1414
0
    NSSArena_Destroy(arena);
1415
0
    return xstatus;
1416
0
}
1417
1418
/* verify the signature of a CRL against its issuer at a given date */
1419
static SECStatus
1420
CERT_VerifyCRL(CERTSignedCrl* crlobject, CERTCertificate* issuer, PRTime vfdate,
1421
               void* wincx)
1422
0
{
1423
0
    return CERT_VerifySignedData(&crlobject->signatureWrap, issuer, vfdate,
1424
0
                                 wincx);
1425
0
}
1426
1427
/* verify a CRL and update cache state */
1428
static SECStatus
1429
CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject, PRTime vfdate,
1430
                 void* wincx)
1431
0
{
1432
0
    /*  Check if it is an invalid CRL
1433
0
        if we got a bad CRL, we want to cache it in order to avoid
1434
0
        subsequent fetches of this same identical bad CRL. We set
1435
0
        the cache to the invalid state to ensure that all certs on this
1436
0
        DP are considered to have unknown status from now on. The cache
1437
0
        object will remain in this state until the bad CRL object
1438
0
        is removed from the token it was fetched from. If the cause
1439
0
        of the failure is that we didn't have the issuer cert to
1440
0
        verify the signature, this state can be cleared when
1441
0
        the issuer certificate becomes available if that causes the
1442
0
        signature to verify */
1443
0
1444
0
    if (!cache || !crlobject) {
1445
0
        PORT_Assert(0);
1446
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1447
0
        return SECFailure;
1448
0
    }
1449
0
    if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError) {
1450
0
        crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
1451
0
            with bogus DER. Mark it checked so we won't try again */
1452
0
        PORT_SetError(SEC_ERROR_BAD_DER);
1453
0
        return SECSuccess;
1454
0
    } else {
1455
0
        SECStatus signstatus = SECFailure;
1456
0
        if (cache->issuerDERCert) {
1457
0
            CERTCertificate* issuer = CERT_NewTempCertificate(
1458
0
                cache->dbHandle, cache->issuerDERCert, NULL, PR_FALSE, PR_TRUE);
1459
0
1460
0
            if (issuer) {
1461
0
                signstatus =
1462
0
                    CERT_VerifyCRL(crlobject->crl, issuer, vfdate, wincx);
1463
0
                CERT_DestroyCertificate(issuer);
1464
0
            }
1465
0
        }
1466
0
        if (SECSuccess != signstatus) {
1467
0
            if (!cache->issuerDERCert) {
1468
0
                /* we tried to verify without an issuer cert . This is
1469
0
                   because this CRL came through a call to SEC_FindCrlByName.
1470
0
                   So, we don't cache this verification failure. We'll try
1471
0
                   to verify the CRL again when a certificate from that issuer
1472
0
                   becomes available */
1473
0
            } else {
1474
0
                crlobject->sigChecked = PR_TRUE;
1475
0
            }
1476
0
            PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
1477
0
            return SECSuccess;
1478
0
        } else {
1479
0
            crlobject->sigChecked = PR_TRUE;
1480
0
            crlobject->sigValid = PR_TRUE;
1481
0
        }
1482
0
    }
1483
0
1484
0
    return SECSuccess;
1485
0
}
1486
1487
/* fetch the CRLs for this DP from the PKCS#11 tokens */
1488
static SECStatus
1489
DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx)
1490
0
{
1491
0
    SECStatus rv = SECSuccess;
1492
0
    CERTCrlHeadNode head;
1493
0
    if (!cache) {
1494
0
        PORT_Assert(0);
1495
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1496
0
        return SECFailure;
1497
0
    }
1498
0
    /* first, initialize list */
1499
0
    memset(&head, 0, sizeof(head));
1500
0
    head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1501
0
    rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
1502
0
1503
0
    /* if this function fails, something very wrong happened, such as an out
1504
0
       of memory error during CRL decoding. We don't want to proceed and must
1505
0
       mark the cache object invalid */
1506
0
    if (SECFailure == rv) {
1507
0
        /* fetch failed, add error bit */
1508
0
        cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1509
0
    } else {
1510
0
        /* fetch was successful, clear this error bit */
1511
0
        cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
1512
0
    }
1513
0
1514
0
    /* add any CRLs found to our array */
1515
0
    if (SECSuccess == rv) {
1516
0
        CERTCrlNode* crlNode = NULL;
1517
0
1518
0
        for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1519
0
            CachedCrl* returned = NULL;
1520
0
            CERTSignedCrl* crlobject = crlNode->crl;
1521
0
            if (!crlobject) {
1522
0
                PORT_Assert(0);
1523
0
                continue;
1524
0
            }
1525
0
            rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
1526
0
            if (SECSuccess == rv) {
1527
0
                PRBool added = PR_FALSE;
1528
0
                rv = DPCache_AddCRL(cache, returned, &added);
1529
0
                if (PR_TRUE != added) {
1530
0
                    rv = CachedCrl_Destroy(returned);
1531
0
                    returned = NULL;
1532
0
                } else if (vfdate) {
1533
0
                    rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
1534
0
                }
1535
0
            } else {
1536
0
                /* not enough memory to add the CRL to the cache. mark it
1537
0
                   invalid so we will try again . */
1538
0
                cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1539
0
            }
1540
0
            if (SECFailure == rv) {
1541
0
                break;
1542
0
            }
1543
0
        }
1544
0
    }
1545
0
1546
0
    if (head.arena) {
1547
0
        CERTCrlNode* crlNode = NULL;
1548
0
        /* clean up the CRL list in case we got a partial one
1549
0
           during a failed fetch */
1550
0
        for (crlNode = head.first; crlNode; crlNode = crlNode->next) {
1551
0
            if (crlNode->crl) {
1552
0
                SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
1553
0
                   added to the cache and the refcount got bumped, or not, and
1554
0
                   thus we need to free its RAM */
1555
0
            }
1556
0
        }
1557
0
        PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
1558
0
    }
1559
0
1560
0
    return rv;
1561
0
}
1562
1563
static SECStatus
1564
CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn, CERTCrlEntry** returned)
1565
0
{
1566
0
    CERTCrlEntry* acrlEntry;
1567
0
1568
0
    PORT_Assert(crl);
1569
0
    PORT_Assert(crl->entries);
1570
0
    PORT_Assert(sn);
1571
0
    PORT_Assert(returned);
1572
0
    if (!crl || !sn || !returned || !crl->entries) {
1573
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1574
0
        return SECFailure;
1575
0
    }
1576
0
    acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
1577
0
    if (acrlEntry) {
1578
0
        *returned = acrlEntry;
1579
0
    } else {
1580
0
        *returned = NULL;
1581
0
    }
1582
0
    return SECSuccess;
1583
0
}
1584
1585
/* check if a particular SN is in the CRL cache and return its entry */
1586
dpcacheStatus
1587
DPCache_Lookup(CRLDPCache* cache, const SECItem* sn, CERTCrlEntry** returned)
1588
0
{
1589
0
    SECStatus rv;
1590
0
    if (!cache || !sn || !returned) {
1591
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
1592
0
        /* no cache or SN to look up, or no way to return entry */
1593
0
        return dpcacheCallerError;
1594
0
    }
1595
0
    *returned = NULL;
1596
0
    if (0 != cache->invalid) {
1597
0
        /* the cache contains a bad CRL, or there was a CRL fetching error. */
1598
0
        PORT_SetError(SEC_ERROR_CRL_INVALID);
1599
0
        return dpcacheInvalidCacheError;
1600
0
    }
1601
0
    if (!cache->selected) {
1602
0
        /* no CRL means no entry to return. This is OK, except for
1603
0
         * NIST policy */
1604
0
        return dpcacheEmpty;
1605
0
    }
1606
0
    rv = CachedCrl_GetEntry(cache->selected, sn, returned);
1607
0
    if (SECSuccess != rv) {
1608
0
        return dpcacheLookupError;
1609
0
    } else {
1610
0
        if (*returned) {
1611
0
            return dpcacheFoundEntry;
1612
0
        } else {
1613
0
            return dpcacheNoEntry;
1614
0
        }
1615
0
    }
1616
0
}
1617
1618
#if defined(DPC_RWLOCK)
1619
1620
#define DPCache_LockWrite()                    \
1621
0
    {                                          \
1622
0
        if (readlocked) {                      \
1623
0
            NSSRWLock_UnlockRead(cache->lock); \
1624
0
        }                                      \
1625
0
        NSSRWLock_LockWrite(cache->lock);      \
1626
0
    }
1627
1628
#define DPCache_UnlockWrite()                \
1629
0
    {                                        \
1630
0
        if (readlocked) {                    \
1631
0
            NSSRWLock_LockRead(cache->lock); \
1632
0
        }                                    \
1633
0
        NSSRWLock_UnlockWrite(cache->lock);  \
1634
0
    }
1635
1636
#else
1637
1638
/* with a global lock, we are always locked for read before we need write
1639
   access, so do nothing */
1640
1641
#define DPCache_LockWrite() \
1642
    {                       \
1643
    }
1644
1645
#define DPCache_UnlockWrite() \
1646
    {                         \
1647
    }
1648
1649
#endif
1650
1651
/* update the content of the CRL cache, including fetching of CRLs, and
1652
   reprocessing with specified issuer and date . We are always holding
1653
   either the read or write lock on DPCache upon entry. */
1654
static SECStatus
1655
DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
1656
                    PRBool readlocked, PRTime vfdate, void* wincx)
1657
0
{
1658
0
    /* Update the CRLDPCache now. We don't cache token CRL lookup misses
1659
0
       yet, as we have no way of getting notified of new PKCS#11 object
1660
0
       creation that happens in a token  */
1661
0
    SECStatus rv = SECSuccess;
1662
0
    PRUint32 i = 0;
1663
0
    PRBool forcedrefresh = PR_FALSE;
1664
0
    PRBool dirty = PR_FALSE; /* whether something was changed in the
1665
0
                                cache state during this update cycle */
1666
0
    PRBool hastokenCRLs = PR_FALSE;
1667
0
    PRTime now = 0;
1668
0
    PRTime lastfetch = 0;
1669
0
    PRBool mustunlock = PR_FALSE;
1670
0
1671
0
    if (!cache) {
1672
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1673
0
        return SECFailure;
1674
0
    }
1675
0
1676
0
    /* first, make sure we have obtained all the CRLs we need.
1677
0
       We do an expensive token fetch in the following cases :
1678
0
       1) cache is empty because no fetch was ever performed yet
1679
0
       2) cache is explicitly set to refresh state
1680
0
       3) cache is in invalid state because last fetch failed
1681
0
       4) cache contains no token CRLs, and it's been more than one minute
1682
0
          since the last fetch
1683
0
       5) cache contains token CRLs, and it's been more than 10 minutes since
1684
0
          the last fetch
1685
0
    */
1686
0
    forcedrefresh = cache->refresh;
1687
0
    lastfetch = cache->lastfetch;
1688
0
    if (PR_TRUE != forcedrefresh &&
1689
0
        (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED))) {
1690
0
        now = PR_Now();
1691
0
        hastokenCRLs = DPCache_HasTokenCRLs(cache);
1692
0
    }
1693
0
    if ((0 == lastfetch) ||
1694
0
1695
0
        (PR_TRUE == forcedrefresh) ||
1696
0
1697
0
        (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
1698
0
1699
0
        ((PR_FALSE == hastokenCRLs) &&
1700
0
         ((now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
1701
0
          (now < cache->lastfetch))) ||
1702
0
1703
0
        ((PR_TRUE == hastokenCRLs) &&
1704
0
         ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
1705
0
          (now < cache->lastfetch)))) {
1706
0
        /* the cache needs to be refreshed, and/or we had zero CRL for this
1707
0
           DP. Try to get one from PKCS#11 tokens */
1708
0
        DPCache_LockWrite();
1709
0
        /* check if another thread updated before us, and skip update if so */
1710
0
        if (lastfetch == cache->lastfetch) {
1711
0
            /* we are the first */
1712
0
            rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
1713
0
            if (PR_TRUE == cache->refresh) {
1714
0
                cache->refresh = PR_FALSE; /* clear refresh state */
1715
0
            }
1716
0
            dirty = PR_TRUE;
1717
0
            cache->lastfetch = PR_Now();
1718
0
        }
1719
0
        DPCache_UnlockWrite();
1720
0
    }
1721
0
1722
0
    /* now, make sure we have no extraneous CRLs (deleted token objects)
1723
0
       we'll do this inexpensive existence check either
1724
0
       1) if there was a token object fetch
1725
0
       2) every minute */
1726
0
    if ((PR_TRUE != dirty) && (!now)) {
1727
0
        now = PR_Now();
1728
0
    }
1729
0
    if ((PR_TRUE == dirty) ||
1730
0
        ((now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
1731
0
         (now < cache->lastcheck))) {
1732
0
        PRTime lastcheck = cache->lastcheck;
1733
0
        mustunlock = PR_FALSE;
1734
0
        /* check if all CRLs still exist */
1735
0
        for (i = 0; (i < cache->ncrls); i++) {
1736
0
            CachedCrl* savcrl = cache->crls[i];
1737
0
            if ((!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin)) {
1738
0
                /* we only want to check token CRLs */
1739
0
                continue;
1740
0
            }
1741
0
            if ((PR_TRUE != TokenCRLStillExists(savcrl->crl))) {
1742
0
1743
0
                /* this CRL is gone */
1744
0
                if (PR_TRUE != mustunlock) {
1745
0
                    DPCache_LockWrite();
1746
0
                    mustunlock = PR_TRUE;
1747
0
                }
1748
0
                /* first, we need to check if another thread did an update
1749
0
                   before we did */
1750
0
                if (lastcheck == cache->lastcheck) {
1751
0
                    /* the CRL is gone. And we are the one to do the update */
1752
0
                    DPCache_RemoveCRL(cache, i);
1753
0
                    dirty = PR_TRUE;
1754
0
                }
1755
0
                /* stay locked here intentionally so we do all the other
1756
0
                   updates in this thread for the remaining CRLs */
1757
0
            }
1758
0
        }
1759
0
        if (PR_TRUE == mustunlock) {
1760
0
            cache->lastcheck = PR_Now();
1761
0
            DPCache_UnlockWrite();
1762
0
            mustunlock = PR_FALSE;
1763
0
        }
1764
0
    }
1765
0
1766
0
    /* add issuer certificate if it was previously unavailable */
1767
0
    if (issuer && (NULL == cache->issuerDERCert) &&
1768
0
        (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN))) {
1769
0
        /* if we didn't have a valid issuer cert yet, but we do now. add it */
1770
0
        DPCache_LockWrite();
1771
0
        if (!cache->issuerDERCert) {
1772
0
            dirty = PR_TRUE;
1773
0
            cache->dbHandle = issuer->dbhandle;
1774
0
            cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert);
1775
0
        }
1776
0
        DPCache_UnlockWrite();
1777
0
    }
1778
0
1779
0
    /* verify CRLs that couldn't be checked when inserted into the cache
1780
0
       because the issuer cert or a verification date was unavailable.
1781
0
       These are CRLs that were inserted into the cache through
1782
0
       SEC_FindCrlByName, or through manual insertion, rather than through a
1783
0
       certificate verification (CERT_CheckCRL) */
1784
0
1785
0
    if (cache->issuerDERCert && vfdate) {
1786
0
        mustunlock = PR_FALSE;
1787
0
        /* re-process all unverified CRLs */
1788
0
        for (i = 0; i < cache->ncrls; i++) {
1789
0
            CachedCrl* savcrl = cache->crls[i];
1790
0
            if (!savcrl) {
1791
0
                continue;
1792
0
            }
1793
0
            if (PR_TRUE != savcrl->sigChecked) {
1794
0
                if (!mustunlock) {
1795
0
                    DPCache_LockWrite();
1796
0
                    mustunlock = PR_TRUE;
1797
0
                }
1798
0
                /* first, we need to check if another thread updated
1799
0
                   it before we did, and abort if it has been modified since
1800
0
                   we acquired the lock. Make sure first that the CRL is still
1801
0
                   in the array at the same position */
1802
0
                if ((i < cache->ncrls) && (savcrl == cache->crls[i]) &&
1803
0
                    (PR_TRUE != savcrl->sigChecked)) {
1804
0
                    /* the CRL is still there, unverified. Do it */
1805
0
                    CachedCrl_Verify(cache, savcrl, vfdate, wincx);
1806
0
                    dirty = PR_TRUE;
1807
0
                }
1808
0
                /* stay locked here intentionally so we do all the other
1809
0
                   updates in this thread for the remaining CRLs */
1810
0
            }
1811
0
            if (mustunlock && !dirty) {
1812
0
                DPCache_UnlockWrite();
1813
0
                mustunlock = PR_FALSE;
1814
0
            }
1815
0
        }
1816
0
    }
1817
0
1818
0
    if (dirty || cache->mustchoose) {
1819
0
        /* changes to the content of the CRL cache necessitate examining all
1820
0
           CRLs for selection of the most appropriate one to cache */
1821
0
        if (!mustunlock) {
1822
0
            DPCache_LockWrite();
1823
0
            mustunlock = PR_TRUE;
1824
0
        }
1825
0
        DPCache_SelectCRL(cache);
1826
0
        cache->mustchoose = PR_FALSE;
1827
0
    }
1828
0
    if (mustunlock)
1829
0
        DPCache_UnlockWrite();
1830
0
1831
0
    return rv;
1832
0
}
1833
1834
/* callback for qsort to sort by thisUpdate */
1835
static int
1836
SortCRLsByThisUpdate(const void* arg1, const void* arg2)
1837
0
{
1838
0
    PRTime timea, timeb;
1839
0
    SECStatus rv = SECSuccess;
1840
0
    CachedCrl *a, *b;
1841
0
1842
0
    a = *(CachedCrl**)arg1;
1843
0
    b = *(CachedCrl**)arg2;
1844
0
1845
0
    if (!a || !b) {
1846
0
        PORT_Assert(0);
1847
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1848
0
        rv = SECFailure;
1849
0
    }
1850
0
1851
0
    if (SECSuccess == rv) {
1852
0
        rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
1853
0
    }
1854
0
    if (SECSuccess == rv) {
1855
0
        rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
1856
0
    }
1857
0
    if (SECSuccess == rv) {
1858
0
        if (timea > timeb) {
1859
0
            return 1; /* a is better than b */
1860
0
        }
1861
0
        if (timea < timeb) {
1862
0
            return -1; /* a is not as good as b */
1863
0
        }
1864
0
    }
1865
0
1866
0
    /* if they are equal, or if all else fails, use pointer differences */
1867
0
    PORT_Assert(a != b); /* they should never be equal */
1868
0
    return a > b ? 1 : -1;
1869
0
}
1870
1871
/* callback for qsort to sort a set of disparate CRLs, some of which are
1872
   invalid DER or failed signature check.
1873
1874
   Validated CRLs are differentiated by thisUpdate .
1875
   Validated CRLs are preferred over non-validated CRLs .
1876
   Proper DER CRLs are preferred over non-DER data .
1877
*/
1878
static int
1879
SortImperfectCRLs(const void* arg1, const void* arg2)
1880
0
{
1881
0
    CachedCrl *a, *b;
1882
0
1883
0
    a = *(CachedCrl**)arg1;
1884
0
    b = *(CachedCrl**)arg2;
1885
0
1886
0
    if (!a || !b) {
1887
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1888
0
        PORT_Assert(0);
1889
0
    } else {
1890
0
        PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
1891
0
        if ((PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid)) {
1892
0
            /* both CRLs have been validated, choose the latest one */
1893
0
            return SortCRLsByThisUpdate(arg1, arg2);
1894
0
        }
1895
0
        if (PR_TRUE == a->sigValid) {
1896
0
            return 1; /* a is greater than b */
1897
0
        }
1898
0
        if (PR_TRUE == b->sigValid) {
1899
0
            return -1; /* a is not as good as b */
1900
0
        }
1901
0
        aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
1902
0
        bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
1903
0
        /* neither CRL had its signature check pass */
1904
0
        if ((PR_FALSE == aDecoded) && (PR_FALSE == bDecoded)) {
1905
0
            /* both CRLs are proper DER, choose the latest one */
1906
0
            return SortCRLsByThisUpdate(arg1, arg2);
1907
0
        }
1908
0
        if (PR_FALSE == aDecoded) {
1909
0
            return 1; /* a is better than b */
1910
0
        }
1911
0
        if (PR_FALSE == bDecoded) {
1912
0
            return -1; /* a is not as good as b */
1913
0
        }
1914
0
        /* both are invalid DER. sigh. */
1915
0
    }
1916
0
    /* if they are equal, or if all else fails, use pointer differences */
1917
0
    PORT_Assert(a != b); /* they should never be equal */
1918
0
    return a > b ? 1 : -1;
1919
0
}
1920
1921
/* Pick best CRL to use . needs write access */
1922
static SECStatus
1923
DPCache_SelectCRL(CRLDPCache* cache)
1924
0
{
1925
0
    PRUint32 i;
1926
0
    PRBool valid = PR_TRUE;
1927
0
    CachedCrl* selected = NULL;
1928
0
1929
0
    PORT_Assert(cache);
1930
0
    if (!cache) {
1931
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1932
0
        return SECFailure;
1933
0
    }
1934
0
    /* if any invalid CRL is present, then the CRL cache is
1935
0
       considered invalid, for security reasons */
1936
0
    for (i = 0; i < cache->ncrls; i++) {
1937
0
        if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
1938
0
            !cache->crls[i]->sigValid) {
1939
0
            valid = PR_FALSE;
1940
0
            break;
1941
0
        }
1942
0
    }
1943
0
    if (PR_TRUE == valid) {
1944
0
        /* all CRLs are valid, clear this error */
1945
0
        cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
1946
0
    } else {
1947
0
        /* some CRLs are invalid, set this error */
1948
0
        cache->invalid |= CRL_CACHE_INVALID_CRLS;
1949
0
    }
1950
0
1951
0
    if (cache->invalid) {
1952
0
        /* cache is in an invalid state, so reset it */
1953
0
        if (cache->selected) {
1954
0
            cache->selected = NULL;
1955
0
        }
1956
0
        /* also sort the CRLs imperfectly */
1957
0
        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortImperfectCRLs);
1958
0
        return SECSuccess;
1959
0
    }
1960
0
1961
0
    if (cache->ncrls) {
1962
0
        /* all CRLs are good, sort them by thisUpdate */
1963
0
        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*), SortCRLsByThisUpdate);
1964
0
1965
0
        /* pick the newest CRL */
1966
0
        selected = cache->crls[cache->ncrls - 1];
1967
0
1968
0
        /* and populate the cache */
1969
0
        if (SECSuccess != CachedCrl_Populate(selected)) {
1970
0
            return SECFailure;
1971
0
        }
1972
0
    }
1973
0
1974
0
    cache->selected = selected;
1975
0
1976
0
    return SECSuccess;
1977
0
}
1978
1979
/* initialize a DPCache object */
1980
static SECStatus
1981
DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
1982
               const SECItem* subject, SECItem* dp)
1983
0
{
1984
0
    CRLDPCache* cache = NULL;
1985
0
    PORT_Assert(returned);
1986
0
    /* issuer and dp are allowed to be NULL */
1987
0
    if (!returned || !subject) {
1988
0
        PORT_Assert(0);
1989
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1990
0
        return SECFailure;
1991
0
    }
1992
0
    *returned = NULL;
1993
0
    cache = PORT_ZAlloc(sizeof(CRLDPCache));
1994
0
    if (!cache) {
1995
0
        return SECFailure;
1996
0
    }
1997
0
#ifdef DPC_RWLOCK
1998
0
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
1999
#else
2000
    cache->lock = PR_NewLock();
2001
#endif
2002
0
    if (!cache->lock) {
2003
0
        PORT_Free(cache);
2004
0
        return SECFailure;
2005
0
    }
2006
0
    if (issuer) {
2007
0
        cache->dbHandle = issuer->dbhandle;
2008
0
        cache->issuerDERCert = SECITEM_DupItem(&issuer->derCert);
2009
0
    }
2010
0
    cache->distributionPoint = SECITEM_DupItem(dp);
2011
0
    cache->subject = SECITEM_DupItem(subject);
2012
0
    cache->lastfetch = 0;
2013
0
    cache->lastcheck = 0;
2014
0
    *returned = cache;
2015
0
    return SECSuccess;
2016
0
}
2017
2018
/* create an issuer cache object (per CA subject ) */
2019
static SECStatus
2020
IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer,
2021
                   const SECItem* subject, const SECItem* dp)
2022
0
{
2023
0
    SECStatus rv = SECSuccess;
2024
0
    CRLIssuerCache* cache = NULL;
2025
0
    PORT_Assert(returned);
2026
0
    PORT_Assert(subject);
2027
0
    /* issuer and dp are allowed to be NULL */
2028
0
    if (!returned || !subject) {
2029
0
        PORT_Assert(0);
2030
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2031
0
        return SECFailure;
2032
0
    }
2033
0
    *returned = NULL;
2034
0
    cache = (CRLIssuerCache*)PORT_ZAlloc(sizeof(CRLIssuerCache));
2035
0
    if (!cache) {
2036
0
        return SECFailure;
2037
0
    }
2038
0
    cache->subject = SECITEM_DupItem(subject);
2039
#ifdef XCRL
2040
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2041
    if (!cache->lock) {
2042
        rv = SECFailure;
2043
    }
2044
    if (SECSuccess == rv && issuer) {
2045
        cache->issuer = CERT_DupCertificate(issuer);
2046
        if (!cache->issuer) {
2047
            rv = SECFailure;
2048
        }
2049
    }
2050
#endif
2051
0
    if (SECSuccess != rv) {
2052
0
        PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
2053
0
        return SECFailure;
2054
0
    }
2055
0
    *returned = cache;
2056
0
    return SECSuccess;
2057
0
}
2058
2059
/* add a DPCache to the issuer cache */
2060
static SECStatus
2061
IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
2062
                  const SECItem* subject, const SECItem* dp,
2063
                  CRLDPCache** newdpc)
2064
0
{
2065
0
    /* now create the required DP cache object */
2066
0
    if (!cache || !subject || !newdpc) {
2067
0
        PORT_Assert(0);
2068
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2069
0
        return SECFailure;
2070
0
    }
2071
0
    if (!dp) {
2072
0
        /* default distribution point */
2073
0
        SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
2074
0
        if (SECSuccess == rv) {
2075
0
            *newdpc = cache->dpp;
2076
0
            return SECSuccess;
2077
0
        }
2078
0
    } else {
2079
0
        /* we should never hit this until we support multiple DPs */
2080
0
        PORT_Assert(dp);
2081
0
        /* XCRL allocate a new distribution point cache object, initialize it,
2082
0
           and add it to the hash table of DPs */
2083
0
    }
2084
0
    return SECFailure;
2085
0
}
2086
2087
/* add an IssuerCache to the global hash table of issuers */
2088
static SECStatus
2089
CRLCache_AddIssuer(CRLIssuerCache* issuer)
2090
0
{
2091
0
    PORT_Assert(issuer);
2092
0
    PORT_Assert(crlcache.issuers);
2093
0
    if (!issuer || !crlcache.issuers) {
2094
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2095
0
        return SECFailure;
2096
0
    }
2097
0
    if (NULL == PL_HashTableAdd(crlcache.issuers, (void*)issuer->subject,
2098
0
                                (void*)issuer)) {
2099
0
        return SECFailure;
2100
0
    }
2101
0
    return SECSuccess;
2102
0
}
2103
2104
/* retrieve the issuer cache object for a given issuer subject */
2105
static SECStatus
2106
CRLCache_GetIssuerCache(CRLCache* cache, const SECItem* subject,
2107
                        CRLIssuerCache** returned)
2108
0
{
2109
0
    /* we need to look up the issuer in the hash table */
2110
0
    SECStatus rv = SECSuccess;
2111
0
    PORT_Assert(cache);
2112
0
    PORT_Assert(subject);
2113
0
    PORT_Assert(returned);
2114
0
    PORT_Assert(crlcache.issuers);
2115
0
    if (!cache || !subject || !returned || !crlcache.issuers) {
2116
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2117
0
        rv = SECFailure;
2118
0
    }
2119
0
2120
0
    if (SECSuccess == rv) {
2121
0
        *returned = (CRLIssuerCache*)PL_HashTableLookup(crlcache.issuers,
2122
0
                                                        (void*)subject);
2123
0
    }
2124
0
2125
0
    return rv;
2126
0
}
2127
2128
/* retrieve the full CRL object that best matches the content of a DPCache */
2129
static CERTSignedCrl*
2130
GetBestCRL(CRLDPCache* cache, PRBool entries)
2131
0
{
2132
0
    CachedCrl* acrl = NULL;
2133
0
2134
0
    PORT_Assert(cache);
2135
0
    if (!cache) {
2136
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2137
0
        return NULL;
2138
0
    }
2139
0
2140
0
    if (0 == cache->ncrls) {
2141
0
        /* empty cache*/
2142
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2143
0
        return NULL;
2144
0
    }
2145
0
2146
0
    /* if we have a valid full CRL selected, return it */
2147
0
    if (cache->selected) {
2148
0
        return SEC_DupCrl(cache->selected->crl);
2149
0
    }
2150
0
2151
0
    /* otherwise, use latest valid DER CRL */
2152
0
    acrl = cache->crls[cache->ncrls - 1];
2153
0
2154
0
    if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError)) {
2155
0
        SECStatus rv = SECSuccess;
2156
0
        if (PR_TRUE == entries) {
2157
0
            rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
2158
0
        }
2159
0
        if (SECSuccess == rv) {
2160
0
            return SEC_DupCrl(acrl->crl);
2161
0
        }
2162
0
    }
2163
0
2164
0
    PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2165
0
    return NULL;
2166
0
}
2167
2168
/* get a particular DPCache object from an IssuerCache */
2169
static CRLDPCache*
2170
IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
2171
0
{
2172
0
    CRLDPCache* dpp = NULL;
2173
0
    PORT_Assert(cache);
2174
0
    /* XCRL for now we only support the "default" DP, ie. the
2175
0
       full CRL. So we can return the global one without locking. In
2176
0
       the future we will have a lock */
2177
0
    PORT_Assert(NULL == dp);
2178
0
    if (!cache || dp) {
2179
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2180
0
        return NULL;
2181
0
    }
2182
#ifdef XCRL
2183
    NSSRWLock_LockRead(cache->lock);
2184
#endif
2185
0
    dpp = cache->dpp;
2186
#ifdef XCRL
2187
    NSSRWLock_UnlockRead(cache->lock);
2188
#endif
2189
    return dpp;
2190
0
}
2191
2192
/* get a DPCache object for the given issuer subject and dp
2193
   Automatically creates the cache object if it doesn't exist yet.
2194
   */
2195
SECStatus
2196
AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
2197
               const SECItem* dp, PRTime t, void* wincx, CRLDPCache** dpcache,
2198
               PRBool* writeLocked)
2199
0
{
2200
0
    SECStatus rv = SECSuccess;
2201
0
    CRLIssuerCache* issuercache = NULL;
2202
#ifdef GLOBAL_RWLOCK
2203
    PRBool globalwrite = PR_FALSE;
2204
#endif
2205
0
    PORT_Assert(crlcache.lock);
2206
0
    if (!crlcache.lock) {
2207
0
        /* CRL cache is not initialized */
2208
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2209
0
        return SECFailure;
2210
0
    }
2211
#ifdef GLOBAL_RWLOCK
2212
    NSSRWLock_LockRead(crlcache.lock);
2213
#else
2214
0
    PR_Lock(crlcache.lock);
2215
0
#endif
2216
0
    rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
2217
0
    if (SECSuccess != rv) {
2218
#ifdef GLOBAL_RWLOCK
2219
        NSSRWLock_UnlockRead(crlcache.lock);
2220
#else
2221
        PR_Unlock(crlcache.lock);
2222
0
#endif
2223
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2224
0
        return SECFailure;
2225
0
    }
2226
0
    if (!issuercache) {
2227
0
        /* there is no cache for this issuer yet. This means this is the
2228
0
           first time we look up a cert from that issuer, and we need to
2229
0
           create the cache. */
2230
0
2231
0
        rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
2232
0
        if (SECSuccess == rv && !issuercache) {
2233
0
            PORT_Assert(issuercache);
2234
0
            rv = SECFailure;
2235
0
        }
2236
0
2237
0
        if (SECSuccess == rv) {
2238
0
            /* This is the first time we look up a cert of this issuer.
2239
0
               Create the DPCache for this DP . */
2240
0
            rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
2241
0
        }
2242
0
2243
0
        if (SECSuccess == rv) {
2244
0
            /* lock the DPCache for write to ensure the update happens in this
2245
0
               thread */
2246
0
            *writeLocked = PR_TRUE;
2247
0
#ifdef DPC_RWLOCK
2248
0
            NSSRWLock_LockWrite((*dpcache)->lock);
2249
#else
2250
            PR_Lock((*dpcache)->lock);
2251
#endif
2252
        }
2253
0
2254
0
        if (SECSuccess == rv) {
2255
0
/* now add the new issuer cache to the global hash table of
2256
0
   issuers */
2257
#ifdef GLOBAL_RWLOCK
2258
            CRLIssuerCache* existing = NULL;
2259
            NSSRWLock_UnlockRead(crlcache.lock);
2260
            /* when using a r/w lock for the global cache, check if the issuer
2261
               already exists before adding to the hash table */
2262
            NSSRWLock_LockWrite(crlcache.lock);
2263
            globalwrite = PR_TRUE;
2264
            rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
2265
            if (!existing) {
2266
#endif
2267
                rv = CRLCache_AddIssuer(issuercache);
2268
0
                if (SECSuccess != rv) {
2269
0
                    /* failure */
2270
0
                    rv = SECFailure;
2271
0
                }
2272
#ifdef GLOBAL_RWLOCK
2273
            } else {
2274
                /* somebody else updated before we did */
2275
                IssuerCache_Destroy(issuercache); /* destroy the new object */
2276
                issuercache = existing;           /* use the existing one */
2277
                *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2278
            }
2279
#endif
2280
        }
2281
0
2282
0
/* now unlock the global cache. We only want to lock the issuer hash
2283
0
   table addition. Holding it longer would hurt scalability */
2284
#ifdef GLOBAL_RWLOCK
2285
        if (PR_TRUE == globalwrite) {
2286
            NSSRWLock_UnlockWrite(crlcache.lock);
2287
            globalwrite = PR_FALSE;
2288
        } else {
2289
            NSSRWLock_UnlockRead(crlcache.lock);
2290
        }
2291
#else
2292
        PR_Unlock(crlcache.lock);
2293
0
#endif
2294
0
2295
0
        /* if there was a failure adding an issuer cache object, destroy it */
2296
0
        if (SECSuccess != rv && issuercache) {
2297
0
            if (PR_TRUE == *writeLocked) {
2298
0
#ifdef DPC_RWLOCK
2299
0
                NSSRWLock_UnlockWrite((*dpcache)->lock);
2300
#else
2301
                PR_Unlock((*dpcache)->lock);
2302
#endif
2303
            }
2304
0
            IssuerCache_Destroy(issuercache);
2305
0
            issuercache = NULL;
2306
0
        }
2307
0
2308
0
        if (SECSuccess != rv) {
2309
0
            return SECFailure;
2310
0
        }
2311
0
    } else {
2312
#ifdef GLOBAL_RWLOCK
2313
        NSSRWLock_UnlockRead(crlcache.lock);
2314
#else
2315
        PR_Unlock(crlcache.lock);
2316
0
#endif
2317
0
        *dpcache = IssuerCache_GetDPCache(issuercache, dp);
2318
0
    }
2319
0
    /* we now have a DPCache that we can use for lookups */
2320
0
    /* lock it for read, unless we already locked for write */
2321
0
    if (PR_FALSE == *writeLocked) {
2322
0
#ifdef DPC_RWLOCK
2323
0
        NSSRWLock_LockRead((*dpcache)->lock);
2324
#else
2325
        PR_Lock((*dpcache)->lock);
2326
#endif
2327
    }
2328
0
2329
0
    if (SECSuccess == rv) {
2330
0
        /* currently there is always one and only one DPCache per issuer */
2331
0
        PORT_Assert(*dpcache);
2332
0
        if (*dpcache) {
2333
0
            /* make sure the DP cache is up to date before using it */
2334
0
            rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
2335
0
                                     t, wincx);
2336
0
        } else {
2337
0
            rv = SECFailure;
2338
0
        }
2339
0
    }
2340
0
    return rv;
2341
0
}
2342
2343
/* unlock access to the DPCache */
2344
void
2345
ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
2346
0
{
2347
0
    if (!dpcache) {
2348
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2349
0
        return;
2350
0
    }
2351
0
#ifdef DPC_RWLOCK
2352
0
    if (PR_TRUE == writeLocked) {
2353
0
        NSSRWLock_UnlockWrite(dpcache->lock);
2354
0
    } else {
2355
0
        NSSRWLock_UnlockRead(dpcache->lock);
2356
0
    }
2357
#else
2358
    PR_Unlock(dpcache->lock);
2359
#endif
2360
}
2361
2362
SECStatus
2363
cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
2364
                               const SECItem* dp, PRTime t, void* wincx,
2365
                               CERTRevocationStatus* revStatus,
2366
                               CERTCRLEntryReasonCode* revReason)
2367
0
{
2368
0
    PRBool lockedwrite = PR_FALSE;
2369
0
    SECStatus rv = SECSuccess;
2370
0
    CRLDPCache* dpcache = NULL;
2371
0
    CERTRevocationStatus status = certRevocationStatusRevoked;
2372
0
    CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
2373
0
    CERTCrlEntry* entry = NULL;
2374
0
    dpcacheStatus ds;
2375
0
2376
0
    if (!cert || !issuer) {
2377
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2378
0
        return SECFailure;
2379
0
    }
2380
0
2381
0
    if (revStatus) {
2382
0
        *revStatus = status;
2383
0
    }
2384
0
    if (revReason) {
2385
0
        *revReason = reason;
2386
0
    }
2387
0
2388
0
    if (t &&
2389
0
        secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE)) {
2390
0
        /* we won't be able to check the CRL's signature if the issuer cert
2391
0
           is expired as of the time we are verifying. This may cause a valid
2392
0
           CRL to be cached as bad. short-circuit to avoid this case. */
2393
0
        PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
2394
0
        return SECFailure;
2395
0
    }
2396
0
2397
0
    rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
2398
0
                        &lockedwrite);
2399
0
    PORT_Assert(SECSuccess == rv);
2400
0
    if (SECSuccess != rv) {
2401
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2402
0
        return SECFailure;
2403
0
    }
2404
0
    /* now look up the certificate SN in the DP cache's CRL */
2405
0
    ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
2406
0
    switch (ds) {
2407
0
        case dpcacheFoundEntry:
2408
0
            PORT_Assert(entry);
2409
0
            /* check the time if we have one */
2410
0
            if (entry->revocationDate.data && entry->revocationDate.len) {
2411
0
                PRTime revocationDate = 0;
2412
0
                if (SECSuccess ==
2413
0
                    DER_DecodeTimeChoice(&revocationDate,
2414
0
                                         &entry->revocationDate)) {
2415
0
                    /* we got a good revocation date, only consider the
2416
0
                       certificate revoked if the time we are inquiring about
2417
0
                       is past the revocation date */
2418
0
                    if (t >= revocationDate) {
2419
0
                        rv = SECFailure;
2420
0
                    } else {
2421
0
                        status = certRevocationStatusValid;
2422
0
                    }
2423
0
                } else {
2424
0
                    /* invalid revocation date, consider the certificate
2425
0
                       permanently revoked */
2426
0
                    rv = SECFailure;
2427
0
                }
2428
0
            } else {
2429
0
                /* no revocation date, certificate is permanently revoked */
2430
0
                rv = SECFailure;
2431
0
            }
2432
0
            if (SECFailure == rv) {
2433
0
                (void)CERT_FindCRLEntryReasonExten(entry, &reason);
2434
0
                PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
2435
0
            }
2436
0
            break;
2437
0
2438
0
        case dpcacheEmpty:
2439
0
            /* useful for NIST policy */
2440
0
            status = certRevocationStatusUnknown;
2441
0
            break;
2442
0
2443
0
        case dpcacheNoEntry:
2444
0
            status = certRevocationStatusValid;
2445
0
            break;
2446
0
2447
0
        case dpcacheInvalidCacheError:
2448
0
            /* treat it as unknown and let the caller decide based on
2449
0
               the policy */
2450
0
            status = certRevocationStatusUnknown;
2451
0
            break;
2452
0
2453
0
        default:
2454
0
            /* leave status as revoked */
2455
0
            break;
2456
0
    }
2457
0
2458
0
    ReleaseDPCache(dpcache, lockedwrite);
2459
0
    if (revStatus) {
2460
0
        *revStatus = status;
2461
0
    }
2462
0
    if (revReason) {
2463
0
        *revReason = reason;
2464
0
    }
2465
0
    return rv;
2466
0
}
2467
2468
/* check CRL revocation status of given certificate and issuer */
2469
SECStatus
2470
CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, const SECItem* dp,
2471
              PRTime t, void* wincx)
2472
0
{
2473
0
    return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx, NULL,
2474
0
                                          NULL);
2475
0
}
2476
2477
/* retrieve full CRL object that best matches the cache status */
2478
CERTSignedCrl*
2479
SEC_FindCrlByName(CERTCertDBHandle* handle, SECItem* crlKey, int type)
2480
0
{
2481
0
    CERTSignedCrl* acrl = NULL;
2482
0
    CRLDPCache* dpcache = NULL;
2483
0
    SECStatus rv = SECSuccess;
2484
0
    PRBool writeLocked = PR_FALSE;
2485
0
2486
0
    if (!crlKey) {
2487
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2488
0
        return NULL;
2489
0
    }
2490
0
2491
0
    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
2492
0
    if (SECSuccess == rv) {
2493
0
        acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
2494
0
        SEC_FindCrlByName always returned fully decoded CRLs in the past */
2495
0
        ReleaseDPCache(dpcache, writeLocked);
2496
0
    }
2497
0
    return acrl;
2498
0
}
2499
2500
/* invalidate the CRL cache for a given issuer, which forces a refetch of
2501
   CRL objects from PKCS#11 tokens */
2502
void
2503
CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
2504
0
{
2505
0
    CRLDPCache* cache = NULL;
2506
0
    SECStatus rv = SECSuccess;
2507
0
    PRBool writeLocked = PR_FALSE;
2508
0
    PRBool readlocked;
2509
0
2510
0
    (void)dbhandle; /* silence compiler warnings */
2511
0
2512
0
    /* XCRL we will need to refresh all the DPs of the issuer in the future,
2513
0
            not just the default one */
2514
0
    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
2515
0
    if (SECSuccess != rv) {
2516
0
        return;
2517
0
    }
2518
0
    /* we need to invalidate the DPCache here */
2519
0
    readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2520
0
    DPCache_LockWrite();
2521
0
    cache->refresh = PR_TRUE;
2522
0
    DPCache_UnlockWrite();
2523
0
    ReleaseDPCache(cache, writeLocked);
2524
0
    return;
2525
0
}
2526
2527
/* add the specified RAM CRL object to the cache */
2528
SECStatus
2529
CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
2530
0
{
2531
0
    CRLDPCache* cache = NULL;
2532
0
    SECStatus rv = SECSuccess;
2533
0
    PRBool writeLocked = PR_FALSE;
2534
0
    PRBool readlocked;
2535
0
    CachedCrl* returned = NULL;
2536
0
    PRBool added = PR_FALSE;
2537
0
    CERTSignedCrl* newcrl = NULL;
2538
0
    int realerror = 0;
2539
0
2540
0
    if (!dbhandle || !newdercrl) {
2541
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2542
0
        return SECFailure;
2543
0
    }
2544
0
2545
0
    /* first decode the DER CRL to make sure it's OK */
2546
0
    newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
2547
0
                                        CRL_DECODE_DONT_COPY_DER |
2548
0
                                            CRL_DECODE_SKIP_ENTRIES);
2549
0
2550
0
    if (!newcrl) {
2551
0
        return SECFailure;
2552
0
    }
2553
0
2554
0
    /* XXX check if it has IDP extension. If so, do not proceed and set error */
2555
0
2556
0
    rv = AcquireDPCache(NULL, &newcrl->crl.derName, NULL, 0, NULL, &cache,
2557
0
                        &writeLocked);
2558
0
    if (SECSuccess == rv) {
2559
0
        readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2560
0
2561
0
        rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
2562
0
        if (SECSuccess == rv && returned) {
2563
0
            DPCache_LockWrite();
2564
0
            rv = DPCache_AddCRL(cache, returned, &added);
2565
0
            if (PR_TRUE != added) {
2566
0
                realerror = PORT_GetError();
2567
0
                CachedCrl_Destroy(returned);
2568
0
                returned = NULL;
2569
0
            }
2570
0
            DPCache_UnlockWrite();
2571
0
        }
2572
0
2573
0
        ReleaseDPCache(cache, writeLocked);
2574
0
2575
0
        if (!added) {
2576
0
            rv = SECFailure;
2577
0
        }
2578
0
    }
2579
0
    SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
2580
0
        and the refcount got bumped, or not, and thus we need to free its
2581
0
        RAM */
2582
0
    if (realerror) {
2583
0
        PORT_SetError(realerror);
2584
0
    }
2585
0
    return rv;
2586
0
}
2587
2588
/* remove the specified RAM CRL object from the cache */
2589
SECStatus
2590
CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
2591
0
{
2592
0
    CRLDPCache* cache = NULL;
2593
0
    SECStatus rv = SECSuccess;
2594
0
    PRBool writeLocked = PR_FALSE;
2595
0
    PRBool readlocked;
2596
0
    PRBool removed = PR_FALSE;
2597
0
    PRUint32 i;
2598
0
    CERTSignedCrl* oldcrl = NULL;
2599
0
2600
0
    if (!dbhandle || !olddercrl) {
2601
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2602
0
        return SECFailure;
2603
0
    }
2604
0
2605
0
    /* first decode the DER CRL to make sure it's OK */
2606
0
    oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
2607
0
                                        CRL_DECODE_DONT_COPY_DER |
2608
0
                                            CRL_DECODE_SKIP_ENTRIES);
2609
0
2610
0
    if (!oldcrl) {
2611
0
        /* if this DER CRL can't decode, it can't be in the cache */
2612
0
        return SECFailure;
2613
0
    }
2614
0
2615
0
    rv = AcquireDPCache(NULL, &oldcrl->crl.derName, NULL, 0, NULL, &cache,
2616
0
                        &writeLocked);
2617
0
    if (SECSuccess == rv) {
2618
0
        CachedCrl* returned = NULL;
2619
0
2620
0
        readlocked = (writeLocked == PR_TRUE ? PR_FALSE : PR_TRUE);
2621
0
2622
0
        rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
2623
0
        if (SECSuccess == rv && returned) {
2624
0
            DPCache_LockWrite();
2625
0
            for (i = 0; i < cache->ncrls; i++) {
2626
0
                PRBool dupe = PR_FALSE, updated = PR_FALSE;
2627
0
                rv = CachedCrl_Compare(returned, cache->crls[i], &dupe,
2628
0
                                       &updated);
2629
0
                if (SECSuccess != rv) {
2630
0
                    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2631
0
                    break;
2632
0
                }
2633
0
                if (PR_TRUE == dupe) {
2634
0
                    rv = DPCache_RemoveCRL(cache, i); /* got a match */
2635
0
                    if (SECSuccess == rv) {
2636
0
                        cache->mustchoose = PR_TRUE;
2637
0
                        removed = PR_TRUE;
2638
0
                    }
2639
0
                    break;
2640
0
                }
2641
0
            }
2642
0
2643
0
            DPCache_UnlockWrite();
2644
0
2645
0
            if (SECSuccess != CachedCrl_Destroy(returned)) {
2646
0
                rv = SECFailure;
2647
0
            }
2648
0
        }
2649
0
2650
0
        ReleaseDPCache(cache, writeLocked);
2651
0
    }
2652
0
    if (SECSuccess != SEC_DestroyCrl(oldcrl)) {
2653
0
        /* need to do this because object is refcounted */
2654
0
        rv = SECFailure;
2655
0
    }
2656
0
    if (SECSuccess == rv && PR_TRUE != removed) {
2657
0
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2658
0
    }
2659
0
    return rv;
2660
0
}
2661
2662
SECStatus
2663
cert_AcquireNamedCRLCache(NamedCRLCache** returned)
2664
0
{
2665
0
    PORT_Assert(returned);
2666
0
    if (!namedCRLCache.lock) {
2667
0
        PORT_Assert(0);
2668
0
        return SECFailure;
2669
0
    }
2670
0
    PR_Lock(namedCRLCache.lock);
2671
0
    *returned = &namedCRLCache;
2672
0
    return SECSuccess;
2673
0
}
2674
2675
/* This must be called only while cache is acquired, and the entry is only
2676
 * valid until cache is released.
2677
 */
2678
SECStatus
2679
cert_FindCRLByGeneralName(NamedCRLCache* ncc, const SECItem* canonicalizedName,
2680
                          NamedCRLCacheEntry** retEntry)
2681
0
{
2682
0
    if (!ncc || !canonicalizedName || !retEntry) {
2683
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2684
0
        return SECFailure;
2685
0
    }
2686
0
    *retEntry = (NamedCRLCacheEntry*)PL_HashTableLookup(
2687
0
        namedCRLCache.entries, (void*)canonicalizedName);
2688
0
    return SECSuccess;
2689
0
}
2690
2691
SECStatus
2692
cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
2693
0
{
2694
0
    if (!ncc) {
2695
0
        return SECFailure;
2696
0
    }
2697
0
    if (!ncc->lock) {
2698
0
        PORT_Assert(0);
2699
0
        return SECFailure;
2700
0
    }
2701
0
    PR_Unlock(namedCRLCache.lock);
2702
0
    return SECSuccess;
2703
0
}
2704
2705
/* creates new named cache entry from CRL, and tries to add it to CRL cache */
2706
static SECStatus
2707
addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
2708
              const SECItem* canonicalizedName, NamedCRLCacheEntry** newEntry)
2709
0
{
2710
0
    SECStatus rv = SECSuccess;
2711
0
    NamedCRLCacheEntry* entry = NULL;
2712
0
2713
0
    /* create new named entry */
2714
0
    if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry) {
2715
0
        /* no need to keep unused CRL around */
2716
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2717
0
        return SECFailure;
2718
0
    }
2719
0
    entry = *newEntry;
2720
0
    entry->crl = crl; /* named CRL cache owns DER */
2721
0
    entry->lastAttemptTime = PR_Now();
2722
0
    entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
2723
0
    if (!entry->canonicalizedName) {
2724
0
        rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
2725
0
        PORT_Assert(SECSuccess == rv);
2726
0
        return SECFailure;
2727
0
    }
2728
0
    /* now, attempt to insert CRL into CRL cache */
2729
0
    if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl)) {
2730
0
        entry->inCRLCache = PR_TRUE;
2731
0
        entry->successfulInsertionTime = entry->lastAttemptTime;
2732
0
    } else {
2733
0
        switch (PR_GetError()) {
2734
0
            case SEC_ERROR_CRL_ALREADY_EXISTS:
2735
0
                entry->dupe = PR_TRUE;
2736
0
                break;
2737
0
2738
0
            case SEC_ERROR_BAD_DER:
2739
0
                entry->badDER = PR_TRUE;
2740
0
                break;
2741
0
2742
0
            /* all other reasons */
2743
0
            default:
2744
0
                entry->unsupported = PR_TRUE;
2745
0
                break;
2746
0
        }
2747
0
        rv = SECFailure;
2748
0
        /* no need to keep unused CRL around */
2749
0
        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
2750
0
        entry->crl = NULL;
2751
0
    }
2752
0
    return rv;
2753
0
}
2754
2755
/* take ownership of CRL, and insert it into the named CRL cache
2756
 * and indexed CRL cache
2757
 */
2758
SECStatus
2759
cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
2760
                           const SECItem* canonicalizedName)
2761
0
{
2762
0
    NamedCRLCacheEntry *oldEntry, *newEntry = NULL;
2763
0
    NamedCRLCache* ncc = NULL;
2764
0
    SECStatus rv = SECSuccess;
2765
0
2766
0
    PORT_Assert(namedCRLCache.lock);
2767
0
    PORT_Assert(namedCRLCache.entries);
2768
0
2769
0
    if (!crl || !canonicalizedName) {
2770
0
        PORT_Assert(0);
2771
0
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
2772
0
        return SECFailure;
2773
0
    }
2774
0
2775
0
    rv = cert_AcquireNamedCRLCache(&ncc);
2776
0
    PORT_Assert(SECSuccess == rv);
2777
0
    if (SECSuccess != rv) {
2778
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2779
0
        return SECFailure;
2780
0
    }
2781
0
    rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
2782
0
    PORT_Assert(SECSuccess == rv);
2783
0
    if (SECSuccess != rv) {
2784
0
        (void)cert_ReleaseNamedCRLCache(ncc);
2785
0
        SECITEM_ZfreeItem(crl, PR_TRUE);
2786
0
        return SECFailure;
2787
0
    }
2788
0
    if (SECSuccess ==
2789
0
        addCRLToCache(dbhandle, crl, canonicalizedName, &newEntry)) {
2790
0
        if (!oldEntry) {
2791
0
            /* add new good entry to the hash table */
2792
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2793
0
                                        (void*)newEntry->canonicalizedName,
2794
0
                                        (void*)newEntry)) {
2795
0
                PORT_Assert(0);
2796
0
                NamedCRLCacheEntry_Destroy(newEntry);
2797
0
                rv = SECFailure;
2798
0
            }
2799
0
        } else {
2800
0
            PRBool removed;
2801
0
            /* remove the old CRL from the cache if needed */
2802
0
            if (oldEntry->inCRLCache) {
2803
0
                rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
2804
0
                PORT_Assert(SECSuccess == rv);
2805
0
            }
2806
0
            removed = PL_HashTableRemove(namedCRLCache.entries,
2807
0
                                         (void*)oldEntry->canonicalizedName);
2808
0
            PORT_Assert(removed);
2809
0
            if (!removed) {
2810
0
                rv = SECFailure;
2811
0
                /* leak old entry since we couldn't remove it from the hash
2812
0
                 * table */
2813
0
            } else {
2814
0
                PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry));
2815
0
            }
2816
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2817
0
                                        (void*)newEntry->canonicalizedName,
2818
0
                                        (void*)newEntry)) {
2819
0
                PORT_Assert(0);
2820
0
                rv = SECFailure;
2821
0
            }
2822
0
        }
2823
0
    } else {
2824
0
        /* error adding new CRL to cache */
2825
0
        if (!oldEntry) {
2826
0
            /* no old cache entry, use the new one even though it's bad */
2827
0
            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2828
0
                                        (void*)newEntry->canonicalizedName,
2829
0
                                        (void*)newEntry)) {
2830
0
                PORT_Assert(0);
2831
0
                rv = SECFailure;
2832
0
            }
2833
0
        } else {
2834
0
            if (oldEntry->inCRLCache) {
2835
0
                /* previous cache entry was good, keep it and update time */
2836
0
                oldEntry->lastAttemptTime = newEntry->lastAttemptTime;
2837
0
                /* throw away new bad entry */
2838
0
                rv = NamedCRLCacheEntry_Destroy(newEntry);
2839
0
                PORT_Assert(SECSuccess == rv);
2840
0
            } else {
2841
0
                /* previous cache entry was bad, just replace it */
2842
0
                PRBool removed = PL_HashTableRemove(
2843
0
                    namedCRLCache.entries, (void*)oldEntry->canonicalizedName);
2844
0
                PORT_Assert(removed);
2845
0
                if (!removed) {
2846
0
                    /* leak old entry since we couldn't remove it from the hash
2847
0
                     * table */
2848
0
                    rv = SECFailure;
2849
0
                } else {
2850
0
                    PORT_CheckSuccess(NamedCRLCacheEntry_Destroy(oldEntry));
2851
0
                }
2852
0
                if (NULL == PL_HashTableAdd(namedCRLCache.entries,
2853
0
                                            (void*)newEntry->canonicalizedName,
2854
0
                                            (void*)newEntry)) {
2855
0
                    PORT_Assert(0);
2856
0
                    rv = SECFailure;
2857
0
                }
2858
0
            }
2859
0
        }
2860
0
    }
2861
0
    PORT_CheckSuccess(cert_ReleaseNamedCRLCache(ncc));
2862
0
2863
0
    return rv;
2864
0
}
2865
2866
static SECStatus
2867
CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, CRLOrigin origin)
2868
0
{
2869
0
    CachedCrl* newcrl = NULL;
2870
0
    if (!returned) {
2871
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2872
0
        return SECFailure;
2873
0
    }
2874
0
    newcrl = PORT_ZAlloc(sizeof(CachedCrl));
2875
0
    if (!newcrl) {
2876
0
        return SECFailure;
2877
0
    }
2878
0
    newcrl->crl = SEC_DupCrl(crl);
2879
0
    newcrl->origin = origin;
2880
0
    *returned = newcrl;
2881
0
    return SECSuccess;
2882
0
}
2883
2884
/* empty the cache content */
2885
static SECStatus
2886
CachedCrl_Depopulate(CachedCrl* crl)
2887
0
{
2888
0
    if (!crl) {
2889
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2890
0
        return SECFailure;
2891
0
    }
2892
0
    /* destroy the hash table */
2893
0
    if (crl->entries) {
2894
0
        PL_HashTableDestroy(crl->entries);
2895
0
        crl->entries = NULL;
2896
0
    }
2897
0
2898
0
    /* free the pre buffer */
2899
0
    if (crl->prebuffer) {
2900
0
        PreAllocator_Destroy(crl->prebuffer);
2901
0
        crl->prebuffer = NULL;
2902
0
    }
2903
0
    return SECSuccess;
2904
0
}
2905
2906
static SECStatus
2907
CachedCrl_Destroy(CachedCrl* crl)
2908
0
{
2909
0
    if (!crl) {
2910
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2911
0
        return SECFailure;
2912
0
    }
2913
0
    CachedCrl_Depopulate(crl);
2914
0
    SEC_DestroyCrl(crl->crl);
2915
0
    PORT_Free(crl);
2916
0
    return SECSuccess;
2917
0
}
2918
2919
/* create hash table of CRL entries */
2920
static SECStatus
2921
CachedCrl_Populate(CachedCrl* crlobject)
2922
0
{
2923
0
    SECStatus rv = SECFailure;
2924
0
    CERTCrlEntry** crlEntry = NULL;
2925
0
    PRUint32 numEntries = 0;
2926
0
2927
0
    if (!crlobject) {
2928
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2929
0
        return SECFailure;
2930
0
    }
2931
0
    /* complete the entry decoding . XXX thread-safety of CRL object */
2932
0
    rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
2933
0
    if (SECSuccess != rv) {
2934
0
        crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
2935
0
        return SECFailure;
2936
0
    }
2937
0
2938
0
    if (crlobject->entries && crlobject->prebuffer) {
2939
0
        /* cache is already built */
2940
0
        return SECSuccess;
2941
0
    }
2942
0
2943
0
    /* build the hash table from the full CRL */
2944
0
    /* count CRL entries so we can pre-allocate space for hash table entries */
2945
0
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2946
0
         crlEntry++) {
2947
0
        numEntries++;
2948
0
    }
2949
0
    crlobject->prebuffer =
2950
0
        PreAllocator_Create(numEntries * sizeof(PLHashEntry));
2951
0
    PORT_Assert(crlobject->prebuffer);
2952
0
    if (!crlobject->prebuffer) {
2953
0
        return SECFailure;
2954
0
    }
2955
0
    /* create a new hash table */
2956
0
    crlobject->entries =
2957
0
        PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues,
2958
0
                        &preAllocOps, crlobject->prebuffer);
2959
0
    PORT_Assert(crlobject->entries);
2960
0
    if (!crlobject->entries) {
2961
0
        return SECFailure;
2962
0
    }
2963
0
    /* add all serial numbers to the hash table */
2964
0
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2965
0
         crlEntry++) {
2966
0
        PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
2967
0
                        *crlEntry);
2968
0
    }
2969
0
2970
0
    return SECSuccess;
2971
0
}
2972
2973
/* returns true if there are CRLs from PKCS#11 slots */
2974
static PRBool
2975
DPCache_HasTokenCRLs(CRLDPCache* cache)
2976
0
{
2977
0
    PRBool answer = PR_FALSE;
2978
0
    PRUint32 i;
2979
0
    for (i = 0; i < cache->ncrls; i++) {
2980
0
        if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin)) {
2981
0
            answer = PR_TRUE;
2982
0
            break;
2983
0
        }
2984
0
    }
2985
0
    return answer;
2986
0
}
2987
2988
/* are these CRLs the same, as far as the cache is concerned ? */
2989
/* are these CRLs the same token object but with different DER ?
2990
   This can happen if the DER CRL got updated in the token, but the PKCS#11
2991
   object ID did not change. NSS softoken has the unfortunate property to
2992
   never change the object ID for CRL objects. */
2993
static SECStatus
2994
CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, PRBool* isUpdated)
2995
0
{
2996
0
    PORT_Assert(a);
2997
0
    PORT_Assert(b);
2998
0
    PORT_Assert(isDupe);
2999
0
    PORT_Assert(isUpdated);
3000
0
    if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl) {
3001
0
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
3002
0
        return SECFailure;
3003
0
    }
3004
0
3005
0
    *isDupe = *isUpdated = PR_FALSE;
3006
0
3007
0
    if (a == b) {
3008
0
        /* dupe */
3009
0
        *isDupe = PR_TRUE;
3010
0
        *isUpdated = PR_FALSE;
3011
0
        return SECSuccess;
3012
0
    }
3013
0
    if (b->origin != a->origin) {
3014
0
        /* CRLs of different origins are not considered dupes,
3015
0
           and can't be updated either */
3016
0
        return SECSuccess;
3017
0
    }
3018
0
    if (CRL_OriginToken == b->origin) {
3019
0
        /* for token CRLs, slot and PKCS#11 object handle must match for CRL
3020
0
           to truly be a dupe */
3021
0
        if ((b->crl->slot == a->crl->slot) &&
3022
0
            (b->crl->pkcs11ID == a->crl->pkcs11ID)) {
3023
0
            /* ASN.1 DER needs to match for dupe check */
3024
0
            /* could optimize by just checking a few fields like thisUpdate */
3025
0
            if (SECEqual ==
3026
0
                SECITEM_CompareItem(b->crl->derCrl, a->crl->derCrl)) {
3027
0
                *isDupe = PR_TRUE;
3028
0
            } else {
3029
0
                *isUpdated = PR_TRUE;
3030
0
            }
3031
0
        }
3032
0
        return SECSuccess;
3033
0
    }
3034
0
    if (CRL_OriginExplicit == b->origin) {
3035
0
        /* We need to make sure this is the same object that the user provided
3036
0
           to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
3037
0
           just do a pointer comparison here.
3038
0
        */
3039
0
        if (b->crl->derCrl == a->crl->derCrl) {
3040
0
            *isDupe = PR_TRUE;
3041
0
        }
3042
0
    }
3043
0
    return SECSuccess;
3044
0
}