blob: d6f5b6bcc8a52d1d548ef694c9ee714a7598f07e [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* pkix_defaultcrlchecker.c
*
* Functions for default CRL Checkers
*
*/
#include "pkix.h"
#include "pkix_crlchecker.h"
#include "pkix_tools.h"
/* --Private-CRLChecker-Data-and-Types------------------------------- */
typedef struct pkix_CrlCheckerStruct {
/* RevocationMethod is the super class of CrlChecker. */
pkix_RevocationMethod method;
PKIX_List *certStores; /* list of CertStore */
PKIX_PL_VerifyCallback crlVerifyFn;
} pkix_CrlChecker;
/* --Private-CRLChecker-Functions----------------------------------- */
/*
* FUNCTION: pkix_CrlCheckerstate_Destroy
* (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
*/
static PKIX_Error *
pkix_CrlChecker_Destroy(
PKIX_PL_Object *object,
void *plContext)
{
pkix_CrlChecker *state = NULL;
PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_Destroy");
PKIX_NULLCHECK_ONE(object);
/* Check that this object is a default CRL checker state */
PKIX_CHECK(
pkix_CheckType(object, PKIX_CRLCHECKER_TYPE, plContext),
PKIX_OBJECTNOTCRLCHECKER);
state = (pkix_CrlChecker *)object;
PKIX_DECREF(state->certStores);
cleanup:
PKIX_RETURN(CRLCHECKER);
}
/*
* FUNCTION: pkix_CrlChecker_RegisterSelf
*
* DESCRIPTION:
* Registers PKIX_CRLCHECKER_TYPE and its related functions
* with systemClasses[]
*
* THREAD SAFETY:
* Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
*
* Since this function is only called by PKIX_PL_Initialize, which should
* only be called once, it is acceptable that this function is not
* thread-safe.
*/
PKIX_Error *
pkix_CrlChecker_RegisterSelf(void *plContext)
{
extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
pkix_ClassTable_Entry* entry = &systemClasses[PKIX_CRLCHECKER_TYPE];
PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_RegisterSelf");
entry->description = "CRLChecker";
entry->typeObjectSize = sizeof(pkix_CrlChecker);
entry->destructor = pkix_CrlChecker_Destroy;
PKIX_RETURN(CRLCHECKER);
}
/*
* FUNCTION: pkix_CrlChecker_Create
*
* DESCRIPTION:
* Allocate and initialize CRLChecker state data.
*
* PARAMETERS
* "certStores"
* Address of CertStore List to be stored in state. Must be non-NULL.
* "testDate"
* Address of PKIX_PL_Date to be checked. May be NULL.
* "trustedPubKey"
* Trusted Anchor Public Key for verifying first Cert in the chain.
* Must be non-NULL.
* "certsRemaining"
* Number of certificates remaining in the chain.
* "nistCRLPolicyEnabled"
* If enabled, enforce nist crl policy.
* "pChecker"
* Address of CRLChecker that is returned. Must be non-NULL.
* "plContext"
* Platform-specific context pointer.
*
* THREAD SAFETY:
* Thread Safe (see Thread Safety Definitions in Programmer's Guide)
*
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a DefaultCrlChecker Error if the function fails in a
* non-fatal way.
* Returns a Fatal Error
*/
PKIX_Error *
pkix_CrlChecker_Create(PKIX_RevocationMethodType methodType,
PKIX_UInt32 flags,
PKIX_UInt32 priority,
pkix_LocalRevocationCheckFn localRevChecker,
pkix_ExternalRevocationCheckFn externalRevChecker,
PKIX_List *certStores,
PKIX_PL_VerifyCallback crlVerifyFn,
pkix_RevocationMethod **pChecker,
void *plContext)
{
pkix_CrlChecker *crlChecker = NULL;
PKIX_ENTER(CRLCHECKER, "pkix_CrlChecker_Create");
PKIX_NULLCHECK_TWO(certStores, pChecker);
PKIX_CHECK(PKIX_PL_Object_Alloc
(PKIX_CRLCHECKER_TYPE,
sizeof (pkix_CrlChecker),
(PKIX_PL_Object **)&crlChecker,
plContext),
PKIX_COULDNOTCREATECRLCHECKEROBJECT);
pkixErrorResult = pkix_RevocationMethod_Init(
(pkix_RevocationMethod*)crlChecker, methodType, flags, priority,
localRevChecker, externalRevChecker, plContext);
if (pkixErrorResult) {
goto cleanup;
}
/* Initialize fields */
PKIX_INCREF(certStores);
crlChecker->certStores = certStores;
crlChecker->crlVerifyFn = crlVerifyFn;
*pChecker = (pkix_RevocationMethod*)crlChecker;
crlChecker = NULL;
cleanup:
PKIX_DECREF(crlChecker);
PKIX_RETURN(CRLCHECKER);
}
/* --Private-CRLChecker-Functions------------------------------------ */
/*
* FUNCTION: pkix_CrlChecker_CheckLocal
*
* DESCRIPTION:
* Check if the Cert has been revoked based the CRLs data. This function
* maintains the checker state to be current.
*
* PARAMETERS
* "checker"
* Address of CertChainChecker which has the state data.
* Must be non-NULL.
* "cert"
* Address of Certificate that is to be validated. Must be non-NULL.
* "unreslvdCrtExts"
* A List OIDs. Not **yet** used in this checker function.
* "plContext"
* Platform-specific context pointer.
*
* THREAD SAFETY:
* Not Thread Safe
* (see Thread Safety Definitions in Programmer's Guide)
*
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a CertChainChecker Error if the function fails in a non-fatal way.
* Returns a Fatal Error
*/
PKIX_Error *
pkix_CrlChecker_CheckLocal(
PKIX_PL_Cert *cert,
PKIX_PL_Cert *issuer,
PKIX_PL_Date *date,
pkix_RevocationMethod *checkerObject,
PKIX_ProcessingParams *procParams,
PKIX_UInt32 methodFlags,
PKIX_Boolean chainVerificationState,
PKIX_RevocationStatus *pRevStatus,
CERTCRLEntryReasonCode *pReasonCode,
void *plContext)
{
PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn;
PKIX_CertStore *certStore = NULL;
pkix_CrlChecker *state = NULL;
PKIX_UInt32 crlStoreIndex = 0;
PKIX_UInt32 numCrlStores = 0;
PKIX_Boolean storeIsLocal = PKIX_FALSE;
PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckLocal");
PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, checkerObject);
state = (pkix_CrlChecker*)checkerObject;
PKIX_CHECK(
PKIX_List_GetLength(state->certStores, &numCrlStores, plContext),
PKIX_LISTGETLENGTHFAILED);
for (;crlStoreIndex < numCrlStores;crlStoreIndex++) {
PKIX_CHECK(
PKIX_List_GetItem(state->certStores, crlStoreIndex,
(PKIX_PL_Object **)&certStore,
plContext),
PKIX_LISTGETITEMFAILED);
PKIX_CHECK(
PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal,
plContext),
PKIX_CERTSTOREGETLOCALFLAGFAILED);
if (storeIsLocal) {
PKIX_CHECK(
PKIX_CertStore_GetCrlCheckerFn(certStore,
&storeCheckRevocationFn,
plContext),
PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);
if (storeCheckRevocationFn) {
PKIX_CHECK(
(*storeCheckRevocationFn)(certStore, cert, issuer,
/* delay sig check if building
* a chain by not specifying the time*/
chainVerificationState ? date : NULL,
/* crl downloading is not done. */
PKIX_FALSE,
pReasonCode, &revStatus, plContext),
PKIX_CERTSTORECRLCHECKFAILED);
if (revStatus == PKIX_RevStatus_Revoked) {
break;
}
}
}
PKIX_DECREF(certStore);
} /* while */
cleanup:
*pRevStatus = revStatus;
PKIX_DECREF(certStore);
PKIX_RETURN(CERTCHAINCHECKER);
}
/*
* FUNCTION: pkix_CrlChecker_CheckRemote
*
* DESCRIPTION:
* Check if the Cert has been revoked based the CRLs data. This function
* maintains the checker state to be current.
*
* PARAMETERS
* "checker"
* Address of CertChainChecker which has the state data.
* Must be non-NULL.
* "cert"
* Address of Certificate that is to be validated. Must be non-NULL.
* "unreslvdCrtExts"
* A List OIDs. Not **yet** used in this checker function.
* "plContext"
* Platform-specific context pointer.
*
* THREAD SAFETY:
* Not Thread Safe
* (see Thread Safety Definitions in Programmer's Guide)
*
* RETURNS:
* Returns NULL if the function succeeds.
* Returns a CertChainChecker Error if the function fails in a non-fatal way.
* Returns a Fatal Error
*/
PKIX_Error *
pkix_CrlChecker_CheckExternal(
PKIX_PL_Cert *cert,
PKIX_PL_Cert *issuer,
PKIX_PL_Date *date,
pkix_RevocationMethod *checkerObject,
PKIX_ProcessingParams *procParams,
PKIX_UInt32 methodFlags,
PKIX_RevocationStatus *pRevStatus,
CERTCRLEntryReasonCode *pReasonCode,
void **pNBIOContext,
void *plContext)
{
PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn = NULL;
PKIX_CertStore_ImportCrlCallback storeImportCrlFn = NULL;
PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
PKIX_CertStore *certStore = NULL;
PKIX_CertStore *localStore = NULL;
PKIX_CRLSelector *crlSelector = NULL;
PKIX_PL_X500Name *issuerName = NULL;
pkix_CrlChecker *state = NULL;
PKIX_UInt32 crlStoreIndex = 0;
PKIX_UInt32 numCrlStores = 0;
PKIX_Boolean storeIsLocal = PKIX_FALSE;
PKIX_List *crlList = NULL;
PKIX_List *dpList = NULL;
void *nbioContext = NULL;
PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckExternal");
PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, pNBIOContext);
nbioContext = *pNBIOContext;
*pNBIOContext = NULL; /* prepare for Error exit */
state = (pkix_CrlChecker*)checkerObject;
PKIX_CHECK(
PKIX_List_GetLength(state->certStores, &numCrlStores, plContext),
PKIX_LISTGETLENGTHFAILED);
/* Find a cert store that is capable of storing crls */
for (;crlStoreIndex < numCrlStores;crlStoreIndex++) {
PKIX_CHECK(
PKIX_List_GetItem(state->certStores, crlStoreIndex,
(PKIX_PL_Object **)&certStore,
plContext),
PKIX_LISTGETITEMFAILED);
PKIX_CHECK(
PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal,
plContext),
PKIX_CERTSTOREGETLOCALFLAGFAILED);
if (storeIsLocal) {
PKIX_CHECK(
PKIX_CertStore_GetImportCrlCallback(certStore,
&storeImportCrlFn,
plContext),
PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);
PKIX_CHECK(
PKIX_CertStore_GetCrlCheckerFn(certStore,
&storeCheckRevocationFn,
plContext),
PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);
if (storeImportCrlFn && storeCheckRevocationFn) {
localStore = certStore;
certStore = NULL;
break;
}
}
PKIX_DECREF(certStore);
} /* while */
/* Report unknown status if we can not check crl in one of the
* local stores. */
if (!localStore) {
PKIX_ERROR_FATAL(PKIX_CRLCHECKERNOLOCALCERTSTOREFOUND);
}
PKIX_CHECK(
PKIX_PL_Cert_VerifyKeyUsage(issuer, PKIX_CRL_SIGN, plContext),
PKIX_CERTCHECKKEYUSAGEFAILED);
PKIX_CHECK(
PKIX_PL_Cert_GetCrlDp(cert, &dpList, plContext),
PKIX_CERTGETCRLDPFAILED);
if (!(methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) &&
(!dpList || !dpList->length)) {
goto cleanup;
}
PKIX_CHECK(
PKIX_PL_Cert_GetIssuer(cert, &issuerName, plContext),
PKIX_CERTGETISSUERFAILED);
PKIX_CHECK(
PKIX_CRLSelector_Create(issuer, dpList, date, &crlSelector, plContext),
PKIX_CRLCHECKERSETSELECTORFAILED);
/* Fetch crl and store in a local cert store */
for (crlStoreIndex = 0;crlStoreIndex < numCrlStores;crlStoreIndex++) {
PKIX_CertStore_CRLCallback getCrlsFn;
PKIX_CHECK(
PKIX_List_GetItem(state->certStores, crlStoreIndex,
(PKIX_PL_Object **)&certStore,
plContext),
PKIX_LISTGETITEMFAILED);
PKIX_CHECK(
PKIX_CertStore_GetCRLCallback(certStore, &getCrlsFn,
plContext),
PKIX_CERTSTOREGETCRLCALLBACKFAILED);
PKIX_CHECK(
(*getCrlsFn)(certStore, crlSelector, &nbioContext,
&crlList, plContext),
PKIX_GETCRLSFAILED);
PKIX_CHECK(
(*storeImportCrlFn)(localStore, issuerName, crlList, plContext),
PKIX_CERTSTOREFAILTOIMPORTCRLLIST);
PKIX_CHECK(
(*storeCheckRevocationFn)(certStore, cert, issuer, date,
/* done with crl downloading */
PKIX_TRUE,
pReasonCode, &revStatus, plContext),
PKIX_CERTSTORECRLCHECKFAILED);
if (revStatus != PKIX_RevStatus_NoInfo) {
break;
}
PKIX_DECREF(crlList);
PKIX_DECREF(certStore);
} /* while */
cleanup:
/* Update return flags */
if (revStatus == PKIX_RevStatus_NoInfo &&
((dpList && dpList->length > 0) ||
(methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE)) &&
methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
revStatus = PKIX_RevStatus_Revoked;
}
*pRevStatus = revStatus;
PKIX_DECREF(dpList);
PKIX_DECREF(crlList);
PKIX_DECREF(certStore);
PKIX_DECREF(issuerName);
PKIX_DECREF(localStore);
PKIX_DECREF(crlSelector);
PKIX_RETURN(CERTCHAINCHECKER);
}