summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjulien.pierre.boogz%sun.com <devnull@localhost>2009-04-17 22:46:54 +0000
committerjulien.pierre.boogz%sun.com <devnull@localhost>2009-04-17 22:46:54 +0000
commit9718f4d8a3d959274ed77c0fea7d05307485b63b (patch)
tree957769e2d2cf931f9859b7d873ea84872d5b13e2
parent43dbf6a86cf9c0572cf2fffdc9b0eb5d0e30727f (diff)
downloadnss-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.h2
-rw-r--r--security/nss/lib/certdb/certi.h79
-rw-r--r--security/nss/lib/certdb/crl.c466
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c12
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: