Back to index

lightning-sunbird  0.9+nobinonly
crl.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /*
00038  * Moved from secpkcs7.c
00039  *
00040  * $Id: crl.c,v 1.49.24.5 2007/01/05 01:29:51 nelson%bolyard.com Exp $
00041  */
00042  
00043 #include "cert.h"
00044 #include "certi.h"
00045 #include "secder.h"
00046 #include "secasn1.h"
00047 #include "secoid.h"
00048 #include "certdb.h"
00049 #include "certxutl.h"
00050 #include "prtime.h"
00051 #include "secerr.h"
00052 #include "pk11func.h"
00053 #include "dev.h"
00054 #include "dev3hack.h"
00055 #include "nssbase.h"
00056 #if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
00057 #include "nssrwlk.h"
00058 #endif
00059 #include "pk11priv.h"
00060 
00061 const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
00062     { SEC_ASN1_SEQUENCE,
00063          0, NULL, sizeof(CERTCertExtension) },
00064     { SEC_ASN1_OBJECT_ID,
00065          offsetof(CERTCertExtension,id) },
00066     { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,             /* XXX DER_DEFAULT */
00067          offsetof(CERTCertExtension,critical), },
00068     { SEC_ASN1_OCTET_STRING,
00069          offsetof(CERTCertExtension,value) },
00070     { 0, }
00071 };
00072 
00073 static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
00074     { SEC_ASN1_SEQUENCE_OF, 0,  SEC_CERTExtensionTemplate}
00075 };
00076 
00077 /*
00078  * XXX Also, these templates, especially the Krl/FORTEZZA ones, need to
00079  * be tested; Lisa did the obvious translation but they still should be
00080  * verified.
00081  */
00082 
00083 const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
00084     { SEC_ASN1_SEQUENCE,
00085          0, NULL, sizeof(CERTIssuerAndSN) },
00086     { SEC_ASN1_SAVE,
00087          offsetof(CERTIssuerAndSN,derIssuer) },
00088     { SEC_ASN1_INLINE,
00089          offsetof(CERTIssuerAndSN,issuer),
00090          CERT_NameTemplate },
00091     { SEC_ASN1_INTEGER,
00092          offsetof(CERTIssuerAndSN,serialNumber) },
00093     { 0 }
00094 };
00095 
00096 static const SEC_ASN1Template cert_KrlEntryTemplate[] = {
00097     { SEC_ASN1_SEQUENCE,
00098          0, NULL, sizeof(CERTCrlEntry) },
00099     { SEC_ASN1_OCTET_STRING,
00100          offsetof(CERTCrlEntry,serialNumber) },
00101     { SEC_ASN1_UTC_TIME,
00102          offsetof(CERTCrlEntry,revocationDate) },
00103     { 0 }
00104 };
00105 
00106 static const SEC_ASN1Template cert_KrlTemplate[] = {
00107     { SEC_ASN1_SEQUENCE,
00108          0, NULL, sizeof(CERTCrl) },
00109     { SEC_ASN1_INLINE,
00110          offsetof(CERTCrl,signatureAlg),
00111          SECOID_AlgorithmIDTemplate },
00112     { SEC_ASN1_SAVE,
00113          offsetof(CERTCrl,derName) },
00114     { SEC_ASN1_INLINE,
00115          offsetof(CERTCrl,name),
00116          CERT_NameTemplate },
00117     { SEC_ASN1_UTC_TIME,
00118          offsetof(CERTCrl,lastUpdate) },
00119     { SEC_ASN1_UTC_TIME,
00120          offsetof(CERTCrl,nextUpdate) },
00121     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
00122          offsetof(CERTCrl,entries),
00123          cert_KrlEntryTemplate },
00124     { 0 }
00125 };
00126 
00127 static const SEC_ASN1Template cert_SignedKrlTemplate[] = {
00128     { SEC_ASN1_SEQUENCE,
00129          0, NULL, sizeof(CERTSignedCrl) },
00130     { SEC_ASN1_SAVE,
00131          offsetof(CERTSignedCrl,signatureWrap.data) },
00132     { SEC_ASN1_INLINE,
00133          offsetof(CERTSignedCrl,crl),
00134          cert_KrlTemplate },
00135     { SEC_ASN1_INLINE,
00136          offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
00137          SECOID_AlgorithmIDTemplate },
00138     { SEC_ASN1_BIT_STRING,
00139          offsetof(CERTSignedCrl,signatureWrap.signature) },
00140     { 0 }
00141 };
00142 
00143 static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
00144     { SEC_ASN1_SEQUENCE,
00145          0, NULL, sizeof(CERTCrlKey) },
00146     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
00147     { SEC_ASN1_SKIP },
00148     { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
00149     { SEC_ASN1_SKIP_REST },
00150     { 0 }
00151 };
00152 
00153 static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
00154     { SEC_ASN1_SEQUENCE,
00155          0, NULL, sizeof(CERTCrlEntry) },
00156     { SEC_ASN1_INTEGER,
00157          offsetof(CERTCrlEntry,serialNumber) },
00158     { SEC_ASN1_INLINE,
00159          offsetof(CERTCrlEntry,revocationDate), CERT_TimeChoiceTemplate },
00160     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
00161          offsetof(CERTCrlEntry, extensions),
00162          SEC_CERTExtensionTemplate},
00163     { 0 }
00164 };
00165 
00166 const SEC_ASN1Template CERT_CrlTemplate[] = {
00167     { SEC_ASN1_SEQUENCE,
00168          0, NULL, sizeof(CERTCrl) },
00169     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
00170     { SEC_ASN1_INLINE,
00171          offsetof(CERTCrl,signatureAlg),
00172          SECOID_AlgorithmIDTemplate },
00173     { SEC_ASN1_SAVE,
00174          offsetof(CERTCrl,derName) },
00175     { SEC_ASN1_INLINE,
00176          offsetof(CERTCrl,name),
00177          CERT_NameTemplate },
00178     { SEC_ASN1_INLINE,
00179          offsetof(CERTCrl,lastUpdate), CERT_TimeChoiceTemplate },
00180     { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
00181          offsetof(CERTCrl,nextUpdate), CERT_TimeChoiceTemplate },
00182     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
00183          offsetof(CERTCrl,entries),
00184          cert_CrlEntryTemplate },
00185     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
00186          SEC_ASN1_EXPLICIT | 0,
00187          offsetof(CERTCrl,extensions),
00188          SEC_CERTExtensionsTemplate},
00189     { 0 }
00190 };
00191 
00192 const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
00193     { SEC_ASN1_SEQUENCE,
00194          0, NULL, sizeof(CERTCrl) },
00195     { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
00196     { SEC_ASN1_INLINE,
00197          offsetof(CERTCrl,signatureAlg),
00198          SECOID_AlgorithmIDTemplate },
00199     { SEC_ASN1_SAVE,
00200          offsetof(CERTCrl,derName) },
00201     { SEC_ASN1_INLINE,
00202          offsetof(CERTCrl,name),
00203          CERT_NameTemplate },
00204     { SEC_ASN1_INLINE,
00205          offsetof(CERTCrl,lastUpdate), CERT_TimeChoiceTemplate },
00206     { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
00207          offsetof(CERTCrl,nextUpdate), CERT_TimeChoiceTemplate },
00208     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
00209       SEC_ASN1_SKIP }, /* skip entries */
00210     { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
00211          SEC_ASN1_EXPLICIT | 0,
00212          offsetof(CERTCrl,extensions),
00213          SEC_CERTExtensionsTemplate },
00214     { 0 }
00215 };
00216 
00217 const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
00218     { SEC_ASN1_SEQUENCE,
00219          0, NULL, sizeof(CERTCrl) },
00220     { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
00221     { SEC_ASN1_SKIP },
00222     { SEC_ASN1_SKIP },
00223     { SEC_ASN1_SKIP | SEC_ASN1_INLINE,
00224         offsetof(CERTCrl,lastUpdate), CERT_TimeChoiceTemplate },
00225     { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL,
00226         offsetof(CERTCrl,nextUpdate), CERT_TimeChoiceTemplate },
00227     { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
00228          offsetof(CERTCrl,entries),
00229          cert_CrlEntryTemplate }, /* decode entries */
00230     { SEC_ASN1_SKIP_REST },
00231     { 0 }
00232 };
00233 
00234 const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
00235     { SEC_ASN1_SEQUENCE,
00236          0, NULL, sizeof(CERTSignedCrl) },
00237     { SEC_ASN1_SAVE,
00238          offsetof(CERTSignedCrl,signatureWrap.data) },
00239     { SEC_ASN1_INLINE,
00240          offsetof(CERTSignedCrl,crl),
00241          CERT_CrlTemplate },
00242     { SEC_ASN1_INLINE,
00243          offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
00244          SECOID_AlgorithmIDTemplate },
00245     { SEC_ASN1_BIT_STRING,
00246          offsetof(CERTSignedCrl,signatureWrap.signature) },
00247     { 0 }
00248 };
00249 
00250 static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
00251     { SEC_ASN1_SEQUENCE,
00252          0, NULL, sizeof(CERTSignedCrl) },
00253     { SEC_ASN1_SAVE,
00254          offsetof(CERTSignedCrl,signatureWrap.data) },
00255     { SEC_ASN1_INLINE,
00256          offsetof(CERTSignedCrl,crl),
00257          CERT_CrlTemplateNoEntries },
00258     { SEC_ASN1_INLINE,
00259          offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
00260          SECOID_AlgorithmIDTemplate },
00261     { SEC_ASN1_BIT_STRING,
00262          offsetof(CERTSignedCrl,signatureWrap.signature) },
00263     { 0 }
00264 };
00265 
00266 const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
00267     { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
00268 };
00269 
00270 /* get CRL version */
00271 int cert_get_crl_version(CERTCrl * crl)
00272 {
00273     /* CRL version is defaulted to v1 */
00274     int version = SEC_CRL_VERSION_1;
00275     if (crl && crl->version.data != 0) {
00276        version = (int)DER_GetUInteger (&crl->version);
00277     }
00278     return version;
00279 }
00280 
00281 
00282 /* check the entries in the CRL */
00283 SECStatus cert_check_crl_entries (CERTCrl *crl)
00284 {
00285     CERTCrlEntry **entries;
00286     CERTCrlEntry *entry;
00287     PRBool hasCriticalExten = PR_FALSE;
00288     SECStatus rv = SECSuccess;
00289 
00290     if (!crl) {
00291         return SECFailure;
00292     }
00293 
00294     if (crl->entries == NULL) {
00295         /* CRLs with no entries are valid */
00296         return (SECSuccess);
00297     }
00298 
00299     /* Look in the crl entry extensions.  If there is a critical extension,
00300        then the crl version must be v2; otherwise, it should be v1.
00301      */
00302     entries = crl->entries;
00303     while (*entries) {
00304        entry = *entries;
00305        if (entry->extensions) {
00306            /* If there is a critical extension in the entries, then the
00307               CRL must be of version 2.  If we already saw a critical extension,
00308               there is no need to check the version again.
00309            */
00310             if (hasCriticalExten == PR_FALSE) {
00311                 hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
00312                 if (hasCriticalExten) {
00313                     if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 
00314                         /* only CRL v2 critical extensions are supported */
00315                         PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
00316                         rv = SECFailure;
00317                         break;
00318                     }
00319                 }
00320             }
00321 
00322            /* For each entry, make sure that it does not contain an unknown
00323               critical extension.  If it does, we must reject the CRL since
00324               we don't know how to process the extension.
00325            */
00326            if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
00327               PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
00328               rv = SECFailure;
00329               break;
00330            }
00331        }
00332        ++entries;
00333     }
00334     return(rv);
00335 }
00336 
00337 /* Check the version of the CRL.  If there is a critical extension in the crl
00338    or crl entry, then the version must be v2. Otherwise, it should be v1. If
00339    the crl contains critical extension(s), then we must recognized the
00340    extension's OID.
00341    */
00342 SECStatus cert_check_crl_version (CERTCrl *crl)
00343 {
00344     PRBool hasCriticalExten = PR_FALSE;
00345     int version = cert_get_crl_version(crl);
00346        
00347     if (version > SEC_CRL_VERSION_2) {
00348        PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
00349        return (SECFailure);
00350     }
00351 
00352     /* Check the crl extensions for a critial extension.  If one is found,
00353        and the version is not v2, then we are done.
00354      */
00355     if (crl->extensions) {
00356        hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
00357        if (hasCriticalExten) {
00358             if (version != SEC_CRL_VERSION_2) {
00359                 /* only CRL v2 critical extensions are supported */
00360                 PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
00361                 return (SECFailure);
00362             }
00363            /* make sure that there is no unknown critical extension */
00364            if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
00365               PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
00366               return (SECFailure);
00367            }
00368        }
00369     }
00370 
00371     return (SECSuccess);
00372 }
00373 
00374 /*
00375  * Generate a database key, based on the issuer name from a
00376  * DER crl.
00377  */
00378 SECStatus
00379 CERT_KeyFromDERCrl(PRArenaPool *arena, SECItem *derCrl, SECItem *key)
00380 {
00381     SECStatus rv;
00382     CERTSignedData sd;
00383     CERTCrlKey crlkey;
00384 
00385     PORT_Memset (&sd, 0, sizeof (sd));
00386     rv = SEC_ASN1DecodeItem (arena, &sd, CERT_SignedDataTemplate, derCrl);
00387     if (rv != SECSuccess) {
00388        return rv;
00389     }
00390 
00391     PORT_Memset (&crlkey, 0, sizeof (crlkey));
00392     rv = SEC_ASN1DecodeItem(arena, &crlkey, cert_CrlKeyTemplate, &sd.data);
00393     if (rv != SECSuccess) {
00394        return rv;
00395     }
00396 
00397     key->len =  crlkey.derName.len;
00398     key->data = crlkey.derName.data;
00399 
00400     return(SECSuccess);
00401 }
00402 
00403 #define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
00404 
00405 SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
00406 {
00407     SECStatus rv = SECSuccess;
00408     SECItem* crldata = NULL;
00409     OpaqueCRLFields* extended = NULL;
00410 
00411     if ( (!crl) ||
00412          (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
00413          (PR_TRUE == extended->decodingError) ) {
00414         rv = SECFailure;
00415     } else {
00416         if (PR_FALSE == extended->partial) {
00417             /* the CRL has already been fully decoded */
00418             return SECSuccess;
00419         }
00420         if (PR_TRUE == extended->badEntries) {
00421             /* the entries decoding already failed */
00422             return SECFailure;
00423         }
00424         crldata = &crl->signatureWrap.data;
00425         if (!crldata) {
00426             rv = SECFailure;
00427         }
00428     }
00429 
00430     if (SECSuccess == rv) {
00431         rv = SEC_QuickDERDecodeItem(crl->arena,
00432             &crl->crl,
00433             CERT_CrlTemplateEntriesOnly,
00434             crldata);
00435         if (SECSuccess == rv) {
00436             extended->partial = PR_FALSE; /* successful decode, avoid
00437                 decoding again */
00438         } else {
00439             extended->decodingError = PR_TRUE;
00440             extended->badEntries = PR_TRUE;
00441             /* cache the decoding failure. If it fails the first time,
00442                it will fail again, which will grow the arena and leak
00443                memory, so we want to avoid it */
00444         }
00445         rv = cert_check_crl_entries(&crl->crl);
00446         if (rv != SECSuccess) {
00447             extended->badExtensions = PR_TRUE;
00448         }
00449     }
00450     return rv;
00451 }
00452 
00453 /*
00454  * take a DER CRL or KRL  and decode it into a CRL structure
00455  * allow reusing the input DER without making a copy
00456  */
00457 CERTSignedCrl *
00458 CERT_DecodeDERCrlWithFlags(PRArenaPool *narena, SECItem *derSignedCrl,
00459                           int type, PRInt32 options)
00460 {
00461     PRArenaPool *arena;
00462     CERTSignedCrl *crl;
00463     SECStatus rv;
00464     OpaqueCRLFields* extended = NULL;
00465     const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
00466     PRInt32 testOptions = options;
00467 
00468     PORT_Assert(derSignedCrl);
00469     if (!derSignedCrl) {
00470         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00471         return NULL;
00472     }
00473 
00474     /* Adopting DER requires not copying it.  Code that sets ADOPT flag 
00475      * but doesn't set DONT_COPY probably doesn't know What it is doing.  
00476      * That condition is a programming error in the caller.
00477      */
00478     testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
00479     PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
00480     if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
00481         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00482         return NULL;
00483     }
00484 
00485     /* make a new arena if needed */
00486     if (narena == NULL) {
00487        arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00488        if ( !arena ) {
00489            return NULL;
00490        }
00491     } else {
00492        arena = narena;
00493     }
00494 
00495     /* allocate the CRL structure */
00496     crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
00497     if ( !crl ) {
00498         PORT_SetError(SEC_ERROR_NO_MEMORY);
00499        goto loser;
00500     }
00501 
00502     crl->arena = arena;
00503 
00504     /* allocate opaque fields */
00505     crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
00506     if ( !crl->opaque ) {
00507        goto loser;
00508     }
00509     extended = (OpaqueCRLFields*) crl->opaque;
00510     if (options & CRL_DECODE_ADOPT_HEAP_DER) {
00511         extended->heapDER = PR_TRUE;
00512     }
00513     if (options & CRL_DECODE_DONT_COPY_DER) {
00514         crl->derCrl = derSignedCrl; /* DER is not copied . The application
00515                                        must keep derSignedCrl until it
00516                                        destroys the CRL */
00517     } else {
00518         crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
00519         if (crl->derCrl == NULL) {
00520             goto loser;
00521         }
00522         rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
00523         if (rv != SECSuccess) {
00524             goto loser;
00525         }
00526     }
00527 
00528     /* Save the arena in the inner crl for CRL extensions support */
00529     crl->crl.arena = arena;
00530     if (options & CRL_DECODE_SKIP_ENTRIES) {
00531         crlTemplate = cert_SignedCrlTemplateNoEntries;
00532         extended->partial = PR_TRUE;
00533     }
00534 
00535     /* decode the CRL info */
00536     switch (type) {
00537     case SEC_CRL_TYPE:
00538         rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
00539         if (rv != SECSuccess) {
00540             extended->badDER = PR_TRUE;
00541             break;
00542         }
00543         /* check for critical extensions */
00544         rv =  cert_check_crl_version (&crl->crl);
00545         if (rv != SECSuccess) {
00546             extended->badExtensions = PR_TRUE;
00547             break;
00548         }
00549 
00550         if (PR_TRUE == extended->partial) {
00551             /* partial decoding, don't verify entries */
00552             break;
00553         }
00554 
00555         rv = cert_check_crl_entries(&crl->crl);
00556         if (rv != SECSuccess) {
00557             extended->badExtensions = PR_TRUE;
00558         }
00559 
00560         break;
00561 
00562     case SEC_KRL_TYPE:
00563        rv = SEC_QuickDERDecodeItem
00564             (arena, crl, cert_SignedKrlTemplate, derSignedCrl);
00565        break;
00566     default:
00567        rv = SECFailure;
00568        break;
00569     }
00570 
00571     if (rv != SECSuccess) {
00572        goto loser;
00573     }
00574 
00575     crl->referenceCount = 1;
00576     
00577     return(crl);
00578     
00579 loser:
00580     if (options & CRL_DECODE_KEEP_BAD_CRL) {
00581         if (extended) {
00582             extended->decodingError = PR_TRUE;
00583         }
00584         if (crl) {
00585             crl->referenceCount = 1;
00586             return(crl);
00587         }
00588     }
00589 
00590     if ((narena == NULL) && arena ) {
00591        PORT_FreeArena(arena, PR_FALSE);
00592     }
00593     
00594     return(0);
00595 }
00596 
00597 /*
00598  * take a DER CRL or KRL  and decode it into a CRL structure
00599  */
00600 CERTSignedCrl *
00601 CERT_DecodeDERCrl(PRArenaPool *narena, SECItem *derSignedCrl, int type)
00602 {
00603     return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
00604                                       CRL_DECODE_DEFAULT_OPTIONS);
00605 }
00606 
00607 /*
00608  * Lookup a CRL in the databases. We mirror the same fast caching data base
00609  *  caching stuff used by certificates....?
00610  * return values :
00611  *
00612  * SECSuccess means we got a valid decodable DER CRL, or no CRL at all.
00613  * Caller may distinguish those cases by the value returned in "decoded".
00614  * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
00615  *
00616  * SECFailure means we got a fatal error - most likely, we found a CRL,
00617  * and it failed decoding, or there was an out of memory error. Do NOT ignore
00618  * it and specifically do NOT treat it the same as having no CRL, as this
00619  * can compromise security !!! Ideally, you should treat this case as if you
00620  * received a "catch-all" CRL where all certs you were looking up are
00621  * considered to be revoked
00622  */
00623 static SECStatus
00624 SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
00625                        CERTSignedCrl** decoded, PRInt32 decodeoptions)
00626 {
00627     SECStatus rv = SECSuccess;
00628     CERTSignedCrl *crl = NULL;
00629     SECItem *derCrl = NULL;
00630     CK_OBJECT_HANDLE crlHandle = 0;
00631     char *url = NULL;
00632 
00633     PORT_Assert(decoded);
00634     if (!decoded) {
00635         PORT_SetError(SEC_ERROR_INVALID_ARGS);
00636         return SECFailure;
00637     }
00638 
00639     derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
00640     if (derCrl == NULL) {
00641        /* if we had a problem other than the CRL just didn't exist, return
00642         * a failure to the upper level */
00643        int nsserror = PORT_GetError();
00644        if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
00645            rv = SECFailure;
00646        }
00647        goto loser;
00648     }
00649     PORT_Assert(crlHandle != CK_INVALID_HANDLE);
00650     /* PK11_FindCrlByName obtained a slot reference. */
00651     
00652     /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
00653        Force adoption of the DER CRL from the heap - this will cause it 
00654        to be automatically freed when SEC_DestroyCrl is invoked */
00655     decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
00656 
00657     crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
00658     if (crl) {
00659         crl->slot = slot;
00660         slot = NULL; /* adopt it */
00661        derCrl = NULL; /* adopted by the crl struct */
00662         crl->pkcs11ID = crlHandle;
00663         if (url) {
00664             crl->url = PORT_ArenaStrdup(crl->arena,url);
00665         }
00666     } else {
00667         rv = SECFailure;
00668     }
00669     
00670     if (url) {
00671        PORT_Free(url);
00672     }
00673 
00674     if (slot) {
00675        PK11_FreeSlot(slot);
00676     }
00677 
00678 loser:
00679     if (derCrl) {
00680        SECITEM_FreeItem(derCrl, PR_TRUE);
00681     }
00682 
00683     *decoded = crl;
00684 
00685     return rv;
00686 }
00687 
00688 
00689 CERTSignedCrl *
00690 crl_storeCRL (PK11SlotInfo *slot,char *url,
00691                   CERTSignedCrl *newCrl, SECItem *derCrl, int type)
00692 {
00693     CERTSignedCrl *oldCrl = NULL, *crl = NULL;
00694     PRBool deleteOldCrl = PR_FALSE;
00695     CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
00696     SECStatus rv;
00697 
00698     PORT_Assert(newCrl);
00699     PORT_Assert(derCrl);
00700 
00701     /* we can't use the cache here because we must look in the same
00702        token */
00703     rv = SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
00704                                 &oldCrl, CRL_DECODE_SKIP_ENTRIES);
00705     /* if there is an old crl on the token, make sure the one we are
00706        installing is newer. If not, exit out, otherwise delete the
00707        old crl.
00708      */
00709     if (oldCrl != NULL) {
00710        /* if it's already there, quietly continue */
00711        if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) 
00712                                           == SECEqual) {
00713            crl = newCrl;
00714            crl->slot = PK11_ReferenceSlot(slot);
00715            crl->pkcs11ID = oldCrl->pkcs11ID;
00716            goto done;
00717        }
00718         if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
00719 
00720             if (type == SEC_CRL_TYPE) {
00721                 PORT_SetError(SEC_ERROR_OLD_CRL);
00722             } else {
00723                 PORT_SetError(SEC_ERROR_OLD_KRL);
00724             }
00725 
00726             goto done;
00727         }
00728 
00729         if ((SECITEM_CompareItem(&newCrl->crl.derName,
00730                 &oldCrl->crl.derName) != SECEqual) &&
00731             (type == SEC_KRL_TYPE) ) {
00732 
00733             PORT_SetError(SEC_ERROR_CKL_CONFLICT);
00734             goto done;
00735         }
00736 
00737         /* if we have a url in the database, use that one */
00738         if (oldCrl->url) {
00739            url = oldCrl->url;
00740         }
00741 
00742         /* really destroy this crl */
00743         /* first drum it out of the permanment Data base */
00744        deleteOldCrl = PR_TRUE;
00745     }
00746 
00747     /* invalidate CRL cache for this issuer */
00748     CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
00749     /* Write the new entry into the data base */
00750     crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
00751     if (crlHandle != CK_INVALID_HANDLE) {
00752        crl = newCrl;
00753        crl->slot = PK11_ReferenceSlot(slot);
00754        crl->pkcs11ID = crlHandle;
00755        if (url) {
00756            crl->url = PORT_ArenaStrdup(crl->arena,url);
00757        }
00758     }
00759 
00760 done:
00761     if (oldCrl) {
00762        if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
00763            SEC_DeletePermCRL(oldCrl);
00764        }
00765        SEC_DestroyCrl(oldCrl);
00766     }
00767 
00768     return crl;
00769 }
00770 
00771 /*
00772  *
00773  * create a new CRL from DER material.
00774  *
00775  * The signature on this CRL must be checked before you
00776  * load it. ???
00777  */
00778 CERTSignedCrl *
00779 SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
00780 {
00781     CERTSignedCrl* retCrl = NULL;
00782     PK11SlotInfo* slot = PK11_GetInternalKeySlot();
00783     retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
00784         CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
00785     PK11_FreeSlot(slot);
00786 
00787     return retCrl;
00788 }
00789     
00790 CERTSignedCrl *
00791 SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
00792 {
00793     PRArenaPool *arena;
00794     SECItem crlKey;
00795     SECStatus rv;
00796     CERTSignedCrl *crl = NULL;
00797     
00798     /* create a scratch arena */
00799     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00800     if ( arena == NULL ) {
00801        return(NULL);
00802     }
00803     
00804     /* extract the database key from the cert */
00805     rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
00806     if ( rv != SECSuccess ) {
00807        goto loser;
00808     }
00809 
00810     /* find the crl */
00811     crl = SEC_FindCrlByName(handle, &crlKey, type);
00812     
00813 loser:
00814     PORT_FreeArena(arena, PR_FALSE);
00815     return(crl);
00816 }
00817 
00818 CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
00819 {
00820     if (acrl)
00821     {
00822         PR_AtomicIncrement(&acrl->referenceCount);
00823         return acrl;
00824     }
00825     return NULL;
00826 }
00827 
00828 SECStatus
00829 SEC_DestroyCrl(CERTSignedCrl *crl)
00830 {
00831     if (crl) {
00832        if (PR_AtomicDecrement(&crl->referenceCount) < 1) {
00833            if (crl->slot) {
00834               PK11_FreeSlot(crl->slot);
00835            }
00836             if (GetOpaqueCRLFields(crl) &&
00837                 PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
00838                 SECITEM_FreeItem(crl->derCrl, PR_TRUE);
00839             }
00840             if (crl->arena) {
00841                 PORT_FreeArena(crl->arena, PR_FALSE);
00842             }
00843        }
00844         return SECSuccess;
00845     } else {
00846         return SECFailure;
00847     }
00848 }
00849 
00850 SECStatus
00851 SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
00852 {
00853     CERTCrlHeadNode *head;
00854     PRArenaPool *arena = NULL;
00855     SECStatus rv;
00856 
00857     *nodes = NULL;
00858 
00859     arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
00860     if ( arena == NULL ) {
00861        return SECFailure;
00862     }
00863 
00864     /* build a head structure */
00865     head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
00866     head->arena = arena;
00867     head->first = NULL;
00868     head->last = NULL;
00869     head->dbhandle = handle;
00870 
00871     /* Look up the proper crl types */
00872     *nodes = head;
00873 
00874     rv = PK11_LookupCrls(head, type, NULL);
00875     
00876     if (rv != SECSuccess) {
00877        if ( arena ) {
00878            PORT_FreeArena(arena, PR_FALSE);
00879            *nodes = NULL;
00880        }
00881     }
00882 
00883     return rv;
00884 }
00885 
00886 /* These functions simply return the address of the above-declared templates.
00887 ** This is necessary for Windows DLLs.  Sigh.
00888 */
00889 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
00890 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
00891 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
00892 SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
00893 
00894 /* CRL cache code starts here */
00895 
00896 /* constructor */
00897 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
00898                            CRLOrigin origin);
00899 /* destructor */
00900 static SECStatus CachedCrl_Destroy(CachedCrl* crl);
00901 
00902 /* create hash table of CRL entries */
00903 static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
00904 
00905 /* empty the cache content */
00906 static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
00907 
00908 /* are these CRLs the same, as far as the cache is concerned ?
00909    Or are they the same token object, but with different DER ? */
00910 
00911 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
00912                                 PRBool* isUpdated);
00913 
00914 /* create a DPCache object */
00915 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
00916                          SECItem* subject, SECItem* dp);
00917 
00918 /* destructor for CRL DPCache object */
00919 static SECStatus DPCache_Destroy(CRLDPCache* cache);
00920 
00921 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
00922    returns the cached CRL object . Needs write access to DPCache. */
00923 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl, PRBool* added);
00924 
00925 /* fetch the CRL for this DP from the PKCS#11 tokens */
00926 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate, void* wincx);
00927 
00928 /* check if a particular SN is in the CRL cache and return its entry */
00929 static SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, CERTCrlEntry** returned);
00930 
00931 /* update the content of the CRL cache, including fetching of CRLs, and
00932    reprocessing with specified issuer and date */
00933 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
00934                          PRBool readlocked, PRTime vfdate, void* wincx);
00935 
00936 /* returns true if there are CRLs from PKCS#11 slots */
00937 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
00938 
00939 /* remove CRL at offset specified */
00940 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
00941 
00942 /* Pick best CRL to use . needs write access */
00943 static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
00944 
00945 /* create an issuer cache object (per CA subject ) */
00946 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
00947                              CERTCertificate* issuer,
00948                              SECItem* subject, SECItem* dp);
00949 
00950 /* destructor for CRL IssuerCache object */
00951 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
00952 
00953 /* add a DPCache to the issuer cache */
00954 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer,
00955                             SECItem* subject, SECItem* dp, CRLDPCache** newdpc);
00956 
00957 /* get a particular DPCache object from an IssuerCache */
00958 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp);
00959 
00960 /*
00961 ** Pre-allocator hash allocator ops.
00962 */
00963 
00964 /* allocate memory for hash table */
00965 static void * PR_CALLBACK
00966 PreAllocTable(void *pool, PRSize size)
00967 {
00968     PreAllocator* alloc = (PreAllocator*)pool;
00969     PORT_Assert(alloc);
00970     if (!alloc)
00971     {
00972         /* no allocator, or buffer full */
00973         return NULL;
00974     }
00975     if (size > (alloc->len - alloc->used))
00976     {
00977         /* initial buffer full, let's use the arena */
00978         alloc->extra += size;
00979         return PORT_ArenaAlloc(alloc->arena, size);
00980     }
00981     /* use the initial buffer */
00982     alloc->used += size;
00983     return (char*) alloc->data + alloc->used - size;
00984 }
00985 
00986 /* free hash table memory.
00987    Individual PreAllocator elements cannot be freed, so this is a no-op. */
00988 static void PR_CALLBACK
00989 PreFreeTable(void *pool, void *item)
00990 {
00991 }
00992 
00993 /* allocate memory for hash table */
00994 static PLHashEntry * PR_CALLBACK
00995 PreAllocEntry(void *pool, const void *key)
00996 {
00997     return PreAllocTable(pool, sizeof(PLHashEntry));
00998 }
00999 
01000 /* free hash table entry.
01001    Individual PreAllocator elements cannot be freed, so this is a no-op. */
01002 static void PR_CALLBACK
01003 PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
01004 {
01005 }
01006 
01007 /* methods required for PL hash table functions */
01008 static PLHashAllocOps preAllocOps =
01009 {
01010     PreAllocTable, PreFreeTable,
01011     PreAllocEntry, PreFreeEntry
01012 };
01013 
01014 /* destructor for PreAllocator object */
01015 void PreAllocator_Destroy(PreAllocator* PreAllocator)
01016 {
01017     if (!PreAllocator)
01018     {
01019         return;
01020     }
01021     if (PreAllocator->arena)
01022     {
01023         PORT_FreeArena(PreAllocator->arena, PR_TRUE);
01024     }
01025     if (PreAllocator->data)
01026     {
01027         PORT_Free(PreAllocator->data);
01028     }
01029     PORT_Free(PreAllocator);
01030 }
01031 
01032 /* constructor for PreAllocator object */
01033 PreAllocator* PreAllocator_Create(PRSize size)
01034 {
01035     PreAllocator prebuffer;
01036     PreAllocator* prepointer = NULL;
01037     memset(&prebuffer, 0, sizeof(PreAllocator));
01038     prebuffer.len = size;
01039     prebuffer.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01040     PORT_Assert(prebuffer.arena);
01041     if (!prebuffer.arena)
01042     {
01043         PreAllocator_Destroy(&prebuffer);
01044         return NULL;
01045     }
01046     if (prebuffer.len)
01047     {
01048         prebuffer.data = PORT_Alloc(prebuffer.len);
01049         if (!prebuffer.data)
01050         {
01051             PreAllocator_Destroy(&prebuffer);
01052             return NULL;
01053         }
01054     }
01055     else
01056     {
01057         prebuffer.data = NULL;
01058     }
01059     prepointer = (PreAllocator*)PORT_Alloc(sizeof(PreAllocator));
01060     if (!prepointer)
01061     {
01062         PreAllocator_Destroy(&prebuffer);
01063         return NULL;
01064     }
01065     *prepointer = prebuffer;
01066     return prepointer;
01067 }
01068 
01069 /* global CRL cache object */
01070 static CRLCache crlcache = { NULL, NULL };
01071 
01072 /* initial state is off */
01073 static PRBool crlcache_initialized = PR_FALSE;
01074 
01075 PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
01076     to query the tokens for CRL objects, in order to discover new objects, if
01077     the cache does not contain any token CRLs . In microseconds */
01078 
01079 PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000 ; /* how often
01080     to query the tokens for CRL objects, in order to discover new objects, if
01081     the cache already contains token CRLs In microseconds */
01082 
01083 PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
01084     if a token CRL object still exists. In microseconds */
01085 
01086 /* this function is called at NSS initialization time */
01087 SECStatus InitCRLCache(void)
01088 {
01089     if (PR_FALSE == crlcache_initialized)
01090     {
01091         PORT_Assert(NULL == crlcache.lock);
01092         PORT_Assert(NULL == crlcache.issuers);
01093         if (crlcache.lock || crlcache.issuers)
01094         {
01095             /* CRL cache already partially initialized */
01096             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01097             return SECFailure;
01098         }
01099 #ifdef GLOBAL_RWLOCK
01100         crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
01101 #else
01102         crlcache.lock = PR_NewLock();
01103 #endif
01104         if (!crlcache.lock)
01105         {
01106             return SECFailure;
01107         }
01108         crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
01109                                   PL_CompareValues, NULL, NULL);
01110         if (!crlcache.issuers)
01111         {
01112 #ifdef GLOBAL_RWLOCK
01113             NSSRWLock_Destroy(crlcache.lock);
01114 #else
01115             PR_DestroyLock(crlcache.lock);
01116 #endif
01117             crlcache.lock = NULL;
01118             return SECFailure;
01119         }
01120         crlcache_initialized = PR_TRUE;
01121         return SECSuccess;
01122     }
01123     else
01124     {
01125         PORT_Assert(crlcache.lock);
01126         PORT_Assert(crlcache.issuers);
01127         if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
01128         {
01129             /* CRL cache not fully initialized */
01130             return SECFailure;
01131         }
01132         else
01133         {
01134             /* CRL cache already initialized */
01135             return SECSuccess;
01136         }
01137     }
01138 }
01139 
01140 /* destructor for CRL DPCache object */
01141 static SECStatus DPCache_Destroy(CRLDPCache* cache)
01142 {
01143     PRUint32 i = 0;
01144     PORT_Assert(cache);
01145     if (!cache)
01146     {
01147         PORT_Assert(0);
01148         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01149         return SECFailure;
01150     }
01151     if (cache->lock)
01152     {
01153 #ifdef DPC_RWLOCK
01154         NSSRWLock_Destroy(cache->lock);
01155 #else
01156         PR_DestroyLock(cache->lock);
01157 #endif
01158     }
01159     else
01160     {
01161         PORT_Assert(0);
01162         return SECFailure;
01163     }
01164     /* destroy all our CRL objects */
01165     for (i=0;i<cache->ncrls;i++)
01166     {
01167         if (!cache->crls || !cache->crls[i] ||
01168             SECSuccess != CachedCrl_Destroy(cache->crls[i]))
01169         {
01170             return SECFailure;
01171         }
01172     }
01173     /* free the array of CRLs */
01174     if (cache->crls)
01175     {
01176        PORT_Free(cache->crls);
01177     }
01178     /* destroy the cert */
01179     if (cache->issuer)
01180     {
01181         CERT_DestroyCertificate(cache->issuer);
01182     }
01183     /* free the subject */
01184     if (cache->subject)
01185     {
01186         SECITEM_FreeItem(cache->subject, PR_TRUE);
01187     }
01188     /* free the distribution points */
01189     if (cache->distributionPoint)
01190     {
01191         SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
01192     }
01193     PORT_Free(cache);
01194     return SECSuccess;
01195 }
01196 
01197 /* destructor for CRL IssuerCache object */
01198 SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
01199 {
01200     PORT_Assert(cache);
01201     if (!cache)
01202     {
01203         PORT_Assert(0);
01204         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01205         return SECFailure;
01206     }
01207 #ifdef XCRL
01208     if (cache->lock)
01209     {
01210         NSSRWLock_Destroy(cache->lock);
01211     }
01212     else
01213     {
01214         PORT_Assert(0);
01215         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01216         return SECFailure;
01217     }
01218     if (cache->issuer)
01219     {
01220         CERT_DestroyCertificate(cache->issuer);
01221     }
01222 #endif
01223     /* free the subject */
01224     if (cache->subject)
01225     {
01226         SECITEM_FreeItem(cache->subject, PR_TRUE);
01227     }
01228     if (SECSuccess != DPCache_Destroy(cache->dpp))
01229     {
01230         PORT_Assert(0);
01231         return SECFailure;
01232     }
01233     PORT_Free(cache);
01234     return SECSuccess;
01235 }
01236 
01237 /* callback function used in hash table destructor */
01238 static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
01239 {
01240     CRLIssuerCache* issuer = NULL;
01241     SECStatus* rv = (SECStatus*) arg;
01242 
01243     PORT_Assert(he);
01244     if (!he)
01245     {
01246         return HT_ENUMERATE_NEXT;
01247     }
01248     issuer = (CRLIssuerCache*) he->value;
01249     PORT_Assert(issuer);
01250     if (issuer)
01251     {
01252         if (SECSuccess != IssuerCache_Destroy(issuer))
01253         {
01254             PORT_Assert(rv);
01255             if (rv)
01256             {
01257                 *rv = SECFailure;
01258             }
01259             return HT_ENUMERATE_NEXT;
01260         }
01261     }
01262     return HT_ENUMERATE_NEXT;
01263 }
01264 
01265 /* needs to be called at NSS shutdown time
01266    This will destroy the global CRL cache, including 
01267    - the hash table of issuer cache objects
01268    - the issuer cache objects
01269    - DPCache objects in issuer cache objects */
01270 SECStatus ShutdownCRLCache(void)
01271 {
01272     SECStatus rv = SECSuccess;
01273     if (PR_FALSE == crlcache_initialized &&
01274         !crlcache.lock && !crlcache.issuers)
01275     {
01276         /* CRL cache has already been shut down */
01277         return SECSuccess;
01278     }
01279     if (PR_TRUE == crlcache_initialized &&
01280         (!crlcache.lock || !crlcache.issuers))
01281     {
01282         /* CRL cache has partially been shut down */
01283         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01284         return SECFailure;
01285     }
01286     /* empty the cache */
01287     /* free the issuers */
01288     PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
01289     /* free the hash table of issuers */
01290     PL_HashTableDestroy(crlcache.issuers);
01291     crlcache.issuers = NULL;
01292     /* free the global lock */
01293 #ifdef GLOBAL_RWLOCK
01294     NSSRWLock_Destroy(crlcache.lock);
01295 #else
01296     PR_DestroyLock(crlcache.lock);
01297 #endif
01298     crlcache.lock = NULL;
01299     crlcache_initialized = PR_FALSE;
01300     return rv;
01301 }
01302 
01303 /* add a new CRL object to the dynamic array of CRLs of the DPCache, and
01304    returns the cached CRL object . Needs write access to DPCache. */
01305 static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl,
01306                                 PRBool* added)
01307 {
01308     CachedCrl** newcrls = NULL;
01309     PRUint32 i = 0;
01310     PORT_Assert(cache);
01311     PORT_Assert(newcrl);
01312     PORT_Assert(added);
01313     if (!cache || !newcrl || !added)
01314     {
01315         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01316         return SECFailure;
01317     }
01318 
01319     *added = PR_FALSE;
01320     /* before adding a new CRL, check if it is a duplicate */
01321     for (i=0;i<cache->ncrls;i++)
01322     {
01323         CachedCrl* existing = NULL;
01324         SECStatus rv = SECSuccess;
01325         PRBool dupe = PR_FALSE, updated = PR_FALSE;
01326         if (!cache->crls)
01327         {
01328             PORT_Assert(0);
01329             return SECFailure;
01330         }
01331         existing = cache->crls[i];
01332         if (!existing)
01333         {
01334             PORT_Assert(0);
01335             return SECFailure;
01336         }
01337         rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
01338         if (SECSuccess != rv)
01339         {
01340             PORT_Assert(0);
01341             PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01342             return SECFailure;
01343         }
01344         if (PR_TRUE == dupe)
01345         {
01346             /* dupe */
01347             PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
01348             return SECSuccess;
01349         }
01350         if (PR_TRUE == updated)
01351         {
01352             /* this token CRL is in the same slot and has the same object ID,
01353                but different content. We need to remove the old object */
01354             if (SECSuccess != DPCache_RemoveCRL(cache, i))
01355             {
01356                 PORT_Assert(0);
01357                 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01358                 return PR_FALSE;
01359             }
01360         }
01361     }
01362 
01363     newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
01364         (cache->ncrls+1)*sizeof(CachedCrl*));
01365     if (!newcrls)
01366     {
01367         return SECFailure;
01368     }
01369     cache->crls = newcrls;
01370     cache->ncrls++;
01371     cache->crls[cache->ncrls-1] = newcrl;
01372     *added = PR_TRUE;
01373     return SECSuccess;
01374 }
01375 
01376 /* remove CRL at offset specified */
01377 static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
01378 {
01379     CachedCrl* acrl = NULL;
01380     PORT_Assert(cache);
01381     if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
01382     {
01383         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01384         return SECFailure;
01385     }
01386     acrl = cache->crls[offset];
01387     PORT_Assert(acrl);
01388     if (!acrl)
01389     {
01390         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01391         return SECFailure;
01392     }
01393     cache->crls[offset] = cache->crls[cache->ncrls-1];
01394     cache->crls[cache->ncrls-1] = NULL;
01395     cache->ncrls--;
01396     if (cache->selected == acrl) {
01397         cache->selected = NULL;
01398     }
01399     if (SECSuccess != CachedCrl_Destroy(acrl))
01400     {
01401         PORT_Assert(0);
01402         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01403         return SECFailure;
01404     }
01405     return SECSuccess;
01406 }
01407 
01408 /* check whether a CRL object stored in a PKCS#11 token still exists in
01409    that token . This has to be efficient (the entire CRL value cannot be
01410    transferred accross the token boundaries), so this is accomplished by
01411    simply fetching the subject attribute and making sure it hasn't changed .
01412    Note that technically, the CRL object could have been replaced with a new
01413    PKCS#11 object of the same ID and subject (which actually happens in
01414    softoken), but this function has no way of knowing that the object
01415    value changed, since CKA_VALUE isn't checked. */
01416 static PRBool TokenCRLStillExists(CERTSignedCrl* crl)
01417 {
01418     NSSItem newsubject;
01419     SECItem subject;
01420     CK_ULONG crl_class;
01421     PRStatus status;
01422     PK11SlotInfo* slot = NULL;
01423     nssCryptokiObject instance;
01424     NSSArena* arena;
01425     PRBool xstatus = PR_TRUE;
01426     SECItem* oldSubject = NULL;
01427 
01428     PORT_Assert(crl);
01429     if (!crl)
01430     {
01431         return PR_FALSE;
01432     }
01433     slot = crl->slot;
01434     PORT_Assert(crl->slot);
01435     if (!slot)
01436     {
01437         return PR_FALSE;
01438     }
01439     oldSubject = &crl->crl.derName;
01440     PORT_Assert(oldSubject);
01441     if (!oldSubject)
01442     {
01443         return PR_FALSE;
01444     }
01445 
01446     /* query subject and type attributes in order to determine if the
01447        object has been deleted */
01448 
01449     /* first, make an nssCryptokiObject */
01450     instance.handle = crl->pkcs11ID;
01451     PORT_Assert(instance.handle);
01452     if (!instance.handle)
01453     {
01454         return PR_FALSE;
01455     }
01456     instance.token = PK11Slot_GetNSSToken(slot);
01457     PORT_Assert(instance.token);
01458     if (!instance.token)
01459     {
01460         return PR_FALSE;
01461     }
01462     instance.isTokenObject = PR_TRUE;
01463     instance.label = NULL;
01464 
01465     arena = NSSArena_Create();
01466     PORT_Assert(arena);
01467     if (!arena)
01468     {
01469         return PR_FALSE;
01470     }
01471 
01472     status = nssCryptokiCRL_GetAttributes(&instance,
01473                                           NULL,  /* XXX sessionOpt */
01474                                           arena,
01475                                           NULL,
01476                                           &newsubject,  /* subject */
01477                                           &crl_class,   /* class */
01478                                           NULL,
01479                                           NULL);
01480     if (PR_SUCCESS == status)
01481     {
01482         subject.data = newsubject.data;
01483         subject.len = newsubject.size;
01484         if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
01485         {
01486             xstatus = PR_FALSE;
01487         }
01488         if (CKO_NETSCAPE_CRL != crl_class)
01489         {
01490             xstatus = PR_FALSE;
01491         }
01492     }
01493     else
01494     {
01495         xstatus = PR_FALSE;
01496     }
01497     NSSArena_Destroy(arena);
01498     return xstatus;
01499 }
01500 
01501 /* verify the signature of a CRL against its issuer at a given date */
01502 static SECStatus CERT_VerifyCRL(
01503     CERTSignedCrl* crlobject,
01504     CERTCertificate* issuer,
01505     PRTime vfdate,
01506     void* wincx)
01507 {
01508     return CERT_VerifySignedData(&crlobject->signatureWrap,
01509                                  issuer, vfdate, wincx);
01510 }
01511 
01512 /* verify a CRL and update cache state */
01513 static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
01514                           PRTime vfdate, void* wincx)
01515 {
01516     /*  Check if it is an invalid CRL
01517         if we got a bad CRL, we want to cache it in order to avoid
01518         subsequent fetches of this same identical bad CRL. We set
01519         the cache to the invalid state to ensure that all certs
01520         on this DP are considered revoked from now on. The cache
01521         object will remain in this state until the bad CRL object
01522         is removed from the token it was fetched from. If the cause
01523         of the failure is that we didn't have the issuer cert to
01524         verify the signature, this state can be cleared when
01525         the issuer certificate becomes available if that causes the
01526         signature to verify */
01527 
01528     if (!cache || !crlobject)
01529     {
01530         PORT_Assert(0);
01531         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01532         return SECFailure;
01533     }
01534     if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
01535     {
01536         crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
01537             with bogus DER. Mark it checked so we won't try again */
01538         PORT_SetError(SEC_ERROR_BAD_DER);
01539         return SECSuccess;
01540     }
01541     else
01542     {
01543         SECStatus signstatus = SECFailure;
01544         if (cache->issuer)
01545         {
01546             signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
01547                                         wincx);
01548         }
01549         if (SECSuccess != signstatus)
01550         {
01551             if (!cache->issuer)
01552             {
01553                 /* we tried to verify without an issuer cert . This is
01554                    because this CRL came through a call to SEC_FindCrlByName.
01555                    So, we don't cache this verification failure. We'll try
01556                    to verify the CRL again when a certificate from that issuer
01557                    becomes available */
01558             } else
01559             {
01560                 crlobject->sigChecked = PR_TRUE;
01561             }
01562             PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
01563             return SECSuccess;
01564         } else
01565         {
01566             crlobject->sigChecked = PR_TRUE;
01567             crlobject->sigValid = PR_TRUE;
01568         }
01569     }
01570     
01571     return SECSuccess;
01572 }
01573 
01574 /* fetch the CRLs for this DP from the PKCS#11 tokens */
01575 static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
01576                                          void* wincx)
01577 {
01578     SECStatus rv = SECSuccess;
01579     CERTCrlHeadNode head;
01580     if (!cache)
01581     {
01582         PORT_Assert(0);
01583         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01584         return SECFailure;
01585     }
01586     /* first, initialize list */
01587     memset(&head, 0, sizeof(head));
01588     head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
01589     rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
01590 
01591     /* if this function fails, something very wrong happened, such as an out
01592        of memory error during CRL decoding. We don't want to proceed and must
01593        mark the cache object invalid */
01594     if (SECFailure == rv)
01595     {
01596         /* fetch failed, add error bit */
01597         cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
01598     } else
01599     {
01600         /* fetch was successful, clear this error bit */
01601         cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
01602     }
01603 
01604     /* add any CRLs found to our array */
01605     if (SECSuccess == rv)
01606     {
01607         CERTCrlNode* crlNode = NULL;
01608 
01609         for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
01610         {
01611             CachedCrl* returned = NULL;
01612             CERTSignedCrl* crlobject = crlNode->crl;
01613             if (!crlobject)
01614             {
01615                 PORT_Assert(0);
01616                 continue;
01617             }
01618             rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
01619             if (SECSuccess == rv)
01620             {
01621                 PRBool added = PR_FALSE;
01622                 rv = DPCache_AddCRL(cache, returned, &added);
01623                 if (PR_TRUE != added)
01624                 {
01625                     rv = CachedCrl_Destroy(returned);
01626                     returned = NULL;
01627                 }
01628                 else
01629                 {
01630                     rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
01631                 }
01632             }
01633             else
01634             {
01635                 /* not enough memory to add the CRL to the cache. mark it
01636                    invalid so we will try again . */
01637                 cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
01638             }
01639             if (SECFailure == rv)
01640             {
01641                 break;
01642             }
01643         }
01644     }
01645 
01646     if (head.arena)
01647     {
01648         CERTCrlNode* crlNode = NULL;
01649         /* clean up the CRL list in case we got a partial one
01650            during a failed fetch */
01651         for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
01652         {
01653             if (crlNode->crl)
01654             {
01655                 SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
01656                    added to the cache and the refcount got bumped, or not, and
01657                    thus we need to free its RAM */
01658             }
01659         }
01660         PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
01661     }
01662 
01663     return rv;
01664 }
01665 
01666 /* check if a particular SN is in the CRL cache and return its entry */
01667 static SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn,
01668                                 CERTCrlEntry** returned)
01669 {
01670     CERTCrlEntry* acrlEntry = NULL;
01671     if (!cache || !sn || !returned)
01672     {
01673         PORT_SetError(SEC_ERROR_INVALID_ARGS);
01674         /* no cache or SN to look up, or no way to return entry */
01675         return SECFailure;
01676     }
01677     if (0 != cache->invalid)
01678     {
01679         /* the cache contains a bad CRL, or there was a CRL fetching error.
01680            consider all certs revoked as a security measure */
01681         PORT_SetError(SEC_ERROR_CRL_INVALID);
01682         return SECFailure;
01683     }
01684     if (!cache->selected)
01685     {
01686         /* no CRL means no entry to return, but this is OK */
01687         *returned = NULL;
01688         return SECSuccess;
01689     }
01690     PORT_Assert(cache->selected->entries);
01691     if (!cache->selected->entries)
01692     {
01693         return SECFailure;
01694     }
01695     /* XXX should probably use CachedCrl accessor function here */
01696     acrlEntry = PL_HashTableLookup(cache->selected->entries, (void*)sn);
01697     if (acrlEntry)
01698     {
01699         *returned = acrlEntry;
01700     }
01701     return SECSuccess;
01702 }
01703 
01704 #if defined(DPC_RWLOCK)
01705 
01706 #define DPCache_LockWrite() \
01707 { \
01708     if (readlocked) \
01709     { \
01710         NSSRWLock_UnlockRead(cache->lock); \
01711     } \
01712     NSSRWLock_LockWrite(cache->lock); \
01713 }
01714 
01715 #define DPCache_UnlockWrite() \
01716 { \
01717     if (readlocked) \
01718     { \
01719         NSSRWLock_LockRead(cache->lock); \
01720     } \
01721     NSSRWLock_UnlockWrite(cache->lock); \
01722 }
01723 
01724 #else
01725 
01726 /* with a global lock, we are always locked for read before we need write
01727    access, so do nothing */
01728 
01729 #define DPCache_LockWrite() \
01730 { \
01731 }
01732 
01733 #define DPCache_UnlockWrite() \
01734 { \
01735 }
01736 
01737 #endif
01738 
01739 /* update the content of the CRL cache, including fetching of CRLs, and
01740    reprocessing with specified issuer and date . We are always holding
01741    either the read or write lock on DPCache upon entry. */
01742 static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate*
01743                                      issuer, PRBool readlocked, PRTime vfdate,
01744                                      void* wincx)
01745 {
01746     /* Update the CRLDPCache now. We don't cache token CRL lookup misses
01747        yet, as we have no way of getting notified of new PKCS#11 object
01748        creation that happens in a token  */
01749     SECStatus rv = SECSuccess;
01750     PRUint32 i = 0;
01751     PRBool forcedrefresh = PR_FALSE;
01752     PRBool dirty = PR_FALSE; /* whether something was changed in the
01753                                 cache state during this update cycle */
01754     PRBool hastokenCRLs = PR_FALSE;
01755     PRTime now = 0;
01756     PRTime lastfetch = 0;
01757 
01758     if (!cache)
01759     {
01760         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01761         return SECFailure;
01762     }
01763 
01764     /* first, make sure we have obtained all the CRLs we need.
01765        We do an expensive token fetch in the following cases :
01766        1) cache is empty because no fetch was ever performed yet
01767        2) cache is explicitly set to refresh state
01768        3) cache is in invalid state because last fetch failed
01769        4) cache contains no token CRLs, and it's been more than one minute
01770           since the last fetch
01771        5) cache contains token CRLs, and it's been more than 10 minutes since
01772           the last fetch
01773     */
01774     forcedrefresh = cache->refresh;
01775     lastfetch = cache->lastfetch;
01776     if (PR_TRUE != forcedrefresh && 
01777         (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
01778     {
01779         now = PR_Now();
01780         hastokenCRLs = DPCache_HasTokenCRLs(cache);
01781     }
01782     if ( (0 == lastfetch) ||
01783 
01784          (PR_TRUE == forcedrefresh) ||
01785 
01786          (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
01787 
01788          ( (PR_FALSE == hastokenCRLs) &&
01789            ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
01790              (now < cache->lastfetch)) ) ||
01791 
01792          ( (PR_TRUE == hastokenCRLs) &&
01793            ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
01794             (now < cache->lastfetch)) ) )
01795     {
01796         /* the cache needs to be refreshed, and/or we had zero CRL for this
01797            DP. Try to get one from PKCS#11 tokens */
01798         DPCache_LockWrite();
01799         /* check if another thread updated before us, and skip update if so */
01800         if (lastfetch == cache->lastfetch)
01801         {
01802             /* we are the first */
01803             rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
01804             if (PR_TRUE == cache->refresh)
01805             {
01806                 cache->refresh = PR_FALSE; /* clear refresh state */
01807             }
01808             dirty = PR_TRUE;
01809             cache->lastfetch = PR_Now();
01810         }
01811         DPCache_UnlockWrite();
01812     }
01813 
01814     /* now, make sure we have no extraneous CRLs (deleted token objects)
01815        we'll do this inexpensive existence check either
01816        1) if there was a token object fetch
01817        2) every minute */
01818     if (( PR_TRUE != dirty) && (!now) )
01819     {
01820         now = PR_Now();
01821     }
01822     if ( (PR_TRUE == dirty) ||
01823          ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
01824            (now < cache->lastcheck)) )
01825     {
01826         PRBool mustunlock = PR_FALSE;
01827         PRTime lastcheck = cache->lastcheck;
01828         /* check if all CRLs still exist */
01829         for (i = 0; (i < cache->ncrls) ; i++)
01830         {
01831             CachedCrl* savcrl = cache->crls[i];
01832             if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
01833             {
01834                 /* we only want to check token CRLs */
01835                 continue;
01836             }
01837             if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
01838             {
01839                 
01840                 /* this CRL is gone */
01841                 if (PR_TRUE != mustunlock)
01842                 {
01843                     DPCache_LockWrite();
01844                     mustunlock = PR_TRUE;
01845                 }
01846                 /* first, we need to check if another thread did an update
01847                    before we did */
01848                 if (lastcheck == cache->lastcheck)
01849                 {
01850                     /* the CRL is gone. And we are the one to do the update */
01851                     DPCache_RemoveCRL(cache, i);
01852                     dirty = PR_TRUE;
01853                 }
01854                 /* stay locked here intentionally so we do all the other
01855                    updates in this thread for the remaining CRLs */
01856             }
01857         }
01858         if (PR_TRUE == mustunlock)
01859         {
01860             cache->lastcheck = PR_Now();
01861             DPCache_UnlockWrite();
01862             mustunlock = PR_FALSE;
01863         }
01864     }
01865 
01866     /* add issuer certificate if it was previously unavailable */
01867     if (issuer && (NULL == cache->issuer) &&
01868         (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
01869     {
01870         /* if we didn't have a valid issuer cert yet, but we do now. add it */
01871         DPCache_LockWrite();
01872         if (!cache->issuer)
01873         {
01874             dirty = PR_TRUE;
01875             cache->issuer = CERT_DupCertificate(issuer);    
01876         }
01877         DPCache_UnlockWrite();
01878     }
01879 
01880     /* verify CRLs that couldn't be checked when inserted into the cache
01881        because the issuer cert or a verification date was unavailable.
01882        These are CRLs that were inserted into the cache through
01883        SEC_FindCrlByName, or through manual insertion, rather than through a
01884        certificate verification (CERT_CheckCRL) */
01885 
01886     if (cache->issuer && vfdate )
01887     {
01888         PRBool mustunlock = PR_FALSE;
01889         /* re-process all unverified CRLs */
01890         for (i = 0; i < cache->ncrls ; i++)
01891         {
01892             CachedCrl* savcrl = cache->crls[i];
01893             if (!savcrl)
01894             {
01895                 continue;
01896             }
01897             if (PR_TRUE != savcrl->sigChecked)
01898             {
01899                 if (PR_TRUE != mustunlock)
01900                 {
01901                     DPCache_LockWrite();
01902                     mustunlock = PR_TRUE;
01903                 }
01904                 /* first, we need to check if another thread updated
01905                    it before we did, and abort if it has been modified since
01906                    we acquired the lock. Make sure first that the CRL is still
01907                    in the array at the same position */
01908                 if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
01909                      (PR_TRUE != savcrl->sigChecked) )
01910                 {
01911                     /* the CRL is still there, unverified. Do it */
01912                     CachedCrl_Verify(cache, savcrl, vfdate, wincx);
01913                     dirty = PR_TRUE;
01914                 }
01915                 /* stay locked here intentionally so we do all the other
01916                    updates in this thread for the remaining CRLs */
01917             }
01918             if (PR_TRUE == mustunlock)
01919             {
01920                 DPCache_UnlockWrite();
01921                 mustunlock = PR_FALSE;
01922             }
01923         }
01924     }
01925 
01926     if (dirty || cache->mustchoose)
01927     {
01928         /* changes to the content of the CRL cache necessitate examining all
01929            CRLs for selection of the most appropriate one to cache */
01930         DPCache_LockWrite();
01931         DPCache_SelectCRL(cache);
01932         cache->mustchoose = PR_FALSE;
01933         DPCache_UnlockWrite();
01934     }
01935 
01936     return rv;
01937 }
01938 
01939 /* callback for qsort to sort by thisUpdate */
01940 static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
01941 {
01942     PRTime timea, timeb;
01943     SECStatus rv = SECSuccess;
01944     CachedCrl* a, *b;
01945 
01946     a = *(CachedCrl**) arg1;
01947     b = *(CachedCrl**) arg2;
01948 
01949     if (!a || !b)
01950     {
01951         PORT_Assert(0);
01952         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01953         rv = SECFailure;
01954     }
01955 
01956     if (SECSuccess == rv)
01957     {
01958         rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
01959     }                       
01960     if (SECSuccess == rv)
01961     {
01962         rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
01963     }
01964     if (SECSuccess == rv)
01965     {
01966         if (timea > timeb)
01967         {
01968             return 1; /* a is better than b */
01969         }
01970         if (timea < timeb )
01971         {
01972             return -1; /* a is not as good as b */
01973         }
01974     }
01975 
01976     /* if they are equal, or if all else fails, use pointer differences */
01977     PORT_Assert(a != b); /* they should never be equal */
01978     return a>b?1:-1;
01979 }
01980 
01981 /* callback for qsort to sort a set of disparate CRLs, some of which are
01982    invalid DER or failed signature check.
01983    
01984    Validated CRLs are differentiated by thisUpdate .
01985    Validated CRLs are preferred over non-validated CRLs .
01986    Proper DER CRLs are preferred over non-DER data .
01987 */
01988 static int SortImperfectCRLs(const void* arg1, const void* arg2)
01989 {
01990     CachedCrl* a, *b;
01991 
01992     a = *(CachedCrl**) arg1;
01993     b = *(CachedCrl**) arg2;
01994 
01995     if (!a || !b)
01996     {
01997         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
01998         PORT_Assert(0);
01999     }
02000     else
02001     {
02002         PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
02003         if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
02004         {
02005             /* both CRLs have been validated, choose the latest one */
02006             return SortCRLsByThisUpdate(arg1, arg2);
02007         }
02008         if (PR_TRUE == a->sigValid)
02009         {
02010             return 1; /* a is greater than b */
02011         }
02012         if (PR_TRUE == b->sigValid)
02013         {
02014             return -1; /* a is not as good as b */
02015         }
02016         aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
02017         bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
02018         /* neither CRL had its signature check pass */
02019         if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
02020         {
02021             /* both CRLs are proper DER, choose the latest one */
02022             return SortCRLsByThisUpdate(arg1, arg2);
02023         }
02024         if (PR_FALSE == aDecoded)
02025         {
02026             return 1; /* a is better than b */
02027         }
02028         if (PR_FALSE == bDecoded)
02029         {
02030             return -1; /* a is not as good as b */
02031         }
02032         /* both are invalid DER. sigh. */
02033     }
02034     /* if they are equal, or if all else fails, use pointer differences */
02035     PORT_Assert(a != b); /* they should never be equal */
02036     return a>b?1:-1;
02037 }
02038 
02039 
02040 /* Pick best CRL to use . needs write access */
02041 static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
02042 {
02043     PRUint32 i;
02044     PRBool valid = PR_TRUE;
02045     CachedCrl* selected = NULL;
02046 
02047     PORT_Assert(cache);
02048     if (!cache)
02049     {
02050         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02051         return SECFailure;
02052     }
02053     /* if any invalid CRL is present, then the CRL cache is
02054        considered invalid, for security reasons */
02055     for (i = 0 ; i<cache->ncrls; i++)
02056     {
02057         if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
02058             !cache->crls[i]->sigValid)
02059         {
02060             valid = PR_FALSE;
02061             break;
02062         }
02063     }
02064     if (PR_TRUE == valid)
02065     {
02066         /* all CRLs are valid, clear this error */
02067         cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
02068     } else
02069     {
02070         /* some CRLs are invalid, set this error */
02071         cache->invalid |= CRL_CACHE_INVALID_CRLS;
02072     }
02073 
02074     if (cache->invalid)
02075     {
02076         /* cache is in an invalid state, so destroy it */
02077         if (cache->selected)
02078         {
02079             if (SECSuccess != CachedCrl_Depopulate(cache->selected))
02080             {
02081                 PORT_Assert(0);
02082                 return SECFailure;
02083             }
02084             cache->selected = NULL;
02085         }
02086         /* also sort the CRLs imperfectly */
02087         qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
02088               SortImperfectCRLs);
02089         return SECSuccess;
02090     }
02091     /* all CRLs are good, sort them by thisUpdate */
02092     qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
02093           SortCRLsByThisUpdate);
02094 
02095     if (cache->ncrls)
02096     {
02097         /* pick the newest CRL */
02098         selected = cache->crls[cache->ncrls-1];
02099     
02100         /* and populate the cache */
02101         if (SECSuccess != CachedCrl_Populate(selected))
02102         {
02103             return SECFailure;
02104         }
02105     }
02106 
02107     /* free the old CRL cache, if it's for a different CRL */
02108     if (cache->selected && cache->selected != selected)
02109     {
02110         if (SECSuccess != CachedCrl_Depopulate(cache->selected))
02111         {
02112             return SECFailure;
02113         }
02114     }
02115 
02116     cache->selected = selected;
02117 
02118     return SECSuccess;
02119 }
02120 
02121 /* initialize a DPCache object */
02122 static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
02123                          SECItem* subject, SECItem* dp)
02124 {
02125     CRLDPCache* cache = NULL;
02126     PORT_Assert(returned);
02127     /* issuer and dp are allowed to be NULL */
02128     if (!returned || !subject)
02129     {
02130         PORT_Assert(0);
02131         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02132         return SECFailure;
02133     }
02134     *returned = NULL;
02135     cache = PORT_ZAlloc(sizeof(CRLDPCache));
02136     if (!cache)
02137     {
02138         return SECFailure;
02139     }
02140 #ifdef DPC_RWLOCK
02141     cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
02142 #else
02143     cache->lock = PR_NewLock();
02144 #endif
02145     if (!cache->lock)
02146     {
02147        PORT_Free(cache);
02148         return SECFailure;
02149     }
02150     if (issuer)
02151     {
02152         cache->issuer = CERT_DupCertificate(issuer);
02153     }
02154     cache->distributionPoint = SECITEM_DupItem(dp);
02155     cache->subject = SECITEM_DupItem(subject);
02156     cache->lastfetch = 0;
02157     cache->lastcheck = 0;
02158     *returned = cache;
02159     return SECSuccess;
02160 }
02161 
02162 /* create an issuer cache object (per CA subject ) */
02163 static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
02164                              CERTCertificate* issuer,
02165                              SECItem* subject, SECItem* dp)
02166 {
02167     SECStatus rv = SECSuccess;
02168     CRLIssuerCache* cache = NULL;
02169     PORT_Assert(returned);
02170     PORT_Assert(subject);
02171     /* issuer and dp are allowed to be NULL */
02172     if (!returned || !subject)
02173     {
02174         PORT_Assert(0);
02175         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02176         return SECFailure;
02177     }
02178     *returned = NULL;
02179     cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
02180     if (!cache)
02181     {
02182         return SECFailure;
02183     }
02184     cache->subject = SECITEM_DupItem(subject);
02185 #ifdef XCRL
02186     cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
02187     if (!cache->lock)
02188     {
02189         rv = SECFailure;
02190     }
02191     if (SECSuccess == rv && issuer)
02192     {
02193         cache->issuer = CERT_DupCertificate(issuer);
02194         if (!cache->issuer)
02195         {
02196             rv = SECFailure;
02197         }
02198     }
02199 #endif
02200     if (SECSuccess != rv)
02201     {
02202         PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
02203         return SECFailure;
02204     }
02205     *returned = cache;
02206     return SECSuccess;
02207 }
02208 
02209 /* add a DPCache to the issuer cache */
02210 static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
02211                                    CERTCertificate* issuer,
02212                                    SECItem* subject, SECItem* dp,
02213                                    CRLDPCache** newdpc)
02214 {
02215     /* now create the required DP cache object */
02216     if (!cache || !subject || !newdpc)
02217     {
02218         PORT_Assert(0);
02219         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02220         return SECFailure;
02221     }
02222     if (!dp)
02223     {
02224         /* default distribution point */
02225         SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
02226         if (SECSuccess == rv)
02227         {
02228             *newdpc = cache->dpp;
02229             return SECSuccess;
02230         }
02231     }
02232     else
02233     {
02234         /* we should never hit this until we support multiple DPs */
02235         PORT_Assert(dp);
02236         /* XCRL allocate a new distribution point cache object, initialize it,
02237            and add it to the hash table of DPs */
02238     }
02239     return SECFailure;
02240 }
02241 
02242 /* add an IssuerCache to the global hash table of issuers */
02243 static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
02244 {    
02245     PORT_Assert(issuer);
02246     PORT_Assert(crlcache.issuers);
02247     if (!issuer || !crlcache.issuers)
02248     {
02249         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02250         return SECFailure;
02251     }
02252     if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
02253                                 (void*) issuer))
02254     {
02255         return SECFailure;
02256     }
02257     return SECSuccess;
02258 }
02259 
02260 /* retrieve the issuer cache object for a given issuer subject */
02261 static SECStatus CRLCache_GetIssuerCache(CRLCache* cache, SECItem* subject,
02262                                          CRLIssuerCache** returned)
02263 {
02264     /* we need to look up the issuer in the hash table */
02265     SECStatus rv = SECSuccess;
02266     PORT_Assert(cache);
02267     PORT_Assert(subject);
02268     PORT_Assert(returned);
02269     PORT_Assert(crlcache.issuers);
02270     if (!cache || !subject || !returned || !crlcache.issuers)
02271     {
02272         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02273         rv = SECFailure;
02274     }
02275 
02276     if (SECSuccess == rv)
02277     {
02278         *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
02279                                                          (void*) subject);
02280     }
02281 
02282     return rv;
02283 }
02284 
02285 /* retrieve the full CRL object that best matches the content of a DPCache */
02286 static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
02287 {
02288     CachedCrl* acrl = NULL;
02289 
02290     PORT_Assert(cache);
02291     if (!cache)
02292     {
02293         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02294         return NULL;
02295     }
02296 
02297     if (0 == cache->ncrls)
02298     {
02299         /* empty cache*/
02300         return NULL;
02301     }    
02302 
02303     /* if we have a valid full CRL selected, return it */
02304     if (cache->selected)
02305     {
02306         return SEC_DupCrl(cache->selected->crl);
02307     }
02308 
02309     /* otherwise, use latest valid DER CRL */
02310     acrl = cache->crls[cache->ncrls-1];
02311 
02312     if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
02313     {
02314         SECStatus rv = SECSuccess;
02315         if (PR_TRUE == entries)
02316         {
02317             rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
02318         }
02319         if (SECSuccess == rv)
02320         {
02321             return SEC_DupCrl(acrl->crl);
02322         }
02323     }
02324 
02325     return NULL;
02326 }
02327 
02328 /* get a particular DPCache object from an IssuerCache */
02329 static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp)
02330 {
02331     CRLDPCache* dpp = NULL;
02332     PORT_Assert(cache);
02333     /* XCRL for now we only support the "default" DP, ie. the
02334        full CRL. So we can return the global one without locking. In
02335        the future we will have a lock */
02336     PORT_Assert(NULL == dp);
02337     if (!cache || dp)
02338     {
02339         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02340         return NULL;
02341     }
02342 #ifdef XCRL
02343     NSSRWLock_LockRead(cache->lock);
02344 #endif
02345     dpp = cache->dpp;
02346 #ifdef XCRL
02347     NSSRWLock_UnlockRead(cache->lock);
02348 #endif
02349     return dpp;
02350 }
02351 
02352 /* get a DPCache object for the given issuer subject and dp
02353    Automatically creates the cache object if it doesn't exist yet.
02354    */
02355 static SECStatus AcquireDPCache(CERTCertificate* issuer, SECItem* subject,
02356                                 SECItem* dp, int64 t, void* wincx,
02357                                 CRLDPCache** dpcache, PRBool* writeLocked)
02358 {
02359     SECStatus rv = SECSuccess;
02360     CRLIssuerCache* issuercache = NULL;
02361 #ifdef GLOBAL_RWLOCK
02362     PRBool globalwrite = PR_FALSE;
02363 #endif
02364     PORT_Assert(crlcache.lock);
02365     if (!crlcache.lock)
02366     {
02367         /* CRL cache is not initialized */
02368         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02369         return SECFailure;
02370     }
02371 #ifdef GLOBAL_RWLOCK
02372     NSSRWLock_LockRead(crlcache.lock);
02373 #else
02374     PR_Lock(crlcache.lock);
02375 #endif
02376     rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
02377     if (SECSuccess != rv)
02378     {
02379 #ifdef GLOBAL_RWLOCK
02380         NSSRWLock_UnlockRead(crlcache.lock);
02381 #else
02382         PR_Unlock(crlcache.lock);
02383 #endif
02384         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02385         return SECFailure;
02386     }
02387     if (!issuercache)
02388     {
02389         /* there is no cache for this issuer yet. This means this is the
02390            first time we look up a cert from that issuer, and we need to
02391            create the cache. */
02392         
02393         rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
02394         if (SECSuccess == rv && !issuercache)
02395         {
02396             PORT_Assert(issuercache);
02397             rv = SECFailure;
02398         }
02399 
02400         if (SECSuccess == rv)
02401         {
02402             /* This is the first time we look up a cert of this issuer.
02403                Create the DPCache for this DP . */
02404             rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
02405         }
02406 
02407         if (SECSuccess == rv)
02408         {
02409             /* lock the DPCache for write to ensure the update happens in this
02410                thread */
02411             *writeLocked = PR_TRUE;
02412 #ifdef DPC_RWLOCK
02413             NSSRWLock_LockWrite((*dpcache)->lock);
02414 #else
02415             PR_Lock((*dpcache)->lock);
02416 #endif
02417         }
02418         
02419         if (SECSuccess == rv)
02420         {
02421             /* now add the new issuer cache to the global hash table of
02422                issuers */
02423 #ifdef GLOBAL_RWLOCK
02424             CRLIssuerCache* existing = NULL;
02425             NSSRWLock_UnlockRead(crlcache.lock);
02426             /* when using a r/w lock for the global cache, check if the issuer
02427                already exists before adding to the hash table */
02428             NSSRWLock_LockWrite(crlcache.lock);
02429             globalwrite = PR_TRUE;
02430             rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
02431             if (!existing)
02432             {
02433 #endif
02434                 rv = CRLCache_AddIssuer(issuercache);
02435                 if (SECSuccess != rv)
02436                 {
02437                     /* failure */
02438                     rv = SECFailure;
02439                 }
02440 #ifdef GLOBAL_RWLOCK
02441             }
02442             else
02443             {
02444                 /* somebody else updated before we did */
02445                 IssuerCache_Destroy(issuercache); /* destroy the new object */
02446                 issuercache = existing; /* use the existing one */
02447                 *dpcache = IssuerCache_GetDPCache(issuercache, dp);
02448             }
02449 #endif
02450         }
02451 
02452         /* now unlock the global cache. We only want to lock the issuer hash
02453            table addition. Holding it longer would hurt scalability */
02454 #ifdef GLOBAL_RWLOCK
02455         if (PR_TRUE == globalwrite)
02456         {
02457             NSSRWLock_UnlockWrite(crlcache.lock);
02458             globalwrite = PR_FALSE;
02459         }
02460         else
02461         {
02462             NSSRWLock_UnlockRead(crlcache.lock);
02463         }
02464 #else
02465         PR_Unlock(crlcache.lock);
02466 #endif
02467 
02468         /* if there was a failure adding an issuer cache object, destroy it */
02469         if (SECSuccess != rv && issuercache)
02470         {
02471             if (PR_TRUE == *writeLocked)
02472             {
02473 #ifdef DPC_RWLOCK
02474                 NSSRWLock_UnlockWrite((*dpcache)->lock);
02475 #else
02476                 PR_Unlock((*dpcache)->lock);
02477 #endif
02478             }
02479             IssuerCache_Destroy(issuercache);
02480             issuercache = NULL;
02481         }
02482 
02483         if (SECSuccess != rv)
02484         {
02485             return SECFailure;
02486         }
02487     } else
02488     {
02489 #ifdef GLOBAL_RWLOCK
02490         NSSRWLock_UnlockRead(crlcache.lock);
02491 #else
02492         PR_Unlock(crlcache.lock);
02493 #endif
02494         *dpcache = IssuerCache_GetDPCache(issuercache, dp);
02495     }
02496     /* we now have a DPCache that we can use for lookups */
02497     /* lock it for read, unless we already locked for write */
02498     if (PR_FALSE == *writeLocked)
02499     {
02500 #ifdef DPC_RWLOCK
02501         NSSRWLock_LockRead((*dpcache)->lock);
02502 #else
02503         PR_Lock((*dpcache)->lock);
02504 #endif
02505     }
02506     
02507     if (SECSuccess == rv)
02508     {
02509         /* currently there is always one and only one DPCache per issuer */
02510         PORT_Assert(*dpcache);
02511         if (*dpcache)
02512         {
02513             /* make sure the DP cache is up to date before using it */
02514             rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
02515                                      t, wincx);
02516         }
02517         else
02518         {
02519             rv = SECFailure;
02520         }
02521     }
02522     return rv;
02523 }
02524 
02525 /* unlock access to the DPCache */
02526 static void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
02527 {
02528     if (!dpcache)
02529     {
02530         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02531         return;
02532     }
02533 #ifdef DPC_RWLOCK
02534     if (PR_TRUE == writeLocked)
02535     {
02536         NSSRWLock_UnlockWrite(dpcache->lock);
02537     }
02538     else
02539     {
02540         NSSRWLock_UnlockRead(dpcache->lock);
02541     }
02542 #else
02543     PR_Unlock(dpcache->lock);
02544 #endif
02545 }
02546 
02547 /* check CRL revocation status of given certificate and issuer */
02548 SECStatus
02549 CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp,
02550               int64 t, void* wincx)
02551 {
02552     PRBool lockedwrite = PR_FALSE;
02553     SECStatus rv = SECSuccess;
02554     CRLDPCache* dpcache = NULL;
02555     if (!cert || !issuer)
02556     {
02557         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02558         return SECFailure;
02559     }
02560 
02561     if (SECSuccess != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
02562     {
02563         /* we won't be able to check the CRL's signature if the issuer cert
02564            is expired as of the time we are verifying. This may cause a valid
02565            CRL to be cached as bad. short-circuit to avoid this case. */
02566         PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
02567         return SECFailure;
02568     }
02569 
02570     rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
02571                         &lockedwrite);
02572     
02573     if (SECSuccess == rv)
02574     {
02575         /* now look up the certificate SN in the DP cache's CRL */
02576         CERTCrlEntry* entry = NULL;
02577         rv = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
02578         if (SECSuccess == rv && entry)
02579         {
02580             /* check the time if we have one */
02581             if (entry->revocationDate.data && entry->revocationDate.len)
02582             {
02583                 int64 revocationDate = 0;
02584                 if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
02585                                                &entry->revocationDate))
02586                 {
02587                     /* we got a good revocation date, only consider the
02588                        certificate revoked if the time we are inquiring about
02589                        is past the revocation date */
02590                     if (t>=revocationDate)
02591                     {
02592                         rv = SECFailure;
02593                     }
02594                 } else {
02595                     /* invalid revocation date, consider the certificate
02596                        permanently revoked */
02597                     rv = SECFailure;
02598                 }
02599             } else {
02600                 /* no revocation date, certificate is permanently revoked */
02601                 rv = SECFailure;
02602             }
02603             if (SECFailure == rv)
02604             {
02605                 PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
02606             }
02607         }
02608     }
02609 
02610     ReleaseDPCache(dpcache, lockedwrite);
02611     return rv;
02612 }
02613 
02614 /* retrieve full CRL object that best matches the cache status */
02615 CERTSignedCrl *
02616 SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
02617 {
02618     CERTSignedCrl* acrl = NULL;
02619     CRLDPCache* dpcache = NULL;
02620     SECStatus rv = SECSuccess;
02621     PRBool writeLocked = PR_FALSE;
02622 
02623     if (!crlKey)
02624     {
02625         PORT_SetError(SEC_ERROR_INVALID_ARGS);
02626         return NULL;
02627     }
02628 
02629     rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
02630     if (SECSuccess == rv)
02631     {
02632         acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
02633         SEC_FindCrlByName always returned fully decoded CRLs in the past */
02634         ReleaseDPCache(dpcache, writeLocked);
02635     }
02636     return acrl;
02637 }
02638 
02639 /* invalidate the CRL cache for a given issuer, which forces a refetch of
02640    CRL objects from PKCS#11 tokens */
02641 void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
02642 {
02643     CRLDPCache* cache = NULL;
02644     SECStatus rv = SECSuccess;
02645     PRBool writeLocked = PR_FALSE;
02646     PRBool readlocked;
02647 
02648     (void) dbhandle; /* silence compiler warnings */
02649 
02650     /* XCRL we will need to refresh all the DPs of the issuer in the future,
02651             not just the default one */
02652     rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
02653     if (SECSuccess != rv)
02654     {
02655         return;
02656     }
02657     /* we need to invalidate the DPCache here */
02658     readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
02659     DPCache_LockWrite();
02660     cache->refresh = PR_TRUE;
02661     DPCache_UnlockWrite();
02662     ReleaseDPCache(cache, writeLocked);
02663     return;
02664 }
02665 
02666 /* add the specified RAM CRL object to the cache */
02667 SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
02668 {
02669     CRLDPCache* cache = NULL;
02670     SECStatus rv = SECSuccess;
02671     PRBool writeLocked = PR_FALSE;
02672     PRBool readlocked;
02673     CachedCrl* returned = NULL;
02674     PRBool added = PR_FALSE;
02675     CERTSignedCrl* newcrl = NULL;
02676     int realerror = 0;
02677     
02678     if (!dbhandle || !newdercrl)
02679     {
02680         PORT_SetError(SEC_ERROR_INVALID_ARGS);
02681         return SECFailure;
02682     }
02683 
02684     /* first decode the DER CRL to make sure it's OK */
02685     newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
02686                                         CRL_DECODE_DONT_COPY_DER |
02687                                         CRL_DECODE_SKIP_ENTRIES);
02688 
02689     if (!newcrl)
02690     {
02691         return SECFailure;
02692     }
02693 
02694     rv = AcquireDPCache(NULL,
02695                         &newcrl->crl.derName,
02696                         NULL, 0, NULL, &cache, &writeLocked);
02697     if (SECSuccess == rv)
02698     {
02699         readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
02700     
02701         rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
02702         if (SECSuccess == rv && returned)
02703         {
02704             DPCache_LockWrite();
02705             rv = DPCache_AddCRL(cache, returned, &added);
02706             if (PR_TRUE != added)
02707             {
02708                 realerror = PORT_GetError();
02709                 CachedCrl_Destroy(returned);
02710                 returned = NULL;
02711             }
02712             DPCache_UnlockWrite();
02713         }
02714     
02715         ReleaseDPCache(cache, writeLocked);
02716     
02717         if (!added)
02718         {
02719             rv = SECFailure;
02720         }
02721     }
02722     SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
02723         and the refcount got bumped, or not, and thus we need to free its
02724         RAM */
02725     if (realerror)
02726     {
02727         PORT_SetError(realerror);
02728     }
02729     return rv;
02730 }
02731 
02732 /* remove the specified RAM CRL object from the cache */
02733 SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
02734 {
02735     CRLDPCache* cache = NULL;
02736     SECStatus rv = SECSuccess;
02737     PRBool writeLocked = PR_FALSE;
02738     PRBool readlocked;
02739     PRBool removed = PR_FALSE;
02740     PRUint32 i;
02741     CERTSignedCrl* oldcrl = NULL;
02742     
02743     if (!dbhandle || !olddercrl)
02744     {
02745         PORT_SetError(SEC_ERROR_INVALID_ARGS);
02746         return SECFailure;
02747     }
02748 
02749     /* first decode the DER CRL to make sure it's OK */
02750     oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
02751                                         CRL_DECODE_DONT_COPY_DER |
02752                                         CRL_DECODE_SKIP_ENTRIES);
02753 
02754     if (!oldcrl)
02755     {
02756         /* if this DER CRL can't decode, it can't be in the cache */
02757         return SECFailure;
02758     }
02759 
02760     rv = AcquireDPCache(NULL,
02761                         &oldcrl->crl.derName,
02762                         NULL, 0, NULL, &cache, &writeLocked);
02763     if (SECSuccess == rv)
02764     {
02765         CachedCrl* returned = NULL;
02766 
02767         readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
02768     
02769         rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
02770         if (SECSuccess == rv && returned)
02771         {
02772             DPCache_LockWrite();
02773             for (i=0;i<cache->ncrls;i++)
02774             {
02775                 PRBool dupe = PR_FALSE, updated = PR_FALSE;
02776                 rv = CachedCrl_Compare(returned, cache->crls[i],
02777                                                       &dupe, &updated);
02778                 if (SECSuccess != rv)
02779                 {
02780                     PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02781                     break;
02782                 }
02783                 if (PR_TRUE == dupe)
02784                 {
02785                     rv = DPCache_RemoveCRL(cache, i); /* got a match */
02786                     if (SECSuccess == rv) {
02787                         cache->mustchoose = PR_TRUE;
02788                         removed = PR_TRUE;
02789                     }
02790                     break;
02791                 }
02792             }
02793             
02794             DPCache_UnlockWrite();
02795 
02796             if (SECSuccess != CachedCrl_Destroy(returned) ) {
02797                 rv = SECFailure;
02798             }
02799         }
02800 
02801         ReleaseDPCache(cache, writeLocked);
02802     }
02803     if (SECSuccess != SEC_DestroyCrl(oldcrl) ) { 
02804         /* need to do this because object is refcounted */
02805         rv = SECFailure;
02806     }
02807     if (SECSuccess == rv && PR_TRUE != removed)
02808     {
02809         PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
02810     }
02811     return rv;
02812 }
02813 
02814 static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
02815                                   CRLOrigin origin)
02816 {
02817     CachedCrl* newcrl = NULL;
02818     if (!returned)
02819     {
02820         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02821         return SECFailure;
02822     }
02823     newcrl = PORT_ZAlloc(sizeof(CachedCrl));
02824     if (!newcrl)
02825     {
02826         return SECFailure;
02827     }
02828     newcrl->crl = SEC_DupCrl(crl);
02829     newcrl->origin = origin;
02830     *returned = newcrl;
02831     return SECSuccess;
02832 }
02833 
02834 /* empty the cache content */
02835 static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
02836 {
02837     if (!crl)
02838     {
02839         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02840         return SECFailure;
02841     }
02842      /* destroy the hash table */
02843     if (crl->entries)
02844     {
02845         PL_HashTableDestroy(crl->entries);
02846         crl->entries = NULL;
02847     }
02848 
02849     /* free the pre buffer */
02850     if (crl->prebuffer)
02851     {
02852         PreAllocator_Destroy(crl->prebuffer);
02853         crl->prebuffer = NULL;
02854     }
02855     return SECSuccess;
02856 }
02857 
02858 static SECStatus CachedCrl_Destroy(CachedCrl* crl)
02859 {
02860     if (!crl)
02861     {
02862         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02863         return SECFailure;
02864     }
02865     CachedCrl_Depopulate(crl);
02866     SEC_DestroyCrl(crl->crl);
02867     PORT_Free(crl);
02868     return SECSuccess;
02869 }
02870 
02871 /* create hash table of CRL entries */
02872 static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
02873 {
02874     SECStatus rv = SECFailure;
02875     CERTCrlEntry** crlEntry = NULL;
02876     PRUint32 numEntries = 0;
02877 
02878     if (!crlobject)
02879     {
02880         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02881         return SECFailure;
02882     }
02883     /* complete the entry decoding . XXX thread-safety of CRL object */
02884     rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
02885     if (SECSuccess != rv)
02886     {
02887         return SECFailure;
02888     }
02889 
02890     if (crlobject->entries && crlobject->prebuffer)
02891     {
02892         /* cache is already built */
02893         return SECSuccess;
02894     }
02895 
02896     /* build the hash table from the full CRL */    
02897     /* count CRL entries so we can pre-allocate space for hash table entries */
02898     for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
02899          crlEntry++)
02900     {
02901         numEntries++;
02902     }
02903     crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
02904     PORT_Assert(crlobject->prebuffer);
02905     if (!crlobject->prebuffer)
02906     {
02907         return SECFailure;
02908     }
02909     /* create a new hash table */
02910     crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
02911                          PL_CompareValues, &preAllocOps, crlobject->prebuffer);
02912     PORT_Assert(crlobject->entries);
02913     if (!crlobject->entries)
02914     {
02915         return SECFailure;
02916     }
02917     /* add all serial numbers to the hash table */
02918     for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
02919          crlEntry++)
02920     {
02921         PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
02922                         *crlEntry);
02923     }
02924 
02925     return SECSuccess;
02926 }
02927 
02928 /* returns true if there are CRLs from PKCS#11 slots */
02929 static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
02930 {
02931     PRBool answer = PR_FALSE;
02932     PRUint32 i;
02933     for (i=0;i<cache->ncrls;i++)
02934     {
02935         if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
02936         {
02937             answer = PR_TRUE;
02938             break;
02939         }
02940     }
02941     return answer;
02942 }
02943 
02944 /* are these CRLs the same, as far as the cache is concerned ? */
02945 /* are these CRLs the same token object but with different DER ?
02946    This can happen if the DER CRL got updated in the token, but the PKCS#11
02947    object ID did not change. NSS softoken has the unfortunate property to
02948    never change the object ID for CRL objects. */
02949 static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
02950                                 PRBool* isUpdated)
02951 {
02952     PORT_Assert(a);
02953     PORT_Assert(b);
02954     PORT_Assert(isDupe);
02955     PORT_Assert(isUpdated);
02956     if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
02957     {
02958         PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
02959         return SECFailure;
02960     }
02961 
02962     *isDupe = *isUpdated = PR_FALSE;
02963 
02964     if (a == b)
02965     {
02966         /* dupe */
02967         *isDupe = PR_TRUE;
02968         *isUpdated = PR_FALSE;
02969         return SECSuccess;
02970     }
02971     if (b->origin != a->origin)
02972     {
02973         /* CRLs of different origins are not considered dupes,
02974            and can't be updated either */
02975         return SECSuccess;
02976     }
02977     if (CRL_OriginToken == b->origin)
02978     {
02979         /* for token CRLs, slot and PKCS#11 object handle must match for CRL
02980            to truly be a dupe */
02981         if ( (b->crl->slot == a->crl->slot) &&
02982              (b->crl->pkcs11ID == a->crl->pkcs11ID) )
02983         {
02984             /* ASN.1 DER needs to match for dupe check */
02985             /* could optimize by just checking a few fields like thisUpdate */
02986             if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
02987                                                  a->crl->derCrl) )
02988             {
02989                 *isDupe = PR_TRUE;
02990             }
02991             else
02992             {
02993                 *isUpdated = PR_TRUE;
02994             }
02995         }
02996         return SECSuccess;
02997     }
02998     if (CRL_OriginExplicit == b->origin)
02999     {
03000         /* We need to make sure this is the same object that the user provided
03001            to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
03002            just do a pointer comparison here.
03003         */
03004         if (b->crl->derCrl == a->crl->derCrl)
03005         {
03006             *isDupe = PR_TRUE;
03007         }
03008     }
03009     return SECSuccess;
03010 }
03011 
03012 
03013