security/nss/lib/certdb/crl.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/certdb/crl.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3371 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * Moved from secpkcs7.c
    1.10 + */
    1.11 + 
    1.12 +#include "cert.h"
    1.13 +#include "certi.h"
    1.14 +#include "secder.h"
    1.15 +#include "secasn1.h"
    1.16 +#include "secoid.h"
    1.17 +#include "certdb.h"
    1.18 +#include "certxutl.h"
    1.19 +#include "prtime.h"
    1.20 +#include "secerr.h"
    1.21 +#include "pk11func.h"
    1.22 +#include "dev.h"
    1.23 +#include "dev3hack.h"
    1.24 +#include "nssbase.h"
    1.25 +#if defined(DPC_RWLOCK) || defined(GLOBAL_RWLOCK)
    1.26 +#include "nssrwlk.h"
    1.27 +#endif
    1.28 +#include "pk11priv.h"
    1.29 +
    1.30 +const SEC_ASN1Template SEC_CERTExtensionTemplate[] = {
    1.31 +    { SEC_ASN1_SEQUENCE,
    1.32 +	  0, NULL, sizeof(CERTCertExtension) },
    1.33 +    { SEC_ASN1_OBJECT_ID,
    1.34 +	  offsetof(CERTCertExtension,id) },
    1.35 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,		/* XXX DER_DEFAULT */
    1.36 +	  offsetof(CERTCertExtension,critical), },
    1.37 +    { SEC_ASN1_OCTET_STRING,
    1.38 +	  offsetof(CERTCertExtension,value) },
    1.39 +    { 0, }
    1.40 +};
    1.41 +
    1.42 +static const SEC_ASN1Template SEC_CERTExtensionsTemplate[] = {
    1.43 +    { SEC_ASN1_SEQUENCE_OF, 0,  SEC_CERTExtensionTemplate}
    1.44 +};
    1.45 +
    1.46 +/*
    1.47 + * XXX Also, these templates need to be tested; Lisa did the obvious
    1.48 + * translation but they still should be verified.
    1.49 + */
    1.50 +
    1.51 +const SEC_ASN1Template CERT_IssuerAndSNTemplate[] = {
    1.52 +    { SEC_ASN1_SEQUENCE,
    1.53 +	  0, NULL, sizeof(CERTIssuerAndSN) },
    1.54 +    { SEC_ASN1_SAVE,
    1.55 +	  offsetof(CERTIssuerAndSN,derIssuer) },
    1.56 +    { SEC_ASN1_INLINE,
    1.57 +	  offsetof(CERTIssuerAndSN,issuer),
    1.58 +	  CERT_NameTemplate },
    1.59 +    { SEC_ASN1_INTEGER,
    1.60 +	  offsetof(CERTIssuerAndSN,serialNumber) },
    1.61 +    { 0 }
    1.62 +};
    1.63 +
    1.64 +SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
    1.65 +SEC_ASN1_MKSUB(CERT_TimeChoiceTemplate)
    1.66 +
    1.67 +static const SEC_ASN1Template cert_CrlKeyTemplate[] = {
    1.68 +    { SEC_ASN1_SEQUENCE,
    1.69 +	  0, NULL, sizeof(CERTCrlKey) },
    1.70 +    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
    1.71 +    { SEC_ASN1_SKIP },
    1.72 +    { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
    1.73 +    { SEC_ASN1_SKIP_REST },
    1.74 +    { 0 }
    1.75 +};
    1.76 +
    1.77 +static const SEC_ASN1Template cert_CrlEntryTemplate[] = {
    1.78 +    { SEC_ASN1_SEQUENCE,
    1.79 +	  0, NULL, sizeof(CERTCrlEntry) },
    1.80 +    { SEC_ASN1_INTEGER,
    1.81 +	  offsetof(CERTCrlEntry,serialNumber) },
    1.82 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    1.83 +	  offsetof(CERTCrlEntry,revocationDate),
    1.84 +          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
    1.85 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
    1.86 +	  offsetof(CERTCrlEntry, extensions),
    1.87 +	  SEC_CERTExtensionTemplate},
    1.88 +    { 0 }
    1.89 +};
    1.90 +
    1.91 +const SEC_ASN1Template CERT_CrlTemplate[] = {
    1.92 +    { SEC_ASN1_SEQUENCE,
    1.93 +	  0, NULL, sizeof(CERTCrl) },
    1.94 +    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
    1.95 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
    1.96 +	  offsetof(CERTCrl,signatureAlg),
    1.97 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate)},
    1.98 +    { SEC_ASN1_SAVE,
    1.99 +	  offsetof(CERTCrl,derName) },
   1.100 +    { SEC_ASN1_INLINE,
   1.101 +	  offsetof(CERTCrl,name),
   1.102 +	  CERT_NameTemplate },
   1.103 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   1.104 +	  offsetof(CERTCrl,lastUpdate),
   1.105 +          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.106 +    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   1.107 +	  offsetof(CERTCrl,nextUpdate),
   1.108 +          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.109 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
   1.110 +	  offsetof(CERTCrl,entries),
   1.111 +	  cert_CrlEntryTemplate },
   1.112 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
   1.113 +	  SEC_ASN1_EXPLICIT | 0,
   1.114 +	  offsetof(CERTCrl,extensions),
   1.115 +	  SEC_CERTExtensionsTemplate},
   1.116 +    { 0 }
   1.117 +};
   1.118 +
   1.119 +const SEC_ASN1Template CERT_CrlTemplateNoEntries[] = {
   1.120 +    { SEC_ASN1_SEQUENCE,
   1.121 +	  0, NULL, sizeof(CERTCrl) },
   1.122 +    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof (CERTCrl, version) },
   1.123 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   1.124 +	  offsetof(CERTCrl,signatureAlg),
   1.125 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   1.126 +    { SEC_ASN1_SAVE,
   1.127 +	  offsetof(CERTCrl,derName) },
   1.128 +    { SEC_ASN1_INLINE,
   1.129 +	  offsetof(CERTCrl,name),
   1.130 +	  CERT_NameTemplate },
   1.131 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   1.132 +	  offsetof(CERTCrl,lastUpdate),
   1.133 +          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.134 +    { SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   1.135 +	  offsetof(CERTCrl,nextUpdate),
   1.136 +          SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.137 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF |
   1.138 +      SEC_ASN1_SKIP }, /* skip entries */
   1.139 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
   1.140 +	  SEC_ASN1_EXPLICIT | 0,
   1.141 +	  offsetof(CERTCrl,extensions),
   1.142 +	  SEC_CERTExtensionsTemplate },
   1.143 +    { 0 }
   1.144 +};
   1.145 +
   1.146 +const SEC_ASN1Template CERT_CrlTemplateEntriesOnly[] = {
   1.147 +    { SEC_ASN1_SEQUENCE,
   1.148 +	  0, NULL, sizeof(CERTCrl) },
   1.149 +    { SEC_ASN1_SKIP | SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL },
   1.150 +    { SEC_ASN1_SKIP },
   1.151 +    { SEC_ASN1_SKIP },
   1.152 +    { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   1.153 +        offsetof(CERTCrl,lastUpdate),
   1.154 +        SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.155 +    { SEC_ASN1_SKIP | SEC_ASN1_INLINE | SEC_ASN1_OPTIONAL | SEC_ASN1_XTRN,
   1.156 +        offsetof(CERTCrl,nextUpdate),
   1.157 +        SEC_ASN1_SUB(CERT_TimeChoiceTemplate) },
   1.158 +    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
   1.159 +	  offsetof(CERTCrl,entries),
   1.160 +	  cert_CrlEntryTemplate }, /* decode entries */
   1.161 +    { SEC_ASN1_SKIP_REST },
   1.162 +    { 0 }
   1.163 +};
   1.164 +
   1.165 +const SEC_ASN1Template CERT_SignedCrlTemplate[] = {
   1.166 +    { SEC_ASN1_SEQUENCE,
   1.167 +	  0, NULL, sizeof(CERTSignedCrl) },
   1.168 +    { SEC_ASN1_SAVE,
   1.169 +	  offsetof(CERTSignedCrl,signatureWrap.data) },
   1.170 +    { SEC_ASN1_INLINE,
   1.171 +	  offsetof(CERTSignedCrl,crl),
   1.172 +	  CERT_CrlTemplate },
   1.173 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN ,
   1.174 +	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
   1.175 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   1.176 +    { SEC_ASN1_BIT_STRING,
   1.177 +	  offsetof(CERTSignedCrl,signatureWrap.signature) },
   1.178 +    { 0 }
   1.179 +};
   1.180 +
   1.181 +static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries[] = {
   1.182 +    { SEC_ASN1_SEQUENCE,
   1.183 +	  0, NULL, sizeof(CERTSignedCrl) },
   1.184 +    { SEC_ASN1_SAVE,
   1.185 +	  offsetof(CERTSignedCrl,signatureWrap.data) },
   1.186 +    { SEC_ASN1_INLINE,
   1.187 +	  offsetof(CERTSignedCrl,crl),
   1.188 +	  CERT_CrlTemplateNoEntries },
   1.189 +    { SEC_ASN1_INLINE | SEC_ASN1_XTRN,
   1.190 +	  offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
   1.191 +	  SEC_ASN1_SUB(SECOID_AlgorithmIDTemplate) },
   1.192 +    { SEC_ASN1_BIT_STRING,
   1.193 +	  offsetof(CERTSignedCrl,signatureWrap.signature) },
   1.194 +    { 0 }
   1.195 +};
   1.196 +
   1.197 +const SEC_ASN1Template CERT_SetOfSignedCrlTemplate[] = {
   1.198 +    { SEC_ASN1_SET_OF, 0, CERT_SignedCrlTemplate },
   1.199 +};
   1.200 +
   1.201 +/* get CRL version */
   1.202 +int cert_get_crl_version(CERTCrl * crl)
   1.203 +{
   1.204 +    /* CRL version is defaulted to v1 */
   1.205 +    int version = SEC_CRL_VERSION_1;
   1.206 +    if (crl && crl->version.data != 0) {
   1.207 +	version = (int)DER_GetUInteger (&crl->version);
   1.208 +    }
   1.209 +    return version;
   1.210 +}
   1.211 +
   1.212 +
   1.213 +/* check the entries in the CRL */
   1.214 +SECStatus cert_check_crl_entries (CERTCrl *crl)
   1.215 +{
   1.216 +    CERTCrlEntry **entries;
   1.217 +    CERTCrlEntry *entry;
   1.218 +    PRBool hasCriticalExten = PR_FALSE;
   1.219 +    SECStatus rv = SECSuccess;
   1.220 +
   1.221 +    if (!crl) {
   1.222 +        return SECFailure;
   1.223 +    }
   1.224 +
   1.225 +    if (crl->entries == NULL) {
   1.226 +        /* CRLs with no entries are valid */
   1.227 +        return (SECSuccess);
   1.228 +    }
   1.229 +
   1.230 +    /* Look in the crl entry extensions.  If there is a critical extension,
   1.231 +       then the crl version must be v2; otherwise, it should be v1.
   1.232 +     */
   1.233 +    entries = crl->entries;
   1.234 +    while (*entries) {
   1.235 +	entry = *entries;
   1.236 +	if (entry->extensions) {
   1.237 +	    /* If there is a critical extension in the entries, then the
   1.238 +	       CRL must be of version 2.  If we already saw a critical extension,
   1.239 +	       there is no need to check the version again.
   1.240 +	    */
   1.241 +            if (hasCriticalExten == PR_FALSE) {
   1.242 +                hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
   1.243 +                if (hasCriticalExten) {
   1.244 +                    if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 
   1.245 +                        /* only CRL v2 critical extensions are supported */
   1.246 +                        PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
   1.247 +                        rv = SECFailure;
   1.248 +                        break;
   1.249 +                    }
   1.250 +                }
   1.251 +            }
   1.252 +
   1.253 +	    /* For each entry, make sure that it does not contain an unknown
   1.254 +	       critical extension.  If it does, we must reject the CRL since
   1.255 +	       we don't know how to process the extension.
   1.256 +	    */
   1.257 +	    if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
   1.258 +		PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
   1.259 +		rv = SECFailure;
   1.260 +		break;
   1.261 +	    }
   1.262 +	}
   1.263 +	++entries;
   1.264 +    }
   1.265 +    return(rv);
   1.266 +}
   1.267 +
   1.268 +/* Check the version of the CRL.  If there is a critical extension in the crl
   1.269 +   or crl entry, then the version must be v2. Otherwise, it should be v1. If
   1.270 +   the crl contains critical extension(s), then we must recognized the
   1.271 +   extension's OID.
   1.272 +   */
   1.273 +SECStatus cert_check_crl_version (CERTCrl *crl)
   1.274 +{
   1.275 +    PRBool hasCriticalExten = PR_FALSE;
   1.276 +    int version = cert_get_crl_version(crl);
   1.277 +	
   1.278 +    if (version > SEC_CRL_VERSION_2) {
   1.279 +	PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
   1.280 +	return (SECFailure);
   1.281 +    }
   1.282 +
   1.283 +    /* Check the crl extensions for a critial extension.  If one is found,
   1.284 +       and the version is not v2, then we are done.
   1.285 +     */
   1.286 +    if (crl->extensions) {
   1.287 +	hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
   1.288 +	if (hasCriticalExten) {
   1.289 +            if (version != SEC_CRL_VERSION_2) {
   1.290 +                /* only CRL v2 critical extensions are supported */
   1.291 +                PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
   1.292 +                return (SECFailure);
   1.293 +            }
   1.294 +	    /* make sure that there is no unknown critical extension */
   1.295 +	    if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
   1.296 +		PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
   1.297 +		return (SECFailure);
   1.298 +	    }
   1.299 +	}
   1.300 +    }
   1.301 +
   1.302 +    return (SECSuccess);
   1.303 +}
   1.304 +
   1.305 +/*
   1.306 + * Generate a database key, based on the issuer name from a
   1.307 + * DER crl.
   1.308 + */
   1.309 +SECStatus
   1.310 +CERT_KeyFromDERCrl(PLArenaPool *arena, SECItem *derCrl, SECItem *key)
   1.311 +{
   1.312 +    SECStatus rv;
   1.313 +    CERTSignedData sd;
   1.314 +    CERTCrlKey crlkey;
   1.315 +    PLArenaPool* myArena;
   1.316 +
   1.317 +    if (!arena) {
   1.318 +        /* arena needed for QuickDER */
   1.319 +        myArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.320 +    } else {
   1.321 +        myArena = arena;
   1.322 +    }
   1.323 +    PORT_Memset (&sd, 0, sizeof (sd));
   1.324 +    rv = SEC_QuickDERDecodeItem (myArena, &sd, CERT_SignedDataTemplate, derCrl);
   1.325 +    if (SECSuccess == rv) {
   1.326 +        PORT_Memset (&crlkey, 0, sizeof (crlkey));
   1.327 +        rv = SEC_QuickDERDecodeItem(myArena, &crlkey, cert_CrlKeyTemplate, &sd.data);
   1.328 +    }
   1.329 +
   1.330 +    /* make a copy so the data doesn't point to memory inside derCrl, which
   1.331 +       may be temporary */
   1.332 +    if (SECSuccess == rv) {
   1.333 +        rv = SECITEM_CopyItem(arena, key, &crlkey.derName);
   1.334 +    }
   1.335 +
   1.336 +    if (myArena != arena) {
   1.337 +        PORT_FreeArena(myArena, PR_FALSE);
   1.338 +    }
   1.339 +
   1.340 +    return rv;
   1.341 +}
   1.342 +
   1.343 +#define GetOpaqueCRLFields(x) ((OpaqueCRLFields*)x->opaque)
   1.344 +
   1.345 +SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
   1.346 +{
   1.347 +    SECStatus rv = SECSuccess;
   1.348 +    SECItem* crldata = NULL;
   1.349 +    OpaqueCRLFields* extended = NULL;
   1.350 +
   1.351 +    if ( (!crl) ||
   1.352 +         (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
   1.353 +         (PR_TRUE == extended->decodingError) ) {
   1.354 +        rv = SECFailure;
   1.355 +    } else {
   1.356 +        if (PR_FALSE == extended->partial) {
   1.357 +            /* the CRL has already been fully decoded */
   1.358 +            return SECSuccess;
   1.359 +        }
   1.360 +        if (PR_TRUE == extended->badEntries) {
   1.361 +            /* the entries decoding already failed */
   1.362 +            return SECFailure;
   1.363 +        }
   1.364 +        crldata = &crl->signatureWrap.data;
   1.365 +        if (!crldata) {
   1.366 +            rv = SECFailure;
   1.367 +        }
   1.368 +    }
   1.369 +
   1.370 +    if (SECSuccess == rv) {
   1.371 +        rv = SEC_QuickDERDecodeItem(crl->arena,
   1.372 +            &crl->crl,
   1.373 +            CERT_CrlTemplateEntriesOnly,
   1.374 +            crldata);
   1.375 +        if (SECSuccess == rv) {
   1.376 +            extended->partial = PR_FALSE; /* successful decode, avoid
   1.377 +                decoding again */
   1.378 +        } else {
   1.379 +            extended->decodingError = PR_TRUE;
   1.380 +            extended->badEntries = PR_TRUE;
   1.381 +            /* cache the decoding failure. If it fails the first time,
   1.382 +               it will fail again, which will grow the arena and leak
   1.383 +               memory, so we want to avoid it */
   1.384 +        }
   1.385 +        rv = cert_check_crl_entries(&crl->crl);
   1.386 +        if (rv != SECSuccess) {
   1.387 +            extended->badExtensions = PR_TRUE;
   1.388 +        }
   1.389 +    }
   1.390 +    return rv;
   1.391 +}
   1.392 +
   1.393 +/*
   1.394 + * take a DER CRL and decode it into a CRL structure
   1.395 + * allow reusing the input DER without making a copy
   1.396 + */
   1.397 +CERTSignedCrl *
   1.398 +CERT_DecodeDERCrlWithFlags(PLArenaPool *narena, SECItem *derSignedCrl,
   1.399 +                          int type, PRInt32 options)
   1.400 +{
   1.401 +    PLArenaPool *arena;
   1.402 +    CERTSignedCrl *crl;
   1.403 +    SECStatus rv;
   1.404 +    OpaqueCRLFields* extended = NULL;
   1.405 +    const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
   1.406 +    PRInt32 testOptions = options;
   1.407 +
   1.408 +    PORT_Assert(derSignedCrl);
   1.409 +    if (!derSignedCrl) {
   1.410 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.411 +        return NULL;
   1.412 +    }
   1.413 +
   1.414 +    /* Adopting DER requires not copying it.  Code that sets ADOPT flag 
   1.415 +     * but doesn't set DONT_COPY probably doesn't know What it is doing.  
   1.416 +     * That condition is a programming error in the caller.
   1.417 +     */
   1.418 +    testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
   1.419 +    PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
   1.420 +    if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
   1.421 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.422 +        return NULL;
   1.423 +    }
   1.424 +
   1.425 +    /* make a new arena if needed */
   1.426 +    if (narena == NULL) {
   1.427 +    	arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.428 +	if ( !arena ) {
   1.429 +	    return NULL;
   1.430 +	}
   1.431 +    } else {
   1.432 +	arena = narena;
   1.433 +    }
   1.434 +
   1.435 +    /* allocate the CRL structure */
   1.436 +    crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
   1.437 +    if ( !crl ) {
   1.438 +        PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.439 +	goto loser;
   1.440 +    }
   1.441 +
   1.442 +    crl->arena = arena;
   1.443 +
   1.444 +    /* allocate opaque fields */
   1.445 +    crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
   1.446 +    if ( !crl->opaque ) {
   1.447 +	goto loser;
   1.448 +    }
   1.449 +    extended = (OpaqueCRLFields*) crl->opaque;
   1.450 +    if (options & CRL_DECODE_ADOPT_HEAP_DER) {
   1.451 +        extended->heapDER = PR_TRUE;
   1.452 +    }
   1.453 +    if (options & CRL_DECODE_DONT_COPY_DER) {
   1.454 +        crl->derCrl = derSignedCrl; /* DER is not copied . The application
   1.455 +                                       must keep derSignedCrl until it
   1.456 +                                       destroys the CRL */
   1.457 +    } else {
   1.458 +        crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
   1.459 +        if (crl->derCrl == NULL) {
   1.460 +            goto loser;
   1.461 +        }
   1.462 +        rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
   1.463 +        if (rv != SECSuccess) {
   1.464 +            goto loser;
   1.465 +        }
   1.466 +    }
   1.467 +
   1.468 +    /* Save the arena in the inner crl for CRL extensions support */
   1.469 +    crl->crl.arena = arena;
   1.470 +    if (options & CRL_DECODE_SKIP_ENTRIES) {
   1.471 +        crlTemplate = cert_SignedCrlTemplateNoEntries;
   1.472 +        extended->partial = PR_TRUE;
   1.473 +    }
   1.474 +
   1.475 +    /* decode the CRL info */
   1.476 +    switch (type) {
   1.477 +    case SEC_CRL_TYPE:
   1.478 +        rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
   1.479 +        if (rv != SECSuccess) {
   1.480 +            extended->badDER = PR_TRUE;
   1.481 +            break;
   1.482 +        }
   1.483 +        /* check for critical extensions */
   1.484 +        rv =  cert_check_crl_version (&crl->crl);
   1.485 +        if (rv != SECSuccess) {
   1.486 +            extended->badExtensions = PR_TRUE;
   1.487 +            break;
   1.488 +        }
   1.489 +
   1.490 +        if (PR_TRUE == extended->partial) {
   1.491 +            /* partial decoding, don't verify entries */
   1.492 +            break;
   1.493 +        }
   1.494 +
   1.495 +        rv = cert_check_crl_entries(&crl->crl);
   1.496 +        if (rv != SECSuccess) {
   1.497 +            extended->badExtensions = PR_TRUE;
   1.498 +        }
   1.499 +
   1.500 +        break;
   1.501 +
   1.502 +    default:
   1.503 +	PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.504 +	rv = SECFailure;
   1.505 +	break;
   1.506 +    }
   1.507 +
   1.508 +    if (rv != SECSuccess) {
   1.509 +	goto loser;
   1.510 +    }
   1.511 +
   1.512 +    crl->referenceCount = 1;
   1.513 +    
   1.514 +    return(crl);
   1.515 +    
   1.516 +loser:
   1.517 +    if (options & CRL_DECODE_KEEP_BAD_CRL) {
   1.518 +        if (extended) {
   1.519 +            extended->decodingError = PR_TRUE;
   1.520 +        }
   1.521 +        if (crl) {
   1.522 +            crl->referenceCount = 1;
   1.523 +            return(crl);
   1.524 +        }
   1.525 +    }
   1.526 +
   1.527 +    if ((narena == NULL) && arena ) {
   1.528 +	PORT_FreeArena(arena, PR_FALSE);
   1.529 +    }
   1.530 +    
   1.531 +    return(0);
   1.532 +}
   1.533 +
   1.534 +/*
   1.535 + * take a DER CRL and decode it into a CRL structure
   1.536 + */
   1.537 +CERTSignedCrl *
   1.538 +CERT_DecodeDERCrl(PLArenaPool *narena, SECItem *derSignedCrl, int type)
   1.539 +{
   1.540 +    return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
   1.541 +                                      CRL_DECODE_DEFAULT_OPTIONS);
   1.542 +}
   1.543 +
   1.544 +/*
   1.545 + * Lookup a CRL in the databases. We mirror the same fast caching data base
   1.546 + *  caching stuff used by certificates....?
   1.547 + * return values :
   1.548 + *
   1.549 + * SECSuccess means we got a valid decodable DER CRL, or no CRL at all.
   1.550 + * Caller may distinguish those cases by the value returned in "decoded".
   1.551 + * When DER CRL is not found, error code will be SEC_ERROR_CRL_NOT_FOUND.
   1.552 + *
   1.553 + * SECFailure means we got a fatal error - most likely, we found a CRL,
   1.554 + * and it failed decoding, or there was an out of memory error. Do NOT ignore
   1.555 + * it and specifically do NOT treat it the same as having no CRL, as this
   1.556 + * can compromise security !!! Ideally, you should treat this case as if you
   1.557 + * received a "catch-all" CRL where all certs you were looking up are
   1.558 + * considered to be revoked
   1.559 + */
   1.560 +static SECStatus
   1.561 +SEC_FindCrlByKeyOnSlot(PK11SlotInfo *slot, SECItem *crlKey, int type,
   1.562 +                       CERTSignedCrl** decoded, PRInt32 decodeoptions)
   1.563 +{
   1.564 +    SECStatus rv = SECSuccess;
   1.565 +    CERTSignedCrl *crl = NULL;
   1.566 +    SECItem *derCrl = NULL;
   1.567 +    CK_OBJECT_HANDLE crlHandle = 0;
   1.568 +    char *url = NULL;
   1.569 +
   1.570 +    PORT_Assert(decoded);
   1.571 +    if (!decoded) {
   1.572 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.573 +        return SECFailure;
   1.574 +    }
   1.575 +
   1.576 +    derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
   1.577 +    if (derCrl == NULL) {
   1.578 +	/* if we had a problem other than the CRL just didn't exist, return
   1.579 +	 * a failure to the upper level */
   1.580 +	int nsserror = PORT_GetError();
   1.581 +	if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
   1.582 +	    rv = SECFailure;
   1.583 +	}
   1.584 +	goto loser;
   1.585 +    }
   1.586 +    PORT_Assert(crlHandle != CK_INVALID_HANDLE);
   1.587 +    /* PK11_FindCrlByName obtained a slot reference. */
   1.588 +    
   1.589 +    /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
   1.590 +       Force adoption of the DER CRL from the heap - this will cause it 
   1.591 +       to be automatically freed when SEC_DestroyCrl is invoked */
   1.592 +    decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
   1.593 +
   1.594 +    crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
   1.595 +    if (crl) {
   1.596 +        crl->slot = slot;
   1.597 +        slot = NULL; /* adopt it */
   1.598 +	derCrl = NULL; /* adopted by the crl struct */
   1.599 +        crl->pkcs11ID = crlHandle;
   1.600 +        if (url) {
   1.601 +            crl->url = PORT_ArenaStrdup(crl->arena,url);
   1.602 +        }
   1.603 +    } else {
   1.604 +        rv = SECFailure;
   1.605 +    }
   1.606 +    
   1.607 +    if (url) {
   1.608 +	PORT_Free(url);
   1.609 +    }
   1.610 +
   1.611 +    if (slot) {
   1.612 +	PK11_FreeSlot(slot);
   1.613 +    }
   1.614 +
   1.615 +loser:
   1.616 +    if (derCrl) {
   1.617 +	SECITEM_FreeItem(derCrl, PR_TRUE);
   1.618 +    }
   1.619 +
   1.620 +    *decoded = crl;
   1.621 +
   1.622 +    return rv;
   1.623 +}
   1.624 +
   1.625 +
   1.626 +CERTSignedCrl *
   1.627 +crl_storeCRL (PK11SlotInfo *slot,char *url,
   1.628 +                  CERTSignedCrl *newCrl, SECItem *derCrl, int type)
   1.629 +{
   1.630 +    CERTSignedCrl *oldCrl = NULL, *crl = NULL;
   1.631 +    PRBool deleteOldCrl = PR_FALSE;
   1.632 +    CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
   1.633 +    SECStatus rv;
   1.634 +
   1.635 +    PORT_Assert(newCrl);
   1.636 +    PORT_Assert(derCrl);
   1.637 +    PORT_Assert(type == SEC_CRL_TYPE);
   1.638 +
   1.639 +    if (type != SEC_CRL_TYPE) {
   1.640 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.641 +        return NULL;
   1.642 +    }
   1.643 +
   1.644 +    /* we can't use the cache here because we must look in the same
   1.645 +       token */
   1.646 +    rv = SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
   1.647 +                                &oldCrl, CRL_DECODE_SKIP_ENTRIES);
   1.648 +    /* if there is an old crl on the token, make sure the one we are
   1.649 +       installing is newer. If not, exit out, otherwise delete the
   1.650 +       old crl.
   1.651 +     */
   1.652 +    if (oldCrl != NULL) {
   1.653 +	/* if it's already there, quietly continue */
   1.654 +	if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) 
   1.655 +						== SECEqual) {
   1.656 +	    crl = newCrl;
   1.657 +	    crl->slot = PK11_ReferenceSlot(slot);
   1.658 +	    crl->pkcs11ID = oldCrl->pkcs11ID;
   1.659 +	    if (oldCrl->url && !url)
   1.660 +	        url = oldCrl->url;
   1.661 +	    if (url)
   1.662 +		crl->url = PORT_ArenaStrdup(crl->arena, url);
   1.663 +	    goto done;
   1.664 +	}
   1.665 +        if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {
   1.666 +            PORT_SetError(SEC_ERROR_OLD_CRL);
   1.667 +            goto done;
   1.668 +        }
   1.669 +
   1.670 +        /* if we have a url in the database, use that one */
   1.671 +        if (oldCrl->url && !url) {
   1.672 +	    url = oldCrl->url;
   1.673 +        }
   1.674 +
   1.675 +        /* really destroy this crl */
   1.676 +        /* first drum it out of the permanment Data base */
   1.677 +	deleteOldCrl = PR_TRUE;
   1.678 +    }
   1.679 +
   1.680 +    /* invalidate CRL cache for this issuer */
   1.681 +    CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
   1.682 +    /* Write the new entry into the data base */
   1.683 +    crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
   1.684 +    if (crlHandle != CK_INVALID_HANDLE) {
   1.685 +	crl = newCrl;
   1.686 +	crl->slot = PK11_ReferenceSlot(slot);
   1.687 +	crl->pkcs11ID = crlHandle;
   1.688 +	if (url) {
   1.689 +	    crl->url = PORT_ArenaStrdup(crl->arena,url);
   1.690 +	}
   1.691 +    }
   1.692 +
   1.693 +done:
   1.694 +    if (oldCrl) {
   1.695 +	if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
   1.696 +	    SEC_DeletePermCRL(oldCrl);
   1.697 +	}
   1.698 +	SEC_DestroyCrl(oldCrl);
   1.699 +    }
   1.700 +
   1.701 +    return crl;
   1.702 +}
   1.703 +
   1.704 +/*
   1.705 + *
   1.706 + * create a new CRL from DER material.
   1.707 + *
   1.708 + * The signature on this CRL must be checked before you
   1.709 + * load it. ???
   1.710 + */
   1.711 +CERTSignedCrl *
   1.712 +SEC_NewCrl(CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
   1.713 +{
   1.714 +    CERTSignedCrl* retCrl = NULL;
   1.715 +    PK11SlotInfo* slot = PK11_GetInternalKeySlot();
   1.716 +    retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
   1.717 +        CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
   1.718 +    PK11_FreeSlot(slot);
   1.719 +
   1.720 +    return retCrl;
   1.721 +}
   1.722 +    
   1.723 +CERTSignedCrl *
   1.724 +SEC_FindCrlByDERCert(CERTCertDBHandle *handle, SECItem *derCrl, int type)
   1.725 +{
   1.726 +    PLArenaPool *arena;
   1.727 +    SECItem crlKey;
   1.728 +    SECStatus rv;
   1.729 +    CERTSignedCrl *crl = NULL;
   1.730 +    
   1.731 +    /* create a scratch arena */
   1.732 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.733 +    if ( arena == NULL ) {
   1.734 +	return(NULL);
   1.735 +    }
   1.736 +    
   1.737 +    /* extract the database key from the cert */
   1.738 +    rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
   1.739 +    if ( rv != SECSuccess ) {
   1.740 +	goto loser;
   1.741 +    }
   1.742 +
   1.743 +    /* find the crl */
   1.744 +    crl = SEC_FindCrlByName(handle, &crlKey, type);
   1.745 +    
   1.746 +loser:
   1.747 +    PORT_FreeArena(arena, PR_FALSE);
   1.748 +    return(crl);
   1.749 +}
   1.750 +
   1.751 +CERTSignedCrl* SEC_DupCrl(CERTSignedCrl* acrl)
   1.752 +{
   1.753 +    if (acrl)
   1.754 +    {
   1.755 +        PR_ATOMIC_INCREMENT(&acrl->referenceCount);
   1.756 +        return acrl;
   1.757 +    }
   1.758 +    return NULL;
   1.759 +}
   1.760 +
   1.761 +SECStatus
   1.762 +SEC_DestroyCrl(CERTSignedCrl *crl)
   1.763 +{
   1.764 +    if (crl) {
   1.765 +	if (PR_ATOMIC_DECREMENT(&crl->referenceCount) < 1) {
   1.766 +	    if (crl->slot) {
   1.767 +		PK11_FreeSlot(crl->slot);
   1.768 +	    }
   1.769 +            if (GetOpaqueCRLFields(crl) &&
   1.770 +                PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
   1.771 +                SECITEM_FreeItem(crl->derCrl, PR_TRUE);
   1.772 +            }
   1.773 +            if (crl->arena) {
   1.774 +                PORT_FreeArena(crl->arena, PR_FALSE);
   1.775 +            }
   1.776 +	}
   1.777 +        return SECSuccess;
   1.778 +    } else {
   1.779 +        return SECFailure;
   1.780 +    }
   1.781 +}
   1.782 +
   1.783 +SECStatus
   1.784 +SEC_LookupCrls(CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
   1.785 +{
   1.786 +    CERTCrlHeadNode *head;
   1.787 +    PLArenaPool *arena = NULL;
   1.788 +    SECStatus rv;
   1.789 +
   1.790 +    *nodes = NULL;
   1.791 +
   1.792 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.793 +    if ( arena == NULL ) {
   1.794 +	return SECFailure;
   1.795 +    }
   1.796 +
   1.797 +    /* build a head structure */
   1.798 +    head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
   1.799 +    head->arena = arena;
   1.800 +    head->first = NULL;
   1.801 +    head->last = NULL;
   1.802 +    head->dbhandle = handle;
   1.803 +
   1.804 +    /* Look up the proper crl types */
   1.805 +    *nodes = head;
   1.806 +
   1.807 +    rv = PK11_LookupCrls(head, type, NULL);
   1.808 +    
   1.809 +    if (rv != SECSuccess) {
   1.810 +	if ( arena ) {
   1.811 +	    PORT_FreeArena(arena, PR_FALSE);
   1.812 +	    *nodes = NULL;
   1.813 +	}
   1.814 +    }
   1.815 +
   1.816 +    return rv;
   1.817 +}
   1.818 +
   1.819 +/* These functions simply return the address of the above-declared templates.
   1.820 +** This is necessary for Windows DLLs.  Sigh.
   1.821 +*/
   1.822 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_IssuerAndSNTemplate)
   1.823 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_CrlTemplate)
   1.824 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SignedCrlTemplate)
   1.825 +SEC_ASN1_CHOOSER_IMPLEMENT(CERT_SetOfSignedCrlTemplate)
   1.826 +
   1.827 +/* CRL cache code starts here */
   1.828 +
   1.829 +/* constructor */
   1.830 +static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
   1.831 +                           CRLOrigin origin);
   1.832 +/* destructor */
   1.833 +static SECStatus CachedCrl_Destroy(CachedCrl* crl);
   1.834 +
   1.835 +/* create hash table of CRL entries */
   1.836 +static SECStatus CachedCrl_Populate(CachedCrl* crlobject);
   1.837 +
   1.838 +/* empty the cache content */
   1.839 +static SECStatus CachedCrl_Depopulate(CachedCrl* crl);
   1.840 +
   1.841 +/* are these CRLs the same, as far as the cache is concerned ?
   1.842 +   Or are they the same token object, but with different DER ? */
   1.843 +
   1.844 +static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
   1.845 +                                PRBool* isUpdated);
   1.846 +
   1.847 +/* create a DPCache object */
   1.848 +static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
   1.849 +                         const SECItem* subject, SECItem* dp);
   1.850 +
   1.851 +/* destructor for CRL DPCache object */
   1.852 +static SECStatus DPCache_Destroy(CRLDPCache* cache);
   1.853 +
   1.854 +/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
   1.855 +   returns the cached CRL object . Needs write access to DPCache. */
   1.856 +static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* crl,
   1.857 +                                PRBool* added);
   1.858 +
   1.859 +/* fetch the CRL for this DP from the PKCS#11 tokens */
   1.860 +static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
   1.861 +                                         void* wincx);
   1.862 +
   1.863 +/* update the content of the CRL cache, including fetching of CRLs, and
   1.864 +   reprocessing with specified issuer and date */
   1.865 +static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate* issuer,
   1.866 +                         PRBool readlocked, PRTime vfdate, void* wincx);
   1.867 +
   1.868 +/* returns true if there are CRLs from PKCS#11 slots */
   1.869 +static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache);
   1.870 +
   1.871 +/* remove CRL at offset specified */
   1.872 +static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset);
   1.873 +
   1.874 +/* Pick best CRL to use . needs write access */
   1.875 +static SECStatus DPCache_SelectCRL(CRLDPCache* cache);
   1.876 +
   1.877 +/* create an issuer cache object (per CA subject ) */
   1.878 +static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
   1.879 +                             CERTCertificate* issuer,
   1.880 +                             const SECItem* subject, const SECItem* dp);
   1.881 +
   1.882 +/* destructor for CRL IssuerCache object */
   1.883 +SECStatus IssuerCache_Destroy(CRLIssuerCache* cache);
   1.884 +
   1.885 +/* add a DPCache to the issuer cache */
   1.886 +static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
   1.887 +                                   CERTCertificate* issuer,
   1.888 +                                   const SECItem* subject,
   1.889 +                                   const SECItem* dp, CRLDPCache** newdpc);
   1.890 +
   1.891 +/* get a particular DPCache object from an IssuerCache */
   1.892 +static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache,
   1.893 +                                          const SECItem* dp);
   1.894 +
   1.895 +/*
   1.896 +** Pre-allocator hash allocator ops.
   1.897 +*/
   1.898 +
   1.899 +/* allocate memory for hash table */
   1.900 +static void * PR_CALLBACK
   1.901 +PreAllocTable(void *pool, PRSize size)
   1.902 +{
   1.903 +    PreAllocator* alloc = (PreAllocator*)pool;
   1.904 +    PORT_Assert(alloc);
   1.905 +    if (!alloc)
   1.906 +    {
   1.907 +        /* no allocator, or buffer full */
   1.908 +        return NULL;
   1.909 +    }
   1.910 +    if (size > (alloc->len - alloc->used))
   1.911 +    {
   1.912 +        /* initial buffer full, let's use the arena */
   1.913 +        alloc->extra += size;
   1.914 +        return PORT_ArenaAlloc(alloc->arena, size);
   1.915 +    }
   1.916 +    /* use the initial buffer */
   1.917 +    alloc->used += size;
   1.918 +    return (char*) alloc->data + alloc->used - size;
   1.919 +}
   1.920 +
   1.921 +/* free hash table memory.
   1.922 +   Individual PreAllocator elements cannot be freed, so this is a no-op. */
   1.923 +static void PR_CALLBACK
   1.924 +PreFreeTable(void *pool, void *item)
   1.925 +{
   1.926 +}
   1.927 +
   1.928 +/* allocate memory for hash table */
   1.929 +static PLHashEntry * PR_CALLBACK
   1.930 +PreAllocEntry(void *pool, const void *key)
   1.931 +{
   1.932 +    return PreAllocTable(pool, sizeof(PLHashEntry));
   1.933 +}
   1.934 +
   1.935 +/* free hash table entry.
   1.936 +   Individual PreAllocator elements cannot be freed, so this is a no-op. */
   1.937 +static void PR_CALLBACK
   1.938 +PreFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
   1.939 +{
   1.940 +}
   1.941 +
   1.942 +/* methods required for PL hash table functions */
   1.943 +static PLHashAllocOps preAllocOps =
   1.944 +{
   1.945 +    PreAllocTable, PreFreeTable,
   1.946 +    PreAllocEntry, PreFreeEntry
   1.947 +};
   1.948 +
   1.949 +/* destructor for PreAllocator object */
   1.950 +void PreAllocator_Destroy(PreAllocator* PreAllocator)
   1.951 +{
   1.952 +    if (!PreAllocator)
   1.953 +    {
   1.954 +        return;
   1.955 +    }
   1.956 +    if (PreAllocator->arena)
   1.957 +    {
   1.958 +        PORT_FreeArena(PreAllocator->arena, PR_TRUE);
   1.959 +    }
   1.960 +}
   1.961 +
   1.962 +/* constructor for PreAllocator object */
   1.963 +PreAllocator* PreAllocator_Create(PRSize size)
   1.964 +{
   1.965 +    PLArenaPool* arena = NULL;
   1.966 +    PreAllocator* prebuffer = NULL;
   1.967 +    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
   1.968 +    if (!arena)
   1.969 +    {
   1.970 +        return NULL;
   1.971 +    }
   1.972 +    prebuffer = (PreAllocator*)PORT_ArenaZAlloc(arena,
   1.973 +                                                sizeof(PreAllocator));
   1.974 +    if (!prebuffer)
   1.975 +    {
   1.976 +        PORT_FreeArena(arena, PR_TRUE);
   1.977 +        return NULL;
   1.978 +    }
   1.979 +    prebuffer->arena = arena;
   1.980 +
   1.981 +    if (size)
   1.982 +    {
   1.983 +        prebuffer->len = size;
   1.984 +        prebuffer->data = PORT_ArenaAlloc(arena, size);
   1.985 +        if (!prebuffer->data)
   1.986 +        {
   1.987 +            PORT_FreeArena(arena, PR_TRUE);
   1.988 +            return NULL;
   1.989 +        }
   1.990 +    }
   1.991 +    return prebuffer;
   1.992 +}
   1.993 +
   1.994 +/* global Named CRL cache object */
   1.995 +static NamedCRLCache namedCRLCache = { NULL, NULL };
   1.996 +
   1.997 +/* global CRL cache object */
   1.998 +static CRLCache crlcache = { NULL, NULL };
   1.999 +
  1.1000 +/* initial state is off */
  1.1001 +static PRBool crlcache_initialized = PR_FALSE;
  1.1002 +
  1.1003 +PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000; /* how often
  1.1004 +    to query the tokens for CRL objects, in order to discover new objects, if
  1.1005 +    the cache does not contain any token CRLs . In microseconds */
  1.1006 +
  1.1007 +PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000 ; /* how often
  1.1008 +    to query the tokens for CRL objects, in order to discover new objects, if
  1.1009 +    the cache already contains token CRLs In microseconds */
  1.1010 +
  1.1011 +PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000; /* how often to check
  1.1012 +    if a token CRL object still exists. In microseconds */
  1.1013 +
  1.1014 +/* this function is called at NSS initialization time */
  1.1015 +SECStatus InitCRLCache(void)
  1.1016 +{
  1.1017 +    if (PR_FALSE == crlcache_initialized)
  1.1018 +    {
  1.1019 +        PORT_Assert(NULL == crlcache.lock);
  1.1020 +        PORT_Assert(NULL == crlcache.issuers);
  1.1021 +        PORT_Assert(NULL == namedCRLCache.lock);
  1.1022 +        PORT_Assert(NULL == namedCRLCache.entries);
  1.1023 +        if (crlcache.lock || crlcache.issuers || namedCRLCache.lock ||
  1.1024 +            namedCRLCache.entries)
  1.1025 +        {
  1.1026 +            /* CRL cache already partially initialized */
  1.1027 +            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1028 +            return SECFailure;
  1.1029 +        }
  1.1030 +#ifdef GLOBAL_RWLOCK
  1.1031 +        crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  1.1032 +#else
  1.1033 +        crlcache.lock = PR_NewLock();
  1.1034 +#endif
  1.1035 +        namedCRLCache.lock = PR_NewLock();
  1.1036 +        crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  1.1037 +                                  PL_CompareValues, NULL, NULL);
  1.1038 +        namedCRLCache.entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  1.1039 +                                  PL_CompareValues, NULL, NULL);
  1.1040 +        if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers ||
  1.1041 +            !namedCRLCache.entries)
  1.1042 +        {
  1.1043 +            if (crlcache.lock)
  1.1044 +            {
  1.1045 +#ifdef GLOBAL_RWLOCK
  1.1046 +                NSSRWLock_Destroy(crlcache.lock);
  1.1047 +#else
  1.1048 +                PR_DestroyLock(crlcache.lock);
  1.1049 +#endif
  1.1050 +                crlcache.lock = NULL;
  1.1051 +            }
  1.1052 +            if (namedCRLCache.lock)
  1.1053 +            {
  1.1054 +                PR_DestroyLock(namedCRLCache.lock);
  1.1055 +                namedCRLCache.lock = NULL;
  1.1056 +            }
  1.1057 +            if (crlcache.issuers)
  1.1058 +            {
  1.1059 +                PL_HashTableDestroy(crlcache.issuers);
  1.1060 +                crlcache.issuers = NULL;
  1.1061 +            }
  1.1062 +            if (namedCRLCache.entries)
  1.1063 +            {
  1.1064 +                PL_HashTableDestroy(namedCRLCache.entries);
  1.1065 +                namedCRLCache.entries = NULL;
  1.1066 +            }
  1.1067 +
  1.1068 +            return SECFailure;
  1.1069 +        }
  1.1070 +        crlcache_initialized = PR_TRUE;
  1.1071 +        return SECSuccess;
  1.1072 +    }
  1.1073 +    else
  1.1074 +    {
  1.1075 +        PORT_Assert(crlcache.lock);
  1.1076 +        PORT_Assert(crlcache.issuers);
  1.1077 +        if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
  1.1078 +        {
  1.1079 +            /* CRL cache not fully initialized */
  1.1080 +            return SECFailure;
  1.1081 +        }
  1.1082 +        else
  1.1083 +        {
  1.1084 +            /* CRL cache already initialized */
  1.1085 +            return SECSuccess;
  1.1086 +        }
  1.1087 +    }
  1.1088 +}
  1.1089 +
  1.1090 +/* destructor for CRL DPCache object */
  1.1091 +static SECStatus DPCache_Destroy(CRLDPCache* cache)
  1.1092 +{
  1.1093 +    PRUint32 i = 0;
  1.1094 +    PORT_Assert(cache);
  1.1095 +    if (!cache)
  1.1096 +    {
  1.1097 +        PORT_Assert(0);
  1.1098 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1099 +        return SECFailure;
  1.1100 +    }
  1.1101 +    if (cache->lock)
  1.1102 +    {
  1.1103 +#ifdef DPC_RWLOCK
  1.1104 +        NSSRWLock_Destroy(cache->lock);
  1.1105 +#else
  1.1106 +        PR_DestroyLock(cache->lock);
  1.1107 +#endif
  1.1108 +    }
  1.1109 +    else
  1.1110 +    {
  1.1111 +        PORT_Assert(0);
  1.1112 +        return SECFailure;
  1.1113 +    }
  1.1114 +    /* destroy all our CRL objects */
  1.1115 +    for (i=0;i<cache->ncrls;i++)
  1.1116 +    {
  1.1117 +        if (!cache->crls || !cache->crls[i] ||
  1.1118 +            SECSuccess != CachedCrl_Destroy(cache->crls[i]))
  1.1119 +        {
  1.1120 +            return SECFailure;
  1.1121 +        }
  1.1122 +    }
  1.1123 +    /* free the array of CRLs */
  1.1124 +    if (cache->crls)
  1.1125 +    {
  1.1126 +	PORT_Free(cache->crls);
  1.1127 +    }
  1.1128 +    /* destroy the cert */
  1.1129 +    if (cache->issuer)
  1.1130 +    {
  1.1131 +        CERT_DestroyCertificate(cache->issuer);
  1.1132 +    }
  1.1133 +    /* free the subject */
  1.1134 +    if (cache->subject)
  1.1135 +    {
  1.1136 +        SECITEM_FreeItem(cache->subject, PR_TRUE);
  1.1137 +    }
  1.1138 +    /* free the distribution points */
  1.1139 +    if (cache->distributionPoint)
  1.1140 +    {
  1.1141 +        SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
  1.1142 +    }
  1.1143 +    PORT_Free(cache);
  1.1144 +    return SECSuccess;
  1.1145 +}
  1.1146 +
  1.1147 +/* destructor for CRL IssuerCache object */
  1.1148 +SECStatus IssuerCache_Destroy(CRLIssuerCache* cache)
  1.1149 +{
  1.1150 +    PORT_Assert(cache);
  1.1151 +    if (!cache)
  1.1152 +    {
  1.1153 +        PORT_Assert(0);
  1.1154 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1155 +        return SECFailure;
  1.1156 +    }
  1.1157 +#ifdef XCRL
  1.1158 +    if (cache->lock)
  1.1159 +    {
  1.1160 +        NSSRWLock_Destroy(cache->lock);
  1.1161 +    }
  1.1162 +    else
  1.1163 +    {
  1.1164 +        PORT_Assert(0);
  1.1165 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1166 +        return SECFailure;
  1.1167 +    }
  1.1168 +    if (cache->issuer)
  1.1169 +    {
  1.1170 +        CERT_DestroyCertificate(cache->issuer);
  1.1171 +    }
  1.1172 +#endif
  1.1173 +    /* free the subject */
  1.1174 +    if (cache->subject)
  1.1175 +    {
  1.1176 +        SECITEM_FreeItem(cache->subject, PR_TRUE);
  1.1177 +    }
  1.1178 +    if (SECSuccess != DPCache_Destroy(cache->dpp))
  1.1179 +    {
  1.1180 +        PORT_Assert(0);
  1.1181 +        return SECFailure;
  1.1182 +    }
  1.1183 +    PORT_Free(cache);
  1.1184 +    return SECSuccess;
  1.1185 +}
  1.1186 +
  1.1187 +/* create a named CRL entry object */
  1.1188 +static SECStatus NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned)
  1.1189 +{
  1.1190 +    NamedCRLCacheEntry* entry = NULL;
  1.1191 +    if (!returned)
  1.1192 +    {
  1.1193 +        PORT_Assert(0);
  1.1194 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1195 +        return SECFailure;
  1.1196 +    }
  1.1197 +    *returned = NULL;
  1.1198 +    entry = (NamedCRLCacheEntry*) PORT_ZAlloc(sizeof(NamedCRLCacheEntry));
  1.1199 +    if (!entry)
  1.1200 +    {
  1.1201 +        return SECFailure;
  1.1202 +    }
  1.1203 +    *returned = entry;
  1.1204 +    return SECSuccess;
  1.1205 +}
  1.1206 +
  1.1207 +/* destroy a named CRL entry object */
  1.1208 +static SECStatus NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry)
  1.1209 +{
  1.1210 +    if (!entry)
  1.1211 +    {
  1.1212 +        PORT_Assert(0);
  1.1213 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1214 +        return SECFailure;
  1.1215 +    }
  1.1216 +    if (entry->crl)
  1.1217 +    {
  1.1218 +        /* named CRL cache owns DER memory */
  1.1219 +        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
  1.1220 +    }
  1.1221 +    if (entry->canonicalizedName)
  1.1222 +    {
  1.1223 +        SECITEM_FreeItem(entry->canonicalizedName, PR_TRUE);
  1.1224 +    }
  1.1225 +    PORT_Free(entry);
  1.1226 +    return SECSuccess;
  1.1227 +}
  1.1228 +
  1.1229 +/* callback function used in hash table destructor */
  1.1230 +static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg)
  1.1231 +{
  1.1232 +    CRLIssuerCache* issuer = NULL;
  1.1233 +    SECStatus* rv = (SECStatus*) arg;
  1.1234 +
  1.1235 +    PORT_Assert(he);
  1.1236 +    if (!he)
  1.1237 +    {
  1.1238 +        return HT_ENUMERATE_NEXT;
  1.1239 +    }
  1.1240 +    issuer = (CRLIssuerCache*) he->value;
  1.1241 +    PORT_Assert(issuer);
  1.1242 +    if (issuer)
  1.1243 +    {
  1.1244 +        if (SECSuccess != IssuerCache_Destroy(issuer))
  1.1245 +        {
  1.1246 +            PORT_Assert(rv);
  1.1247 +            if (rv)
  1.1248 +            {
  1.1249 +                *rv = SECFailure;
  1.1250 +            }
  1.1251 +            return HT_ENUMERATE_NEXT;
  1.1252 +        }
  1.1253 +    }
  1.1254 +    return HT_ENUMERATE_NEXT;
  1.1255 +}
  1.1256 +
  1.1257 +/* callback function used in hash table destructor */
  1.1258 +static PRIntn PR_CALLBACK FreeNamedEntries(PLHashEntry *he, PRIntn i, void *arg)
  1.1259 +{
  1.1260 +    NamedCRLCacheEntry* entry = NULL;
  1.1261 +    SECStatus* rv = (SECStatus*) arg;
  1.1262 +
  1.1263 +    PORT_Assert(he);
  1.1264 +    if (!he)
  1.1265 +    {
  1.1266 +        return HT_ENUMERATE_NEXT;
  1.1267 +    }
  1.1268 +    entry = (NamedCRLCacheEntry*) he->value;
  1.1269 +    PORT_Assert(entry);
  1.1270 +    if (entry)
  1.1271 +    {
  1.1272 +        if (SECSuccess != NamedCRLCacheEntry_Destroy(entry))
  1.1273 +        {
  1.1274 +            PORT_Assert(rv);
  1.1275 +            if (rv)
  1.1276 +            {
  1.1277 +                *rv = SECFailure;
  1.1278 +            }
  1.1279 +            return HT_ENUMERATE_NEXT;
  1.1280 +        }
  1.1281 +    }
  1.1282 +    return HT_ENUMERATE_NEXT;
  1.1283 +}
  1.1284 +
  1.1285 +/* needs to be called at NSS shutdown time
  1.1286 +   This will destroy the global CRL cache, including 
  1.1287 +   - the hash table of issuer cache objects
  1.1288 +   - the issuer cache objects
  1.1289 +   - DPCache objects in issuer cache objects */
  1.1290 +SECStatus ShutdownCRLCache(void)
  1.1291 +{
  1.1292 +    SECStatus rv = SECSuccess;
  1.1293 +    if (PR_FALSE == crlcache_initialized &&
  1.1294 +        !crlcache.lock && !crlcache.issuers)
  1.1295 +    {
  1.1296 +        /* CRL cache has already been shut down */
  1.1297 +        return SECSuccess;
  1.1298 +    }
  1.1299 +    if (PR_TRUE == crlcache_initialized &&
  1.1300 +        (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock ||
  1.1301 +         !namedCRLCache.entries))
  1.1302 +    {
  1.1303 +        /* CRL cache has partially been shut down */
  1.1304 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1305 +        return SECFailure;
  1.1306 +    }
  1.1307 +    /* empty the CRL cache */
  1.1308 +    /* free the issuers */
  1.1309 +    PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
  1.1310 +    /* free the hash table of issuers */
  1.1311 +    PL_HashTableDestroy(crlcache.issuers);
  1.1312 +    crlcache.issuers = NULL;
  1.1313 +    /* free the global lock */
  1.1314 +#ifdef GLOBAL_RWLOCK
  1.1315 +    NSSRWLock_Destroy(crlcache.lock);
  1.1316 +#else
  1.1317 +    PR_DestroyLock(crlcache.lock);
  1.1318 +#endif
  1.1319 +    crlcache.lock = NULL;
  1.1320 +
  1.1321 +    /* empty the named CRL cache. This must be done after freeing the CRL
  1.1322 +     * cache, since some CRLs in this cache are in the memory for the other  */
  1.1323 +    /* free the entries */
  1.1324 +    PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv);
  1.1325 +    /* free the hash table of issuers */
  1.1326 +    PL_HashTableDestroy(namedCRLCache.entries);
  1.1327 +    namedCRLCache.entries = NULL;
  1.1328 +    /* free the global lock */
  1.1329 +    PR_DestroyLock(namedCRLCache.lock);
  1.1330 +    namedCRLCache.lock = NULL;
  1.1331 +
  1.1332 +    crlcache_initialized = PR_FALSE;
  1.1333 +    return rv;
  1.1334 +}
  1.1335 +
  1.1336 +/* add a new CRL object to the dynamic array of CRLs of the DPCache, and
  1.1337 +   returns the cached CRL object . Needs write access to DPCache. */
  1.1338 +static SECStatus DPCache_AddCRL(CRLDPCache* cache, CachedCrl* newcrl,
  1.1339 +                                PRBool* added)
  1.1340 +{
  1.1341 +    CachedCrl** newcrls = NULL;
  1.1342 +    PRUint32 i = 0;
  1.1343 +    PORT_Assert(cache);
  1.1344 +    PORT_Assert(newcrl);
  1.1345 +    PORT_Assert(added);
  1.1346 +    if (!cache || !newcrl || !added)
  1.1347 +    {
  1.1348 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1349 +        return SECFailure;
  1.1350 +    }
  1.1351 +
  1.1352 +    *added = PR_FALSE;
  1.1353 +    /* before adding a new CRL, check if it is a duplicate */
  1.1354 +    for (i=0;i<cache->ncrls;i++)
  1.1355 +    {
  1.1356 +        CachedCrl* existing = NULL;
  1.1357 +        SECStatus rv = SECSuccess;
  1.1358 +        PRBool dupe = PR_FALSE, updated = PR_FALSE;
  1.1359 +        if (!cache->crls)
  1.1360 +        {
  1.1361 +            PORT_Assert(0);
  1.1362 +            return SECFailure;
  1.1363 +        }
  1.1364 +        existing = cache->crls[i];
  1.1365 +        if (!existing)
  1.1366 +        {
  1.1367 +            PORT_Assert(0);
  1.1368 +            return SECFailure;
  1.1369 +        }
  1.1370 +        rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
  1.1371 +        if (SECSuccess != rv)
  1.1372 +        {
  1.1373 +            PORT_Assert(0);
  1.1374 +            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1375 +            return SECFailure;
  1.1376 +        }
  1.1377 +        if (PR_TRUE == dupe)
  1.1378 +        {
  1.1379 +            /* dupe */
  1.1380 +            PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
  1.1381 +            return SECSuccess;
  1.1382 +        }
  1.1383 +        if (PR_TRUE == updated)
  1.1384 +        {
  1.1385 +            /* this token CRL is in the same slot and has the same object ID,
  1.1386 +               but different content. We need to remove the old object */
  1.1387 +            if (SECSuccess != DPCache_RemoveCRL(cache, i))
  1.1388 +            {
  1.1389 +                PORT_Assert(0);
  1.1390 +                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1391 +                return PR_FALSE;
  1.1392 +            }
  1.1393 +        }
  1.1394 +    }
  1.1395 +
  1.1396 +    newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
  1.1397 +        (cache->ncrls+1)*sizeof(CachedCrl*));
  1.1398 +    if (!newcrls)
  1.1399 +    {
  1.1400 +        return SECFailure;
  1.1401 +    }
  1.1402 +    cache->crls = newcrls;
  1.1403 +    cache->ncrls++;
  1.1404 +    cache->crls[cache->ncrls-1] = newcrl;
  1.1405 +    *added = PR_TRUE;
  1.1406 +    return SECSuccess;
  1.1407 +}
  1.1408 +
  1.1409 +/* remove CRL at offset specified */
  1.1410 +static SECStatus DPCache_RemoveCRL(CRLDPCache* cache, PRUint32 offset)
  1.1411 +{
  1.1412 +    CachedCrl* acrl = NULL;
  1.1413 +    PORT_Assert(cache);
  1.1414 +    if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
  1.1415 +    {
  1.1416 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1417 +        return SECFailure;
  1.1418 +    }
  1.1419 +    acrl = cache->crls[offset];
  1.1420 +    PORT_Assert(acrl);
  1.1421 +    if (!acrl)
  1.1422 +    {
  1.1423 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1424 +        return SECFailure;
  1.1425 +    }
  1.1426 +    cache->crls[offset] = cache->crls[cache->ncrls-1];
  1.1427 +    cache->crls[cache->ncrls-1] = NULL;
  1.1428 +    cache->ncrls--;
  1.1429 +    if (cache->selected == acrl) {
  1.1430 +        cache->selected = NULL;
  1.1431 +    }
  1.1432 +    if (SECSuccess != CachedCrl_Destroy(acrl))
  1.1433 +    {
  1.1434 +        PORT_Assert(0);
  1.1435 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1436 +        return SECFailure;
  1.1437 +    }
  1.1438 +    return SECSuccess;
  1.1439 +}
  1.1440 +
  1.1441 +/* check whether a CRL object stored in a PKCS#11 token still exists in
  1.1442 +   that token . This has to be efficient (the entire CRL value cannot be
  1.1443 +   transferred accross the token boundaries), so this is accomplished by
  1.1444 +   simply fetching the subject attribute and making sure it hasn't changed .
  1.1445 +   Note that technically, the CRL object could have been replaced with a new
  1.1446 +   PKCS#11 object of the same ID and subject (which actually happens in
  1.1447 +   softoken), but this function has no way of knowing that the object
  1.1448 +   value changed, since CKA_VALUE isn't checked. */
  1.1449 +static PRBool TokenCRLStillExists(CERTSignedCrl* crl)
  1.1450 +{
  1.1451 +    NSSItem newsubject;
  1.1452 +    SECItem subject;
  1.1453 +    CK_ULONG crl_class;
  1.1454 +    PRStatus status;
  1.1455 +    PK11SlotInfo* slot = NULL;
  1.1456 +    nssCryptokiObject instance;
  1.1457 +    NSSArena* arena;
  1.1458 +    PRBool xstatus = PR_TRUE;
  1.1459 +    SECItem* oldSubject = NULL;
  1.1460 +
  1.1461 +    PORT_Assert(crl);
  1.1462 +    if (!crl)
  1.1463 +    {
  1.1464 +        return PR_FALSE;
  1.1465 +    }
  1.1466 +    slot = crl->slot;
  1.1467 +    PORT_Assert(crl->slot);
  1.1468 +    if (!slot)
  1.1469 +    {
  1.1470 +        return PR_FALSE;
  1.1471 +    }
  1.1472 +    oldSubject = &crl->crl.derName;
  1.1473 +    PORT_Assert(oldSubject);
  1.1474 +    if (!oldSubject)
  1.1475 +    {
  1.1476 +        return PR_FALSE;
  1.1477 +    }
  1.1478 +
  1.1479 +    /* query subject and type attributes in order to determine if the
  1.1480 +       object has been deleted */
  1.1481 +
  1.1482 +    /* first, make an nssCryptokiObject */
  1.1483 +    instance.handle = crl->pkcs11ID;
  1.1484 +    PORT_Assert(instance.handle);
  1.1485 +    if (!instance.handle)
  1.1486 +    {
  1.1487 +        return PR_FALSE;
  1.1488 +    }
  1.1489 +    instance.token = PK11Slot_GetNSSToken(slot);
  1.1490 +    PORT_Assert(instance.token);
  1.1491 +    if (!instance.token)
  1.1492 +    {
  1.1493 +        return PR_FALSE;
  1.1494 +    }
  1.1495 +    instance.isTokenObject = PR_TRUE;
  1.1496 +    instance.label = NULL;
  1.1497 +
  1.1498 +    arena = NSSArena_Create();
  1.1499 +    PORT_Assert(arena);
  1.1500 +    if (!arena)
  1.1501 +    {
  1.1502 +        return PR_FALSE;
  1.1503 +    }
  1.1504 +
  1.1505 +    status = nssCryptokiCRL_GetAttributes(&instance,
  1.1506 +                                          NULL,  /* XXX sessionOpt */
  1.1507 +                                          arena,
  1.1508 +                                          NULL,
  1.1509 +                                          &newsubject,  /* subject */
  1.1510 +                                          &crl_class,   /* class */
  1.1511 +                                          NULL,
  1.1512 +                                          NULL);
  1.1513 +    if (PR_SUCCESS == status)
  1.1514 +    {
  1.1515 +        subject.data = newsubject.data;
  1.1516 +        subject.len = newsubject.size;
  1.1517 +        if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
  1.1518 +        {
  1.1519 +            xstatus = PR_FALSE;
  1.1520 +        }
  1.1521 +        if (CKO_NETSCAPE_CRL != crl_class)
  1.1522 +        {
  1.1523 +            xstatus = PR_FALSE;
  1.1524 +        }
  1.1525 +    }
  1.1526 +    else
  1.1527 +    {
  1.1528 +        xstatus = PR_FALSE;
  1.1529 +    }
  1.1530 +    NSSArena_Destroy(arena);
  1.1531 +    return xstatus;
  1.1532 +}
  1.1533 +
  1.1534 +/* verify the signature of a CRL against its issuer at a given date */
  1.1535 +static SECStatus CERT_VerifyCRL(
  1.1536 +    CERTSignedCrl* crlobject,
  1.1537 +    CERTCertificate* issuer,
  1.1538 +    PRTime vfdate,
  1.1539 +    void* wincx)
  1.1540 +{
  1.1541 +    return CERT_VerifySignedData(&crlobject->signatureWrap,
  1.1542 +                                 issuer, vfdate, wincx);
  1.1543 +}
  1.1544 +
  1.1545 +/* verify a CRL and update cache state */
  1.1546 +static SECStatus CachedCrl_Verify(CRLDPCache* cache, CachedCrl* crlobject,
  1.1547 +                          PRTime vfdate, void* wincx)
  1.1548 +{
  1.1549 +    /*  Check if it is an invalid CRL
  1.1550 +        if we got a bad CRL, we want to cache it in order to avoid
  1.1551 +        subsequent fetches of this same identical bad CRL. We set
  1.1552 +        the cache to the invalid state to ensure that all certs on this
  1.1553 +        DP are considered to have unknown status from now on. The cache
  1.1554 +        object will remain in this state until the bad CRL object
  1.1555 +        is removed from the token it was fetched from. If the cause
  1.1556 +        of the failure is that we didn't have the issuer cert to
  1.1557 +        verify the signature, this state can be cleared when
  1.1558 +        the issuer certificate becomes available if that causes the
  1.1559 +        signature to verify */
  1.1560 +
  1.1561 +    if (!cache || !crlobject)
  1.1562 +    {
  1.1563 +        PORT_Assert(0);
  1.1564 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1565 +        return SECFailure;
  1.1566 +    }
  1.1567 +    if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
  1.1568 +    {
  1.1569 +        crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
  1.1570 +            with bogus DER. Mark it checked so we won't try again */
  1.1571 +        PORT_SetError(SEC_ERROR_BAD_DER);
  1.1572 +        return SECSuccess;
  1.1573 +    }
  1.1574 +    else
  1.1575 +    {
  1.1576 +        SECStatus signstatus = SECFailure;
  1.1577 +        if (cache->issuer)
  1.1578 +        {
  1.1579 +            signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
  1.1580 +                                        wincx);
  1.1581 +        }
  1.1582 +        if (SECSuccess != signstatus)
  1.1583 +        {
  1.1584 +            if (!cache->issuer)
  1.1585 +            {
  1.1586 +                /* we tried to verify without an issuer cert . This is
  1.1587 +                   because this CRL came through a call to SEC_FindCrlByName.
  1.1588 +                   So, we don't cache this verification failure. We'll try
  1.1589 +                   to verify the CRL again when a certificate from that issuer
  1.1590 +                   becomes available */
  1.1591 +            } else
  1.1592 +            {
  1.1593 +                crlobject->sigChecked = PR_TRUE;
  1.1594 +            }
  1.1595 +            PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
  1.1596 +            return SECSuccess;
  1.1597 +        } else
  1.1598 +        {
  1.1599 +            crlobject->sigChecked = PR_TRUE;
  1.1600 +            crlobject->sigValid = PR_TRUE;
  1.1601 +        }
  1.1602 +    }
  1.1603 +    
  1.1604 +    return SECSuccess;
  1.1605 +}
  1.1606 +
  1.1607 +/* fetch the CRLs for this DP from the PKCS#11 tokens */
  1.1608 +static SECStatus DPCache_FetchFromTokens(CRLDPCache* cache, PRTime vfdate,
  1.1609 +                                         void* wincx)
  1.1610 +{
  1.1611 +    SECStatus rv = SECSuccess;
  1.1612 +    CERTCrlHeadNode head;
  1.1613 +    if (!cache)
  1.1614 +    {
  1.1615 +        PORT_Assert(0);
  1.1616 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1617 +        return SECFailure;
  1.1618 +    }
  1.1619 +    /* first, initialize list */
  1.1620 +    memset(&head, 0, sizeof(head));
  1.1621 +    head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
  1.1622 +    rv = pk11_RetrieveCrls(&head, cache->subject, wincx);
  1.1623 +
  1.1624 +    /* if this function fails, something very wrong happened, such as an out
  1.1625 +       of memory error during CRL decoding. We don't want to proceed and must
  1.1626 +       mark the cache object invalid */
  1.1627 +    if (SECFailure == rv)
  1.1628 +    {
  1.1629 +        /* fetch failed, add error bit */
  1.1630 +        cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
  1.1631 +    } else
  1.1632 +    {
  1.1633 +        /* fetch was successful, clear this error bit */
  1.1634 +        cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
  1.1635 +    }
  1.1636 +
  1.1637 +    /* add any CRLs found to our array */
  1.1638 +    if (SECSuccess == rv)
  1.1639 +    {
  1.1640 +        CERTCrlNode* crlNode = NULL;
  1.1641 +
  1.1642 +        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
  1.1643 +        {
  1.1644 +            CachedCrl* returned = NULL;
  1.1645 +            CERTSignedCrl* crlobject = crlNode->crl;
  1.1646 +            if (!crlobject)
  1.1647 +            {
  1.1648 +                PORT_Assert(0);
  1.1649 +                continue;
  1.1650 +            }
  1.1651 +            rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
  1.1652 +            if (SECSuccess == rv)
  1.1653 +            {
  1.1654 +                PRBool added = PR_FALSE;
  1.1655 +                rv = DPCache_AddCRL(cache, returned, &added);
  1.1656 +                if (PR_TRUE != added)
  1.1657 +                {
  1.1658 +                    rv = CachedCrl_Destroy(returned);
  1.1659 +                    returned = NULL;
  1.1660 +                }
  1.1661 +                else if (vfdate)
  1.1662 +                {
  1.1663 +                    rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
  1.1664 +                }
  1.1665 +            }
  1.1666 +            else
  1.1667 +            {
  1.1668 +                /* not enough memory to add the CRL to the cache. mark it
  1.1669 +                   invalid so we will try again . */
  1.1670 +                cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
  1.1671 +            }
  1.1672 +            if (SECFailure == rv)
  1.1673 +            {
  1.1674 +                break;
  1.1675 +            }
  1.1676 +        }
  1.1677 +    }
  1.1678 +
  1.1679 +    if (head.arena)
  1.1680 +    {
  1.1681 +        CERTCrlNode* crlNode = NULL;
  1.1682 +        /* clean up the CRL list in case we got a partial one
  1.1683 +           during a failed fetch */
  1.1684 +        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
  1.1685 +        {
  1.1686 +            if (crlNode->crl)
  1.1687 +            {
  1.1688 +                SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
  1.1689 +                   added to the cache and the refcount got bumped, or not, and
  1.1690 +                   thus we need to free its RAM */
  1.1691 +            }
  1.1692 +        }
  1.1693 +        PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
  1.1694 +    }
  1.1695 +
  1.1696 +    return rv;
  1.1697 +}
  1.1698 +
  1.1699 +static SECStatus CachedCrl_GetEntry(CachedCrl* crl, const SECItem* sn,
  1.1700 +                                    CERTCrlEntry** returned)
  1.1701 +{
  1.1702 +    CERTCrlEntry* acrlEntry;
  1.1703 +     
  1.1704 +    PORT_Assert(crl);
  1.1705 +    PORT_Assert(crl->entries);
  1.1706 +    PORT_Assert(sn);
  1.1707 +    PORT_Assert(returned);
  1.1708 +    if (!crl || !sn || !returned || !crl->entries)
  1.1709 +    {
  1.1710 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1711 +        return SECFailure;
  1.1712 +    }
  1.1713 +    acrlEntry = PL_HashTableLookup(crl->entries, (void*)sn);
  1.1714 +    if (acrlEntry)
  1.1715 +    {
  1.1716 +        *returned = acrlEntry;
  1.1717 +    }
  1.1718 +    else
  1.1719 +    {
  1.1720 +        *returned = NULL;
  1.1721 +    }
  1.1722 +    return SECSuccess;
  1.1723 +}
  1.1724 +
  1.1725 +/* check if a particular SN is in the CRL cache and return its entry */
  1.1726 +dpcacheStatus DPCache_Lookup(CRLDPCache* cache, const SECItem* sn,
  1.1727 +                         CERTCrlEntry** returned)
  1.1728 +{
  1.1729 +    SECStatus rv;
  1.1730 +    if (!cache || !sn || !returned)
  1.1731 +    {
  1.1732 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.1733 +        /* no cache or SN to look up, or no way to return entry */
  1.1734 +        return dpcacheCallerError;
  1.1735 +    }
  1.1736 +    *returned = NULL;
  1.1737 +    if (0 != cache->invalid)
  1.1738 +    {
  1.1739 +        /* the cache contains a bad CRL, or there was a CRL fetching error. */
  1.1740 +        PORT_SetError(SEC_ERROR_CRL_INVALID);
  1.1741 +        return dpcacheInvalidCacheError;
  1.1742 +    }
  1.1743 +    if (!cache->selected)
  1.1744 +    {
  1.1745 +        /* no CRL means no entry to return. This is OK, except for
  1.1746 +         * NIST policy */
  1.1747 +        return dpcacheEmpty;
  1.1748 +    }
  1.1749 +    rv = CachedCrl_GetEntry(cache->selected, sn, returned);
  1.1750 +    if (SECSuccess != rv)
  1.1751 +    {
  1.1752 +        return dpcacheLookupError;
  1.1753 +    }
  1.1754 +    else
  1.1755 +    {
  1.1756 +        if (*returned)
  1.1757 +        {
  1.1758 +            return dpcacheFoundEntry;
  1.1759 +        }
  1.1760 +        else
  1.1761 +        {
  1.1762 +            return dpcacheNoEntry;
  1.1763 +        }
  1.1764 +    }
  1.1765 +}
  1.1766 +
  1.1767 +#if defined(DPC_RWLOCK)
  1.1768 +
  1.1769 +#define DPCache_LockWrite() \
  1.1770 +{ \
  1.1771 +    if (readlocked) \
  1.1772 +    { \
  1.1773 +        NSSRWLock_UnlockRead(cache->lock); \
  1.1774 +    } \
  1.1775 +    NSSRWLock_LockWrite(cache->lock); \
  1.1776 +}
  1.1777 +
  1.1778 +#define DPCache_UnlockWrite() \
  1.1779 +{ \
  1.1780 +    if (readlocked) \
  1.1781 +    { \
  1.1782 +        NSSRWLock_LockRead(cache->lock); \
  1.1783 +    } \
  1.1784 +    NSSRWLock_UnlockWrite(cache->lock); \
  1.1785 +}
  1.1786 +
  1.1787 +#else
  1.1788 +
  1.1789 +/* with a global lock, we are always locked for read before we need write
  1.1790 +   access, so do nothing */
  1.1791 +
  1.1792 +#define DPCache_LockWrite() \
  1.1793 +{ \
  1.1794 +}
  1.1795 +
  1.1796 +#define DPCache_UnlockWrite() \
  1.1797 +{ \
  1.1798 +}
  1.1799 +
  1.1800 +#endif
  1.1801 +
  1.1802 +/* update the content of the CRL cache, including fetching of CRLs, and
  1.1803 +   reprocessing with specified issuer and date . We are always holding
  1.1804 +   either the read or write lock on DPCache upon entry. */
  1.1805 +static SECStatus DPCache_GetUpToDate(CRLDPCache* cache, CERTCertificate*
  1.1806 +                                     issuer, PRBool readlocked, PRTime vfdate,
  1.1807 +                                     void* wincx)
  1.1808 +{
  1.1809 +    /* Update the CRLDPCache now. We don't cache token CRL lookup misses
  1.1810 +       yet, as we have no way of getting notified of new PKCS#11 object
  1.1811 +       creation that happens in a token  */
  1.1812 +    SECStatus rv = SECSuccess;
  1.1813 +    PRUint32 i = 0;
  1.1814 +    PRBool forcedrefresh = PR_FALSE;
  1.1815 +    PRBool dirty = PR_FALSE; /* whether something was changed in the
  1.1816 +                                cache state during this update cycle */
  1.1817 +    PRBool hastokenCRLs = PR_FALSE;
  1.1818 +    PRTime now = 0;
  1.1819 +    PRTime lastfetch = 0;
  1.1820 +    PRBool mustunlock = PR_FALSE;
  1.1821 +
  1.1822 +    if (!cache)
  1.1823 +    {
  1.1824 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.1825 +        return SECFailure;
  1.1826 +    }
  1.1827 +
  1.1828 +    /* first, make sure we have obtained all the CRLs we need.
  1.1829 +       We do an expensive token fetch in the following cases :
  1.1830 +       1) cache is empty because no fetch was ever performed yet
  1.1831 +       2) cache is explicitly set to refresh state
  1.1832 +       3) cache is in invalid state because last fetch failed
  1.1833 +       4) cache contains no token CRLs, and it's been more than one minute
  1.1834 +          since the last fetch
  1.1835 +       5) cache contains token CRLs, and it's been more than 10 minutes since
  1.1836 +          the last fetch
  1.1837 +    */
  1.1838 +    forcedrefresh = cache->refresh;
  1.1839 +    lastfetch = cache->lastfetch;
  1.1840 +    if (PR_TRUE != forcedrefresh && 
  1.1841 +        (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
  1.1842 +    {
  1.1843 +        now = PR_Now();
  1.1844 +        hastokenCRLs = DPCache_HasTokenCRLs(cache);
  1.1845 +    }
  1.1846 +    if ( (0 == lastfetch) ||
  1.1847 +
  1.1848 +         (PR_TRUE == forcedrefresh) ||
  1.1849 +
  1.1850 +         (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||
  1.1851 +
  1.1852 +         ( (PR_FALSE == hastokenCRLs) &&
  1.1853 +           ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
  1.1854 +             (now < cache->lastfetch)) ) ||
  1.1855 +
  1.1856 +         ( (PR_TRUE == hastokenCRLs) &&
  1.1857 +           ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
  1.1858 +            (now < cache->lastfetch)) ) )
  1.1859 +    {
  1.1860 +        /* the cache needs to be refreshed, and/or we had zero CRL for this
  1.1861 +           DP. Try to get one from PKCS#11 tokens */
  1.1862 +        DPCache_LockWrite();
  1.1863 +        /* check if another thread updated before us, and skip update if so */
  1.1864 +        if (lastfetch == cache->lastfetch)
  1.1865 +        {
  1.1866 +            /* we are the first */
  1.1867 +            rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
  1.1868 +            if (PR_TRUE == cache->refresh)
  1.1869 +            {
  1.1870 +                cache->refresh = PR_FALSE; /* clear refresh state */
  1.1871 +            }
  1.1872 +            dirty = PR_TRUE;
  1.1873 +            cache->lastfetch = PR_Now();
  1.1874 +        }
  1.1875 +        DPCache_UnlockWrite();
  1.1876 +    }
  1.1877 +
  1.1878 +    /* now, make sure we have no extraneous CRLs (deleted token objects)
  1.1879 +       we'll do this inexpensive existence check either
  1.1880 +       1) if there was a token object fetch
  1.1881 +       2) every minute */
  1.1882 +    if (( PR_TRUE != dirty) && (!now) )
  1.1883 +    {
  1.1884 +        now = PR_Now();
  1.1885 +    }
  1.1886 +    if ( (PR_TRUE == dirty) ||
  1.1887 +         ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
  1.1888 +           (now < cache->lastcheck)) )
  1.1889 +    {
  1.1890 +        PRTime lastcheck = cache->lastcheck;
  1.1891 +        mustunlock = PR_FALSE;
  1.1892 +        /* check if all CRLs still exist */
  1.1893 +        for (i = 0; (i < cache->ncrls) ; i++)
  1.1894 +        {
  1.1895 +            CachedCrl* savcrl = cache->crls[i];
  1.1896 +            if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
  1.1897 +            {
  1.1898 +                /* we only want to check token CRLs */
  1.1899 +                continue;
  1.1900 +            }
  1.1901 +            if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
  1.1902 +            {
  1.1903 +                
  1.1904 +                /* this CRL is gone */
  1.1905 +                if (PR_TRUE != mustunlock)
  1.1906 +                {
  1.1907 +                    DPCache_LockWrite();
  1.1908 +                    mustunlock = PR_TRUE;
  1.1909 +                }
  1.1910 +                /* first, we need to check if another thread did an update
  1.1911 +                   before we did */
  1.1912 +                if (lastcheck == cache->lastcheck)
  1.1913 +                {
  1.1914 +                    /* the CRL is gone. And we are the one to do the update */
  1.1915 +                    DPCache_RemoveCRL(cache, i);
  1.1916 +                    dirty = PR_TRUE;
  1.1917 +                }
  1.1918 +                /* stay locked here intentionally so we do all the other
  1.1919 +                   updates in this thread for the remaining CRLs */
  1.1920 +            }
  1.1921 +        }
  1.1922 +        if (PR_TRUE == mustunlock)
  1.1923 +        {
  1.1924 +            cache->lastcheck = PR_Now();
  1.1925 +            DPCache_UnlockWrite();
  1.1926 +            mustunlock = PR_FALSE;
  1.1927 +        }
  1.1928 +    }
  1.1929 +
  1.1930 +    /* add issuer certificate if it was previously unavailable */
  1.1931 +    if (issuer && (NULL == cache->issuer) &&
  1.1932 +        (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
  1.1933 +    {
  1.1934 +        /* if we didn't have a valid issuer cert yet, but we do now. add it */
  1.1935 +        DPCache_LockWrite();
  1.1936 +        if (!cache->issuer)
  1.1937 +        {
  1.1938 +            dirty = PR_TRUE;
  1.1939 +            cache->issuer = CERT_DupCertificate(issuer);    
  1.1940 +        }
  1.1941 +        DPCache_UnlockWrite();
  1.1942 +    }
  1.1943 +
  1.1944 +    /* verify CRLs that couldn't be checked when inserted into the cache
  1.1945 +       because the issuer cert or a verification date was unavailable.
  1.1946 +       These are CRLs that were inserted into the cache through
  1.1947 +       SEC_FindCrlByName, or through manual insertion, rather than through a
  1.1948 +       certificate verification (CERT_CheckCRL) */
  1.1949 +
  1.1950 +    if (cache->issuer && vfdate )
  1.1951 +    {
  1.1952 +	mustunlock = PR_FALSE;
  1.1953 +        /* re-process all unverified CRLs */
  1.1954 +        for (i = 0; i < cache->ncrls ; i++)
  1.1955 +        {
  1.1956 +            CachedCrl* savcrl = cache->crls[i];
  1.1957 +            if (!savcrl)
  1.1958 +            {
  1.1959 +                continue;
  1.1960 +            }
  1.1961 +            if (PR_TRUE != savcrl->sigChecked)
  1.1962 +            {
  1.1963 +                if (!mustunlock)
  1.1964 +                {
  1.1965 +                    DPCache_LockWrite();
  1.1966 +                    mustunlock = PR_TRUE;
  1.1967 +                }
  1.1968 +                /* first, we need to check if another thread updated
  1.1969 +                   it before we did, and abort if it has been modified since
  1.1970 +                   we acquired the lock. Make sure first that the CRL is still
  1.1971 +                   in the array at the same position */
  1.1972 +                if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
  1.1973 +                     (PR_TRUE != savcrl->sigChecked) )
  1.1974 +                {
  1.1975 +                    /* the CRL is still there, unverified. Do it */
  1.1976 +                    CachedCrl_Verify(cache, savcrl, vfdate, wincx);
  1.1977 +                    dirty = PR_TRUE;
  1.1978 +                }
  1.1979 +                /* stay locked here intentionally so we do all the other
  1.1980 +                   updates in this thread for the remaining CRLs */
  1.1981 +            }
  1.1982 +            if (mustunlock && !dirty)
  1.1983 +            {
  1.1984 +                DPCache_UnlockWrite();
  1.1985 +                mustunlock = PR_FALSE;
  1.1986 +            }
  1.1987 +        }
  1.1988 +    }
  1.1989 +
  1.1990 +    if (dirty || cache->mustchoose)
  1.1991 +    {
  1.1992 +        /* changes to the content of the CRL cache necessitate examining all
  1.1993 +           CRLs for selection of the most appropriate one to cache */
  1.1994 +	if (!mustunlock)
  1.1995 +	{
  1.1996 +	    DPCache_LockWrite();
  1.1997 +	    mustunlock = PR_TRUE;
  1.1998 +	}
  1.1999 +        DPCache_SelectCRL(cache);
  1.2000 +        cache->mustchoose = PR_FALSE;
  1.2001 +    }
  1.2002 +    if (mustunlock)
  1.2003 +	DPCache_UnlockWrite();
  1.2004 +
  1.2005 +    return rv;
  1.2006 +}
  1.2007 +
  1.2008 +/* callback for qsort to sort by thisUpdate */
  1.2009 +static int SortCRLsByThisUpdate(const void* arg1, const void* arg2)
  1.2010 +{
  1.2011 +    PRTime timea, timeb;
  1.2012 +    SECStatus rv = SECSuccess;
  1.2013 +    CachedCrl* a, *b;
  1.2014 +
  1.2015 +    a = *(CachedCrl**) arg1;
  1.2016 +    b = *(CachedCrl**) arg2;
  1.2017 +
  1.2018 +    if (!a || !b)
  1.2019 +    {
  1.2020 +        PORT_Assert(0);
  1.2021 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2022 +        rv = SECFailure;
  1.2023 +    }
  1.2024 +
  1.2025 +    if (SECSuccess == rv)
  1.2026 +    {
  1.2027 +        rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
  1.2028 +    }                       
  1.2029 +    if (SECSuccess == rv)
  1.2030 +    {
  1.2031 +        rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
  1.2032 +    }
  1.2033 +    if (SECSuccess == rv)
  1.2034 +    {
  1.2035 +        if (timea > timeb)
  1.2036 +        {
  1.2037 +            return 1; /* a is better than b */
  1.2038 +        }
  1.2039 +        if (timea < timeb )
  1.2040 +        {
  1.2041 +            return -1; /* a is not as good as b */
  1.2042 +        }
  1.2043 +    }
  1.2044 +
  1.2045 +    /* if they are equal, or if all else fails, use pointer differences */
  1.2046 +    PORT_Assert(a != b); /* they should never be equal */
  1.2047 +    return a>b?1:-1;
  1.2048 +}
  1.2049 +
  1.2050 +/* callback for qsort to sort a set of disparate CRLs, some of which are
  1.2051 +   invalid DER or failed signature check.
  1.2052 +   
  1.2053 +   Validated CRLs are differentiated by thisUpdate .
  1.2054 +   Validated CRLs are preferred over non-validated CRLs .
  1.2055 +   Proper DER CRLs are preferred over non-DER data .
  1.2056 +*/
  1.2057 +static int SortImperfectCRLs(const void* arg1, const void* arg2)
  1.2058 +{
  1.2059 +    CachedCrl* a, *b;
  1.2060 +
  1.2061 +    a = *(CachedCrl**) arg1;
  1.2062 +    b = *(CachedCrl**) arg2;
  1.2063 +
  1.2064 +    if (!a || !b)
  1.2065 +    {
  1.2066 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2067 +        PORT_Assert(0);
  1.2068 +    }
  1.2069 +    else
  1.2070 +    {
  1.2071 +        PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
  1.2072 +        if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
  1.2073 +        {
  1.2074 +            /* both CRLs have been validated, choose the latest one */
  1.2075 +            return SortCRLsByThisUpdate(arg1, arg2);
  1.2076 +        }
  1.2077 +        if (PR_TRUE == a->sigValid)
  1.2078 +        {
  1.2079 +            return 1; /* a is greater than b */
  1.2080 +        }
  1.2081 +        if (PR_TRUE == b->sigValid)
  1.2082 +        {
  1.2083 +            return -1; /* a is not as good as b */
  1.2084 +        }
  1.2085 +        aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
  1.2086 +        bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
  1.2087 +        /* neither CRL had its signature check pass */
  1.2088 +        if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
  1.2089 +        {
  1.2090 +            /* both CRLs are proper DER, choose the latest one */
  1.2091 +            return SortCRLsByThisUpdate(arg1, arg2);
  1.2092 +        }
  1.2093 +        if (PR_FALSE == aDecoded)
  1.2094 +        {
  1.2095 +            return 1; /* a is better than b */
  1.2096 +        }
  1.2097 +        if (PR_FALSE == bDecoded)
  1.2098 +        {
  1.2099 +            return -1; /* a is not as good as b */
  1.2100 +        }
  1.2101 +        /* both are invalid DER. sigh. */
  1.2102 +    }
  1.2103 +    /* if they are equal, or if all else fails, use pointer differences */
  1.2104 +    PORT_Assert(a != b); /* they should never be equal */
  1.2105 +    return a>b?1:-1;
  1.2106 +}
  1.2107 +
  1.2108 +
  1.2109 +/* Pick best CRL to use . needs write access */
  1.2110 +static SECStatus DPCache_SelectCRL(CRLDPCache* cache)
  1.2111 +{
  1.2112 +    PRUint32 i;
  1.2113 +    PRBool valid = PR_TRUE;
  1.2114 +    CachedCrl* selected = NULL;
  1.2115 +
  1.2116 +    PORT_Assert(cache);
  1.2117 +    if (!cache)
  1.2118 +    {
  1.2119 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2120 +        return SECFailure;
  1.2121 +    }
  1.2122 +    /* if any invalid CRL is present, then the CRL cache is
  1.2123 +       considered invalid, for security reasons */
  1.2124 +    for (i = 0 ; i<cache->ncrls; i++)
  1.2125 +    {
  1.2126 +        if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
  1.2127 +            !cache->crls[i]->sigValid)
  1.2128 +        {
  1.2129 +            valid = PR_FALSE;
  1.2130 +            break;
  1.2131 +        }
  1.2132 +    }
  1.2133 +    if (PR_TRUE == valid)
  1.2134 +    {
  1.2135 +        /* all CRLs are valid, clear this error */
  1.2136 +        cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
  1.2137 +    } else
  1.2138 +    {
  1.2139 +        /* some CRLs are invalid, set this error */
  1.2140 +        cache->invalid |= CRL_CACHE_INVALID_CRLS;
  1.2141 +    }
  1.2142 +
  1.2143 +    if (cache->invalid)
  1.2144 +    {
  1.2145 +        /* cache is in an invalid state, so reset it */
  1.2146 +        if (cache->selected)
  1.2147 +        {
  1.2148 +            cache->selected = NULL;
  1.2149 +        }
  1.2150 +        /* also sort the CRLs imperfectly */
  1.2151 +        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
  1.2152 +              SortImperfectCRLs);
  1.2153 +        return SECSuccess;
  1.2154 +    }
  1.2155 +    /* all CRLs are good, sort them by thisUpdate */
  1.2156 +    qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
  1.2157 +          SortCRLsByThisUpdate);
  1.2158 +
  1.2159 +    if (cache->ncrls)
  1.2160 +    {
  1.2161 +        /* pick the newest CRL */
  1.2162 +        selected = cache->crls[cache->ncrls-1];
  1.2163 +    
  1.2164 +        /* and populate the cache */
  1.2165 +        if (SECSuccess != CachedCrl_Populate(selected))
  1.2166 +        {
  1.2167 +            return SECFailure;
  1.2168 +        }
  1.2169 +    }
  1.2170 +
  1.2171 +    cache->selected = selected;
  1.2172 +
  1.2173 +    return SECSuccess;
  1.2174 +}
  1.2175 +
  1.2176 +/* initialize a DPCache object */
  1.2177 +static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer,
  1.2178 +                         const SECItem* subject, SECItem* dp)
  1.2179 +{
  1.2180 +    CRLDPCache* cache = NULL;
  1.2181 +    PORT_Assert(returned);
  1.2182 +    /* issuer and dp are allowed to be NULL */
  1.2183 +    if (!returned || !subject)
  1.2184 +    {
  1.2185 +        PORT_Assert(0);
  1.2186 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2187 +        return SECFailure;
  1.2188 +    }
  1.2189 +    *returned = NULL;
  1.2190 +    cache = PORT_ZAlloc(sizeof(CRLDPCache));
  1.2191 +    if (!cache)
  1.2192 +    {
  1.2193 +        return SECFailure;
  1.2194 +    }
  1.2195 +#ifdef DPC_RWLOCK
  1.2196 +    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  1.2197 +#else
  1.2198 +    cache->lock = PR_NewLock();
  1.2199 +#endif
  1.2200 +    if (!cache->lock)
  1.2201 +    {
  1.2202 +	PORT_Free(cache);
  1.2203 +        return SECFailure;
  1.2204 +    }
  1.2205 +    if (issuer)
  1.2206 +    {
  1.2207 +        cache->issuer = CERT_DupCertificate(issuer);
  1.2208 +    }
  1.2209 +    cache->distributionPoint = SECITEM_DupItem(dp);
  1.2210 +    cache->subject = SECITEM_DupItem(subject);
  1.2211 +    cache->lastfetch = 0;
  1.2212 +    cache->lastcheck = 0;
  1.2213 +    *returned = cache;
  1.2214 +    return SECSuccess;
  1.2215 +}
  1.2216 +
  1.2217 +/* create an issuer cache object (per CA subject ) */
  1.2218 +static SECStatus IssuerCache_Create(CRLIssuerCache** returned,
  1.2219 +                             CERTCertificate* issuer,
  1.2220 +                             const SECItem* subject, const SECItem* dp)
  1.2221 +{
  1.2222 +    SECStatus rv = SECSuccess;
  1.2223 +    CRLIssuerCache* cache = NULL;
  1.2224 +    PORT_Assert(returned);
  1.2225 +    PORT_Assert(subject);
  1.2226 +    /* issuer and dp are allowed to be NULL */
  1.2227 +    if (!returned || !subject)
  1.2228 +    {
  1.2229 +        PORT_Assert(0);
  1.2230 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2231 +        return SECFailure;
  1.2232 +    }
  1.2233 +    *returned = NULL;
  1.2234 +    cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
  1.2235 +    if (!cache)
  1.2236 +    {
  1.2237 +        return SECFailure;
  1.2238 +    }
  1.2239 +    cache->subject = SECITEM_DupItem(subject);
  1.2240 +#ifdef XCRL
  1.2241 +    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
  1.2242 +    if (!cache->lock)
  1.2243 +    {
  1.2244 +        rv = SECFailure;
  1.2245 +    }
  1.2246 +    if (SECSuccess == rv && issuer)
  1.2247 +    {
  1.2248 +        cache->issuer = CERT_DupCertificate(issuer);
  1.2249 +        if (!cache->issuer)
  1.2250 +        {
  1.2251 +            rv = SECFailure;
  1.2252 +        }
  1.2253 +    }
  1.2254 +#endif
  1.2255 +    if (SECSuccess != rv)
  1.2256 +    {
  1.2257 +        PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
  1.2258 +        return SECFailure;
  1.2259 +    }
  1.2260 +    *returned = cache;
  1.2261 +    return SECSuccess;
  1.2262 +}
  1.2263 +
  1.2264 +/* add a DPCache to the issuer cache */
  1.2265 +static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache,
  1.2266 +                                   CERTCertificate* issuer,
  1.2267 +                                   const SECItem* subject,
  1.2268 +                                   const SECItem* dp,
  1.2269 +                                   CRLDPCache** newdpc)
  1.2270 +{
  1.2271 +    /* now create the required DP cache object */
  1.2272 +    if (!cache || !subject || !newdpc)
  1.2273 +    {
  1.2274 +        PORT_Assert(0);
  1.2275 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2276 +        return SECFailure;
  1.2277 +    }
  1.2278 +    if (!dp)
  1.2279 +    {
  1.2280 +        /* default distribution point */
  1.2281 +        SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
  1.2282 +        if (SECSuccess == rv)
  1.2283 +        {
  1.2284 +            *newdpc = cache->dpp;
  1.2285 +            return SECSuccess;
  1.2286 +        }
  1.2287 +    }
  1.2288 +    else
  1.2289 +    {
  1.2290 +        /* we should never hit this until we support multiple DPs */
  1.2291 +        PORT_Assert(dp);
  1.2292 +        /* XCRL allocate a new distribution point cache object, initialize it,
  1.2293 +           and add it to the hash table of DPs */
  1.2294 +    }
  1.2295 +    return SECFailure;
  1.2296 +}
  1.2297 +
  1.2298 +/* add an IssuerCache to the global hash table of issuers */
  1.2299 +static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer)
  1.2300 +{    
  1.2301 +    PORT_Assert(issuer);
  1.2302 +    PORT_Assert(crlcache.issuers);
  1.2303 +    if (!issuer || !crlcache.issuers)
  1.2304 +    {
  1.2305 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2306 +        return SECFailure;
  1.2307 +    }
  1.2308 +    if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
  1.2309 +                                (void*) issuer))
  1.2310 +    {
  1.2311 +        return SECFailure;
  1.2312 +    }
  1.2313 +    return SECSuccess;
  1.2314 +}
  1.2315 +
  1.2316 +/* retrieve the issuer cache object for a given issuer subject */
  1.2317 +static SECStatus CRLCache_GetIssuerCache(CRLCache* cache,
  1.2318 +                                         const SECItem* subject,
  1.2319 +                                         CRLIssuerCache** returned)
  1.2320 +{
  1.2321 +    /* we need to look up the issuer in the hash table */
  1.2322 +    SECStatus rv = SECSuccess;
  1.2323 +    PORT_Assert(cache);
  1.2324 +    PORT_Assert(subject);
  1.2325 +    PORT_Assert(returned);
  1.2326 +    PORT_Assert(crlcache.issuers);
  1.2327 +    if (!cache || !subject || !returned || !crlcache.issuers)
  1.2328 +    {
  1.2329 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2330 +        rv = SECFailure;
  1.2331 +    }
  1.2332 +
  1.2333 +    if (SECSuccess == rv)
  1.2334 +    {
  1.2335 +        *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
  1.2336 +                                                         (void*) subject);
  1.2337 +    }
  1.2338 +
  1.2339 +    return rv;
  1.2340 +}
  1.2341 +
  1.2342 +/* retrieve the full CRL object that best matches the content of a DPCache */
  1.2343 +static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries)
  1.2344 +{
  1.2345 +    CachedCrl* acrl = NULL;
  1.2346 +
  1.2347 +    PORT_Assert(cache);
  1.2348 +    if (!cache)
  1.2349 +    {
  1.2350 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2351 +        return NULL;
  1.2352 +    }
  1.2353 +
  1.2354 +    if (0 == cache->ncrls)
  1.2355 +    {
  1.2356 +        /* empty cache*/
  1.2357 +        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  1.2358 +        return NULL;
  1.2359 +    }    
  1.2360 +
  1.2361 +    /* if we have a valid full CRL selected, return it */
  1.2362 +    if (cache->selected)
  1.2363 +    {
  1.2364 +        return SEC_DupCrl(cache->selected->crl);
  1.2365 +    }
  1.2366 +
  1.2367 +    /* otherwise, use latest valid DER CRL */
  1.2368 +    acrl = cache->crls[cache->ncrls-1];
  1.2369 +
  1.2370 +    if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
  1.2371 +    {
  1.2372 +        SECStatus rv = SECSuccess;
  1.2373 +        if (PR_TRUE == entries)
  1.2374 +        {
  1.2375 +            rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
  1.2376 +        }
  1.2377 +        if (SECSuccess == rv)
  1.2378 +        {
  1.2379 +            return SEC_DupCrl(acrl->crl);
  1.2380 +        }
  1.2381 +    }
  1.2382 +
  1.2383 +    PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  1.2384 +    return NULL;
  1.2385 +}
  1.2386 +
  1.2387 +/* get a particular DPCache object from an IssuerCache */
  1.2388 +static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp)
  1.2389 +{
  1.2390 +    CRLDPCache* dpp = NULL;
  1.2391 +    PORT_Assert(cache);
  1.2392 +    /* XCRL for now we only support the "default" DP, ie. the
  1.2393 +       full CRL. So we can return the global one without locking. In
  1.2394 +       the future we will have a lock */
  1.2395 +    PORT_Assert(NULL == dp);
  1.2396 +    if (!cache || dp)
  1.2397 +    {
  1.2398 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2399 +        return NULL;
  1.2400 +    }
  1.2401 +#ifdef XCRL
  1.2402 +    NSSRWLock_LockRead(cache->lock);
  1.2403 +#endif
  1.2404 +    dpp = cache->dpp;
  1.2405 +#ifdef XCRL
  1.2406 +    NSSRWLock_UnlockRead(cache->lock);
  1.2407 +#endif
  1.2408 +    return dpp;
  1.2409 +}
  1.2410 +
  1.2411 +/* get a DPCache object for the given issuer subject and dp
  1.2412 +   Automatically creates the cache object if it doesn't exist yet.
  1.2413 +   */
  1.2414 +SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject,
  1.2415 +                         const SECItem* dp, PRTime t, void* wincx,
  1.2416 +                         CRLDPCache** dpcache, PRBool* writeLocked)
  1.2417 +{
  1.2418 +    SECStatus rv = SECSuccess;
  1.2419 +    CRLIssuerCache* issuercache = NULL;
  1.2420 +#ifdef GLOBAL_RWLOCK
  1.2421 +    PRBool globalwrite = PR_FALSE;
  1.2422 +#endif
  1.2423 +    PORT_Assert(crlcache.lock);
  1.2424 +    if (!crlcache.lock)
  1.2425 +    {
  1.2426 +        /* CRL cache is not initialized */
  1.2427 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2428 +        return SECFailure;
  1.2429 +    }
  1.2430 +#ifdef GLOBAL_RWLOCK
  1.2431 +    NSSRWLock_LockRead(crlcache.lock);
  1.2432 +#else
  1.2433 +    PR_Lock(crlcache.lock);
  1.2434 +#endif
  1.2435 +    rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
  1.2436 +    if (SECSuccess != rv)
  1.2437 +    {
  1.2438 +#ifdef GLOBAL_RWLOCK
  1.2439 +        NSSRWLock_UnlockRead(crlcache.lock);
  1.2440 +#else
  1.2441 +        PR_Unlock(crlcache.lock);
  1.2442 +#endif
  1.2443 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2444 +        return SECFailure;
  1.2445 +    }
  1.2446 +    if (!issuercache)
  1.2447 +    {
  1.2448 +        /* there is no cache for this issuer yet. This means this is the
  1.2449 +           first time we look up a cert from that issuer, and we need to
  1.2450 +           create the cache. */
  1.2451 +        
  1.2452 +        rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
  1.2453 +        if (SECSuccess == rv && !issuercache)
  1.2454 +        {
  1.2455 +            PORT_Assert(issuercache);
  1.2456 +            rv = SECFailure;
  1.2457 +        }
  1.2458 +
  1.2459 +        if (SECSuccess == rv)
  1.2460 +        {
  1.2461 +            /* This is the first time we look up a cert of this issuer.
  1.2462 +               Create the DPCache for this DP . */
  1.2463 +            rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
  1.2464 +        }
  1.2465 +
  1.2466 +        if (SECSuccess == rv)
  1.2467 +        {
  1.2468 +            /* lock the DPCache for write to ensure the update happens in this
  1.2469 +               thread */
  1.2470 +            *writeLocked = PR_TRUE;
  1.2471 +#ifdef DPC_RWLOCK
  1.2472 +            NSSRWLock_LockWrite((*dpcache)->lock);
  1.2473 +#else
  1.2474 +            PR_Lock((*dpcache)->lock);
  1.2475 +#endif
  1.2476 +        }
  1.2477 +        
  1.2478 +        if (SECSuccess == rv)
  1.2479 +        {
  1.2480 +            /* now add the new issuer cache to the global hash table of
  1.2481 +               issuers */
  1.2482 +#ifdef GLOBAL_RWLOCK
  1.2483 +            CRLIssuerCache* existing = NULL;
  1.2484 +            NSSRWLock_UnlockRead(crlcache.lock);
  1.2485 +            /* when using a r/w lock for the global cache, check if the issuer
  1.2486 +               already exists before adding to the hash table */
  1.2487 +            NSSRWLock_LockWrite(crlcache.lock);
  1.2488 +            globalwrite = PR_TRUE;
  1.2489 +            rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
  1.2490 +            if (!existing)
  1.2491 +            {
  1.2492 +#endif
  1.2493 +                rv = CRLCache_AddIssuer(issuercache);
  1.2494 +                if (SECSuccess != rv)
  1.2495 +                {
  1.2496 +                    /* failure */
  1.2497 +                    rv = SECFailure;
  1.2498 +                }
  1.2499 +#ifdef GLOBAL_RWLOCK
  1.2500 +            }
  1.2501 +            else
  1.2502 +            {
  1.2503 +                /* somebody else updated before we did */
  1.2504 +                IssuerCache_Destroy(issuercache); /* destroy the new object */
  1.2505 +                issuercache = existing; /* use the existing one */
  1.2506 +                *dpcache = IssuerCache_GetDPCache(issuercache, dp);
  1.2507 +            }
  1.2508 +#endif
  1.2509 +        }
  1.2510 +
  1.2511 +        /* now unlock the global cache. We only want to lock the issuer hash
  1.2512 +           table addition. Holding it longer would hurt scalability */
  1.2513 +#ifdef GLOBAL_RWLOCK
  1.2514 +        if (PR_TRUE == globalwrite)
  1.2515 +        {
  1.2516 +            NSSRWLock_UnlockWrite(crlcache.lock);
  1.2517 +            globalwrite = PR_FALSE;
  1.2518 +        }
  1.2519 +        else
  1.2520 +        {
  1.2521 +            NSSRWLock_UnlockRead(crlcache.lock);
  1.2522 +        }
  1.2523 +#else
  1.2524 +        PR_Unlock(crlcache.lock);
  1.2525 +#endif
  1.2526 +
  1.2527 +        /* if there was a failure adding an issuer cache object, destroy it */
  1.2528 +        if (SECSuccess != rv && issuercache)
  1.2529 +        {
  1.2530 +            if (PR_TRUE == *writeLocked)
  1.2531 +            {
  1.2532 +#ifdef DPC_RWLOCK
  1.2533 +                NSSRWLock_UnlockWrite((*dpcache)->lock);
  1.2534 +#else
  1.2535 +                PR_Unlock((*dpcache)->lock);
  1.2536 +#endif
  1.2537 +            }
  1.2538 +            IssuerCache_Destroy(issuercache);
  1.2539 +            issuercache = NULL;
  1.2540 +        }
  1.2541 +
  1.2542 +        if (SECSuccess != rv)
  1.2543 +        {
  1.2544 +            return SECFailure;
  1.2545 +        }
  1.2546 +    } else
  1.2547 +    {
  1.2548 +#ifdef GLOBAL_RWLOCK
  1.2549 +        NSSRWLock_UnlockRead(crlcache.lock);
  1.2550 +#else
  1.2551 +        PR_Unlock(crlcache.lock);
  1.2552 +#endif
  1.2553 +        *dpcache = IssuerCache_GetDPCache(issuercache, dp);
  1.2554 +    }
  1.2555 +    /* we now have a DPCache that we can use for lookups */
  1.2556 +    /* lock it for read, unless we already locked for write */
  1.2557 +    if (PR_FALSE == *writeLocked)
  1.2558 +    {
  1.2559 +#ifdef DPC_RWLOCK
  1.2560 +        NSSRWLock_LockRead((*dpcache)->lock);
  1.2561 +#else
  1.2562 +        PR_Lock((*dpcache)->lock);
  1.2563 +#endif
  1.2564 +    }
  1.2565 +    
  1.2566 +    if (SECSuccess == rv)
  1.2567 +    {
  1.2568 +        /* currently there is always one and only one DPCache per issuer */
  1.2569 +        PORT_Assert(*dpcache);
  1.2570 +        if (*dpcache)
  1.2571 +        {
  1.2572 +            /* make sure the DP cache is up to date before using it */
  1.2573 +            rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
  1.2574 +                                     t, wincx);
  1.2575 +        }
  1.2576 +        else
  1.2577 +        {
  1.2578 +            rv = SECFailure;
  1.2579 +        }
  1.2580 +    }
  1.2581 +    return rv;
  1.2582 +}
  1.2583 +
  1.2584 +/* unlock access to the DPCache */
  1.2585 +void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked)
  1.2586 +{
  1.2587 +    if (!dpcache)
  1.2588 +    {
  1.2589 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2590 +        return;
  1.2591 +    }
  1.2592 +#ifdef DPC_RWLOCK
  1.2593 +    if (PR_TRUE == writeLocked)
  1.2594 +    {
  1.2595 +        NSSRWLock_UnlockWrite(dpcache->lock);
  1.2596 +    }
  1.2597 +    else
  1.2598 +    {
  1.2599 +        NSSRWLock_UnlockRead(dpcache->lock);
  1.2600 +    }
  1.2601 +#else
  1.2602 +    PR_Unlock(dpcache->lock);
  1.2603 +#endif
  1.2604 +}
  1.2605 +
  1.2606 +SECStatus
  1.2607 +cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer,
  1.2608 +                               const SECItem* dp, PRTime t, void *wincx,
  1.2609 +                               CERTRevocationStatus *revStatus,
  1.2610 +                               CERTCRLEntryReasonCode *revReason)
  1.2611 +{
  1.2612 +    PRBool lockedwrite = PR_FALSE;
  1.2613 +    SECStatus rv = SECSuccess;
  1.2614 +    CRLDPCache* dpcache = NULL;
  1.2615 +    CERTRevocationStatus status = certRevocationStatusRevoked;
  1.2616 +    CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified;
  1.2617 +    CERTCrlEntry* entry = NULL;
  1.2618 +    dpcacheStatus ds;
  1.2619 +
  1.2620 +    if (!cert || !issuer)
  1.2621 +    {
  1.2622 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2623 +        return SECFailure;
  1.2624 +    }
  1.2625 +
  1.2626 +    if (revStatus)
  1.2627 +    {
  1.2628 +        *revStatus = status;
  1.2629 +    }
  1.2630 +    if (revReason)
  1.2631 +    {
  1.2632 +        *revReason = reason;
  1.2633 +    }
  1.2634 +
  1.2635 +    if (t && secCertTimeValid != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
  1.2636 +    {
  1.2637 +        /* we won't be able to check the CRL's signature if the issuer cert
  1.2638 +           is expired as of the time we are verifying. This may cause a valid
  1.2639 +           CRL to be cached as bad. short-circuit to avoid this case. */
  1.2640 +        PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
  1.2641 +        return SECFailure;
  1.2642 +    }
  1.2643 +
  1.2644 +    rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
  1.2645 +                        &lockedwrite);
  1.2646 +    PORT_Assert(SECSuccess == rv);
  1.2647 +    if (SECSuccess != rv)
  1.2648 +    {
  1.2649 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2650 +        return SECFailure;
  1.2651 +    }
  1.2652 +    /* now look up the certificate SN in the DP cache's CRL */
  1.2653 +    ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
  1.2654 +    switch (ds)
  1.2655 +    {
  1.2656 +        case dpcacheFoundEntry:
  1.2657 +            PORT_Assert(entry);
  1.2658 +            /* check the time if we have one */
  1.2659 +            if (entry->revocationDate.data && entry->revocationDate.len)
  1.2660 +            {
  1.2661 +                PRTime revocationDate = 0;
  1.2662 +                if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
  1.2663 +                                               &entry->revocationDate))
  1.2664 +                {
  1.2665 +                    /* we got a good revocation date, only consider the
  1.2666 +                       certificate revoked if the time we are inquiring about
  1.2667 +                       is past the revocation date */
  1.2668 +                    if (t>=revocationDate)
  1.2669 +                    {
  1.2670 +                        rv = SECFailure;
  1.2671 +                    }
  1.2672 +                    else
  1.2673 +                    {
  1.2674 +                        status = certRevocationStatusValid;
  1.2675 +                    }
  1.2676 +                }
  1.2677 +                else
  1.2678 +                {
  1.2679 +                    /* invalid revocation date, consider the certificate
  1.2680 +                       permanently revoked */
  1.2681 +                    rv = SECFailure;
  1.2682 +                }
  1.2683 +            }
  1.2684 +            else
  1.2685 +            {
  1.2686 +                /* no revocation date, certificate is permanently revoked */
  1.2687 +                rv = SECFailure;
  1.2688 +            }
  1.2689 +            if (SECFailure == rv)
  1.2690 +            {
  1.2691 +                SECStatus rv2 = CERT_FindCRLEntryReasonExten(entry, &reason);
  1.2692 +                PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
  1.2693 +            }
  1.2694 +            break;
  1.2695 +
  1.2696 +        case dpcacheEmpty:
  1.2697 +            /* useful for NIST policy */
  1.2698 +            status = certRevocationStatusUnknown;
  1.2699 +            break;
  1.2700 +
  1.2701 +        case dpcacheNoEntry:
  1.2702 +            status = certRevocationStatusValid;
  1.2703 +            break;
  1.2704 +
  1.2705 +        case dpcacheInvalidCacheError:
  1.2706 +            /* treat it as unknown and let the caller decide based on
  1.2707 +               the policy */
  1.2708 +            status = certRevocationStatusUnknown;
  1.2709 +            break;
  1.2710 +
  1.2711 +        default:
  1.2712 +            /* leave status as revoked */
  1.2713 +            break;
  1.2714 +    }
  1.2715 +
  1.2716 +    ReleaseDPCache(dpcache, lockedwrite);
  1.2717 +    if (revStatus)
  1.2718 +    {
  1.2719 +        *revStatus = status;
  1.2720 +    }
  1.2721 +    if (revReason)
  1.2722 +    {
  1.2723 +        *revReason = reason;
  1.2724 +    }
  1.2725 +    return rv;
  1.2726 +}
  1.2727 +
  1.2728 +/* check CRL revocation status of given certificate and issuer */
  1.2729 +SECStatus
  1.2730 +CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer,
  1.2731 +              const SECItem* dp, PRTime t, void* wincx)
  1.2732 +{
  1.2733 +    return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx,
  1.2734 +                                          NULL, NULL);
  1.2735 +}
  1.2736 +
  1.2737 +/* retrieve full CRL object that best matches the cache status */
  1.2738 +CERTSignedCrl *
  1.2739 +SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
  1.2740 +{
  1.2741 +    CERTSignedCrl* acrl = NULL;
  1.2742 +    CRLDPCache* dpcache = NULL;
  1.2743 +    SECStatus rv = SECSuccess;
  1.2744 +    PRBool writeLocked = PR_FALSE;
  1.2745 +
  1.2746 +    if (!crlKey)
  1.2747 +    {
  1.2748 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2749 +        return NULL;
  1.2750 +    }
  1.2751 +
  1.2752 +    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
  1.2753 +    if (SECSuccess == rv)
  1.2754 +    {
  1.2755 +        acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
  1.2756 +        SEC_FindCrlByName always returned fully decoded CRLs in the past */
  1.2757 +        ReleaseDPCache(dpcache, writeLocked);
  1.2758 +    }
  1.2759 +    return acrl;
  1.2760 +}
  1.2761 +
  1.2762 +/* invalidate the CRL cache for a given issuer, which forces a refetch of
  1.2763 +   CRL objects from PKCS#11 tokens */
  1.2764 +void CERT_CRLCacheRefreshIssuer(CERTCertDBHandle* dbhandle, SECItem* crlKey)
  1.2765 +{
  1.2766 +    CRLDPCache* cache = NULL;
  1.2767 +    SECStatus rv = SECSuccess;
  1.2768 +    PRBool writeLocked = PR_FALSE;
  1.2769 +    PRBool readlocked;
  1.2770 +
  1.2771 +    (void) dbhandle; /* silence compiler warnings */
  1.2772 +
  1.2773 +    /* XCRL we will need to refresh all the DPs of the issuer in the future,
  1.2774 +            not just the default one */
  1.2775 +    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
  1.2776 +    if (SECSuccess != rv)
  1.2777 +    {
  1.2778 +        return;
  1.2779 +    }
  1.2780 +    /* we need to invalidate the DPCache here */
  1.2781 +    readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  1.2782 +    DPCache_LockWrite();
  1.2783 +    cache->refresh = PR_TRUE;
  1.2784 +    DPCache_UnlockWrite();
  1.2785 +    ReleaseDPCache(cache, writeLocked);
  1.2786 +    return;
  1.2787 +}
  1.2788 +
  1.2789 +/* add the specified RAM CRL object to the cache */
  1.2790 +SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl)
  1.2791 +{
  1.2792 +    CRLDPCache* cache = NULL;
  1.2793 +    SECStatus rv = SECSuccess;
  1.2794 +    PRBool writeLocked = PR_FALSE;
  1.2795 +    PRBool readlocked;
  1.2796 +    CachedCrl* returned = NULL;
  1.2797 +    PRBool added = PR_FALSE;
  1.2798 +    CERTSignedCrl* newcrl = NULL;
  1.2799 +    int realerror = 0;
  1.2800 +    
  1.2801 +    if (!dbhandle || !newdercrl)
  1.2802 +    {
  1.2803 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2804 +        return SECFailure;
  1.2805 +    }
  1.2806 +
  1.2807 +    /* first decode the DER CRL to make sure it's OK */
  1.2808 +    newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
  1.2809 +                                        CRL_DECODE_DONT_COPY_DER |
  1.2810 +                                        CRL_DECODE_SKIP_ENTRIES);
  1.2811 +
  1.2812 +    if (!newcrl)
  1.2813 +    {
  1.2814 +        return SECFailure;
  1.2815 +    }
  1.2816 +
  1.2817 +    /* XXX check if it has IDP extension. If so, do not proceed and set error */
  1.2818 +
  1.2819 +    rv = AcquireDPCache(NULL,
  1.2820 +                        &newcrl->crl.derName,
  1.2821 +                        NULL, 0, NULL, &cache, &writeLocked);
  1.2822 +    if (SECSuccess == rv)
  1.2823 +    {
  1.2824 +        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  1.2825 +    
  1.2826 +        rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
  1.2827 +        if (SECSuccess == rv && returned)
  1.2828 +        {
  1.2829 +            DPCache_LockWrite();
  1.2830 +            rv = DPCache_AddCRL(cache, returned, &added);
  1.2831 +            if (PR_TRUE != added)
  1.2832 +            {
  1.2833 +                realerror = PORT_GetError();
  1.2834 +                CachedCrl_Destroy(returned);
  1.2835 +                returned = NULL;
  1.2836 +            }
  1.2837 +            DPCache_UnlockWrite();
  1.2838 +        }
  1.2839 +    
  1.2840 +        ReleaseDPCache(cache, writeLocked);
  1.2841 +    
  1.2842 +        if (!added)
  1.2843 +        {
  1.2844 +            rv = SECFailure;
  1.2845 +        }
  1.2846 +    }
  1.2847 +    SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
  1.2848 +        and the refcount got bumped, or not, and thus we need to free its
  1.2849 +        RAM */
  1.2850 +    if (realerror)
  1.2851 +    {
  1.2852 +        PORT_SetError(realerror);
  1.2853 +    }
  1.2854 +    return rv;
  1.2855 +}
  1.2856 +
  1.2857 +/* remove the specified RAM CRL object from the cache */
  1.2858 +SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl)
  1.2859 +{
  1.2860 +    CRLDPCache* cache = NULL;
  1.2861 +    SECStatus rv = SECSuccess;
  1.2862 +    PRBool writeLocked = PR_FALSE;
  1.2863 +    PRBool readlocked;
  1.2864 +    PRBool removed = PR_FALSE;
  1.2865 +    PRUint32 i;
  1.2866 +    CERTSignedCrl* oldcrl = NULL;
  1.2867 +    
  1.2868 +    if (!dbhandle || !olddercrl)
  1.2869 +    {
  1.2870 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2871 +        return SECFailure;
  1.2872 +    }
  1.2873 +
  1.2874 +    /* first decode the DER CRL to make sure it's OK */
  1.2875 +    oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
  1.2876 +                                        CRL_DECODE_DONT_COPY_DER |
  1.2877 +                                        CRL_DECODE_SKIP_ENTRIES);
  1.2878 +
  1.2879 +    if (!oldcrl)
  1.2880 +    {
  1.2881 +        /* if this DER CRL can't decode, it can't be in the cache */
  1.2882 +        return SECFailure;
  1.2883 +    }
  1.2884 +
  1.2885 +    rv = AcquireDPCache(NULL,
  1.2886 +                        &oldcrl->crl.derName,
  1.2887 +                        NULL, 0, NULL, &cache, &writeLocked);
  1.2888 +    if (SECSuccess == rv)
  1.2889 +    {
  1.2890 +        CachedCrl* returned = NULL;
  1.2891 +
  1.2892 +        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
  1.2893 +    
  1.2894 +        rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
  1.2895 +        if (SECSuccess == rv && returned)
  1.2896 +        {
  1.2897 +            DPCache_LockWrite();
  1.2898 +            for (i=0;i<cache->ncrls;i++)
  1.2899 +            {
  1.2900 +                PRBool dupe = PR_FALSE, updated = PR_FALSE;
  1.2901 +                rv = CachedCrl_Compare(returned, cache->crls[i],
  1.2902 +                                                      &dupe, &updated);
  1.2903 +                if (SECSuccess != rv)
  1.2904 +                {
  1.2905 +                    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.2906 +                    break;
  1.2907 +                }
  1.2908 +                if (PR_TRUE == dupe)
  1.2909 +                {
  1.2910 +                    rv = DPCache_RemoveCRL(cache, i); /* got a match */
  1.2911 +                    if (SECSuccess == rv) {
  1.2912 +                        cache->mustchoose = PR_TRUE;
  1.2913 +                        removed = PR_TRUE;
  1.2914 +                    }
  1.2915 +                    break;
  1.2916 +                }
  1.2917 +            }
  1.2918 +            
  1.2919 +            DPCache_UnlockWrite();
  1.2920 +
  1.2921 +            if (SECSuccess != CachedCrl_Destroy(returned) ) {
  1.2922 +                rv = SECFailure;
  1.2923 +            }
  1.2924 +        }
  1.2925 +
  1.2926 +        ReleaseDPCache(cache, writeLocked);
  1.2927 +    }
  1.2928 +    if (SECSuccess != SEC_DestroyCrl(oldcrl) ) { 
  1.2929 +        /* need to do this because object is refcounted */
  1.2930 +        rv = SECFailure;
  1.2931 +    }
  1.2932 +    if (SECSuccess == rv && PR_TRUE != removed)
  1.2933 +    {
  1.2934 +        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
  1.2935 +    }
  1.2936 +    return rv;
  1.2937 +}
  1.2938 +
  1.2939 +SECStatus cert_AcquireNamedCRLCache(NamedCRLCache** returned)
  1.2940 +{
  1.2941 +    PORT_Assert(returned);
  1.2942 +    if (!namedCRLCache.lock)
  1.2943 +    {
  1.2944 +        PORT_Assert(0);
  1.2945 +        return SECFailure;
  1.2946 +    }
  1.2947 +    PR_Lock(namedCRLCache.lock);
  1.2948 +    *returned = &namedCRLCache;
  1.2949 +    return SECSuccess;
  1.2950 +}
  1.2951 +
  1.2952 +/* This must be called only while cache is acquired, and the entry is only
  1.2953 + * valid until cache is released.
  1.2954 + */
  1.2955 +SECStatus cert_FindCRLByGeneralName(NamedCRLCache* ncc,
  1.2956 +                                    const SECItem* canonicalizedName,
  1.2957 +                                    NamedCRLCacheEntry** retEntry)
  1.2958 +{
  1.2959 +    if (!ncc || !canonicalizedName || !retEntry)
  1.2960 +    {
  1.2961 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.2962 +        return SECFailure;
  1.2963 +    }
  1.2964 +    *retEntry = (NamedCRLCacheEntry*) PL_HashTableLookup(namedCRLCache.entries,
  1.2965 +                                         (void*) canonicalizedName);
  1.2966 +    return SECSuccess;
  1.2967 +}
  1.2968 +
  1.2969 +SECStatus cert_ReleaseNamedCRLCache(NamedCRLCache* ncc)
  1.2970 +{
  1.2971 +    if (!ncc)
  1.2972 +    {
  1.2973 +        return SECFailure;
  1.2974 +    }
  1.2975 +    if (!ncc->lock)
  1.2976 +    {
  1.2977 +        PORT_Assert(0);
  1.2978 +        return SECFailure;
  1.2979 +    }
  1.2980 +    PR_Unlock(namedCRLCache.lock);
  1.2981 +    return SECSuccess;
  1.2982 +}
  1.2983 +
  1.2984 +/* creates new named cache entry from CRL, and tries to add it to CRL cache */
  1.2985 +static SECStatus addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl,
  1.2986 +                                    const SECItem* canonicalizedName,
  1.2987 +                                    NamedCRLCacheEntry** newEntry)
  1.2988 +{
  1.2989 +    SECStatus rv = SECSuccess;
  1.2990 +    NamedCRLCacheEntry* entry = NULL;
  1.2991 +
  1.2992 +    /* create new named entry */
  1.2993 +    if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry)
  1.2994 +    {
  1.2995 +        /* no need to keep unused CRL around */
  1.2996 +        SECITEM_ZfreeItem(crl, PR_TRUE);
  1.2997 +        return SECFailure;
  1.2998 +    }
  1.2999 +    entry = *newEntry;
  1.3000 +    entry->crl = crl; /* named CRL cache owns DER */
  1.3001 +    entry->lastAttemptTime = PR_Now();
  1.3002 +    entry->canonicalizedName = SECITEM_DupItem(canonicalizedName);
  1.3003 +    if (!entry->canonicalizedName)
  1.3004 +    {
  1.3005 +        rv = NamedCRLCacheEntry_Destroy(entry); /* destroys CRL too */
  1.3006 +        PORT_Assert(SECSuccess == rv);
  1.3007 +        return SECFailure;
  1.3008 +    }
  1.3009 +    /* now, attempt to insert CRL into CRL cache */
  1.3010 +    if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl))
  1.3011 +    {
  1.3012 +        entry->inCRLCache = PR_TRUE;
  1.3013 +        entry->successfulInsertionTime = entry->lastAttemptTime;
  1.3014 +    }
  1.3015 +    else
  1.3016 +    {
  1.3017 +        switch (PR_GetError())
  1.3018 +        {
  1.3019 +            case SEC_ERROR_CRL_ALREADY_EXISTS:
  1.3020 +                entry->dupe = PR_TRUE;
  1.3021 +                break;
  1.3022 +
  1.3023 +            case SEC_ERROR_BAD_DER:
  1.3024 +                entry->badDER = PR_TRUE;
  1.3025 +                break;
  1.3026 +
  1.3027 +            /* all other reasons */
  1.3028 +            default:
  1.3029 +                entry->unsupported = PR_TRUE;
  1.3030 +                break;
  1.3031 +        }
  1.3032 +        rv = SECFailure;
  1.3033 +        /* no need to keep unused CRL around */
  1.3034 +        SECITEM_ZfreeItem(entry->crl, PR_TRUE);
  1.3035 +        entry->crl = NULL;
  1.3036 +    }
  1.3037 +    return rv;
  1.3038 +}
  1.3039 +
  1.3040 +/* take ownership of CRL, and insert it into the named CRL cache
  1.3041 + * and indexed CRL cache
  1.3042 + */
  1.3043 +SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl,
  1.3044 +                                     const SECItem* canonicalizedName)
  1.3045 +{
  1.3046 +    NamedCRLCacheEntry* oldEntry, * newEntry = NULL;
  1.3047 +    NamedCRLCache* ncc = NULL;
  1.3048 +    SECStatus rv = SECSuccess, rv2;
  1.3049 +
  1.3050 +    PORT_Assert(namedCRLCache.lock);
  1.3051 +    PORT_Assert(namedCRLCache.entries);
  1.3052 +
  1.3053 +    if (!crl || !canonicalizedName)
  1.3054 +    {
  1.3055 +        PORT_Assert(0);
  1.3056 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
  1.3057 +        return SECFailure;
  1.3058 +    }
  1.3059 +
  1.3060 +    rv = cert_AcquireNamedCRLCache(&ncc);
  1.3061 +    PORT_Assert(SECSuccess == rv);
  1.3062 +    if (SECSuccess != rv)
  1.3063 +    {
  1.3064 +        SECITEM_ZfreeItem(crl, PR_TRUE);
  1.3065 +        return SECFailure;
  1.3066 +    }
  1.3067 +    rv = cert_FindCRLByGeneralName(ncc, canonicalizedName, &oldEntry);
  1.3068 +    PORT_Assert(SECSuccess == rv);
  1.3069 +    if (SECSuccess != rv)
  1.3070 +    {
  1.3071 +        rv = cert_ReleaseNamedCRLCache(ncc);
  1.3072 +        SECITEM_ZfreeItem(crl, PR_TRUE);
  1.3073 +        return SECFailure;
  1.3074 +    }
  1.3075 +    if (SECSuccess == addCRLToCache(dbhandle, crl, canonicalizedName,
  1.3076 +                                    &newEntry) )
  1.3077 +    {
  1.3078 +        if (!oldEntry)
  1.3079 +        {
  1.3080 +            /* add new good entry to the hash table */
  1.3081 +            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  1.3082 +                                        (void*) newEntry->canonicalizedName,
  1.3083 +                                        (void*) newEntry))
  1.3084 +            {
  1.3085 +                PORT_Assert(0);
  1.3086 +                rv2 = NamedCRLCacheEntry_Destroy(newEntry);
  1.3087 +                PORT_Assert(SECSuccess == rv2);
  1.3088 +                rv = SECFailure;
  1.3089 +            }
  1.3090 +        }
  1.3091 +        else
  1.3092 +        {
  1.3093 +            PRBool removed;
  1.3094 +            /* remove the old CRL from the cache if needed */
  1.3095 +            if (oldEntry->inCRLCache)
  1.3096 +            {
  1.3097 +                rv = CERT_UncacheCRL(dbhandle, oldEntry->crl);
  1.3098 +                PORT_Assert(SECSuccess == rv);
  1.3099 +            }
  1.3100 +            removed = PL_HashTableRemove(namedCRLCache.entries,
  1.3101 +                                      (void*) oldEntry->canonicalizedName);
  1.3102 +            PORT_Assert(removed);
  1.3103 +            if (!removed)
  1.3104 +            {
  1.3105 +                rv = SECFailure;
  1.3106 +		/* leak old entry since we couldn't remove it from the hash table */
  1.3107 +            }
  1.3108 +            else
  1.3109 +            {
  1.3110 +                rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
  1.3111 +                PORT_Assert(SECSuccess == rv2);
  1.3112 +            }
  1.3113 +            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  1.3114 +                                      (void*) newEntry->canonicalizedName,
  1.3115 +                                      (void*) newEntry))
  1.3116 +            {
  1.3117 +                PORT_Assert(0);
  1.3118 +                rv = SECFailure;
  1.3119 +            }
  1.3120 +        }
  1.3121 +    } else
  1.3122 +    {
  1.3123 +        /* error adding new CRL to cache */
  1.3124 +        if (!oldEntry)
  1.3125 +        {
  1.3126 +            /* no old cache entry, use the new one even though it's bad */
  1.3127 +            if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  1.3128 +                                        (void*) newEntry->canonicalizedName,
  1.3129 +                                        (void*) newEntry))
  1.3130 +            {
  1.3131 +                PORT_Assert(0);
  1.3132 +                rv = SECFailure;
  1.3133 +            }
  1.3134 +        }
  1.3135 +        else
  1.3136 +        {
  1.3137 +            if (oldEntry->inCRLCache)
  1.3138 +            {
  1.3139 +                /* previous cache entry was good, keep it and update time */
  1.3140 +                oldEntry-> lastAttemptTime = newEntry->lastAttemptTime;
  1.3141 +                /* throw away new bad entry */
  1.3142 +                rv = NamedCRLCacheEntry_Destroy(newEntry);
  1.3143 +                PORT_Assert(SECSuccess == rv);
  1.3144 +            }
  1.3145 +            else
  1.3146 +            {
  1.3147 +                /* previous cache entry was bad, just replace it */
  1.3148 +                PRBool removed = PL_HashTableRemove(namedCRLCache.entries,
  1.3149 +                                          (void*) oldEntry->canonicalizedName);
  1.3150 +                PORT_Assert(removed);
  1.3151 +                if (!removed)
  1.3152 +                {
  1.3153 +		    /* leak old entry since we couldn't remove it from the hash table */
  1.3154 +                    rv = SECFailure;
  1.3155 +                }
  1.3156 +                else
  1.3157 +                {
  1.3158 +                    rv2 = NamedCRLCacheEntry_Destroy(oldEntry);
  1.3159 +                    PORT_Assert(SECSuccess == rv2);
  1.3160 +                }
  1.3161 +                if (NULL == PL_HashTableAdd(namedCRLCache.entries,
  1.3162 +                                          (void*) newEntry->canonicalizedName,
  1.3163 +                                          (void*) newEntry))
  1.3164 +                {
  1.3165 +                    PORT_Assert(0);
  1.3166 +                    rv = SECFailure;
  1.3167 +                }
  1.3168 +            }
  1.3169 +        }
  1.3170 +    }
  1.3171 +    rv2 = cert_ReleaseNamedCRLCache(ncc);
  1.3172 +    PORT_Assert(SECSuccess == rv2);
  1.3173 +
  1.3174 +    return rv;
  1.3175 +}
  1.3176 +
  1.3177 +static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl,
  1.3178 +                                  CRLOrigin origin)
  1.3179 +{
  1.3180 +    CachedCrl* newcrl = NULL;
  1.3181 +    if (!returned)
  1.3182 +    {
  1.3183 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.3184 +        return SECFailure;
  1.3185 +    }
  1.3186 +    newcrl = PORT_ZAlloc(sizeof(CachedCrl));
  1.3187 +    if (!newcrl)
  1.3188 +    {
  1.3189 +        return SECFailure;
  1.3190 +    }
  1.3191 +    newcrl->crl = SEC_DupCrl(crl);
  1.3192 +    newcrl->origin = origin;
  1.3193 +    *returned = newcrl;
  1.3194 +    return SECSuccess;
  1.3195 +}
  1.3196 +
  1.3197 +/* empty the cache content */
  1.3198 +static SECStatus CachedCrl_Depopulate(CachedCrl* crl)
  1.3199 +{
  1.3200 +    if (!crl)
  1.3201 +    {
  1.3202 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.3203 +        return SECFailure;
  1.3204 +    }
  1.3205 +     /* destroy the hash table */
  1.3206 +    if (crl->entries)
  1.3207 +    {
  1.3208 +        PL_HashTableDestroy(crl->entries);
  1.3209 +        crl->entries = NULL;
  1.3210 +    }
  1.3211 +
  1.3212 +    /* free the pre buffer */
  1.3213 +    if (crl->prebuffer)
  1.3214 +    {
  1.3215 +        PreAllocator_Destroy(crl->prebuffer);
  1.3216 +        crl->prebuffer = NULL;
  1.3217 +    }
  1.3218 +    return SECSuccess;
  1.3219 +}
  1.3220 +
  1.3221 +static SECStatus CachedCrl_Destroy(CachedCrl* crl)
  1.3222 +{
  1.3223 +    if (!crl)
  1.3224 +    {
  1.3225 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.3226 +        return SECFailure;
  1.3227 +    }
  1.3228 +    CachedCrl_Depopulate(crl);
  1.3229 +    SEC_DestroyCrl(crl->crl);
  1.3230 +    PORT_Free(crl);
  1.3231 +    return SECSuccess;
  1.3232 +}
  1.3233 +
  1.3234 +/* create hash table of CRL entries */
  1.3235 +static SECStatus CachedCrl_Populate(CachedCrl* crlobject)
  1.3236 +{
  1.3237 +    SECStatus rv = SECFailure;
  1.3238 +    CERTCrlEntry** crlEntry = NULL;
  1.3239 +    PRUint32 numEntries = 0;
  1.3240 +
  1.3241 +    if (!crlobject)
  1.3242 +    {
  1.3243 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.3244 +        return SECFailure;
  1.3245 +    }
  1.3246 +    /* complete the entry decoding . XXX thread-safety of CRL object */
  1.3247 +    rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
  1.3248 +    if (SECSuccess != rv)
  1.3249 +    {
  1.3250 +        crlobject->unbuildable = PR_TRUE; /* don't try to build this again */
  1.3251 +        return SECFailure;
  1.3252 +    }
  1.3253 +
  1.3254 +    if (crlobject->entries && crlobject->prebuffer)
  1.3255 +    {
  1.3256 +        /* cache is already built */
  1.3257 +        return SECSuccess;
  1.3258 +    }
  1.3259 +
  1.3260 +    /* build the hash table from the full CRL */    
  1.3261 +    /* count CRL entries so we can pre-allocate space for hash table entries */
  1.3262 +    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
  1.3263 +         crlEntry++)
  1.3264 +    {
  1.3265 +        numEntries++;
  1.3266 +    }
  1.3267 +    crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
  1.3268 +    PORT_Assert(crlobject->prebuffer);
  1.3269 +    if (!crlobject->prebuffer)
  1.3270 +    {
  1.3271 +        return SECFailure;
  1.3272 +    }
  1.3273 +    /* create a new hash table */
  1.3274 +    crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
  1.3275 +                         PL_CompareValues, &preAllocOps, crlobject->prebuffer);
  1.3276 +    PORT_Assert(crlobject->entries);
  1.3277 +    if (!crlobject->entries)
  1.3278 +    {
  1.3279 +        return SECFailure;
  1.3280 +    }
  1.3281 +    /* add all serial numbers to the hash table */
  1.3282 +    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
  1.3283 +         crlEntry++)
  1.3284 +    {
  1.3285 +        PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
  1.3286 +                        *crlEntry);
  1.3287 +    }
  1.3288 +
  1.3289 +    return SECSuccess;
  1.3290 +}
  1.3291 +
  1.3292 +/* returns true if there are CRLs from PKCS#11 slots */
  1.3293 +static PRBool DPCache_HasTokenCRLs(CRLDPCache* cache)
  1.3294 +{
  1.3295 +    PRBool answer = PR_FALSE;
  1.3296 +    PRUint32 i;
  1.3297 +    for (i=0;i<cache->ncrls;i++)
  1.3298 +    {
  1.3299 +        if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
  1.3300 +        {
  1.3301 +            answer = PR_TRUE;
  1.3302 +            break;
  1.3303 +        }
  1.3304 +    }
  1.3305 +    return answer;
  1.3306 +}
  1.3307 +
  1.3308 +/* are these CRLs the same, as far as the cache is concerned ? */
  1.3309 +/* are these CRLs the same token object but with different DER ?
  1.3310 +   This can happen if the DER CRL got updated in the token, but the PKCS#11
  1.3311 +   object ID did not change. NSS softoken has the unfortunate property to
  1.3312 +   never change the object ID for CRL objects. */
  1.3313 +static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe,
  1.3314 +                                PRBool* isUpdated)
  1.3315 +{
  1.3316 +    PORT_Assert(a);
  1.3317 +    PORT_Assert(b);
  1.3318 +    PORT_Assert(isDupe);
  1.3319 +    PORT_Assert(isUpdated);
  1.3320 +    if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
  1.3321 +    {
  1.3322 +        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
  1.3323 +        return SECFailure;
  1.3324 +    }
  1.3325 +
  1.3326 +    *isDupe = *isUpdated = PR_FALSE;
  1.3327 +
  1.3328 +    if (a == b)
  1.3329 +    {
  1.3330 +        /* dupe */
  1.3331 +        *isDupe = PR_TRUE;
  1.3332 +        *isUpdated = PR_FALSE;
  1.3333 +        return SECSuccess;
  1.3334 +    }
  1.3335 +    if (b->origin != a->origin)
  1.3336 +    {
  1.3337 +        /* CRLs of different origins are not considered dupes,
  1.3338 +           and can't be updated either */
  1.3339 +        return SECSuccess;
  1.3340 +    }
  1.3341 +    if (CRL_OriginToken == b->origin)
  1.3342 +    {
  1.3343 +        /* for token CRLs, slot and PKCS#11 object handle must match for CRL
  1.3344 +           to truly be a dupe */
  1.3345 +        if ( (b->crl->slot == a->crl->slot) &&
  1.3346 +             (b->crl->pkcs11ID == a->crl->pkcs11ID) )
  1.3347 +        {
  1.3348 +            /* ASN.1 DER needs to match for dupe check */
  1.3349 +            /* could optimize by just checking a few fields like thisUpdate */
  1.3350 +            if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
  1.3351 +                                                 a->crl->derCrl) )
  1.3352 +            {
  1.3353 +                *isDupe = PR_TRUE;
  1.3354 +            }
  1.3355 +            else
  1.3356 +            {
  1.3357 +                *isUpdated = PR_TRUE;
  1.3358 +            }
  1.3359 +        }
  1.3360 +        return SECSuccess;
  1.3361 +    }
  1.3362 +    if (CRL_OriginExplicit == b->origin)
  1.3363 +    {
  1.3364 +        /* We need to make sure this is the same object that the user provided
  1.3365 +           to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
  1.3366 +           just do a pointer comparison here.
  1.3367 +        */
  1.3368 +        if (b->crl->derCrl == a->crl->derCrl)
  1.3369 +        {
  1.3370 +            *isDupe = PR_TRUE;
  1.3371 +        }
  1.3372 +    }
  1.3373 +    return SECSuccess;
  1.3374 +}

mercurial