| /* 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_build.c |
| * |
| * Top level buildChain function |
| * |
| */ |
| |
| /* #define PKIX_BUILDDEBUG 1 */ |
| /* #define PKIX_FORWARDBUILDERSTATEDEBUG 1 */ |
| |
| #include "pkix_build.h" |
| |
| extern PRLogModuleInfo *pkixLog; |
| |
| /* |
| * List of critical extension OIDs associate with what build chain has |
| * checked. Those OIDs need to be removed from the unresolved critical |
| * extension OIDs list manually (instead of by checker automatically). |
| */ |
| static SECOidTag buildCheckedCritExtOIDs[] = { |
| PKIX_CERTKEYUSAGE_OID, |
| PKIX_CERTSUBJALTNAME_OID, |
| PKIX_BASICCONSTRAINTS_OID, |
| PKIX_NAMECONSTRAINTS_OID, |
| PKIX_EXTENDEDKEYUSAGE_OID, |
| PKIX_NSCERTTYPE_OID, |
| PKIX_UNKNOWN_OID |
| }; |
| |
| /* --Private-ForwardBuilderState-Functions---------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_Destroy |
| * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_ForwardBuilderState_Destroy( |
| PKIX_PL_Object *object, |
| void *plContext) |
| { |
| PKIX_ForwardBuilderState *state = NULL; |
| |
| PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Destroy"); |
| PKIX_NULLCHECK_ONE(object); |
| |
| PKIX_CHECK(pkix_CheckType |
| (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext), |
| PKIX_OBJECTNOTFORWARDBUILDERSTATE); |
| |
| state = (PKIX_ForwardBuilderState *)object; |
| |
| state->status = BUILD_INITIAL; |
| state->traversedCACerts = 0; |
| state->certStoreIndex = 0; |
| state->numCerts = 0; |
| state->numAias = 0; |
| state->certIndex = 0; |
| state->aiaIndex = 0; |
| state->certCheckedIndex = 0; |
| state->checkerIndex = 0; |
| state->hintCertIndex = 0; |
| state->numFanout = 0; |
| state->numDepth = 0; |
| state->reasonCode = 0; |
| state->canBeCached = PKIX_FALSE; |
| state->useOnlyLocal = PKIX_FALSE; |
| state->revChecking = PKIX_FALSE; |
| state->usingHintCerts = PKIX_FALSE; |
| state->certLoopingDetected = PKIX_FALSE; |
| PKIX_DECREF(state->validityDate); |
| PKIX_DECREF(state->prevCert); |
| PKIX_DECREF(state->candidateCert); |
| PKIX_DECREF(state->traversedSubjNames); |
| PKIX_DECREF(state->trustChain); |
| PKIX_DECREF(state->aia); |
| PKIX_DECREF(state->candidateCerts); |
| PKIX_DECREF(state->reversedCertChain); |
| PKIX_DECREF(state->checkedCritExtOIDs); |
| PKIX_DECREF(state->checkerChain); |
| PKIX_DECREF(state->certSel); |
| PKIX_DECREF(state->verifyNode); |
| PKIX_DECREF(state->client); |
| |
| /* |
| * If we ever add a child link we have to be careful not to have loops |
| * in the Destroy process. But with one-way links we should be okay. |
| */ |
| if (state->parentState == NULL) { |
| state->buildConstants.numAnchors = 0; |
| state->buildConstants.numCertStores = 0; |
| state->buildConstants.numHintCerts = 0; |
| state->buildConstants.procParams = 0; |
| PKIX_DECREF(state->buildConstants.testDate); |
| PKIX_DECREF(state->buildConstants.timeLimit); |
| PKIX_DECREF(state->buildConstants.targetCert); |
| PKIX_DECREF(state->buildConstants.targetPubKey); |
| PKIX_DECREF(state->buildConstants.certStores); |
| PKIX_DECREF(state->buildConstants.anchors); |
| PKIX_DECREF(state->buildConstants.userCheckers); |
| PKIX_DECREF(state->buildConstants.hintCerts); |
| PKIX_DECREF(state->buildConstants.revChecker); |
| PKIX_DECREF(state->buildConstants.aiaMgr); |
| } else { |
| PKIX_DECREF(state->parentState); |
| } |
| |
| cleanup: |
| |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| } |
| |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_Create |
| * |
| * DESCRIPTION: |
| * Allocate and initialize a ForwardBuilderState. |
| * |
| * PARAMETERS |
| * "traversedCACerts" |
| * Number of CA certificates traversed. |
| * "numFanout" |
| * Number of Certs that can be considered at this level (0 = no limit) |
| * "numDepth" |
| * Number of additional levels that can be searched (0 = no limit) |
| * "canBeCached" |
| * Boolean value indicating whether all certs on the chain can be cached. |
| * "validityDate" |
| * Address of Date at which build chain Certs' most restricted validity |
| * time is kept. May be NULL. |
| * "prevCert" |
| * Address of Cert just traversed. Must be non-NULL. |
| * "traversedSubjNames" |
| * Address of List of GeneralNames that have been traversed. |
| * Must be non-NULL. |
| * "trustChain" |
| * Address of List of certificates traversed. Must be non-NULL. |
| * "parentState" |
| * Address of previous ForwardBuilderState |
| * "pState" |
| * Address where ForwardBuilderState will be stored. 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 Build Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_ForwardBuilderState_Create( |
| PKIX_Int32 traversedCACerts, |
| PKIX_UInt32 numFanout, |
| PKIX_UInt32 numDepth, |
| PKIX_Boolean canBeCached, |
| PKIX_PL_Date *validityDate, |
| PKIX_PL_Cert *prevCert, |
| PKIX_List *traversedSubjNames, |
| PKIX_List *trustChain, |
| PKIX_ForwardBuilderState *parentState, |
| PKIX_ForwardBuilderState **pState, |
| void *plContext) |
| { |
| PKIX_ForwardBuilderState *state = NULL; |
| |
| PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Create"); |
| PKIX_NULLCHECK_FOUR(prevCert, traversedSubjNames, pState, trustChain); |
| |
| PKIX_CHECK(PKIX_PL_Object_Alloc |
| (PKIX_FORWARDBUILDERSTATE_TYPE, |
| sizeof (PKIX_ForwardBuilderState), |
| (PKIX_PL_Object **)&state, |
| plContext), |
| PKIX_COULDNOTCREATEFORWARDBUILDERSTATEOBJECT); |
| |
| state->status = BUILD_INITIAL; |
| state->traversedCACerts = traversedCACerts; |
| state->certStoreIndex = 0; |
| state->numCerts = 0; |
| state->numAias = 0; |
| state->certIndex = 0; |
| state->aiaIndex = 0; |
| state->certCheckedIndex = 0; |
| state->checkerIndex = 0; |
| state->hintCertIndex = 0; |
| state->numFanout = numFanout; |
| state->numDepth = numDepth; |
| state->reasonCode = 0; |
| state->revChecking = numDepth; |
| state->canBeCached = canBeCached; |
| state->useOnlyLocal = PKIX_TRUE; |
| state->revChecking = PKIX_FALSE; |
| state->usingHintCerts = PKIX_FALSE; |
| state->certLoopingDetected = PKIX_FALSE; |
| |
| PKIX_INCREF(validityDate); |
| state->validityDate = validityDate; |
| |
| PKIX_INCREF(prevCert); |
| state->prevCert = prevCert; |
| |
| state->candidateCert = NULL; |
| |
| PKIX_INCREF(traversedSubjNames); |
| state->traversedSubjNames = traversedSubjNames; |
| |
| PKIX_INCREF(trustChain); |
| state->trustChain = trustChain; |
| |
| state->aia = NULL; |
| state->candidateCerts = NULL; |
| state->reversedCertChain = NULL; |
| state->checkedCritExtOIDs = NULL; |
| state->checkerChain = NULL; |
| state->certSel = NULL; |
| state->verifyNode = NULL; |
| state->client = NULL; |
| |
| PKIX_INCREF(parentState); |
| state->parentState = parentState; |
| |
| if (parentState != NULL) { |
| state->buildConstants.numAnchors = |
| parentState->buildConstants.numAnchors; |
| state->buildConstants.numCertStores = |
| parentState->buildConstants.numCertStores; |
| state->buildConstants.numHintCerts = |
| parentState->buildConstants.numHintCerts; |
| state->buildConstants.maxFanout = |
| parentState->buildConstants.maxFanout; |
| state->buildConstants.maxDepth = |
| parentState->buildConstants.maxDepth; |
| state->buildConstants.maxTime = |
| parentState->buildConstants.maxTime; |
| state->buildConstants.procParams = |
| parentState->buildConstants.procParams; |
| state->buildConstants.testDate = |
| parentState->buildConstants.testDate; |
| state->buildConstants.timeLimit = |
| parentState->buildConstants.timeLimit; |
| state->buildConstants.targetCert = |
| parentState->buildConstants.targetCert; |
| state->buildConstants.targetPubKey = |
| parentState->buildConstants.targetPubKey; |
| state->buildConstants.certStores = |
| parentState->buildConstants.certStores; |
| state->buildConstants.anchors = |
| parentState->buildConstants.anchors; |
| state->buildConstants.userCheckers = |
| parentState->buildConstants.userCheckers; |
| state->buildConstants.hintCerts = |
| parentState->buildConstants.hintCerts; |
| state->buildConstants.revChecker = |
| parentState->buildConstants.revChecker; |
| state->buildConstants.aiaMgr = |
| parentState->buildConstants.aiaMgr; |
| state->buildConstants.trustOnlyUserAnchors = |
| parentState->buildConstants.trustOnlyUserAnchors; |
| } |
| |
| *pState = state; |
| state = NULL; |
| cleanup: |
| |
| PKIX_DECREF(state); |
| |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_GetResourceLimits |
| * |
| * DESCRIPTION: |
| * Retrieve Resource Limits from ProcessingParams and initialize them in |
| * BuildConstants. |
| * |
| * PARAMETERS |
| * "buildConstants" |
| * Address of a BuildConstants structure containing objects and values |
| * that remain constant throughout the building of a chain. 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 Build Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_GetResourceLimits( |
| BuildConstants *buildConstants, |
| void *plContext) |
| { |
| PKIX_ResourceLimits *resourceLimits = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_GetResourceLimits"); |
| PKIX_NULLCHECK_ONE(buildConstants); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetResourceLimits |
| (buildConstants->procParams, &resourceLimits, plContext), |
| PKIX_PROCESSINGPARAMSGETRESOURCELIMITSFAILED); |
| |
| buildConstants->maxFanout = 0; |
| buildConstants->maxDepth = 0; |
| buildConstants->maxTime = 0; |
| |
| if (resourceLimits) { |
| |
| PKIX_CHECK(PKIX_ResourceLimits_GetMaxFanout |
| (resourceLimits, &buildConstants->maxFanout, plContext), |
| PKIX_RESOURCELIMITSGETMAXFANOUTFAILED); |
| |
| PKIX_CHECK(PKIX_ResourceLimits_GetMaxDepth |
| (resourceLimits, &buildConstants->maxDepth, plContext), |
| PKIX_RESOURCELIMITSGETMAXDEPTHFAILED); |
| |
| PKIX_CHECK(PKIX_ResourceLimits_GetMaxTime |
| (resourceLimits, &buildConstants->maxTime, plContext), |
| PKIX_RESOURCELIMITSGETMAXTIMEFAILED); |
| } |
| |
| cleanup: |
| |
| PKIX_DECREF(resourceLimits); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_ToString |
| * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) |
| */ |
| static PKIX_Error * |
| pkix_ForwardBuilderState_ToString |
| (PKIX_PL_Object *object, |
| PKIX_PL_String **pString, |
| void *plContext) |
| { |
| PKIX_ForwardBuilderState *state = NULL; |
| PKIX_PL_String *formatString = NULL; |
| PKIX_PL_String *resultString = NULL; |
| PKIX_PL_String *buildStatusString = NULL; |
| PKIX_PL_String *validityDateString = NULL; |
| PKIX_PL_String *prevCertString = NULL; |
| PKIX_PL_String *candidateCertString = NULL; |
| PKIX_PL_String *traversedSubjNamesString = NULL; |
| PKIX_PL_String *trustChainString = NULL; |
| PKIX_PL_String *candidateCertsString = NULL; |
| PKIX_PL_String *certSelString = NULL; |
| PKIX_PL_String *verifyNodeString = NULL; |
| PKIX_PL_String *parentStateString = NULL; |
| char *asciiFormat = "\n" |
| "\t{buildStatus: \t%s\n" |
| "\ttraversedCACerts: \t%d\n" |
| "\tcertStoreIndex: \t%d\n" |
| "\tnumCerts: \t%d\n" |
| "\tnumAias: \t%d\n" |
| "\tcertIndex: \t%d\n" |
| "\taiaIndex: \t%d\n" |
| "\tnumFanout: \t%d\n" |
| "\tnumDepth: \t%d\n" |
| "\treasonCode: \t%d\n" |
| "\tcanBeCached: \t%d\n" |
| "\tuseOnlyLocal: \t%d\n" |
| "\trevChecking: \t%d\n" |
| "\tvalidityDate: \t%s\n" |
| "\tprevCert: \t%s\n" |
| "\tcandidateCert: \t%s\n" |
| "\ttraversedSubjNames: \t%s\n" |
| "\ttrustChain: \t%s\n" |
| "\tcandidateCerts: \t%s\n" |
| "\tcertSel: \t%s\n" |
| "\tverifyNode: \t%s\n" |
| "\tparentState: \t%s}\n"; |
| char *asciiStatus = NULL; |
| |
| PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_ToString"); |
| PKIX_NULLCHECK_TWO(object, pString); |
| |
| PKIX_CHECK(pkix_CheckType |
| (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext), |
| PKIX_OBJECTNOTFORWARDBUILDERSTATE); |
| |
| state = (PKIX_ForwardBuilderState *)object; |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| switch (state->status) { |
| case BUILD_SHORTCUTPENDING: asciiStatus = "BUILD_SHORTCUTPENDING"; |
| break; |
| case BUILD_INITIAL: asciiStatus = "BUILD_INITIAL"; |
| break; |
| case BUILD_TRYAIA: asciiStatus = "BUILD_TRYAIA"; |
| break; |
| case BUILD_AIAPENDING: asciiStatus = "BUILD_AIAPENDING"; |
| break; |
| case BUILD_COLLECTINGCERTS: asciiStatus = "BUILD_COLLECTINGCERTS"; |
| break; |
| case BUILD_GATHERPENDING: asciiStatus = "BUILD_GATHERPENDING"; |
| break; |
| case BUILD_CERTVALIDATING: asciiStatus = "BUILD_CERTVALIDATING"; |
| break; |
| case BUILD_ABANDONNODE: asciiStatus = "BUILD_ABANDONNODE"; |
| break; |
| case BUILD_DATEPREP: asciiStatus = "BUILD_DATEPREP"; |
| break; |
| case BUILD_CHECKTRUSTED: asciiStatus = "BUILD_CHECKTRUSTED"; |
| break; |
| case BUILD_CHECKTRUSTED2: asciiStatus = "BUILD_CHECKTRUSTED2"; |
| break; |
| case BUILD_ADDTOCHAIN: asciiStatus = "BUILD_ADDTOCHAIN"; |
| break; |
| case BUILD_VALCHAIN: asciiStatus = "BUILD_VALCHAIN"; |
| break; |
| case BUILD_VALCHAIN2: asciiStatus = "BUILD_VALCHAIN2"; |
| break; |
| case BUILD_EXTENDCHAIN: asciiStatus = "BUILD_EXTENDCHAIN"; |
| break; |
| case BUILD_GETNEXTCERT: asciiStatus = "BUILD_GETNEXTCERT"; |
| break; |
| default: asciiStatus = "INVALID STATUS"; |
| break; |
| } |
| |
| PKIX_CHECK(PKIX_PL_String_Create |
| (PKIX_ESCASCII, asciiStatus, 0, &buildStatusString, plContext), |
| PKIX_STRINGCREATEFAILED); |
| |
| PKIX_TOSTRING |
| (state->validityDate, &validityDateString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->prevCert, &prevCertString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->candidateCert, &candidateCertString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->traversedSubjNames, |
| &traversedSubjNamesString, |
| plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->trustChain, &trustChainString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->candidateCerts, &candidateCertsString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->certSel, &certSelString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->verifyNode, &verifyNodeString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_TOSTRING |
| (state->parentState, &parentStateString, plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Sprintf |
| (&resultString, |
| plContext, |
| formatString, |
| buildStatusString, |
| (PKIX_Int32)state->traversedCACerts, |
| (PKIX_UInt32)state->certStoreIndex, |
| (PKIX_UInt32)state->numCerts, |
| (PKIX_UInt32)state->numAias, |
| (PKIX_UInt32)state->certIndex, |
| (PKIX_UInt32)state->aiaIndex, |
| (PKIX_UInt32)state->numFanout, |
| (PKIX_UInt32)state->numDepth, |
| (PKIX_UInt32)state->reasonCode, |
| state->canBeCached, |
| state->useOnlyLocal, |
| state->revChecking, |
| validityDateString, |
| prevCertString, |
| candidateCertString, |
| traversedSubjNamesString, |
| trustChainString, |
| candidateCertsString, |
| certSelString, |
| verifyNodeString, |
| parentStateString), |
| PKIX_SPRINTFFAILED); |
| |
| *pString = resultString; |
| |
| cleanup: |
| PKIX_DECREF(formatString); |
| PKIX_DECREF(buildStatusString); |
| PKIX_DECREF(validityDateString); |
| PKIX_DECREF(prevCertString); |
| PKIX_DECREF(candidateCertString); |
| PKIX_DECREF(traversedSubjNamesString); |
| PKIX_DECREF(trustChainString); |
| PKIX_DECREF(candidateCertsString); |
| PKIX_DECREF(certSelString); |
| PKIX_DECREF(verifyNodeString); |
| PKIX_DECREF(parentStateString); |
| |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| |
| } |
| |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_RegisterSelf |
| * |
| * DESCRIPTION: |
| * Registers PKIX_FORWARDBUILDERSTATE_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_ForwardBuilderState_RegisterSelf(void *plContext) |
| { |
| |
| extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; |
| pkix_ClassTable_Entry entry; |
| |
| PKIX_ENTER(FORWARDBUILDERSTATE, |
| "pkix_ForwardBuilderState_RegisterSelf"); |
| |
| entry.description = "ForwardBuilderState"; |
| entry.objCounter = 0; |
| entry.typeObjectSize = sizeof(PKIX_ForwardBuilderState); |
| entry.destructor = pkix_ForwardBuilderState_Destroy; |
| entry.equalsFunction = NULL; |
| entry.hashcodeFunction = NULL; |
| entry.toStringFunction = pkix_ForwardBuilderState_ToString; |
| entry.comparator = NULL; |
| entry.duplicateFunction = NULL; |
| |
| systemClasses[PKIX_FORWARDBUILDERSTATE_TYPE] = entry; |
| |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| } |
| |
| #if PKIX_FORWARDBUILDERSTATEDEBUG |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_DumpState |
| * |
| * DESCRIPTION: |
| * This function invokes the ToString function on the argument pointed to |
| * by "state". |
| * PARAMETERS: |
| * "state" |
| * The address of the ForwardBuilderState object. Must be non-NULL. |
| * |
| * THREAD SAFETY: |
| * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) |
| */ |
| PKIX_Error * |
| pkix_ForwardBuilderState_DumpState( |
| PKIX_ForwardBuilderState *state, |
| void *plContext) |
| { |
| PKIX_PL_String *stateString = NULL; |
| char *stateAscii = NULL; |
| PKIX_UInt32 length; |
| |
| PKIX_ENTER(FORWARDBUILDERSTATE,"pkix_ForwardBuilderState_DumpState"); |
| PKIX_NULLCHECK_ONE(state); |
| |
| PKIX_CHECK(PKIX_PL_Object_InvalidateCache |
| ((PKIX_PL_Object *)state, plContext), |
| PKIX_OBJECTINVALIDATECACHEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Object_ToString |
| ((PKIX_PL_Object*)state, &stateString, plContext), |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_GetEncoded |
| (stateString, |
| PKIX_ESCASCII, |
| (void **)&stateAscii, |
| &length, |
| plContext), |
| PKIX_STRINGGETENCODEDFAILED); |
| |
| PKIX_DEBUG_ARG("In Phase 1: state = %s\n", stateAscii); |
| |
| PKIX_FREE(stateAscii); |
| PKIX_DECREF(stateString); |
| |
| cleanup: |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| } |
| #endif |
| |
| /* |
| * FUNCTION: pkix_ForwardBuilderState_IsIOPending |
| * DESCRIPTION: |
| * |
| * This function determines whether the state of the ForwardBuilderState |
| * pointed to by "state" indicates I/O is in progress, and stores the Boolean |
| * result at "pPending". |
| * |
| * PARAMETERS: |
| * "state" |
| * The address of the ForwardBuilderState object. Must be non-NULL. |
| * "pPending" |
| * The address at which the result is stored. 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 ForwardBuilderState Error if the function fails in a |
| * non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error* |
| pkix_ForwardBuilderState_IsIOPending( |
| PKIX_ForwardBuilderState *state, |
| PKIX_Boolean *pPending, |
| void *plContext) |
| { |
| PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_IsIOPending"); |
| PKIX_NULLCHECK_TWO(state, pPending); |
| |
| if ((state->status == BUILD_GATHERPENDING) || |
| (state->status == BUILD_CHECKTRUSTED2) || |
| (state->status == BUILD_VALCHAIN2) || |
| (state->status == BUILD_AIAPENDING)) { |
| *pPending = PKIX_TRUE; |
| } else { |
| *pPending = PKIX_FALSE; |
| } |
| |
| PKIX_RETURN(FORWARDBUILDERSTATE); |
| } |
| |
| /* --Private-BuildChain-Functions------------------------------------------- */ |
| |
| /* |
| * FUNCTION: pkix_Build_SortCertComparator |
| * DESCRIPTION: |
| * |
| * This Function takes two Certificates cast in "obj1" and "obj2", |
| * compares them to determine which is a more preferable certificate |
| * for chain building. This Function is suitable for use as a |
| * comparator callback for pkix_List_BubbleSort, setting "*pResult" to |
| * > 0 if "obj1" is less desirable than "obj2" and < 0 if "obj1" |
| * is more desirable than "obj2". |
| * |
| * PARAMETERS: |
| * "obj1" |
| * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert. |
| * Must be non-NULL. |
| * "obj2" |
| * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert. |
| * Must be non-NULL. |
| * "pResult" |
| * Address where the comparison result 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_SortCertComparator( |
| PKIX_PL_Object *obj1, |
| PKIX_PL_Object *obj2, |
| PKIX_Int32 *pResult, |
| void *plContext) |
| { |
| PKIX_PL_Date *date1 = NULL; |
| PKIX_PL_Date *date2 = NULL; |
| PKIX_Int32 result = 0; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_SortCertComparator"); |
| PKIX_NULLCHECK_THREE(obj1, obj2, pResult); |
| |
| /* |
| * For sorting candidate certificates, we use NotAfter date as the |
| * comparison key for now (can be expanded if desired in the future). |
| * |
| * In PKIX_BuildChain, the List of CertStores was reordered so that |
| * trusted CertStores are ahead of untrusted CertStores. That sort, or |
| * this one, could be taken out if it is determined that it doesn't help |
| * performance, or in some way hinders the solution of choosing desired |
| * candidates. |
| */ |
| |
| PKIX_CHECK(pkix_CheckType(obj1, PKIX_CERT_TYPE, plContext), |
| PKIX_OBJECTNOTCERT); |
| PKIX_CHECK(pkix_CheckType(obj2, PKIX_CERT_TYPE, plContext), |
| PKIX_OBJECTNOTCERT); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter |
| ((PKIX_PL_Cert *)obj1, &date1, plContext), |
| PKIX_CERTGETVALIDITYNOTAFTERFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter |
| ((PKIX_PL_Cert *)obj2, &date2, plContext), |
| PKIX_CERTGETVALIDITYNOTAFTERFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Object_Compare |
| ((PKIX_PL_Object *)date1, |
| (PKIX_PL_Object *)date2, |
| &result, |
| plContext), |
| PKIX_OBJECTCOMPARATORFAILED); |
| |
| /* |
| * Invert the result, so that if date1 is greater than date2, |
| * obj1 is sorted before obj2. This is because pkix_List_BubbleSort |
| * sorts in ascending order. |
| */ |
| *pResult = -result; |
| |
| cleanup: |
| |
| PKIX_DECREF(date1); |
| PKIX_DECREF(date2); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* This local error check macro */ |
| #define ERROR_CHECK(errCode) \ |
| if (pkixErrorResult) { \ |
| if (pkixLog) { \ |
| PR_LOG(pkixLog, PR_LOG_DEBUG, ("====> ERROR_CHECK code %s\n", #errCode)); \ |
| } \ |
| pkixTempErrorReceived = PKIX_TRUE; \ |
| pkixErrorClass = pkixErrorResult->errClass; \ |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { \ |
| goto cleanup; \ |
| } \ |
| if (verifyNode) { \ |
| PKIX_DECREF(verifyNode->error); \ |
| PKIX_INCREF(pkixErrorResult); \ |
| verifyNode->error = pkixErrorResult; \ |
| } \ |
| pkixErrorCode = errCode; \ |
| goto cleanup; \ |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_VerifyCertificate |
| * DESCRIPTION: |
| * |
| * Checks whether the previous Cert stored in the ForwardBuilderState pointed |
| * to by "state" successfully chains, including signature verification, to the |
| * candidate Cert also stored in "state", using the Boolean value in "trusted" |
| * to determine whether "candidateCert" is trusted. |
| * |
| * First it checks whether "candidateCert" has already been traversed by |
| * determining whether it is contained in the List of traversed Certs. It then |
| * checks the candidate Cert with user checkers, if any, in the List pointed to |
| * by "userCheckers". Finally, it runs the signature validation. |
| * |
| * If this Certificate fails verification, and state->verifyNode is non-NULL, |
| * this function sets the Error code into the verifyNode. |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. Must be non-NULL. |
| * "userCheckers" |
| * Address of a List of CertChainCheckers to be used, if present, to |
| * validate the candidateCert. |
| * "trusted" |
| * Boolean value of trust for the candidate Cert |
| * "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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_VerifyCertificate( |
| PKIX_ForwardBuilderState *state, |
| PKIX_List *userCheckers, |
| PKIX_Boolean *pTrusted, |
| PKIX_VerifyNode *verifyNode, |
| void *plContext) |
| { |
| PKIX_UInt32 numUserCheckers = 0; |
| PKIX_UInt32 i = 0; |
| PKIX_Boolean loopFound = PKIX_FALSE; |
| PKIX_Boolean supportForwardChecking = PKIX_FALSE; |
| PKIX_Boolean trusted = PKIX_FALSE; |
| PKIX_PL_Cert *candidateCert = NULL; |
| PKIX_PL_PublicKey *candidatePubKey = NULL; |
| PKIX_CertChainChecker *userChecker = NULL; |
| PKIX_CertChainChecker_CheckCallback checkerCheck = NULL; |
| PKIX_PL_TrustAnchorMode trustAnchorMode = |
| PKIX_PL_TrustAnchorMode_Ignore; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_VerifyCertificate"); |
| PKIX_NULLCHECK_TWO(state, pTrusted); |
| PKIX_NULLCHECK_THREE |
| (state->candidateCerts, state->prevCert, state->trustChain); |
| |
| PKIX_INCREF(state->candidateCert); |
| candidateCert = state->candidateCert; |
| |
| if (state->buildConstants.numAnchors) { |
| if (state->buildConstants.trustOnlyUserAnchors) { |
| trustAnchorMode = PKIX_PL_TrustAnchorMode_Exclusive; |
| } else { |
| trustAnchorMode = PKIX_PL_TrustAnchorMode_Additive; |
| } |
| } else { |
| trustAnchorMode = PKIX_PL_TrustAnchorMode_Ignore; |
| } |
| |
| PKIX_CHECK( |
| PKIX_PL_Cert_IsCertTrusted(candidateCert, trustAnchorMode, |
| &trusted, plContext), |
| PKIX_CERTISCERTTRUSTEDFAILED); |
| |
| *pTrusted = trusted; |
| |
| /* check for loops */ |
| PKIX_CHECK(pkix_List_Contains |
| (state->trustChain, |
| (PKIX_PL_Object *)candidateCert, |
| &loopFound, |
| plContext), |
| PKIX_LISTCONTAINSFAILED); |
| |
| if (loopFound) { |
| if (verifyNode != NULL) { |
| PKIX_Error *verifyError = NULL; |
| PKIX_ERROR_CREATE |
| (BUILD, |
| PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED, |
| verifyError); |
| PKIX_DECREF(verifyNode->error); |
| verifyNode->error = verifyError; |
| } |
| /* Even if error logged, still need to abort |
| * if cert is not trusted. */ |
| if (!trusted) { |
| PKIX_ERROR(PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED); |
| } |
| state->certLoopingDetected = PKIX_TRUE; |
| } |
| |
| if (userCheckers != NULL) { |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (userCheckers, &numUserCheckers, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| for (i = 0; i < numUserCheckers; i++) { |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (userCheckers, |
| i, |
| (PKIX_PL_Object **) &userChecker, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK |
| (PKIX_CertChainChecker_IsForwardCheckingSupported |
| (userChecker, &supportForwardChecking, plContext), |
| PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED); |
| |
| if (supportForwardChecking == PKIX_TRUE) { |
| |
| PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback |
| (userChecker, &checkerCheck, plContext), |
| PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED); |
| |
| pkixErrorResult = |
| checkerCheck(userChecker, candidateCert, NULL, |
| &nbioContext, plContext); |
| |
| ERROR_CHECK(PKIX_USERCHECKERCHECKFAILED); |
| } |
| |
| PKIX_DECREF(userChecker); |
| } |
| } |
| |
| /* Check that public key of the trusted dsa cert has |
| * dsa parameters */ |
| if (trusted) { |
| PKIX_Boolean paramsNeeded = PKIX_FALSE; |
| PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey |
| (candidateCert, &candidatePubKey, plContext), |
| PKIX_CERTGETSUBJECTPUBLICKEYFAILED); |
| PKIX_CHECK(PKIX_PL_PublicKey_NeedsDSAParameters |
| (candidatePubKey, ¶msNeeded, plContext), |
| PKIX_PUBLICKEYNEEDSDSAPARAMETERSFAILED); |
| if (paramsNeeded) { |
| PKIX_ERROR(PKIX_MISSINGDSAPARAMETERS); |
| } |
| } |
| |
| cleanup: |
| PKIX_DECREF(candidateCert); |
| PKIX_DECREF(candidatePubKey); |
| PKIX_DECREF(userChecker); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_ValidationCheckers |
| * DESCRIPTION: |
| * |
| * Creates a List of Objects to be used in determining whether the List of |
| * Certs pointed to by "certChain" successfully validates using the |
| * ForwardBuilderState pointed to by "state", and the TrustAnchor pointed to by |
| * "anchor". These objects are a reversed Cert Chain, consisting of the certs |
| * in "certChain" in reversed order, suitable for presenting to the |
| * CertChainCheckers; a List of critical extension OIDS that have already been |
| * processed in forward building; a List of CertChainCheckers to be called, and |
| * a List of RevocationCheckers to be called. These results are stored in |
| * fields of "state". |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. Must be non-NULL. |
| * "certChain" |
| * Address of List of Certs to be validated. Must be non-NULL. |
| * "anchor" |
| * Address of TrustAnchor to be used. Must be non-NULL. |
| * "addEkuChecker" |
| * Boolean flags that tells to add eku checker to the list |
| * of checkers. Only needs to be done for existing chain revalidation. |
| * "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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_ValidationCheckers( |
| PKIX_ForwardBuilderState *state, |
| PKIX_List *certChain, |
| PKIX_TrustAnchor *anchor, |
| PKIX_Boolean chainRevalidationStage, |
| void *plContext) |
| { |
| PKIX_List *checkers = NULL; |
| PKIX_List *initialPolicies = NULL; |
| PKIX_List *reversedCertChain = NULL; |
| PKIX_List *buildCheckedCritExtOIDsList = NULL; |
| PKIX_ProcessingParams *procParams = NULL; |
| PKIX_PL_Cert *trustedCert = NULL; |
| PKIX_PL_PublicKey *trustedPubKey = NULL; |
| PKIX_PL_CertNameConstraints *trustedNC = NULL; |
| PKIX_CertChainChecker *sigChecker = NULL; |
| PKIX_CertChainChecker *policyChecker = NULL; |
| PKIX_CertChainChecker *userChecker = NULL; |
| PKIX_CertChainChecker *nameConstraintsChecker = NULL; |
| PKIX_CertChainChecker *checker = NULL; |
| PKIX_CertSelector *certSelector = NULL; |
| PKIX_List *userCheckerExtOIDs = NULL; |
| PKIX_PL_OID *oid = NULL; |
| PKIX_Boolean supportForwardChecking = PKIX_FALSE; |
| PKIX_Boolean policyQualifiersRejected = PKIX_FALSE; |
| PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE; |
| PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE; |
| PKIX_Boolean initialExplicitPolicy = PKIX_FALSE; |
| PKIX_UInt32 numChainCerts; |
| PKIX_UInt32 numCertCheckers; |
| PKIX_UInt32 i; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_ValidationCheckers"); |
| PKIX_NULLCHECK_THREE(state, certChain, anchor); |
| |
| PKIX_CHECK(PKIX_List_Create(&checkers, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_ReverseList |
| (certChain, &reversedCertChain, plContext), |
| PKIX_LISTREVERSELISTFAILED); |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (reversedCertChain, &numChainCerts, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| procParams = state->buildConstants.procParams; |
| |
| /* Do need to add a number of checker to revalidate |
| * a built chain. KU, EKU, CertType and Validity Date |
| * get checked by certificate selector during chain |
| * construction, but needed to be checked for chain from |
| * the cache.*/ |
| if (chainRevalidationStage) { |
| PKIX_CHECK(pkix_ExpirationChecker_Initialize |
| (state->buildConstants.testDate, &checker, plContext), |
| PKIX_EXPIRATIONCHECKERINITIALIZEFAILED); |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, (PKIX_PL_Object *)checker, plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| PKIX_DECREF(checker); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints |
| (procParams, &certSelector, plContext), |
| PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); |
| |
| PKIX_CHECK(pkix_TargetCertChecker_Initialize |
| (certSelector, numChainCerts, &checker, plContext), |
| PKIX_EXPIRATIONCHECKERINITIALIZEFAILED); |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, (PKIX_PL_Object *)checker, plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| PKIX_DECREF(checker); |
| } |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetInitialPolicies |
| (procParams, &initialPolicies, plContext), |
| PKIX_PROCESSINGPARAMSGETINITIALPOLICIESFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetPolicyQualifiersRejected |
| (procParams, &policyQualifiersRejected, plContext), |
| PKIX_PROCESSINGPARAMSGETPOLICYQUALIFIERSREJECTEDFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_IsPolicyMappingInhibited |
| (procParams, &initialPolicyMappingInhibit, plContext), |
| PKIX_PROCESSINGPARAMSISPOLICYMAPPINGINHIBITEDFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_IsAnyPolicyInhibited |
| (procParams, &initialAnyPolicyInhibit, plContext), |
| PKIX_PROCESSINGPARAMSISANYPOLICYINHIBITEDFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_IsExplicitPolicyRequired |
| (procParams, &initialExplicitPolicy, plContext), |
| PKIX_PROCESSINGPARAMSISEXPLICITPOLICYREQUIREDFAILED); |
| |
| PKIX_CHECK(pkix_PolicyChecker_Initialize |
| (initialPolicies, |
| policyQualifiersRejected, |
| initialPolicyMappingInhibit, |
| initialExplicitPolicy, |
| initialAnyPolicyInhibit, |
| numChainCerts, |
| &policyChecker, |
| plContext), |
| PKIX_POLICYCHECKERINITIALIZEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, (PKIX_PL_Object *)policyChecker, plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| /* |
| * Create an OID list that contains critical extensions processed |
| * by BuildChain. These are specified in a static const array. |
| */ |
| PKIX_CHECK(PKIX_List_Create(&buildCheckedCritExtOIDsList, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| for (i = 0; buildCheckedCritExtOIDs[i] != PKIX_UNKNOWN_OID; i++) { |
| PKIX_CHECK(PKIX_PL_OID_Create |
| (buildCheckedCritExtOIDs[i], &oid, plContext), |
| PKIX_OIDCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (buildCheckedCritExtOIDsList, |
| (PKIX_PL_Object *) oid, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| PKIX_DECREF(oid); |
| } |
| |
| if (state->buildConstants.userCheckers != NULL) { |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (state->buildConstants.userCheckers, |
| &numCertCheckers, |
| plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| for (i = 0; i < numCertCheckers; i++) { |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (state->buildConstants.userCheckers, |
| i, |
| (PKIX_PL_Object **) &userChecker, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK |
| (PKIX_CertChainChecker_IsForwardCheckingSupported |
| (userChecker, &supportForwardChecking, plContext), |
| PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); |
| |
| /* |
| * If this userChecker supports forwardChecking then it |
| * should have been checked during build chain. Skip |
| * checking but need to add checker's extension OIDs |
| * to buildCheckedCritExtOIDsList. |
| */ |
| if (supportForwardChecking == PKIX_TRUE) { |
| |
| PKIX_CHECK |
| (PKIX_CertChainChecker_GetSupportedExtensions |
| (userChecker, &userCheckerExtOIDs, plContext), |
| PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED); |
| |
| if (userCheckerExtOIDs != NULL) { |
| PKIX_CHECK(pkix_List_AppendList |
| (buildCheckedCritExtOIDsList, |
| userCheckerExtOIDs, |
| plContext), |
| PKIX_LISTAPPENDLISTFAILED); |
| } |
| |
| } else { |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, |
| (PKIX_PL_Object *)userChecker, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| } |
| |
| PKIX_DECREF(userCheckerExtOIDs); |
| PKIX_DECREF(userChecker); |
| } |
| } |
| |
| /* Enabling post chain building signature check on the certs. */ |
| PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
| (anchor, &trustedCert, plContext), |
| PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey |
| (trustedCert, &trustedPubKey, plContext), |
| PKIX_CERTGETSUBJECTPUBLICKEYFAILED); |
| |
| PKIX_CHECK(pkix_SignatureChecker_Initialize |
| (trustedPubKey, |
| numChainCerts, |
| &sigChecker, |
| plContext), |
| PKIX_SIGNATURECHECKERINITIALIZEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, |
| (PKIX_PL_Object *)sigChecker, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| /* Enabling post chain building name constraints check on the certs. */ |
| PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints |
| (anchor, &trustedNC, plContext), |
| PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED); |
| |
| PKIX_CHECK(pkix_NameConstraintsChecker_Initialize |
| (trustedNC, numChainCerts, &nameConstraintsChecker, |
| plContext), |
| PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (checkers, |
| (PKIX_PL_Object *)nameConstraintsChecker, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| |
| PKIX_DECREF(state->reversedCertChain); |
| PKIX_INCREF(reversedCertChain); |
| state->reversedCertChain = reversedCertChain; |
| PKIX_DECREF(state->checkedCritExtOIDs); |
| PKIX_INCREF(buildCheckedCritExtOIDsList); |
| state->checkedCritExtOIDs = buildCheckedCritExtOIDsList; |
| PKIX_DECREF(state->checkerChain); |
| state->checkerChain = checkers; |
| checkers = NULL; |
| state->certCheckedIndex = 0; |
| state->checkerIndex = 0; |
| state->revChecking = PKIX_FALSE; |
| |
| |
| cleanup: |
| |
| PKIX_DECREF(oid); |
| PKIX_DECREF(reversedCertChain); |
| PKIX_DECREF(buildCheckedCritExtOIDsList); |
| PKIX_DECREF(checker); |
| PKIX_DECREF(checkers); |
| PKIX_DECREF(initialPolicies); |
| PKIX_DECREF(trustedCert); |
| PKIX_DECREF(trustedPubKey); |
| PKIX_DECREF(certSelector); |
| PKIX_DECREF(sigChecker); |
| PKIX_DECREF(trustedNC); |
| PKIX_DECREF(nameConstraintsChecker); |
| PKIX_DECREF(policyChecker); |
| PKIX_DECREF(userChecker); |
| PKIX_DECREF(userCheckerExtOIDs); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_ValidateEntireChain |
| * DESCRIPTION: |
| * |
| * Checks whether the current List of Certs successfully validates using the |
| * TrustAnchor pointed to by "anchor" and other parameters contained, as was |
| * the Cert List, in "state". |
| * |
| * If a checker using non-blocking I/O returns with a non-NULL non-blocking I/O |
| * context (NBIOContext), an indication that I/O is in progress and the |
| * checking has not been completed, this function stores that context at |
| * "pNBIOContext". Otherwise, it stores NULL at "pNBIOContext". |
| * |
| * If not awaiting I/O and if successful, a ValidateResult is created |
| * containing the Public Key of the target certificate (including DSA parameter |
| * inheritance, if any) and the PolicyNode representing the policy tree output |
| * by the validation algorithm. If not successful, an Error pointer is |
| * returned. |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. Must be non-NULL. |
| * "anchor" |
| * Address of TrustAnchor to be used. Must be non-NULL. |
| * "pNBIOContext" |
| * Address at which the NBIOContext is stored indicating whether the |
| * validation is complete. Must be non-NULL. |
| * "pValResult" |
| * Address at which the ValidateResult is stored. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_ValidateEntireChain( |
| PKIX_ForwardBuilderState *state, |
| PKIX_TrustAnchor *anchor, |
| void **pNBIOContext, |
| PKIX_ValidateResult **pValResult, |
| PKIX_VerifyNode *verifyNode, |
| void *plContext) |
| { |
| PKIX_UInt32 numChainCerts = 0; |
| PKIX_PL_PublicKey *subjPubKey = NULL; |
| PKIX_PolicyNode *policyTree = NULL; |
| PKIX_ValidateResult *valResult = NULL; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_ValidateEntireChain"); |
| PKIX_NULLCHECK_FOUR(state, anchor, pNBIOContext, pValResult); |
| |
| *pNBIOContext = NULL; /* prepare for case of error exit */ |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (state->reversedCertChain, &numChainCerts, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| pkixErrorResult = |
| pkix_CheckChain(state->reversedCertChain, numChainCerts, anchor, |
| state->checkerChain, |
| state->buildConstants.revChecker, |
| state->checkedCritExtOIDs, |
| state->buildConstants.procParams, |
| &state->certCheckedIndex, &state->checkerIndex, |
| &state->revChecking, &state->reasonCode, |
| &nbioContext, &subjPubKey, &policyTree, NULL, |
| plContext); |
| |
| if (nbioContext != NULL) { |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| |
| ERROR_CHECK(PKIX_CHECKCHAINFAILED); |
| |
| /* XXX Remove this assertion after 2014-12-31. See bug 946984. */ |
| PORT_Assert(state->reasonCode == 0); |
| |
| PKIX_CHECK(pkix_ValidateResult_Create |
| (subjPubKey, anchor, policyTree, &valResult, plContext), |
| PKIX_VALIDATERESULTCREATEFAILED); |
| |
| *pValResult = valResult; |
| valResult = NULL; |
| |
| cleanup: |
| PKIX_DECREF(subjPubKey); |
| PKIX_DECREF(policyTree); |
| PKIX_DECREF(valResult); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_SortCandidateCerts |
| * DESCRIPTION: |
| * |
| * This function sorts a List of candidate Certs pointed to by "candidates" |
| * using an algorithm that places Certs most likely to produce a successful |
| * chain at the front of the list, storing the resulting sorted List at |
| * "pSortedCandidates". |
| * |
| * At present the only sort criterion is that trusted Certs go ahead of |
| * untrusted Certs. |
| * |
| * PARAMETERS: |
| * "candidates" |
| * Address of List of Candidate Certs to be sorted. Must be non-NULL. |
| * "pSortedCandidates" |
| * Address at which sorted List is stored. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_SortCandidateCerts( |
| PKIX_List *candidates, |
| PKIX_List **pSortedCandidates, |
| void *plContext) |
| { |
| PKIX_List *sortedList = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_SortCandidateCerts"); |
| PKIX_NULLCHECK_TWO(candidates, pSortedCandidates); |
| |
| /* |
| * Both bubble and quick sort algorithms are available. |
| * For a list of fewer than around 100 items, the bubble sort is more |
| * efficient. (This number was determined by experimenting with both |
| * algorithms on a Java List.) |
| * If the candidate list is very small, using the sort can drag down |
| * the performance a little bit. |
| */ |
| |
| PKIX_CHECK(pkix_List_BubbleSort |
| (candidates, |
| pkix_Build_SortCertComparator, |
| &sortedList, |
| plContext), |
| PKIX_LISTBUBBLESORTFAILED); |
| |
| *pSortedCandidates = sortedList; |
| |
| cleanup: |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_BuildSelectorAndParams |
| * DESCRIPTION: |
| * |
| * This function creates a CertSelector, initialized with an appropriate |
| * ComCertSelParams, using the variables provided in the ForwardBuilderState |
| * pointed to by "state". The CertSelector created is stored in the certsel |
| * element of "state". |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_BuildSelectorAndParams( |
| PKIX_ForwardBuilderState *state, |
| void *plContext) |
| { |
| PKIX_ComCertSelParams *certSelParams = NULL; |
| PKIX_CertSelector *certSel = NULL; |
| PKIX_PL_X500Name *currentIssuer = NULL; |
| PKIX_PL_ByteArray *authKeyId = NULL; |
| PKIX_PL_Date *testDate = NULL; |
| PKIX_CertSelector *callerCertSelector = NULL; |
| PKIX_ComCertSelParams *callerComCertSelParams = NULL; |
| PKIX_UInt32 reqKu = 0; |
| PKIX_List *reqEkuOids = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_BuildSelectorAndParams"); |
| PKIX_NULLCHECK_THREE(state, state->prevCert, state->traversedSubjNames); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetIssuer |
| (state->prevCert, ¤tIssuer, plContext), |
| PKIX_CERTGETISSUERFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier |
| (state->prevCert, &authKeyId, plContext), |
| PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_Create(&certSelParams, plContext), |
| PKIX_COMCERTSELPARAMSCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_SetSubject |
| (certSelParams, currentIssuer, plContext), |
| PKIX_COMCERTSELPARAMSSETSUBJECTFAILED); |
| |
| if (authKeyId != NULL) { |
| PKIX_CHECK(PKIX_ComCertSelParams_SetSubjKeyIdentifier |
| (certSelParams, authKeyId, plContext), |
| PKIX_COMCERTSELPARAMSSETSUBJKEYIDENTIFIERFAILED); |
| } |
| |
| PKIX_INCREF(state->buildConstants.testDate); |
| testDate = state->buildConstants.testDate; |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_SetCertificateValid |
| (certSelParams, testDate, plContext), |
| PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_SetBasicConstraints |
| (certSelParams, state->traversedCACerts, plContext), |
| PKIX_COMCERTSELPARAMSSETBASICCONSTRAINTSFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_SetPathToNames |
| (certSelParams, state->traversedSubjNames, plContext), |
| PKIX_COMCERTSELPARAMSSETPATHTONAMESFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints |
| (state->buildConstants.procParams, |
| &callerCertSelector, plContext), |
| PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); |
| |
| if (callerCertSelector != NULL) { |
| |
| /* Get initial EKU OIDs from ComCertSelParams, if set */ |
| PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams |
| (callerCertSelector, &callerComCertSelParams, plContext), |
| PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED); |
| |
| if (callerComCertSelParams != NULL) { |
| PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage |
| (callerComCertSelParams, &reqEkuOids, plContext), |
| PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_GetKeyUsage |
| (callerComCertSelParams, &reqKu, plContext), |
| PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED); |
| } |
| } |
| |
| PKIX_CHECK( |
| PKIX_ComCertSelParams_SetKeyUsage(certSelParams, reqKu, |
| plContext), |
| PKIX_COMCERTSELPARAMSSETKEYUSAGEFAILED); |
| |
| PKIX_CHECK( |
| PKIX_ComCertSelParams_SetExtendedKeyUsage(certSelParams, |
| reqEkuOids, |
| plContext), |
| PKIX_COMCERTSELPARAMSSETEXTKEYUSAGEFAILED); |
| |
| PKIX_CHECK(PKIX_CertSelector_Create |
| (NULL, NULL, &state->certSel, plContext), |
| PKIX_CERTSELECTORCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams |
| (state->certSel, certSelParams, plContext), |
| PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED); |
| |
| PKIX_CHECK(PKIX_List_Create(&state->candidateCerts, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| state->certStoreIndex = 0; |
| |
| cleanup: |
| PKIX_DECREF(certSelParams); |
| PKIX_DECREF(certSel); |
| PKIX_DECREF(currentIssuer); |
| PKIX_DECREF(authKeyId); |
| PKIX_DECREF(testDate); |
| PKIX_DECREF(reqEkuOids); |
| PKIX_DECREF(callerComCertSelParams); |
| PKIX_DECREF(callerCertSelector); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* Match trust anchor to select params in order to find next cert. */ |
| static PKIX_Error* |
| pkix_Build_SelectCertsFromTrustAnchors( |
| PKIX_List *trustAnchorsList, |
| PKIX_ComCertSelParams *certSelParams, |
| PKIX_List **pMatchList, |
| void *plContext) |
| { |
| unsigned int anchorIndex = 0; |
| PKIX_TrustAnchor *anchor = NULL; |
| PKIX_PL_Cert *trustedCert = NULL; |
| PKIX_List *matchList = NULL; |
| PKIX_CertSelector *certSel = NULL; |
| PKIX_CertSelector_MatchCallback selectorMatchCB = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_SelectCertsFromTrustAnchors"); |
| |
| PKIX_CHECK(PKIX_CertSelector_Create |
| (NULL, NULL, &certSel, plContext), |
| PKIX_CERTSELECTORCREATEFAILED); |
| PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams |
| (certSel, certSelParams, plContext), |
| PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED); |
| PKIX_CHECK(PKIX_CertSelector_GetMatchCallback |
| (certSel, &selectorMatchCB, plContext), |
| PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); |
| |
| for (anchorIndex = 0;anchorIndex < trustAnchorsList->length; anchorIndex++) { |
| PKIX_CHECK( |
| PKIX_List_GetItem(trustAnchorsList, |
| anchorIndex, |
| (PKIX_PL_Object **)&anchor, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
| (anchor, &trustedCert, plContext), |
| PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
| pkixErrorResult = |
| (*selectorMatchCB)(certSel, trustedCert, plContext); |
| if (!pkixErrorResult) { |
| if (!matchList) { |
| PKIX_CHECK(PKIX_List_Create(&matchList, |
| plContext), |
| PKIX_LISTCREATEFAILED); |
| } |
| PKIX_CHECK( |
| PKIX_List_AppendItem(matchList, |
| (PKIX_PL_Object*)trustedCert, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| } else { |
| PKIX_DECREF(pkixErrorResult); |
| } |
| PKIX_DECREF(trustedCert); |
| PKIX_DECREF(anchor); |
| } |
| |
| *pMatchList = matchList; |
| matchList = NULL; |
| |
| cleanup: |
| PKIX_DECREF(matchList); |
| PKIX_DECREF(trustedCert); |
| PKIX_DECREF(anchor); |
| PKIX_DECREF(certSel); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| |
| static PKIX_Error* |
| pkix_Build_RemoveDupUntrustedCerts( |
| PKIX_List *trustedCertList, |
| PKIX_List *certsFound, |
| void *plContext) |
| { |
| PKIX_UInt32 trustIndex; |
| PKIX_PL_Cert *trustCert = NULL, *cert = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_RemoveDupUntrustedCerts"); |
| if (trustedCertList == NULL || certsFound == NULL) { |
| goto cleanup; |
| } |
| for (trustIndex = 0;trustIndex < trustedCertList->length; |
| trustIndex++) { |
| PKIX_UInt32 certIndex = 0; |
| PKIX_CHECK( |
| PKIX_List_GetItem(trustedCertList, |
| trustIndex, |
| (PKIX_PL_Object **)&trustCert, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| while (certIndex < certsFound->length) { |
| PKIX_Boolean result = PKIX_FALSE; |
| PKIX_DECREF(cert); |
| PKIX_CHECK( |
| PKIX_List_GetItem(certsFound, certIndex, |
| (PKIX_PL_Object **)&cert, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| PKIX_CHECK( |
| PKIX_PL_Object_Equals((PKIX_PL_Object *)trustCert, |
| (PKIX_PL_Object *)cert, |
| &result, |
| plContext), |
| PKIX_OBJECTEQUALSFAILED); |
| if (!result) { |
| certIndex += 1; |
| continue; |
| } |
| PKIX_CHECK( |
| PKIX_List_DeleteItem(certsFound, certIndex, |
| plContext), |
| PKIX_LISTDELETEITEMFAILED); |
| } |
| PKIX_DECREF(trustCert); |
| } |
| cleanup: |
| PKIX_DECREF(cert); |
| PKIX_DECREF(trustCert); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| |
| /* |
| * FUNCTION: pkix_Build_GatherCerts |
| * DESCRIPTION: |
| * |
| * This function traverses the CertStores in the List of CertStores contained |
| * in "state", using the certSelector and other parameters contained in |
| * "state", to obtain a List of all available Certs that satisfy the criteria. |
| * If a CertStore has a cache, "certSelParams" is used both to query the cache |
| * and, if an actual CertStore search occurred, to update the cache. (Behavior |
| * is undefined if "certSelParams" is different from the parameters that were |
| * used to initialize the certSelector in "state".) |
| * |
| * If a CertStore using non-blocking I/O returns with an indication that I/O is |
| * in progress and the checking has not been completed, this function stores |
| * platform-dependent information at "pNBIOContext". Otherwise it stores NULL |
| * at "pNBIOContext", and state is updated with the results of the search. |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. Must be non-NULL. |
| * "certSelParams" |
| * Address of ComCertSelParams which were used in creating the current |
| * CertSelector, and to be used in querying and updating any caches that |
| * may be associated with with the CertStores. |
| * "pNBIOContext" |
| * Address at which platform-dependent information is returned if request |
| * is suspended for non-blocking I/O. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| /* return NULL if wouldblock, empty list if none found, else list of found */ |
| static PKIX_Error * |
| pkix_Build_GatherCerts( |
| PKIX_ForwardBuilderState *state, |
| PKIX_ComCertSelParams *certSelParams, |
| void **pNBIOContext, |
| void *plContext) |
| { |
| PKIX_Boolean certStoreIsCached = PKIX_FALSE; |
| PKIX_Boolean certStoreIsLocal = PKIX_FALSE; |
| PKIX_Boolean foundInCache = PKIX_FALSE; |
| PKIX_CertStore *certStore = NULL; |
| PKIX_CertStore_CertCallback getCerts = NULL; |
| PKIX_List *certsFound = NULL; |
| PKIX_List *trustedCertList = NULL; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_GatherCerts"); |
| PKIX_NULLCHECK_THREE(state, certSelParams, pNBIOContext); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| PKIX_DECREF(state->candidateCerts); |
| |
| while (state->certStoreIndex < state->buildConstants.numCertStores) { |
| |
| /* Get the current CertStore */ |
| PKIX_CHECK(PKIX_List_GetItem |
| (state->buildConstants.certStores, |
| state->certStoreIndex, |
| (PKIX_PL_Object **)&certStore, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(PKIX_CertStore_GetLocalFlag |
| (certStore, &certStoreIsLocal, plContext), |
| PKIX_CERTSTOREGETLOCALFLAGFAILED); |
| |
| if (state->useOnlyLocal == certStoreIsLocal) { |
| /* If GATHERPENDING, we've already checked the cache */ |
| if (state->status == BUILD_GATHERPENDING) { |
| certStoreIsCached = PKIX_FALSE; |
| foundInCache = PKIX_FALSE; |
| } else { |
| PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag |
| (certStore, &certStoreIsCached, plContext), |
| PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED); |
| |
| if (certStoreIsCached) { |
| /* |
| * Look for Certs in the cache, using the SubjectName as |
| * the key. Then the ComCertSelParams are used to filter |
| * for qualified certs. If none are found, then the |
| * certStores are queried. When we eventually add items |
| * to the cache, we will only add items that passed the |
| * ComCertSelParams filter, rather than all Certs which |
| * matched the SubjectName. |
| */ |
| |
| PKIX_CHECK(pkix_CacheCert_Lookup |
| (certStore, |
| certSelParams, |
| state->buildConstants.testDate, |
| &foundInCache, |
| &certsFound, |
| plContext), |
| PKIX_CACHECERTCHAINLOOKUPFAILED); |
| |
| } |
| } |
| |
| /* |
| * XXX need to verify if Cert is trusted, hence may not |
| * be worth it to have the Cert Cached or |
| * If it is trusted, don't cache, but once there is cached |
| * certs, we won't get certs from database any more. |
| * can use flag to force not getting certs from cache |
| */ |
| if (!foundInCache) { |
| |
| if (nbioContext == NULL) { |
| PKIX_CHECK(PKIX_CertStore_GetCertCallback |
| (certStore, &getCerts, plContext), |
| PKIX_CERTSTOREGETCERTCALLBACKFAILED); |
| |
| PKIX_CHECK(getCerts |
| (certStore, |
| state->certSel, |
| state->verifyNode, |
| &nbioContext, |
| &certsFound, |
| plContext), |
| PKIX_GETCERTSFAILED); |
| } else { |
| PKIX_CHECK(PKIX_CertStore_CertContinue |
| (certStore, |
| state->certSel, |
| state->verifyNode, |
| &nbioContext, |
| &certsFound, |
| plContext), |
| PKIX_CERTSTORECERTCONTINUEFAILED); |
| } |
| |
| if (certStoreIsCached && certsFound) { |
| |
| PKIX_CHECK(pkix_CacheCert_Add |
| (certStore, |
| certSelParams, |
| certsFound, |
| plContext), |
| PKIX_CACHECERTADDFAILED); |
| } |
| } |
| |
| /* |
| * getCerts returns an empty list for "NONE FOUND", |
| * a NULL list for "would block" |
| */ |
| if (certsFound == NULL) { |
| state->status = BUILD_GATHERPENDING; |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| } |
| |
| /* Are there any more certStores to query? */ |
| PKIX_DECREF(certStore); |
| ++(state->certStoreIndex); |
| } |
| |
| if (certsFound && certsFound->length > 1) { |
| PKIX_List *sorted = NULL; |
| |
| /* sort Certs to try to optimize search */ |
| PKIX_CHECK(pkix_Build_SortCandidateCerts |
| (certsFound, &sorted, plContext), |
| PKIX_BUILDSORTCANDIDATECERTSFAILED); |
| PKIX_DECREF(certsFound); |
| certsFound = sorted; |
| } |
| |
| PKIX_CHECK( |
| pkix_Build_SelectCertsFromTrustAnchors( |
| state->buildConstants.anchors, |
| certSelParams, &trustedCertList, |
| plContext), |
| PKIX_FAILTOSELECTCERTSFROMANCHORS); |
| PKIX_CHECK( |
| pkix_Build_RemoveDupUntrustedCerts(trustedCertList, |
| certsFound, |
| plContext), |
| PKIX_REMOVEDUPUNTRUSTEDCERTSFAILED); |
| |
| PKIX_CHECK( |
| pkix_List_MergeLists(trustedCertList, |
| certsFound, |
| &state->candidateCerts, |
| plContext), |
| PKIX_LISTMERGEFAILED); |
| |
| /* No, return the list we have gathered */ |
| PKIX_CHECK(PKIX_List_GetLength |
| (state->candidateCerts, &state->numCerts, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| state->certIndex = 0; |
| |
| cleanup: |
| PKIX_DECREF(trustedCertList); |
| PKIX_DECREF(certStore); |
| PKIX_DECREF(certsFound); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_UpdateDate |
| * DESCRIPTION: |
| * |
| * This function updates the validityDate contained in "state", for the current |
| * CertChain contained in "state", to include the validityDate of the |
| * candidateCert contained in "state". The validityDate of a chain is the |
| * earliest of all the notAfter dates contained in the respective Certificates. |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_UpdateDate( |
| PKIX_ForwardBuilderState *state, |
| void *plContext) |
| { |
| PKIX_Boolean canBeCached = PKIX_FALSE; |
| PKIX_Int32 comparison = 0; |
| PKIX_PL_Date *notAfter = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_UpdateDate"); |
| PKIX_NULLCHECK_ONE(state); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetCacheFlag |
| (state->candidateCert, &canBeCached, plContext), |
| PKIX_CERTGETCACHEFLAGFAILED); |
| |
| state->canBeCached = state->canBeCached && canBeCached; |
| if (state->canBeCached == PKIX_TRUE) { |
| |
| /* |
| * So far, all certs can be cached. Update cert |
| * chain validity time, which is the earliest of |
| * all certs' notAfter times. |
| */ |
| PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter |
| (state->candidateCert, ¬After, plContext), |
| PKIX_CERTGETVALIDITYNOTAFTERFAILED); |
| |
| if (state->validityDate == NULL) { |
| state->validityDate = notAfter; |
| notAfter = NULL; |
| } else { |
| PKIX_CHECK(PKIX_PL_Object_Compare |
| ((PKIX_PL_Object *)state->validityDate, |
| (PKIX_PL_Object *)notAfter, |
| &comparison, |
| plContext), |
| PKIX_OBJECTCOMPARATORFAILED); |
| if (comparison > 0) { |
| PKIX_DECREF(state->validityDate); |
| state->validityDate = notAfter; |
| notAfter = NULL; |
| } |
| } |
| } |
| |
| cleanup: |
| |
| PKIX_DECREF(notAfter); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* Prepare 'state' for the AIA round. */ |
| static void |
| pkix_PrepareForwardBuilderStateForAIA( |
| PKIX_ForwardBuilderState *state) |
| { |
| PORT_Assert(state->useOnlyLocal == PKIX_TRUE); |
| state->useOnlyLocal = PKIX_FALSE; |
| state->certStoreIndex = 0; |
| state->numFanout = state->buildConstants.maxFanout; |
| state->status = BUILD_TRYAIA; |
| } |
| |
| extern SECStatus |
| isIssuerCertAllowedAtCertIssuanceTime(CERTCertificate *issuerCert, |
| CERTCertificate *referenceCert); |
| |
| /* |
| * FUNCTION: pkix_BuildForwardDepthFirstSearch |
| * DESCRIPTION: |
| * |
| * This function performs a depth first search in the "forward" direction (from |
| * the target Cert to the trust anchor). A non-NULL targetCert must be stored |
| * in the ForwardBuilderState before this function is called. It is not written |
| * recursively since execution may be suspended in in any of several places |
| * pending completion of non-blocking I/O. This iterative structure makes it |
| * much easier to resume where it left off. |
| * |
| * Since the nature of the search is recursive, the recursion is handled by |
| * chaining states. That is, each new step involves creating a new |
| * ForwardBuilderState linked to its predecessor. If a step turns out to be |
| * fruitless, the state of the predecessor is restored and the next alternative |
| * is tried. When a search is successful, values needed from the last state |
| * (canBeCached and validityDate) are copied to the state provided by the |
| * caller, so that the caller can retrieve those values. |
| * |
| * There are three return arguments, the NBIOContext, the ValidateResult and |
| * the ForwardBuilderState. If NBIOContext is non-NULL, it means the search is |
| * suspended until the results of a non-blocking IO become available. The |
| * caller may wait for the completion using platform-dependent methods and then |
| * call this function again, allowing it to resume the search. If NBIOContext |
| * is NULL and the ValidateResult is non-NULL, it means the search has |
| * concluded successfully. If the NBIOContext is NULL but the ValidateResult is |
| * NULL, it means the search was unsuccessful. |
| * |
| * This function performs several steps at each node in the constructed chain: |
| * |
| * 1) It retrieves Certs from the registered CertStores that match the |
| * criteria established by the ForwardBuilderState pointed to by "state", such |
| * as a subject name matching the issuer name of the previous Cert. If there |
| * are no matching Certs, the function returns to the previous, or "parent", |
| * state and tries to continue the chain building with another of the Certs |
| * obtained from the CertStores as possible issuers for that parent Cert. |
| * |
| * 2) For each candidate Cert returned by the CertStores, this function checks |
| * whether the Cert is valid. If it is trusted, this function checks whether |
| * this Cert might serve as a TrustAnchor for a complete chain. |
| * |
| * 3) It determines whether this Cert, in conjunction with any of the |
| * TrustAnchors, might complete a chain. A complete chain, from this or the |
| * preceding step, is checked to see whether it is valid as a complete |
| * chain, including the checks that cannot be done in the forward direction. |
| * |
| * 4) If this Cert chains successfully, but is not a complete chain, that is, |
| * we have not reached a trusted Cert, a new ForwardBuilderState is created |
| * with this Cert as the immediate predecessor, and we continue in step (1), |
| * attempting to get Certs from the CertStores with this Certs "issuer" as |
| * their subject. |
| * |
| * 5) If an entire chain validates successfully, then we are done. A |
| * ValidateResult is created containing the Public Key of the target |
| * certificate (including DSA parameter inheritance, if any) and the |
| * PolicyNode representing the policy tree output by the validation algorithm, |
| * and stored at pValResult, and the function exits returning NULL. |
| * |
| * 5) If the entire chain does not validate successfully, the algorithm |
| * discards the latest Cert and continues in step 2 with the next candidate |
| * Cert, backing up to a parent state when no more possibilities exist at a |
| * given level, and returning failure when we try to back up but discover we |
| * are at the top level. |
| * |
| * PARAMETERS: |
| * "pNBIOContext" |
| * Address at which platform-dependent information is returned if building |
| * is suspended for non-blocking I/O. Must be non-NULL. |
| * "pState" |
| * Address at which input ForwardBuilderState is found, and at which output |
| * ForwardBuilderState is stored. Must be non-NULL. |
| * "pValResult" |
| * Address at which the ValidateResult is stored. 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 Build Error if the function fails in a non-fatal way. |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_BuildForwardDepthFirstSearch( |
| void **pNBIOContext, |
| PKIX_ForwardBuilderState *state, |
| PKIX_ValidateResult **pValResult, |
| void *plContext) |
| { |
| PKIX_Boolean outOfOptions = PKIX_FALSE; |
| PKIX_Boolean trusted = PKIX_FALSE; |
| PKIX_Boolean isSelfIssued = PKIX_FALSE; |
| PKIX_Boolean canBeCached = PKIX_FALSE; |
| PKIX_Boolean ioPending = PKIX_FALSE; |
| PKIX_PL_Date *validityDate = NULL; |
| PKIX_PL_Date *currTime = NULL; |
| PKIX_Int32 childTraversedCACerts = 0; |
| PKIX_UInt32 numSubjectNames = 0; |
| PKIX_UInt32 numChained = 0; |
| PKIX_Int32 cmpTimeResult = 0; |
| PKIX_UInt32 i = 0; |
| PKIX_UInt32 certsSoFar = 0; |
| PKIX_List *childTraversedSubjNames = NULL; |
| PKIX_List *subjectNames = NULL; |
| PKIX_List *unfilteredCerts = NULL; |
| PKIX_List *filteredCerts = NULL; |
| PKIX_PL_Object *subjectName = NULL; |
| PKIX_ValidateResult *valResult = NULL; |
| PKIX_ForwardBuilderState *childState = NULL; |
| PKIX_ForwardBuilderState *parentState = NULL; |
| PKIX_PL_Object *revCheckerState = NULL; |
| PKIX_ComCertSelParams *certSelParams = NULL; |
| PKIX_TrustAnchor *trustAnchor = NULL; |
| PKIX_PL_Cert *trustedCert = NULL; |
| PKIX_PL_Cert *targetCert = NULL; |
| PKIX_VerifyNode *verifyNode = NULL; |
| PKIX_Error *verifyError = NULL; |
| PKIX_Error *finalError = NULL; |
| void *nbio = NULL; |
| PKIX_UInt32 numIterations = 0; |
| |
| PKIX_ENTER(BUILD, "pkix_BuildForwardDepthFirstSearch"); |
| PKIX_NULLCHECK_THREE(pNBIOContext, state, pValResult); |
| |
| nbio = *pNBIOContext; |
| *pNBIOContext = NULL; |
| PKIX_INCREF(state->validityDate); |
| validityDate = state->validityDate; |
| canBeCached = state->canBeCached; |
| PKIX_DECREF(*pValResult); |
| targetCert = state->buildConstants.targetCert; |
| |
| /* |
| * We return if successful; if we fall off the end |
| * of this "while" clause our search has failed. |
| */ |
| while (outOfOptions == PKIX_FALSE) { |
| /* |
| * The maximum number of iterations works around a bug that |
| * causes this while loop to never exit when AIA and cross |
| * certificates are involved. See bug xxxxx. |
| */ |
| if (numIterations++ > 250) |
| PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS); |
| |
| if (state->buildConstants.maxTime != 0) { |
| PKIX_DECREF(currTime); |
| PKIX_CHECK(PKIX_PL_Date_Create_UTCTime |
| (NULL, &currTime, plContext), |
| PKIX_DATECREATEUTCTIMEFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Object_Compare |
| ((PKIX_PL_Object *)state->buildConstants.timeLimit, |
| (PKIX_PL_Object *)currTime, |
| &cmpTimeResult, |
| plContext), |
| PKIX_OBJECTCOMPARATORFAILED); |
| |
| if (cmpTimeResult < 0) { |
| if (state->verifyNode != NULL) { |
| PKIX_ERROR_CREATE |
| (BUILD, |
| PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS, |
| verifyError); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_SetError |
| (state->verifyNode, |
| verifyError, |
| plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_DECREF(finalError); |
| finalError = verifyError; |
| verifyError = NULL; |
| } |
| /* Even if we logged error, we still have to abort */ |
| PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS); |
| } |
| } |
| |
| if (state->status == BUILD_INITIAL) { |
| |
| PKIX_CHECK(pkix_Build_BuildSelectorAndParams(state, plContext), |
| PKIX_BUILDBUILDSELECTORANDPARAMSFAILED); |
| |
| /* |
| * If the caller supplied a partial certChain (hintCerts) try |
| * the next one from that List before we go to the certStores. |
| */ |
| if (state->buildConstants.numHintCerts > 0) { |
| /* How many Certs does our trust chain have already? */ |
| PKIX_CHECK(PKIX_List_GetLength |
| (state->trustChain, &certsSoFar, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| /* That includes the target Cert. Don't count it. */ |
| certsSoFar--; |
| |
| /* Are we still within range of the partial chain? */ |
| if (certsSoFar >= state->buildConstants.numHintCerts) { |
| state->status = BUILD_TRYAIA; |
| } else { |
| /* |
| * If we already have n certs, we want the n+1th |
| * (i.e., index = n) from the list of hints. |
| */ |
| PKIX_DECREF(state->candidateCert); |
| PKIX_CHECK(PKIX_List_GetItem |
| (state->buildConstants.hintCerts, |
| certsSoFar, |
| (PKIX_PL_Object **)&state->candidateCert, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (state->candidateCerts, |
| (PKIX_PL_Object *)state->candidateCert, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| state->numCerts = 1; |
| state->usingHintCerts = PKIX_TRUE; |
| state->status = BUILD_CERTVALIDATING; |
| } |
| } else { |
| state->status = BUILD_TRYAIA; |
| } |
| |
| } |
| |
| if (state->status == BUILD_TRYAIA) { |
| if (state->useOnlyLocal == PKIX_TRUE) { |
| state->status = BUILD_COLLECTINGCERTS; |
| } else { |
| state->status = BUILD_AIAPENDING; |
| } |
| } |
| |
| if (state->status == BUILD_AIAPENDING && |
| state->buildConstants.aiaMgr) { |
| pkixErrorResult = PKIX_PL_AIAMgr_GetAIACerts |
| (state->buildConstants.aiaMgr, |
| state->prevCert, |
| &nbio, |
| &unfilteredCerts, |
| plContext); |
| |
| if (nbio != NULL) { |
| /* IO still pending, resume later */ |
| *pNBIOContext = nbio; |
| goto cleanup; |
| } |
| state->numCerts = 0; |
| if (pkixErrorResult) { |
| pkixErrorClass = pkixErrorResult->errClass; |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { |
| goto fatal; |
| } |
| PKIX_DECREF(finalError); |
| finalError = pkixErrorResult; |
| pkixErrorResult = NULL; |
| if (state->verifyNode != NULL) { |
| /* state->verifyNode is the object that contains a list |
| * of verifyNodes. verifyNodes contains cert chain |
| * build failures that occurred on this level of chain |
| * building. Here, creating new verify node |
| * to log the failure and adding it to the list. */ |
| PKIX_CHECK_FATAL(pkix_VerifyNode_Create |
| (state->prevCert, |
| 0, NULL, |
| &verifyNode, |
| plContext), |
| PKIX_VERIFYNODECREATEFAILED); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_SetError |
| (verifyNode, finalError, plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, |
| verifyNode, |
| plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| } |
| } |
| #ifdef PKIX_BUILDDEBUG |
| /* Turn this on to trace the List of Certs, before CertSelect */ |
| { |
| PKIX_PL_String *unString; |
| char *unAscii; |
| PKIX_UInt32 length; |
| PKIX_TOSTRING |
| ((PKIX_PL_Object*)unfilteredCerts, |
| &unString, |
| plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_GetEncoded |
| (unString, |
| PKIX_ESCASCII, |
| (void **)&unAscii, |
| &length, |
| plContext), |
| PKIX_STRINGGETENCODEDFAILED); |
| |
| PKIX_DEBUG_ARG |
| ("unfilteredCerts = %s\n", unAscii); |
| PKIX_DECREF(unString); |
| PKIX_FREE(unAscii); |
| } |
| #endif |
| |
| /* Note: Certs winnowed here don't get into VerifyTree. */ |
| if (unfilteredCerts) { |
| PKIX_CHECK(pkix_CertSelector_Select |
| (state->certSel, |
| unfilteredCerts, |
| &filteredCerts, |
| plContext), |
| PKIX_CERTSELECTORSELECTFAILED); |
| |
| PKIX_DECREF(unfilteredCerts); |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (filteredCerts, &(state->numCerts), plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| #ifdef PKIX_BUILDDEBUG |
| /* Turn this on to trace the List of Certs, after CertSelect */ |
| { |
| PKIX_PL_String *unString; |
| char *unAscii; |
| PKIX_UInt32 length; |
| PKIX_TOSTRING |
| ((PKIX_PL_Object*)filteredCerts, |
| &unString, |
| plContext, |
| PKIX_OBJECTTOSTRINGFAILED); |
| |
| PKIX_CHECK(PKIX_PL_String_GetEncoded |
| (unString, |
| PKIX_ESCASCII, |
| (void **)&unAscii, |
| &length, |
| plContext), |
| PKIX_STRINGGETENCODEDFAILED); |
| |
| PKIX_DEBUG_ARG("filteredCerts = %s\n", unAscii); |
| PKIX_DECREF(unString); |
| PKIX_FREE(unAscii); |
| } |
| #endif |
| |
| PKIX_DECREF(state->candidateCerts); |
| state->candidateCerts = filteredCerts; |
| state->certIndex = 0; |
| filteredCerts = NULL; |
| } |
| |
| /* Are there any Certs to try? */ |
| if (state->numCerts > 0) { |
| state->status = BUILD_CERTVALIDATING; |
| } else { |
| state->status = BUILD_COLLECTINGCERTS; |
| } |
| } |
| |
| PKIX_DECREF(certSelParams); |
| PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams |
| (state->certSel, &certSelParams, plContext), |
| PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED); |
| |
| /* **** Querying the CertStores ***** */ |
| if ((state->status == BUILD_COLLECTINGCERTS) || |
| (state->status == BUILD_GATHERPENDING)) { |
| |
| #if PKIX_FORWARDBUILDERSTATEDEBUG |
| PKIX_CHECK(pkix_ForwardBuilderState_DumpState |
| (state, plContext), |
| PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED); |
| #endif |
| |
| PKIX_CHECK(pkix_Build_GatherCerts |
| (state, certSelParams, &nbio, plContext), |
| PKIX_BUILDGATHERCERTSFAILED); |
| |
| if (nbio != NULL) { |
| /* IO still pending, resume later */ |
| *pNBIOContext = nbio; |
| goto cleanup; |
| } |
| |
| /* Are there any Certs to try? */ |
| if (state->numCerts > 0) { |
| state->status = BUILD_CERTVALIDATING; |
| } else { |
| state->status = BUILD_ABANDONNODE; |
| } |
| } |
| |
| /* ****Phase 2 - Chain building***** */ |
| |
| #if PKIX_FORWARDBUILDERSTATEDEBUG |
| PKIX_CHECK(pkix_ForwardBuilderState_DumpState(state, plContext), |
| PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED); |
| #endif |
| |
| if (state->status == BUILD_CERTVALIDATING) { |
| PKIX_DECREF(state->candidateCert); |
| PKIX_CHECK(PKIX_List_GetItem |
| (state->candidateCerts, |
| state->certIndex, |
| (PKIX_PL_Object **)&(state->candidateCert), |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| if (isIssuerCertAllowedAtCertIssuanceTime( |
| state->candidateCert->nssCert, targetCert->nssCert) |
| != SECSuccess) { |
| PKIX_ERROR(PKIX_CERTISBLACKLISTEDATISSUANCETIME); |
| } |
| |
| if ((state->verifyNode) != NULL) { |
| PKIX_CHECK_FATAL(pkix_VerifyNode_Create |
| (state->candidateCert, |
| 0, |
| NULL, |
| &verifyNode, |
| plContext), |
| PKIX_VERIFYNODECREATEFAILED); |
| } |
| |
| /* If failure, this function sets Error in verifyNode */ |
| verifyError = pkix_Build_VerifyCertificate |
| (state, |
| state->buildConstants.userCheckers, |
| &trusted, |
| verifyNode, |
| plContext); |
| |
| if (verifyError) { |
| pkixTempErrorReceived = PKIX_TRUE; |
| pkixErrorClass = verifyError->errClass; |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { |
| pkixErrorResult = verifyError; |
| verifyError = NULL; |
| goto fatal; |
| } |
| } |
| |
| if (PKIX_ERROR_RECEIVED) { |
| if (state->verifyNode != NULL) { |
| PKIX_CHECK_FATAL(pkix_VerifyNode_SetError |
| (verifyNode, verifyError, plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, |
| verifyNode, |
| plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| } |
| pkixTempErrorReceived = PKIX_FALSE; |
| PKIX_DECREF(finalError); |
| finalError = verifyError; |
| verifyError = NULL; |
| if (state->certLoopingDetected) { |
| PKIX_ERROR |
| (PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED); |
| } |
| state->status = BUILD_GETNEXTCERT; |
| } else { |
| state->status = BUILD_DATEPREP; |
| } |
| } |
| |
| if (state->status == BUILD_DATEPREP) { |
| /* Keep track of whether this chain can be cached */ |
| PKIX_CHECK(pkix_Build_UpdateDate(state, plContext), |
| PKIX_BUILDUPDATEDATEFAILED); |
| |
| canBeCached = state->canBeCached; |
| PKIX_DECREF(validityDate); |
| PKIX_INCREF(state->validityDate); |
| validityDate = state->validityDate; |
| if (trusted == PKIX_TRUE) { |
| state->status = BUILD_CHECKTRUSTED; |
| } else { |
| state->status = BUILD_ADDTOCHAIN; |
| } |
| } |
| |
| if (state->status == BUILD_CHECKTRUSTED) { |
| |
| /* |
| * If this cert is trusted, try to validate the entire |
| * chain using this certificate as trust anchor. |
| */ |
| PKIX_CHECK(PKIX_TrustAnchor_CreateWithCert |
| (state->candidateCert, |
| &trustAnchor, |
| plContext), |
| PKIX_TRUSTANCHORCREATEWITHCERTFAILED); |
| |
| PKIX_CHECK(pkix_Build_ValidationCheckers |
| (state, |
| state->trustChain, |
| trustAnchor, |
| PKIX_FALSE, /* do not add eku checker |
| * since eku was already |
| * checked */ |
| plContext), |
| PKIX_BUILDVALIDATIONCHECKERSFAILED); |
| |
| state->status = BUILD_CHECKTRUSTED2; |
| } |
| |
| if (state->status == BUILD_CHECKTRUSTED2) { |
| verifyError = |
| pkix_Build_ValidateEntireChain(state, |
| trustAnchor, |
| &nbio, &valResult, |
| verifyNode, |
| plContext); |
| if (nbio != NULL) { |
| /* IO still pending, resume later */ |
| goto cleanup; |
| } else { |
| /* checking the error for fatal status */ |
| if (verifyError) { |
| pkixTempErrorReceived = PKIX_TRUE; |
| pkixErrorClass = verifyError->errClass; |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { |
| pkixErrorResult = verifyError; |
| verifyError = NULL; |
| goto fatal; |
| } |
| } |
| if (state->verifyNode != NULL) { |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, |
| verifyNode, |
| plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| } |
| if (!PKIX_ERROR_RECEIVED) { |
| *pValResult = valResult; |
| valResult = NULL; |
| /* Change state so IsIOPending is FALSE */ |
| state->status = BUILD_CHECKTRUSTED; |
| goto cleanup; |
| } |
| PKIX_DECREF(finalError); |
| finalError = verifyError; |
| verifyError = NULL; |
| /* Reset temp error that was set by |
| * PKIX_CHECK_ONLY_FATAL and continue */ |
| pkixTempErrorReceived = PKIX_FALSE; |
| PKIX_DECREF(trustAnchor); |
| } |
| |
| /* |
| * If chain doesn't validate with a trusted Cert, |
| * adding more Certs to it can't help. |
| */ |
| if (state->certLoopingDetected) { |
| PKIX_DECREF(verifyError); |
| PKIX_ERROR_CREATE(BUILD, |
| PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED, |
| verifyError); |
| PKIX_CHECK_FATAL( |
| pkix_VerifyNode_SetError(state->verifyNode, |
| verifyError, |
| plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_DECREF(verifyError); |
| } |
| state->status = BUILD_GETNEXTCERT; |
| } |
| |
| /* |
| * This Cert was not trusted. Add it to our chain, and |
| * continue building. If we don't reach a trust anchor, |
| * we'll take it off later and continue without it. |
| */ |
| if (state->status == BUILD_ADDTOCHAIN) { |
| PKIX_CHECK(PKIX_List_AppendItem |
| (state->trustChain, |
| (PKIX_PL_Object *)state->candidateCert, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| state->status = BUILD_EXTENDCHAIN; |
| } |
| |
| if (state->status == BUILD_EXTENDCHAIN) { |
| |
| /* Check whether we are allowed to extend the chain */ |
| if ((state->buildConstants.maxDepth != 0) && |
| (state->numDepth <= 1)) { |
| |
| if (state->verifyNode != NULL) { |
| PKIX_ERROR_CREATE |
| (BUILD, |
| PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS, |
| verifyError); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_SetError |
| (verifyNode, verifyError, plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, verifyNode, plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| PKIX_DECREF(finalError); |
| finalError = verifyError; |
| verifyError = NULL; |
| } |
| /* Even if error logged, still need to abort */ |
| PKIX_ERROR(PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS); |
| } |
| |
| PKIX_CHECK(pkix_IsCertSelfIssued |
| (state->candidateCert, &isSelfIssued, plContext), |
| PKIX_ISCERTSELFISSUEDFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Object_Duplicate |
| ((PKIX_PL_Object *)state->traversedSubjNames, |
| (PKIX_PL_Object **)&childTraversedSubjNames, |
| plContext), |
| PKIX_OBJECTDUPLICATEFAILED); |
| |
| if (isSelfIssued) { |
| childTraversedCACerts = state->traversedCACerts; |
| } else { |
| childTraversedCACerts = state->traversedCACerts + 1; |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames |
| (state->candidateCert, |
| &subjectNames, |
| plContext), |
| PKIX_CERTGETALLSUBJECTNAMESFAILED); |
| |
| if (subjectNames) { |
| PKIX_CHECK(PKIX_List_GetLength |
| (subjectNames, |
| &numSubjectNames, |
| plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| } else { |
| numSubjectNames = 0; |
| } |
| |
| for (i = 0; i < numSubjectNames; i++) { |
| PKIX_CHECK(PKIX_List_GetItem |
| (subjectNames, |
| i, |
| &subjectName, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| PKIX_NULLCHECK_ONE |
| (state->traversedSubjNames); |
| PKIX_CHECK(PKIX_List_AppendItem |
| (state->traversedSubjNames, |
| subjectName, |
| plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| PKIX_DECREF(subjectName); |
| } |
| PKIX_DECREF(subjectNames); |
| } |
| |
| PKIX_CHECK(pkix_ForwardBuilderState_Create |
| (childTraversedCACerts, |
| state->buildConstants.maxFanout, |
| state->numDepth - 1, |
| canBeCached, |
| validityDate, |
| state->candidateCert, |
| childTraversedSubjNames, |
| state->trustChain, |
| state, |
| &childState, |
| plContext), |
| PKIX_FORWARDBUILDSTATECREATEFAILED); |
| |
| PKIX_DECREF(childTraversedSubjNames); |
| PKIX_DECREF(certSelParams); |
| childState->verifyNode = verifyNode; |
| verifyNode = NULL; |
| PKIX_DECREF(state); |
| state = childState; /* state->status == BUILD_INITIAL */ |
| childState = NULL; |
| continue; /* with while (!outOfOptions) */ |
| } |
| |
| if (state->status == BUILD_GETNEXTCERT) { |
| pkixTempErrorReceived = PKIX_FALSE; |
| PKIX_DECREF(state->candidateCert); |
| |
| /* |
| * If we were using a Cert from the callier-supplied partial |
| * chain, delete it and go to the certStores. |
| */ |
| if (state->usingHintCerts == PKIX_TRUE) { |
| PKIX_DECREF(state->candidateCerts); |
| PKIX_CHECK(PKIX_List_Create |
| (&state->candidateCerts, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| state->numCerts = 0; |
| state->usingHintCerts = PKIX_FALSE; |
| state->status = BUILD_TRYAIA; |
| continue; |
| } else if (++(state->certIndex) < (state->numCerts)) { |
| if ((state->buildConstants.maxFanout != 0) && |
| (--(state->numFanout) == 0)) { |
| |
| if (state->verifyNode != NULL) { |
| PKIX_ERROR_CREATE |
| (BUILD, |
| PKIX_FANOUTEXCEEDSRESOURCELIMITS, |
| verifyError); |
| PKIX_CHECK_FATAL |
| (pkix_VerifyNode_SetError |
| (state->verifyNode, |
| verifyError, |
| plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_DECREF(finalError); |
| finalError = verifyError; |
| verifyError = NULL; |
| } |
| /* Even if error logged, still need to abort */ |
| PKIX_ERROR |
| (PKIX_FANOUTEXCEEDSRESOURCELIMITS); |
| } |
| state->status = BUILD_CERTVALIDATING; |
| continue; |
| } |
| } |
| |
| /* |
| * Adding the current cert to the chain didn't help. If our search |
| * has been restricted to local certStores, try opening up the |
| * search and see whether that helps. Otherwise, back up to the |
| * parent cert, and see if there are any more to try. |
| */ |
| if (state->useOnlyLocal == PKIX_TRUE) { |
| pkix_PrepareForwardBuilderStateForAIA(state); |
| } else do { |
| if (state->parentState == NULL) { |
| /* We are at the top level, and can't back up! */ |
| outOfOptions = PKIX_TRUE; |
| } else { |
| /* |
| * Try the next cert, if any, for this parent. |
| * Otherwise keep backing up until we reach a |
| * parent with more certs to try. |
| */ |
| PKIX_CHECK(PKIX_List_GetLength |
| (state->trustChain, &numChained, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| PKIX_CHECK(PKIX_List_DeleteItem |
| (state->trustChain, numChained - 1, plContext), |
| PKIX_LISTDELETEITEMFAILED); |
| |
| /* local and aia fetching returned no good certs. |
| * Creating a verify node in the parent that tells |
| * us this. */ |
| if (!state->verifyNode) { |
| PKIX_CHECK_FATAL( |
| pkix_VerifyNode_Create(state->prevCert, |
| 0, NULL, |
| &state->verifyNode, |
| plContext), |
| PKIX_VERIFYNODECREATEFAILED); |
| } |
| /* Updating the log with the error. */ |
| PKIX_DECREF(verifyError); |
| PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER, |
| verifyError); |
| PKIX_CHECK_FATAL( |
| pkix_VerifyNode_SetError(state->verifyNode, |
| verifyError, |
| plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| PKIX_DECREF(verifyError); |
| |
| PKIX_INCREF(state->parentState); |
| parentState = state->parentState; |
| PKIX_DECREF(verifyNode); |
| verifyNode = state->verifyNode; |
| state->verifyNode = NULL; |
| PKIX_DECREF(state); |
| state = parentState; |
| parentState = NULL; |
| if (state->verifyNode != NULL && verifyNode) { |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, |
| verifyNode, |
| plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| } |
| PKIX_DECREF(validityDate); |
| PKIX_INCREF(state->validityDate); |
| validityDate = state->validityDate; |
| canBeCached = state->canBeCached; |
| |
| /* Are there any more Certs to try? */ |
| if (++(state->certIndex) < (state->numCerts)) { |
| state->status = BUILD_CERTVALIDATING; |
| PKIX_DECREF(state->candidateCert); |
| break; |
| } |
| if (state->useOnlyLocal == PKIX_TRUE) { |
| /* Clean up and go for AIA round. */ |
| pkix_PrepareForwardBuilderStateForAIA(state); |
| break; |
| } |
| } |
| PKIX_DECREF(state->candidateCert); |
| } while (outOfOptions == PKIX_FALSE); |
| |
| } /* while (outOfOptions == PKIX_FALSE) */ |
| |
| cleanup: |
| |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { |
| goto fatal; |
| } |
| |
| /* verifyNode should be equal to NULL at this point. Assert it. |
| * Temporarelly use verifyError to store an error ref to which we |
| * have in pkixErrorResult. This is done to prevent error cloberring |
| * while using macros below. */ |
| PORT_Assert(verifyError == NULL); |
| verifyError = pkixErrorResult; |
| |
| /* |
| * We were called with an initialState that had no parent. If we are |
| * returning with an error or with a result, we must destroy any state |
| * that we created (any state with a parent). |
| */ |
| |
| PKIX_CHECK_FATAL(pkix_ForwardBuilderState_IsIOPending |
| (state, &ioPending, plContext), |
| PKIX_FORWARDBUILDERSTATEISIOPENDINGFAILED); |
| |
| if (ioPending == PKIX_FALSE) { |
| while (state->parentState) { |
| PKIX_INCREF(state->parentState); |
| parentState = state->parentState; |
| PKIX_DECREF(verifyNode); |
| verifyNode = state->verifyNode; |
| state->verifyNode = NULL; |
| PKIX_DECREF(state); |
| state = parentState; |
| parentState = NULL; |
| if (state->verifyNode != NULL && verifyNode) { |
| PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree |
| (state->verifyNode, |
| verifyNode, |
| plContext), |
| PKIX_VERIFYNODEADDTOTREEFAILED); |
| PKIX_DECREF(verifyNode); |
| } |
| } |
| state->canBeCached = canBeCached; |
| PKIX_DECREF(state->validityDate); |
| state->validityDate = validityDate; |
| validityDate = NULL; |
| } |
| if (!*pValResult && !verifyError) { |
| if (!finalError) { |
| PKIX_CHECK_FATAL( |
| pkix_VerifyNode_FindError(state->verifyNode, |
| &finalError, |
| plContext), |
| PKIX_VERIFYNODEFINDERRORFAILED); |
| } |
| if (finalError) { |
| pkixErrorResult = finalError; |
| pkixErrorCode = PKIX_BUILDFORWARDDEPTHFIRSTSEARCHFAILED; |
| finalError = NULL; |
| goto fatal; |
| } |
| pkixErrorCode = PKIX_SECERRORUNKNOWNISSUER; |
| pkixErrorReceived = PKIX_TRUE; |
| PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER, |
| verifyError); |
| PKIX_CHECK_FATAL( |
| pkix_VerifyNode_SetError(state->verifyNode, verifyError, |
| plContext), |
| PKIX_VERIFYNODESETERRORFAILED); |
| } else { |
| pkixErrorResult = verifyError; |
| verifyError = NULL; |
| } |
| |
| fatal: |
| if (state->parentState) { |
| /* parentState in "state" object should be NULL at this point. |
| * If itn't, that means that we got fatal error(we have jumped to |
| * "fatal" label) and we should destroy all state except the top one. */ |
| while (state->parentState) { |
| PKIX_Error *error = NULL; |
| PKIX_ForwardBuilderState *prntState = state->parentState; |
| /* Dumb: need to increment parentState to avoid destruction |
| * of "build constants"(they get destroyed when parentState is |
| * set to NULL. */ |
| PKIX_INCREF(prntState); |
| error = PKIX_PL_Object_DecRef((PKIX_PL_Object*)state, plContext); |
| if (error) { |
| PKIX_PL_Object_DecRef((PKIX_PL_Object*)error, plContext); |
| } |
| /* No need to decref the parent state. It was already done by |
| * pkix_ForwardBuilderState_Destroy function. */ |
| state = prntState; |
| } |
| } |
| PKIX_DECREF(parentState); |
| PKIX_DECREF(childState); |
| PKIX_DECREF(valResult); |
| PKIX_DECREF(verifyError); |
| PKIX_DECREF(finalError); |
| PKIX_DECREF(verifyNode); |
| PKIX_DECREF(childTraversedSubjNames); |
| PKIX_DECREF(certSelParams); |
| PKIX_DECREF(subjectNames); |
| PKIX_DECREF(subjectName); |
| PKIX_DECREF(trustAnchor); |
| PKIX_DECREF(validityDate); |
| PKIX_DECREF(revCheckerState); |
| PKIX_DECREF(currTime); |
| PKIX_DECREF(filteredCerts); |
| PKIX_DECREF(unfilteredCerts); |
| PKIX_DECREF(trustedCert); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_CheckInCache |
| * DESCRIPTION: |
| * |
| * The function tries to locate a chain for a cert in the cert chain cache. |
| * If found, the chain goes through revocation chacking and returned back to |
| * caller. Chains that fail revocation check get removed from cache. |
| * |
| * PARAMETERS: |
| * "state" |
| * Address of ForwardBuilderState to be used. Must be non-NULL. |
| * "pBuildResult" |
| * Address at which the BuildResult is stored, after a successful build. |
| * Must be non-NULL. |
| * "pNBIOContext" |
| * Address at which the NBIOContext is stored indicating whether the |
| * validation is complete. 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error* |
| pkix_Build_CheckInCache( |
| PKIX_ForwardBuilderState *state, |
| PKIX_BuildResult **pBuildResult, |
| void **pNBIOContext, |
| void *plContext) |
| { |
| PKIX_PL_Cert *targetCert = NULL; |
| PKIX_List *anchors = NULL; |
| PKIX_PL_Date *testDate = NULL; |
| PKIX_BuildResult *buildResult = NULL; |
| PKIX_ValidateResult *valResult = NULL; |
| PKIX_Error *buildError = NULL; |
| PKIX_TrustAnchor *matchingAnchor = NULL; |
| PKIX_PL_Cert *trustedCert = NULL; |
| PKIX_List *certList = NULL; |
| PKIX_Boolean cacheHit = PKIX_FALSE; |
| PKIX_Boolean trusted = PKIX_FALSE; |
| PKIX_Boolean stillValid = PKIX_FALSE; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_CheckInCache"); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| targetCert = state->buildConstants.targetCert; |
| anchors = state->buildConstants.anchors; |
| testDate = state->buildConstants.testDate; |
| |
| /* Check whether this cert verification has been cached. */ |
| PKIX_CHECK(pkix_CacheCertChain_Lookup |
| (targetCert, |
| anchors, |
| testDate, |
| &cacheHit, |
| &buildResult, |
| plContext), |
| PKIX_CACHECERTCHAINLOOKUPFAILED); |
| |
| if (!cacheHit) { |
| goto cleanup; |
| } |
| |
| /* |
| * We found something in cache. Verify that the anchor |
| * cert is still trusted, |
| */ |
| PKIX_CHECK(PKIX_BuildResult_GetValidateResult |
| (buildResult, &valResult, plContext), |
| PKIX_BUILDRESULTGETVALIDATERESULTFAILED); |
| |
| PKIX_CHECK(PKIX_ValidateResult_GetTrustAnchor |
| (valResult, &matchingAnchor, plContext), |
| PKIX_VALIDATERESULTGETTRUSTANCHORFAILED); |
| |
| PKIX_DECREF(valResult); |
| |
| PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert |
| (matchingAnchor, &trustedCert, plContext), |
| PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED); |
| |
| if (anchors && state->buildConstants.numAnchors) { |
| /* Check if it is one of the trust anchors */ |
| PKIX_CHECK( |
| pkix_List_Contains(anchors, |
| (PKIX_PL_Object *)matchingAnchor, |
| &trusted, |
| plContext), |
| PKIX_LISTCONTAINSFAILED); |
| } |
| |
| if ((!trusted && !state->buildConstants.trustOnlyUserAnchors) || |
| !state->buildConstants.numAnchors) { |
| /* If it is not one of the trust anchors and the trust anchors |
| * are supplemental, or if there are no trust anchors, then check |
| * if the cert is trusted directly. |
| */ |
| PKIX_CHECK( |
| PKIX_PL_Cert_IsCertTrusted(trustedCert, |
| PKIX_PL_TrustAnchorMode_Ignore, |
| &trusted, plContext), |
| PKIX_CERTISCERTTRUSTEDFAILED); |
| } |
| |
| if (!trusted) { |
| goto cleanup; |
| } |
| /* |
| * Since the key usage may vary for different |
| * applications, we need to verify the chain again. |
| * Reverification will be improved with a fix for 397805. |
| */ |
| PKIX_CHECK(PKIX_BuildResult_GetCertChain |
| (buildResult, &certList, plContext), |
| PKIX_BUILDRESULTGETCERTCHAINFAILED); |
| |
| PKIX_CHECK(pkix_Build_ValidationCheckers |
| (state, |
| certList, |
| matchingAnchor, |
| PKIX_TRUE, /* Chain revalidation stage. */ |
| plContext), |
| PKIX_BUILDVALIDATIONCHECKERSFAILED); |
| |
| PKIX_CHECK_ONLY_FATAL( |
| pkix_Build_ValidateEntireChain(state, matchingAnchor, |
| &nbioContext, &valResult, |
| state->verifyNode, plContext), |
| PKIX_BUILDVALIDATEENTIRECHAINFAILED); |
| |
| if (nbioContext != NULL) { |
| /* IO still pending, resume later */ |
| *pNBIOContext = nbioContext; |
| goto cleanup; |
| } |
| if (!PKIX_ERROR_RECEIVED) { |
| /* The result from cache is still valid. But we replace an old*/ |
| *pBuildResult = buildResult; |
| buildResult = NULL; |
| stillValid = PKIX_TRUE; |
| } |
| |
| cleanup: |
| |
| if (!nbioContext && cacheHit && !(trusted && stillValid)) { |
| /* The anchor of this chain is no longer trusted or |
| * chain cert(s) has been revoked. |
| * Invalidate this result in the cache */ |
| buildError = pkixErrorResult; |
| PKIX_CHECK_FATAL(pkix_CacheCertChain_Remove |
| (targetCert, |
| anchors, |
| plContext), |
| PKIX_CACHECERTCHAINREMOVEFAILED); |
| pkixErrorResult = buildError; |
| buildError = NULL; |
| } |
| |
| fatal: |
| PKIX_DECREF(buildResult); |
| PKIX_DECREF(valResult); |
| PKIX_DECREF(buildError); |
| PKIX_DECREF(certList); |
| PKIX_DECREF(matchingAnchor); |
| PKIX_DECREF(trustedCert); |
| |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_InitiateBuildChain |
| * DESCRIPTION: |
| * |
| * This function initiates the search for a BuildChain, using the parameters |
| * provided in "procParams" and, if continuing a search that was suspended |
| * for I/O, using the ForwardBuilderState pointed to by "pState". |
| * |
| * If a successful chain is built, this function stores the BuildResult at |
| * "pBuildResult". Alternatively, if an operation using non-blocking I/O |
| * is in progress and the operation has not been completed, this function |
| * stores the platform-dependent non-blocking I/O context (nbioContext) at |
| * "pNBIOContext", the FowardBuilderState at "pState", and NULL at |
| * "pBuildResult". Finally, if chain building was unsuccessful, this function |
| * stores NULL at both "pState" and at "pBuildResult". |
| * |
| * Note: This function is re-entered only for the case of non-blocking I/O |
| * in the "short-cut" attempt to build a chain using the target Certificate |
| * directly with one of the trustAnchors. For all other cases, resumption |
| * after non-blocking I/O is via pkix_Build_ResumeBuildChain. |
| * |
| * PARAMETERS: |
| * "procParams" |
| * Address of the ProcessingParams for the search. Must be non-NULL. |
| * "pNBIOContext" |
| * Address at which the NBIOContext is stored indicating whether the |
| * validation is complete. Must be non-NULL. |
| * "pState" |
| * Address at which the ForwardBuilderState is stored, if the chain |
| * building is suspended for waiting I/O; also, the address at which the |
| * ForwardBuilderState is provided for resumption of the chain building |
| * attempt. Must be non-NULL. |
| * "pBuildResult" |
| * Address at which the BuildResult is stored, after a successful build. |
| * Must be non-NULL. |
| * "pVerifyNode" |
| * Address at which a VerifyNode chain is returned, if 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_InitiateBuildChain( |
| PKIX_ProcessingParams *procParams, |
| void **pNBIOContext, |
| PKIX_ForwardBuilderState **pState, |
| PKIX_BuildResult **pBuildResult, |
| PKIX_VerifyNode **pVerifyNode, |
| void *plContext) |
| { |
| PKIX_UInt32 numAnchors = 0; |
| PKIX_UInt32 numCertStores = 0; |
| PKIX_UInt32 numHintCerts = 0; |
| PKIX_UInt32 i = 0; |
| PKIX_Boolean isDuplicate = PKIX_FALSE; |
| PKIX_PL_Cert *trustedCert = NULL; |
| PKIX_CertSelector *targetConstraints = NULL; |
| PKIX_ComCertSelParams *targetParams = NULL; |
| PKIX_List *anchors = NULL; |
| PKIX_List *targetSubjNames = NULL; |
| PKIX_PL_Cert *targetCert = NULL; |
| PKIX_PL_Object *firstHintCert = NULL; |
| PKIX_RevocationChecker *revChecker = NULL; |
| PKIX_List *certStores = NULL; |
| PKIX_CertStore *certStore = NULL; |
| PKIX_List *userCheckers = NULL; |
| PKIX_List *hintCerts = NULL; |
| PKIX_PL_Date *testDate = NULL; |
| PKIX_PL_PublicKey *targetPubKey = NULL; |
| void *nbioContext = NULL; |
| BuildConstants buildConstants; |
| |
| PKIX_List *tentativeChain = NULL; |
| PKIX_ValidateResult *valResult = NULL; |
| PKIX_BuildResult *buildResult = NULL; |
| PKIX_List *certList = NULL; |
| PKIX_ForwardBuilderState *state = NULL; |
| PKIX_CertStore_CheckTrustCallback trustCallback = NULL; |
| PKIX_CertSelector_MatchCallback selectorCallback = NULL; |
| PKIX_Boolean trusted = PKIX_FALSE; |
| PKIX_PL_AIAMgr *aiaMgr = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_InitiateBuildChain"); |
| PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| state = *pState; |
| *pState = NULL; /* no net change in reference count */ |
| |
| if (state == NULL) { |
| PKIX_CHECK(PKIX_ProcessingParams_GetDate |
| (procParams, &testDate, plContext), |
| PKIX_PROCESSINGPARAMSGETDATEFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors |
| (procParams, &anchors, plContext), |
| PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED); |
| |
| PKIX_CHECK(PKIX_List_GetLength(anchors, &numAnchors, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| /* retrieve stuff from targetCertConstraints */ |
| PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints |
| (procParams, &targetConstraints, plContext), |
| PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED); |
| |
| PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams |
| (targetConstraints, &targetParams, plContext), |
| PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED); |
| |
| PKIX_CHECK(PKIX_ComCertSelParams_GetCertificate |
| (targetParams, &targetCert, plContext), |
| PKIX_COMCERTSELPARAMSGETCERTIFICATEFAILED); |
| |
| PKIX_CHECK( |
| PKIX_ComCertSelParams_SetLeafCertFlag(targetParams, |
| PKIX_TRUE, plContext), |
| PKIX_COMCERTSELPARAMSSETLEAFCERTFLAGFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetHintCerts |
| (procParams, &hintCerts, plContext), |
| PKIX_PROCESSINGPARAMSGETHINTCERTSFAILED); |
| |
| if (hintCerts != NULL) { |
| PKIX_CHECK(PKIX_List_GetLength |
| (hintCerts, &numHintCerts, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| } |
| |
| /* |
| * Caller must provide either a target Cert |
| * (in ComCertSelParams->Certificate) or a partial Cert |
| * chain (in ProcParams->HintCerts). |
| */ |
| |
| if (targetCert == NULL) { |
| |
| /* Use first cert of hintCerts as the targetCert */ |
| if (numHintCerts == 0) { |
| PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED); |
| } |
| |
| PKIX_CHECK(PKIX_List_GetItem |
| (hintCerts, |
| 0, |
| (PKIX_PL_Object **)&targetCert, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(PKIX_List_DeleteItem(hintCerts, 0, plContext), |
| PKIX_LISTGETITEMFAILED); |
| } else { |
| |
| /* |
| * If the first hintCert is the same as the targetCert, |
| * delete it from hintCerts. |
| */ |
| if (numHintCerts != 0) { |
| PKIX_CHECK(PKIX_List_GetItem |
| (hintCerts, 0, &firstHintCert, plContext), |
| PKIX_LISTGETITEMFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Object_Equals |
| ((PKIX_PL_Object *)targetCert, |
| firstHintCert, |
| &isDuplicate, |
| plContext), |
| PKIX_OBJECTEQUALSFAILED); |
| |
| if (isDuplicate) { |
| PKIX_CHECK(PKIX_List_DeleteItem |
| (hintCerts, 0, plContext), |
| PKIX_LISTGETITEMFAILED); |
| } |
| PKIX_DECREF(firstHintCert); |
| } |
| |
| } |
| |
| if (targetCert == NULL) { |
| PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED); |
| } |
| |
| PKIX_CHECK(PKIX_PL_Cert_IsLeafCertTrusted |
| (targetCert, |
| &trusted, |
| plContext), |
| PKIX_CERTISCERTTRUSTEDFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames |
| (targetCert, |
| &targetSubjNames, |
| plContext), |
| PKIX_CERTGETALLSUBJECTNAMESFAILED); |
| |
| PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey |
| (targetCert, &targetPubKey, plContext), |
| PKIX_CERTGETSUBJECTPUBLICKEYFAILED); |
| |
| PKIX_CHECK(PKIX_List_Create(&tentativeChain, plContext), |
| PKIX_LISTCREATEFAILED); |
| |
| PKIX_CHECK(PKIX_List_AppendItem |
| (tentativeChain, (PKIX_PL_Object *)targetCert, plContext), |
| PKIX_LISTAPPENDITEMFAILED); |
| |
| if (procParams->qualifyTargetCert) { |
| /* EE cert validation */ |
| /* Sync up the time on the target selector parameter struct. */ |
| PKIX_CHECK( |
| PKIX_ComCertSelParams_SetCertificateValid(targetParams, |
| testDate, |
| plContext), |
| PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED); |
| |
| PKIX_CHECK(PKIX_CertSelector_GetMatchCallback |
| (targetConstraints, &selectorCallback, plContext), |
| PKIX_CERTSELECTORGETMATCHCALLBACKFAILED); |
| |
| pkixErrorResult = |
| (*selectorCallback)(targetConstraints, targetCert, |
| plContext); |
| if (pkixErrorResult) { |
| pkixErrorClass = pkixErrorResult->errClass; |
| if (pkixErrorClass == PKIX_FATAL_ERROR) { |
| goto cleanup; |
| } |
| if (pVerifyNode != NULL) { |
| PKIX_Error *tempResult = |
| pkix_VerifyNode_Create(targetCert, 0, |
| pkixErrorResult, |
| pVerifyNode, |
| plContext); |
| if (tempResult) { |
| PKIX_DECREF(pkixErrorResult); |
| pkixErrorResult = tempResult; |
| pkixErrorCode = PKIX_VERIFYNODECREATEFAILED; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| } |
| } |
| pkixErrorCode = PKIX_CERTCHECKVALIDITYFAILED; |
| goto cleanup; |
| } |
| } |
| |
| /* If the EE cert is trusted, force success. We only want to do |
| * this if we aren't validating against a policy (like EV). */ |
| if (trusted && procParams->initialPolicies == NULL) { |
| if (pVerifyNode != NULL) { |
| PKIX_Error *tempResult = |
| pkix_VerifyNode_Create(targetCert, 0, NULL, |
| pVerifyNode, |
| plContext); |
| if (tempResult) { |
| pkixErrorResult = tempResult; |
| pkixErrorCode = PKIX_VERIFYNODECREATEFAILED; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| } |
| } |
| PKIX_CHECK(pkix_ValidateResult_Create |
| (targetPubKey, NULL /* anchor */, |
| NULL /* policyTree */, &valResult, plContext), |
| PKIX_VALIDATERESULTCREATEFAILED); |
| PKIX_CHECK( |
| pkix_BuildResult_Create(valResult, tentativeChain, |
| &buildResult, plContext), |
| PKIX_BUILDRESULTCREATEFAILED); |
| *pBuildResult = buildResult; |
| /* Note that *pState is NULL. The only side effect is that |
| * the cert chain won't be cached in PKIX_BuildChain, which |
| * is fine. */ |
| goto cleanup; |
| } |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetCertStores |
| (procParams, &certStores, plContext), |
| PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED); |
| |
| PKIX_CHECK(PKIX_List_GetLength |
| (certStores, &numCertStores, plContext), |
| PKIX_LISTGETLENGTHFAILED); |
| |
| /* Reorder CertStores so trusted are at front of the List */ |
| if (numCertStores > 1) { |
| for (i = numCertStores - 1; i > 0; i--) { |
| PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem |
| (certStores, |
| i, |
| (PKIX_PL_Object **)&certStore, |
| plContext), |
| PKIX_LISTGETITEMFAILED); |
| PKIX_CHECK_ONLY_FATAL(PKIX_CertStore_GetTrustCallback |
| (certStore, &trustCallback, plContext), |
| PKIX_CERTSTOREGETTRUSTCALLBACKFAILED); |
| |
| if (trustCallback != NULL) { |
| /* Is a trusted Cert, move CertStore to front */ |
| PKIX_CHECK(PKIX_List_DeleteItem |
| (certStores, i, plContext), |
| PKIX_LISTDELETEITEMFAILED); |
| PKIX_CHECK(PKIX_List_InsertItem |
| (certStores, |
| 0, |
| (PKIX_PL_Object *)certStore, |
| plContext), |
| PKIX_LISTINSERTITEMFAILED); |
| |
| } |
| |
| PKIX_DECREF(certStore); |
| } |
| } |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers |
| (procParams, &userCheckers, plContext), |
| PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED); |
| |
| PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker |
| (procParams, &revChecker, plContext), |
| PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED); |
| /* Do not initialize AIA manager if we are not going to fetch |
| * cert using aia url. */ |
| if (procParams->useAIAForCertFetching) { |
| PKIX_CHECK(PKIX_PL_AIAMgr_Create(&aiaMgr, plContext), |
| PKIX_AIAMGRCREATEFAILED); |
| } |
| |
| /* |
| * We initialize all the fields of buildConstants here, in one place, |
| * just to help keep track and ensure that we got everything. |
| */ |
| |
| buildConstants.numAnchors = numAnchors; |
| buildConstants.numCertStores = numCertStores; |
| buildConstants.numHintCerts = numHintCerts; |
| buildConstants.procParams = procParams; |
| buildConstants.testDate = testDate; |
| buildConstants.timeLimit = NULL; |
| buildConstants.targetCert = targetCert; |
| buildConstants.targetPubKey = targetPubKey; |
| buildConstants.certStores = certStores; |
| buildConstants.anchors = anchors; |
| buildConstants.userCheckers = userCheckers; |
| buildConstants.hintCerts = hintCerts; |
| buildConstants.revChecker = revChecker; |
| buildConstants.aiaMgr = aiaMgr; |
| buildConstants.trustOnlyUserAnchors = |
| procParams->useOnlyTrustAnchors; |
| |
| PKIX_CHECK(pkix_Build_GetResourceLimits(&buildConstants, plContext), |
| PKIX_BUILDGETRESOURCELIMITSFAILED); |
| |
| PKIX_CHECK(pkix_ForwardBuilderState_Create |
| (0, /* PKIX_UInt32 traversedCACerts */ |
| buildConstants.maxFanout, |
| buildConstants.maxDepth, |
| PKIX_TRUE, /* PKIX_Boolean canBeCached */ |
| NULL, /* PKIX_Date *validityDate */ |
| targetCert, /* PKIX_PL_Cert *prevCert */ |
| targetSubjNames, /* PKIX_List *traversedSubjNames */ |
| tentativeChain, /* PKIX_List *trustChain */ |
| NULL, /* PKIX_ForwardBuilderState *parent */ |
| &state, /* PKIX_ForwardBuilderState **pState */ |
| plContext), |
| PKIX_BUILDSTATECREATEFAILED); |
| |
| state->buildConstants.numAnchors = buildConstants.numAnchors; |
| state->buildConstants.numCertStores = buildConstants.numCertStores; |
| state->buildConstants.numHintCerts = buildConstants.numHintCerts; |
| state->buildConstants.maxFanout = buildConstants.maxFanout; |
| state->buildConstants.maxDepth = buildConstants.maxDepth; |
| state->buildConstants.maxTime = buildConstants.maxTime; |
| state->buildConstants.procParams = buildConstants.procParams; |
| PKIX_INCREF(buildConstants.testDate); |
| state->buildConstants.testDate = buildConstants.testDate; |
| state->buildConstants.timeLimit = buildConstants.timeLimit; |
| PKIX_INCREF(buildConstants.targetCert); |
| state->buildConstants.targetCert = buildConstants.targetCert; |
| PKIX_INCREF(buildConstants.targetPubKey); |
| state->buildConstants.targetPubKey = |
| buildConstants.targetPubKey; |
| PKIX_INCREF(buildConstants.certStores); |
| state->buildConstants.certStores = buildConstants.certStores; |
| PKIX_INCREF(buildConstants.anchors); |
| state->buildConstants.anchors = buildConstants.anchors; |
| PKIX_INCREF(buildConstants.userCheckers); |
| state->buildConstants.userCheckers = |
| buildConstants.userCheckers; |
| PKIX_INCREF(buildConstants.hintCerts); |
| state->buildConstants.hintCerts = buildConstants.hintCerts; |
| PKIX_INCREF(buildConstants.revChecker); |
| state->buildConstants.revChecker = buildConstants.revChecker; |
| state->buildConstants.aiaMgr = buildConstants.aiaMgr; |
| aiaMgr = NULL; |
| state->buildConstants.trustOnlyUserAnchors = |
| buildConstants.trustOnlyUserAnchors; |
| |
| if (buildConstants.maxTime != 0) { |
| PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds |
| (buildConstants.maxTime, |
| &state->buildConstants.timeLimit, |
| plContext), |
| PKIX_DATECREATECURRENTOFFBYSECONDSFAILED); |
| } |
| |
| if (pVerifyNode != NULL) { |
| PKIX_Error *tempResult = |
| pkix_VerifyNode_Create(targetCert, 0, NULL, |
| &(state->verifyNode), |
| plContext); |
| if (tempResult) { |
| pkixErrorResult = tempResult; |
| pkixErrorCode = PKIX_VERIFYNODECREATEFAILED; |
| pkixErrorClass = PKIX_FATAL_ERROR; |
| goto cleanup; |
| } |
| } |
| |
| PKIX_CHECK_ONLY_FATAL( |
| pkix_Build_CheckInCache(state, &buildResult, |
| &nbioContext, plContext), |
| PKIX_UNABLETOBUILDCHAIN); |
| if (nbioContext) { |
| *pNBIOContext = nbioContext; |
| *pState = state; |
| state = NULL; |
| goto cleanup; |
| } |
| if (buildResult) { |
| *pBuildResult = buildResult; |
| if (pVerifyNode != NULL) { |
| *pVerifyNode = state->verifyNode; |
| state->verifyNode = NULL; |
| } |
| goto cleanup; |
| } |
| } |
| |
| /* If we're resuming after non-blocking I/O we need to get SubjNames */ |
| if (targetSubjNames == NULL) { |
| PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames |
| (state->buildConstants.targetCert, |
| &targetSubjNames, |
| plContext), |
| PKIX_CERTGETALLSUBJECTNAMESFAILED); |
| } |
| |
| state->status = BUILD_INITIAL; |
| |
| pkixErrorResult = |
| pkix_BuildForwardDepthFirstSearch(&nbioContext, state, |
| &valResult, plContext); |
| |
| /* non-null nbioContext means the build would block */ |
| if (pkixErrorResult == NULL && nbioContext != NULL) { |
| |
| *pNBIOContext = nbioContext; |
| *pBuildResult = NULL; |
| |
| /* no valResult means the build has failed */ |
| } else { |
| if (pVerifyNode != NULL) { |
| PKIX_INCREF(state->verifyNode); |
| *pVerifyNode = state->verifyNode; |
| } |
| |
| if (valResult == NULL || pkixErrorResult) |
| PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN); |
| PKIX_CHECK( |
| pkix_BuildResult_Create(valResult, state->trustChain, |
| &buildResult, plContext), |
| PKIX_BUILDRESULTCREATEFAILED); |
| *pBuildResult = buildResult; |
| } |
| |
| *pState = state; |
| state = NULL; |
| |
| cleanup: |
| |
| PKIX_DECREF(targetConstraints); |
| PKIX_DECREF(targetParams); |
| PKIX_DECREF(anchors); |
| PKIX_DECREF(targetSubjNames); |
| PKIX_DECREF(targetCert); |
| PKIX_DECREF(revChecker); |
| PKIX_DECREF(certStores); |
| PKIX_DECREF(certStore); |
| PKIX_DECREF(userCheckers); |
| PKIX_DECREF(hintCerts); |
| PKIX_DECREF(firstHintCert); |
| PKIX_DECREF(testDate); |
| PKIX_DECREF(targetPubKey); |
| PKIX_DECREF(tentativeChain); |
| PKIX_DECREF(valResult); |
| PKIX_DECREF(certList); |
| PKIX_DECREF(trustedCert); |
| PKIX_DECREF(state); |
| PKIX_DECREF(aiaMgr); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* |
| * FUNCTION: pkix_Build_ResumeBuildChain |
| * DESCRIPTION: |
| * |
| * This function continues the search for a BuildChain, using the parameters |
| * provided in "procParams" and the ForwardBuilderState pointed to by "state". |
| * |
| * If a successful chain is built, this function stores the BuildResult at |
| * "pBuildResult". Alternatively, if an operation using non-blocking I/O |
| * is in progress and the operation has not been completed, this function |
| * stores the FowardBuilderState at "pState" and NULL at "pBuildResult". |
| * Finally, if chain building was unsuccessful, this function stores NULL |
| * at both "pState" and at "pBuildResult". |
| * |
| * PARAMETERS: |
| * "pNBIOContext" |
| * Address at which the NBIOContext is stored indicating whether the |
| * validation is complete. Must be non-NULL. |
| * "pState" |
| * Address at which the ForwardBuilderState is provided for resumption of |
| * the chain building attempt; also, the address at which the |
| * ForwardBuilderStateis stored, if the chain building is suspended for |
| * waiting I/O. Must be non-NULL. |
| * "pBuildResult" |
| * Address at which the BuildResult is stored, after a successful build. |
| * 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 Build Error if the function fails in a non-fatal way |
| * Returns a Fatal Error if the function fails in an unrecoverable way. |
| */ |
| static PKIX_Error * |
| pkix_Build_ResumeBuildChain( |
| void **pNBIOContext, |
| PKIX_ForwardBuilderState *state, |
| PKIX_BuildResult **pBuildResult, |
| PKIX_VerifyNode **pVerifyNode, |
| void *plContext) |
| { |
| PKIX_ValidateResult *valResult = NULL; |
| PKIX_BuildResult *buildResult = NULL; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "pkix_Build_ResumeBuildChain"); |
| PKIX_NULLCHECK_TWO(state, pBuildResult); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| pkixErrorResult = |
| pkix_BuildForwardDepthFirstSearch(&nbioContext, state, |
| &valResult, plContext); |
| |
| /* non-null nbioContext means the build would block */ |
| if (pkixErrorResult == NULL && nbioContext != NULL) { |
| |
| *pNBIOContext = nbioContext; |
| *pBuildResult = NULL; |
| |
| /* no valResult means the build has failed */ |
| } else { |
| if (pVerifyNode != NULL) { |
| PKIX_INCREF(state->verifyNode); |
| *pVerifyNode = state->verifyNode; |
| } |
| |
| if (valResult == NULL || pkixErrorResult) |
| PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN); |
| |
| PKIX_CHECK( |
| pkix_BuildResult_Create(valResult, state->trustChain, |
| &buildResult, plContext), |
| PKIX_BUILDRESULTCREATEFAILED); |
| *pBuildResult = buildResult; |
| } |
| |
| cleanup: |
| |
| PKIX_DECREF(valResult); |
| |
| PKIX_RETURN(BUILD); |
| } |
| |
| /* --Public-Functions--------------------------------------------- */ |
| |
| /* |
| * FUNCTION: PKIX_BuildChain (see comments in pkix.h) |
| */ |
| PKIX_Error * |
| PKIX_BuildChain( |
| PKIX_ProcessingParams *procParams, |
| void **pNBIOContext, |
| void **pState, |
| PKIX_BuildResult **pBuildResult, |
| PKIX_VerifyNode **pVerifyNode, |
| void *plContext) |
| { |
| PKIX_ForwardBuilderState *state = NULL; |
| PKIX_BuildResult *buildResult = NULL; |
| void *nbioContext = NULL; |
| |
| PKIX_ENTER(BUILD, "PKIX_BuildChain"); |
| PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult); |
| |
| nbioContext = *pNBIOContext; |
| *pNBIOContext = NULL; |
| |
| if (*pState == NULL) { |
| PKIX_CHECK(pkix_Build_InitiateBuildChain |
| (procParams, |
| &nbioContext, |
| &state, |
| &buildResult, |
| pVerifyNode, |
| plContext), |
| PKIX_BUILDINITIATEBUILDCHAINFAILED); |
| } else { |
| state = (PKIX_ForwardBuilderState *)(*pState); |
| *pState = NULL; /* no net change in reference count */ |
| if (state->status == BUILD_SHORTCUTPENDING) { |
| PKIX_CHECK(pkix_Build_InitiateBuildChain |
| (procParams, |
| &nbioContext, |
| &state, |
| &buildResult, |
| pVerifyNode, |
| plContext), |
| PKIX_BUILDINITIATEBUILDCHAINFAILED); |
| } else { |
| PKIX_CHECK(pkix_Build_ResumeBuildChain |
| (&nbioContext, |
| state, |
| &buildResult, |
| pVerifyNode, |
| plContext), |
| PKIX_BUILDINITIATEBUILDCHAINFAILED); |
| } |
| } |
| |
| /* non-null nbioContext means the build would block */ |
| if (nbioContext != NULL) { |
| |
| *pNBIOContext = nbioContext; |
| *pState = state; |
| state = NULL; |
| *pBuildResult = NULL; |
| |
| /* no buildResult means the build has failed */ |
| } else if (buildResult == NULL) { |
| PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN); |
| } else { |
| /* |
| * If we made a successful chain by combining the target Cert |
| * with one of the Trust Anchors, we may have never created a |
| * validityDate. We treat this situation as |
| * canBeCached = PKIX_FALSE. |
| */ |
| if ((state != NULL) && |
| ((state->validityDate) != NULL) && |
| (state->canBeCached)) { |
| PKIX_CHECK(pkix_CacheCertChain_Add |
| (state->buildConstants.targetCert, |
| state->buildConstants.anchors, |
| state->validityDate, |
| buildResult, |
| plContext), |
| PKIX_CACHECERTCHAINADDFAILED); |
| } |
| |
| *pState = NULL; |
| *pBuildResult = buildResult; |
| buildResult = NULL; |
| } |
| |
| cleanup: |
| PKIX_DECREF(buildResult); |
| PKIX_DECREF(state); |
| |
| PKIX_RETURN(BUILD); |
| } |