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