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