Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
crl.c File Reference
#include "cert.h"
#include "certi.h"
#include "secder.h"
#include "secasn1.h"
#include "secoid.h"
#include "certdb.h"
#include "certxutl.h"
#include "prtime.h"
#include "secerr.h"
#include "pk11func.h"
#include "dev.h"
#include "dev3hack.h"
#include "nssbase.h"
#include "nssrwlk.h"
#include "pk11priv.h"

Go to the source code of this file.

Defines

#define GetOpaqueCRLFields(x)   ((OpaqueCRLFields*)x->opaque)
#define DPCache_LockWrite()
#define DPCache_UnlockWrite()

Functions

int cert_get_crl_version (CERTCrl *crl)
SECStatus cert_check_crl_entries (CERTCrl *crl)
SECStatus cert_check_crl_version (CERTCrl *crl)
SECStatus CERT_KeyFromDERCrl (PRArenaPool *arena, SECItem *derCrl, SECItem *key)
SECStatus CERT_CompleteCRLDecodeEntries (CERTSignedCrl *crl)
CERTSignedCrl * CERT_DecodeDERCrlWithFlags (PRArenaPool *narena, SECItem *derSignedCrl, int type, PRInt32 options)
CERTSignedCrl * CERT_DecodeDERCrl (PRArenaPool *narena, SECItem *derSignedCrl, int type)
static SECStatus SEC_FindCrlByKeyOnSlot (PK11SlotInfo *slot, SECItem *crlKey, int type, CERTSignedCrl **decoded, PRInt32 decodeoptions)
CERTSignedCrl * crl_storeCRL (PK11SlotInfo *slot, char *url, CERTSignedCrl *newCrl, SECItem *derCrl, int type)
CERTSignedCrl * SEC_NewCrl (CERTCertDBHandle *handle, char *url, SECItem *derCrl, int type)
CERTSignedCrl * SEC_FindCrlByDERCert (CERTCertDBHandle *handle, SECItem *derCrl, int type)
CERTSignedCrl * SEC_DupCrl (CERTSignedCrl *acrl)
SECStatus SEC_DestroyCrl (CERTSignedCrl *crl)
SECStatus SEC_LookupCrls (CERTCertDBHandle *handle, CERTCrlHeadNode **nodes, int type)
static SECStatus CachedCrl_Create (CachedCrl **returned, CERTSignedCrl *crl, CRLOrigin origin)
static SECStatus CachedCrl_Destroy (CachedCrl *crl)
static SECStatus CachedCrl_Populate (CachedCrl *crlobject)
static SECStatus CachedCrl_Depopulate (CachedCrl *crl)
static SECStatus CachedCrl_Compare (CachedCrl *a, CachedCrl *b, PRBool *isDupe, PRBool *isUpdated)
static SECStatus DPCache_Create (CRLDPCache **returned, CERTCertificate *issuer, SECItem *subject, SECItem *dp)
static SECStatus DPCache_Destroy (CRLDPCache *cache)
static SECStatus DPCache_AddCRL (CRLDPCache *cache, CachedCrl *crl, PRBool *added)
static SECStatus DPCache_FetchFromTokens (CRLDPCache *cache, PRTime vfdate, void *wincx)
static SECStatus DPCache_Lookup (CRLDPCache *cache, SECItem *sn, CERTCrlEntry **returned)
static SECStatus DPCache_GetUpToDate (CRLDPCache *cache, CERTCertificate *issuer, PRBool readlocked, PRTime vfdate, void *wincx)
static PRBool DPCache_HasTokenCRLs (CRLDPCache *cache)
static SECStatus DPCache_RemoveCRL (CRLDPCache *cache, PRUint32 offset)
static SECStatus DPCache_SelectCRL (CRLDPCache *cache)
static SECStatus IssuerCache_Create (CRLIssuerCache **returned, CERTCertificate *issuer, SECItem *subject, SECItem *dp)
SECStatus IssuerCache_Destroy (CRLIssuerCache *cache)
static SECStatus IssuerCache_AddDP (CRLIssuerCache *cache, CERTCertificate *issuer, SECItem *subject, SECItem *dp, CRLDPCache **newdpc)
static CRLDPCache * IssuerCache_GetDPCache (CRLIssuerCache *cache, SECItem *dp)
static void *PR_CALLBACK PreAllocTable (void *pool, PRSize size)
static void PR_CALLBACK PreFreeTable (void *pool, void *item)
static PLHashEntry *PR_CALLBACK PreAllocEntry (void *pool, const void *key)
static void PR_CALLBACK PreFreeEntry (void *pool, PLHashEntry *he, PRUintn flag)
void PreAllocator_Destroy (PreAllocator *PreAllocator)
PreAllocator * PreAllocator_Create (PRSize size)
SECStatus InitCRLCache (void)
static PRIntn PR_CALLBACK FreeIssuer (PLHashEntry *he, PRIntn i, void *arg)
SECStatus ShutdownCRLCache (void)
static PRBool TokenCRLStillExists (CERTSignedCrl *crl)
static SECStatus CERT_VerifyCRL (CERTSignedCrl *crlobject, CERTCertificate *issuer, PRTime vfdate, void *wincx)
static SECStatus CachedCrl_Verify (CRLDPCache *cache, CachedCrl *crlobject, PRTime vfdate, void *wincx)
static int SortCRLsByThisUpdate (const void *arg1, const void *arg2)
static int SortImperfectCRLs (const void *arg1, const void *arg2)
static SECStatus CRLCache_AddIssuer (CRLIssuerCache *issuer)
static SECStatus CRLCache_GetIssuerCache (CRLCache *cache, SECItem *subject, CRLIssuerCache **returned)
static CERTSignedCrl * GetBestCRL (CRLDPCache *cache, PRBool entries)
static SECStatus AcquireDPCache (CERTCertificate *issuer, SECItem *subject, SECItem *dp, int64 t, void *wincx, CRLDPCache **dpcache, PRBool *writeLocked)
static void ReleaseDPCache (CRLDPCache *dpcache, PRBool writeLocked)
SECStatus CERT_CheckCRL (CERTCertificate *cert, CERTCertificate *issuer, SECItem *dp, int64 t, void *wincx)
CERTSignedCrl * SEC_FindCrlByName (CERTCertDBHandle *handle, SECItem *crlKey, int type)
void CERT_CRLCacheRefreshIssuer (CERTCertDBHandle *dbhandle, SECItem *crlKey)
SECStatus CERT_CacheCRL (CERTCertDBHandle *dbhandle, SECItem *newdercrl)
SECStatus CERT_UncacheCRL (CERTCertDBHandle *dbhandle, SECItem *olddercrl)

Variables

const SEC_ASN1Template SEC_CERTExtensionTemplate []
static const SEC_ASN1Template SEC_CERTExtensionsTemplate []
const SEC_ASN1Template CERT_IssuerAndSNTemplate []
static const SEC_ASN1Template cert_KrlEntryTemplate []
static const SEC_ASN1Template cert_KrlTemplate []
static const SEC_ASN1Template cert_SignedKrlTemplate []
static const SEC_ASN1Template cert_CrlKeyTemplate []
static const SEC_ASN1Template cert_CrlEntryTemplate []
const SEC_ASN1Template CERT_CrlTemplate []
const SEC_ASN1Template CERT_CrlTemplateNoEntries []
const SEC_ASN1Template CERT_CrlTemplateEntriesOnly []
const SEC_ASN1Template CERT_SignedCrlTemplate []
static const SEC_ASN1Template cert_SignedCrlTemplateNoEntries []
const SEC_ASN1Template CERT_SetOfSignedCrlTemplate []
static PLHashAllocOps preAllocOps
static CRLCache crlcache = { NULL, NULL }
static PRBool crlcache_initialized = PR_FALSE
PRTime CRLCache_Empty_TokenFetch_Interval = 60 * 1000000
PRTime CRLCache_TokenRefetch_Interval = 600 * 1000000
PRTime CRLCache_ExistenceCheck_Interval = 60 * 1000000

Define Documentation

Value:
{ \
    if (readlocked) \
    { \
        NSSRWLock_UnlockRead(cache->lock); \
    } \
    NSSRWLock_LockWrite(cache->lock); \
}

Definition at line 1706 of file crl.c.

Value:
{ \
    if (readlocked) \
    { \
        NSSRWLock_LockRead(cache->lock); \
    } \
    NSSRWLock_UnlockWrite(cache->lock); \
}

Definition at line 1715 of file crl.c.

#define GetOpaqueCRLFields (   x)    ((OpaqueCRLFields*)x->opaque)

Definition at line 403 of file crl.c.


Function Documentation

static SECStatus AcquireDPCache ( CERTCertificate *  issuer,
SECItem *  subject,
SECItem *  dp,
int64  t,
void wincx,
CRLDPCache **  dpcache,
PRBool writeLocked 
) [static]

Definition at line 2355 of file crl.c.

{
    SECStatus rv = SECSuccess;
    CRLIssuerCache* issuercache = NULL;
#ifdef GLOBAL_RWLOCK
    PRBool globalwrite = PR_FALSE;
#endif
    PORT_Assert(crlcache.lock);
    if (!crlcache.lock)
    {
        /* CRL cache is not initialized */
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
#ifdef GLOBAL_RWLOCK
    NSSRWLock_LockRead(crlcache.lock);
#else
    PR_Lock(crlcache.lock);
#endif
    rv = CRLCache_GetIssuerCache(&crlcache, subject, &issuercache);
    if (SECSuccess != rv)
    {
#ifdef GLOBAL_RWLOCK
        NSSRWLock_UnlockRead(crlcache.lock);
#else
        PR_Unlock(crlcache.lock);
#endif
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (!issuercache)
    {
        /* there is no cache for this issuer yet. This means this is the
           first time we look up a cert from that issuer, and we need to
           create the cache. */
        
        rv = IssuerCache_Create(&issuercache, issuer, subject, dp);
        if (SECSuccess == rv && !issuercache)
        {
            PORT_Assert(issuercache);
            rv = SECFailure;
        }

        if (SECSuccess == rv)
        {
            /* This is the first time we look up a cert of this issuer.
               Create the DPCache for this DP . */
            rv = IssuerCache_AddDP(issuercache, issuer, subject, dp, dpcache);
        }

        if (SECSuccess == rv)
        {
            /* lock the DPCache for write to ensure the update happens in this
               thread */
            *writeLocked = PR_TRUE;
#ifdef DPC_RWLOCK
            NSSRWLock_LockWrite((*dpcache)->lock);
#else
            PR_Lock((*dpcache)->lock);
#endif
        }
        
        if (SECSuccess == rv)
        {
            /* now add the new issuer cache to the global hash table of
               issuers */
#ifdef GLOBAL_RWLOCK
            CRLIssuerCache* existing = NULL;
            NSSRWLock_UnlockRead(crlcache.lock);
            /* when using a r/w lock for the global cache, check if the issuer
               already exists before adding to the hash table */
            NSSRWLock_LockWrite(crlcache.lock);
            globalwrite = PR_TRUE;
            rv = CRLCache_GetIssuerCache(&crlcache, subject, &existing);
            if (!existing)
            {
#endif
                rv = CRLCache_AddIssuer(issuercache);
                if (SECSuccess != rv)
                {
                    /* failure */
                    rv = SECFailure;
                }
#ifdef GLOBAL_RWLOCK
            }
            else
            {
                /* somebody else updated before we did */
                IssuerCache_Destroy(issuercache); /* destroy the new object */
                issuercache = existing; /* use the existing one */
                *dpcache = IssuerCache_GetDPCache(issuercache, dp);
            }
#endif
        }

        /* now unlock the global cache. We only want to lock the issuer hash
           table addition. Holding it longer would hurt scalability */
#ifdef GLOBAL_RWLOCK
        if (PR_TRUE == globalwrite)
        {
            NSSRWLock_UnlockWrite(crlcache.lock);
            globalwrite = PR_FALSE;
        }
        else
        {
            NSSRWLock_UnlockRead(crlcache.lock);
        }
#else
        PR_Unlock(crlcache.lock);
#endif

        /* if there was a failure adding an issuer cache object, destroy it */
        if (SECSuccess != rv && issuercache)
        {
            if (PR_TRUE == *writeLocked)
            {
#ifdef DPC_RWLOCK
                NSSRWLock_UnlockWrite((*dpcache)->lock);
#else
                PR_Unlock((*dpcache)->lock);
#endif
            }
            IssuerCache_Destroy(issuercache);
            issuercache = NULL;
        }

        if (SECSuccess != rv)
        {
            return SECFailure;
        }
    } else
    {
#ifdef GLOBAL_RWLOCK
        NSSRWLock_UnlockRead(crlcache.lock);
#else
        PR_Unlock(crlcache.lock);
#endif
        *dpcache = IssuerCache_GetDPCache(issuercache, dp);
    }
    /* we now have a DPCache that we can use for lookups */
    /* lock it for read, unless we already locked for write */
    if (PR_FALSE == *writeLocked)
    {
#ifdef DPC_RWLOCK
        NSSRWLock_LockRead((*dpcache)->lock);
#else
        PR_Lock((*dpcache)->lock);
#endif
    }
    
    if (SECSuccess == rv)
    {
        /* currently there is always one and only one DPCache per issuer */
        PORT_Assert(*dpcache);
        if (*dpcache)
        {
            /* make sure the DP cache is up to date before using it */
            rv = DPCache_GetUpToDate(*dpcache, issuer, PR_FALSE == *writeLocked,
                                     t, wincx);
        }
        else
        {
            rv = SECFailure;
        }
    }
    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Compare ( CachedCrl *  a,
CachedCrl *  b,
PRBool isDupe,
PRBool isUpdated 
) [static]

Definition at line 2949 of file crl.c.

{
    PORT_Assert(a);
    PORT_Assert(b);
    PORT_Assert(isDupe);
    PORT_Assert(isUpdated);
    if (!a || !b || !isDupe || !isUpdated || !a->crl || !b->crl)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    *isDupe = *isUpdated = PR_FALSE;

    if (a == b)
    {
        /* dupe */
        *isDupe = PR_TRUE;
        *isUpdated = PR_FALSE;
        return SECSuccess;
    }
    if (b->origin != a->origin)
    {
        /* CRLs of different origins are not considered dupes,
           and can't be updated either */
        return SECSuccess;
    }
    if (CRL_OriginToken == b->origin)
    {
        /* for token CRLs, slot and PKCS#11 object handle must match for CRL
           to truly be a dupe */
        if ( (b->crl->slot == a->crl->slot) &&
             (b->crl->pkcs11ID == a->crl->pkcs11ID) )
        {
            /* ASN.1 DER needs to match for dupe check */
            /* could optimize by just checking a few fields like thisUpdate */
            if ( SECEqual == SECITEM_CompareItem(b->crl->derCrl,
                                                 a->crl->derCrl) )
            {
                *isDupe = PR_TRUE;
            }
            else
            {
                *isUpdated = PR_TRUE;
            }
        }
        return SECSuccess;
    }
    if (CRL_OriginExplicit == b->origin)
    {
        /* We need to make sure this is the same object that the user provided
           to CERT_CacheCRL previously. That API takes a SECItem*, thus, we
           just do a pointer comparison here.
        */
        if (b->crl->derCrl == a->crl->derCrl)
        {
            *isDupe = PR_TRUE;
        }
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Create ( CachedCrl **  returned,
CERTSignedCrl *  crl,
CRLOrigin  origin 
) [static]

Definition at line 2814 of file crl.c.

{
    CachedCrl* newcrl = NULL;
    if (!returned)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    newcrl = PORT_ZAlloc(sizeof(CachedCrl));
    if (!newcrl)
    {
        return SECFailure;
    }
    newcrl->crl = SEC_DupCrl(crl);
    newcrl->origin = origin;
    *returned = newcrl;
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Depopulate ( CachedCrl *  crl) [static]

Definition at line 2835 of file crl.c.

{
    if (!crl)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
     /* destroy the hash table */
    if (crl->entries)
    {
        PL_HashTableDestroy(crl->entries);
        crl->entries = NULL;
    }

    /* free the pre buffer */
    if (crl->prebuffer)
    {
        PreAllocator_Destroy(crl->prebuffer);
        crl->prebuffer = NULL;
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Destroy ( CachedCrl *  crl) [static]

Definition at line 2858 of file crl.c.

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Populate ( CachedCrl *  crlobject) [static]

Definition at line 2872 of file crl.c.

{
    SECStatus rv = SECFailure;
    CERTCrlEntry** crlEntry = NULL;
    PRUint32 numEntries = 0;

    if (!crlobject)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* complete the entry decoding . XXX thread-safety of CRL object */
    rv = CERT_CompleteCRLDecodeEntries(crlobject->crl);
    if (SECSuccess != rv)
    {
        return SECFailure;
    }

    if (crlobject->entries && crlobject->prebuffer)
    {
        /* cache is already built */
        return SECSuccess;
    }

    /* build the hash table from the full CRL */    
    /* count CRL entries so we can pre-allocate space for hash table entries */
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
         crlEntry++)
    {
        numEntries++;
    }
    crlobject->prebuffer = PreAllocator_Create(numEntries*sizeof(PLHashEntry));
    PORT_Assert(crlobject->prebuffer);
    if (!crlobject->prebuffer)
    {
        return SECFailure;
    }
    /* create a new hash table */
    crlobject->entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
                         PL_CompareValues, &preAllocOps, crlobject->prebuffer);
    PORT_Assert(crlobject->entries);
    if (!crlobject->entries)
    {
        return SECFailure;
    }
    /* add all serial numbers to the hash table */
    for (crlEntry = crlobject->crl->crl.entries; crlEntry && *crlEntry;
         crlEntry++)
    {
        PL_HashTableAdd(crlobject->entries, &(*crlEntry)->serialNumber,
                        *crlEntry);
    }

    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CachedCrl_Verify ( CRLDPCache *  cache,
CachedCrl *  crlobject,
PRTime  vfdate,
void wincx 
) [static]

Definition at line 1513 of file crl.c.

{
    /*  Check if it is an invalid CRL
        if we got a bad CRL, we want to cache it in order to avoid
        subsequent fetches of this same identical bad CRL. We set
        the cache to the invalid state to ensure that all certs
        on this DP are considered revoked from now on. The cache
        object will remain in this state until the bad CRL object
        is removed from the token it was fetched from. If the cause
        of the failure is that we didn't have the issuer cert to
        verify the signature, this state can be cleared when
        the issuer certificate becomes available if that causes the
        signature to verify */

    if (!cache || !crlobject)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (PR_TRUE == GetOpaqueCRLFields(crlobject->crl)->decodingError)
    {
        crlobject->sigChecked = PR_TRUE; /* we can never verify a CRL
            with bogus DER. Mark it checked so we won't try again */
        PORT_SetError(SEC_ERROR_BAD_DER);
        return SECSuccess;
    }
    else
    {
        SECStatus signstatus = SECFailure;
        if (cache->issuer)
        {
            signstatus = CERT_VerifyCRL(crlobject->crl, cache->issuer, vfdate,
                                        wincx);
        }
        if (SECSuccess != signstatus)
        {
            if (!cache->issuer)
            {
                /* we tried to verify without an issuer cert . This is
                   because this CRL came through a call to SEC_FindCrlByName.
                   So, we don't cache this verification failure. We'll try
                   to verify the CRL again when a certificate from that issuer
                   becomes available */
            } else
            {
                crlobject->sigChecked = PR_TRUE;
            }
            PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
            return SECSuccess;
        } else
        {
            crlobject->sigChecked = PR_TRUE;
            crlobject->sigValid = PR_TRUE;
        }
    }
    
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus CERT_CacheCRL ( CERTCertDBHandle *  dbhandle,
SECItem *  newdercrl 
)

Definition at line 2667 of file crl.c.

{
    CRLDPCache* cache = NULL;
    SECStatus rv = SECSuccess;
    PRBool writeLocked = PR_FALSE;
    PRBool readlocked;
    CachedCrl* returned = NULL;
    PRBool added = PR_FALSE;
    CERTSignedCrl* newcrl = NULL;
    int realerror = 0;
    
    if (!dbhandle || !newdercrl)
    {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* first decode the DER CRL to make sure it's OK */
    newcrl = CERT_DecodeDERCrlWithFlags(NULL, newdercrl, SEC_CRL_TYPE,
                                        CRL_DECODE_DONT_COPY_DER |
                                        CRL_DECODE_SKIP_ENTRIES);

    if (!newcrl)
    {
        return SECFailure;
    }

    rv = AcquireDPCache(NULL,
                        &newcrl->crl.derName,
                        NULL, 0, NULL, &cache, &writeLocked);
    if (SECSuccess == rv)
    {
        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
    
        rv = CachedCrl_Create(&returned, newcrl, CRL_OriginExplicit);
        if (SECSuccess == rv && returned)
        {
            DPCache_LockWrite();
            rv = DPCache_AddCRL(cache, returned, &added);
            if (PR_TRUE != added)
            {
                realerror = PORT_GetError();
                CachedCrl_Destroy(returned);
                returned = NULL;
            }
            DPCache_UnlockWrite();
        }
    
        ReleaseDPCache(cache, writeLocked);
    
        if (!added)
        {
            rv = SECFailure;
        }
    }
    SEC_DestroyCrl(newcrl); /* free the CRL. Either it got added to the cache
        and the refcount got bumped, or not, and thus we need to free its
        RAM */
    if (realerror)
    {
        PORT_SetError(realerror);
    }
    return rv;
}
SECStatus cert_check_crl_entries ( CERTCrl *  crl)

Definition at line 283 of file crl.c.

{
    CERTCrlEntry **entries;
    CERTCrlEntry *entry;
    PRBool hasCriticalExten = PR_FALSE;
    SECStatus rv = SECSuccess;

    if (!crl) {
        return SECFailure;
    }

    if (crl->entries == NULL) {
        /* CRLs with no entries are valid */
        return (SECSuccess);
    }

    /* Look in the crl entry extensions.  If there is a critical extension,
       then the crl version must be v2; otherwise, it should be v1.
     */
    entries = crl->entries;
    while (*entries) {
       entry = *entries;
       if (entry->extensions) {
           /* If there is a critical extension in the entries, then the
              CRL must be of version 2.  If we already saw a critical extension,
              there is no need to check the version again.
           */
            if (hasCriticalExten == PR_FALSE) {
                hasCriticalExten = cert_HasCriticalExtension (entry->extensions);
                if (hasCriticalExten) {
                    if (cert_get_crl_version(crl) != SEC_CRL_VERSION_2) { 
                        /* only CRL v2 critical extensions are supported */
                        PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
                        rv = SECFailure;
                        break;
                    }
                }
            }

           /* For each entry, make sure that it does not contain an unknown
              critical extension.  If it does, we must reject the CRL since
              we don't know how to process the extension.
           */
           if (cert_HasUnknownCriticalExten (entry->extensions) == PR_TRUE) {
              PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
              rv = SECFailure;
              break;
           }
       }
       ++entries;
    }
    return(rv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus cert_check_crl_version ( CERTCrl *  crl)

Definition at line 342 of file crl.c.

{
    PRBool hasCriticalExten = PR_FALSE;
    int version = cert_get_crl_version(crl);
       
    if (version > SEC_CRL_VERSION_2) {
       PORT_SetError (SEC_ERROR_CRL_INVALID_VERSION);
       return (SECFailure);
    }

    /* Check the crl extensions for a critial extension.  If one is found,
       and the version is not v2, then we are done.
     */
    if (crl->extensions) {
       hasCriticalExten = cert_HasCriticalExtension (crl->extensions);
       if (hasCriticalExten) {
            if (version != SEC_CRL_VERSION_2) {
                /* only CRL v2 critical extensions are supported */
                PORT_SetError(SEC_ERROR_CRL_V1_CRITICAL_EXTENSION);
                return (SECFailure);
            }
           /* make sure that there is no unknown critical extension */
           if (cert_HasUnknownCriticalExten (crl->extensions) == PR_TRUE) {
              PORT_SetError (SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION);
              return (SECFailure);
           }
       }
    }

    return (SECSuccess);
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus CERT_CheckCRL ( CERTCertificate *  cert,
CERTCertificate *  issuer,
SECItem *  dp,
int64  t,
void wincx 
)

Definition at line 2549 of file crl.c.

{
    PRBool lockedwrite = PR_FALSE;
    SECStatus rv = SECSuccess;
    CRLDPCache* dpcache = NULL;
    if (!cert || !issuer)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    if (SECSuccess != CERT_CheckCertValidTimes(issuer, t, PR_FALSE))
    {
        /* we won't be able to check the CRL's signature if the issuer cert
           is expired as of the time we are verifying. This may cause a valid
           CRL to be cached as bad. short-circuit to avoid this case. */
        PORT_SetError(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
        return SECFailure;
    }

    rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache,
                        &lockedwrite);
    
    if (SECSuccess == rv)
    {
        /* now look up the certificate SN in the DP cache's CRL */
        CERTCrlEntry* entry = NULL;
        rv = DPCache_Lookup(dpcache, &cert->serialNumber, &entry);
        if (SECSuccess == rv && entry)
        {
            /* check the time if we have one */
            if (entry->revocationDate.data && entry->revocationDate.len)
            {
                int64 revocationDate = 0;
                if (SECSuccess == DER_DecodeTimeChoice(&revocationDate,
                                               &entry->revocationDate))
                {
                    /* we got a good revocation date, only consider the
                       certificate revoked if the time we are inquiring about
                       is past the revocation date */
                    if (t>=revocationDate)
                    {
                        rv = SECFailure;
                    }
                } else {
                    /* invalid revocation date, consider the certificate
                       permanently revoked */
                    rv = SECFailure;
                }
            } else {
                /* no revocation date, certificate is permanently revoked */
                rv = SECFailure;
            }
            if (SECFailure == rv)
            {
                PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE);
            }
        }
    }

    ReleaseDPCache(dpcache, lockedwrite);
    return rv;
}
SECStatus CERT_CompleteCRLDecodeEntries ( CERTSignedCrl *  crl)

Definition at line 405 of file crl.c.

{
    SECStatus rv = SECSuccess;
    SECItem* crldata = NULL;
    OpaqueCRLFields* extended = NULL;

    if ( (!crl) ||
         (!(extended = (OpaqueCRLFields*) crl->opaque)) ||
         (PR_TRUE == extended->decodingError) ) {
        rv = SECFailure;
    } else {
        if (PR_FALSE == extended->partial) {
            /* the CRL has already been fully decoded */
            return SECSuccess;
        }
        if (PR_TRUE == extended->badEntries) {
            /* the entries decoding already failed */
            return SECFailure;
        }
        crldata = &crl->signatureWrap.data;
        if (!crldata) {
            rv = SECFailure;
        }
    }

    if (SECSuccess == rv) {
        rv = SEC_QuickDERDecodeItem(crl->arena,
            &crl->crl,
            CERT_CrlTemplateEntriesOnly,
            crldata);
        if (SECSuccess == rv) {
            extended->partial = PR_FALSE; /* successful decode, avoid
                decoding again */
        } else {
            extended->decodingError = PR_TRUE;
            extended->badEntries = PR_TRUE;
            /* cache the decoding failure. If it fails the first time,
               it will fail again, which will grow the arena and leak
               memory, so we want to avoid it */
        }
        rv = cert_check_crl_entries(&crl->crl);
        if (rv != SECSuccess) {
            extended->badExtensions = PR_TRUE;
        }
    }
    return rv;
}
void CERT_CRLCacheRefreshIssuer ( CERTCertDBHandle *  dbhandle,
SECItem *  crlKey 
)

Definition at line 2641 of file crl.c.

{
    CRLDPCache* cache = NULL;
    SECStatus rv = SECSuccess;
    PRBool writeLocked = PR_FALSE;
    PRBool readlocked;

    (void) dbhandle; /* silence compiler warnings */

    /* XCRL we will need to refresh all the DPs of the issuer in the future,
            not just the default one */
    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
    if (SECSuccess != rv)
    {
        return;
    }
    /* we need to invalidate the DPCache here */
    readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
    DPCache_LockWrite();
    cache->refresh = PR_TRUE;
    DPCache_UnlockWrite();
    ReleaseDPCache(cache, writeLocked);
    return;
}
CERTSignedCrl* CERT_DecodeDERCrl ( PRArenaPool narena,
SECItem *  derSignedCrl,
int  type 
)

Definition at line 601 of file crl.c.

{
    return CERT_DecodeDERCrlWithFlags(narena, derSignedCrl, type,
                                      CRL_DECODE_DEFAULT_OPTIONS);
}
CERTSignedCrl* CERT_DecodeDERCrlWithFlags ( PRArenaPool narena,
SECItem *  derSignedCrl,
int  type,
PRInt32  options 
)

Definition at line 458 of file crl.c.

{
    PRArenaPool *arena;
    CERTSignedCrl *crl;
    SECStatus rv;
    OpaqueCRLFields* extended = NULL;
    const SEC_ASN1Template* crlTemplate = CERT_SignedCrlTemplate;
    PRInt32 testOptions = options;

    PORT_Assert(derSignedCrl);
    if (!derSignedCrl) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    /* Adopting DER requires not copying it.  Code that sets ADOPT flag 
     * but doesn't set DONT_COPY probably doesn't know What it is doing.  
     * That condition is a programming error in the caller.
     */
    testOptions &= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);
    PORT_Assert(testOptions != CRL_DECODE_ADOPT_HEAP_DER);
    if (testOptions == CRL_DECODE_ADOPT_HEAP_DER) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    /* make a new arena if needed */
    if (narena == NULL) {
       arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
       if ( !arena ) {
           return NULL;
       }
    } else {
       arena = narena;
    }

    /* allocate the CRL structure */
    crl = (CERTSignedCrl *)PORT_ArenaZAlloc(arena, sizeof(CERTSignedCrl));
    if ( !crl ) {
        PORT_SetError(SEC_ERROR_NO_MEMORY);
       goto loser;
    }

    crl->arena = arena;

    /* allocate opaque fields */
    crl->opaque = (void*)PORT_ArenaZAlloc(arena, sizeof(OpaqueCRLFields));
    if ( !crl->opaque ) {
       goto loser;
    }
    extended = (OpaqueCRLFields*) crl->opaque;
    if (options & CRL_DECODE_ADOPT_HEAP_DER) {
        extended->heapDER = PR_TRUE;
    }
    if (options & CRL_DECODE_DONT_COPY_DER) {
        crl->derCrl = derSignedCrl; /* DER is not copied . The application
                                       must keep derSignedCrl until it
                                       destroys the CRL */
    } else {
        crl->derCrl = (SECItem *)PORT_ArenaZAlloc(arena,sizeof(SECItem));
        if (crl->derCrl == NULL) {
            goto loser;
        }
        rv = SECITEM_CopyItem(arena, crl->derCrl, derSignedCrl);
        if (rv != SECSuccess) {
            goto loser;
        }
    }

    /* Save the arena in the inner crl for CRL extensions support */
    crl->crl.arena = arena;
    if (options & CRL_DECODE_SKIP_ENTRIES) {
        crlTemplate = cert_SignedCrlTemplateNoEntries;
        extended->partial = PR_TRUE;
    }

    /* decode the CRL info */
    switch (type) {
    case SEC_CRL_TYPE:
        rv = SEC_QuickDERDecodeItem(arena, crl, crlTemplate, crl->derCrl);
        if (rv != SECSuccess) {
            extended->badDER = PR_TRUE;
            break;
        }
        /* check for critical extensions */
        rv =  cert_check_crl_version (&crl->crl);
        if (rv != SECSuccess) {
            extended->badExtensions = PR_TRUE;
            break;
        }

        if (PR_TRUE == extended->partial) {
            /* partial decoding, don't verify entries */
            break;
        }

        rv = cert_check_crl_entries(&crl->crl);
        if (rv != SECSuccess) {
            extended->badExtensions = PR_TRUE;
        }

        break;

    case SEC_KRL_TYPE:
       rv = SEC_QuickDERDecodeItem
            (arena, crl, cert_SignedKrlTemplate, derSignedCrl);
       break;
    default:
       rv = SECFailure;
       break;
    }

    if (rv != SECSuccess) {
       goto loser;
    }

    crl->referenceCount = 1;
    
    return(crl);
    
loser:
    if (options & CRL_DECODE_KEEP_BAD_CRL) {
        if (extended) {
            extended->decodingError = PR_TRUE;
        }
        if (crl) {
            crl->referenceCount = 1;
            return(crl);
        }
    }

    if ((narena == NULL) && arena ) {
       PORT_FreeArena(arena, PR_FALSE);
    }
    
    return(0);
}
int cert_get_crl_version ( CERTCrl *  crl)

Definition at line 271 of file crl.c.

{
    /* CRL version is defaulted to v1 */
    int version = SEC_CRL_VERSION_1;
    if (crl && crl->version.data != 0) {
       version = (int)DER_GetUInteger (&crl->version);
    }
    return version;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus CERT_KeyFromDERCrl ( PRArenaPool arena,
SECItem *  derCrl,
SECItem *  key 
)

Definition at line 379 of file crl.c.

{
    SECStatus rv;
    CERTSignedData sd;
    CERTCrlKey crlkey;

    PORT_Memset (&sd, 0, sizeof (sd));
    rv = SEC_ASN1DecodeItem (arena, &sd, CERT_SignedDataTemplate, derCrl);
    if (rv != SECSuccess) {
       return rv;
    }

    PORT_Memset (&crlkey, 0, sizeof (crlkey));
    rv = SEC_ASN1DecodeItem(arena, &crlkey, cert_CrlKeyTemplate, &sd.data);
    if (rv != SECSuccess) {
       return rv;
    }

    key->len =  crlkey.derName.len;
    key->data = crlkey.derName.data;

    return(SECSuccess);
}
SECStatus CERT_UncacheCRL ( CERTCertDBHandle *  dbhandle,
SECItem *  olddercrl 
)

Definition at line 2733 of file crl.c.

{
    CRLDPCache* cache = NULL;
    SECStatus rv = SECSuccess;
    PRBool writeLocked = PR_FALSE;
    PRBool readlocked;
    PRBool removed = PR_FALSE;
    PRUint32 i;
    CERTSignedCrl* oldcrl = NULL;
    
    if (!dbhandle || !olddercrl)
    {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    /* first decode the DER CRL to make sure it's OK */
    oldcrl = CERT_DecodeDERCrlWithFlags(NULL, olddercrl, SEC_CRL_TYPE,
                                        CRL_DECODE_DONT_COPY_DER |
                                        CRL_DECODE_SKIP_ENTRIES);

    if (!oldcrl)
    {
        /* if this DER CRL can't decode, it can't be in the cache */
        return SECFailure;
    }

    rv = AcquireDPCache(NULL,
                        &oldcrl->crl.derName,
                        NULL, 0, NULL, &cache, &writeLocked);
    if (SECSuccess == rv)
    {
        CachedCrl* returned = NULL;

        readlocked = (writeLocked == PR_TRUE? PR_FALSE : PR_TRUE);
    
        rv = CachedCrl_Create(&returned, oldcrl, CRL_OriginExplicit);
        if (SECSuccess == rv && returned)
        {
            DPCache_LockWrite();
            for (i=0;i<cache->ncrls;i++)
            {
                PRBool dupe = PR_FALSE, updated = PR_FALSE;
                rv = CachedCrl_Compare(returned, cache->crls[i],
                                                      &dupe, &updated);
                if (SECSuccess != rv)
                {
                    PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
                    break;
                }
                if (PR_TRUE == dupe)
                {
                    rv = DPCache_RemoveCRL(cache, i); /* got a match */
                    if (SECSuccess == rv) {
                        cache->mustchoose = PR_TRUE;
                        removed = PR_TRUE;
                    }
                    break;
                }
            }
            
            DPCache_UnlockWrite();

            if (SECSuccess != CachedCrl_Destroy(returned) ) {
                rv = SECFailure;
            }
        }

        ReleaseDPCache(cache, writeLocked);
    }
    if (SECSuccess != SEC_DestroyCrl(oldcrl) ) { 
        /* need to do this because object is refcounted */
        rv = SECFailure;
    }
    if (SECSuccess == rv && PR_TRUE != removed)
    {
        PORT_SetError(SEC_ERROR_CRL_NOT_FOUND);
    }
    return rv;
}
static SECStatus CERT_VerifyCRL ( CERTSignedCrl *  crlobject,
CERTCertificate *  issuer,
PRTime  vfdate,
void wincx 
) [static]

Definition at line 1502 of file crl.c.

{
    return CERT_VerifySignedData(&crlobject->signatureWrap,
                                 issuer, vfdate, wincx);
}

Here is the call graph for this function:

Here is the caller graph for this function:

CERTSignedCrl* crl_storeCRL ( PK11SlotInfo *  slot,
char *  url,
CERTSignedCrl *  newCrl,
SECItem *  derCrl,
int  type 
)

Definition at line 690 of file crl.c.

{
    CERTSignedCrl *oldCrl = NULL, *crl = NULL;
    PRBool deleteOldCrl = PR_FALSE;
    CK_OBJECT_HANDLE crlHandle = CK_INVALID_HANDLE;
    SECStatus rv;

    PORT_Assert(newCrl);
    PORT_Assert(derCrl);

    /* we can't use the cache here because we must look in the same
       token */
    rv = SEC_FindCrlByKeyOnSlot(slot, &newCrl->crl.derName, type,
                                &oldCrl, CRL_DECODE_SKIP_ENTRIES);
    /* if there is an old crl on the token, make sure the one we are
       installing is newer. If not, exit out, otherwise delete the
       old crl.
     */
    if (oldCrl != NULL) {
       /* if it's already there, quietly continue */
       if (SECITEM_CompareItem(newCrl->derCrl, oldCrl->derCrl) 
                                          == SECEqual) {
           crl = newCrl;
           crl->slot = PK11_ReferenceSlot(slot);
           crl->pkcs11ID = oldCrl->pkcs11ID;
           goto done;
       }
        if (!SEC_CrlIsNewer(&newCrl->crl,&oldCrl->crl)) {

            if (type == SEC_CRL_TYPE) {
                PORT_SetError(SEC_ERROR_OLD_CRL);
            } else {
                PORT_SetError(SEC_ERROR_OLD_KRL);
            }

            goto done;
        }

        if ((SECITEM_CompareItem(&newCrl->crl.derName,
                &oldCrl->crl.derName) != SECEqual) &&
            (type == SEC_KRL_TYPE) ) {

            PORT_SetError(SEC_ERROR_CKL_CONFLICT);
            goto done;
        }

        /* if we have a url in the database, use that one */
        if (oldCrl->url) {
           url = oldCrl->url;
        }

        /* really destroy this crl */
        /* first drum it out of the permanment Data base */
       deleteOldCrl = PR_TRUE;
    }

    /* invalidate CRL cache for this issuer */
    CERT_CRLCacheRefreshIssuer(NULL, &newCrl->crl.derName);
    /* Write the new entry into the data base */
    crlHandle = PK11_PutCrl(slot, derCrl, &newCrl->crl.derName, url, type);
    if (crlHandle != CK_INVALID_HANDLE) {
       crl = newCrl;
       crl->slot = PK11_ReferenceSlot(slot);
       crl->pkcs11ID = crlHandle;
       if (url) {
           crl->url = PORT_ArenaStrdup(crl->arena,url);
       }
    }

done:
    if (oldCrl) {
       if (deleteOldCrl && crlHandle != CK_INVALID_HANDLE) {
           SEC_DeletePermCRL(oldCrl);
       }
       SEC_DestroyCrl(oldCrl);
    }

    return crl;
}

Here is the caller graph for this function:

static SECStatus CRLCache_AddIssuer ( CRLIssuerCache *  issuer) [static]

Definition at line 2243 of file crl.c.

{    
    PORT_Assert(issuer);
    PORT_Assert(crlcache.issuers);
    if (!issuer || !crlcache.issuers)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (NULL == PL_HashTableAdd(crlcache.issuers, (void*) issuer->subject,
                                (void*) issuer))
    {
        return SECFailure;
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus CRLCache_GetIssuerCache ( CRLCache *  cache,
SECItem *  subject,
CRLIssuerCache **  returned 
) [static]

Definition at line 2261 of file crl.c.

{
    /* we need to look up the issuer in the hash table */
    SECStatus rv = SECSuccess;
    PORT_Assert(cache);
    PORT_Assert(subject);
    PORT_Assert(returned);
    PORT_Assert(crlcache.issuers);
    if (!cache || !subject || !returned || !crlcache.issuers)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        rv = SECFailure;
    }

    if (SECSuccess == rv)
    {
        *returned = (CRLIssuerCache*) PL_HashTableLookup(crlcache.issuers,
                                                         (void*) subject);
    }

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_AddCRL ( CRLDPCache *  cache,
CachedCrl *  crl,
PRBool added 
) [static]

Definition at line 1305 of file crl.c.

{
    CachedCrl** newcrls = NULL;
    PRUint32 i = 0;
    PORT_Assert(cache);
    PORT_Assert(newcrl);
    PORT_Assert(added);
    if (!cache || !newcrl || !added)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    *added = PR_FALSE;
    /* before adding a new CRL, check if it is a duplicate */
    for (i=0;i<cache->ncrls;i++)
    {
        CachedCrl* existing = NULL;
        SECStatus rv = SECSuccess;
        PRBool dupe = PR_FALSE, updated = PR_FALSE;
        if (!cache->crls)
        {
            PORT_Assert(0);
            return SECFailure;
        }
        existing = cache->crls[i];
        if (!existing)
        {
            PORT_Assert(0);
            return SECFailure;
        }
        rv = CachedCrl_Compare(existing, newcrl, &dupe, &updated);
        if (SECSuccess != rv)
        {
            PORT_Assert(0);
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            return SECFailure;
        }
        if (PR_TRUE == dupe)
        {
            /* dupe */
            PORT_SetError(SEC_ERROR_CRL_ALREADY_EXISTS);
            return SECSuccess;
        }
        if (PR_TRUE == updated)
        {
            /* this token CRL is in the same slot and has the same object ID,
               but different content. We need to remove the old object */
            if (SECSuccess != DPCache_RemoveCRL(cache, i))
            {
                PORT_Assert(0);
                PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
                return PR_FALSE;
            }
        }
    }

    newcrls = (CachedCrl**)PORT_Realloc(cache->crls,
        (cache->ncrls+1)*sizeof(CachedCrl*));
    if (!newcrls)
    {
        return SECFailure;
    }
    cache->crls = newcrls;
    cache->ncrls++;
    cache->crls[cache->ncrls-1] = newcrl;
    *added = PR_TRUE;
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_Create ( CRLDPCache **  returned,
CERTCertificate *  issuer,
SECItem *  subject,
SECItem *  dp 
) [static]

Definition at line 2122 of file crl.c.

{
    CRLDPCache* cache = NULL;
    PORT_Assert(returned);
    /* issuer and dp are allowed to be NULL */
    if (!returned || !subject)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    *returned = NULL;
    cache = PORT_ZAlloc(sizeof(CRLDPCache));
    if (!cache)
    {
        return SECFailure;
    }
#ifdef DPC_RWLOCK
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
#else
    cache->lock = PR_NewLock();
#endif
    if (!cache->lock)
    {
       PORT_Free(cache);
        return SECFailure;
    }
    if (issuer)
    {
        cache->issuer = CERT_DupCertificate(issuer);
    }
    cache->distributionPoint = SECITEM_DupItem(dp);
    cache->subject = SECITEM_DupItem(subject);
    cache->lastfetch = 0;
    cache->lastcheck = 0;
    *returned = cache;
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_Destroy ( CRLDPCache *  cache) [static]

Definition at line 1141 of file crl.c.

{
    PRUint32 i = 0;
    PORT_Assert(cache);
    if (!cache)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (cache->lock)
    {
#ifdef DPC_RWLOCK
        NSSRWLock_Destroy(cache->lock);
#else
        PR_DestroyLock(cache->lock);
#endif
    }
    else
    {
        PORT_Assert(0);
        return SECFailure;
    }
    /* destroy all our CRL objects */
    for (i=0;i<cache->ncrls;i++)
    {
        if (!cache->crls || !cache->crls[i] ||
            SECSuccess != CachedCrl_Destroy(cache->crls[i]))
        {
            return SECFailure;
        }
    }
    /* free the array of CRLs */
    if (cache->crls)
    {
       PORT_Free(cache->crls);
    }
    /* destroy the cert */
    if (cache->issuer)
    {
        CERT_DestroyCertificate(cache->issuer);
    }
    /* free the subject */
    if (cache->subject)
    {
        SECITEM_FreeItem(cache->subject, PR_TRUE);
    }
    /* free the distribution points */
    if (cache->distributionPoint)
    {
        SECITEM_FreeItem(cache->distributionPoint, PR_TRUE);
    }
    PORT_Free(cache);
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_FetchFromTokens ( CRLDPCache *  cache,
PRTime  vfdate,
void wincx 
) [static]

Definition at line 1575 of file crl.c.

{
    SECStatus rv = SECSuccess;
    CERTCrlHeadNode head;
    if (!cache)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* first, initialize list */
    memset(&head, 0, sizeof(head));
    head.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    rv = pk11_RetrieveCrls(&head, cache->subject, wincx);

    /* if this function fails, something very wrong happened, such as an out
       of memory error during CRL decoding. We don't want to proceed and must
       mark the cache object invalid */
    if (SECFailure == rv)
    {
        /* fetch failed, add error bit */
        cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
    } else
    {
        /* fetch was successful, clear this error bit */
        cache->invalid &= (~CRL_CACHE_LAST_FETCH_FAILED);
    }

    /* add any CRLs found to our array */
    if (SECSuccess == rv)
    {
        CERTCrlNode* crlNode = NULL;

        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
        {
            CachedCrl* returned = NULL;
            CERTSignedCrl* crlobject = crlNode->crl;
            if (!crlobject)
            {
                PORT_Assert(0);
                continue;
            }
            rv = CachedCrl_Create(&returned, crlobject, CRL_OriginToken);
            if (SECSuccess == rv)
            {
                PRBool added = PR_FALSE;
                rv = DPCache_AddCRL(cache, returned, &added);
                if (PR_TRUE != added)
                {
                    rv = CachedCrl_Destroy(returned);
                    returned = NULL;
                }
                else
                {
                    rv = CachedCrl_Verify(cache, returned, vfdate, wincx);
                }
            }
            else
            {
                /* not enough memory to add the CRL to the cache. mark it
                   invalid so we will try again . */
                cache->invalid |= CRL_CACHE_LAST_FETCH_FAILED;
            }
            if (SECFailure == rv)
            {
                break;
            }
        }
    }

    if (head.arena)
    {
        CERTCrlNode* crlNode = NULL;
        /* clean up the CRL list in case we got a partial one
           during a failed fetch */
        for (crlNode = head.first; crlNode ; crlNode = crlNode->next)
        {
            if (crlNode->crl)
            {
                SEC_DestroyCrl(crlNode->crl); /* free the CRL. Either it got
                   added to the cache and the refcount got bumped, or not, and
                   thus we need to free its RAM */
            }
        }
        PORT_FreeArena(head.arena, PR_FALSE); /* destroy CRL list */
    }

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_GetUpToDate ( CRLDPCache *  cache,
CERTCertificate *  issuer,
PRBool  readlocked,
PRTime  vfdate,
void wincx 
) [static]

Definition at line 1742 of file crl.c.

{
    /* Update the CRLDPCache now. We don't cache token CRL lookup misses
       yet, as we have no way of getting notified of new PKCS#11 object
       creation that happens in a token  */
    SECStatus rv = SECSuccess;
    PRUint32 i = 0;
    PRBool forcedrefresh = PR_FALSE;
    PRBool dirty = PR_FALSE; /* whether something was changed in the
                                cache state during this update cycle */
    PRBool hastokenCRLs = PR_FALSE;
    PRTime now = 0;
    PRTime lastfetch = 0;

    if (!cache)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }

    /* first, make sure we have obtained all the CRLs we need.
       We do an expensive token fetch in the following cases :
       1) cache is empty because no fetch was ever performed yet
       2) cache is explicitly set to refresh state
       3) cache is in invalid state because last fetch failed
       4) cache contains no token CRLs, and it's been more than one minute
          since the last fetch
       5) cache contains token CRLs, and it's been more than 10 minutes since
          the last fetch
    */
    forcedrefresh = cache->refresh;
    lastfetch = cache->lastfetch;
    if (PR_TRUE != forcedrefresh && 
        (!(cache->invalid & CRL_CACHE_LAST_FETCH_FAILED)))
    {
        now = PR_Now();
        hastokenCRLs = DPCache_HasTokenCRLs(cache);
    }
    if ( (0 == lastfetch) ||

         (PR_TRUE == forcedrefresh) ||

         (cache->invalid & CRL_CACHE_LAST_FETCH_FAILED) ||

         ( (PR_FALSE == hastokenCRLs) &&
           ( (now - cache->lastfetch > CRLCache_Empty_TokenFetch_Interval) ||
             (now < cache->lastfetch)) ) ||

         ( (PR_TRUE == hastokenCRLs) &&
           ((now - cache->lastfetch > CRLCache_TokenRefetch_Interval) ||
            (now < cache->lastfetch)) ) )
    {
        /* the cache needs to be refreshed, and/or we had zero CRL for this
           DP. Try to get one from PKCS#11 tokens */
        DPCache_LockWrite();
        /* check if another thread updated before us, and skip update if so */
        if (lastfetch == cache->lastfetch)
        {
            /* we are the first */
            rv = DPCache_FetchFromTokens(cache, vfdate, wincx);
            if (PR_TRUE == cache->refresh)
            {
                cache->refresh = PR_FALSE; /* clear refresh state */
            }
            dirty = PR_TRUE;
            cache->lastfetch = PR_Now();
        }
        DPCache_UnlockWrite();
    }

    /* now, make sure we have no extraneous CRLs (deleted token objects)
       we'll do this inexpensive existence check either
       1) if there was a token object fetch
       2) every minute */
    if (( PR_TRUE != dirty) && (!now) )
    {
        now = PR_Now();
    }
    if ( (PR_TRUE == dirty) ||
         ( (now - cache->lastcheck > CRLCache_ExistenceCheck_Interval) ||
           (now < cache->lastcheck)) )
    {
        PRBool mustunlock = PR_FALSE;
        PRTime lastcheck = cache->lastcheck;
        /* check if all CRLs still exist */
        for (i = 0; (i < cache->ncrls) ; i++)
        {
            CachedCrl* savcrl = cache->crls[i];
            if ( (!savcrl) || (savcrl && CRL_OriginToken != savcrl->origin))
            {
                /* we only want to check token CRLs */
                continue;
            }
            if ((PR_TRUE != TokenCRLStillExists(savcrl->crl)))
            {
                
                /* this CRL is gone */
                if (PR_TRUE != mustunlock)
                {
                    DPCache_LockWrite();
                    mustunlock = PR_TRUE;
                }
                /* first, we need to check if another thread did an update
                   before we did */
                if (lastcheck == cache->lastcheck)
                {
                    /* the CRL is gone. And we are the one to do the update */
                    DPCache_RemoveCRL(cache, i);
                    dirty = PR_TRUE;
                }
                /* stay locked here intentionally so we do all the other
                   updates in this thread for the remaining CRLs */
            }
        }
        if (PR_TRUE == mustunlock)
        {
            cache->lastcheck = PR_Now();
            DPCache_UnlockWrite();
            mustunlock = PR_FALSE;
        }
    }

    /* add issuer certificate if it was previously unavailable */
    if (issuer && (NULL == cache->issuer) &&
        (SECSuccess == CERT_CheckCertUsage(issuer, KU_CRL_SIGN)))
    {
        /* if we didn't have a valid issuer cert yet, but we do now. add it */
        DPCache_LockWrite();
        if (!cache->issuer)
        {
            dirty = PR_TRUE;
            cache->issuer = CERT_DupCertificate(issuer);    
        }
        DPCache_UnlockWrite();
    }

    /* verify CRLs that couldn't be checked when inserted into the cache
       because the issuer cert or a verification date was unavailable.
       These are CRLs that were inserted into the cache through
       SEC_FindCrlByName, or through manual insertion, rather than through a
       certificate verification (CERT_CheckCRL) */

    if (cache->issuer && vfdate )
    {
        PRBool mustunlock = PR_FALSE;
        /* re-process all unverified CRLs */
        for (i = 0; i < cache->ncrls ; i++)
        {
            CachedCrl* savcrl = cache->crls[i];
            if (!savcrl)
            {
                continue;
            }
            if (PR_TRUE != savcrl->sigChecked)
            {
                if (PR_TRUE != mustunlock)
                {
                    DPCache_LockWrite();
                    mustunlock = PR_TRUE;
                }
                /* first, we need to check if another thread updated
                   it before we did, and abort if it has been modified since
                   we acquired the lock. Make sure first that the CRL is still
                   in the array at the same position */
                if ( (i<cache->ncrls) && (savcrl == cache->crls[i]) &&
                     (PR_TRUE != savcrl->sigChecked) )
                {
                    /* the CRL is still there, unverified. Do it */
                    CachedCrl_Verify(cache, savcrl, vfdate, wincx);
                    dirty = PR_TRUE;
                }
                /* stay locked here intentionally so we do all the other
                   updates in this thread for the remaining CRLs */
            }
            if (PR_TRUE == mustunlock)
            {
                DPCache_UnlockWrite();
                mustunlock = PR_FALSE;
            }
        }
    }

    if (dirty || cache->mustchoose)
    {
        /* changes to the content of the CRL cache necessitate examining all
           CRLs for selection of the most appropriate one to cache */
        DPCache_LockWrite();
        DPCache_SelectCRL(cache);
        cache->mustchoose = PR_FALSE;
        DPCache_UnlockWrite();
    }

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool DPCache_HasTokenCRLs ( CRLDPCache *  cache) [static]

Definition at line 2929 of file crl.c.

{
    PRBool answer = PR_FALSE;
    PRUint32 i;
    for (i=0;i<cache->ncrls;i++)
    {
        if (cache->crls[i] && (CRL_OriginToken == cache->crls[i]->origin) )
        {
            answer = PR_TRUE;
            break;
        }
    }
    return answer;
}

Here is the caller graph for this function:

static SECStatus DPCache_Lookup ( CRLDPCache *  cache,
SECItem *  sn,
CERTCrlEntry **  returned 
) [static]

Definition at line 1667 of file crl.c.

{
    CERTCrlEntry* acrlEntry = NULL;
    if (!cache || !sn || !returned)
    {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        /* no cache or SN to look up, or no way to return entry */
        return SECFailure;
    }
    if (0 != cache->invalid)
    {
        /* the cache contains a bad CRL, or there was a CRL fetching error.
           consider all certs revoked as a security measure */
        PORT_SetError(SEC_ERROR_CRL_INVALID);
        return SECFailure;
    }
    if (!cache->selected)
    {
        /* no CRL means no entry to return, but this is OK */
        *returned = NULL;
        return SECSuccess;
    }
    PORT_Assert(cache->selected->entries);
    if (!cache->selected->entries)
    {
        return SECFailure;
    }
    /* XXX should probably use CachedCrl accessor function here */
    acrlEntry = PL_HashTableLookup(cache->selected->entries, (void*)sn);
    if (acrlEntry)
    {
        *returned = acrlEntry;
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_RemoveCRL ( CRLDPCache *  cache,
PRUint32  offset 
) [static]

Definition at line 1377 of file crl.c.

{
    CachedCrl* acrl = NULL;
    PORT_Assert(cache);
    if (!cache || (!cache->crls) || (!(offset<cache->ncrls)) )
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    acrl = cache->crls[offset];
    PORT_Assert(acrl);
    if (!acrl)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    cache->crls[offset] = cache->crls[cache->ncrls-1];
    cache->crls[cache->ncrls-1] = NULL;
    cache->ncrls--;
    if (cache->selected == acrl) {
        cache->selected = NULL;
    }
    if (SECSuccess != CachedCrl_Destroy(acrl))
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus DPCache_SelectCRL ( CRLDPCache *  cache) [static]

Definition at line 2041 of file crl.c.

{
    PRUint32 i;
    PRBool valid = PR_TRUE;
    CachedCrl* selected = NULL;

    PORT_Assert(cache);
    if (!cache)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* if any invalid CRL is present, then the CRL cache is
       considered invalid, for security reasons */
    for (i = 0 ; i<cache->ncrls; i++)
    {
        if (!cache->crls[i] || !cache->crls[i]->sigChecked ||
            !cache->crls[i]->sigValid)
        {
            valid = PR_FALSE;
            break;
        }
    }
    if (PR_TRUE == valid)
    {
        /* all CRLs are valid, clear this error */
        cache->invalid &= (~CRL_CACHE_INVALID_CRLS);
    } else
    {
        /* some CRLs are invalid, set this error */
        cache->invalid |= CRL_CACHE_INVALID_CRLS;
    }

    if (cache->invalid)
    {
        /* cache is in an invalid state, so destroy it */
        if (cache->selected)
        {
            if (SECSuccess != CachedCrl_Depopulate(cache->selected))
            {
                PORT_Assert(0);
                return SECFailure;
            }
            cache->selected = NULL;
        }
        /* also sort the CRLs imperfectly */
        qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
              SortImperfectCRLs);
        return SECSuccess;
    }
    /* all CRLs are good, sort them by thisUpdate */
    qsort(cache->crls, cache->ncrls, sizeof(CachedCrl*),
          SortCRLsByThisUpdate);

    if (cache->ncrls)
    {
        /* pick the newest CRL */
        selected = cache->crls[cache->ncrls-1];
    
        /* and populate the cache */
        if (SECSuccess != CachedCrl_Populate(selected))
        {
            return SECFailure;
        }
    }

    /* free the old CRL cache, if it's for a different CRL */
    if (cache->selected && cache->selected != selected)
    {
        if (SECSuccess != CachedCrl_Depopulate(cache->selected))
        {
            return SECFailure;
        }
    }

    cache->selected = selected;

    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRIntn PR_CALLBACK FreeIssuer ( PLHashEntry he,
PRIntn  i,
void arg 
) [static]

Definition at line 1238 of file crl.c.

{
    CRLIssuerCache* issuer = NULL;
    SECStatus* rv = (SECStatus*) arg;

    PORT_Assert(he);
    if (!he)
    {
        return HT_ENUMERATE_NEXT;
    }
    issuer = (CRLIssuerCache*) he->value;
    PORT_Assert(issuer);
    if (issuer)
    {
        if (SECSuccess != IssuerCache_Destroy(issuer))
        {
            PORT_Assert(rv);
            if (rv)
            {
                *rv = SECFailure;
            }
            return HT_ENUMERATE_NEXT;
        }
    }
    return HT_ENUMERATE_NEXT;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static CERTSignedCrl* GetBestCRL ( CRLDPCache *  cache,
PRBool  entries 
) [static]

Definition at line 2286 of file crl.c.

{
    CachedCrl* acrl = NULL;

    PORT_Assert(cache);
    if (!cache)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return NULL;
    }

    if (0 == cache->ncrls)
    {
        /* empty cache*/
        return NULL;
    }    

    /* if we have a valid full CRL selected, return it */
    if (cache->selected)
    {
        return SEC_DupCrl(cache->selected->crl);
    }

    /* otherwise, use latest valid DER CRL */
    acrl = cache->crls[cache->ncrls-1];

    if (acrl && (PR_FALSE == GetOpaqueCRLFields(acrl->crl)->decodingError) )
    {
        SECStatus rv = SECSuccess;
        if (PR_TRUE == entries)
        {
            rv = CERT_CompleteCRLDecodeEntries(acrl->crl);
        }
        if (SECSuccess == rv)
        {
            return SEC_DupCrl(acrl->crl);
        }
    }

    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1087 of file crl.c.

{
    if (PR_FALSE == crlcache_initialized)
    {
        PORT_Assert(NULL == crlcache.lock);
        PORT_Assert(NULL == crlcache.issuers);
        if (crlcache.lock || crlcache.issuers)
        {
            /* CRL cache already partially initialized */
            PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
            return SECFailure;
        }
#ifdef GLOBAL_RWLOCK
        crlcache.lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
#else
        crlcache.lock = PR_NewLock();
#endif
        if (!crlcache.lock)
        {
            return SECFailure;
        }
        crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
                                  PL_CompareValues, NULL, NULL);
        if (!crlcache.issuers)
        {
#ifdef GLOBAL_RWLOCK
            NSSRWLock_Destroy(crlcache.lock);
#else
            PR_DestroyLock(crlcache.lock);
#endif
            crlcache.lock = NULL;
            return SECFailure;
        }
        crlcache_initialized = PR_TRUE;
        return SECSuccess;
    }
    else
    {
        PORT_Assert(crlcache.lock);
        PORT_Assert(crlcache.issuers);
        if ( (NULL == crlcache.lock) || (NULL == crlcache.issuers) )
        {
            /* CRL cache not fully initialized */
            return SECFailure;
        }
        else
        {
            /* CRL cache already initialized */
            return SECSuccess;
        }
    }
}
static SECStatus IssuerCache_AddDP ( CRLIssuerCache *  cache,
CERTCertificate *  issuer,
SECItem *  subject,
SECItem *  dp,
CRLDPCache **  newdpc 
) [static]

Definition at line 2210 of file crl.c.

{
    /* now create the required DP cache object */
    if (!cache || !subject || !newdpc)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (!dp)
    {
        /* default distribution point */
        SECStatus rv = DPCache_Create(&cache->dpp, issuer, subject, NULL);
        if (SECSuccess == rv)
        {
            *newdpc = cache->dpp;
            return SECSuccess;
        }
    }
    else
    {
        /* we should never hit this until we support multiple DPs */
        PORT_Assert(dp);
        /* XCRL allocate a new distribution point cache object, initialize it,
           and add it to the hash table of DPs */
    }
    return SECFailure;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static SECStatus IssuerCache_Create ( CRLIssuerCache **  returned,
CERTCertificate *  issuer,
SECItem *  subject,
SECItem *  dp 
) [static]

Definition at line 2163 of file crl.c.

{
    SECStatus rv = SECSuccess;
    CRLIssuerCache* cache = NULL;
    PORT_Assert(returned);
    PORT_Assert(subject);
    /* issuer and dp are allowed to be NULL */
    if (!returned || !subject)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    *returned = NULL;
    cache = (CRLIssuerCache*) PORT_ZAlloc(sizeof(CRLIssuerCache));
    if (!cache)
    {
        return SECFailure;
    }
    cache->subject = SECITEM_DupItem(subject);
#ifdef XCRL
    cache->lock = NSSRWLock_New(NSS_RWLOCK_RANK_NONE, NULL);
    if (!cache->lock)
    {
        rv = SECFailure;
    }
    if (SECSuccess == rv && issuer)
    {
        cache->issuer = CERT_DupCertificate(issuer);
        if (!cache->issuer)
        {
            rv = SECFailure;
        }
    }
#endif
    if (SECSuccess != rv)
    {
        PORT_Assert(SECSuccess == IssuerCache_Destroy(cache));
        return SECFailure;
    }
    *returned = cache;
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus IssuerCache_Destroy ( CRLIssuerCache *  cache)

Definition at line 1198 of file crl.c.

{
    PORT_Assert(cache);
    if (!cache)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
#ifdef XCRL
    if (cache->lock)
    {
        NSSRWLock_Destroy(cache->lock);
    }
    else
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    if (cache->issuer)
    {
        CERT_DestroyCertificate(cache->issuer);
    }
#endif
    /* free the subject */
    if (cache->subject)
    {
        SECITEM_FreeItem(cache->subject, PR_TRUE);
    }
    if (SECSuccess != DPCache_Destroy(cache->dpp))
    {
        PORT_Assert(0);
        return SECFailure;
    }
    PORT_Free(cache);
    return SECSuccess;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static CRLDPCache * IssuerCache_GetDPCache ( CRLIssuerCache *  cache,
SECItem *  dp 
) [static]

Definition at line 2329 of file crl.c.

{
    CRLDPCache* dpp = NULL;
    PORT_Assert(cache);
    /* XCRL for now we only support the "default" DP, ie. the
       full CRL. So we can return the global one without locking. In
       the future we will have a lock */
    PORT_Assert(NULL == dp);
    if (!cache || dp)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return NULL;
    }
#ifdef XCRL
    NSSRWLock_LockRead(cache->lock);
#endif
    dpp = cache->dpp;
#ifdef XCRL
    NSSRWLock_UnlockRead(cache->lock);
#endif
    return dpp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

PreAllocator* PreAllocator_Create ( PRSize  size)

Definition at line 1033 of file crl.c.

{
    PreAllocator prebuffer;
    PreAllocator* prepointer = NULL;
    memset(&prebuffer, 0, sizeof(PreAllocator));
    prebuffer.len = size;
    prebuffer.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    PORT_Assert(prebuffer.arena);
    if (!prebuffer.arena)
    {
        PreAllocator_Destroy(&prebuffer);
        return NULL;
    }
    if (prebuffer.len)
    {
        prebuffer.data = PORT_Alloc(prebuffer.len);
        if (!prebuffer.data)
        {
            PreAllocator_Destroy(&prebuffer);
            return NULL;
        }
    }
    else
    {
        prebuffer.data = NULL;
    }
    prepointer = (PreAllocator*)PORT_Alloc(sizeof(PreAllocator));
    if (!prepointer)
    {
        PreAllocator_Destroy(&prebuffer);
        return NULL;
    }
    *prepointer = prebuffer;
    return prepointer;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void PreAllocator_Destroy ( PreAllocator *  PreAllocator)

Definition at line 1015 of file crl.c.

{
    if (!PreAllocator)
    {
        return;
    }
    if (PreAllocator->arena)
    {
        PORT_FreeArena(PreAllocator->arena, PR_TRUE);
    }
    if (PreAllocator->data)
    {
        PORT_Free(PreAllocator->data);
    }
    PORT_Free(PreAllocator);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PLHashEntry* PR_CALLBACK PreAllocEntry ( void pool,
const void key 
) [static]

Definition at line 995 of file crl.c.

{
    return PreAllocTable(pool, sizeof(PLHashEntry));
}

Here is the call graph for this function:

static void* PR_CALLBACK PreAllocTable ( void pool,
PRSize  size 
) [static]

Definition at line 966 of file crl.c.

{
    PreAllocator* alloc = (PreAllocator*)pool;
    PORT_Assert(alloc);
    if (!alloc)
    {
        /* no allocator, or buffer full */
        return NULL;
    }
    if (size > (alloc->len - alloc->used))
    {
        /* initial buffer full, let's use the arena */
        alloc->extra += size;
        return PORT_ArenaAlloc(alloc->arena, size);
    }
    /* use the initial buffer */
    alloc->used += size;
    return (char*) alloc->data + alloc->used - size;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void PR_CALLBACK PreFreeEntry ( void pool,
PLHashEntry he,
PRUintn  flag 
) [static]

Definition at line 1003 of file crl.c.

{
}
static void PR_CALLBACK PreFreeTable ( void pool,
void item 
) [static]

Definition at line 989 of file crl.c.

{
}
static void ReleaseDPCache ( CRLDPCache *  dpcache,
PRBool  writeLocked 
) [static]

Definition at line 2526 of file crl.c.

{
    if (!dpcache)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return;
    }
#ifdef DPC_RWLOCK
    if (PR_TRUE == writeLocked)
    {
        NSSRWLock_UnlockWrite(dpcache->lock);
    }
    else
    {
        NSSRWLock_UnlockRead(dpcache->lock);
    }
#else
    PR_Unlock(dpcache->lock);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

SECStatus SEC_DestroyCrl ( CERTSignedCrl *  crl)

Definition at line 829 of file crl.c.

{
    if (crl) {
       if (PR_AtomicDecrement(&crl->referenceCount) < 1) {
           if (crl->slot) {
              PK11_FreeSlot(crl->slot);
           }
            if (GetOpaqueCRLFields(crl) &&
                PR_TRUE == GetOpaqueCRLFields(crl)->heapDER) {
                SECITEM_FreeItem(crl->derCrl, PR_TRUE);
            }
            if (crl->arena) {
                PORT_FreeArena(crl->arena, PR_FALSE);
            }
       }
        return SECSuccess;
    } else {
        return SECFailure;
    }
}
CERTSignedCrl* SEC_DupCrl ( CERTSignedCrl *  acrl)

Definition at line 818 of file crl.c.

{
    if (acrl)
    {
        PR_AtomicIncrement(&acrl->referenceCount);
        return acrl;
    }
    return NULL;
}
CERTSignedCrl* SEC_FindCrlByDERCert ( CERTCertDBHandle *  handle,
SECItem *  derCrl,
int  type 
)

Definition at line 791 of file crl.c.

{
    PRArenaPool *arena;
    SECItem crlKey;
    SECStatus rv;
    CERTSignedCrl *crl = NULL;
    
    /* create a scratch arena */
    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if ( arena == NULL ) {
       return(NULL);
    }
    
    /* extract the database key from the cert */
    rv = CERT_KeyFromDERCrl(arena, derCrl, &crlKey);
    if ( rv != SECSuccess ) {
       goto loser;
    }

    /* find the crl */
    crl = SEC_FindCrlByName(handle, &crlKey, type);
    
loser:
    PORT_FreeArena(arena, PR_FALSE);
    return(crl);
}
static SECStatus SEC_FindCrlByKeyOnSlot ( PK11SlotInfo *  slot,
SECItem *  crlKey,
int  type,
CERTSignedCrl **  decoded,
PRInt32  decodeoptions 
) [static]

Definition at line 624 of file crl.c.

{
    SECStatus rv = SECSuccess;
    CERTSignedCrl *crl = NULL;
    SECItem *derCrl = NULL;
    CK_OBJECT_HANDLE crlHandle = 0;
    char *url = NULL;

    PORT_Assert(decoded);
    if (!decoded) {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return SECFailure;
    }

    derCrl = PK11_FindCrlByName(&slot, &crlHandle, crlKey, type, &url);
    if (derCrl == NULL) {
       /* if we had a problem other than the CRL just didn't exist, return
        * a failure to the upper level */
       int nsserror = PORT_GetError();
       if (nsserror != SEC_ERROR_CRL_NOT_FOUND) {
           rv = SECFailure;
       }
       goto loser;
    }
    PORT_Assert(crlHandle != CK_INVALID_HANDLE);
    /* PK11_FindCrlByName obtained a slot reference. */
    
    /* derCRL is a fresh HEAP copy made for us by PK11_FindCrlByName.
       Force adoption of the DER CRL from the heap - this will cause it 
       to be automatically freed when SEC_DestroyCrl is invoked */
    decodeoptions |= (CRL_DECODE_ADOPT_HEAP_DER | CRL_DECODE_DONT_COPY_DER);

    crl = CERT_DecodeDERCrlWithFlags(NULL, derCrl, type, decodeoptions);
    if (crl) {
        crl->slot = slot;
        slot = NULL; /* adopt it */
       derCrl = NULL; /* adopted by the crl struct */
        crl->pkcs11ID = crlHandle;
        if (url) {
            crl->url = PORT_ArenaStrdup(crl->arena,url);
        }
    } else {
        rv = SECFailure;
    }
    
    if (url) {
       PORT_Free(url);
    }

    if (slot) {
       PK11_FreeSlot(slot);
    }

loser:
    if (derCrl) {
       SECITEM_FreeItem(derCrl, PR_TRUE);
    }

    *decoded = crl;

    return rv;
}

Here is the call graph for this function:

Here is the caller graph for this function:

CERTSignedCrl* SEC_FindCrlByName ( CERTCertDBHandle *  handle,
SECItem *  crlKey,
int  type 
)

Definition at line 2616 of file crl.c.

{
    CERTSignedCrl* acrl = NULL;
    CRLDPCache* dpcache = NULL;
    SECStatus rv = SECSuccess;
    PRBool writeLocked = PR_FALSE;

    if (!crlKey)
    {
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
        return NULL;
    }

    rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &dpcache, &writeLocked);
    if (SECSuccess == rv)
    {
        acrl = GetBestCRL(dpcache, PR_TRUE); /* decode entries, because
        SEC_FindCrlByName always returned fully decoded CRLs in the past */
        ReleaseDPCache(dpcache, writeLocked);
    }
    return acrl;
}
SECStatus SEC_LookupCrls ( CERTCertDBHandle *  handle,
CERTCrlHeadNode **  nodes,
int  type 
)

Definition at line 851 of file crl.c.

{
    CERTCrlHeadNode *head;
    PRArenaPool *arena = NULL;
    SECStatus rv;

    *nodes = NULL;

    arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
    if ( arena == NULL ) {
       return SECFailure;
    }

    /* build a head structure */
    head = (CERTCrlHeadNode *)PORT_ArenaAlloc(arena, sizeof(CERTCrlHeadNode));
    head->arena = arena;
    head->first = NULL;
    head->last = NULL;
    head->dbhandle = handle;

    /* Look up the proper crl types */
    *nodes = head;

    rv = PK11_LookupCrls(head, type, NULL);
    
    if (rv != SECSuccess) {
       if ( arena ) {
           PORT_FreeArena(arena, PR_FALSE);
           *nodes = NULL;
       }
    }

    return rv;
}
CERTSignedCrl* SEC_NewCrl ( CERTCertDBHandle *  handle,
char *  url,
SECItem *  derCrl,
int  type 
)

Definition at line 779 of file crl.c.

{
    CERTSignedCrl* retCrl = NULL;
    PK11SlotInfo* slot = PK11_GetInternalKeySlot();
    retCrl = PK11_ImportCRL(slot, derCrl, url, type, NULL,
        CRL_IMPORT_BYPASS_CHECKS, NULL, CRL_DECODE_DEFAULT_OPTIONS);
    PK11_FreeSlot(slot);

    return retCrl;
}

Definition at line 1270 of file crl.c.

{
    SECStatus rv = SECSuccess;
    if (PR_FALSE == crlcache_initialized &&
        !crlcache.lock && !crlcache.issuers)
    {
        /* CRL cache has already been shut down */
        return SECSuccess;
    }
    if (PR_TRUE == crlcache_initialized &&
        (!crlcache.lock || !crlcache.issuers))
    {
        /* CRL cache has partially been shut down */
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        return SECFailure;
    }
    /* empty the cache */
    /* free the issuers */
    PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv);
    /* free the hash table of issuers */
    PL_HashTableDestroy(crlcache.issuers);
    crlcache.issuers = NULL;
    /* free the global lock */
#ifdef GLOBAL_RWLOCK
    NSSRWLock_Destroy(crlcache.lock);
#else
    PR_DestroyLock(crlcache.lock);
#endif
    crlcache.lock = NULL;
    crlcache_initialized = PR_FALSE;
    return rv;
}
static int SortCRLsByThisUpdate ( const void arg1,
const void arg2 
) [static]

Definition at line 1940 of file crl.c.

{
    PRTime timea, timeb;
    SECStatus rv = SECSuccess;
    CachedCrl* a, *b;

    a = *(CachedCrl**) arg1;
    b = *(CachedCrl**) arg2;

    if (!a || !b)
    {
        PORT_Assert(0);
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        rv = SECFailure;
    }

    if (SECSuccess == rv)
    {
        rv = DER_DecodeTimeChoice(&timea, &a->crl->crl.lastUpdate);
    }                       
    if (SECSuccess == rv)
    {
        rv = DER_DecodeTimeChoice(&timeb, &b->crl->crl.lastUpdate);
    }
    if (SECSuccess == rv)
    {
        if (timea > timeb)
        {
            return 1; /* a is better than b */
        }
        if (timea < timeb )
        {
            return -1; /* a is not as good as b */
        }
    }

    /* if they are equal, or if all else fails, use pointer differences */
    PORT_Assert(a != b); /* they should never be equal */
    return a>b?1:-1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static int SortImperfectCRLs ( const void arg1,
const void arg2 
) [static]

Definition at line 1988 of file crl.c.

{
    CachedCrl* a, *b;

    a = *(CachedCrl**) arg1;
    b = *(CachedCrl**) arg2;

    if (!a || !b)
    {
        PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
        PORT_Assert(0);
    }
    else
    {
        PRBool aDecoded = PR_FALSE, bDecoded = PR_FALSE;
        if ( (PR_TRUE == a->sigValid) && (PR_TRUE == b->sigValid) )
        {
            /* both CRLs have been validated, choose the latest one */
            return SortCRLsByThisUpdate(arg1, arg2);
        }
        if (PR_TRUE == a->sigValid)
        {
            return 1; /* a is greater than b */
        }
        if (PR_TRUE == b->sigValid)
        {
            return -1; /* a is not as good as b */
        }
        aDecoded = GetOpaqueCRLFields(a->crl)->decodingError;
        bDecoded = GetOpaqueCRLFields(b->crl)->decodingError;
        /* neither CRL had its signature check pass */
        if ( (PR_FALSE == aDecoded) && (PR_FALSE == bDecoded) )
        {
            /* both CRLs are proper DER, choose the latest one */
            return SortCRLsByThisUpdate(arg1, arg2);
        }
        if (PR_FALSE == aDecoded)
        {
            return 1; /* a is better than b */
        }
        if (PR_FALSE == bDecoded)
        {
            return -1; /* a is not as good as b */
        }
        /* both are invalid DER. sigh. */
    }
    /* if they are equal, or if all else fails, use pointer differences */
    PORT_Assert(a != b); /* they should never be equal */
    return a>b?1:-1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool TokenCRLStillExists ( CERTSignedCrl *  crl) [static]

Definition at line 1416 of file crl.c.

{
    NSSItem newsubject;
    SECItem subject;
    CK_ULONG crl_class;
    PRStatus status;
    PK11SlotInfo* slot = NULL;
    nssCryptokiObject instance;
    NSSArena* arena;
    PRBool xstatus = PR_TRUE;
    SECItem* oldSubject = NULL;

    PORT_Assert(crl);
    if (!crl)
    {
        return PR_FALSE;
    }
    slot = crl->slot;
    PORT_Assert(crl->slot);
    if (!slot)
    {
        return PR_FALSE;
    }
    oldSubject = &crl->crl.derName;
    PORT_Assert(oldSubject);
    if (!oldSubject)
    {
        return PR_FALSE;
    }

    /* query subject and type attributes in order to determine if the
       object has been deleted */

    /* first, make an nssCryptokiObject */
    instance.handle = crl->pkcs11ID;
    PORT_Assert(instance.handle);
    if (!instance.handle)
    {
        return PR_FALSE;
    }
    instance.token = PK11Slot_GetNSSToken(slot);
    PORT_Assert(instance.token);
    if (!instance.token)
    {
        return PR_FALSE;
    }
    instance.isTokenObject = PR_TRUE;
    instance.label = NULL;

    arena = NSSArena_Create();
    PORT_Assert(arena);
    if (!arena)
    {
        return PR_FALSE;
    }

    status = nssCryptokiCRL_GetAttributes(&instance,
                                          NULL,  /* XXX sessionOpt */
                                          arena,
                                          NULL,
                                          &newsubject,  /* subject */
                                          &crl_class,   /* class */
                                          NULL,
                                          NULL);
    if (PR_SUCCESS == status)
    {
        subject.data = newsubject.data;
        subject.len = newsubject.size;
        if (SECITEM_CompareItem(oldSubject, &subject) != SECEqual)
        {
            xstatus = PR_FALSE;
        }
        if (CKO_NETSCAPE_CRL != crl_class)
        {
            xstatus = PR_FALSE;
        }
    }
    else
    {
        xstatus = PR_FALSE;
    }
    NSSArena_Destroy(arena);
    return xstatus;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTCrlEntry) },
    { SEC_ASN1_INTEGER,
         offsetof(CERTCrlEntry,serialNumber) },
    { SEC_ASN1_INLINE,
         offsetof(CERTCrlEntry,revocationDate), CERT_TimeChoiceTemplate },
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
         offsetof(CERTCrlEntry, extensions),
         SEC_CERTExtensionTemplate},
    { 0 }
}

Definition at line 153 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTCrlKey) },
    { SEC_ASN1_INTEGER | SEC_ASN1_OPTIONAL, offsetof(CERTCrlKey,dummy) },
    { SEC_ASN1_SKIP },
    { SEC_ASN1_ANY, offsetof(CERTCrlKey,derName) },
    { SEC_ASN1_SKIP_REST },
    { 0 }
}

Definition at line 143 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTIssuerAndSN) },
    { SEC_ASN1_SAVE,
         offsetof(CERTIssuerAndSN,derIssuer) },
    { SEC_ASN1_INLINE,
         offsetof(CERTIssuerAndSN,issuer),
         CERT_NameTemplate },
    { SEC_ASN1_INTEGER,
         offsetof(CERTIssuerAndSN,serialNumber) },
    { 0 }
}

Definition at line 83 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTCrlEntry) },
    { SEC_ASN1_OCTET_STRING,
         offsetof(CERTCrlEntry,serialNumber) },
    { SEC_ASN1_UTC_TIME,
         offsetof(CERTCrlEntry,revocationDate) },
    { 0 }
}

Definition at line 96 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTCrl) },
    { SEC_ASN1_INLINE,
         offsetof(CERTCrl,signatureAlg),
         SECOID_AlgorithmIDTemplate },
    { SEC_ASN1_SAVE,
         offsetof(CERTCrl,derName) },
    { SEC_ASN1_INLINE,
         offsetof(CERTCrl,name),
         CERT_NameTemplate },
    { SEC_ASN1_UTC_TIME,
         offsetof(CERTCrl,lastUpdate) },
    { SEC_ASN1_UTC_TIME,
         offsetof(CERTCrl,nextUpdate) },
    { SEC_ASN1_OPTIONAL | SEC_ASN1_SEQUENCE_OF,
         offsetof(CERTCrl,entries),
         cert_KrlEntryTemplate },
    { 0 }
}

Definition at line 106 of file crl.c.

Initial value:

Definition at line 266 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTSignedCrl) },
    { SEC_ASN1_SAVE,
         offsetof(CERTSignedCrl,signatureWrap.data) },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,crl),
         CERT_CrlTemplate },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
         SECOID_AlgorithmIDTemplate },
    { SEC_ASN1_BIT_STRING,
         offsetof(CERTSignedCrl,signatureWrap.signature) },
    { 0 }
}

Definition at line 234 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTSignedCrl) },
    { SEC_ASN1_SAVE,
         offsetof(CERTSignedCrl,signatureWrap.data) },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,crl),
         CERT_CrlTemplateNoEntries },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
         SECOID_AlgorithmIDTemplate },
    { SEC_ASN1_BIT_STRING,
         offsetof(CERTSignedCrl,signatureWrap.signature) },
    { 0 }
}

Definition at line 250 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTSignedCrl) },
    { SEC_ASN1_SAVE,
         offsetof(CERTSignedCrl,signatureWrap.data) },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,crl),
         cert_KrlTemplate },
    { SEC_ASN1_INLINE,
         offsetof(CERTSignedCrl,signatureWrap.signatureAlgorithm),
         SECOID_AlgorithmIDTemplate },
    { SEC_ASN1_BIT_STRING,
         offsetof(CERTSignedCrl,signatureWrap.signature) },
    { 0 }
}

Definition at line 127 of file crl.c.

CRLCache crlcache = { NULL, NULL } [static]

Definition at line 1070 of file crl.c.

Definition at line 1075 of file crl.c.

Definition at line 1083 of file crl.c.

Definition at line 1073 of file crl.c.

Definition at line 1079 of file crl.c.

Initial value:

Definition at line 1008 of file crl.c.

Initial value:

Definition at line 73 of file crl.c.

Initial value:
 {
    { SEC_ASN1_SEQUENCE,
         0, NULL, sizeof(CERTCertExtension) },
    { SEC_ASN1_OBJECT_ID,
         offsetof(CERTCertExtension,id) },
    { SEC_ASN1_OPTIONAL | SEC_ASN1_BOOLEAN,             
         offsetof(CERTCertExtension,critical), },
    { SEC_ASN1_OCTET_STRING,
         offsetof(CERTCertExtension,value) },
    { 0, }
}

Definition at line 61 of file crl.c.