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