tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

crl.c (96998B)


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