diff options
author | julien.pierre.boogz%sun.com <devnull@localhost> | 2009-04-17 22:46:54 +0000 |
---|---|---|
committer | julien.pierre.boogz%sun.com <devnull@localhost> | 2009-04-17 22:46:54 +0000 |
commit | 9718f4d8a3d959274ed77c0fea7d05307485b63b (patch) | |
tree | 957769e2d2cf931f9859b7d873ea84872d5b13e2 | |
parent | 43dbf6a86cf9c0572cf2fffdc9b0eb5d0e30727f (diff) | |
download | nss-hg-9718f4d8a3d959274ed77c0fea7d05307485b63b.tar.gz |
Fix for bug 321755 . Changes in CRL cache to implement CRL DP. Work in progress, not reviewed, per Nelson and Alexei.
-rw-r--r-- | security/nss/lib/certdb/cert.h | 2 | ||||
-rw-r--r-- | security/nss/lib/certdb/certi.h | 79 | ||||
-rw-r--r-- | security/nss/lib/certdb/crl.c | 466 | ||||
-rwxr-xr-x | security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c | 12 |
4 files changed, 505 insertions, 54 deletions
diff --git a/security/nss/lib/certdb/cert.h b/security/nss/lib/certdb/cert.h index ad77cb743..f43117f7e 100644 --- a/security/nss/lib/certdb/cert.h +++ b/security/nss/lib/certdb/cert.h @@ -1525,7 +1525,7 @@ CERT_GetSPKIDigest(PLArenaPool *arena, const CERTCertificate *cert, SECStatus CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, - SECItem* dp, PRTime t, void* wincx); + const SECItem* dp, PRTime t, void* wincx); /* diff --git a/security/nss/lib/certdb/certi.h b/security/nss/lib/certdb/certi.h index 4cd1fef2d..a33801c2c 100644 --- a/security/nss/lib/certdb/certi.h +++ b/security/nss/lib/certdb/certi.h @@ -58,6 +58,8 @@ typedef struct CRLDPCacheStr CRLDPCache; typedef struct CRLIssuerCacheStr CRLIssuerCache; typedef struct CRLCacheStr CRLCache; typedef struct CachedCrlStr CachedCrl; +typedef struct NamedCRLCacheStr NamedCRLCache; +typedef struct NamedCRLCacheEntryStr NamedCRLCacheEntry; struct OpaqueCRLFieldsStr { PRBool partial; @@ -103,6 +105,17 @@ typedef enum { CRL_OriginExplicit = 1 /* CRL was explicitly added to the cache, from RAM */ } CRLOrigin; +typedef enum { + dpcacheNoEntry = 0, /* no entry found for this SN */ + dpcacheFoundEntry = 1, /* entry found for this SN */ + dpcacheCallerError = 2, /* invalid args */ + dpcacheInvalidCacheError = 3, /* CRL in cache may be bad DER */ + /* or unverified */ + dpcacheEmpty = 4, /* no CRL in cache */ + dpcacheLookupError = 5 /* internal error */ +} dpcacheStatus; + + struct CachedCrlStr { CERTSignedCrl* crl; CRLOrigin origin; @@ -257,13 +270,13 @@ extern CERTAVA * CERT_CreateAVAFromSECItem(PRArenaPool *arena, SECOidTag kind, * get a DPCache object for the given issuer subject and dp * Automatically creates the cache object if it doesn't exist yet. */ -SECStatus AcquireDPCache(CERTCertificate* issuer, SECItem* subject, - SECItem* dp, int64 t, void* wincx, +SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject, + const SECItem* dp, int64 t, void* wincx, CRLDPCache** dpcache, PRBool* writeLocked); /* check if a particular SN is in the CRL cache and return its entry */ -SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, - CERTCrlEntry** returned); +dpcacheStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, + CERTCrlEntry** returned); /* release a DPCache object that was previously acquired */ void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked); @@ -315,5 +328,63 @@ void cert_AddToVerifyLog(CERTVerifyLog *log,CERTCertificate *cert, unsigned long errorCode, unsigned int depth, void *arg); +/* Insert a DER CRL into the CRL cache, and take ownership of it. + * + * This function takes ownership of the memory in crl argument completely. + * crl must be freeable by SECITEM_FreeItem. It will be freed immediately + * if it is rejected from the CRL cache, or later during cache updates when + * a new crl is available, or at shutdown time. + * + * canonicalizedName represents the source of the CRL (a GeneralName). This + * should be canonicalized by the caller, since this function will not attempt + * to do any name matching. + * + */ + +SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl, + const SECItem* canonicalizedName); + +struct NamedCRLCacheStr { + PRLock* lock; + PLHashTable* entries; +}; + +struct NamedCRLCacheEntryStr { + SECItem* crl; /* DER, kept only if CRL + * is successfully cached */ + PRBool inCRLCache; + PRTime successfulInsertionTime; /* insertion time */ + PRTime lastAttemptTime; /* time of last call to + cert_CacheCRLByGeneralName with this name */ + PRBool badDER; /* ASN.1 error */ + PRBool dupe; /* matching DER CRL already in CRL cache */ + PRBool unsupported; /* IDP, delta, any other reason */ +}; + +typedef enum { + certRevocationStatusRevoked = 0, + certRevocationStatusValid = 1, + certRevocationStatusUnknown = 2, +} CERTRevocationStatus; + +/* Returns detailed status of the cert(revStatus variable). Tells if + * issuer cache has OriginFetchedWithTimeout crl in it. */ +SECStatus +cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer, + const SECItem* dp, PRTime t, void *wincx, + CERTRevocationStatus *revStatus, + CERTCRLEntryReasonCode *revReason); + + +SECStatus cert_AcquireNamedCRLCache(); + +/* This must be called only while cache is acquired, and the entry is only + * valid until cache is released. + */ +SECStatus cert_FindCRLByGeneralName(const SECItem* canonicalizedName, + NamedCRLCacheEntry** retEntry); + +SECStatus cert_ReleaseNamedCRLCache(); + #endif /* _CERTI_H_ */ diff --git a/security/nss/lib/certdb/crl.c b/security/nss/lib/certdb/crl.c index 6f8d141bd..7d362c870 100644 --- a/security/nss/lib/certdb/crl.c +++ b/security/nss/lib/certdb/crl.c @@ -936,7 +936,7 @@ static SECStatus CachedCrl_Compare(CachedCrl* a, CachedCrl* b, PRBool* isDupe, /* create a DPCache object */ static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer, - SECItem* subject, SECItem* dp); + const SECItem* subject, SECItem* dp); /* destructor for CRL DPCache object */ static SECStatus DPCache_Destroy(CRLDPCache* cache); @@ -967,18 +967,20 @@ static SECStatus DPCache_SelectCRL(CRLDPCache* cache); /* create an issuer cache object (per CA subject ) */ static SECStatus IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer, - SECItem* subject, SECItem* dp); + const SECItem* subject, const SECItem* dp); /* destructor for CRL IssuerCache object */ SECStatus IssuerCache_Destroy(CRLIssuerCache* cache); /* add a DPCache to the issuer cache */ static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, - CERTCertificate* issuer, SECItem* subject, - SECItem* dp, CRLDPCache** newdpc); + CERTCertificate* issuer, + const SECItem* subject, + const SECItem* dp, CRLDPCache** newdpc); /* get a particular DPCache object from an IssuerCache */ -static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp); +static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, + const SECItem* dp); /* ** Pre-allocator hash allocator ops. @@ -1089,6 +1091,9 @@ PreAllocator* PreAllocator_Create(PRSize size) return prepointer; } +/* global Named CRL cache object */ +static NamedCRLCache namedCRLCache = { NULL, NULL }; + /* global CRL cache object */ static CRLCache crlcache = { NULL, NULL }; @@ -1113,7 +1118,10 @@ SECStatus InitCRLCache(void) { PORT_Assert(NULL == crlcache.lock); PORT_Assert(NULL == crlcache.issuers); - if (crlcache.lock || crlcache.issuers) + PORT_Assert(NULL == namedCRLCache.lock); + PORT_Assert(NULL == namedCRLCache.entries); + if (crlcache.lock || crlcache.issuers || namedCRLCache.lock || + namedCRLCache.entries) { /* CRL cache already partially initialized */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); @@ -1124,20 +1132,39 @@ SECStatus InitCRLCache(void) #else crlcache.lock = PR_NewLock(); #endif - if (!crlcache.lock) - { - return SECFailure; - } + namedCRLCache.lock = PR_NewLock(); crlcache.issuers = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, PL_CompareValues, NULL, NULL); - if (!crlcache.issuers) + namedCRLCache.entries = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare, + PL_CompareValues, NULL, NULL); + if (!crlcache.lock || !namedCRLCache.lock || !crlcache.issuers || + !namedCRLCache.entries) { + if (crlcache.lock) + { #ifdef GLOBAL_RWLOCK - NSSRWLock_Destroy(crlcache.lock); + NSSRWLock_Destroy(crlcache.lock); #else - PR_DestroyLock(crlcache.lock); + PR_DestroyLock(crlcache.lock); #endif - crlcache.lock = NULL; + crlcache.lock = NULL; + } + if (namedCRLCache.lock) + { + PR_DestroyLock(namedCRLCache.lock); + namedCRLCache.lock = NULL; + } + if (crlcache.issuers) + { + PL_HashTableDestroy(crlcache.issuers); + crlcache.issuers = NULL; + } + if (namedCRLCache.entries) + { + PL_HashTableDestroy(namedCRLCache.entries); + namedCRLCache.entries = NULL; + } + return SECFailure; } crlcache_initialized = PR_TRUE; @@ -1257,6 +1284,44 @@ SECStatus IssuerCache_Destroy(CRLIssuerCache* cache) return SECSuccess; } +/* create a named CRL entry object */ +static SECStatus NamedCRLCacheEntry_Create(NamedCRLCacheEntry** returned) +{ + NamedCRLCacheEntry* entry = NULL; + if (!returned) + { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + *returned = NULL; + entry = (NamedCRLCacheEntry*) PORT_ZAlloc(sizeof(NamedCRLCacheEntry)); + if (!entry) + { + return SECFailure; + } + *returned = entry; + return SECSuccess; +} + +/* destroy a named CRL entry object */ +static SECStatus NamedCRLCacheEntry_Destroy(NamedCRLCacheEntry* entry) +{ + if (!entry) + { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + if (entry->crl) + { + /* named CRL cache owns DER memory */ + SECITEM_ZfreeItem(entry->crl, PR_TRUE); + } + PORT_Free(entry); + return SECSuccess; +} + /* callback function used in hash table destructor */ static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg) { @@ -1285,6 +1350,34 @@ static PRIntn PR_CALLBACK FreeIssuer(PLHashEntry *he, PRIntn i, void *arg) return HT_ENUMERATE_NEXT; } +/* callback function used in hash table destructor */ +static PRIntn PR_CALLBACK FreeNamedEntries(PLHashEntry *he, PRIntn i, void *arg) +{ + NamedCRLCacheEntry* entry = NULL; + SECStatus* rv = (SECStatus*) arg; + + PORT_Assert(he); + if (!he) + { + return HT_ENUMERATE_NEXT; + } + entry = (NamedCRLCacheEntry*) he->value; + PORT_Assert(entry); + if (entry) + { + if (SECSuccess != NamedCRLCacheEntry_Destroy(entry)) + { + PORT_Assert(rv); + if (rv) + { + *rv = SECFailure; + } + return HT_ENUMERATE_NEXT; + } + } + return HT_ENUMERATE_NEXT; +} + /* needs to be called at NSS shutdown time This will destroy the global CRL cache, including - the hash table of issuer cache objects @@ -1300,13 +1393,14 @@ SECStatus ShutdownCRLCache(void) return SECSuccess; } if (PR_TRUE == crlcache_initialized && - (!crlcache.lock || !crlcache.issuers)) + (!crlcache.lock || !crlcache.issuers || !namedCRLCache.lock || + !namedCRLCache.entries)) { /* CRL cache has partially been shut down */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - /* empty the cache */ + /* empty the CRL cache */ /* free the issuers */ PL_HashTableEnumerateEntries(crlcache.issuers, &FreeIssuer, &rv); /* free the hash table of issuers */ @@ -1319,6 +1413,18 @@ SECStatus ShutdownCRLCache(void) PR_DestroyLock(crlcache.lock); #endif crlcache.lock = NULL; + + /* empty the named CRL cache. This must be done after freeing the CRL + * cache, since some CRLs in this cache are in the memory for the other */ + /* free the entries */ + PL_HashTableEnumerateEntries(namedCRLCache.entries, &FreeNamedEntries, &rv); + /* free the hash table of issuers */ + PL_HashTableDestroy(namedCRLCache.entries); + namedCRLCache.entries = NULL; + /* free the global lock */ + PR_DestroyLock(namedCRLCache.lock); + namedCRLCache.lock = NULL; + crlcache_initialized = PR_FALSE; return rv; } @@ -1713,29 +1819,46 @@ static SECStatus CachedCrl_GetEntry(CachedCrl* crl, SECItem* sn, } /* check if a particular SN is in the CRL cache and return its entry */ -SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, - CERTCrlEntry** returned) +dpcacheStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, + CERTCrlEntry** returned) { + SECStatus rv; 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; + return dpcacheCallerError; } + *returned = NULL; 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; + return dpcacheInvalidCacheError; } if (!cache->selected) { - /* no CRL means no entry to return, but this is OK */ - *returned = NULL; - return SECSuccess; + /* no CRL means no entry to return. This is OK, except for + * NIST policy */ + return dpcacheEmpty; + } + rv = CachedCrl_GetEntry(cache->selected, sn, returned); + if (SECSuccess != rv) + { + return dpcacheLookupError; + } + else + { + if (*returned) + { + return dpcacheFoundEntry; + } + else + { + return dpcacheNoEntry; + } } - return CachedCrl_GetEntry(cache->selected, sn, returned); } #if defined(DPC_RWLOCK) @@ -2143,7 +2266,7 @@ static SECStatus DPCache_SelectCRL(CRLDPCache* cache) /* initialize a DPCache object */ static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer, - SECItem* subject, SECItem* dp) + const SECItem* subject, SECItem* dp) { CRLDPCache* cache = NULL; PORT_Assert(returned); @@ -2185,7 +2308,7 @@ static SECStatus DPCache_Create(CRLDPCache** returned, CERTCertificate* issuer, /* create an issuer cache object (per CA subject ) */ static SECStatus IssuerCache_Create(CRLIssuerCache** returned, CERTCertificate* issuer, - SECItem* subject, SECItem* dp) + const SECItem* subject, const SECItem* dp) { SECStatus rv = SECSuccess; CRLIssuerCache* cache = NULL; @@ -2232,7 +2355,8 @@ static SECStatus IssuerCache_Create(CRLIssuerCache** returned, /* add a DPCache to the issuer cache */ static SECStatus IssuerCache_AddDP(CRLIssuerCache* cache, CERTCertificate* issuer, - SECItem* subject, SECItem* dp, + const SECItem* subject, + const SECItem* dp, CRLDPCache** newdpc) { /* now create the required DP cache object */ @@ -2281,7 +2405,8 @@ static SECStatus CRLCache_AddIssuer(CRLIssuerCache* issuer) } /* retrieve the issuer cache object for a given issuer subject */ -static SECStatus CRLCache_GetIssuerCache(CRLCache* cache, SECItem* subject, +static SECStatus CRLCache_GetIssuerCache(CRLCache* cache, + const SECItem* subject, CRLIssuerCache** returned) { /* we need to look up the issuer in the hash table */ @@ -2351,7 +2476,7 @@ static CERTSignedCrl* GetBestCRL(CRLDPCache* cache, PRBool entries) } /* get a particular DPCache object from an IssuerCache */ -static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp) +static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, const SECItem* dp) { CRLDPCache* dpp = NULL; PORT_Assert(cache); @@ -2377,8 +2502,8 @@ static CRLDPCache* IssuerCache_GetDPCache(CRLIssuerCache* cache, SECItem* dp) /* get a DPCache object for the given issuer subject and dp Automatically creates the cache object if it doesn't exist yet. */ -SECStatus AcquireDPCache(CERTCertificate* issuer, SECItem* subject, - SECItem* dp, PRTime t, void* wincx, +SECStatus AcquireDPCache(CERTCertificate* issuer, const SECItem* subject, + const SECItem* dp, PRTime t, void* wincx, CRLDPCache** dpcache, PRBool* writeLocked) { SECStatus rv = SECSuccess; @@ -2569,21 +2694,36 @@ void ReleaseDPCache(CRLDPCache* dpcache, PRBool writeLocked) #endif } -/* check CRL revocation status of given certificate and issuer */ SECStatus -CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp, - PRTime t, void* wincx) +cert_CheckCertRevocationStatus(CERTCertificate* cert, CERTCertificate* issuer, + const SECItem* dp, PRTime t, void *wincx, + CERTRevocationStatus *revStatus, + CERTCRLEntryReasonCode *revReason) { PRBool lockedwrite = PR_FALSE; SECStatus rv = SECSuccess; CRLDPCache* dpcache = NULL; + CERTRevocationStatus status = certRevocationStatusRevoked; + CERTCRLEntryReasonCode reason = crlEntryReasonUnspecified; + CERTCrlEntry* entry = NULL; + dpcacheStatus ds; + if (!cert || !issuer) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - if (SECSuccess != CERT_CheckCertValidTimes(issuer, t, PR_FALSE)) + if (revStatus) + { + *revStatus = status; + } + if (revReason) + { + *revReason = reason; + } + + if (t && 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 @@ -2594,14 +2734,18 @@ CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp, rv = AcquireDPCache(issuer, &issuer->derSubject, dp, t, wincx, &dpcache, &lockedwrite); - - if (SECSuccess == rv) + PORT_Assert(SECSuccess == rv); + 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) - { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + /* now look up the certificate SN in the DP cache's CRL */ + ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry); + switch (ds) + { + case dpcacheFoundEntry: + PORT_Assert(entry); /* check the time if we have one */ if (entry->revocationDate.data && entry->revocationDate.len) { @@ -2616,26 +2760,74 @@ CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, SECItem* dp, { rv = SECFailure; } - } else { + else + { + status = certRevocationStatusValid; + } + } + else + { /* invalid revocation date, consider the certificate permanently revoked */ rv = SECFailure; } - } else { + } + else + { /* no revocation date, certificate is permanently revoked */ rv = SECFailure; } if (SECFailure == rv) { + SECStatus rv2 = CERT_FindCRLEntryReasonExten(entry, &reason); PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); } - } + break; + + case dpcacheEmpty: + /* useful for NIST policy */ + status = certRevocationStatusUnknown; + break; + + case dpcacheNoEntry: + status = certRevocationStatusValid; + break; + + case dpcacheInvalidCacheError: + /* t of zero may have caused the CRL cache to fail to verify + * a CRL. treat it as unknown */ + if (!t) + { + status = certRevocationStatusUnknown; + } + break; + + default: + /* leave status as revoked */ + break; } ReleaseDPCache(dpcache, lockedwrite); + if (revStatus) + { + *revStatus = status; + } + if (revReason) + { + *revReason = reason; + } return rv; } +/* check CRL revocation status of given certificate and issuer */ +SECStatus +CERT_CheckCRL(CERTCertificate* cert, CERTCertificate* issuer, + const SECItem* dp, PRTime t, void* wincx) +{ + return cert_CheckCertRevocationStatus(cert, issuer, dp, t, wincx, + NULL, NULL); +} + /* retrieve full CRL object that best matches the cache status */ CERTSignedCrl * SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type) @@ -2716,6 +2908,8 @@ SECStatus CERT_CacheCRL(CERTCertDBHandle* dbhandle, SECItem* newdercrl) return SECFailure; } + /* XXX check if it has IDP extension. If so, do not proceed and set error */ + rv = AcquireDPCache(NULL, &newcrl->crl.derName, NULL, 0, NULL, &cache, &writeLocked); @@ -2836,6 +3030,188 @@ SECStatus CERT_UncacheCRL(CERTCertDBHandle* dbhandle, SECItem* olddercrl) return rv; } +SECStatus cert_AcquireNamedCRLCache() +{ + if (!namedCRLCache.lock) + { + PORT_Assert(0); + return SECFailure; + } + PR_Lock(namedCRLCache.lock); + return SECSuccess; +} + +/* This must be called only while cache is acquired, and the entry is only + * valid until cache is released. + */ +SECStatus cert_FindCRLByGeneralName(const SECItem* canonicalizedName, + NamedCRLCacheEntry** retEntry) +{ + if (!canonicalizedName || !retEntry) + { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + *retEntry = (NamedCRLCacheEntry*) PL_HashTableLookup(namedCRLCache.entries, + (void*) canonicalizedName); + return SECSuccess; +} + +SECStatus cert_ReleaseNamedCRLCache() +{ + if (!namedCRLCache.lock) + { + PORT_Assert(0); + return SECFailure; + } + PR_Unlock(namedCRLCache.lock); + return SECSuccess; +} + +/* creates new named cache entry from CRL, and tries to add it to CRL cache */ +static SECStatus addCRLToCache(CERTCertDBHandle* dbhandle, SECItem* crl, + const SECItem* canonicalizedName, + NamedCRLCacheEntry** newEntry) +{ + SECStatus rv = SECSuccess; + NamedCRLCacheEntry* entry; + + /* create new named entry */ + if (SECSuccess != NamedCRLCacheEntry_Create(newEntry) || !*newEntry) + { + /* no need to keep unused CRL around */ + SECITEM_ZfreeItem(entry->crl, PR_TRUE); + return SECFailure; + } + entry = *newEntry; + entry->crl = crl; /* named CRL cache owns DER */ + entry->lastAttemptTime = PR_Now(); + /* now, attempt to insert CRL into CRL cache */ + if (SECSuccess == CERT_CacheCRL(dbhandle, entry->crl)) + { + entry->inCRLCache = PR_TRUE; + entry->successfulInsertionTime = entry->lastAttemptTime; + } + else + { + switch (PR_GetError()) + { + case SEC_ERROR_CRL_ALREADY_EXISTS: + entry->dupe = PR_TRUE; + break; + + case SEC_ERROR_BAD_DER: + entry->badDER = PR_TRUE; + break; + + /* all other reasons */ + default: + entry->unsupported = PR_TRUE; + break; + } + rv = SECFailure; + /* no need to keep unused CRL around */ + SECITEM_ZfreeItem(entry->crl, PR_TRUE); + } + return rv; +} + +/* take ownership of CRL, and insert it into the named CRL cache + * and indexed CRL cache + */ +SECStatus cert_CacheCRLByGeneralName(CERTCertDBHandle* dbhandle, SECItem* crl, + const SECItem* canonicalizedName) +{ + NamedCRLCacheEntry* oldEntry, * newEntry = NULL; + SECStatus rv = SECSuccess, rv2; + + PORT_Assert(namedCRLCache.lock); + PORT_Assert(namedCRLCache.entries); + + if (!crl || !canonicalizedName) + { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + rv = cert_AcquireNamedCRLCache(); + PORT_Assert(SECSuccess == rv); + if (SECSuccess != rv) + { + SECITEM_ZfreeItem(crl, PR_TRUE); + return SECFailure; + } + rv = cert_FindCRLByGeneralName(canonicalizedName, &oldEntry); + PORT_Assert(SECSuccess == rv); + if (SECSuccess != rv) + { + rv = cert_ReleaseNamedCRLCache(); + SECITEM_ZfreeItem(crl, PR_TRUE); + return SECFailure; + } + if (SECSuccess == addCRLToCache(dbhandle, crl, canonicalizedName, + &newEntry) ) { + if (NULL == PL_HashTableAdd(namedCRLCache.entries, + (void*) canonicalizedName, + (void*) newEntry)) + { + rv2 = NamedCRLCacheEntry_Destroy(newEntry); + PORT_Assert(SECSuccess == rv2); + rv = SECFailure; + PORT_Assert(0); + } + else + if (oldEntry) + { + /* new entry was added successfully, now delete old entry */ + rv = NamedCRLCacheEntry_Destroy(oldEntry); + PORT_Assert(SECSuccess == rv); + } + } else { + /* error adding new CRL to cache */ + if (!oldEntry) + { + /* no old cache entry, use the new one even though it's bad */ + if (NULL == PL_HashTableAdd(namedCRLCache.entries, + (void*) canonicalizedName, + (void*) newEntry)) + { + rv = SECFailure; + PORT_Assert(0); + } + } + else + { + if (oldEntry->inCRLCache) + { + /* previous cache entry was good, keep it and update time */ + oldEntry-> lastAttemptTime = newEntry->lastAttemptTime; + /* throw away new bad entry */ + rv = NamedCRLCacheEntry_Destroy(newEntry); + PORT_Assert(SECSuccess == rv); + } + else + { + /* previous cache entry was bad, just replace it */ + if (NULL == PL_HashTableAdd(namedCRLCache.entries, + (void*) canonicalizedName, + (void*) newEntry)) + { + rv = SECFailure; + PORT_Assert(0); + } + rv2 = NamedCRLCacheEntry_Destroy(oldEntry); + PORT_Assert(SECSuccess == rv2); + } + } + } + rv2 = cert_ReleaseNamedCRLCache(); + PORT_Assert(SECSuccess == rv2); + + return rv; +} + static SECStatus CachedCrl_Create(CachedCrl** returned, CERTSignedCrl* crl, CRLOrigin origin) { diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c index 4a94161a9..a62199cf0 100755 --- a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c +++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c @@ -587,6 +587,7 @@ pkix_pl_Pk11CertStore_CheckRevByCrl( CRLDPCache* dpcache = NULL; CERTCertificate *cert, *issuer; CERTCrlEntry* entry = NULL; + dpcacheStatus ds; PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl"); PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, date); @@ -626,11 +627,12 @@ pkix_pl_Pk11CertStore_CheckRevByCrl( goto cleanup; } /* now look up the certificate SN in the DP cache's CRL */ - rv = DPCache_Lookup(dpcache, &cert->serialNumber, &entry); - if (rv == SECFailure) { + ds = DPCache_Lookup(dpcache, &cert->serialNumber, &entry); + if (ds != dpcacheFoundEntry && ds!= dpcacheNoEntry && ds != dpcacheEmpty) { PKIX_ERROR(PKIX_CERTCHECKCRLFAILED); } - if (entry) { + if (dpcacheFoundEntry == ds) { + PORT_Assert(entry); /* check the time if we have one */ if (entry->revocationDate.data && entry->revocationDate.len) { PRTime revocationDate = 0; @@ -658,8 +660,10 @@ pkix_pl_Pk11CertStore_CheckRevByCrl( status = PKIX_RevStatus_Revoked; PORT_SetError(SEC_ERROR_REVOKED_CERTIFICATE); } - } else { + } else if (dpcacheNoEntry == ds) { status = PKIX_RevStatus_Success; + } else if (dpcacheEmpty == ds) { + status = PKIX_RevStatus_NoInfo; } cleanup: |