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