| /* 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); |
| } |