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