Fix for 167649 - invalidate CRL cache when new CRL object is imported into a token

This commit is contained in:
jpierre%netscape.com 2002-09-10 04:49:09 +00:00
Родитель d38f0b028d
Коммит 524901374d
2 изменённых файлов: 163 добавлений и 30 удалений

Просмотреть файл

@ -33,7 +33,7 @@
/*
* certi.h - private data structures for the certificate library
*
* $Id: certi.h,v 1.3 2002/09/05 06:12:32 jpierre%netscape.com Exp $
* $Id: certi.h,v 1.4 2002/09/10 04:49:09 jpierre%netscape.com Exp $
*/
#ifndef _CERTI_H_
#define _CERTI_H_
@ -59,6 +59,7 @@ struct OpaqueCRLFieldsStr {
PRBool badExtensions;
PRBool deleted;
PRBool heapDER;
PRBool unverified;
};
typedef struct PreAllocatorStr PreAllocator;
@ -88,6 +89,9 @@ struct CRLEntryCacheStr {
if the last CRL fetch encountered an error. Can be cleared if a
new fetch succeeds */
#define CRL_CACHE_OUT_OF_MEMORY 0x0004 /* this state will be set
if we don't have enough memory to build the hash table of entries */
/* CRL distribution point cache object
This is a cache of CRL entries for a given distribution point of an issuer
It is built from a collection of one full and 0 or more delta CRLs.

Просмотреть файл

@ -34,7 +34,7 @@
/*
* Moved from secpkcs7.c
*
* $Id: crl.c,v 1.21 2002/09/06 20:17:35 wtc%netscape.com Exp $
* $Id: crl.c,v 1.22 2002/09/10 04:49:09 jpierre%netscape.com Exp $
*/
#include "cert.h"
@ -421,9 +421,8 @@ SECStatus CERT_CompleteCRLDecodeEntries(CERTSignedCrl* crl)
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*/
memory, so we want to avoid it */
}
}
return rv;
}
@ -627,6 +626,8 @@ loser:
SECStatus SEC_DestroyCrl(CERTSignedCrl *crl);
void RefreshIssuer(SECItem* crlKey);
CERTSignedCrl *
crl_storeCRL (PK11SlotInfo *slot,char *url,
CERTSignedCrl *newCrl, SECItem *derCrl, int type)
@ -685,6 +686,8 @@ crl_storeCRL (PK11SlotInfo *slot,char *url,
SEC_DeletePermCRL(oldCrl);
}
/* invalidate CRL cache for this issuer */
RefreshIssuer(&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) {
@ -1028,7 +1031,7 @@ SECStatus ShutdownCRLCache(void)
return SECSuccess;
}
SECStatus DP_AddCRL(CRLDPCache* cache, CERTSignedCrl* crl)
SECStatus DPCache_AddCRL(CRLDPCache* cache, CERTSignedCrl* crl)
{
CERTSignedCrl** newcrls = NULL;
PORT_Assert(cache);
@ -1048,6 +1051,25 @@ SECStatus DP_AddCRL(CRLDPCache* cache, CERTSignedCrl* crl)
return SECSuccess;
}
SECStatus DPCache_Cleanup(CRLDPCache* cache)
{
/* remove deleted CRLs from memory */
PRUint32 i = 0;
PORT_Assert(cache);
if (!cache) {
return SECFailure;
}
for (i=0;i<cache->ncrls;i++) {
CERTSignedCrl* acrl = cache->crls[i];
if (acrl && (PR_TRUE == GetOpaqueCRLFields(acrl)->deleted)) {
cache->crls[i] = cache->crls[cache->ncrls-1];
cache->crls[cache->ncrls-1] = NULL;
cache->ncrls--;
}
}
return SECSuccess;
}
PRBool CRLStillExists(CERTSignedCrl* crl)
{
NSSItem newsubject;
@ -1122,7 +1144,7 @@ PRBool CRLStillExists(CERTSignedCrl* crl)
return xstatus;
}
SECStatus DP_RefreshCache(CRLDPCache* cache, CERTSignedCrl* crlobject,
SECStatus DPCache_Refresh(CRLDPCache* cache, CERTSignedCrl* crlobject,
int64 t, void* wincx)
{
SECStatus rv = SECSuccess;
@ -1140,7 +1162,7 @@ SECStatus DP_RefreshCache(CRLDPCache* cache, CERTSignedCrl* crlobject,
if (PR_TRUE == GetOpaqueCRLFields(crlobject)->bad) {
PORT_SetError(SEC_ERROR_BAD_DER);
cache->invalid = PR_TRUE;
cache->invalid |= CRL_CACHE_INVALID_CRLS;
return SECSuccess;
} else {
SECStatus signstatus = SECFailure;
@ -1149,9 +1171,22 @@ SECStatus DP_RefreshCache(CRLDPCache* cache, CERTSignedCrl* crlobject,
cache->issuer, t, wincx);
}
if (SECSuccess != signstatus) {
if (0 == t) {
/* we tried to verify with a time of t=0 . Most likely this is
because this CRL came through a call to SEC_FindCrlByName,
not because the signature fails to verify.
So we don't cache this verification failure. We'll try
to verify the CRL again when a certificate from that issuer
gets verified */
GetOpaqueCRLFields(crlobject)->unverified = PR_TRUE;
} else {
GetOpaqueCRLFields(crlobject)->unverified = PR_FALSE;
}
PORT_SetError(SEC_ERROR_CRL_BAD_SIGNATURE);
cache->invalid = PR_TRUE;
cache->invalid |= CRL_CACHE_INVALID_CRLS;
return SECSuccess;
} else {
GetOpaqueCRLFields(crlobject)->unverified = PR_FALSE;
}
}
@ -1166,7 +1201,10 @@ SECStatus DP_RefreshCache(CRLDPCache* cache, CERTSignedCrl* crlobject,
/* we already have a hash table, destroy it */
PL_HashTableDestroy(cache->entries);
cache->entries = NULL;
/* also destroy the PreAllocator */
}
/* also destroy the PreAllocator */
if (cache->prebuffer)
{
PreAllocator_Destroy(cache->prebuffer);
cache->prebuffer = NULL;
}
@ -1185,21 +1223,56 @@ SECStatus DP_RefreshCache(CRLDPCache* cache, CERTSignedCrl* crlobject,
if (!cache->entries) {
rv = SECFailure;
}
if (SECSuccess == rv){
if (SECSuccess == rv) {
/* add all serial numbers to the hash table */
for (crlEntry = crlobject->crl.entries; crlEntry && *crlEntry; crlEntry++) {
PL_HashTableAdd(cache->entries, &(*crlEntry)->serialNumber, *crlEntry);
}
cache->full = crlobject;
cache->invalid = 0; /* valid cache */
} else {
cache->invalid = PR_TRUE;
cache->invalid |= CRL_CACHE_OUT_OF_MEMORY;
}
} else {
cache->invalid = PR_TRUE;
cache->invalid |= CRL_CACHE_INVALID_CRLS;
}
return rv;
}
void DPCache_Empty(CRLDPCache* cache)
{
PRUint32 i;
PR_ASSERT(cache);
if (!cache)
{
return;
}
cache->full = NULL;
cache->invalid = 0;
if (cache->entries) {
/* we already have a hash table, destroy it */
PL_HashTableDestroy(cache->entries);
cache->entries = NULL;
}
/* also destroy the PreAllocator */
if (cache->prebuffer)
{
PreAllocator_Destroy(cache->prebuffer);
cache->prebuffer = NULL;
}
for (i=0;i<cache->ncrls;i++)
{
CERTSignedCrl* crl = cache->crls[i];
if (crl)
{
GetOpaqueCRLFields(crl)->deleted = PR_TRUE;
}
}
}
SECStatus DPCache_Fetch(CRLDPCache* cache, int64 t, void* wincx)
{
SECStatus rv = SECSuccess;
@ -1222,6 +1295,7 @@ SECStatus DPCache_Fetch(CRLDPCache* cache, int64 t, void* wincx)
if ((SECSuccess == rv) && (!crlobject)) {
/* no CRL was found. This is OK */
DPCache_Empty(cache);
return SECSuccess;
}
@ -1254,12 +1328,12 @@ SECStatus DPCache_Fetch(CRLDPCache* cache, int64 t, void* wincx)
/* add the CRL to our array */
if (SECSuccess == rv) {
rv = DP_AddCRL(cache, crlobject);
rv = DPCache_AddCRL(cache, crlobject);
}
/* update the cache with this new CRL */
if (SECSuccess == rv) {
rv = DP_RefreshCache(cache, crlobject, t, wincx);
rv = DPCache_Refresh(cache, crlobject, t, wincx);
}
return rv;
}
@ -1273,7 +1347,7 @@ SECStatus DPCache_Lookup(CRLDPCache* cache, SECItem* sn, CERTCrlEntry** returned
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (PR_TRUE == cache->invalid) {
if (0 != cache->invalid) {
/* the cache contains a bad CRL, consider all certs revoked
as a security measure */
PORT_SetError(SEC_ERROR_CRL_INVALID);
@ -1336,22 +1410,37 @@ SECStatus DPCache_Update(CRLDPCache* cache, CERTCertificate* issuer, int64 t,
return SECFailure;
}
if (NULL == cache->issuer && issuer) {
/* we didn't have a valid issuer cert yet, but we do now. add it */
DPCache_LockWrite();
/* check that we are the first thread to update */
/* verify CRLs that couldn't be checked when inserted into the cache
because issuer and time was unavailable. These are CRLs that were
inserted through SEC_FindCrlByName, rather than through a certificate
verification */
if (t && issuer) {
/* if we didn't have a valid issuer cert yet, but we do now. add it */
if (NULL == cache->issuer) {
/* save the issuer cert */
cache->issuer = CERT_DupCertificate(issuer);
/* also re-process all the CRLs in case some of them now verify */
for (i = 0; i < cache->ncrls ; i++) {
CERTSignedCrl* acrl = cache->crls[i];
if (PR_FALSE == GetOpaqueCRLFields(acrl)->bad) {
DP_RefreshCache(cache, acrl, t, wincx);
}
/* re-process all unverified CRLs */
for (i = 0; i < cache->ncrls ; i++) {
CERTSignedCrl* acrl = cache->crls[i];
if (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified) {
DPCache_LockWrite();
/* check that we are the first thread to update */
if (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified) {
DPCache_Refresh(cache, acrl, t, wincx);
/* also check all the other CRLs */
for (i = i+1 ; i < cache->ncrls ; i++) {
acrl = cache->crls[i];
if (acrl && (PR_TRUE == GetOpaqueCRLFields(acrl)->unverified)) {
DPCache_Refresh(cache, acrl, t, wincx);
}
}
}
DPCache_UnlockWrite();
break;
}
}
DPCache_UnlockWrite();
}
if (cache->ncrls) {
@ -1359,11 +1448,9 @@ SECStatus DPCache_Update(CRLDPCache* cache, CERTCertificate* issuer, int64 t,
for (i = 0; (i < cache->ncrls) && (PR_FALSE == updated); i++)
{
CERTSignedCrl* savcrl = cache->crls[i];
if (PR_TRUE != CRLStillExists(savcrl)) {
if (savcrl && (PR_TRUE != CRLStillExists(savcrl))) {
/* this CRL is gone. But first, we need to check if we are
the first to do the update. We can't acquire the write lock
now or it could create a deadlock */
/* this CRL is gone */
DPCache_LockWrite();
/* first, we need to check if another thread updated
it before we did, and abort if it has been modified since
@ -1371,10 +1458,22 @@ SECStatus DPCache_Update(CRLDPCache* cache, CERTCertificate* issuer, int64 t,
if ((savcrl == cache->crls[i]) &&
PR_TRUE != CRLStillExists(savcrl)) {
/* the CRL is gone. And we are the one to do the update */
/* Mark the CRL deleted, and try to fetch a new one */
/* Mark the CRL deleted */
GetOpaqueCRLFields(savcrl)->deleted = PR_TRUE;
/* also check all the other CRLs */
for (i = i+1 ; i < cache->ncrls ; i++) {
CERTSignedCrl* acrl = cache->crls[i];
if (acrl && (PR_TRUE != CRLStillExists(acrl))) {
GetOpaqueCRLFields(acrl)->deleted = PR_TRUE;
}
}
/* and try to fetch a new one */
rv = DPCache_Fetch(cache, t, wincx);
updated = PR_TRUE;
if (SECSuccess == rv) {
rv = DPCache_Cleanup(cache); /* clean up deleted CRLs
from the cache*/
}
}
DPCache_UnlockWrite();
}
@ -1777,3 +1876,33 @@ SEC_FindCrlByName(CERTCertDBHandle *handle, SECItem *crlKey, int type)
return acrl;
}
void RefreshIssuer(SECItem* crlKey)
{
CERTSignedCrl* acrl = NULL;
CRLDPCache* cache = NULL;
SECStatus rv = SECSuccess;
PRBool writeLocked = PR_FALSE;
rv = AcquireDPCache(NULL, crlKey, NULL, 0, NULL, &cache, &writeLocked);
if (SECSuccess != rv)
{
return;
}
if (PR_TRUE == writeLocked)
{
/* the DPCache is write-locked. This means that the issuer was just
added to the CRL cache. There is no need to do anything */
}
else
{
PRBool readlocked = PR_TRUE;
/* we need to invalidate the DPCache here */
DPCache_LockWrite();
DPCache_Empty(cache);
DPCache_Cleanup(cache);
DPCache_UnlockWrite();
}
ReleaseDPCache(cache, writeLocked);
return;
}