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