~ubuntu-branches/ubuntu/lucid/seamonkey/lucid-security

« back to all changes in this revision

Viewing changes to security/nss-fips/lib/certdb/crl.c

  • Committer: Bazaar Package Importer
  • Author(s): Fabien Tassin
  • Date: 2008-07-29 21:29:02 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080729212902-spm9kpvchp9udwbw
Tags: 1.1.11+nobinonly-0ubuntu1
* New security upstream release: 1.1.11 (LP: #218534)
  Fixes USN-602-1, USN-619-1, USN-623-1 and USN-629-1
* Refresh diverged patch:
  - update debian/patches/80_security_build.patch
* Fix FTBFS with missing -lfontconfig
  - add debian/patches/11_fix_ftbfs_with_fontconfig.patch
  - update debian/patches/series
* Build with default gcc (hardy: 4.2, intrepid: 4.3)
  - update debian/rules
  - update debian/control

Show diffs side-by-side

added added

removed removed

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