1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
14
* The Original Code is the Netscape security libraries.
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.
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.
35
* ***** END LICENSE BLOCK ***** */
38
* Moved from secpkcs7.c
40
* $Id: crl.c,v 1.49.24.4 2006/09/11 23:14:09 julien.pierre.bugs%sun.com Exp $
56
#if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
61
const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
63
0, NULL, sizeof(CERTCertExtension) },
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) },
73
static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
74
{ SEC_ASN1_SEQUENCE_OF, 0, SEC_CERTExtensionTemplate}
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
83
const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
85
0, NULL, sizeof(CERTIssuerAndSN) },
87
offsetof(CERTIssuerAndSN,derIssuer) },
89
offsetof(CERTIssuerAndSN,issuer),
92
offsetof(CERTIssuerAndSN,serialNumber) },
96
static const SEC_ASN1Template cert_KrlEntryTemplate[] = {
98
0, NULL, sizeof(CERTCrlEntry) },
99
{ SEC_ASN1_OCTET_STRING,
100
offsetof(CERTCrlEntry,serialNumber) },
102
offsetof(CERTCrlEntry,revocationDate) },
106
static const SEC_ASN1Template cert_KrlTemplate[] = {
108
0, NULL, sizeof(CERTCrl) },
110
offsetof(CERTCrl,signatureAlg),
111
SECOID_AlgorithmIDTemplate },
113
offsetof(CERTCrl,derName) },
115
offsetof(CERTCrl,name),
118
offsetof(CERTCrl,lastUpdate) },
120
offsetof(CERTCrl,nextUpdate) },
121
{ SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
122
offsetof(CERTCrl,entries),
123
cert_KrlEntryTemplate },
127
static const SEC_ASN1Template cert_SignedKrlTemplate[] = {
129
0, NULL, sizeof(CERTSignedCrl) },
131
offsetof(CERTSignedCrl,signatureWrap.data) },
133
offsetof(CERTSignedCrl,crl),
136
offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
137
SECOID_AlgorithmIDTemplate },
138
{ SEC_ASN1_BIT_STRING,
139
offsetof(CERTSignedCrl,signatureWrap.signature) },
143
static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
145
0, NULL, sizeof(CERTCrlKey) },
146
{ SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
148
{ SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
149
{ SEC_ASN1_SKIP_REST },
153
static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
155
0, NULL, sizeof(CERTCrlEntry) },
157
offsetof(CERTCrlEntry,serialNumber) },
159
offsetof(CERTCrlEntry,revocationDate), CERT_TimeChoiceTemplate },
160
{ SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
161
offsetof(CERTCrlEntry, extensions),
162
SEC_CERTExtensionTemplate},
166
const SEC_ASN1Template CERT_CrlTemplate[] = {
168
0, NULL, sizeof(CERTCrl) },
169
{ SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
171
offsetof(CERTCrl,signatureAlg),
172
SECOID_AlgorithmIDTemplate },
174
offsetof(CERTCrl,derName) },
176
offsetof(CERTCrl,name),
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},
192
const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
194
0, NULL, sizeof(CERTCrl) },
195
{ SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
197
offsetof(CERTCrl,signatureAlg),
198
SECOID_AlgorithmIDTemplate },
200
offsetof(CERTCrl,derName) },
202
offsetof(CERTCrl,name),
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 },
217
const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
219
0, NULL, sizeof(CERTCrl) },
220
{ SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
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 },
234
const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
236
0, NULL, sizeof(CERTSignedCrl) },
238
offsetof(CERTSignedCrl,signatureWrap.data) },
240
offsetof(CERTSignedCrl,crl),
243
offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
244
SECOID_AlgorithmIDTemplate },
245
{ SEC_ASN1_BIT_STRING,
246
offsetof(CERTSignedCrl,signatureWrap.signature) },
250
static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
252
0, NULL, sizeof(CERTSignedCrl) },
254
offsetof(CERTSignedCrl,signatureWrap.data) },
256
offsetof(CERTSignedCrl,crl),
257
CERT_CrlTemplateNoEntries },
259
offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
260
SECOID_AlgorithmIDTemplate },
261
{ SEC_ASN1_BIT_STRING,
262
offsetof(CERTSignedCrl,signatureWrap.signature) },
266
const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
267
{ SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
270
/* get CRL version */
271
int cert_get_crl_version(CERTCrl * crl)
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);
282
/* check the entries in the CRL */
283
SECStatus cert_check_crl_entries (CERTCrl *crl)
285
CERTCrlEntry **entries;
287
PRBool hasCriticalExten = PR_FALSE;
288
SECStatus rv = SECSuccess;
294
if (crl->entries == NULL) {
295
/* CRLs with no entries are valid */
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.
302
entries = crl->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.
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);
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.
326
if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
327
PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
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
342
SECStatus cert_check_crl_version (CERTCrl *crl)
344
PRBool hasCriticalExten = PR_FALSE;
345
int version = cert_get_crl_version(crl);
347
if (version > SEC_CRL_VERSION_2) {
348
PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
352
/* Check the crl extensions for a critial extension. If one is found,
353
and the version is not v2, then we are done.
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);
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);
375
* Generate a database key, based on the issuer name from a
379
CERT_KeyFromDERCrl(PRArenaPool *arena, SECItem *derCrl, SECItem *key)
385
PORT_Memset (&sd, 0, sizeof (sd));
386
rv = SEC_ASN1DecodeItem (arena, &sd, CERT_SignedDataTemplate, derCrl);
387
if (rv != SECSuccess) {
391
PORT_Memset (&crlkey, 0, sizeof (crlkey));
392
rv = SEC_ASN1DecodeItem(arena, &crlkey, cert_CrlKeyTemplate, &sd.data);
393
if (rv != SECSuccess) {
397
key->len = crlkey.derName.len;
398
key->data = crlkey.derName.data;
403
#define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
405
SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
407
SECStatus rv = SECSuccess;
408
SECItem* crldata = NULL;
409
OpaqueCRLFields* extended = NULL;
412
(!(extended = (OpaqueCRLFields*) crl->opaque)) ||
413
(PR_TRUE == extended->decodingError) ) {
416
if (PR_FALSE == extended->partial) {
417
/* the CRL has already been fully decoded */
420
if (PR_TRUE == extended->badEntries) {
421
/* the entries decoding already failed */
424
crldata = &crl->signatureWrap.data;
430
if (SECSuccess == rv) {
431
rv = SEC_QuickDERDecodeItem(crl->arena,
433
CERT_CrlTemplateEntriesOnly,
435
if (SECSuccess == rv) {
436
extended->partial = PR_FALSE; /* successful decode, avoid
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 */
445
rv = cert_check_crl_entries(&crl->crl);
446
if (rv != SECSuccess) {
447
extended->badExtensions = PR_TRUE;
454
* take a DER CRL or KRL and decode it into a CRL structure
455
* allow reusing the input DER without making a copy
458
CERT_DecodeDERCrlWithFlags(PRArenaPool *narena, SECItem *derSignedCrl,
459
int type, PRInt32 options)
464
OpaqueCRLFields* extended = NULL;
465
const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
468
( (options & CRL_DECODE_ADOPT_HEAP_DER) && /* adopting DER requires
470
(!(options & CRL_DECODE_DONT_COPY_DER))
473
PORT_SetError(SEC_ERROR_INVALID_ARGS);
477
/* make a new arena if needed */
478
if (narena == NULL) {
479
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
487
/* allocate the CRL structure */
488
crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
490
PORT_SetError(SEC_ERROR_NO_MEMORY);
496
/* allocate opaque fields */
497
crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
498
if ( !crl->opaque ) {
501
extended = (OpaqueCRLFields*) crl->opaque;
502
if (options & CRL_DECODE_ADOPT_HEAP_DER) {
503
extended->heapDER = PR_TRUE;
505
if (options & CRL_DECODE_DONT_COPY_DER) {
506
crl->derCrl = derSignedCrl; /* DER is not copied . The application
507
must keep derSignedCrl until it
510
crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
511
if (crl->derCrl == NULL) {
514
rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
515
if (rv != SECSuccess) {
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;
527
/* decode the CRL info */
530
rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
531
if (rv != SECSuccess) {
532
extended->badDER = PR_TRUE;
535
/* check for critical extensions */
536
rv = cert_check_crl_version (&crl->crl);
537
if (rv != SECSuccess) {
538
extended->badExtensions = PR_TRUE;
542
if (PR_TRUE == extended->partial) {
543
/* partial decoding, don't verify entries */
547
rv = cert_check_crl_entries(&crl->crl);
548
if (rv != SECSuccess) {
549
extended->badExtensions = PR_TRUE;
555
rv = SEC_QuickDERDecodeItem
556
(arena, crl, cert_SignedKrlTemplate, derSignedCrl);
563
if (rv != SECSuccess) {
567
crl->referenceCount = 1;
572
if (options & CRL_DECODE_KEEP_BAD_CRL) {
574
extended->decodingError = PR_TRUE;
577
crl->referenceCount = 1;
582
if ((narena == NULL) && arena ) {
583
PORT_FreeArena(arena, PR_FALSE);
590
* take a DER CRL or KRL and decode it into a CRL structure
593
CERT_DecodeDERCrl(PRArenaPool *narena, SECItem *derSignedCrl, int type)
595
return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
596
CRL_DECODE_DEFAULT_OPTIONS);
600
* Lookup a CRL in the databases. We mirror the same fast caching data base
601
* caching stuff used by certificates....?
604
* SECSuccess means we got a valid DER CRL (passed in "decoded"), or no CRL at
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
615
SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
616
CERTSignedCrl** decoded, PRInt32 decodeoptions)
618
SECStatus rv = SECSuccess;
619
CERTSignedCrl *crl = NULL;
620
SECItem *derCrl = NULL;
621
CK_OBJECT_HANDLE crlHandle = 0;
625
PORT_Assert(decoded);
627
PORT_SetError(SEC_ERROR_INVALID_ARGS);
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 */
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)) {
644
PORT_Assert(crlHandle != CK_INVALID_HANDLE);
645
/* PK11_FindCrlByName obtained a slot reference. */
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;
652
crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
655
slot = NULL; /* adopt it */
656
crl->pkcs11ID = crlHandle;
658
crl->url = PORT_ArenaStrdup(crl->arena,url);
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);
685
SECStatus SEC_DestroyCrl(CERTSignedCrl *crl);
688
crl_storeCRL (PK11SlotInfo *slot,char *url,
689
CERTSignedCrl *newCrl, SECItem *derCrl, int type)
691
CERTSignedCrl *oldCrl = NULL, *crl = NULL;
692
PRBool deleteOldCrl = PR_FALSE;
693
CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
698
/* we can't use the cache here because we must look in the same
700
SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
701
&oldCrl, CRL_DECODE_SKIP_ENTRIES);
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
707
if (oldCrl != NULL) {
708
/* if it's already there, quietly continue */
709
if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl)
712
crl->slot = PK11_ReferenceSlot(slot);
713
crl->pkcs11ID = oldCrl->pkcs11ID;
716
if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
718
if (type == SEC_CRL_TYPE) {
719
PORT_SetError(SEC_ERROR_OLD_CRL);
721
PORT_SetError(SEC_ERROR_OLD_KRL);
727
if ((SECITEM_CompareItem(&newCrl->crl.derName,
728
&oldCrl->crl.derName) != SECEqual) &&
729
(type == SEC_KRL_TYPE) ) {
731
PORT_SetError(SEC_ERROR_CKL_CONFLICT);
735
/* if we have a url in the database, use that one */
740
/* really destroy this crl */
741
/* first drum it out of the permanment Data base */
742
deleteOldCrl = PR_TRUE;
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) {
751
crl->slot = PK11_ReferenceSlot(slot);
752
crl->pkcs11ID = crlHandle;
754
crl->url = PORT_ArenaStrdup(crl->arena,url);
760
if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
761
SEC_DeletePermCRL(oldCrl);
763
SEC_DestroyCrl(oldCrl);
771
* create a new CRL from DER material.
773
* The signature on this CRL must be checked before you
777
SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
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);
789
SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
794
CERTSignedCrl *crl = NULL;
796
/* create a scratch arena */
797
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
798
if ( arena == NULL ) {
802
/* extract the database key from the cert */
803
rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
804
if ( rv != SECSuccess ) {
809
crl = SEC_FindCrlByName(handle, &crlKey, type);
812
PORT_FreeArena(arena, PR_FALSE);
816
CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
820
PR_AtomicIncrement(&acrl->referenceCount);
827
SEC_DestroyCrl(CERTSignedCrl *crl)
830
if (PR_AtomicDecrement(&crl->referenceCount) < 1) {
832
PK11_FreeSlot(crl->slot);
834
if (GetOpaqueCRLFields(crl) &&
835
PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
836
SECITEM_FreeItem(crl->derCrl, PR_TRUE);
839
PORT_FreeArena(crl->arena, PR_FALSE);
849
SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
851
CERTCrlHeadNode *head;
852
PRArenaPool *arena = NULL;
857
arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
858
if ( arena == NULL ) {
862
/* build a head structure */
863
head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
867
head->dbhandle = handle;
869
/* Look up the proper crl types */
872
rv = PK11_LookupCrls(head, type, NULL);
874
if (rv != SECSuccess) {
876
PORT_FreeArena(arena, PR_FALSE);
884
/* These functions simply return the address of the above-declared templates.
885
** This is necessary for Windows DLLs. Sigh.
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)
892
/* CRL cache code starts here */
895
static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
898
static SECStatus CachedCrl_Destroy(CachedCrl* crl);
900
/* create hash table of CRL entries */
901
static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
903
/* empty the cache content */
904
static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
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 ? */
909
static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
912
/* create a DPCache object */
913
static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
914
SECItem* subject, SECItem* dp);
916
/* destructor for CRL DPCache object */
917
static SECStatus DPCache_Destroy(CRLDPCache* cache);
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);
923
/* fetch the CRL for this DP from the PKCS#11 tokens */
924
static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx);
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);
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);
934
/* returns true if there are CRLs from PKCS#11 slots */
935
static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
937
/* remove CRL at offset specified */
938
static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
940
/* Pick best CRL to use . needs write access */
941
static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
943
/* create an issuer cache object (per CA subject ) */
944
static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
945
CERTCertificate* issuer,
946
SECItem* subject, SECItem* dp);
948
/* destructor for CRL IssuerCache object */
949
SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
951
/* add a DPCache to the issuer cache */
952
static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
953
SECItem* subject, SECItem* dp, CRLDPCache** newdpc);
955
/* get a particular DPCache object from an IssuerCache */
956
static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp);
959
** Pre-allocator hash allocator ops.
962
/* allocate memory for hash table */
963
static void * PR_CALLBACK
964
PreAllocTable(void *pool, PRSize size)
966
PreAllocator* alloc = (PreAllocator*)pool;
970
/* no allocator, or buffer full */
973
if (size > (alloc->len - alloc->used))
975
/* initial buffer full, let's use the arena */
976
alloc->extra += size;
977
return PORT_ArenaAlloc(alloc->arena, size);
979
/* use the initial buffer */
981
return (char*) alloc->data + alloc->used - size;
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)
991
/* allocate memory for hash table */
992
static PLHashEntry * PR_CALLBACK
993
PreAllocEntry(void *pool, const void *key)
995
return PreAllocTable(pool, sizeof(PLHashEntry));
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)
1005
/* methods required for PL hash table functions */
1006
static PLHashAllocOps preAllocOps =
1008
PreAllocTable, PreFreeTable,
1009
PreAllocEntry, PreFreeEntry
1012
/* destructor for PreAllocator object */
1013
void PreAllocator_Destroy(PreAllocator* PreAllocator)
1019
if (PreAllocator->arena)
1021
PORT_FreeArena(PreAllocator->arena, PR_TRUE);
1023
if (PreAllocator->data)
1025
PORT_Free(PreAllocator->data);
1027
PORT_Free(PreAllocator);
1030
/* constructor for PreAllocator object */
1031
PreAllocator* PreAllocator_Create(PRSize size)
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)
1041
PreAllocator_Destroy(&prebuffer);
1046
prebuffer.data = PORT_Alloc(prebuffer.len);
1047
if (!prebuffer.data)
1049
PreAllocator_Destroy(&prebuffer);
1055
prebuffer.data = NULL;
1057
prepointer = (PreAllocator*)PORT_Alloc(sizeof(PreAllocator));
1060
PreAllocator_Destroy(&prebuffer);
1063
*prepointer = prebuffer;
1067
/* global CRL cache object */
1068
static CRLCache crlcache = { NULL, NULL };
1070
/* initial state is off */
1071
static PRBool crlcache_initialized = PR_FALSE;
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 */
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 */
1081
PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
1082
if a token CRL object still exists. In microseconds */
1084
/* this function is called at NSS initialization time */
1085
SECStatus InitCRLCache(void)
1087
if (PR_FALSE == crlcache_initialized)
1089
PORT_Assert(NULL == crlcache.lock);
1090
PORT_Assert(NULL == crlcache.issuers);
1091
if (crlcache.lock || crlcache.issuers)
1093
/* CRL cache already partially initialized */
1094
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1097
#ifdef GLOBAL_RWLOCK
1098
crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
1100
crlcache.lock = PR_NewLock();
1106
crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
1107
PL_CompareValues, NULL, NULL);
1108
if (!crlcache.issuers)
1110
#ifdef GLOBAL_RWLOCK
1111
NSSRWLock_Destroy(crlcache.lock);
1113
PR_DestroyLock(crlcache.lock);
1115
crlcache.lock = NULL;
1118
crlcache_initialized = PR_TRUE;
1123
PORT_Assert(crlcache.lock);
1124
PORT_Assert(crlcache.issuers);
1125
if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
1127
/* CRL cache not fully initialized */
1132
/* CRL cache already initialized */
1138
/* destructor for CRL DPCache object */
1139
static SECStatus DPCache_Destroy(CRLDPCache* cache)
1146
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1152
NSSRWLock_Destroy(cache->lock);
1154
PR_DestroyLock(cache->lock);
1162
/* destroy all our CRL objects */
1163
for (i=0;i<cache->ncrls;i++)
1165
if (!cache->crls || !cache->crls[i] ||
1166
SECSuccess != CachedCrl_Destroy(cache->crls[i]))
1171
/* free the array of CRLs */
1174
PORT_Free(cache->crls);
1176
/* destroy the cert */
1179
CERT_DestroyCertificate(cache->issuer);
1181
/* free the subject */
1184
SECITEM_FreeItem(cache->subject, PR_TRUE);
1186
/* free the distribution points */
1187
if (cache->distributionPoint)
1189
SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
1195
/* destructor for CRL IssuerCache object */
1196
SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
1202
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1208
NSSRWLock_Destroy(cache->lock);
1213
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1218
CERT_DestroyCertificate(cache->issuer);
1221
/* free the subject */
1224
SECITEM_FreeItem(cache->subject, PR_TRUE);
1226
if (SECSuccess != DPCache_Destroy(cache->dpp))
1235
/* callback function used in hash table destructor */
1236
static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
1238
CRLIssuerCache* issuer = NULL;
1239
SECStatus* rv = (SECStatus*) arg;
1244
return HT_ENUMERATE_NEXT;
1246
issuer = (CRLIssuerCache*) he->value;
1247
PORT_Assert(issuer);
1250
if (SECSuccess != IssuerCache_Destroy(issuer))
1257
return HT_ENUMERATE_NEXT;
1260
return HT_ENUMERATE_NEXT;
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)
1270
SECStatus rv = SECSuccess;
1271
if (PR_FALSE == crlcache_initialized &&
1272
!crlcache.lock && !crlcache.issuers)
1274
/* CRL cache has already been shut down */
1277
if (PR_TRUE == crlcache_initialized &&
1278
(!crlcache.lock || !crlcache.issuers))
1280
/* CRL cache has partially been shut down */
1281
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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);
1294
PR_DestroyLock(crlcache.lock);
1296
crlcache.lock = NULL;
1297
crlcache_initialized = PR_FALSE;
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,
1306
CachedCrl** newcrls = NULL;
1309
PORT_Assert(newcrl);
1311
if (!cache || !newcrl || !added)
1313
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1318
/* before adding a new CRL, check if it is a duplicate */
1319
for (i=0;i<cache->ncrls;i++)
1321
CachedCrl* existing = NULL;
1322
SECStatus rv = SECSuccess;
1323
PRBool dupe = PR_FALSE, updated = PR_FALSE;
1329
existing = cache->crls[i];
1335
rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
1336
if (SECSuccess != rv)
1339
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1342
if (PR_TRUE == dupe)
1345
PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
1348
if (PR_TRUE == updated)
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))
1355
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1361
newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
1362
(cache->ncrls+1)*sizeof(CachedCrl*));
1367
cache->crls = newcrls;
1369
cache->crls[cache->ncrls-1] = newcrl;
1374
/* remove CRL at offset specified */
1375
static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
1377
CachedCrl* acrl = NULL;
1379
if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
1381
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1384
acrl = cache->crls[offset];
1388
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1391
cache->crls[offset] = cache->crls[cache->ncrls-1];
1392
cache->crls[cache->ncrls-1] = NULL;
1394
if (cache->selected == acrl) {
1395
cache->selected = NULL;
1397
if (SECSuccess != CachedCrl_Destroy(acrl))
1400
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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)
1420
PK11SlotInfo* slot = NULL;
1421
nssCryptokiObject instance;
1423
PRBool xstatus = PR_TRUE;
1424
SECItem* oldSubject = NULL;
1432
PORT_Assert(crl->slot);
1437
oldSubject = &crl->crl.derName;
1438
PORT_Assert(oldSubject);
1444
/* query subject and type attributes in order to determine if the
1445
object has been deleted */
1447
/* first, make an nssCryptokiObject */
1448
instance.handle = crl->pkcs11ID;
1449
PORT_Assert(instance.handle);
1450
if (!instance.handle)
1454
instance.token = PK11Slot_GetNSSToken(slot);
1455
PORT_Assert(instance.token);
1456
if (!instance.token)
1460
instance.isTokenObject = PR_TRUE;
1461
instance.label = NULL;
1463
arena = NSSArena_Create();
1470
status = nssCryptokiCRL_GetAttributes(&instance,
1471
NULL, /* XXX sessionOpt */
1474
&newsubject, /* subject */
1475
&crl_class, /* class */
1478
if (PR_SUCCESS == status)
1480
subject.data = newsubject.data;
1481
subject.len = newsubject.size;
1482
if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
1486
if (CKO_NETSCAPE_CRL != crl_class)
1495
NSSArena_Destroy(arena);
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,
1506
return CERT_VerifySignedData(&crlobject->signatureWrap,
1507
issuer, vfdate, wincx);
1510
/* verify a CRL and update cache state */
1511
static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
1512
PRTime vfdate, void* wincx)
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 */
1526
if (!cache || !crlobject)
1529
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1532
if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
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);
1541
SECStatus signstatus = SECFailure;
1544
signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
1547
if (SECSuccess != signstatus)
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 */
1558
crlobject->sigChecked = PR_TRUE;
1560
PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
1564
crlobject->sigChecked = PR_TRUE;
1565
crlobject->sigValid = PR_TRUE;
1572
/* fetch the CRLs for this DP from the PKCS#11 tokens */
1573
static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
1576
SECStatus rv = SECSuccess;
1577
CERTCrlHeadNode head;
1581
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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);
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)
1594
/* fetch failed, add error bit */
1595
cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
1598
/* fetch was successful, clear this error bit */
1599
cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
1602
/* add any CRLs found to our array */
1603
if (SECSuccess == rv)
1605
CERTCrlNode* crlNode = NULL;
1607
for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
1609
CachedCrl* returned = NULL;
1610
CERTSignedCrl* crlobject = crlNode->crl;
1616
rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
1617
if (SECSuccess == rv)
1619
PRBool added = PR_FALSE;
1620
rv = DPCache_AddCRL(cache, returned, &added);
1621
if (PR_TRUE != added)
1623
rv = CachedCrl_Destroy(returned);
1628
rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
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;
1637
if (SECFailure == rv)
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)
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 */
1658
PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
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)
1668
CERTCrlEntry* acrlEntry = NULL;
1669
if (!cache || !sn || !returned)
1671
PORT_SetError(SEC_ERROR_INVALID_ARGS);
1672
/* no cache or SN to look up, or no way to return entry */
1675
if (0 != cache->invalid)
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);
1682
if (!cache->selected)
1684
/* no CRL means no entry to return, but this is OK */
1688
PORT_Assert(cache->selected->entries);
1689
if (!cache->selected->entries)
1693
/* XXX should probably use CachedCrl accessor function here */
1694
acrlEntry = PL_HashTableLookup(cache->selected->entries, (void*)sn);
1697
*returned = acrlEntry;
1702
#if defined(DPC_RWLOCK)
1704
#define DPCache_LockWrite() \
1708
NSSRWLock_UnlockRead(cache->lock); \
1710
NSSRWLock_LockWrite(cache->lock); \
1713
#define DPCache_UnlockWrite() \
1717
NSSRWLock_LockRead(cache->lock); \
1719
NSSRWLock_UnlockWrite(cache->lock); \
1724
/* with a global lock, we are always locked for read before we need write
1725
access, so do nothing */
1727
#define DPCache_LockWrite() \
1731
#define DPCache_UnlockWrite() \
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,
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;
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;
1754
PRTime lastfetch = 0;
1758
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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
1772
forcedrefresh = cache->refresh;
1773
lastfetch = cache->lastfetch;
1774
if (PR_TRUE != forcedrefresh &&
1775
(!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
1778
hastokenCRLs = DPCache_HasTokenCRLs(cache);
1780
if ( (0 == lastfetch) ||
1782
(PR_TRUE == forcedrefresh) ||
1784
(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
1786
( (PR_FALSE == hastokenCRLs) &&
1787
( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
1788
(now < cache->lastfetch)) ) ||
1790
( (PR_TRUE == hastokenCRLs) &&
1791
((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
1792
(now < cache->lastfetch)) ) )
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)
1800
/* we are the first */
1801
rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
1802
if (PR_TRUE == cache->refresh)
1804
cache->refresh = PR_FALSE; /* clear refresh state */
1807
cache->lastfetch = PR_Now();
1809
DPCache_UnlockWrite();
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
1816
if (( PR_TRUE != dirty) && (!now) )
1820
if ( (PR_TRUE == dirty) ||
1821
( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
1822
(now < cache->lastcheck)) )
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++)
1829
CachedCrl* savcrl = cache->crls[i];
1830
if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
1832
/* we only want to check token CRLs */
1835
if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
1838
/* this CRL is gone */
1839
if (PR_TRUE != mustunlock)
1841
DPCache_LockWrite();
1842
mustunlock = PR_TRUE;
1844
/* first, we need to check if another thread did an update
1846
if (lastcheck == cache->lastcheck)
1848
/* the CRL is gone. And we are the one to do the update */
1849
DPCache_RemoveCRL(cache, i);
1852
/* stay locked here intentionally so we do all the other
1853
updates in this thread for the remaining CRLs */
1856
if (PR_TRUE == mustunlock)
1858
cache->lastcheck = PR_Now();
1859
DPCache_UnlockWrite();
1860
mustunlock = PR_FALSE;
1864
/* add issuer certificate if it was previously unavailable */
1865
if (issuer && (NULL == cache->issuer) &&
1866
(SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
1868
/* if we didn't have a valid issuer cert yet, but we do now. add it */
1869
DPCache_LockWrite();
1873
cache->issuer = CERT_DupCertificate(issuer);
1875
DPCache_UnlockWrite();
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) */
1884
if (cache->issuer && vfdate )
1886
PRBool mustunlock = PR_FALSE;
1887
/* re-process all unverified CRLs */
1888
for (i = 0; i < cache->ncrls ; i++)
1890
CachedCrl* savcrl = cache->crls[i];
1895
if (PR_TRUE != savcrl->sigChecked)
1897
if (PR_TRUE != mustunlock)
1899
DPCache_LockWrite();
1900
mustunlock = PR_TRUE;
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) )
1909
/* the CRL is still there, unverified. Do it */
1910
CachedCrl_Verify(cache, savcrl, vfdate, wincx);
1913
/* stay locked here intentionally so we do all the other
1914
updates in this thread for the remaining CRLs */
1916
if (PR_TRUE == mustunlock)
1918
DPCache_UnlockWrite();
1919
mustunlock = PR_FALSE;
1924
if (dirty || cache->mustchoose)
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();
1937
/* callback for qsort to sort by thisUpdate */
1938
static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
1940
PRTime timea, timeb;
1941
SECStatus rv = SECSuccess;
1944
a = *(CachedCrl**) arg1;
1945
b = *(CachedCrl**) arg2;
1950
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
1954
if (SECSuccess == rv)
1956
rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
1958
if (SECSuccess == rv)
1960
rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
1962
if (SECSuccess == rv)
1966
return 1; /* a is better than b */
1970
return -1; /* a is not as good as b */
1974
/* if they are equal, or if all else fails, use pointer differences */
1975
PORT_Assert(a != b); /* they should never be equal */
1979
/* callback for qsort to sort a set of disparate CRLs, some of which are
1980
invalid DER or failed signature check.
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 .
1986
static int SortImperfectCRLs(const void* arg1, const void* arg2)
1990
a = *(CachedCrl**) arg1;
1991
b = *(CachedCrl**) arg2;
1995
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2000
PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
2001
if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
2003
/* both CRLs have been validated, choose the latest one */
2004
return SortCRLsByThisUpdate(arg1, arg2);
2006
if (PR_TRUE == a->sigValid)
2008
return 1; /* a is greater than b */
2010
if (PR_TRUE == b->sigValid)
2012
return -1; /* a is not as good as b */
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) )
2019
/* both CRLs are proper DER, choose the latest one */
2020
return SortCRLsByThisUpdate(arg1, arg2);
2022
if (PR_FALSE == aDecoded)
2024
return 1; /* a is better than b */
2026
if (PR_FALSE == bDecoded)
2028
return -1; /* a is not as good as b */
2030
/* both are invalid DER. sigh. */
2032
/* if they are equal, or if all else fails, use pointer differences */
2033
PORT_Assert(a != b); /* they should never be equal */
2038
/* Pick best CRL to use . needs write access */
2039
static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
2042
PRBool valid = PR_TRUE;
2043
CachedCrl* selected = NULL;
2048
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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++)
2055
if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
2056
!cache->crls[i]->sigValid)
2062
if (PR_TRUE == valid)
2064
/* all CRLs are valid, clear this error */
2065
cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
2068
/* some CRLs are invalid, set this error */
2069
cache->invalid |= CRL_CACHE_INVALID_CRLS;
2074
/* cache is in an invalid state, so destroy it */
2075
if (cache->selected)
2077
if (SECSuccess != CachedCrl_Depopulate(cache->selected))
2082
cache->selected = NULL;
2084
/* also sort the CRLs imperfectly */
2085
qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
2089
/* all CRLs are good, sort them by thisUpdate */
2090
qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
2091
SortCRLsByThisUpdate);
2095
/* pick the newest CRL */
2096
selected = cache->crls[cache->ncrls-1];
2098
/* and populate the cache */
2099
if (SECSuccess != CachedCrl_Populate(selected))
2105
/* free the old CRL cache, if it's for a different CRL */
2106
if (cache->selected && cache->selected != selected)
2108
if (SECSuccess != CachedCrl_Depopulate(cache->selected))
2114
cache->selected = selected;
2119
/* initialize a DPCache object */
2120
static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
2121
SECItem* subject, SECItem* dp)
2123
CRLDPCache* cache = NULL;
2124
PORT_Assert(returned);
2125
/* issuer and dp are allowed to be NULL */
2126
if (!returned || !subject)
2129
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2133
cache = PORT_ZAlloc(sizeof(CRLDPCache));
2139
cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2141
cache->lock = PR_NewLock();
2150
cache->issuer = CERT_DupCertificate(issuer);
2152
cache->distributionPoint = SECITEM_DupItem(dp);
2153
cache->subject = SECITEM_DupItem(subject);
2154
cache->lastfetch = 0;
2155
cache->lastcheck = 0;
2160
/* create an issuer cache object (per CA subject ) */
2161
static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
2162
CERTCertificate* issuer,
2163
SECItem* subject, SECItem* dp)
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)
2173
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2177
cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
2182
cache->subject = SECITEM_DupItem(subject);
2184
cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
2189
if (SECSuccess == rv && issuer)
2191
cache->issuer = CERT_DupCertificate(issuer);
2198
if (SECSuccess != rv)
2200
PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
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)
2213
/* now create the required DP cache object */
2214
if (!cache || !subject || !newdpc)
2217
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2222
/* default distribution point */
2223
SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
2224
if (SECSuccess == rv)
2226
*newdpc = cache->dpp;
2232
/* we should never hit this until we support multiple DPs */
2234
/* XCRL allocate a new distribution point cache object, initialize it,
2235
and add it to the hash table of DPs */
2240
/* add an IssuerCache to the global hash table of issuers */
2241
static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
2243
PORT_Assert(issuer);
2244
PORT_Assert(crlcache.issuers);
2245
if (!issuer || !crlcache.issuers)
2247
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2250
if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
2258
/* retrieve the issuer cache object for a given issuer subject */
2259
static SECStatus CRLCache_GetIssuerCache(CRLCache* cache, SECItem* subject,
2260
CRLIssuerCache** returned)
2262
/* we need to look up the issuer in the hash table */
2263
SECStatus rv = SECSuccess;
2265
PORT_Assert(subject);
2266
PORT_Assert(returned);
2267
PORT_Assert(crlcache.issuers);
2268
if (!cache || !subject || !returned || !crlcache.issuers)
2270
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2274
if (SECSuccess == rv)
2276
*returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
2283
/* retrieve the full CRL object that best matches the content of a DPCache */
2284
static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
2286
CachedCrl* acrl = NULL;
2291
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2295
if (0 == cache->ncrls)
2301
/* if we have a valid full CRL selected, return it */
2302
if (cache->selected)
2304
return SEC_DupCrl(cache->selected->crl);
2307
/* otherwise, use latest valid DER CRL */
2308
acrl = cache->crls[cache->ncrls-1];
2310
if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
2312
SECStatus rv = SECSuccess;
2313
if (PR_TRUE == entries)
2315
rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
2317
if (SECSuccess == rv)
2319
return SEC_DupCrl(acrl->crl);
2326
/* get a particular DPCache object from an IssuerCache */
2327
static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp)
2329
CRLDPCache* dpp = NULL;
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);
2337
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2341
NSSRWLock_LockRead(cache->lock);
2345
NSSRWLock_UnlockRead(cache->lock);
2350
/* get a DPCache object for the given issuer subject and dp
2351
Automatically creates the cache object if it doesn't exist yet.
2353
static SECStatus AcquireDPCache(CERTCertificate* issuer, SECItem* subject,
2354
SECItem* dp, int64 t, void* wincx,
2355
CRLDPCache** dpcache, PRBool* writeLocked)
2357
SECStatus rv = SECSuccess;
2358
CRLIssuerCache* issuercache = NULL;
2359
#ifdef GLOBAL_RWLOCK
2360
PRBool globalwrite = PR_FALSE;
2362
PORT_Assert(crlcache.lock);
2365
/* CRL cache is not initialized */
2366
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2369
#ifdef GLOBAL_RWLOCK
2370
NSSRWLock_LockRead(crlcache.lock);
2372
PR_Lock(crlcache.lock);
2374
rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
2375
if (SECSuccess != rv)
2377
#ifdef GLOBAL_RWLOCK
2378
NSSRWLock_UnlockRead(crlcache.lock);
2380
PR_Unlock(crlcache.lock);
2382
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
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. */
2391
rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
2392
if (SECSuccess == rv && !issuercache)
2394
PORT_Assert(issuercache);
2398
if (SECSuccess == rv)
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);
2405
if (SECSuccess == rv)
2407
/* lock the DPCache for write to ensure the update happens in this
2409
*writeLocked = PR_TRUE;
2411
NSSRWLock_LockWrite((*dpcache)->lock);
2413
PR_Lock((*dpcache)->lock);
2417
if (SECSuccess == rv)
2419
/* now add the new issuer cache to the global hash table of
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);
2432
rv = CRLCache_AddIssuer(issuercache);
2433
if (SECSuccess != rv)
2438
#ifdef GLOBAL_RWLOCK
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);
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)
2455
NSSRWLock_UnlockWrite(crlcache.lock);
2456
globalwrite = PR_FALSE;
2460
NSSRWLock_UnlockRead(crlcache.lock);
2463
PR_Unlock(crlcache.lock);
2466
/* if there was a failure adding an issuer cache object, destroy it */
2467
if (SECSuccess != rv && issuercache)
2469
if (PR_TRUE == *writeLocked)
2472
NSSRWLock_UnlockWrite((*dpcache)->lock);
2474
PR_Unlock((*dpcache)->lock);
2477
IssuerCache_Destroy(issuercache);
2481
if (SECSuccess != rv)
2487
#ifdef GLOBAL_RWLOCK
2488
NSSRWLock_UnlockRead(crlcache.lock);
2490
PR_Unlock(crlcache.lock);
2492
*dpcache = IssuerCache_GetDPCache(issuercache, dp);
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)
2499
NSSRWLock_LockRead((*dpcache)->lock);
2501
PR_Lock((*dpcache)->lock);
2505
if (SECSuccess == rv)
2507
/* currently there is always one and only one DPCache per issuer */
2508
PORT_Assert(*dpcache);
2511
/* make sure the DP cache is up to date before using it */
2512
rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
2523
/* unlock access to the DPCache */
2524
static void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
2528
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2532
if (PR_TRUE == writeLocked)
2534
NSSRWLock_UnlockWrite(dpcache->lock);
2538
NSSRWLock_UnlockRead(dpcache->lock);
2541
PR_Unlock(dpcache->lock);
2545
/* check CRL revocation status of given certificate and issuer */
2547
CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp,
2548
int64 t, void* wincx)
2550
PRBool lockedwrite = PR_FALSE;
2551
SECStatus rv = SECSuccess;
2552
CRLDPCache* dpcache = NULL;
2553
if (!cert || !issuer)
2555
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2559
if (SECSuccess != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
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);
2568
rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
2571
if (SECSuccess == rv)
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)
2578
/* check the time if we have one */
2579
if (entry->revocationDate.data && entry->revocationDate.len)
2581
int64 revocationDate = 0;
2582
if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
2583
&entry->revocationDate))
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)
2593
/* invalid revocation date, consider the certificate
2594
permanently revoked */
2598
/* no revocation date, certificate is permanently revoked */
2601
if (SECFailure == rv)
2603
PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
2608
ReleaseDPCache(dpcache, lockedwrite);
2612
/* retrieve full CRL object that best matches the cache status */
2614
SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
2616
CERTSignedCrl* acrl = NULL;
2617
CRLDPCache* dpcache = NULL;
2618
SECStatus rv = SECSuccess;
2619
PRBool writeLocked = PR_FALSE;
2623
PORT_SetError(SEC_ERROR_INVALID_ARGS);
2627
rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
2628
if (SECSuccess == rv)
2630
acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
2631
SEC_FindCrlByName always returned fully decoded CRLs in the past */
2632
ReleaseDPCache(dpcache, writeLocked);
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)
2641
CRLDPCache* cache = NULL;
2642
SECStatus rv = SECSuccess;
2643
PRBool writeLocked = PR_FALSE;
2646
(void) dbhandle; /* silence compiler warnings */
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)
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);
2664
/* add the specified RAM CRL object to the cache */
2665
SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
2667
CRLDPCache* cache = NULL;
2668
SECStatus rv = SECSuccess;
2669
PRBool writeLocked = PR_FALSE;
2671
CachedCrl* returned = NULL;
2672
PRBool added = PR_FALSE;
2673
CERTSignedCrl* newcrl = NULL;
2676
if (!dbhandle || !newdercrl)
2678
PORT_SetError(SEC_ERROR_INVALID_ARGS);
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);
2692
rv = AcquireDPCache(NULL,
2693
&newcrl->crl.derName,
2694
NULL, 0, NULL, &cache, &writeLocked);
2695
if (SECSuccess == rv)
2697
readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
2699
rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
2700
if (SECSuccess == rv && returned)
2702
DPCache_LockWrite();
2703
rv = DPCache_AddCRL(cache, returned, &added);
2704
if (PR_TRUE != added)
2706
realerror = PORT_GetError();
2707
CachedCrl_Destroy(returned);
2710
DPCache_UnlockWrite();
2713
ReleaseDPCache(cache, writeLocked);
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
2725
PORT_SetError(realerror);
2730
/* remove the specified RAM CRL object from the cache */
2731
SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
2733
CRLDPCache* cache = NULL;
2734
SECStatus rv = SECSuccess;
2735
PRBool writeLocked = PR_FALSE;
2737
PRBool removed = PR_FALSE;
2739
CERTSignedCrl* oldcrl = NULL;
2741
if (!dbhandle || !olddercrl)
2743
PORT_SetError(SEC_ERROR_INVALID_ARGS);
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);
2754
/* if this DER CRL can't decode, it can't be in the cache */
2758
rv = AcquireDPCache(NULL,
2759
&oldcrl->crl.derName,
2760
NULL, 0, NULL, &cache, &writeLocked);
2761
if (SECSuccess == rv)
2763
CachedCrl* returned = NULL;
2765
readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
2767
rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
2768
if (SECSuccess == rv && returned)
2770
DPCache_LockWrite();
2771
for (i=0;i<cache->ncrls;i++)
2773
PRBool dupe = PR_FALSE, updated = PR_FALSE;
2774
rv = CachedCrl_Compare(returned, cache->crls[i],
2776
if (SECSuccess != rv)
2778
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2781
if (PR_TRUE == dupe)
2783
rv = DPCache_RemoveCRL(cache, i); /* got a match */
2784
if (SECSuccess == rv) {
2785
cache->mustchoose = PR_TRUE;
2792
DPCache_UnlockWrite();
2794
if (SECSuccess != CachedCrl_Destroy(returned) ) {
2799
ReleaseDPCache(cache, writeLocked);
2801
if (SECSuccess != SEC_DestroyCrl(oldcrl) ) {
2802
/* need to do this because object is refcounted */
2805
if (SECSuccess == rv && PR_TRUE != removed)
2807
PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
2812
static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
2815
CachedCrl* newcrl = NULL;
2818
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2821
newcrl = PORT_ZAlloc(sizeof(CachedCrl));
2826
newcrl->crl = SEC_DupCrl(crl);
2827
newcrl->origin = origin;
2832
/* empty the cache content */
2833
static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
2837
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2840
/* destroy the hash table */
2843
PL_HashTableDestroy(crl->entries);
2844
crl->entries = NULL;
2847
/* free the pre buffer */
2850
PreAllocator_Destroy(crl->prebuffer);
2851
crl->prebuffer = NULL;
2856
static SECStatus CachedCrl_Destroy(CachedCrl* crl)
2860
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2863
CachedCrl_Depopulate(crl);
2864
SEC_DestroyCrl(crl->crl);
2869
/* create hash table of CRL entries */
2870
static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
2872
SECStatus rv = SECFailure;
2873
CERTCrlEntry** crlEntry = NULL;
2874
PRUint32 numEntries = 0;
2878
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2881
/* complete the entry decoding . XXX thread-safety of CRL object */
2882
rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
2883
if (SECSuccess != rv)
2888
if (crlobject->entries && crlobject->prebuffer)
2890
/* cache is already built */
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;
2901
crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
2902
PORT_Assert(crlobject->prebuffer);
2903
if (!crlobject->prebuffer)
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)
2915
/* add all serial numbers to the hash table */
2916
for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
2919
PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
2926
/* returns true if there are CRLs from PKCS#11 slots */
2927
static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
2929
PRBool answer = PR_FALSE;
2931
for (i=0;i<cache->ncrls;i++)
2933
if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
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,
2952
PORT_Assert(isDupe);
2953
PORT_Assert(isUpdated);
2954
if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
2956
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
2960
*isDupe = *isUpdated = PR_FALSE;
2966
*isUpdated = PR_FALSE;
2969
if (b->origin != a->origin)
2971
/* CRLs of different origins are not considered dupes,
2972
and can't be updated either */
2975
if (CRL_OriginToken == b->origin)
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) )
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,
2991
*isUpdated = PR_TRUE;
2996
if (CRL_OriginExplicit == b->origin)
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.
3002
if (b->crl->derCrl == a->crl->derCrl)