summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix/top
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/libpkix/pkix/top')
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/Makefile48
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/config.mk15
-rw-r--r--security/nss/lib/libpkix/pkix/top/exports.gyp27
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/manifest.mn25
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_build.c3763
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_build.h120
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_lifecycle.c210
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_lifecycle.h23
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_validate.c1451
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix/top/pkix_validate.h42
-rw-r--r--security/nss/lib/libpkix/pkix/top/top.gyp25
11 files changed, 5749 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix/top/Makefile b/security/nss/lib/libpkix/pkix/top/Makefile
new file mode 100755
index 000000000..36524f56a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/Makefile
@@ -0,0 +1,48 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
diff --git a/security/nss/lib/libpkix/pkix/top/config.mk b/security/nss/lib/libpkix/pkix/top/config.mk
new file mode 100755
index 000000000..b8c03de79
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/config.mk
@@ -0,0 +1,15 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/libpkix/pkix/top/exports.gyp b/security/nss/lib/libpkix/pkix/top/exports.gyp
new file mode 100644
index 000000000..d41f2b5ec
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/exports.gyp
@@ -0,0 +1,27 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_libpkix_pkix_top_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'pkix_build.h',
+ 'pkix_lifecycle.h',
+ 'pkix_validate.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/libpkix/pkix/top/manifest.mn b/security/nss/lib/libpkix/pkix/top/manifest.mn
new file mode 100755
index 000000000..c49941034
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/manifest.mn
@@ -0,0 +1,25 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../../..
+
+EXPORTS = \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ pkix_build.h \
+ pkix_lifecycle.h \
+ pkix_validate.h \
+ $(NULL)
+
+MODULE = nss
+
+CSRCS = \
+ pkix_validate.c \
+ pkix_lifecycle.c \
+ pkix_build.c \
+ $(NULL)
+
+LIBRARY_NAME = pkixtop
+
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_build.c b/security/nss/lib/libpkix/pkix/top/pkix_build.c
new file mode 100755
index 000000000..0c87ba3f3
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_build.c
@@ -0,0 +1,3763 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_build.c
+ *
+ * Top level buildChain function
+ *
+ */
+
+/* #define PKIX_BUILDDEBUG 1 */
+/* #define PKIX_FORWARDBUILDERSTATEDEBUG 1 */
+
+#include "pkix_build.h"
+
+extern PRLogModuleInfo *pkixLog;
+
+/*
+ * List of critical extension OIDs associate with what build chain has
+ * checked. Those OIDs need to be removed from the unresolved critical
+ * extension OIDs list manually (instead of by checker automatically).
+ */
+static SECOidTag buildCheckedCritExtOIDs[] = {
+ PKIX_CERTKEYUSAGE_OID,
+ PKIX_CERTSUBJALTNAME_OID,
+ PKIX_BASICCONSTRAINTS_OID,
+ PKIX_NAMECONSTRAINTS_OID,
+ PKIX_EXTENDEDKEYUSAGE_OID,
+ PKIX_NSCERTTYPE_OID,
+ PKIX_UNKNOWN_OID
+};
+
+/* --Private-ForwardBuilderState-Functions---------------------------------- */
+
+/*
+ * FUNCTION: pkix_ForwardBuilderState_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_ForwardBuilderState_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ForwardBuilderState *state = NULL;
+
+ PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext),
+ PKIX_OBJECTNOTFORWARDBUILDERSTATE);
+
+ state = (PKIX_ForwardBuilderState *)object;
+
+ state->status = BUILD_INITIAL;
+ state->traversedCACerts = 0;
+ state->certStoreIndex = 0;
+ state->numCerts = 0;
+ state->numAias = 0;
+ state->certIndex = 0;
+ state->aiaIndex = 0;
+ state->certCheckedIndex = 0;
+ state->checkerIndex = 0;
+ state->hintCertIndex = 0;
+ state->numFanout = 0;
+ state->numDepth = 0;
+ state->reasonCode = 0;
+ state->canBeCached = PKIX_FALSE;
+ state->useOnlyLocal = PKIX_FALSE;
+ state->revChecking = PKIX_FALSE;
+ state->usingHintCerts = PKIX_FALSE;
+ state->certLoopingDetected = PKIX_FALSE;
+ PKIX_DECREF(state->validityDate);
+ PKIX_DECREF(state->prevCert);
+ PKIX_DECREF(state->candidateCert);
+ PKIX_DECREF(state->traversedSubjNames);
+ PKIX_DECREF(state->trustChain);
+ PKIX_DECREF(state->aia);
+ PKIX_DECREF(state->candidateCerts);
+ PKIX_DECREF(state->reversedCertChain);
+ PKIX_DECREF(state->checkedCritExtOIDs);
+ PKIX_DECREF(state->checkerChain);
+ PKIX_DECREF(state->certSel);
+ PKIX_DECREF(state->verifyNode);
+ PKIX_DECREF(state->client);
+
+ /*
+ * If we ever add a child link we have to be careful not to have loops
+ * in the Destroy process. But with one-way links we should be okay.
+ */
+ if (state->parentState == NULL) {
+ state->buildConstants.numAnchors = 0;
+ state->buildConstants.numCertStores = 0;
+ state->buildConstants.numHintCerts = 0;
+ state->buildConstants.procParams = 0;
+ PKIX_DECREF(state->buildConstants.testDate);
+ PKIX_DECREF(state->buildConstants.timeLimit);
+ PKIX_DECREF(state->buildConstants.targetCert);
+ PKIX_DECREF(state->buildConstants.targetPubKey);
+ PKIX_DECREF(state->buildConstants.certStores);
+ PKIX_DECREF(state->buildConstants.anchors);
+ PKIX_DECREF(state->buildConstants.userCheckers);
+ PKIX_DECREF(state->buildConstants.hintCerts);
+ PKIX_DECREF(state->buildConstants.revChecker);
+ PKIX_DECREF(state->buildConstants.aiaMgr);
+ } else {
+ PKIX_DECREF(state->parentState);
+ }
+
+cleanup:
+
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+}
+
+/*
+ * FUNCTION: pkix_ForwardBuilderState_Create
+ *
+ * DESCRIPTION:
+ * Allocate and initialize a ForwardBuilderState.
+ *
+ * PARAMETERS
+ * "traversedCACerts"
+ * Number of CA certificates traversed.
+ * "numFanout"
+ * Number of Certs that can be considered at this level (0 = no limit)
+ * "numDepth"
+ * Number of additional levels that can be searched (0 = no limit)
+ * "canBeCached"
+ * Boolean value indicating whether all certs on the chain can be cached.
+ * "validityDate"
+ * Address of Date at which build chain Certs' most restricted validity
+ * time is kept. May be NULL.
+ * "prevCert"
+ * Address of Cert just traversed. Must be non-NULL.
+ * "traversedSubjNames"
+ * Address of List of GeneralNames that have been traversed.
+ * Must be non-NULL.
+ * "trustChain"
+ * Address of List of certificates traversed. Must be non-NULL.
+ * "parentState"
+ * Address of previous ForwardBuilderState
+ * "pState"
+ * Address where ForwardBuilderState will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_ForwardBuilderState_Create(
+ PKIX_Int32 traversedCACerts,
+ PKIX_UInt32 numFanout,
+ PKIX_UInt32 numDepth,
+ PKIX_Boolean canBeCached,
+ PKIX_PL_Date *validityDate,
+ PKIX_PL_Cert *prevCert,
+ PKIX_List *traversedSubjNames,
+ PKIX_List *trustChain,
+ PKIX_ForwardBuilderState *parentState,
+ PKIX_ForwardBuilderState **pState,
+ void *plContext)
+{
+ PKIX_ForwardBuilderState *state = NULL;
+
+ PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_Create");
+ PKIX_NULLCHECK_FOUR(prevCert, traversedSubjNames, pState, trustChain);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_FORWARDBUILDERSTATE_TYPE,
+ sizeof (PKIX_ForwardBuilderState),
+ (PKIX_PL_Object **)&state,
+ plContext),
+ PKIX_COULDNOTCREATEFORWARDBUILDERSTATEOBJECT);
+
+ state->status = BUILD_INITIAL;
+ state->traversedCACerts = traversedCACerts;
+ state->certStoreIndex = 0;
+ state->numCerts = 0;
+ state->numAias = 0;
+ state->certIndex = 0;
+ state->aiaIndex = 0;
+ state->certCheckedIndex = 0;
+ state->checkerIndex = 0;
+ state->hintCertIndex = 0;
+ state->numFanout = numFanout;
+ state->numDepth = numDepth;
+ state->reasonCode = 0;
+ state->revChecking = numDepth;
+ state->canBeCached = canBeCached;
+ state->useOnlyLocal = PKIX_TRUE;
+ state->revChecking = PKIX_FALSE;
+ state->usingHintCerts = PKIX_FALSE;
+ state->certLoopingDetected = PKIX_FALSE;
+
+ PKIX_INCREF(validityDate);
+ state->validityDate = validityDate;
+
+ PKIX_INCREF(prevCert);
+ state->prevCert = prevCert;
+
+ state->candidateCert = NULL;
+
+ PKIX_INCREF(traversedSubjNames);
+ state->traversedSubjNames = traversedSubjNames;
+
+ PKIX_INCREF(trustChain);
+ state->trustChain = trustChain;
+
+ state->aia = NULL;
+ state->candidateCerts = NULL;
+ state->reversedCertChain = NULL;
+ state->checkedCritExtOIDs = NULL;
+ state->checkerChain = NULL;
+ state->certSel = NULL;
+ state->verifyNode = NULL;
+ state->client = NULL;
+
+ PKIX_INCREF(parentState);
+ state->parentState = parentState;
+
+ if (parentState != NULL) {
+ state->buildConstants.numAnchors =
+ parentState->buildConstants.numAnchors;
+ state->buildConstants.numCertStores =
+ parentState->buildConstants.numCertStores;
+ state->buildConstants.numHintCerts =
+ parentState->buildConstants.numHintCerts;
+ state->buildConstants.maxFanout =
+ parentState->buildConstants.maxFanout;
+ state->buildConstants.maxDepth =
+ parentState->buildConstants.maxDepth;
+ state->buildConstants.maxTime =
+ parentState->buildConstants.maxTime;
+ state->buildConstants.procParams =
+ parentState->buildConstants.procParams;
+ state->buildConstants.testDate =
+ parentState->buildConstants.testDate;
+ state->buildConstants.timeLimit =
+ parentState->buildConstants.timeLimit;
+ state->buildConstants.targetCert =
+ parentState->buildConstants.targetCert;
+ state->buildConstants.targetPubKey =
+ parentState->buildConstants.targetPubKey;
+ state->buildConstants.certStores =
+ parentState->buildConstants.certStores;
+ state->buildConstants.anchors =
+ parentState->buildConstants.anchors;
+ state->buildConstants.userCheckers =
+ parentState->buildConstants.userCheckers;
+ state->buildConstants.hintCerts =
+ parentState->buildConstants.hintCerts;
+ state->buildConstants.revChecker =
+ parentState->buildConstants.revChecker;
+ state->buildConstants.aiaMgr =
+ parentState->buildConstants.aiaMgr;
+ state->buildConstants.trustOnlyUserAnchors =
+ parentState->buildConstants.trustOnlyUserAnchors;
+ }
+
+ *pState = state;
+ state = NULL;
+cleanup:
+
+ PKIX_DECREF(state);
+
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+}
+
+/*
+ * FUNCTION: pkix_Build_GetResourceLimits
+ *
+ * DESCRIPTION:
+ * Retrieve Resource Limits from ProcessingParams and initialize them in
+ * BuildConstants.
+ *
+ * PARAMETERS
+ * "buildConstants"
+ * Address of a BuildConstants structure containing objects and values
+ * that remain constant throughout the building of a chain. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_GetResourceLimits(
+ BuildConstants *buildConstants,
+ void *plContext)
+{
+ PKIX_ResourceLimits *resourceLimits = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_GetResourceLimits");
+ PKIX_NULLCHECK_ONE(buildConstants);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetResourceLimits
+ (buildConstants->procParams, &resourceLimits, plContext),
+ PKIX_PROCESSINGPARAMSGETRESOURCELIMITSFAILED);
+
+ buildConstants->maxFanout = 0;
+ buildConstants->maxDepth = 0;
+ buildConstants->maxTime = 0;
+
+ if (resourceLimits) {
+
+ PKIX_CHECK(PKIX_ResourceLimits_GetMaxFanout
+ (resourceLimits, &buildConstants->maxFanout, plContext),
+ PKIX_RESOURCELIMITSGETMAXFANOUTFAILED);
+
+ PKIX_CHECK(PKIX_ResourceLimits_GetMaxDepth
+ (resourceLimits, &buildConstants->maxDepth, plContext),
+ PKIX_RESOURCELIMITSGETMAXDEPTHFAILED);
+
+ PKIX_CHECK(PKIX_ResourceLimits_GetMaxTime
+ (resourceLimits, &buildConstants->maxTime, plContext),
+ PKIX_RESOURCELIMITSGETMAXTIMEFAILED);
+ }
+
+cleanup:
+
+ PKIX_DECREF(resourceLimits);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_ForwardBuilderState_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_ForwardBuilderState_ToString
+ (PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_ForwardBuilderState *state = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *resultString = NULL;
+ PKIX_PL_String *buildStatusString = NULL;
+ PKIX_PL_String *validityDateString = NULL;
+ PKIX_PL_String *prevCertString = NULL;
+ PKIX_PL_String *candidateCertString = NULL;
+ PKIX_PL_String *traversedSubjNamesString = NULL;
+ PKIX_PL_String *trustChainString = NULL;
+ PKIX_PL_String *candidateCertsString = NULL;
+ PKIX_PL_String *certSelString = NULL;
+ PKIX_PL_String *verifyNodeString = NULL;
+ PKIX_PL_String *parentStateString = NULL;
+ char *asciiFormat = "\n"
+ "\t{buildStatus: \t%s\n"
+ "\ttraversedCACerts: \t%d\n"
+ "\tcertStoreIndex: \t%d\n"
+ "\tnumCerts: \t%d\n"
+ "\tnumAias: \t%d\n"
+ "\tcertIndex: \t%d\n"
+ "\taiaIndex: \t%d\n"
+ "\tnumFanout: \t%d\n"
+ "\tnumDepth: \t%d\n"
+ "\treasonCode: \t%d\n"
+ "\tcanBeCached: \t%d\n"
+ "\tuseOnlyLocal: \t%d\n"
+ "\trevChecking: \t%d\n"
+ "\tvalidityDate: \t%s\n"
+ "\tprevCert: \t%s\n"
+ "\tcandidateCert: \t%s\n"
+ "\ttraversedSubjNames: \t%s\n"
+ "\ttrustChain: \t%s\n"
+ "\tcandidateCerts: \t%s\n"
+ "\tcertSel: \t%s\n"
+ "\tverifyNode: \t%s\n"
+ "\tparentState: \t%s}\n";
+ char *asciiStatus = NULL;
+
+ PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_FORWARDBUILDERSTATE_TYPE, plContext),
+ PKIX_OBJECTNOTFORWARDBUILDERSTATE);
+
+ state = (PKIX_ForwardBuilderState *)object;
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ switch (state->status) {
+ case BUILD_SHORTCUTPENDING: asciiStatus = "BUILD_SHORTCUTPENDING";
+ break;
+ case BUILD_INITIAL: asciiStatus = "BUILD_INITIAL";
+ break;
+ case BUILD_TRYAIA: asciiStatus = "BUILD_TRYAIA";
+ break;
+ case BUILD_AIAPENDING: asciiStatus = "BUILD_AIAPENDING";
+ break;
+ case BUILD_COLLECTINGCERTS: asciiStatus = "BUILD_COLLECTINGCERTS";
+ break;
+ case BUILD_GATHERPENDING: asciiStatus = "BUILD_GATHERPENDING";
+ break;
+ case BUILD_CERTVALIDATING: asciiStatus = "BUILD_CERTVALIDATING";
+ break;
+ case BUILD_ABANDONNODE: asciiStatus = "BUILD_ABANDONNODE";
+ break;
+ case BUILD_DATEPREP: asciiStatus = "BUILD_DATEPREP";
+ break;
+ case BUILD_CHECKTRUSTED: asciiStatus = "BUILD_CHECKTRUSTED";
+ break;
+ case BUILD_CHECKTRUSTED2: asciiStatus = "BUILD_CHECKTRUSTED2";
+ break;
+ case BUILD_ADDTOCHAIN: asciiStatus = "BUILD_ADDTOCHAIN";
+ break;
+ case BUILD_VALCHAIN: asciiStatus = "BUILD_VALCHAIN";
+ break;
+ case BUILD_VALCHAIN2: asciiStatus = "BUILD_VALCHAIN2";
+ break;
+ case BUILD_EXTENDCHAIN: asciiStatus = "BUILD_EXTENDCHAIN";
+ break;
+ case BUILD_GETNEXTCERT: asciiStatus = "BUILD_GETNEXTCERT";
+ break;
+ default: asciiStatus = "INVALID STATUS";
+ break;
+ }
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiStatus, 0, &buildStatusString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_TOSTRING
+ (state->validityDate, &validityDateString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->prevCert, &prevCertString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->candidateCert, &candidateCertString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->traversedSubjNames,
+ &traversedSubjNamesString,
+ plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->trustChain, &trustChainString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->candidateCerts, &candidateCertsString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->certSel, &certSelString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->verifyNode, &verifyNodeString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (state->parentState, &parentStateString, plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&resultString,
+ plContext,
+ formatString,
+ buildStatusString,
+ (PKIX_Int32)state->traversedCACerts,
+ (PKIX_UInt32)state->certStoreIndex,
+ (PKIX_UInt32)state->numCerts,
+ (PKIX_UInt32)state->numAias,
+ (PKIX_UInt32)state->certIndex,
+ (PKIX_UInt32)state->aiaIndex,
+ (PKIX_UInt32)state->numFanout,
+ (PKIX_UInt32)state->numDepth,
+ (PKIX_UInt32)state->reasonCode,
+ state->canBeCached,
+ state->useOnlyLocal,
+ state->revChecking,
+ validityDateString,
+ prevCertString,
+ candidateCertString,
+ traversedSubjNamesString,
+ trustChainString,
+ candidateCertsString,
+ certSelString,
+ verifyNodeString,
+ parentStateString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = resultString;
+
+cleanup:
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(buildStatusString);
+ PKIX_DECREF(validityDateString);
+ PKIX_DECREF(prevCertString);
+ PKIX_DECREF(candidateCertString);
+ PKIX_DECREF(traversedSubjNamesString);
+ PKIX_DECREF(trustChainString);
+ PKIX_DECREF(candidateCertsString);
+ PKIX_DECREF(certSelString);
+ PKIX_DECREF(verifyNodeString);
+ PKIX_DECREF(parentStateString);
+
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+
+}
+
+/*
+ * FUNCTION: pkix_ForwardBuilderState_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_FORWARDBUILDERSTATE_TYPE and its related functions
+ * with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_ForwardBuilderState_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(FORWARDBUILDERSTATE,
+ "pkix_ForwardBuilderState_RegisterSelf");
+
+ entry.description = "ForwardBuilderState";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_ForwardBuilderState);
+ entry.destructor = pkix_ForwardBuilderState_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = pkix_ForwardBuilderState_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_FORWARDBUILDERSTATE_TYPE] = entry;
+
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+}
+
+#if PKIX_FORWARDBUILDERSTATEDEBUG
+/*
+ * FUNCTION: pkix_ForwardBuilderState_DumpState
+ *
+ * DESCRIPTION:
+ * This function invokes the ToString function on the argument pointed to
+ * by "state".
+ * PARAMETERS:
+ * "state"
+ * The address of the ForwardBuilderState object. Must be non-NULL.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ */
+PKIX_Error *
+pkix_ForwardBuilderState_DumpState(
+ PKIX_ForwardBuilderState *state,
+ void *plContext)
+{
+ PKIX_PL_String *stateString = NULL;
+ char *stateAscii = NULL;
+ PKIX_UInt32 length;
+
+ PKIX_ENTER(FORWARDBUILDERSTATE,"pkix_ForwardBuilderState_DumpState");
+ PKIX_NULLCHECK_ONE(state);
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)state, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object*)state, &stateString, plContext),
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (stateString,
+ PKIX_ESCASCII,
+ (void **)&stateAscii,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_DEBUG_ARG("In Phase 1: state = %s\n", stateAscii);
+
+ PKIX_FREE(stateAscii);
+ PKIX_DECREF(stateString);
+
+cleanup:
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+}
+#endif
+
+/*
+ * FUNCTION: pkix_ForwardBuilderState_IsIOPending
+ * DESCRIPTION:
+ *
+ * This function determines whether the state of the ForwardBuilderState
+ * pointed to by "state" indicates I/O is in progress, and stores the Boolean
+ * result at "pPending".
+ *
+ * PARAMETERS:
+ * "state"
+ * The address of the ForwardBuilderState object. Must be non-NULL.
+ * "pPending"
+ * The address at which the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a ForwardBuilderState Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error*
+pkix_ForwardBuilderState_IsIOPending(
+ PKIX_ForwardBuilderState *state,
+ PKIX_Boolean *pPending,
+ void *plContext)
+{
+ PKIX_ENTER(FORWARDBUILDERSTATE, "pkix_ForwardBuilderState_IsIOPending");
+ PKIX_NULLCHECK_TWO(state, pPending);
+
+ if ((state->status == BUILD_GATHERPENDING) ||
+ (state->status == BUILD_CHECKTRUSTED2) ||
+ (state->status == BUILD_VALCHAIN2) ||
+ (state->status == BUILD_AIAPENDING)) {
+ *pPending = PKIX_TRUE;
+ } else {
+ *pPending = PKIX_FALSE;
+ }
+
+ PKIX_RETURN(FORWARDBUILDERSTATE);
+}
+
+/* --Private-BuildChain-Functions------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_Build_SortCertComparator
+ * DESCRIPTION:
+ *
+ * This Function takes two Certificates cast in "obj1" and "obj2",
+ * compares them to determine which is a more preferable certificate
+ * for chain building. This Function is suitable for use as a
+ * comparator callback for pkix_List_BubbleSort, setting "*pResult" to
+ * > 0 if "obj1" is less desirable than "obj2" and < 0 if "obj1"
+ * is more desirable than "obj2".
+ *
+ * PARAMETERS:
+ * "obj1"
+ * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert.
+ * Must be non-NULL.
+ * "obj2"
+ * Address of the PKIX_PL_Object that is a cast of PKIX_PL_Cert.
+ * Must be non-NULL.
+ * "pResult"
+ * Address where the comparison result is returned. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_SortCertComparator(
+ PKIX_PL_Object *obj1,
+ PKIX_PL_Object *obj2,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_Date *date1 = NULL;
+ PKIX_PL_Date *date2 = NULL;
+ PKIX_Int32 result = 0;
+
+ PKIX_ENTER(BUILD, "pkix_Build_SortCertComparator");
+ PKIX_NULLCHECK_THREE(obj1, obj2, pResult);
+
+ /*
+ * For sorting candidate certificates, we use NotAfter date as the
+ * comparison key for now (can be expanded if desired in the future).
+ *
+ * In PKIX_BuildChain, the List of CertStores was reordered so that
+ * trusted CertStores are ahead of untrusted CertStores. That sort, or
+ * this one, could be taken out if it is determined that it doesn't help
+ * performance, or in some way hinders the solution of choosing desired
+ * candidates.
+ */
+
+ PKIX_CHECK(pkix_CheckType(obj1, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+ PKIX_CHECK(pkix_CheckType(obj2, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
+ ((PKIX_PL_Cert *)obj1, &date1, plContext),
+ PKIX_CERTGETVALIDITYNOTAFTERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
+ ((PKIX_PL_Cert *)obj2, &date2, plContext),
+ PKIX_CERTGETVALIDITYNOTAFTERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_Compare
+ ((PKIX_PL_Object *)date1,
+ (PKIX_PL_Object *)date2,
+ &result,
+ plContext),
+ PKIX_OBJECTCOMPARATORFAILED);
+
+ /*
+ * Invert the result, so that if date1 is greater than date2,
+ * obj1 is sorted before obj2. This is because pkix_List_BubbleSort
+ * sorts in ascending order.
+ */
+ *pResult = -result;
+
+cleanup:
+
+ PKIX_DECREF(date1);
+ PKIX_DECREF(date2);
+
+ PKIX_RETURN(BUILD);
+}
+
+/* This local error check macro */
+#define ERROR_CHECK(errCode) \
+ if (pkixErrorResult) { \
+ if (pkixLog) { \
+ PR_LOG(pkixLog, PR_LOG_DEBUG, ("====> ERROR_CHECK code %s\n", #errCode)); \
+ } \
+ pkixTempErrorReceived = PKIX_TRUE; \
+ pkixErrorClass = pkixErrorResult->errClass; \
+ if (pkixErrorClass == PKIX_FATAL_ERROR) { \
+ goto cleanup; \
+ } \
+ if (verifyNode) { \
+ PKIX_DECREF(verifyNode->error); \
+ PKIX_INCREF(pkixErrorResult); \
+ verifyNode->error = pkixErrorResult; \
+ } \
+ pkixErrorCode = errCode; \
+ goto cleanup; \
+ }
+
+/*
+ * FUNCTION: pkix_Build_VerifyCertificate
+ * DESCRIPTION:
+ *
+ * Checks whether the previous Cert stored in the ForwardBuilderState pointed
+ * to by "state" successfully chains, including signature verification, to the
+ * candidate Cert also stored in "state", using the Boolean value in "trusted"
+ * to determine whether "candidateCert" is trusted.
+ *
+ * First it checks whether "candidateCert" has already been traversed by
+ * determining whether it is contained in the List of traversed Certs. It then
+ * checks the candidate Cert with user checkers, if any, in the List pointed to
+ * by "userCheckers". Finally, it runs the signature validation.
+ *
+ * If this Certificate fails verification, and state->verifyNode is non-NULL,
+ * this function sets the Error code into the verifyNode.
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "userCheckers"
+ * Address of a List of CertChainCheckers to be used, if present, to
+ * validate the candidateCert.
+ * "trusted"
+ * Boolean value of trust for the candidate Cert
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_VerifyCertificate(
+ PKIX_ForwardBuilderState *state,
+ PKIX_List *userCheckers,
+ PKIX_Boolean *pTrusted,
+ PKIX_VerifyNode *verifyNode,
+ void *plContext)
+{
+ PKIX_UInt32 numUserCheckers = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_Boolean loopFound = PKIX_FALSE;
+ PKIX_Boolean supportForwardChecking = PKIX_FALSE;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ PKIX_PL_Cert *candidateCert = NULL;
+ PKIX_PL_PublicKey *candidatePubKey = NULL;
+ PKIX_CertChainChecker *userChecker = NULL;
+ PKIX_CertChainChecker_CheckCallback checkerCheck = NULL;
+ PKIX_PL_TrustAnchorMode trustAnchorMode =
+ PKIX_PL_TrustAnchorMode_Ignore;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_VerifyCertificate");
+ PKIX_NULLCHECK_TWO(state, pTrusted);
+ PKIX_NULLCHECK_THREE
+ (state->candidateCerts, state->prevCert, state->trustChain);
+
+ PKIX_INCREF(state->candidateCert);
+ candidateCert = state->candidateCert;
+
+ if (state->buildConstants.numAnchors) {
+ if (state->buildConstants.trustOnlyUserAnchors) {
+ trustAnchorMode = PKIX_PL_TrustAnchorMode_Exclusive;
+ } else {
+ trustAnchorMode = PKIX_PL_TrustAnchorMode_Additive;
+ }
+ } else {
+ trustAnchorMode = PKIX_PL_TrustAnchorMode_Ignore;
+ }
+
+ PKIX_CHECK(
+ PKIX_PL_Cert_IsCertTrusted(candidateCert, trustAnchorMode,
+ &trusted, plContext),
+ PKIX_CERTISCERTTRUSTEDFAILED);
+
+ *pTrusted = trusted;
+
+ /* check for loops */
+ PKIX_CHECK(pkix_List_Contains
+ (state->trustChain,
+ (PKIX_PL_Object *)candidateCert,
+ &loopFound,
+ plContext),
+ PKIX_LISTCONTAINSFAILED);
+
+ if (loopFound) {
+ if (verifyNode != NULL) {
+ PKIX_Error *verifyError = NULL;
+ PKIX_ERROR_CREATE
+ (BUILD,
+ PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED,
+ verifyError);
+ PKIX_DECREF(verifyNode->error);
+ verifyNode->error = verifyError;
+ }
+ /* Even if error logged, still need to abort
+ * if cert is not trusted. */
+ if (!trusted) {
+ PKIX_ERROR(PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED);
+ }
+ state->certLoopingDetected = PKIX_TRUE;
+ }
+
+ if (userCheckers != NULL) {
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (userCheckers, &numUserCheckers, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (i = 0; i < numUserCheckers; i++) {
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (userCheckers,
+ i,
+ (PKIX_PL_Object **) &userChecker,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK
+ (PKIX_CertChainChecker_IsForwardCheckingSupported
+ (userChecker, &supportForwardChecking, plContext),
+ PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED);
+
+ if (supportForwardChecking == PKIX_TRUE) {
+
+ PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback
+ (userChecker, &checkerCheck, plContext),
+ PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED);
+
+ pkixErrorResult =
+ checkerCheck(userChecker, candidateCert, NULL,
+ &nbioContext, plContext);
+
+ ERROR_CHECK(PKIX_USERCHECKERCHECKFAILED);
+ }
+
+ PKIX_DECREF(userChecker);
+ }
+ }
+
+ /* Check that public key of the trusted dsa cert has
+ * dsa parameters */
+ if (trusted) {
+ PKIX_Boolean paramsNeeded = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (candidateCert, &candidatePubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+ PKIX_CHECK(PKIX_PL_PublicKey_NeedsDSAParameters
+ (candidatePubKey, &paramsNeeded, plContext),
+ PKIX_PUBLICKEYNEEDSDSAPARAMETERSFAILED);
+ if (paramsNeeded) {
+ PKIX_ERROR(PKIX_MISSINGDSAPARAMETERS);
+ }
+ }
+
+cleanup:
+ PKIX_DECREF(candidateCert);
+ PKIX_DECREF(candidatePubKey);
+ PKIX_DECREF(userChecker);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_ValidationCheckers
+ * DESCRIPTION:
+ *
+ * Creates a List of Objects to be used in determining whether the List of
+ * Certs pointed to by "certChain" successfully validates using the
+ * ForwardBuilderState pointed to by "state", and the TrustAnchor pointed to by
+ * "anchor". These objects are a reversed Cert Chain, consisting of the certs
+ * in "certChain" in reversed order, suitable for presenting to the
+ * CertChainCheckers; a List of critical extension OIDS that have already been
+ * processed in forward building; a List of CertChainCheckers to be called, and
+ * a List of RevocationCheckers to be called. These results are stored in
+ * fields of "state".
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "certChain"
+ * Address of List of Certs to be validated. Must be non-NULL.
+ * "anchor"
+ * Address of TrustAnchor to be used. Must be non-NULL.
+ * "addEkuChecker"
+ * Boolean flags that tells to add eku checker to the list
+ * of checkers. Only needs to be done for existing chain revalidation.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_ValidationCheckers(
+ PKIX_ForwardBuilderState *state,
+ PKIX_List *certChain,
+ PKIX_TrustAnchor *anchor,
+ PKIX_Boolean chainRevalidationStage,
+ void *plContext)
+{
+ PKIX_List *checkers = NULL;
+ PKIX_List *initialPolicies = NULL;
+ PKIX_List *reversedCertChain = NULL;
+ PKIX_List *buildCheckedCritExtOIDsList = NULL;
+ PKIX_ProcessingParams *procParams = NULL;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_PL_PublicKey *trustedPubKey = NULL;
+ PKIX_PL_CertNameConstraints *trustedNC = NULL;
+ PKIX_CertChainChecker *sigChecker = NULL;
+ PKIX_CertChainChecker *policyChecker = NULL;
+ PKIX_CertChainChecker *userChecker = NULL;
+ PKIX_CertChainChecker *nameConstraintsChecker = NULL;
+ PKIX_CertChainChecker *checker = NULL;
+ PKIX_CertSelector *certSelector = NULL;
+ PKIX_List *userCheckerExtOIDs = NULL;
+ PKIX_PL_OID *oid = NULL;
+ PKIX_Boolean supportForwardChecking = PKIX_FALSE;
+ PKIX_Boolean policyQualifiersRejected = PKIX_FALSE;
+ PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE;
+ PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE;
+ PKIX_Boolean initialExplicitPolicy = PKIX_FALSE;
+ PKIX_UInt32 numChainCerts;
+ PKIX_UInt32 numCertCheckers;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(BUILD, "pkix_Build_ValidationCheckers");
+ PKIX_NULLCHECK_THREE(state, certChain, anchor);
+
+ PKIX_CHECK(PKIX_List_Create(&checkers, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_ReverseList
+ (certChain, &reversedCertChain, plContext),
+ PKIX_LISTREVERSELISTFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (reversedCertChain, &numChainCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ procParams = state->buildConstants.procParams;
+
+ /* Do need to add a number of checker to revalidate
+ * a built chain. KU, EKU, CertType and Validity Date
+ * get checked by certificate selector during chain
+ * construction, but needed to be checked for chain from
+ * the cache.*/
+ if (chainRevalidationStage) {
+ PKIX_CHECK(pkix_ExpirationChecker_Initialize
+ (state->buildConstants.testDate, &checker, plContext),
+ PKIX_EXPIRATIONCHECKERINITIALIZEFAILED);
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)checker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(checker);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
+ (procParams, &certSelector, plContext),
+ PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
+
+ PKIX_CHECK(pkix_TargetCertChecker_Initialize
+ (certSelector, numChainCerts, &checker, plContext),
+ PKIX_EXPIRATIONCHECKERINITIALIZEFAILED);
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)checker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(checker);
+ }
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetInitialPolicies
+ (procParams, &initialPolicies, plContext),
+ PKIX_PROCESSINGPARAMSGETINITIALPOLICIESFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetPolicyQualifiersRejected
+ (procParams, &policyQualifiersRejected, plContext),
+ PKIX_PROCESSINGPARAMSGETPOLICYQUALIFIERSREJECTEDFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_IsPolicyMappingInhibited
+ (procParams, &initialPolicyMappingInhibit, plContext),
+ PKIX_PROCESSINGPARAMSISPOLICYMAPPINGINHIBITEDFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_IsAnyPolicyInhibited
+ (procParams, &initialAnyPolicyInhibit, plContext),
+ PKIX_PROCESSINGPARAMSISANYPOLICYINHIBITEDFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_IsExplicitPolicyRequired
+ (procParams, &initialExplicitPolicy, plContext),
+ PKIX_PROCESSINGPARAMSISEXPLICITPOLICYREQUIREDFAILED);
+
+ PKIX_CHECK(pkix_PolicyChecker_Initialize
+ (initialPolicies,
+ policyQualifiersRejected,
+ initialPolicyMappingInhibit,
+ initialExplicitPolicy,
+ initialAnyPolicyInhibit,
+ numChainCerts,
+ &policyChecker,
+ plContext),
+ PKIX_POLICYCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)policyChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ /*
+ * Create an OID list that contains critical extensions processed
+ * by BuildChain. These are specified in a static const array.
+ */
+ PKIX_CHECK(PKIX_List_Create(&buildCheckedCritExtOIDsList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; buildCheckedCritExtOIDs[i] != PKIX_UNKNOWN_OID; i++) {
+ PKIX_CHECK(PKIX_PL_OID_Create
+ (buildCheckedCritExtOIDs[i], &oid, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (buildCheckedCritExtOIDsList,
+ (PKIX_PL_Object *) oid,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(oid);
+ }
+
+ if (state->buildConstants.userCheckers != NULL) {
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (state->buildConstants.userCheckers,
+ &numCertCheckers,
+ plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (i = 0; i < numCertCheckers; i++) {
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (state->buildConstants.userCheckers,
+ i,
+ (PKIX_PL_Object **) &userChecker,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK
+ (PKIX_CertChainChecker_IsForwardCheckingSupported
+ (userChecker, &supportForwardChecking, plContext),
+ PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
+
+ /*
+ * If this userChecker supports forwardChecking then it
+ * should have been checked during build chain. Skip
+ * checking but need to add checker's extension OIDs
+ * to buildCheckedCritExtOIDsList.
+ */
+ if (supportForwardChecking == PKIX_TRUE) {
+
+ PKIX_CHECK
+ (PKIX_CertChainChecker_GetSupportedExtensions
+ (userChecker, &userCheckerExtOIDs, plContext),
+ PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
+
+ if (userCheckerExtOIDs != NULL) {
+ PKIX_CHECK(pkix_List_AppendList
+ (buildCheckedCritExtOIDsList,
+ userCheckerExtOIDs,
+ plContext),
+ PKIX_LISTAPPENDLISTFAILED);
+ }
+
+ } else {
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers,
+ (PKIX_PL_Object *)userChecker,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+
+ PKIX_DECREF(userCheckerExtOIDs);
+ PKIX_DECREF(userChecker);
+ }
+ }
+
+ /* Enabling post chain building signature check on the certs. */
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (anchor, &trustedCert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (trustedCert, &trustedPubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+
+ PKIX_CHECK(pkix_SignatureChecker_Initialize
+ (trustedPubKey,
+ numChainCerts,
+ &sigChecker,
+ plContext),
+ PKIX_SIGNATURECHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers,
+ (PKIX_PL_Object *)sigChecker,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ /* Enabling post chain building name constraints check on the certs. */
+ PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints
+ (anchor, &trustedNC, plContext),
+ PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED);
+
+ PKIX_CHECK(pkix_NameConstraintsChecker_Initialize
+ (trustedNC, numChainCerts, &nameConstraintsChecker,
+ plContext),
+ PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers,
+ (PKIX_PL_Object *)nameConstraintsChecker,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+
+ PKIX_DECREF(state->reversedCertChain);
+ PKIX_INCREF(reversedCertChain);
+ state->reversedCertChain = reversedCertChain;
+ PKIX_DECREF(state->checkedCritExtOIDs);
+ PKIX_INCREF(buildCheckedCritExtOIDsList);
+ state->checkedCritExtOIDs = buildCheckedCritExtOIDsList;
+ PKIX_DECREF(state->checkerChain);
+ state->checkerChain = checkers;
+ checkers = NULL;
+ state->certCheckedIndex = 0;
+ state->checkerIndex = 0;
+ state->revChecking = PKIX_FALSE;
+
+
+cleanup:
+
+ PKIX_DECREF(oid);
+ PKIX_DECREF(reversedCertChain);
+ PKIX_DECREF(buildCheckedCritExtOIDsList);
+ PKIX_DECREF(checker);
+ PKIX_DECREF(checkers);
+ PKIX_DECREF(initialPolicies);
+ PKIX_DECREF(trustedCert);
+ PKIX_DECREF(trustedPubKey);
+ PKIX_DECREF(certSelector);
+ PKIX_DECREF(sigChecker);
+ PKIX_DECREF(trustedNC);
+ PKIX_DECREF(nameConstraintsChecker);
+ PKIX_DECREF(policyChecker);
+ PKIX_DECREF(userChecker);
+ PKIX_DECREF(userCheckerExtOIDs);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_ValidateEntireChain
+ * DESCRIPTION:
+ *
+ * Checks whether the current List of Certs successfully validates using the
+ * TrustAnchor pointed to by "anchor" and other parameters contained, as was
+ * the Cert List, in "state".
+ *
+ * If a checker using non-blocking I/O returns with a non-NULL non-blocking I/O
+ * context (NBIOContext), an indication that I/O is in progress and the
+ * checking has not been completed, this function stores that context at
+ * "pNBIOContext". Otherwise, it stores NULL at "pNBIOContext".
+ *
+ * If not awaiting I/O and if successful, a ValidateResult is created
+ * containing the Public Key of the target certificate (including DSA parameter
+ * inheritance, if any) and the PolicyNode representing the policy tree output
+ * by the validation algorithm. If not successful, an Error pointer is
+ * returned.
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "anchor"
+ * Address of TrustAnchor to be used. Must be non-NULL.
+ * "pNBIOContext"
+ * Address at which the NBIOContext is stored indicating whether the
+ * validation is complete. Must be non-NULL.
+ * "pValResult"
+ * Address at which the ValidateResult is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_ValidateEntireChain(
+ PKIX_ForwardBuilderState *state,
+ PKIX_TrustAnchor *anchor,
+ void **pNBIOContext,
+ PKIX_ValidateResult **pValResult,
+ PKIX_VerifyNode *verifyNode,
+ void *plContext)
+{
+ PKIX_UInt32 numChainCerts = 0;
+ PKIX_PL_PublicKey *subjPubKey = NULL;
+ PKIX_PolicyNode *policyTree = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_ValidateEntireChain");
+ PKIX_NULLCHECK_FOUR(state, anchor, pNBIOContext, pValResult);
+
+ *pNBIOContext = NULL; /* prepare for case of error exit */
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (state->reversedCertChain, &numChainCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ pkixErrorResult =
+ pkix_CheckChain(state->reversedCertChain, numChainCerts, anchor,
+ state->checkerChain,
+ state->buildConstants.revChecker,
+ state->checkedCritExtOIDs,
+ state->buildConstants.procParams,
+ &state->certCheckedIndex, &state->checkerIndex,
+ &state->revChecking, &state->reasonCode,
+ &nbioContext, &subjPubKey, &policyTree, NULL,
+ plContext);
+
+ if (nbioContext != NULL) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ ERROR_CHECK(PKIX_CHECKCHAINFAILED);
+
+ /* XXX Remove this assertion after 2014-12-31. See bug 946984. */
+ PORT_Assert(state->reasonCode == 0);
+
+ PKIX_CHECK(pkix_ValidateResult_Create
+ (subjPubKey, anchor, policyTree, &valResult, plContext),
+ PKIX_VALIDATERESULTCREATEFAILED);
+
+ *pValResult = valResult;
+ valResult = NULL;
+
+cleanup:
+ PKIX_DECREF(subjPubKey);
+ PKIX_DECREF(policyTree);
+ PKIX_DECREF(valResult);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_SortCandidateCerts
+ * DESCRIPTION:
+ *
+ * This function sorts a List of candidate Certs pointed to by "candidates"
+ * using an algorithm that places Certs most likely to produce a successful
+ * chain at the front of the list, storing the resulting sorted List at
+ * "pSortedCandidates".
+ *
+ * At present the only sort criterion is that trusted Certs go ahead of
+ * untrusted Certs.
+ *
+ * PARAMETERS:
+ * "candidates"
+ * Address of List of Candidate Certs to be sorted. Must be non-NULL.
+ * "pSortedCandidates"
+ * Address at which sorted List is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_SortCandidateCerts(
+ PKIX_List *candidates,
+ PKIX_List **pSortedCandidates,
+ void *plContext)
+{
+ PKIX_List *sortedList = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_SortCandidateCerts");
+ PKIX_NULLCHECK_TWO(candidates, pSortedCandidates);
+
+ /*
+ * Both bubble and quick sort algorithms are available.
+ * For a list of fewer than around 100 items, the bubble sort is more
+ * efficient. (This number was determined by experimenting with both
+ * algorithms on a Java List.)
+ * If the candidate list is very small, using the sort can drag down
+ * the performance a little bit.
+ */
+
+ PKIX_CHECK(pkix_List_BubbleSort
+ (candidates,
+ pkix_Build_SortCertComparator,
+ &sortedList,
+ plContext),
+ PKIX_LISTBUBBLESORTFAILED);
+
+ *pSortedCandidates = sortedList;
+
+cleanup:
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_BuildSelectorAndParams
+ * DESCRIPTION:
+ *
+ * This function creates a CertSelector, initialized with an appropriate
+ * ComCertSelParams, using the variables provided in the ForwardBuilderState
+ * pointed to by "state". The CertSelector created is stored in the certsel
+ * element of "state".
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_BuildSelectorAndParams(
+ PKIX_ForwardBuilderState *state,
+ void *plContext)
+{
+ PKIX_ComCertSelParams *certSelParams = NULL;
+ PKIX_CertSelector *certSel = NULL;
+ PKIX_PL_X500Name *currentIssuer = NULL;
+ PKIX_PL_ByteArray *authKeyId = NULL;
+ PKIX_PL_Date *testDate = NULL;
+ PKIX_CertSelector *callerCertSelector = NULL;
+ PKIX_ComCertSelParams *callerComCertSelParams = NULL;
+ PKIX_UInt32 reqKu = 0;
+ PKIX_List *reqEkuOids = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_BuildSelectorAndParams");
+ PKIX_NULLCHECK_THREE(state, state->prevCert, state->traversedSubjNames);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetIssuer
+ (state->prevCert, &currentIssuer, plContext),
+ PKIX_CERTGETISSUERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier
+ (state->prevCert, &authKeyId, plContext),
+ PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_Create(&certSelParams, plContext),
+ PKIX_COMCERTSELPARAMSCREATEFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_SetSubject
+ (certSelParams, currentIssuer, plContext),
+ PKIX_COMCERTSELPARAMSSETSUBJECTFAILED);
+
+ if (authKeyId != NULL) {
+ PKIX_CHECK(PKIX_ComCertSelParams_SetSubjKeyIdentifier
+ (certSelParams, authKeyId, plContext),
+ PKIX_COMCERTSELPARAMSSETSUBJKEYIDENTIFIERFAILED);
+ }
+
+ PKIX_INCREF(state->buildConstants.testDate);
+ testDate = state->buildConstants.testDate;
+
+ PKIX_CHECK(PKIX_ComCertSelParams_SetCertificateValid
+ (certSelParams, testDate, plContext),
+ PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_SetBasicConstraints
+ (certSelParams, state->traversedCACerts, plContext),
+ PKIX_COMCERTSELPARAMSSETBASICCONSTRAINTSFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_SetPathToNames
+ (certSelParams, state->traversedSubjNames, plContext),
+ PKIX_COMCERTSELPARAMSSETPATHTONAMESFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
+ (state->buildConstants.procParams,
+ &callerCertSelector, plContext),
+ PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
+
+ if (callerCertSelector != NULL) {
+
+ /* Get initial EKU OIDs from ComCertSelParams, if set */
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (callerCertSelector, &callerComCertSelParams, plContext),
+ PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
+
+ if (callerComCertSelParams != NULL) {
+ PKIX_CHECK(PKIX_ComCertSelParams_GetExtendedKeyUsage
+ (callerComCertSelParams, &reqEkuOids, plContext),
+ PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetKeyUsage
+ (callerComCertSelParams, &reqKu, plContext),
+ PKIX_COMCERTSELPARAMSGETEXTENDEDKEYUSAGEFAILED);
+ }
+ }
+
+ PKIX_CHECK(
+ PKIX_ComCertSelParams_SetKeyUsage(certSelParams, reqKu,
+ plContext),
+ PKIX_COMCERTSELPARAMSSETKEYUSAGEFAILED);
+
+ PKIX_CHECK(
+ PKIX_ComCertSelParams_SetExtendedKeyUsage(certSelParams,
+ reqEkuOids,
+ plContext),
+ PKIX_COMCERTSELPARAMSSETEXTKEYUSAGEFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_Create
+ (NULL, NULL, &state->certSel, plContext),
+ PKIX_CERTSELECTORCREATEFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
+ (state->certSel, certSelParams, plContext),
+ PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_List_Create(&state->candidateCerts, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ state->certStoreIndex = 0;
+
+cleanup:
+ PKIX_DECREF(certSelParams);
+ PKIX_DECREF(certSel);
+ PKIX_DECREF(currentIssuer);
+ PKIX_DECREF(authKeyId);
+ PKIX_DECREF(testDate);
+ PKIX_DECREF(reqEkuOids);
+ PKIX_DECREF(callerComCertSelParams);
+ PKIX_DECREF(callerCertSelector);
+
+ PKIX_RETURN(BUILD);
+}
+
+/* Match trust anchor to select params in order to find next cert. */
+static PKIX_Error*
+pkix_Build_SelectCertsFromTrustAnchors(
+ PKIX_List *trustAnchorsList,
+ PKIX_ComCertSelParams *certSelParams,
+ PKIX_List **pMatchList,
+ void *plContext)
+{
+ unsigned int anchorIndex = 0;
+ PKIX_TrustAnchor *anchor = NULL;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_List *matchList = NULL;
+ PKIX_CertSelector *certSel = NULL;
+ PKIX_CertSelector_MatchCallback selectorMatchCB = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_SelectCertsFromTrustAnchors");
+
+ PKIX_CHECK(PKIX_CertSelector_Create
+ (NULL, NULL, &certSel, plContext),
+ PKIX_CERTSELECTORCREATEFAILED);
+ PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
+ (certSel, certSelParams, plContext),
+ PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (certSel, &selectorMatchCB, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ for (anchorIndex = 0;anchorIndex < trustAnchorsList->length; anchorIndex++) {
+ PKIX_CHECK(
+ PKIX_List_GetItem(trustAnchorsList,
+ anchorIndex,
+ (PKIX_PL_Object **)&anchor,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (anchor, &trustedCert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+ pkixErrorResult =
+ (*selectorMatchCB)(certSel, trustedCert, plContext);
+ if (!pkixErrorResult) {
+ if (!matchList) {
+ PKIX_CHECK(PKIX_List_Create(&matchList,
+ plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ PKIX_CHECK(
+ PKIX_List_AppendItem(matchList,
+ (PKIX_PL_Object*)trustedCert,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ } else {
+ PKIX_DECREF(pkixErrorResult);
+ }
+ PKIX_DECREF(trustedCert);
+ PKIX_DECREF(anchor);
+ }
+
+ *pMatchList = matchList;
+ matchList = NULL;
+
+cleanup:
+ PKIX_DECREF(matchList);
+ PKIX_DECREF(trustedCert);
+ PKIX_DECREF(anchor);
+ PKIX_DECREF(certSel);
+
+ PKIX_RETURN(BUILD);
+}
+
+
+static PKIX_Error*
+pkix_Build_RemoveDupUntrustedCerts(
+ PKIX_List *trustedCertList,
+ PKIX_List *certsFound,
+ void *plContext)
+{
+ PKIX_UInt32 trustIndex;
+ PKIX_PL_Cert *trustCert = NULL, *cert = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_RemoveDupUntrustedCerts");
+ if (trustedCertList == NULL || certsFound == NULL) {
+ goto cleanup;
+ }
+ for (trustIndex = 0;trustIndex < trustedCertList->length;
+ trustIndex++) {
+ PKIX_UInt32 certIndex = 0;
+ PKIX_CHECK(
+ PKIX_List_GetItem(trustedCertList,
+ trustIndex,
+ (PKIX_PL_Object **)&trustCert,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ while (certIndex < certsFound->length) {
+ PKIX_Boolean result = PKIX_FALSE;
+ PKIX_DECREF(cert);
+ PKIX_CHECK(
+ PKIX_List_GetItem(certsFound, certIndex,
+ (PKIX_PL_Object **)&cert,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ PKIX_CHECK(
+ PKIX_PL_Object_Equals((PKIX_PL_Object *)trustCert,
+ (PKIX_PL_Object *)cert,
+ &result,
+ plContext),
+ PKIX_OBJECTEQUALSFAILED);
+ if (!result) {
+ certIndex += 1;
+ continue;
+ }
+ PKIX_CHECK(
+ PKIX_List_DeleteItem(certsFound, certIndex,
+ plContext),
+ PKIX_LISTDELETEITEMFAILED);
+ }
+ PKIX_DECREF(trustCert);
+ }
+cleanup:
+ PKIX_DECREF(cert);
+ PKIX_DECREF(trustCert);
+
+ PKIX_RETURN(BUILD);
+}
+
+
+/*
+ * FUNCTION: pkix_Build_GatherCerts
+ * DESCRIPTION:
+ *
+ * This function traverses the CertStores in the List of CertStores contained
+ * in "state", using the certSelector and other parameters contained in
+ * "state", to obtain a List of all available Certs that satisfy the criteria.
+ * If a CertStore has a cache, "certSelParams" is used both to query the cache
+ * and, if an actual CertStore search occurred, to update the cache. (Behavior
+ * is undefined if "certSelParams" is different from the parameters that were
+ * used to initialize the certSelector in "state".)
+ *
+ * If a CertStore using non-blocking I/O returns with an indication that I/O is
+ * in progress and the checking has not been completed, this function stores
+ * platform-dependent information at "pNBIOContext". Otherwise it stores NULL
+ * at "pNBIOContext", and state is updated with the results of the search.
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "certSelParams"
+ * Address of ComCertSelParams which were used in creating the current
+ * CertSelector, and to be used in querying and updating any caches that
+ * may be associated with with the CertStores.
+ * "pNBIOContext"
+ * Address at which platform-dependent information is returned if request
+ * is suspended for non-blocking I/O. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+/* return NULL if wouldblock, empty list if none found, else list of found */
+static PKIX_Error *
+pkix_Build_GatherCerts(
+ PKIX_ForwardBuilderState *state,
+ PKIX_ComCertSelParams *certSelParams,
+ void **pNBIOContext,
+ void *plContext)
+{
+ PKIX_Boolean certStoreIsCached = PKIX_FALSE;
+ PKIX_Boolean certStoreIsLocal = PKIX_FALSE;
+ PKIX_Boolean foundInCache = PKIX_FALSE;
+ PKIX_CertStore *certStore = NULL;
+ PKIX_CertStore_CertCallback getCerts = NULL;
+ PKIX_List *certsFound = NULL;
+ PKIX_List *trustedCertList = NULL;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_GatherCerts");
+ PKIX_NULLCHECK_THREE(state, certSelParams, pNBIOContext);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ PKIX_DECREF(state->candidateCerts);
+
+ while (state->certStoreIndex < state->buildConstants.numCertStores) {
+
+ /* Get the current CertStore */
+ PKIX_CHECK(PKIX_List_GetItem
+ (state->buildConstants.certStores,
+ state->certStoreIndex,
+ (PKIX_PL_Object **)&certStore,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_CertStore_GetLocalFlag
+ (certStore, &certStoreIsLocal, plContext),
+ PKIX_CERTSTOREGETLOCALFLAGFAILED);
+
+ if (state->useOnlyLocal == certStoreIsLocal) {
+ /* If GATHERPENDING, we've already checked the cache */
+ if (state->status == BUILD_GATHERPENDING) {
+ certStoreIsCached = PKIX_FALSE;
+ foundInCache = PKIX_FALSE;
+ } else {
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (certStore, &certStoreIsCached, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ if (certStoreIsCached) {
+ /*
+ * Look for Certs in the cache, using the SubjectName as
+ * the key. Then the ComCertSelParams are used to filter
+ * for qualified certs. If none are found, then the
+ * certStores are queried. When we eventually add items
+ * to the cache, we will only add items that passed the
+ * ComCertSelParams filter, rather than all Certs which
+ * matched the SubjectName.
+ */
+
+ PKIX_CHECK(pkix_CacheCert_Lookup
+ (certStore,
+ certSelParams,
+ state->buildConstants.testDate,
+ &foundInCache,
+ &certsFound,
+ plContext),
+ PKIX_CACHECERTCHAINLOOKUPFAILED);
+
+ }
+ }
+
+ /*
+ * XXX need to verify if Cert is trusted, hence may not
+ * be worth it to have the Cert Cached or
+ * If it is trusted, don't cache, but once there is cached
+ * certs, we won't get certs from database any more.
+ * can use flag to force not getting certs from cache
+ */
+ if (!foundInCache) {
+
+ if (nbioContext == NULL) {
+ PKIX_CHECK(PKIX_CertStore_GetCertCallback
+ (certStore, &getCerts, plContext),
+ PKIX_CERTSTOREGETCERTCALLBACKFAILED);
+
+ PKIX_CHECK(getCerts
+ (certStore,
+ state->certSel,
+ state->verifyNode,
+ &nbioContext,
+ &certsFound,
+ plContext),
+ PKIX_GETCERTSFAILED);
+ } else {
+ PKIX_CHECK(PKIX_CertStore_CertContinue
+ (certStore,
+ state->certSel,
+ state->verifyNode,
+ &nbioContext,
+ &certsFound,
+ plContext),
+ PKIX_CERTSTORECERTCONTINUEFAILED);
+ }
+
+ if (certStoreIsCached && certsFound) {
+
+ PKIX_CHECK(pkix_CacheCert_Add
+ (certStore,
+ certSelParams,
+ certsFound,
+ plContext),
+ PKIX_CACHECERTADDFAILED);
+ }
+ }
+
+ /*
+ * getCerts returns an empty list for "NONE FOUND",
+ * a NULL list for "would block"
+ */
+ if (certsFound == NULL) {
+ state->status = BUILD_GATHERPENDING;
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+ }
+
+ /* Are there any more certStores to query? */
+ PKIX_DECREF(certStore);
+ ++(state->certStoreIndex);
+ }
+
+ if (certsFound && certsFound->length > 1) {
+ PKIX_List *sorted = NULL;
+
+ /* sort Certs to try to optimize search */
+ PKIX_CHECK(pkix_Build_SortCandidateCerts
+ (certsFound, &sorted, plContext),
+ PKIX_BUILDSORTCANDIDATECERTSFAILED);
+ PKIX_DECREF(certsFound);
+ certsFound = sorted;
+ }
+
+ PKIX_CHECK(
+ pkix_Build_SelectCertsFromTrustAnchors(
+ state->buildConstants.anchors,
+ certSelParams, &trustedCertList,
+ plContext),
+ PKIX_FAILTOSELECTCERTSFROMANCHORS);
+ PKIX_CHECK(
+ pkix_Build_RemoveDupUntrustedCerts(trustedCertList,
+ certsFound,
+ plContext),
+ PKIX_REMOVEDUPUNTRUSTEDCERTSFAILED);
+
+ PKIX_CHECK(
+ pkix_List_MergeLists(trustedCertList,
+ certsFound,
+ &state->candidateCerts,
+ plContext),
+ PKIX_LISTMERGEFAILED);
+
+ /* No, return the list we have gathered */
+ PKIX_CHECK(PKIX_List_GetLength
+ (state->candidateCerts, &state->numCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ state->certIndex = 0;
+
+cleanup:
+ PKIX_DECREF(trustedCertList);
+ PKIX_DECREF(certStore);
+ PKIX_DECREF(certsFound);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_UpdateDate
+ * DESCRIPTION:
+ *
+ * This function updates the validityDate contained in "state", for the current
+ * CertChain contained in "state", to include the validityDate of the
+ * candidateCert contained in "state". The validityDate of a chain is the
+ * earliest of all the notAfter dates contained in the respective Certificates.
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_UpdateDate(
+ PKIX_ForwardBuilderState *state,
+ void *plContext)
+{
+ PKIX_Boolean canBeCached = PKIX_FALSE;
+ PKIX_Int32 comparison = 0;
+ PKIX_PL_Date *notAfter = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_UpdateDate");
+ PKIX_NULLCHECK_ONE(state);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetCacheFlag
+ (state->candidateCert, &canBeCached, plContext),
+ PKIX_CERTGETCACHEFLAGFAILED);
+
+ state->canBeCached = state->canBeCached && canBeCached;
+ if (state->canBeCached == PKIX_TRUE) {
+
+ /*
+ * So far, all certs can be cached. Update cert
+ * chain validity time, which is the earliest of
+ * all certs' notAfter times.
+ */
+ PKIX_CHECK(PKIX_PL_Cert_GetValidityNotAfter
+ (state->candidateCert, &notAfter, plContext),
+ PKIX_CERTGETVALIDITYNOTAFTERFAILED);
+
+ if (state->validityDate == NULL) {
+ state->validityDate = notAfter;
+ notAfter = NULL;
+ } else {
+ PKIX_CHECK(PKIX_PL_Object_Compare
+ ((PKIX_PL_Object *)state->validityDate,
+ (PKIX_PL_Object *)notAfter,
+ &comparison,
+ plContext),
+ PKIX_OBJECTCOMPARATORFAILED);
+ if (comparison > 0) {
+ PKIX_DECREF(state->validityDate);
+ state->validityDate = notAfter;
+ notAfter = NULL;
+ }
+ }
+ }
+
+cleanup:
+
+ PKIX_DECREF(notAfter);
+
+ PKIX_RETURN(BUILD);
+}
+
+/* Prepare 'state' for the AIA round. */
+static void
+pkix_PrepareForwardBuilderStateForAIA(
+ PKIX_ForwardBuilderState *state)
+{
+ PORT_Assert(state->useOnlyLocal == PKIX_TRUE);
+ state->useOnlyLocal = PKIX_FALSE;
+ state->certStoreIndex = 0;
+ state->numFanout = state->buildConstants.maxFanout;
+ state->status = BUILD_TRYAIA;
+}
+
+extern SECStatus
+isIssuerCertAllowedAtCertIssuanceTime(CERTCertificate *issuerCert,
+ CERTCertificate *referenceCert);
+
+/*
+ * FUNCTION: pkix_BuildForwardDepthFirstSearch
+ * DESCRIPTION:
+ *
+ * This function performs a depth first search in the "forward" direction (from
+ * the target Cert to the trust anchor). A non-NULL targetCert must be stored
+ * in the ForwardBuilderState before this function is called. It is not written
+ * recursively since execution may be suspended in in any of several places
+ * pending completion of non-blocking I/O. This iterative structure makes it
+ * much easier to resume where it left off.
+ *
+ * Since the nature of the search is recursive, the recursion is handled by
+ * chaining states. That is, each new step involves creating a new
+ * ForwardBuilderState linked to its predecessor. If a step turns out to be
+ * fruitless, the state of the predecessor is restored and the next alternative
+ * is tried. When a search is successful, values needed from the last state
+ * (canBeCached and validityDate) are copied to the state provided by the
+ * caller, so that the caller can retrieve those values.
+ *
+ * There are three return arguments, the NBIOContext, the ValidateResult and
+ * the ForwardBuilderState. If NBIOContext is non-NULL, it means the search is
+ * suspended until the results of a non-blocking IO become available. The
+ * caller may wait for the completion using platform-dependent methods and then
+ * call this function again, allowing it to resume the search. If NBIOContext
+ * is NULL and the ValidateResult is non-NULL, it means the search has
+ * concluded successfully. If the NBIOContext is NULL but the ValidateResult is
+ * NULL, it means the search was unsuccessful.
+ *
+ * This function performs several steps at each node in the constructed chain:
+ *
+ * 1) It retrieves Certs from the registered CertStores that match the
+ * criteria established by the ForwardBuilderState pointed to by "state", such
+ * as a subject name matching the issuer name of the previous Cert. If there
+ * are no matching Certs, the function returns to the previous, or "parent",
+ * state and tries to continue the chain building with another of the Certs
+ * obtained from the CertStores as possible issuers for that parent Cert.
+ *
+ * 2) For each candidate Cert returned by the CertStores, this function checks
+ * whether the Cert is valid. If it is trusted, this function checks whether
+ * this Cert might serve as a TrustAnchor for a complete chain.
+ *
+ * 3) It determines whether this Cert, in conjunction with any of the
+ * TrustAnchors, might complete a chain. A complete chain, from this or the
+ * preceding step, is checked to see whether it is valid as a complete
+ * chain, including the checks that cannot be done in the forward direction.
+ *
+ * 4) If this Cert chains successfully, but is not a complete chain, that is,
+ * we have not reached a trusted Cert, a new ForwardBuilderState is created
+ * with this Cert as the immediate predecessor, and we continue in step (1),
+ * attempting to get Certs from the CertStores with this Certs "issuer" as
+ * their subject.
+ *
+ * 5) If an entire chain validates successfully, then we are done. A
+ * ValidateResult is created containing the Public Key of the target
+ * certificate (including DSA parameter inheritance, if any) and the
+ * PolicyNode representing the policy tree output by the validation algorithm,
+ * and stored at pValResult, and the function exits returning NULL.
+ *
+ * 5) If the entire chain does not validate successfully, the algorithm
+ * discards the latest Cert and continues in step 2 with the next candidate
+ * Cert, backing up to a parent state when no more possibilities exist at a
+ * given level, and returning failure when we try to back up but discover we
+ * are at the top level.
+ *
+ * PARAMETERS:
+ * "pNBIOContext"
+ * Address at which platform-dependent information is returned if building
+ * is suspended for non-blocking I/O. Must be non-NULL.
+ * "pState"
+ * Address at which input ForwardBuilderState is found, and at which output
+ * ForwardBuilderState is stored. Must be non-NULL.
+ * "pValResult"
+ * Address at which the ValidateResult is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_BuildForwardDepthFirstSearch(
+ void **pNBIOContext,
+ PKIX_ForwardBuilderState *state,
+ PKIX_ValidateResult **pValResult,
+ void *plContext)
+{
+ PKIX_Boolean outOfOptions = PKIX_FALSE;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ PKIX_Boolean isSelfIssued = PKIX_FALSE;
+ PKIX_Boolean canBeCached = PKIX_FALSE;
+ PKIX_Boolean ioPending = PKIX_FALSE;
+ PKIX_PL_Date *validityDate = NULL;
+ PKIX_PL_Date *currTime = NULL;
+ PKIX_Int32 childTraversedCACerts = 0;
+ PKIX_UInt32 numSubjectNames = 0;
+ PKIX_UInt32 numChained = 0;
+ PKIX_Int32 cmpTimeResult = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 certsSoFar = 0;
+ PKIX_List *childTraversedSubjNames = NULL;
+ PKIX_List *subjectNames = NULL;
+ PKIX_List *unfilteredCerts = NULL;
+ PKIX_List *filteredCerts = NULL;
+ PKIX_PL_Object *subjectName = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_ForwardBuilderState *childState = NULL;
+ PKIX_ForwardBuilderState *parentState = NULL;
+ PKIX_PL_Object *revCheckerState = NULL;
+ PKIX_ComCertSelParams *certSelParams = NULL;
+ PKIX_TrustAnchor *trustAnchor = NULL;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_PL_Cert *targetCert = NULL;
+ PKIX_VerifyNode *verifyNode = NULL;
+ PKIX_Error *verifyError = NULL;
+ PKIX_Error *finalError = NULL;
+ void *nbio = NULL;
+ PKIX_UInt32 numIterations = 0;
+
+ PKIX_ENTER(BUILD, "pkix_BuildForwardDepthFirstSearch");
+ PKIX_NULLCHECK_THREE(pNBIOContext, state, pValResult);
+
+ nbio = *pNBIOContext;
+ *pNBIOContext = NULL;
+ PKIX_INCREF(state->validityDate);
+ validityDate = state->validityDate;
+ canBeCached = state->canBeCached;
+ PKIX_DECREF(*pValResult);
+ targetCert = state->buildConstants.targetCert;
+
+ /*
+ * We return if successful; if we fall off the end
+ * of this "while" clause our search has failed.
+ */
+ while (outOfOptions == PKIX_FALSE) {
+ /*
+ * The maximum number of iterations works around a bug that
+ * causes this while loop to never exit when AIA and cross
+ * certificates are involved. See bug xxxxx.
+ */
+ if (numIterations++ > 250)
+ PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS);
+
+ if (state->buildConstants.maxTime != 0) {
+ PKIX_DECREF(currTime);
+ PKIX_CHECK(PKIX_PL_Date_Create_UTCTime
+ (NULL, &currTime, plContext),
+ PKIX_DATECREATEUTCTIMEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_Compare
+ ((PKIX_PL_Object *)state->buildConstants.timeLimit,
+ (PKIX_PL_Object *)currTime,
+ &cmpTimeResult,
+ plContext),
+ PKIX_OBJECTCOMPARATORFAILED);
+
+ if (cmpTimeResult < 0) {
+ if (state->verifyNode != NULL) {
+ PKIX_ERROR_CREATE
+ (BUILD,
+ PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS,
+ verifyError);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
+ (state->verifyNode,
+ verifyError,
+ plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_DECREF(finalError);
+ finalError = verifyError;
+ verifyError = NULL;
+ }
+ /* Even if we logged error, we still have to abort */
+ PKIX_ERROR(PKIX_TIMECONSUMEDEXCEEDSRESOURCELIMITS);
+ }
+ }
+
+ if (state->status == BUILD_INITIAL) {
+
+ PKIX_CHECK(pkix_Build_BuildSelectorAndParams(state, plContext),
+ PKIX_BUILDBUILDSELECTORANDPARAMSFAILED);
+
+ /*
+ * If the caller supplied a partial certChain (hintCerts) try
+ * the next one from that List before we go to the certStores.
+ */
+ if (state->buildConstants.numHintCerts > 0) {
+ /* How many Certs does our trust chain have already? */
+ PKIX_CHECK(PKIX_List_GetLength
+ (state->trustChain, &certsSoFar, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ /* That includes the target Cert. Don't count it. */
+ certsSoFar--;
+
+ /* Are we still within range of the partial chain? */
+ if (certsSoFar >= state->buildConstants.numHintCerts) {
+ state->status = BUILD_TRYAIA;
+ } else {
+ /*
+ * If we already have n certs, we want the n+1th
+ * (i.e., index = n) from the list of hints.
+ */
+ PKIX_DECREF(state->candidateCert);
+ PKIX_CHECK(PKIX_List_GetItem
+ (state->buildConstants.hintCerts,
+ certsSoFar,
+ (PKIX_PL_Object **)&state->candidateCert,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (state->candidateCerts,
+ (PKIX_PL_Object *)state->candidateCert,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ state->numCerts = 1;
+ state->usingHintCerts = PKIX_TRUE;
+ state->status = BUILD_CERTVALIDATING;
+ }
+ } else {
+ state->status = BUILD_TRYAIA;
+ }
+
+ }
+
+ if (state->status == BUILD_TRYAIA) {
+ if (state->useOnlyLocal == PKIX_TRUE) {
+ state->status = BUILD_COLLECTINGCERTS;
+ } else {
+ state->status = BUILD_AIAPENDING;
+ }
+ }
+
+ if (state->status == BUILD_AIAPENDING &&
+ state->buildConstants.aiaMgr) {
+ pkixErrorResult = PKIX_PL_AIAMgr_GetAIACerts
+ (state->buildConstants.aiaMgr,
+ state->prevCert,
+ &nbio,
+ &unfilteredCerts,
+ plContext);
+
+ if (nbio != NULL) {
+ /* IO still pending, resume later */
+ *pNBIOContext = nbio;
+ goto cleanup;
+ }
+ state->numCerts = 0;
+ if (pkixErrorResult) {
+ pkixErrorClass = pkixErrorResult->errClass;
+ if (pkixErrorClass == PKIX_FATAL_ERROR) {
+ goto fatal;
+ }
+ PKIX_DECREF(finalError);
+ finalError = pkixErrorResult;
+ pkixErrorResult = NULL;
+ if (state->verifyNode != NULL) {
+ /* state->verifyNode is the object that contains a list
+ * of verifyNodes. verifyNodes contains cert chain
+ * build failures that occurred on this level of chain
+ * building. Here, creating new verify node
+ * to log the failure and adding it to the list. */
+ PKIX_CHECK_FATAL(pkix_VerifyNode_Create
+ (state->prevCert,
+ 0, NULL,
+ &verifyNode,
+ plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
+ (verifyNode, finalError, plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ }
+#ifdef PKIX_BUILDDEBUG
+ /* Turn this on to trace the List of Certs, before CertSelect */
+ {
+ PKIX_PL_String *unString;
+ char *unAscii;
+ PKIX_UInt32 length;
+ PKIX_TOSTRING
+ ((PKIX_PL_Object*)unfilteredCerts,
+ &unString,
+ plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (unString,
+ PKIX_ESCASCII,
+ (void **)&unAscii,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_DEBUG_ARG
+ ("unfilteredCerts = %s\n", unAscii);
+ PKIX_DECREF(unString);
+ PKIX_FREE(unAscii);
+ }
+#endif
+
+ /* Note: Certs winnowed here don't get into VerifyTree. */
+ if (unfilteredCerts) {
+ PKIX_CHECK(pkix_CertSelector_Select
+ (state->certSel,
+ unfilteredCerts,
+ &filteredCerts,
+ plContext),
+ PKIX_CERTSELECTORSELECTFAILED);
+
+ PKIX_DECREF(unfilteredCerts);
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (filteredCerts, &(state->numCerts), plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+#ifdef PKIX_BUILDDEBUG
+ /* Turn this on to trace the List of Certs, after CertSelect */
+ {
+ PKIX_PL_String *unString;
+ char *unAscii;
+ PKIX_UInt32 length;
+ PKIX_TOSTRING
+ ((PKIX_PL_Object*)filteredCerts,
+ &unString,
+ plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (unString,
+ PKIX_ESCASCII,
+ (void **)&unAscii,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_DEBUG_ARG("filteredCerts = %s\n", unAscii);
+ PKIX_DECREF(unString);
+ PKIX_FREE(unAscii);
+ }
+#endif
+
+ PKIX_DECREF(state->candidateCerts);
+ state->candidateCerts = filteredCerts;
+ state->certIndex = 0;
+ filteredCerts = NULL;
+ }
+
+ /* Are there any Certs to try? */
+ if (state->numCerts > 0) {
+ state->status = BUILD_CERTVALIDATING;
+ } else {
+ state->status = BUILD_COLLECTINGCERTS;
+ }
+ }
+
+ PKIX_DECREF(certSelParams);
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (state->certSel, &certSelParams, plContext),
+ PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
+
+ /* **** Querying the CertStores ***** */
+ if ((state->status == BUILD_COLLECTINGCERTS) ||
+ (state->status == BUILD_GATHERPENDING)) {
+
+#if PKIX_FORWARDBUILDERSTATEDEBUG
+ PKIX_CHECK(pkix_ForwardBuilderState_DumpState
+ (state, plContext),
+ PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED);
+#endif
+
+ PKIX_CHECK(pkix_Build_GatherCerts
+ (state, certSelParams, &nbio, plContext),
+ PKIX_BUILDGATHERCERTSFAILED);
+
+ if (nbio != NULL) {
+ /* IO still pending, resume later */
+ *pNBIOContext = nbio;
+ goto cleanup;
+ }
+
+ /* Are there any Certs to try? */
+ if (state->numCerts > 0) {
+ state->status = BUILD_CERTVALIDATING;
+ } else {
+ state->status = BUILD_ABANDONNODE;
+ }
+ }
+
+ /* ****Phase 2 - Chain building***** */
+
+#if PKIX_FORWARDBUILDERSTATEDEBUG
+ PKIX_CHECK(pkix_ForwardBuilderState_DumpState(state, plContext),
+ PKIX_FORWARDBUILDERSTATEDUMPSTATEFAILED);
+#endif
+
+ if (state->status == BUILD_CERTVALIDATING) {
+ PKIX_DECREF(state->candidateCert);
+ PKIX_CHECK(PKIX_List_GetItem
+ (state->candidateCerts,
+ state->certIndex,
+ (PKIX_PL_Object **)&(state->candidateCert),
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (isIssuerCertAllowedAtCertIssuanceTime(
+ state->candidateCert->nssCert, targetCert->nssCert)
+ != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTISBLACKLISTEDATISSUANCETIME);
+ }
+
+ if ((state->verifyNode) != NULL) {
+ PKIX_CHECK_FATAL(pkix_VerifyNode_Create
+ (state->candidateCert,
+ 0,
+ NULL,
+ &verifyNode,
+ plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ }
+
+ /* If failure, this function sets Error in verifyNode */
+ verifyError = pkix_Build_VerifyCertificate
+ (state,
+ state->buildConstants.userCheckers,
+ &trusted,
+ verifyNode,
+ plContext);
+
+ if (verifyError) {
+ pkixTempErrorReceived = PKIX_TRUE;
+ pkixErrorClass = verifyError->errClass;
+ if (pkixErrorClass == PKIX_FATAL_ERROR) {
+ pkixErrorResult = verifyError;
+ verifyError = NULL;
+ goto fatal;
+ }
+ }
+
+ if (PKIX_ERROR_RECEIVED) {
+ if (state->verifyNode != NULL) {
+ PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
+ (verifyNode, verifyError, plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ pkixTempErrorReceived = PKIX_FALSE;
+ PKIX_DECREF(finalError);
+ finalError = verifyError;
+ verifyError = NULL;
+ if (state->certLoopingDetected) {
+ PKIX_ERROR
+ (PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED);
+ }
+ state->status = BUILD_GETNEXTCERT;
+ } else {
+ state->status = BUILD_DATEPREP;
+ }
+ }
+
+ if (state->status == BUILD_DATEPREP) {
+ /* Keep track of whether this chain can be cached */
+ PKIX_CHECK(pkix_Build_UpdateDate(state, plContext),
+ PKIX_BUILDUPDATEDATEFAILED);
+
+ canBeCached = state->canBeCached;
+ PKIX_DECREF(validityDate);
+ PKIX_INCREF(state->validityDate);
+ validityDate = state->validityDate;
+ if (trusted == PKIX_TRUE) {
+ state->status = BUILD_CHECKTRUSTED;
+ } else {
+ state->status = BUILD_ADDTOCHAIN;
+ }
+ }
+
+ if (state->status == BUILD_CHECKTRUSTED) {
+
+ /*
+ * If this cert is trusted, try to validate the entire
+ * chain using this certificate as trust anchor.
+ */
+ PKIX_CHECK(PKIX_TrustAnchor_CreateWithCert
+ (state->candidateCert,
+ &trustAnchor,
+ plContext),
+ PKIX_TRUSTANCHORCREATEWITHCERTFAILED);
+
+ PKIX_CHECK(pkix_Build_ValidationCheckers
+ (state,
+ state->trustChain,
+ trustAnchor,
+ PKIX_FALSE, /* do not add eku checker
+ * since eku was already
+ * checked */
+ plContext),
+ PKIX_BUILDVALIDATIONCHECKERSFAILED);
+
+ state->status = BUILD_CHECKTRUSTED2;
+ }
+
+ if (state->status == BUILD_CHECKTRUSTED2) {
+ verifyError =
+ pkix_Build_ValidateEntireChain(state,
+ trustAnchor,
+ &nbio, &valResult,
+ verifyNode,
+ plContext);
+ if (nbio != NULL) {
+ /* IO still pending, resume later */
+ goto cleanup;
+ } else {
+ /* checking the error for fatal status */
+ if (verifyError) {
+ pkixTempErrorReceived = PKIX_TRUE;
+ pkixErrorClass = verifyError->errClass;
+ if (pkixErrorClass == PKIX_FATAL_ERROR) {
+ pkixErrorResult = verifyError;
+ verifyError = NULL;
+ goto fatal;
+ }
+ }
+ if (state->verifyNode != NULL) {
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ if (!PKIX_ERROR_RECEIVED) {
+ *pValResult = valResult;
+ valResult = NULL;
+ /* Change state so IsIOPending is FALSE */
+ state->status = BUILD_CHECKTRUSTED;
+ goto cleanup;
+ }
+ PKIX_DECREF(finalError);
+ finalError = verifyError;
+ verifyError = NULL;
+ /* Reset temp error that was set by
+ * PKIX_CHECK_ONLY_FATAL and continue */
+ pkixTempErrorReceived = PKIX_FALSE;
+ PKIX_DECREF(trustAnchor);
+ }
+
+ /*
+ * If chain doesn't validate with a trusted Cert,
+ * adding more Certs to it can't help.
+ */
+ if (state->certLoopingDetected) {
+ PKIX_DECREF(verifyError);
+ PKIX_ERROR_CREATE(BUILD,
+ PKIX_LOOPDISCOVEREDDUPCERTSNOTALLOWED,
+ verifyError);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_SetError(state->verifyNode,
+ verifyError,
+ plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_DECREF(verifyError);
+ }
+ state->status = BUILD_GETNEXTCERT;
+ }
+
+ /*
+ * This Cert was not trusted. Add it to our chain, and
+ * continue building. If we don't reach a trust anchor,
+ * we'll take it off later and continue without it.
+ */
+ if (state->status == BUILD_ADDTOCHAIN) {
+ PKIX_CHECK(PKIX_List_AppendItem
+ (state->trustChain,
+ (PKIX_PL_Object *)state->candidateCert,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ state->status = BUILD_EXTENDCHAIN;
+ }
+
+ if (state->status == BUILD_EXTENDCHAIN) {
+
+ /* Check whether we are allowed to extend the chain */
+ if ((state->buildConstants.maxDepth != 0) &&
+ (state->numDepth <= 1)) {
+
+ if (state->verifyNode != NULL) {
+ PKIX_ERROR_CREATE
+ (BUILD,
+ PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS,
+ verifyError);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_SetError
+ (verifyNode, verifyError, plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode, verifyNode, plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ PKIX_DECREF(finalError);
+ finalError = verifyError;
+ verifyError = NULL;
+ }
+ /* Even if error logged, still need to abort */
+ PKIX_ERROR(PKIX_DEPTHWOULDEXCEEDRESOURCELIMITS);
+ }
+
+ PKIX_CHECK(pkix_IsCertSelfIssued
+ (state->candidateCert, &isSelfIssued, plContext),
+ PKIX_ISCERTSELFISSUEDFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_Duplicate
+ ((PKIX_PL_Object *)state->traversedSubjNames,
+ (PKIX_PL_Object **)&childTraversedSubjNames,
+ plContext),
+ PKIX_OBJECTDUPLICATEFAILED);
+
+ if (isSelfIssued) {
+ childTraversedCACerts = state->traversedCACerts;
+ } else {
+ childTraversedCACerts = state->traversedCACerts + 1;
+
+ PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
+ (state->candidateCert,
+ &subjectNames,
+ plContext),
+ PKIX_CERTGETALLSUBJECTNAMESFAILED);
+
+ if (subjectNames) {
+ PKIX_CHECK(PKIX_List_GetLength
+ (subjectNames,
+ &numSubjectNames,
+ plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ } else {
+ numSubjectNames = 0;
+ }
+
+ for (i = 0; i < numSubjectNames; i++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (subjectNames,
+ i,
+ &subjectName,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ PKIX_NULLCHECK_ONE
+ (state->traversedSubjNames);
+ PKIX_CHECK(PKIX_List_AppendItem
+ (state->traversedSubjNames,
+ subjectName,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(subjectName);
+ }
+ PKIX_DECREF(subjectNames);
+ }
+
+ PKIX_CHECK(pkix_ForwardBuilderState_Create
+ (childTraversedCACerts,
+ state->buildConstants.maxFanout,
+ state->numDepth - 1,
+ canBeCached,
+ validityDate,
+ state->candidateCert,
+ childTraversedSubjNames,
+ state->trustChain,
+ state,
+ &childState,
+ plContext),
+ PKIX_FORWARDBUILDSTATECREATEFAILED);
+
+ PKIX_DECREF(childTraversedSubjNames);
+ PKIX_DECREF(certSelParams);
+ childState->verifyNode = verifyNode;
+ verifyNode = NULL;
+ PKIX_DECREF(state);
+ state = childState; /* state->status == BUILD_INITIAL */
+ childState = NULL;
+ continue; /* with while (!outOfOptions) */
+ }
+
+ if (state->status == BUILD_GETNEXTCERT) {
+ pkixTempErrorReceived = PKIX_FALSE;
+ PKIX_DECREF(state->candidateCert);
+
+ /*
+ * If we were using a Cert from the callier-supplied partial
+ * chain, delete it and go to the certStores.
+ */
+ if (state->usingHintCerts == PKIX_TRUE) {
+ PKIX_DECREF(state->candidateCerts);
+ PKIX_CHECK(PKIX_List_Create
+ (&state->candidateCerts, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ state->numCerts = 0;
+ state->usingHintCerts = PKIX_FALSE;
+ state->status = BUILD_TRYAIA;
+ continue;
+ } else if (++(state->certIndex) < (state->numCerts)) {
+ if ((state->buildConstants.maxFanout != 0) &&
+ (--(state->numFanout) == 0)) {
+
+ if (state->verifyNode != NULL) {
+ PKIX_ERROR_CREATE
+ (BUILD,
+ PKIX_FANOUTEXCEEDSRESOURCELIMITS,
+ verifyError);
+ PKIX_CHECK_FATAL
+ (pkix_VerifyNode_SetError
+ (state->verifyNode,
+ verifyError,
+ plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_DECREF(finalError);
+ finalError = verifyError;
+ verifyError = NULL;
+ }
+ /* Even if error logged, still need to abort */
+ PKIX_ERROR
+ (PKIX_FANOUTEXCEEDSRESOURCELIMITS);
+ }
+ state->status = BUILD_CERTVALIDATING;
+ continue;
+ }
+ }
+
+ /*
+ * Adding the current cert to the chain didn't help. If our search
+ * has been restricted to local certStores, try opening up the
+ * search and see whether that helps. Otherwise, back up to the
+ * parent cert, and see if there are any more to try.
+ */
+ if (state->useOnlyLocal == PKIX_TRUE) {
+ pkix_PrepareForwardBuilderStateForAIA(state);
+ } else do {
+ if (state->parentState == NULL) {
+ /* We are at the top level, and can't back up! */
+ outOfOptions = PKIX_TRUE;
+ } else {
+ /*
+ * Try the next cert, if any, for this parent.
+ * Otherwise keep backing up until we reach a
+ * parent with more certs to try.
+ */
+ PKIX_CHECK(PKIX_List_GetLength
+ (state->trustChain, &numChained, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ PKIX_CHECK(PKIX_List_DeleteItem
+ (state->trustChain, numChained - 1, plContext),
+ PKIX_LISTDELETEITEMFAILED);
+
+ /* local and aia fetching returned no good certs.
+ * Creating a verify node in the parent that tells
+ * us this. */
+ if (!state->verifyNode) {
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_Create(state->prevCert,
+ 0, NULL,
+ &state->verifyNode,
+ plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ }
+ /* Updating the log with the error. */
+ PKIX_DECREF(verifyError);
+ PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER,
+ verifyError);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_SetError(state->verifyNode,
+ verifyError,
+ plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ PKIX_DECREF(verifyError);
+
+ PKIX_INCREF(state->parentState);
+ parentState = state->parentState;
+ PKIX_DECREF(verifyNode);
+ verifyNode = state->verifyNode;
+ state->verifyNode = NULL;
+ PKIX_DECREF(state);
+ state = parentState;
+ parentState = NULL;
+ if (state->verifyNode != NULL && verifyNode) {
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ PKIX_DECREF(validityDate);
+ PKIX_INCREF(state->validityDate);
+ validityDate = state->validityDate;
+ canBeCached = state->canBeCached;
+
+ /* Are there any more Certs to try? */
+ if (++(state->certIndex) < (state->numCerts)) {
+ state->status = BUILD_CERTVALIDATING;
+ PKIX_DECREF(state->candidateCert);
+ break;
+ }
+ if (state->useOnlyLocal == PKIX_TRUE) {
+ /* Clean up and go for AIA round. */
+ pkix_PrepareForwardBuilderStateForAIA(state);
+ break;
+ }
+ }
+ PKIX_DECREF(state->candidateCert);
+ } while (outOfOptions == PKIX_FALSE);
+
+ } /* while (outOfOptions == PKIX_FALSE) */
+
+cleanup:
+
+ if (pkixErrorClass == PKIX_FATAL_ERROR) {
+ goto fatal;
+ }
+
+ /* verifyNode should be equal to NULL at this point. Assert it.
+ * Temporarelly use verifyError to store an error ref to which we
+ * have in pkixErrorResult. This is done to prevent error cloberring
+ * while using macros below. */
+ PORT_Assert(verifyError == NULL);
+ verifyError = pkixErrorResult;
+
+ /*
+ * We were called with an initialState that had no parent. If we are
+ * returning with an error or with a result, we must destroy any state
+ * that we created (any state with a parent).
+ */
+
+ PKIX_CHECK_FATAL(pkix_ForwardBuilderState_IsIOPending
+ (state, &ioPending, plContext),
+ PKIX_FORWARDBUILDERSTATEISIOPENDINGFAILED);
+
+ if (ioPending == PKIX_FALSE) {
+ while (state->parentState) {
+ PKIX_INCREF(state->parentState);
+ parentState = state->parentState;
+ PKIX_DECREF(verifyNode);
+ verifyNode = state->verifyNode;
+ state->verifyNode = NULL;
+ PKIX_DECREF(state);
+ state = parentState;
+ parentState = NULL;
+ if (state->verifyNode != NULL && verifyNode) {
+ PKIX_CHECK_FATAL(pkix_VerifyNode_AddToTree
+ (state->verifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ }
+ state->canBeCached = canBeCached;
+ PKIX_DECREF(state->validityDate);
+ state->validityDate = validityDate;
+ validityDate = NULL;
+ }
+ if (!*pValResult && !verifyError) {
+ if (!finalError) {
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_FindError(state->verifyNode,
+ &finalError,
+ plContext),
+ PKIX_VERIFYNODEFINDERRORFAILED);
+ }
+ if (finalError) {
+ pkixErrorResult = finalError;
+ pkixErrorCode = PKIX_BUILDFORWARDDEPTHFIRSTSEARCHFAILED;
+ finalError = NULL;
+ goto fatal;
+ }
+ pkixErrorCode = PKIX_SECERRORUNKNOWNISSUER;
+ pkixErrorReceived = PKIX_TRUE;
+ PKIX_ERROR_CREATE(BUILD, PKIX_SECERRORUNKNOWNISSUER,
+ verifyError);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_SetError(state->verifyNode, verifyError,
+ plContext),
+ PKIX_VERIFYNODESETERRORFAILED);
+ } else {
+ pkixErrorResult = verifyError;
+ verifyError = NULL;
+ }
+
+fatal:
+ if (state->parentState) {
+ /* parentState in "state" object should be NULL at this point.
+ * If itn't, that means that we got fatal error(we have jumped to
+ * "fatal" label) and we should destroy all state except the top one. */
+ while (state->parentState) {
+ PKIX_Error *error = NULL;
+ PKIX_ForwardBuilderState *prntState = state->parentState;
+ /* Dumb: need to increment parentState to avoid destruction
+ * of "build constants"(they get destroyed when parentState is
+ * set to NULL. */
+ PKIX_INCREF(prntState);
+ error = PKIX_PL_Object_DecRef((PKIX_PL_Object*)state, plContext);
+ if (error) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object*)error, plContext);
+ }
+ /* No need to decref the parent state. It was already done by
+ * pkix_ForwardBuilderState_Destroy function. */
+ state = prntState;
+ }
+ }
+ PKIX_DECREF(parentState);
+ PKIX_DECREF(childState);
+ PKIX_DECREF(valResult);
+ PKIX_DECREF(verifyError);
+ PKIX_DECREF(finalError);
+ PKIX_DECREF(verifyNode);
+ PKIX_DECREF(childTraversedSubjNames);
+ PKIX_DECREF(certSelParams);
+ PKIX_DECREF(subjectNames);
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(trustAnchor);
+ PKIX_DECREF(validityDate);
+ PKIX_DECREF(revCheckerState);
+ PKIX_DECREF(currTime);
+ PKIX_DECREF(filteredCerts);
+ PKIX_DECREF(unfilteredCerts);
+ PKIX_DECREF(trustedCert);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_CheckInCache
+ * DESCRIPTION:
+ *
+ * The function tries to locate a chain for a cert in the cert chain cache.
+ * If found, the chain goes through revocation chacking and returned back to
+ * caller. Chains that fail revocation check get removed from cache.
+ *
+ * PARAMETERS:
+ * "state"
+ * Address of ForwardBuilderState to be used. Must be non-NULL.
+ * "pBuildResult"
+ * Address at which the BuildResult is stored, after a successful build.
+ * Must be non-NULL.
+ * "pNBIOContext"
+ * Address at which the NBIOContext is stored indicating whether the
+ * validation is complete. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error*
+pkix_Build_CheckInCache(
+ PKIX_ForwardBuilderState *state,
+ PKIX_BuildResult **pBuildResult,
+ void **pNBIOContext,
+ void *plContext)
+{
+ PKIX_PL_Cert *targetCert = NULL;
+ PKIX_List *anchors = NULL;
+ PKIX_PL_Date *testDate = NULL;
+ PKIX_BuildResult *buildResult = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_Error *buildError = NULL;
+ PKIX_TrustAnchor *matchingAnchor = NULL;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_List *certList = NULL;
+ PKIX_Boolean cacheHit = PKIX_FALSE;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ PKIX_Boolean stillValid = PKIX_FALSE;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_CheckInCache");
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ targetCert = state->buildConstants.targetCert;
+ anchors = state->buildConstants.anchors;
+ testDate = state->buildConstants.testDate;
+
+ /* Check whether this cert verification has been cached. */
+ PKIX_CHECK(pkix_CacheCertChain_Lookup
+ (targetCert,
+ anchors,
+ testDate,
+ &cacheHit,
+ &buildResult,
+ plContext),
+ PKIX_CACHECERTCHAINLOOKUPFAILED);
+
+ if (!cacheHit) {
+ goto cleanup;
+ }
+
+ /*
+ * We found something in cache. Verify that the anchor
+ * cert is still trusted,
+ */
+ PKIX_CHECK(PKIX_BuildResult_GetValidateResult
+ (buildResult, &valResult, plContext),
+ PKIX_BUILDRESULTGETVALIDATERESULTFAILED);
+
+ PKIX_CHECK(PKIX_ValidateResult_GetTrustAnchor
+ (valResult, &matchingAnchor, plContext),
+ PKIX_VALIDATERESULTGETTRUSTANCHORFAILED);
+
+ PKIX_DECREF(valResult);
+
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (matchingAnchor, &trustedCert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+
+ if (anchors && state->buildConstants.numAnchors) {
+ /* Check if it is one of the trust anchors */
+ PKIX_CHECK(
+ pkix_List_Contains(anchors,
+ (PKIX_PL_Object *)matchingAnchor,
+ &trusted,
+ plContext),
+ PKIX_LISTCONTAINSFAILED);
+ }
+
+ if ((!trusted && !state->buildConstants.trustOnlyUserAnchors) ||
+ !state->buildConstants.numAnchors) {
+ /* If it is not one of the trust anchors and the trust anchors
+ * are supplemental, or if there are no trust anchors, then check
+ * if the cert is trusted directly.
+ */
+ PKIX_CHECK(
+ PKIX_PL_Cert_IsCertTrusted(trustedCert,
+ PKIX_PL_TrustAnchorMode_Ignore,
+ &trusted, plContext),
+ PKIX_CERTISCERTTRUSTEDFAILED);
+ }
+
+ if (!trusted) {
+ goto cleanup;
+ }
+ /*
+ * Since the key usage may vary for different
+ * applications, we need to verify the chain again.
+ * Reverification will be improved with a fix for 397805.
+ */
+ PKIX_CHECK(PKIX_BuildResult_GetCertChain
+ (buildResult, &certList, plContext),
+ PKIX_BUILDRESULTGETCERTCHAINFAILED);
+
+ PKIX_CHECK(pkix_Build_ValidationCheckers
+ (state,
+ certList,
+ matchingAnchor,
+ PKIX_TRUE, /* Chain revalidation stage. */
+ plContext),
+ PKIX_BUILDVALIDATIONCHECKERSFAILED);
+
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_Build_ValidateEntireChain(state, matchingAnchor,
+ &nbioContext, &valResult,
+ state->verifyNode, plContext),
+ PKIX_BUILDVALIDATEENTIRECHAINFAILED);
+
+ if (nbioContext != NULL) {
+ /* IO still pending, resume later */
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+ if (!PKIX_ERROR_RECEIVED) {
+ /* The result from cache is still valid. But we replace an old*/
+ *pBuildResult = buildResult;
+ buildResult = NULL;
+ stillValid = PKIX_TRUE;
+ }
+
+cleanup:
+
+ if (!nbioContext && cacheHit && !(trusted && stillValid)) {
+ /* The anchor of this chain is no longer trusted or
+ * chain cert(s) has been revoked.
+ * Invalidate this result in the cache */
+ buildError = pkixErrorResult;
+ PKIX_CHECK_FATAL(pkix_CacheCertChain_Remove
+ (targetCert,
+ anchors,
+ plContext),
+ PKIX_CACHECERTCHAINREMOVEFAILED);
+ pkixErrorResult = buildError;
+ buildError = NULL;
+ }
+
+fatal:
+ PKIX_DECREF(buildResult);
+ PKIX_DECREF(valResult);
+ PKIX_DECREF(buildError);
+ PKIX_DECREF(certList);
+ PKIX_DECREF(matchingAnchor);
+ PKIX_DECREF(trustedCert);
+
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_InitiateBuildChain
+ * DESCRIPTION:
+ *
+ * This function initiates the search for a BuildChain, using the parameters
+ * provided in "procParams" and, if continuing a search that was suspended
+ * for I/O, using the ForwardBuilderState pointed to by "pState".
+ *
+ * If a successful chain is built, this function stores the BuildResult at
+ * "pBuildResult". Alternatively, if an operation using non-blocking I/O
+ * is in progress and the operation has not been completed, this function
+ * stores the platform-dependent non-blocking I/O context (nbioContext) at
+ * "pNBIOContext", the FowardBuilderState at "pState", and NULL at
+ * "pBuildResult". Finally, if chain building was unsuccessful, this function
+ * stores NULL at both "pState" and at "pBuildResult".
+ *
+ * Note: This function is re-entered only for the case of non-blocking I/O
+ * in the "short-cut" attempt to build a chain using the target Certificate
+ * directly with one of the trustAnchors. For all other cases, resumption
+ * after non-blocking I/O is via pkix_Build_ResumeBuildChain.
+ *
+ * PARAMETERS:
+ * "procParams"
+ * Address of the ProcessingParams for the search. Must be non-NULL.
+ * "pNBIOContext"
+ * Address at which the NBIOContext is stored indicating whether the
+ * validation is complete. Must be non-NULL.
+ * "pState"
+ * Address at which the ForwardBuilderState is stored, if the chain
+ * building is suspended for waiting I/O; also, the address at which the
+ * ForwardBuilderState is provided for resumption of the chain building
+ * attempt. Must be non-NULL.
+ * "pBuildResult"
+ * Address at which the BuildResult is stored, after a successful build.
+ * Must be non-NULL.
+ * "pVerifyNode"
+ * Address at which a VerifyNode chain is returned, if non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_InitiateBuildChain(
+ PKIX_ProcessingParams *procParams,
+ void **pNBIOContext,
+ PKIX_ForwardBuilderState **pState,
+ PKIX_BuildResult **pBuildResult,
+ PKIX_VerifyNode **pVerifyNode,
+ void *plContext)
+{
+ PKIX_UInt32 numAnchors = 0;
+ PKIX_UInt32 numCertStores = 0;
+ PKIX_UInt32 numHintCerts = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_Boolean isDuplicate = PKIX_FALSE;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_CertSelector *targetConstraints = NULL;
+ PKIX_ComCertSelParams *targetParams = NULL;
+ PKIX_List *anchors = NULL;
+ PKIX_List *targetSubjNames = NULL;
+ PKIX_PL_Cert *targetCert = NULL;
+ PKIX_PL_Object *firstHintCert = NULL;
+ PKIX_RevocationChecker *revChecker = NULL;
+ PKIX_List *certStores = NULL;
+ PKIX_CertStore *certStore = NULL;
+ PKIX_List *userCheckers = NULL;
+ PKIX_List *hintCerts = NULL;
+ PKIX_PL_Date *testDate = NULL;
+ PKIX_PL_PublicKey *targetPubKey = NULL;
+ void *nbioContext = NULL;
+ BuildConstants buildConstants;
+
+ PKIX_List *tentativeChain = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_BuildResult *buildResult = NULL;
+ PKIX_List *certList = NULL;
+ PKIX_ForwardBuilderState *state = NULL;
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ PKIX_CertSelector_MatchCallback selectorCallback = NULL;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ PKIX_PL_AIAMgr *aiaMgr = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_InitiateBuildChain");
+ PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ state = *pState;
+ *pState = NULL; /* no net change in reference count */
+
+ if (state == NULL) {
+ PKIX_CHECK(PKIX_ProcessingParams_GetDate
+ (procParams, &testDate, plContext),
+ PKIX_PROCESSINGPARAMSGETDATEFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors
+ (procParams, &anchors, plContext),
+ PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(anchors, &numAnchors, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ /* retrieve stuff from targetCertConstraints */
+ PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
+ (procParams, &targetConstraints, plContext),
+ PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (targetConstraints, &targetParams, plContext),
+ PKIX_CERTSELECTORGETCOMMONCERTSELECTORPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetCertificate
+ (targetParams, &targetCert, plContext),
+ PKIX_COMCERTSELPARAMSGETCERTIFICATEFAILED);
+
+ PKIX_CHECK(
+ PKIX_ComCertSelParams_SetLeafCertFlag(targetParams,
+ PKIX_TRUE, plContext),
+ PKIX_COMCERTSELPARAMSSETLEAFCERTFLAGFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetHintCerts
+ (procParams, &hintCerts, plContext),
+ PKIX_PROCESSINGPARAMSGETHINTCERTSFAILED);
+
+ if (hintCerts != NULL) {
+ PKIX_CHECK(PKIX_List_GetLength
+ (hintCerts, &numHintCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ /*
+ * Caller must provide either a target Cert
+ * (in ComCertSelParams->Certificate) or a partial Cert
+ * chain (in ProcParams->HintCerts).
+ */
+
+ if (targetCert == NULL) {
+
+ /* Use first cert of hintCerts as the targetCert */
+ if (numHintCerts == 0) {
+ PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED);
+ }
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (hintCerts,
+ 0,
+ (PKIX_PL_Object **)&targetCert,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_DeleteItem(hintCerts, 0, plContext),
+ PKIX_LISTGETITEMFAILED);
+ } else {
+
+ /*
+ * If the first hintCert is the same as the targetCert,
+ * delete it from hintCerts.
+ */
+ if (numHintCerts != 0) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (hintCerts, 0, &firstHintCert, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *)targetCert,
+ firstHintCert,
+ &isDuplicate,
+ plContext),
+ PKIX_OBJECTEQUALSFAILED);
+
+ if (isDuplicate) {
+ PKIX_CHECK(PKIX_List_DeleteItem
+ (hintCerts, 0, plContext),
+ PKIX_LISTGETITEMFAILED);
+ }
+ PKIX_DECREF(firstHintCert);
+ }
+
+ }
+
+ if (targetCert == NULL) {
+ PKIX_ERROR(PKIX_NOTARGETCERTSUPPLIED);
+ }
+
+ PKIX_CHECK(PKIX_PL_Cert_IsLeafCertTrusted
+ (targetCert,
+ &trusted,
+ plContext),
+ PKIX_CERTISCERTTRUSTEDFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
+ (targetCert,
+ &targetSubjNames,
+ plContext),
+ PKIX_CERTGETALLSUBJECTNAMESFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (targetCert, &targetPubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+
+ PKIX_CHECK(PKIX_List_Create(&tentativeChain, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (tentativeChain, (PKIX_PL_Object *)targetCert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ if (procParams->qualifyTargetCert) {
+ /* EE cert validation */
+ /* Sync up the time on the target selector parameter struct. */
+ PKIX_CHECK(
+ PKIX_ComCertSelParams_SetCertificateValid(targetParams,
+ testDate,
+ plContext),
+ PKIX_COMCERTSELPARAMSSETCERTIFICATEVALIDFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (targetConstraints, &selectorCallback, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ pkixErrorResult =
+ (*selectorCallback)(targetConstraints, targetCert,
+ plContext);
+ if (pkixErrorResult) {
+ pkixErrorClass = pkixErrorResult->errClass;
+ if (pkixErrorClass == PKIX_FATAL_ERROR) {
+ goto cleanup;
+ }
+ if (pVerifyNode != NULL) {
+ PKIX_Error *tempResult =
+ pkix_VerifyNode_Create(targetCert, 0,
+ pkixErrorResult,
+ pVerifyNode,
+ plContext);
+ if (tempResult) {
+ PKIX_DECREF(pkixErrorResult);
+ pkixErrorResult = tempResult;
+ pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+ }
+ }
+ pkixErrorCode = PKIX_CERTCHECKVALIDITYFAILED;
+ goto cleanup;
+ }
+ }
+
+ /* If the EE cert is trusted, force success. We only want to do
+ * this if we aren't validating against a policy (like EV). */
+ if (trusted && procParams->initialPolicies == NULL) {
+ if (pVerifyNode != NULL) {
+ PKIX_Error *tempResult =
+ pkix_VerifyNode_Create(targetCert, 0, NULL,
+ pVerifyNode,
+ plContext);
+ if (tempResult) {
+ pkixErrorResult = tempResult;
+ pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+ }
+ }
+ PKIX_CHECK(pkix_ValidateResult_Create
+ (targetPubKey, NULL /* anchor */,
+ NULL /* policyTree */, &valResult, plContext),
+ PKIX_VALIDATERESULTCREATEFAILED);
+ PKIX_CHECK(
+ pkix_BuildResult_Create(valResult, tentativeChain,
+ &buildResult, plContext),
+ PKIX_BUILDRESULTCREATEFAILED);
+ *pBuildResult = buildResult;
+ /* Note that *pState is NULL. The only side effect is that
+ * the cert chain won't be cached in PKIX_BuildChain, which
+ * is fine. */
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetCertStores
+ (procParams, &certStores, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (certStores, &numCertStores, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ /* Reorder CertStores so trusted are at front of the List */
+ if (numCertStores > 1) {
+ for (i = numCertStores - 1; i > 0; i--) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (certStores,
+ i,
+ (PKIX_PL_Object **)&certStore,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ PKIX_CHECK_ONLY_FATAL(PKIX_CertStore_GetTrustCallback
+ (certStore, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ if (trustCallback != NULL) {
+ /* Is a trusted Cert, move CertStore to front */
+ PKIX_CHECK(PKIX_List_DeleteItem
+ (certStores, i, plContext),
+ PKIX_LISTDELETEITEMFAILED);
+ PKIX_CHECK(PKIX_List_InsertItem
+ (certStores,
+ 0,
+ (PKIX_PL_Object *)certStore,
+ plContext),
+ PKIX_LISTINSERTITEMFAILED);
+
+ }
+
+ PKIX_DECREF(certStore);
+ }
+ }
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers
+ (procParams, &userCheckers, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker
+ (procParams, &revChecker, plContext),
+ PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED);
+ /* Do not initialize AIA manager if we are not going to fetch
+ * cert using aia url. */
+ if (procParams->useAIAForCertFetching) {
+ PKIX_CHECK(PKIX_PL_AIAMgr_Create(&aiaMgr, plContext),
+ PKIX_AIAMGRCREATEFAILED);
+ }
+
+ /*
+ * We initialize all the fields of buildConstants here, in one place,
+ * just to help keep track and ensure that we got everything.
+ */
+
+ buildConstants.numAnchors = numAnchors;
+ buildConstants.numCertStores = numCertStores;
+ buildConstants.numHintCerts = numHintCerts;
+ buildConstants.procParams = procParams;
+ buildConstants.testDate = testDate;
+ buildConstants.timeLimit = NULL;
+ buildConstants.targetCert = targetCert;
+ buildConstants.targetPubKey = targetPubKey;
+ buildConstants.certStores = certStores;
+ buildConstants.anchors = anchors;
+ buildConstants.userCheckers = userCheckers;
+ buildConstants.hintCerts = hintCerts;
+ buildConstants.revChecker = revChecker;
+ buildConstants.aiaMgr = aiaMgr;
+ buildConstants.trustOnlyUserAnchors =
+ procParams->useOnlyTrustAnchors;
+
+ PKIX_CHECK(pkix_Build_GetResourceLimits(&buildConstants, plContext),
+ PKIX_BUILDGETRESOURCELIMITSFAILED);
+
+ PKIX_CHECK(pkix_ForwardBuilderState_Create
+ (0, /* PKIX_UInt32 traversedCACerts */
+ buildConstants.maxFanout,
+ buildConstants.maxDepth,
+ PKIX_TRUE, /* PKIX_Boolean canBeCached */
+ NULL, /* PKIX_Date *validityDate */
+ targetCert, /* PKIX_PL_Cert *prevCert */
+ targetSubjNames, /* PKIX_List *traversedSubjNames */
+ tentativeChain, /* PKIX_List *trustChain */
+ NULL, /* PKIX_ForwardBuilderState *parent */
+ &state, /* PKIX_ForwardBuilderState **pState */
+ plContext),
+ PKIX_BUILDSTATECREATEFAILED);
+
+ state->buildConstants.numAnchors = buildConstants.numAnchors;
+ state->buildConstants.numCertStores = buildConstants.numCertStores;
+ state->buildConstants.numHintCerts = buildConstants.numHintCerts;
+ state->buildConstants.maxFanout = buildConstants.maxFanout;
+ state->buildConstants.maxDepth = buildConstants.maxDepth;
+ state->buildConstants.maxTime = buildConstants.maxTime;
+ state->buildConstants.procParams = buildConstants.procParams;
+ PKIX_INCREF(buildConstants.testDate);
+ state->buildConstants.testDate = buildConstants.testDate;
+ state->buildConstants.timeLimit = buildConstants.timeLimit;
+ PKIX_INCREF(buildConstants.targetCert);
+ state->buildConstants.targetCert = buildConstants.targetCert;
+ PKIX_INCREF(buildConstants.targetPubKey);
+ state->buildConstants.targetPubKey =
+ buildConstants.targetPubKey;
+ PKIX_INCREF(buildConstants.certStores);
+ state->buildConstants.certStores = buildConstants.certStores;
+ PKIX_INCREF(buildConstants.anchors);
+ state->buildConstants.anchors = buildConstants.anchors;
+ PKIX_INCREF(buildConstants.userCheckers);
+ state->buildConstants.userCheckers =
+ buildConstants.userCheckers;
+ PKIX_INCREF(buildConstants.hintCerts);
+ state->buildConstants.hintCerts = buildConstants.hintCerts;
+ PKIX_INCREF(buildConstants.revChecker);
+ state->buildConstants.revChecker = buildConstants.revChecker;
+ state->buildConstants.aiaMgr = buildConstants.aiaMgr;
+ aiaMgr = NULL;
+ state->buildConstants.trustOnlyUserAnchors =
+ buildConstants.trustOnlyUserAnchors;
+
+ if (buildConstants.maxTime != 0) {
+ PKIX_CHECK(PKIX_PL_Date_Create_CurrentOffBySeconds
+ (buildConstants.maxTime,
+ &state->buildConstants.timeLimit,
+ plContext),
+ PKIX_DATECREATECURRENTOFFBYSECONDSFAILED);
+ }
+
+ if (pVerifyNode != NULL) {
+ PKIX_Error *tempResult =
+ pkix_VerifyNode_Create(targetCert, 0, NULL,
+ &(state->verifyNode),
+ plContext);
+ if (tempResult) {
+ pkixErrorResult = tempResult;
+ pkixErrorCode = PKIX_VERIFYNODECREATEFAILED;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+ }
+ }
+
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_Build_CheckInCache(state, &buildResult,
+ &nbioContext, plContext),
+ PKIX_UNABLETOBUILDCHAIN);
+ if (nbioContext) {
+ *pNBIOContext = nbioContext;
+ *pState = state;
+ state = NULL;
+ goto cleanup;
+ }
+ if (buildResult) {
+ *pBuildResult = buildResult;
+ if (pVerifyNode != NULL) {
+ *pVerifyNode = state->verifyNode;
+ state->verifyNode = NULL;
+ }
+ goto cleanup;
+ }
+ }
+
+ /* If we're resuming after non-blocking I/O we need to get SubjNames */
+ if (targetSubjNames == NULL) {
+ PKIX_CHECK(PKIX_PL_Cert_GetAllSubjectNames
+ (state->buildConstants.targetCert,
+ &targetSubjNames,
+ plContext),
+ PKIX_CERTGETALLSUBJECTNAMESFAILED);
+ }
+
+ state->status = BUILD_INITIAL;
+
+ pkixErrorResult =
+ pkix_BuildForwardDepthFirstSearch(&nbioContext, state,
+ &valResult, plContext);
+
+ /* non-null nbioContext means the build would block */
+ if (pkixErrorResult == NULL && nbioContext != NULL) {
+
+ *pNBIOContext = nbioContext;
+ *pBuildResult = NULL;
+
+ /* no valResult means the build has failed */
+ } else {
+ if (pVerifyNode != NULL) {
+ PKIX_INCREF(state->verifyNode);
+ *pVerifyNode = state->verifyNode;
+ }
+
+ if (valResult == NULL || pkixErrorResult)
+ PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
+ PKIX_CHECK(
+ pkix_BuildResult_Create(valResult, state->trustChain,
+ &buildResult, plContext),
+ PKIX_BUILDRESULTCREATEFAILED);
+ *pBuildResult = buildResult;
+ }
+
+ *pState = state;
+ state = NULL;
+
+cleanup:
+
+ PKIX_DECREF(targetConstraints);
+ PKIX_DECREF(targetParams);
+ PKIX_DECREF(anchors);
+ PKIX_DECREF(targetSubjNames);
+ PKIX_DECREF(targetCert);
+ PKIX_DECREF(revChecker);
+ PKIX_DECREF(certStores);
+ PKIX_DECREF(certStore);
+ PKIX_DECREF(userCheckers);
+ PKIX_DECREF(hintCerts);
+ PKIX_DECREF(firstHintCert);
+ PKIX_DECREF(testDate);
+ PKIX_DECREF(targetPubKey);
+ PKIX_DECREF(tentativeChain);
+ PKIX_DECREF(valResult);
+ PKIX_DECREF(certList);
+ PKIX_DECREF(trustedCert);
+ PKIX_DECREF(state);
+ PKIX_DECREF(aiaMgr);
+
+ PKIX_RETURN(BUILD);
+}
+
+/*
+ * FUNCTION: pkix_Build_ResumeBuildChain
+ * DESCRIPTION:
+ *
+ * This function continues the search for a BuildChain, using the parameters
+ * provided in "procParams" and the ForwardBuilderState pointed to by "state".
+ *
+ * If a successful chain is built, this function stores the BuildResult at
+ * "pBuildResult". Alternatively, if an operation using non-blocking I/O
+ * is in progress and the operation has not been completed, this function
+ * stores the FowardBuilderState at "pState" and NULL at "pBuildResult".
+ * Finally, if chain building was unsuccessful, this function stores NULL
+ * at both "pState" and at "pBuildResult".
+ *
+ * PARAMETERS:
+ * "pNBIOContext"
+ * Address at which the NBIOContext is stored indicating whether the
+ * validation is complete. Must be non-NULL.
+ * "pState"
+ * Address at which the ForwardBuilderState is provided for resumption of
+ * the chain building attempt; also, the address at which the
+ * ForwardBuilderStateis stored, if the chain building is suspended for
+ * waiting I/O. Must be non-NULL.
+ * "pBuildResult"
+ * Address at which the BuildResult is stored, after a successful build.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Build Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_Build_ResumeBuildChain(
+ void **pNBIOContext,
+ PKIX_ForwardBuilderState *state,
+ PKIX_BuildResult **pBuildResult,
+ PKIX_VerifyNode **pVerifyNode,
+ void *plContext)
+{
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_BuildResult *buildResult = NULL;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "pkix_Build_ResumeBuildChain");
+ PKIX_NULLCHECK_TWO(state, pBuildResult);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ pkixErrorResult =
+ pkix_BuildForwardDepthFirstSearch(&nbioContext, state,
+ &valResult, plContext);
+
+ /* non-null nbioContext means the build would block */
+ if (pkixErrorResult == NULL && nbioContext != NULL) {
+
+ *pNBIOContext = nbioContext;
+ *pBuildResult = NULL;
+
+ /* no valResult means the build has failed */
+ } else {
+ if (pVerifyNode != NULL) {
+ PKIX_INCREF(state->verifyNode);
+ *pVerifyNode = state->verifyNode;
+ }
+
+ if (valResult == NULL || pkixErrorResult)
+ PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
+
+ PKIX_CHECK(
+ pkix_BuildResult_Create(valResult, state->trustChain,
+ &buildResult, plContext),
+ PKIX_BUILDRESULTCREATEFAILED);
+ *pBuildResult = buildResult;
+ }
+
+cleanup:
+
+ PKIX_DECREF(valResult);
+
+ PKIX_RETURN(BUILD);
+}
+
+/* --Public-Functions--------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_BuildChain (see comments in pkix.h)
+ */
+PKIX_Error *
+PKIX_BuildChain(
+ PKIX_ProcessingParams *procParams,
+ void **pNBIOContext,
+ void **pState,
+ PKIX_BuildResult **pBuildResult,
+ PKIX_VerifyNode **pVerifyNode,
+ void *plContext)
+{
+ PKIX_ForwardBuilderState *state = NULL;
+ PKIX_BuildResult *buildResult = NULL;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(BUILD, "PKIX_BuildChain");
+ PKIX_NULLCHECK_FOUR(procParams, pNBIOContext, pState, pBuildResult);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ if (*pState == NULL) {
+ PKIX_CHECK(pkix_Build_InitiateBuildChain
+ (procParams,
+ &nbioContext,
+ &state,
+ &buildResult,
+ pVerifyNode,
+ plContext),
+ PKIX_BUILDINITIATEBUILDCHAINFAILED);
+ } else {
+ state = (PKIX_ForwardBuilderState *)(*pState);
+ *pState = NULL; /* no net change in reference count */
+ if (state->status == BUILD_SHORTCUTPENDING) {
+ PKIX_CHECK(pkix_Build_InitiateBuildChain
+ (procParams,
+ &nbioContext,
+ &state,
+ &buildResult,
+ pVerifyNode,
+ plContext),
+ PKIX_BUILDINITIATEBUILDCHAINFAILED);
+ } else {
+ PKIX_CHECK(pkix_Build_ResumeBuildChain
+ (&nbioContext,
+ state,
+ &buildResult,
+ pVerifyNode,
+ plContext),
+ PKIX_BUILDINITIATEBUILDCHAINFAILED);
+ }
+ }
+
+ /* non-null nbioContext means the build would block */
+ if (nbioContext != NULL) {
+
+ *pNBIOContext = nbioContext;
+ *pState = state;
+ state = NULL;
+ *pBuildResult = NULL;
+
+ /* no buildResult means the build has failed */
+ } else if (buildResult == NULL) {
+ PKIX_ERROR(PKIX_UNABLETOBUILDCHAIN);
+ } else {
+ /*
+ * If we made a successful chain by combining the target Cert
+ * with one of the Trust Anchors, we may have never created a
+ * validityDate. We treat this situation as
+ * canBeCached = PKIX_FALSE.
+ */
+ if ((state != NULL) &&
+ ((state->validityDate) != NULL) &&
+ (state->canBeCached)) {
+ PKIX_CHECK(pkix_CacheCertChain_Add
+ (state->buildConstants.targetCert,
+ state->buildConstants.anchors,
+ state->validityDate,
+ buildResult,
+ plContext),
+ PKIX_CACHECERTCHAINADDFAILED);
+ }
+
+ *pState = NULL;
+ *pBuildResult = buildResult;
+ buildResult = NULL;
+ }
+
+cleanup:
+ PKIX_DECREF(buildResult);
+ PKIX_DECREF(state);
+
+ PKIX_RETURN(BUILD);
+}
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_build.h b/security/nss/lib/libpkix/pkix/top/pkix_build.h
new file mode 100755
index 000000000..eeba9239d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_build.h
@@ -0,0 +1,120 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_build.h
+ *
+ * Header file for buildChain function
+ *
+ */
+
+#ifndef _PKIX_BUILD_H
+#define _PKIX_BUILD_H
+#include "pkix_tools.h"
+#ifndef NSS_PKIX_NO_LDAP
+#include "pkix_pl_ldapt.h"
+#endif
+#include "pkix_ekuchecker.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ BUILD_SHORTCUTPENDING,
+ BUILD_INITIAL,
+ BUILD_TRYAIA,
+ BUILD_AIAPENDING,
+ BUILD_COLLECTINGCERTS,
+ BUILD_GATHERPENDING,
+ BUILD_CERTVALIDATING,
+ BUILD_ABANDONNODE,
+ BUILD_DATEPREP,
+ BUILD_CHECKTRUSTED,
+ BUILD_CHECKTRUSTED2,
+ BUILD_ADDTOCHAIN,
+ BUILD_VALCHAIN,
+ BUILD_VALCHAIN2,
+ BUILD_EXTENDCHAIN,
+ BUILD_GETNEXTCERT
+} BuildStatus;
+
+typedef struct BuildConstantsStruct BuildConstants;
+
+/*
+ * These fields (the ones that are objects) are not reference-counted
+ * in *each* state, but only in the root, the state that has no parent.
+ * That saves time in creation and destruction of child states, but is
+ * safe enough since they are constants.
+ */
+struct BuildConstantsStruct {
+ PKIX_UInt32 numAnchors;
+ PKIX_UInt32 numCertStores;
+ PKIX_UInt32 numHintCerts;
+ PKIX_UInt32 maxDepth;
+ PKIX_UInt32 maxFanout;
+ PKIX_UInt32 maxTime;
+ PKIX_ProcessingParams *procParams;
+ PKIX_PL_Date *testDate;
+ PKIX_PL_Date *timeLimit;
+ PKIX_PL_Cert *targetCert;
+ PKIX_PL_PublicKey *targetPubKey;
+ PKIX_List *certStores;
+ PKIX_List *anchors;
+ PKIX_List *userCheckers;
+ PKIX_List *hintCerts;
+ PKIX_RevocationChecker *revChecker;
+ PKIX_PL_AIAMgr *aiaMgr;
+ PKIX_Boolean useAIAForCertFetching;
+ PKIX_Boolean trustOnlyUserAnchors;
+};
+
+struct PKIX_ForwardBuilderStateStruct{
+ BuildStatus status;
+ PKIX_Int32 traversedCACerts;
+ PKIX_UInt32 certStoreIndex;
+ PKIX_UInt32 numCerts;
+ PKIX_UInt32 numAias;
+ PKIX_UInt32 certIndex;
+ PKIX_UInt32 aiaIndex;
+ PKIX_UInt32 certCheckedIndex;
+ PKIX_UInt32 checkerIndex;
+ PKIX_UInt32 hintCertIndex;
+ PKIX_UInt32 numFanout;
+ PKIX_UInt32 numDepth;
+ PKIX_UInt32 reasonCode;
+ PKIX_Boolean canBeCached;
+ PKIX_Boolean useOnlyLocal;
+ PKIX_Boolean revChecking;
+ PKIX_Boolean usingHintCerts;
+ PKIX_Boolean certLoopingDetected;
+ PKIX_PL_Date *validityDate;
+ PKIX_PL_Cert *prevCert;
+ PKIX_PL_Cert *candidateCert;
+ PKIX_List *traversedSubjNames;
+ PKIX_List *trustChain;
+ PKIX_List *aia;
+ PKIX_List *candidateCerts;
+ PKIX_List *reversedCertChain;
+ PKIX_List *checkedCritExtOIDs;
+ PKIX_List *checkerChain;
+ PKIX_CertSelector *certSel;
+ PKIX_VerifyNode *verifyNode;
+ void *client; /* messageHandler, such as LDAPClient */
+ PKIX_ForwardBuilderState *parentState;
+ BuildConstants buildConstants;
+};
+
+/* --Private-Functions-------------------------------------------- */
+
+PKIX_Error *
+pkix_ForwardBuilderState_RegisterSelf(void *plContext);
+
+PKIX_Error *
+PKIX_Build_GetNBIOContext(void *state, void **pNBIOContext, void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_BUILD_H */
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.c b/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.c
new file mode 100755
index 000000000..aad0e1aaf
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.c
@@ -0,0 +1,210 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_lifecycle.c
+ *
+ * Top level initialize and shutdown functions
+ *
+ */
+
+#include "pkix_lifecycle.h"
+
+static PKIX_Boolean pkixIsInitialized;
+
+/* Lock used by Logger - is reentrant by the same thread */
+extern PKIX_PL_MonitorLock *pkixLoggerLock;
+
+/*
+ * Following pkix_* variables are for debugging purpose. They should be taken
+ * out eventually. The purpose is to verify cache tables usage (via debugger).
+ */
+int pkix_ccAddCount = 0;
+int pkix_ccLookupCount = 0;
+int pkix_ccRemoveCount = 0;
+int pkix_cAddCount = 0;
+int pkix_cLookupCount = 0;
+int pkix_cRemoveCount = 0;
+int pkix_ceAddCount = 0;
+int pkix_ceLookupCount = 0;
+
+PKIX_PL_HashTable *cachedCrlSigTable = NULL;
+PKIX_PL_HashTable *cachedCertSigTable = NULL;
+PKIX_PL_HashTable *cachedCertChainTable = NULL;
+PKIX_PL_HashTable *cachedCertTable = NULL;
+PKIX_PL_HashTable *cachedCrlEntryTable = NULL;
+PKIX_PL_HashTable *aiaConnectionCache = NULL;
+PKIX_PL_HashTable *httpSocketCache = NULL;
+
+extern PKIX_List *pkixLoggers;
+extern PKIX_List *pkixLoggersErrors;
+extern PKIX_List *pkixLoggersDebugTrace;
+
+/* --Public-Functions--------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_Initialize (see comments in pkix.h)
+ */
+PKIX_Error *
+PKIX_Initialize(
+ PKIX_Boolean platformInitNeeded,
+ PKIX_UInt32 desiredMajorVersion,
+ PKIX_UInt32 minDesiredMinorVersion,
+ PKIX_UInt32 maxDesiredMinorVersion,
+ PKIX_UInt32 *pActualMinorVersion,
+ void **pPlContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(LIFECYCLE, "PKIX_Initialize");
+ PKIX_NULLCHECK_ONE(pPlContext);
+
+ /*
+ * If we are called a second time other than in the situation handled
+ * above, we return a positive status.
+ */
+ if (pkixIsInitialized){
+ /* Already initialized */
+ PKIX_RETURN(LIFECYCLE);
+ }
+
+ PKIX_CHECK(PKIX_PL_Initialize
+ (platformInitNeeded, PKIX_FALSE, &plContext),
+ PKIX_INITIALIZEFAILED);
+
+ *pPlContext = plContext;
+
+ if (desiredMajorVersion != PKIX_MAJOR_VERSION){
+ PKIX_ERROR(PKIX_MAJORVERSIONSDONTMATCH);
+ }
+
+ if ((minDesiredMinorVersion > PKIX_MINOR_VERSION) ||
+ (maxDesiredMinorVersion < PKIX_MINOR_VERSION)){
+ PKIX_ERROR(PKIX_MINORVERSIONNOTBETWEENDESIREDMINANDMAX);
+ }
+
+ *pActualMinorVersion = PKIX_MINOR_VERSION;
+
+ /* Create Cache Tables
+ * Do not initialize hash tables for object leak test */
+#if !defined(PKIX_OBJECT_LEAK_TEST)
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (32, 0, &cachedCertSigTable, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (32, 0, &cachedCrlSigTable, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (32, 10, &cachedCertChainTable, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (32, 10, &cachedCertTable, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (32, 10, &cachedCrlEntryTable, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (5, 5, &aiaConnectionCache, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+#ifdef PKIX_SOCKETCACHE
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (5, 5, &httpSocketCache, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+#endif
+ if (pkixLoggerLock == NULL) {
+ PKIX_CHECK(PKIX_PL_MonitorLock_Create
+ (&pkixLoggerLock, plContext),
+ PKIX_MONITORLOCKCREATEFAILED);
+ }
+#else
+ fnInvTable = PL_NewHashTable(0, pkix_ErrorGen_Hash,
+ PL_CompareValues,
+ PL_CompareValues, NULL, NULL);
+ if (!fnInvTable) {
+ PKIX_ERROR(PKIX_HASHTABLECREATEFAILED);
+ }
+
+ fnStackNameArr = PORT_ZNewArray(char*, MAX_STACK_DEPTH);
+ if (!fnStackNameArr) {
+ PKIX_ERROR(PKIX_HASHTABLECREATEFAILED);
+ }
+
+ fnStackInvCountArr = PORT_ZNewArray(PKIX_UInt32, MAX_STACK_DEPTH);
+ if (!fnStackInvCountArr) {
+ PKIX_ERROR(PKIX_HASHTABLECREATEFAILED);
+ }
+#endif /* PKIX_OBJECT_LEAK_TEST */
+
+ pkixIsInitialized = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LIFECYCLE);
+}
+
+/*
+ * FUNCTION: PKIX_Shutdown (see comments in pkix.h)
+ */
+PKIX_Error *
+PKIX_Shutdown(void *plContext)
+{
+ PKIX_List *savedPkixLoggers = NULL;
+ PKIX_List *savedPkixLoggersErrors = NULL;
+ PKIX_List *savedPkixLoggersDebugTrace = NULL;
+
+ PKIX_ENTER(LIFECYCLE, "PKIX_Shutdown");
+
+ if (!pkixIsInitialized){
+ /* The library was not initialized */
+ PKIX_RETURN(LIFECYCLE);
+ }
+
+ pkixIsInitialized = PKIX_FALSE;
+
+ if (pkixLoggers) {
+ savedPkixLoggers = pkixLoggers;
+ savedPkixLoggersErrors = pkixLoggersErrors;
+ savedPkixLoggersDebugTrace = pkixLoggersDebugTrace;
+ pkixLoggers = NULL;
+ pkixLoggersErrors = NULL;
+ pkixLoggersDebugTrace = NULL;
+ PKIX_DECREF(savedPkixLoggers);
+ PKIX_DECREF(savedPkixLoggersErrors);
+ PKIX_DECREF(savedPkixLoggersDebugTrace);
+ }
+ PKIX_DECREF(pkixLoggerLock);
+
+ /* Destroy Cache Tables */
+ PKIX_DECREF(cachedCertSigTable);
+ PKIX_DECREF(cachedCrlSigTable);
+ PKIX_DECREF(cachedCertChainTable);
+ PKIX_DECREF(cachedCertTable);
+ PKIX_DECREF(cachedCrlEntryTable);
+ PKIX_DECREF(aiaConnectionCache);
+ PKIX_DECREF(httpSocketCache);
+
+ /* Clean up any temporary errors that happened during shutdown */
+ if (pkixErrorList) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorList, plContext);
+ pkixErrorList = NULL;
+ }
+
+ PKIX_CHECK(PKIX_PL_Shutdown(plContext),
+ PKIX_SHUTDOWNFAILED);
+
+#ifdef PKIX_OBJECT_LEAK_TEST
+ PORT_Free(fnStackInvCountArr);
+ PORT_Free(fnStackNameArr);
+ PL_HashTableDestroy(fnInvTable);
+#endif
+
+cleanup:
+
+ PKIX_RETURN(LIFECYCLE);
+}
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.h b/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.h
new file mode 100755
index 000000000..02631229c
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_lifecycle.h
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_lifecycle.h
+ *
+ * Header file for initialize and shutdown functions.
+ *
+ */
+
+#ifndef _PKIX_LIFECYCLE_H
+#define _PKIX_LIFECYCLE_H
+#include "pkix_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_LIFECYCLE_H */
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_validate.c b/security/nss/lib/libpkix/pkix/top/pkix_validate.c
new file mode 100755
index 000000000..1e5dec795
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_validate.c
@@ -0,0 +1,1451 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_validate.c
+ *
+ * Top level validateChain function
+ *
+ */
+
+#include "pkix_validate.h"
+#include "pkix_pl_common.h"
+
+/* --Private-Functions-------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_AddToVerifyLog
+ * DESCRIPTION:
+ *
+ * This function returns immediately if the address for the VerifyNode tree
+ * pointed to by "pVerifyTree" is NULL. Otherwise it creates a new VerifyNode
+ * from the Cert pointed to by "cert" and the Error pointed to by "error",
+ * and inserts it at the depth in the VerifyNode tree determined by "depth". A
+ * depth of zero means that this function creates the root node of a new tree.
+ *
+ * Note: this function does not include the means of choosing among branches
+ * of a tree. It is intended for non-branching trees, that is, where each
+ * parent node has only a single child node.
+ *
+ * PARAMETERS:
+ * "cert"
+ * The address of the Cert to be included in the new VerifyNode. Must be
+ * non-NULL.
+ * "depth"
+ * The UInt32 value of the depth.
+ * "error"
+ * The address of the Error to be included in the new VerifyNode.
+ * "pVerifyTree"
+ * The address of the VerifyNode tree into which the created VerifyNode
+ * is to be inserted. The node is not created if VerifyTree is 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 Validate 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_AddToVerifyLog(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 depth,
+ PKIX_Error *error,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext)
+{
+
+ PKIX_VerifyNode *verifyNode = NULL;
+
+ PKIX_ENTER(VALIDATE, "pkix_AddToVerifyLog");
+ PKIX_NULLCHECK_ONE(cert);
+
+ if (pVerifyTree) { /* nothing to do if no address given for log */
+
+ PKIX_CHECK(pkix_VerifyNode_Create
+ (cert, depth, error, &verifyNode, plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+
+ if (depth == 0) {
+ /* We just created the root node */
+ *pVerifyTree = verifyNode;
+ } else {
+ PKIX_CHECK(pkix_VerifyNode_AddToChain
+ (*pVerifyTree, verifyNode, plContext),
+ PKIX_VERIFYNODEADDTOCHAINFAILED);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(VALIDATE);
+
+}
+
+/*
+ * FUNCTION: pkix_CheckCert
+ * DESCRIPTION:
+ *
+ * Checks whether the Cert pointed to by "cert" successfully validates
+ * using the List of CertChainCheckers pointed to by "checkers". If the
+ * certificate does not validate, an Error pointer is returned.
+ *
+ * This function should be called initially with the UInt32 pointed to by
+ * "pCheckerIndex" containing zero, and the pointer at "pNBIOContext"
+ * containing NULL. If a checker does non-blocking I/O, this function will
+ * return with the index of that checker stored at "pCheckerIndex" and a
+ * platform-dependent non-blocking I/O context stored at "pNBIOContext".
+ * A subsequent call to this function with those values intact will allow the
+ * checking to resume where it left off. This should be repeated until the
+ * function returns with NULL stored at "pNBIOContext".
+ *
+ * PARAMETERS:
+ * "cert"
+ * Address of Cert to validate. Must be non-NULL.
+ * "checkers"
+ * List of CertChainCheckers which must each validate the certificate.
+ * Must be non-NULL.
+ * "checkedExtOIDs"
+ * List of PKIX_PL_OID that has been processed. If called from building
+ * chain, it is the list of critical extension OIDs that has been
+ * processed prior to validation. May be NULL.
+ * "pCheckerIndex"
+ * Address at which is stored the the index, within the List "checkers",
+ * of a checker whose processing was interrupted by non-blocking I/O.
+ * Must be non-NULL.
+ * "pNBIOContext"
+ * Address at which is stored platform-specific non-blocking I/O context.
+ * 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 Validate 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_CheckCert(
+ PKIX_PL_Cert *cert,
+ PKIX_List *checkers,
+ PKIX_List *checkedExtOIDsList,
+ PKIX_UInt32 *pCheckerIndex,
+ void **pNBIOContext,
+ void *plContext)
+{
+ PKIX_CertChainChecker_CheckCallback checkerCheck = NULL;
+ PKIX_CertChainChecker *checker = NULL;
+ PKIX_List *unresCritExtOIDs = NULL;
+ PKIX_UInt32 numCheckers;
+ PKIX_UInt32 numUnresCritExtOIDs = 0;
+ PKIX_UInt32 checkerIndex = 0;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(VALIDATE, "pkix_CheckCert");
+ PKIX_NULLCHECK_FOUR(cert, checkers, pCheckerIndex, pNBIOContext);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL; /* prepare for case of error exit */
+
+ PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs
+ (cert, &unresCritExtOIDs, plContext),
+ PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (checkerIndex = *pCheckerIndex;
+ checkerIndex < numCheckers;
+ checkerIndex++) {
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (checkers,
+ checkerIndex,
+ (PKIX_PL_Object **)&checker,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_CertChainChecker_GetCheckCallback
+ (checker, &checkerCheck, plContext),
+ PKIX_CERTCHAINCHECKERGETCHECKCALLBACKFAILED);
+
+ PKIX_CHECK(checkerCheck(checker, cert, unresCritExtOIDs,
+ &nbioContext, plContext),
+ PKIX_CERTCHAINCHECKERCHECKFAILED);
+
+ if (nbioContext != NULL) {
+ *pCheckerIndex = checkerIndex;
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ PKIX_DECREF(checker);
+ }
+
+ if (unresCritExtOIDs){
+
+#ifdef PKIX_VALIDATEDEBUG
+ {
+ PKIX_PL_String *oidString = NULL;
+ PKIX_UInt32 length;
+ char *oidAscii = NULL;
+ PKIX_TOSTRING(unresCritExtOIDs, &oidString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (oidString,
+ PKIX_ESCASCII,
+ (void **) &oidAscii,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+ PKIX_VALIDATE_DEBUG_ARG
+ ("unrecognized critical extension OIDs:"
+ " %s\n", oidAscii);
+ PKIX_DECREF(oidString);
+ PKIX_PL_Free(oidAscii, plContext);
+ }
+#endif
+
+ if (checkedExtOIDsList != NULL) {
+ /* Take out OID's that had been processed, if any */
+ PKIX_CHECK(pkix_List_RemoveItems
+ (unresCritExtOIDs,
+ checkedExtOIDsList,
+ plContext),
+ PKIX_LISTREMOVEITEMSFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (unresCritExtOIDs, &numUnresCritExtOIDs, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (numUnresCritExtOIDs != 0){
+ PKIX_ERROR(PKIX_UNRECOGNIZEDCRITICALEXTENSION);
+ }
+
+ }
+
+cleanup:
+
+ PKIX_DECREF(checker);
+ PKIX_DECREF(unresCritExtOIDs);
+
+ PKIX_RETURN(VALIDATE);
+
+}
+
+/*
+ * FUNCTION: pkix_InitializeCheckers
+ * DESCRIPTION:
+ *
+ * Creates several checkers and initializes them with values derived from the
+ * TrustAnchor pointed to by "anchor", the ProcessingParams pointed to by
+ * "procParams", and the number of Certs in the Chain, represented by
+ * "numCerts". The List of checkers is stored at "pCheckers".
+ *
+ * PARAMETERS:
+ * "anchor"
+ * Address of TrustAnchor used to initialize the SignatureChecker and
+ * NameChainingChecker. Must be non-NULL.
+ * "procParams"
+ * Address of ProcessingParams used to initialize the ExpirationChecker
+ * and TargetCertChecker. Must be non-NULL.
+ * "numCerts"
+ * Number of certificates in the CertChain.
+ * "pCheckers"
+ * Address where object pointer 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 Validate 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_InitializeCheckers(
+ PKIX_TrustAnchor *anchor,
+ PKIX_ProcessingParams *procParams,
+ PKIX_UInt32 numCerts,
+ PKIX_List **pCheckers,
+ void *plContext)
+{
+ PKIX_CertChainChecker *targetCertChecker = NULL;
+ PKIX_CertChainChecker *expirationChecker = NULL;
+ PKIX_CertChainChecker *nameChainingChecker = NULL;
+ PKIX_CertChainChecker *nameConstraintsChecker = NULL;
+ PKIX_CertChainChecker *basicConstraintsChecker = NULL;
+ PKIX_CertChainChecker *policyChecker = NULL;
+ PKIX_CertChainChecker *sigChecker = NULL;
+ PKIX_CertChainChecker *defaultCrlChecker = NULL;
+ PKIX_CertChainChecker *userChecker = NULL;
+ PKIX_PL_X500Name *trustedCAName = NULL;
+ PKIX_PL_PublicKey *trustedPubKey = NULL;
+ PKIX_List *checkers = NULL;
+ PKIX_PL_Date *testDate = NULL;
+ PKIX_CertSelector *certSelector = NULL;
+ PKIX_PL_Cert *trustedCert = NULL;
+ PKIX_PL_CertNameConstraints *trustedNC = NULL;
+ PKIX_List *initialPolicies = NULL;
+ PKIX_Boolean policyQualifiersRejected = PKIX_FALSE;
+ PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE;
+ PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE;
+ PKIX_Boolean initialExplicitPolicy = PKIX_FALSE;
+ PKIX_List *userCheckersList = NULL;
+ PKIX_List *certStores = NULL;
+ PKIX_UInt32 numCertCheckers = 0;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(VALIDATE, "pkix_InitializeCheckers");
+ PKIX_NULLCHECK_THREE(anchor, procParams, pCheckers);
+ PKIX_CHECK(PKIX_List_Create(&checkers, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /*
+ * The TrustAnchor may have been created using CreateWithCert
+ * (in which case GetCAPublicKey and GetCAName will return NULL)
+ * or may have been created using CreateWithNameKeyPair (in which
+ * case GetTrustedCert will return NULL. So we call GetTrustedCert
+ * and populate trustedPubKey and trustedCAName accordingly.
+ */
+
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (anchor, &trustedCert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+
+ if (trustedCert){
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (trustedCert, &trustedPubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetSubject
+ (trustedCert, &trustedCAName, plContext),
+ PKIX_CERTGETSUBJECTFAILED);
+ } else {
+ PKIX_CHECK(PKIX_TrustAnchor_GetCAPublicKey
+ (anchor, &trustedPubKey, plContext),
+ PKIX_TRUSTANCHORGETCAPUBLICKEYFAILED);
+
+ PKIX_CHECK(PKIX_TrustAnchor_GetCAName
+ (anchor, &trustedCAName, plContext),
+ PKIX_TRUSTANCHORGETCANAMEFAILED);
+ }
+
+ PKIX_NULLCHECK_TWO(trustedPubKey, trustedCAName);
+
+ PKIX_CHECK(PKIX_TrustAnchor_GetNameConstraints
+ (anchor, &trustedNC, plContext),
+ PKIX_TRUSTANCHORGETNAMECONSTRAINTSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetTargetCertConstraints
+ (procParams, &certSelector, plContext),
+ PKIX_PROCESSINGPARAMSGETTARGETCERTCONSTRAINTSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetDate
+ (procParams, &testDate, plContext),
+ PKIX_PROCESSINGPARAMSGETDATEFAILED);
+
+ 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_ProcessingParams_GetCertStores
+ (procParams, &certStores, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers
+ (procParams, &userCheckersList, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED);
+
+ /* now, initialize all the checkers */
+ PKIX_CHECK(pkix_TargetCertChecker_Initialize
+ (certSelector, numCerts, &targetCertChecker, plContext),
+ PKIX_TARGETCERTCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_ExpirationChecker_Initialize
+ (testDate, &expirationChecker, plContext),
+ PKIX_EXPIRATIONCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_NameChainingChecker_Initialize
+ (trustedCAName, &nameChainingChecker, plContext),
+ PKIX_NAMECHAININGCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_NameConstraintsChecker_Initialize
+ (trustedNC, numCerts, &nameConstraintsChecker, plContext),
+ PKIX_NAMECONSTRAINTSCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_BasicConstraintsChecker_Initialize
+ (numCerts, &basicConstraintsChecker, plContext),
+ PKIX_BASICCONSTRAINTSCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_PolicyChecker_Initialize
+ (initialPolicies,
+ policyQualifiersRejected,
+ initialPolicyMappingInhibit,
+ initialExplicitPolicy,
+ initialAnyPolicyInhibit,
+ numCerts,
+ &policyChecker,
+ plContext),
+ PKIX_POLICYCHECKERINITIALIZEFAILED);
+
+ PKIX_CHECK(pkix_SignatureChecker_Initialize
+ (trustedPubKey, numCerts, &sigChecker, plContext),
+ PKIX_SIGNATURECHECKERINITIALIZEFAILED);
+
+ if (userCheckersList != NULL) {
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (userCheckersList, &numCertCheckers, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (i = 0; i < numCertCheckers; i++) {
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (userCheckersList,
+ i,
+ (PKIX_PL_Object **) &userChecker,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers,
+ (PKIX_PL_Object *)userChecker,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(userChecker);
+ }
+ }
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)targetCertChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)expirationChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)nameChainingChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)nameConstraintsChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)basicConstraintsChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)policyChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (checkers, (PKIX_PL_Object *)sigChecker, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ *pCheckers = checkers;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(checkers);
+ }
+
+ PKIX_DECREF(certSelector);
+ PKIX_DECREF(testDate);
+ PKIX_DECREF(initialPolicies);
+ PKIX_DECREF(targetCertChecker);
+ PKIX_DECREF(expirationChecker);
+ PKIX_DECREF(nameChainingChecker);
+ PKIX_DECREF(nameConstraintsChecker);
+ PKIX_DECREF(basicConstraintsChecker);
+ PKIX_DECREF(policyChecker);
+ PKIX_DECREF(sigChecker);
+ PKIX_DECREF(trustedCAName);
+ PKIX_DECREF(trustedPubKey);
+ PKIX_DECREF(trustedNC);
+ PKIX_DECREF(trustedCert);
+ PKIX_DECREF(defaultCrlChecker);
+ PKIX_DECREF(userCheckersList);
+ PKIX_DECREF(certStores);
+ PKIX_DECREF(userChecker);
+
+ PKIX_RETURN(VALIDATE);
+}
+
+/*
+ * FUNCTION: pkix_RetrieveOutputs
+ * DESCRIPTION:
+ *
+ * This function queries the respective states of the List of checkers in
+ * "checkers" to to obtain the final public key from the SignatureChecker
+ * and the policy tree from the PolicyChecker, storing those values at
+ * "pFinalSubjPubKey" and "pPolicyTree", respectively.
+ *
+ * PARAMETERS:
+ * "checkers"
+ * Address of List of checkers to be queried. Must be non-NULL.
+ * "pFinalSubjPubKey"
+ * Address where final public key will be stored. Must be non-NULL.
+ * "pPolicyTree"
+ * Address where policy tree 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 Validate 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_RetrieveOutputs(
+ PKIX_List *checkers,
+ PKIX_PL_PublicKey **pFinalSubjPubKey,
+ PKIX_PolicyNode **pPolicyTree,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *finalSubjPubKey = NULL;
+ PKIX_PolicyNode *validPolicyTree = NULL;
+ PKIX_CertChainChecker *checker = NULL;
+ PKIX_PL_Object *state = NULL;
+ PKIX_UInt32 numCheckers = 0;
+ PKIX_UInt32 type;
+ PKIX_Int32 j;
+
+ PKIX_ENTER(VALIDATE, "pkix_RetrieveOutputs");
+
+ PKIX_NULLCHECK_TWO(checkers, pPolicyTree);
+
+ /*
+ * To optimize the search, we guess that the sigChecker is
+ * last in the tree and is preceded by the policyChecker. We
+ * search toward the front of the chain. Remember that List
+ * items are indexed 0..(numItems - 1).
+ */
+
+ PKIX_CHECK(PKIX_List_GetLength(checkers, &numCheckers, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (j = numCheckers - 1; j >= 0; j--){
+ PKIX_CHECK(PKIX_List_GetItem
+ (checkers, j, (PKIX_PL_Object **)&checker, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
+ (checker, &state, plContext),
+ PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);
+
+ /* user defined checker may have no state */
+ if (state != NULL) {
+
+ PKIX_CHECK(PKIX_PL_Object_GetType(state, &type, plContext),
+ PKIX_OBJECTGETTYPEFAILED);
+
+ if (type == PKIX_SIGNATURECHECKERSTATE_TYPE){
+ /* final pubKey will include any inherited DSA params */
+ finalSubjPubKey =
+ ((pkix_SignatureCheckerState *)state)->
+ prevPublicKey;
+ PKIX_INCREF(finalSubjPubKey);
+ *pFinalSubjPubKey = finalSubjPubKey;
+ }
+
+ if (type == PKIX_CERTPOLICYCHECKERSTATE_TYPE) {
+ validPolicyTree =
+ ((PKIX_PolicyCheckerState *)state)->validPolicyTree;
+ break;
+ }
+ }
+
+ PKIX_DECREF(checker);
+ PKIX_DECREF(state);
+ }
+
+ PKIX_INCREF(validPolicyTree);
+ *pPolicyTree = validPolicyTree;
+
+cleanup:
+
+ PKIX_DECREF(checker);
+ PKIX_DECREF(state);
+
+ PKIX_RETURN(VALIDATE);
+
+}
+
+/*
+ * FUNCTION: pkix_CheckChain
+ * DESCRIPTION:
+ *
+ * Checks whether the List of Certs pointed to by "certs", containing
+ * "numCerts" entries, successfully validates using each CertChainChecker in
+ * the List pointed to by "checkers" and has not been revoked, according to any
+ * of the Revocation Checkers in the List pointed to by "revChecker". Checkers
+ * are expected to remove from "removeCheckedExtOIDs" and extensions that they
+ * process. Indices to the certChain and the checkerChain are obtained and
+ * returned in "pCertCheckedIndex" and "pCheckerIndex", respectively. These
+ * should be set to zero prior to the initial call, but may be changed (and
+ * must be supplied on subsequent calls) if processing is suspended for non-
+ * blocking I/O. Each time a Cert passes from being validated by one of the
+ * CertChainCheckers to being checked by a Revocation Checker, the Boolean
+ * stored at "pRevChecking" is changed from FALSE to TRUE. If the Cert is
+ * rejected by a Revocation Checker, its reason code is returned at
+ * "pReasonCode. If the List of Certs successfully validates, the public key i
+ * the final certificate is obtained and stored at "pFinalSubjPubKey" and the
+ * validPolicyTree, which could be NULL, is stored at pPolicyTree. If the List
+ * of Certs fails to validate, an Error pointer is returned.
+ *
+ * If "pVerifyTree" is non-NULL, a chain of VerifyNodes is created which
+ * tracks the results of the validation. That is, either each node in the
+ * chain has a NULL Error component, or the last node contains an Error
+ * which indicates why the validation failed.
+ *
+ * The number of Certs in the List, represented by "numCerts", is used to
+ * determine which Cert is the final Cert.
+ *
+ * PARAMETERS:
+ * "certs"
+ * Address of List of Certs to validate. Must be non-NULL.
+ * "numCerts"
+ * Number of certificates in the List of certificates.
+ * "checkers"
+ * List of CertChainCheckers which must each validate the List of
+ * certificates. Must be non-NULL.
+ * "revChecker"
+ * List of RevocationCheckers which must each not reject the List of
+ * certificates. May be empty, but must be non-NULL.
+ * "removeCheckedExtOIDs"
+ * List of PKIX_PL_OID that has been processed. If called from building
+ * chain, it is the list of critical extension OIDs that has been
+ * processed prior to validation. Extension OIDs that may be processed by
+ * user defined checker processes are also in the list. May be NULL.
+ * "procParams"
+ * Address of ProcessingParams used to initialize various checkers. Must
+ * be non-NULL.
+ * "pCertCheckedIndex"
+ * Address where Int32 index to the Cert chain is obtained and
+ * returned. Must be non-NULL.
+ * "pCheckerIndex"
+ * Address where Int32 index to the CheckerChain is obtained and
+ * returned. Must be non-NULL.
+ * "pRevChecking"
+ * Address where Boolean is obtained and returned, indicating, if FALSE,
+ * that CertChainCheckers are being called; or, if TRUE, that RevChecker
+ * are being called. Must be non-NULL.
+ * "pReasonCode"
+ * Address where UInt32 results of revocation checking are stored. Must be
+ * non-NULL.
+ * "pNBIOContext"
+ * Address where platform-dependent context is stored if checking is
+ * suspended for non-blocking I/O. Must be non-NULL.
+ * "pFinalSubjPubKey"
+ * Address where the final public key will be stored. Must be non-NULL.
+ * "pPolicyTree"
+ * Address where the final validPolicyTree is stored. Must be non-NULL.
+ * "pVerifyTree"
+ * Address where a VerifyTree is stored, 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 Validate Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_CheckChain(
+ PKIX_List *certs,
+ PKIX_UInt32 numCerts,
+ PKIX_TrustAnchor *anchor,
+ PKIX_List *checkers,
+ PKIX_RevocationChecker *revChecker,
+ PKIX_List *removeCheckedExtOIDs,
+ PKIX_ProcessingParams *procParams,
+ PKIX_UInt32 *pCertCheckedIndex,
+ PKIX_UInt32 *pCheckerIndex,
+ PKIX_Boolean *pRevChecking,
+ PKIX_UInt32 *pReasonCode,
+ void **pNBIOContext,
+ PKIX_PL_PublicKey **pFinalSubjPubKey,
+ PKIX_PolicyNode **pPolicyTree,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext)
+{
+ PKIX_UInt32 j = 0;
+ PKIX_Boolean revChecking = PKIX_FALSE;
+ PKIX_Error *checkCertError = NULL;
+ void *nbioContext = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ PKIX_PL_Cert *issuer = NULL;
+ PKIX_PL_NssContext *nssContext = NULL;
+ CERTCertList *certList = NULL;
+ const CERTChainVerifyCallback *chainVerifyCallback = NULL;
+ CERTCertificate *nssCert = NULL;
+
+ PKIX_ENTER(VALIDATE, "pkix_CheckChain");
+ PKIX_NULLCHECK_FOUR(certs, checkers, revChecker, pCertCheckedIndex);
+ PKIX_NULLCHECK_FOUR(pCheckerIndex, pRevChecking, pReasonCode, anchor);
+ PKIX_NULLCHECK_THREE(pNBIOContext, pFinalSubjPubKey, pPolicyTree);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+ revChecking = *pRevChecking;
+ nssContext = (PKIX_PL_NssContext *)plContext;
+ chainVerifyCallback = &nssContext->chainVerifyCallback;
+
+ if (chainVerifyCallback->isChainValid != NULL) {
+ PRBool chainOK = PR_FALSE; /*assume failure*/
+ SECStatus rv;
+
+ certList = CERT_NewCertList();
+ if (certList == NULL) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+
+ /* Add the trust anchor to the list */
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (anchor, &cert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+
+ PKIX_CHECK(
+ PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext),
+ PKIX_CERTGETCERTCERTIFICATEFAILED);
+
+ rv = CERT_AddCertToListHead(certList, nssCert);
+ if (rv != SECSuccess) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+ /* the certList takes ownership of nssCert on success */
+ nssCert = NULL;
+ PKIX_DECREF(cert);
+
+ /* Add the rest of the chain to the list */
+ for (j = *pCertCheckedIndex; j < numCerts; j++) {
+ PKIX_CHECK(PKIX_List_GetItem(
+ certs, j, (PKIX_PL_Object **)&cert, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(
+ PKIX_PL_Cert_GetCERTCertificate(cert, &nssCert, plContext),
+ PKIX_CERTGETCERTCERTIFICATEFAILED);
+
+ rv = CERT_AddCertToListHead(certList, nssCert);
+ if (rv != SECSuccess) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+ /* the certList takes ownership of nssCert on success */
+ nssCert = NULL;
+ PKIX_DECREF(cert);
+ }
+
+ rv = (*chainVerifyCallback->isChainValid)
+ (chainVerifyCallback->isChainValidArg, certList, &chainOK);
+ if (rv != SECSuccess) {
+ PKIX_ERROR_FATAL(PKIX_CHAINVERIFYCALLBACKFAILED);
+ }
+
+ if (!chainOK) {
+ PKIX_ERROR(PKIX_CHAINVERIFYCALLBACKFAILED);
+ }
+
+ }
+
+ PKIX_CHECK(PKIX_TrustAnchor_GetTrustedCert
+ (anchor, &cert, plContext),
+ PKIX_TRUSTANCHORGETTRUSTEDCERTFAILED);
+
+ for (j = *pCertCheckedIndex; j < numCerts; j++) {
+
+ PORT_Assert(cert);
+ PKIX_DECREF(issuer);
+ issuer = cert;
+ cert = NULL;
+
+ PKIX_CHECK(PKIX_List_GetItem(
+ certs, j, (PKIX_PL_Object **)&cert, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* check if cert pointer is valid */
+ PORT_Assert(cert);
+ if (cert == NULL) {
+ continue;
+ }
+
+ if (revChecking == PKIX_FALSE) {
+
+ PKIX_CHECK(pkix_CheckCert
+ (cert,
+ checkers,
+ removeCheckedExtOIDs,
+ pCheckerIndex,
+ &nbioContext,
+ plContext),
+ PKIX_CHECKCERTFAILED);
+
+ if (nbioContext != NULL) {
+ *pCertCheckedIndex = j;
+ *pRevChecking = revChecking;
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ revChecking = PKIX_TRUE;
+ *pCheckerIndex = 0;
+ }
+
+ if (revChecking == PKIX_TRUE) {
+ PKIX_RevocationStatus revStatus;
+ pkixErrorResult =
+ PKIX_RevocationChecker_Check(
+ cert, issuer, revChecker,
+ procParams, PKIX_TRUE,
+ (j == numCerts - 1) ? PKIX_TRUE : PKIX_FALSE,
+ &revStatus, pReasonCode,
+ &nbioContext, plContext);
+ if (nbioContext != NULL) {
+ *pCertCheckedIndex = j;
+ *pRevChecking = revChecking;
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+ if (revStatus == PKIX_RevStatus_Revoked ||
+ pkixErrorResult) {
+ if (!pkixErrorResult) {
+ /* if pkixErrorResult is returned then
+ * use it as it has a detailed revocation
+ * error code. Otherwise create a new error */
+ PKIX_ERROR_CREATE(VALIDATE,
+ PKIX_CERTIFICATEREVOKED,
+ pkixErrorResult);
+ }
+ goto cleanup;
+ }
+ revChecking = PKIX_FALSE;
+ *pCheckerIndex = 0;
+ }
+
+ PKIX_CHECK(pkix_AddToVerifyLog
+ (cert, j, NULL, pVerifyTree, plContext),
+ PKIX_ADDTOVERIFYLOGFAILED);
+ }
+
+ PKIX_CHECK(pkix_RetrieveOutputs
+ (checkers, pFinalSubjPubKey, pPolicyTree, plContext),
+ PKIX_RETRIEVEOUTPUTSFAILED);
+
+ *pNBIOContext = NULL;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED && cert) {
+ checkCertError = pkixErrorResult;
+
+ PKIX_CHECK_FATAL(
+ pkix_AddToVerifyLog(cert, j, checkCertError, pVerifyTree,
+ plContext),
+ PKIX_ADDTOVERIFYLOGFAILED);
+ pkixErrorResult = checkCertError;
+ pkixErrorCode = pkixErrorResult->errCode;
+ checkCertError = NULL;
+ }
+
+fatal:
+ if (nssCert) {
+ CERT_DestroyCertificate(nssCert);
+ }
+
+ if (certList) {
+ CERT_DestroyCertList(certList);
+ }
+
+ PKIX_DECREF(checkCertError);
+ PKIX_DECREF(cert);
+ PKIX_DECREF(issuer);
+
+ PKIX_RETURN(VALIDATE);
+}
+
+/*
+ * FUNCTION: pkix_ExtractParameters
+ * DESCRIPTION:
+ *
+ * Extracts several parameters from the ValidateParams object pointed to by
+ * "valParams" and stores the CertChain at "pChain", the List of Certs at
+ * "pCerts", the number of Certs in the chain at "pNumCerts", the
+ * ProcessingParams object at "pProcParams", the List of TrustAnchors at
+ * "pAnchors", and the number of TrustAnchors at "pNumAnchors".
+ *
+ * PARAMETERS:
+ * "valParams"
+ * Address of ValidateParams from which the parameters are extracted.
+ * Must be non-NULL.
+ * "pCerts"
+ * Address where object pointer for List of Certs will be stored.
+ * Must be non-NULL.
+ * "pNumCerts"
+ * Address where number of Certs will be stored. Must be non-NULL.
+ * "pProcParams"
+ * Address where object pointer for ProcessingParams will be stored.
+ * Must be non-NULL.
+ * "pAnchors"
+ * Address where object pointer for List of Anchors will be stored.
+ * Must be non-NULL.
+ * "pNumAnchors"
+ * Address where number of Anchors 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 Validate 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_ExtractParameters(
+ PKIX_ValidateParams *valParams,
+ PKIX_List **pCerts,
+ PKIX_UInt32 *pNumCerts,
+ PKIX_ProcessingParams **pProcParams,
+ PKIX_List **pAnchors,
+ PKIX_UInt32 *pNumAnchors,
+ void *plContext)
+{
+ PKIX_ENTER(VALIDATE, "pkix_ExtractParameters");
+ PKIX_NULLCHECK_THREE(valParams, pCerts, pNumCerts);
+ PKIX_NULLCHECK_THREE(pProcParams, pAnchors, pNumAnchors);
+
+ /* extract relevant parameters from chain */
+ PKIX_CHECK(PKIX_ValidateParams_GetCertChain
+ (valParams, pCerts, plContext),
+ PKIX_VALIDATEPARAMSGETCERTCHAINFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(*pCerts, pNumCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ /* extract relevant parameters from procParams */
+ PKIX_CHECK(PKIX_ValidateParams_GetProcessingParams
+ (valParams, pProcParams, plContext),
+ PKIX_VALIDATEPARAMSGETPROCESSINGPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetTrustAnchors
+ (*pProcParams, pAnchors, plContext),
+ PKIX_PROCESSINGPARAMSGETTRUSTANCHORSFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(*pAnchors, pNumAnchors, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+cleanup:
+
+ PKIX_RETURN(VALIDATE);
+}
+
+/* --Public-Functions--------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_ValidateChain (see comments in pkix.h)
+ */
+PKIX_Error *
+PKIX_ValidateChain(
+ PKIX_ValidateParams *valParams,
+ PKIX_ValidateResult **pResult,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext)
+{
+ PKIX_Error *chainFailed = NULL;
+
+ PKIX_ProcessingParams *procParams = NULL;
+ PKIX_CertChainChecker *userChecker = NULL;
+ PKIX_RevocationChecker *revChecker = NULL;
+ PKIX_List *certs = NULL;
+ PKIX_List *checkers = NULL;
+ PKIX_List *anchors = NULL;
+ PKIX_List *userCheckers = NULL;
+ PKIX_List *userCheckerExtOIDs = NULL;
+ PKIX_List *validateCheckedCritExtOIDsList = NULL;
+ PKIX_TrustAnchor *anchor = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_PL_PublicKey *finalPubKey = NULL;
+ PKIX_PolicyNode *validPolicyTree = NULL;
+ PKIX_Boolean supportForwarding = PKIX_FALSE;
+ PKIX_Boolean revChecking = PKIX_FALSE;
+ PKIX_UInt32 i, numCerts, numAnchors;
+ PKIX_UInt32 numUserCheckers = 0;
+ PKIX_UInt32 certCheckedIndex = 0;
+ PKIX_UInt32 checkerIndex = 0;
+ PKIX_UInt32 reasonCode = 0;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(VALIDATE, "PKIX_ValidateChain");
+ PKIX_NULLCHECK_TWO(valParams, pResult);
+
+ /* extract various parameters from valParams */
+ PKIX_CHECK(pkix_ExtractParameters
+ (valParams,
+ &certs,
+ &numCerts,
+ &procParams,
+ &anchors,
+ &numAnchors,
+ plContext),
+ PKIX_EXTRACTPARAMETERSFAILED);
+
+ /*
+ * setup an extension OID list that user had defined for his checker
+ * processing. User checker is not responsible for taking out OIDs
+ * from unresolved critical extension list as the libpkix checker
+ * is doing. Here we add those user checkers' OIDs to the removal
+ * list to be taken out by CheckChain
+ */
+ PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers
+ (procParams, &userCheckers, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED);
+
+ if (userCheckers != NULL) {
+
+ PKIX_CHECK(PKIX_List_Create
+ (&validateCheckedCritExtOIDsList,
+ plContext),
+ PKIX_LISTCREATEFAILED);
+
+ 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, &supportForwarding, plContext),
+ PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED);
+
+ if (supportForwarding == PKIX_FALSE) {
+
+ PKIX_CHECK
+ (PKIX_CertChainChecker_GetSupportedExtensions
+ (userChecker, &userCheckerExtOIDs, plContext),
+ PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
+
+ if (userCheckerExtOIDs != NULL) {
+ PKIX_CHECK(pkix_List_AppendList
+ (validateCheckedCritExtOIDsList,
+ userCheckerExtOIDs,
+ plContext),
+ PKIX_LISTAPPENDLISTFAILED);
+ }
+ }
+
+ PKIX_DECREF(userCheckerExtOIDs);
+ PKIX_DECREF(userChecker);
+ }
+ }
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker
+ (procParams, &revChecker, plContext),
+ PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED);
+
+ /* try to validate the chain with each anchor */
+ for (i = 0; i < numAnchors; i++){
+
+ /* get trust anchor */
+ PKIX_CHECK(PKIX_List_GetItem
+ (anchors, i, (PKIX_PL_Object **)&anchor, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* initialize checkers using information from trust anchor */
+ PKIX_CHECK(pkix_InitializeCheckers
+ (anchor, procParams, numCerts, &checkers, plContext),
+ PKIX_INITIALIZECHECKERSFAILED);
+
+ /*
+ * Validate the chain using this trust anchor and these
+ * checkers. (WARNING: checkers that use non-blocking I/O
+ * are not currently supported.)
+ */
+ certCheckedIndex = 0;
+ checkerIndex = 0;
+ revChecking = PKIX_FALSE;
+ chainFailed = pkix_CheckChain
+ (certs,
+ numCerts,
+ anchor,
+ checkers,
+ revChecker,
+ validateCheckedCritExtOIDsList,
+ procParams,
+ &certCheckedIndex,
+ &checkerIndex,
+ &revChecking,
+ &reasonCode,
+ &nbioContext,
+ &finalPubKey,
+ &validPolicyTree,
+ pVerifyTree,
+ plContext);
+
+ if (chainFailed) {
+
+ /* cert chain failed to validate */
+
+ PKIX_DECREF(chainFailed);
+ PKIX_DECREF(anchor);
+ PKIX_DECREF(checkers);
+ PKIX_DECREF(validPolicyTree);
+
+ /* if last anchor, we fail; else, we try next anchor */
+ if (i == (numAnchors - 1)) { /* last anchor */
+ PKIX_ERROR(PKIX_VALIDATECHAINFAILED);
+ }
+
+ } else {
+
+ /* XXX Remove this assertion after 2014-12-31.
+ * See bug 946984. */
+ PORT_Assert(reasonCode == 0);
+
+ /* cert chain successfully validated! */
+ PKIX_CHECK(pkix_ValidateResult_Create
+ (finalPubKey,
+ anchor,
+ validPolicyTree,
+ &valResult,
+ plContext),
+ PKIX_VALIDATERESULTCREATEFAILED);
+
+ *pResult = valResult;
+
+ /* no need to try any more anchors in the loop */
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ PKIX_DECREF(finalPubKey);
+ PKIX_DECREF(certs);
+ PKIX_DECREF(anchors);
+ PKIX_DECREF(anchor);
+ PKIX_DECREF(checkers);
+ PKIX_DECREF(revChecker);
+ PKIX_DECREF(validPolicyTree);
+ PKIX_DECREF(chainFailed);
+ PKIX_DECREF(procParams);
+ PKIX_DECREF(userCheckers);
+ PKIX_DECREF(validateCheckedCritExtOIDsList);
+
+ PKIX_RETURN(VALIDATE);
+}
+
+/*
+ * FUNCTION: pkix_Validate_BuildUserOIDs
+ * DESCRIPTION:
+ *
+ * This function creates a List of the OIDs that are processed by the user
+ * checkers in the List pointed to by "userCheckers", storing the resulting
+ * List at "pUserCritOIDs". If the List of userCheckers is NULL, the output
+ * List will be NULL. Otherwise the output List will be non-NULL, but may be
+ * empty.
+ *
+ * PARAMETERS:
+ * "userCheckers"
+ * The address of the List of userCheckers.
+ * "pUserCritOIDs"
+ * The address at which the 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 VALIDATE 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_Validate_BuildUserOIDs(
+ PKIX_List *userCheckers,
+ PKIX_List **pUserCritOIDs,
+ void *plContext)
+{
+ PKIX_UInt32 numUserCheckers = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_List *userCritOIDs = NULL;
+ PKIX_List *userCheckerExtOIDs = NULL;
+ PKIX_Boolean supportForwarding = PKIX_FALSE;
+ PKIX_CertChainChecker *userChecker = NULL;
+
+ PKIX_ENTER(VALIDATE, "pkix_Validate_BuildUserOIDs");
+ PKIX_NULLCHECK_ONE(pUserCritOIDs);
+
+ if (userCheckers != NULL) {
+ PKIX_CHECK(PKIX_List_Create(&userCritOIDs, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ 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, &supportForwarding, plContext),
+ PKIX_CERTCHAINCHECKERISFORWARDCHECKINGSUPPORTEDFAILED);
+
+ if (supportForwarding == PKIX_FALSE) {
+
+ PKIX_CHECK(PKIX_CertChainChecker_GetSupportedExtensions
+ (userChecker, &userCheckerExtOIDs, plContext),
+ PKIX_CERTCHAINCHECKERGETSUPPORTEDEXTENSIONSFAILED);
+
+ if (userCheckerExtOIDs != NULL) {
+ PKIX_CHECK(pkix_List_AppendList
+ (userCritOIDs, userCheckerExtOIDs, plContext),
+ PKIX_LISTAPPENDLISTFAILED);
+ }
+ }
+
+ PKIX_DECREF(userCheckerExtOIDs);
+ PKIX_DECREF(userChecker);
+ }
+ }
+
+ *pUserCritOIDs = userCritOIDs;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(userCritOIDs);
+ }
+
+ PKIX_DECREF(userCheckerExtOIDs);
+ PKIX_DECREF(userChecker);
+
+ PKIX_RETURN(VALIDATE);
+}
+
+/*
+ * FUNCTION: PKIX_ValidateChain_nb (see comments in pkix.h)
+ */
+PKIX_Error *
+PKIX_ValidateChain_NB(
+ PKIX_ValidateParams *valParams,
+ PKIX_UInt32 *pCertIndex,
+ PKIX_UInt32 *pAnchorIndex,
+ PKIX_UInt32 *pCheckerIndex,
+ PKIX_Boolean *pRevChecking,
+ PKIX_List **pCheckers,
+ void **pNBIOContext,
+ PKIX_ValidateResult **pResult,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext)
+{
+ PKIX_UInt32 numCerts = 0;
+ PKIX_UInt32 numAnchors = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 certIndex = 0;
+ PKIX_UInt32 anchorIndex = 0;
+ PKIX_UInt32 checkerIndex = 0;
+ PKIX_UInt32 reasonCode = 0;
+ PKIX_Boolean revChecking = PKIX_FALSE;
+ PKIX_List *certs = NULL;
+ PKIX_List *anchors = NULL;
+ PKIX_List *checkers = NULL;
+ PKIX_List *userCheckers = NULL;
+ PKIX_List *validateCheckedCritExtOIDsList = NULL;
+ PKIX_TrustAnchor *anchor = NULL;
+ PKIX_ValidateResult *valResult = NULL;
+ PKIX_PL_PublicKey *finalPubKey = NULL;
+ PKIX_PolicyNode *validPolicyTree = NULL;
+ PKIX_ProcessingParams *procParams = NULL;
+ PKIX_RevocationChecker *revChecker = NULL;
+ PKIX_Error *chainFailed = NULL;
+ void *nbioContext = NULL;
+
+ PKIX_ENTER(VALIDATE, "PKIX_ValidateChain_NB");
+ PKIX_NULLCHECK_FOUR
+ (valParams, pCertIndex, pAnchorIndex, pCheckerIndex);
+ PKIX_NULLCHECK_FOUR(pRevChecking, pCheckers, pNBIOContext, pResult);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ /* extract various parameters from valParams */
+ PKIX_CHECK(pkix_ExtractParameters
+ (valParams,
+ &certs,
+ &numCerts,
+ &procParams,
+ &anchors,
+ &numAnchors,
+ plContext),
+ PKIX_EXTRACTPARAMETERSFAILED);
+
+ /*
+ * Create a List of the OIDs that will be processed by the user
+ * checkers. User checkers are not responsible for removing OIDs from
+ * the List of unresolved critical extensions, as libpkix checkers are.
+ * So we add those user checkers' OIDs to the removal list to be taken
+ * out by CheckChain.
+ */
+ PKIX_CHECK(PKIX_ProcessingParams_GetCertChainCheckers
+ (procParams, &userCheckers, plContext),
+ PKIX_PROCESSINGPARAMSGETCERTCHAINCHECKERSFAILED);
+
+ PKIX_CHECK(pkix_Validate_BuildUserOIDs
+ (userCheckers, &validateCheckedCritExtOIDsList, plContext),
+ PKIX_VALIDATEBUILDUSEROIDSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_GetRevocationChecker
+ (procParams, &revChecker, plContext),
+ PKIX_PROCESSINGPARAMSGETREVOCATIONCHECKERFAILED);
+
+ /* Are we resuming after a WOULDBLOCK return, or starting anew ? */
+ if (nbioContext != NULL) {
+ /* Resuming */
+ certIndex = *pCertIndex;
+ anchorIndex = *pAnchorIndex;
+ checkerIndex = *pCheckerIndex;
+ revChecking = *pRevChecking;
+ checkers = *pCheckers;
+ *pCheckers = NULL;
+ }
+
+ /* try to validate the chain with each anchor */
+ for (i = anchorIndex; i < numAnchors; i++) {
+
+ /* get trust anchor */
+ PKIX_CHECK(PKIX_List_GetItem
+ (anchors, i, (PKIX_PL_Object **)&anchor, plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* initialize checkers using information from trust anchor */
+ if (nbioContext == NULL) {
+ PKIX_CHECK(pkix_InitializeCheckers
+ (anchor,
+ procParams,
+ numCerts,
+ &checkers,
+ plContext),
+ PKIX_INITIALIZECHECKERSFAILED);
+ }
+
+ /*
+ * Validate the chain using this trust anchor and these
+ * checkers.
+ */
+ chainFailed = pkix_CheckChain
+ (certs,
+ numCerts,
+ anchor,
+ checkers,
+ revChecker,
+ validateCheckedCritExtOIDsList,
+ procParams,
+ &certIndex,
+ &checkerIndex,
+ &revChecking,
+ &reasonCode,
+ &nbioContext,
+ &finalPubKey,
+ &validPolicyTree,
+ pVerifyTree,
+ plContext);
+
+ if (nbioContext != NULL) {
+ *pCertIndex = certIndex;
+ *pAnchorIndex = anchorIndex;
+ *pCheckerIndex = checkerIndex;
+ *pRevChecking = revChecking;
+ PKIX_INCREF(checkers);
+ *pCheckers = checkers;
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ if (chainFailed) {
+
+ /* cert chain failed to validate */
+
+ PKIX_DECREF(chainFailed);
+ PKIX_DECREF(anchor);
+ PKIX_DECREF(checkers);
+ PKIX_DECREF(validPolicyTree);
+
+ /* if last anchor, we fail; else, we try next anchor */
+ if (i == (numAnchors - 1)) { /* last anchor */
+ PKIX_ERROR(PKIX_VALIDATECHAINFAILED);
+ }
+
+ } else {
+
+ /* XXX Remove this assertion after 2014-12-31.
+ * See bug 946984. */
+ PORT_Assert(reasonCode == 0);
+
+ /* cert chain successfully validated! */
+ PKIX_CHECK(pkix_ValidateResult_Create
+ (finalPubKey,
+ anchor,
+ validPolicyTree,
+ &valResult,
+ plContext),
+ PKIX_VALIDATERESULTCREATEFAILED);
+
+ *pResult = valResult;
+
+ /* no need to try any more anchors in the loop */
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ PKIX_DECREF(finalPubKey);
+ PKIX_DECREF(certs);
+ PKIX_DECREF(anchors);
+ PKIX_DECREF(anchor);
+ PKIX_DECREF(checkers);
+ PKIX_DECREF(revChecker);
+ PKIX_DECREF(validPolicyTree);
+ PKIX_DECREF(chainFailed);
+ PKIX_DECREF(procParams);
+ PKIX_DECREF(userCheckers);
+ PKIX_DECREF(validateCheckedCritExtOIDsList);
+
+ PKIX_RETURN(VALIDATE);
+}
diff --git a/security/nss/lib/libpkix/pkix/top/pkix_validate.h b/security/nss/lib/libpkix/pkix/top/pkix_validate.h
new file mode 100755
index 000000000..7692e3bab
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/pkix_validate.h
@@ -0,0 +1,42 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_validate.h
+ *
+ * Header file for validateChain function
+ *
+ */
+
+#ifndef _PKIX_VALIDATE_H
+#define _PKIX_VALIDATE_H
+#include "pkix_tools.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PKIX_Error *
+pkix_CheckChain(
+ PKIX_List *certs,
+ PKIX_UInt32 numCerts,
+ PKIX_TrustAnchor *anchor,
+ PKIX_List *checkers,
+ PKIX_RevocationChecker *revChecker,
+ PKIX_List *buildCheckedExtOIDs,
+ PKIX_ProcessingParams *procParams,
+ PKIX_UInt32 *pCertCheckedIndex,
+ PKIX_UInt32 *pCheckerIndex,
+ PKIX_Boolean *pRevChecking,
+ PKIX_UInt32 *pReasonCode,
+ void **pNBIOContext,
+ PKIX_PL_PublicKey **pFinalSubjPubKey,
+ PKIX_PolicyNode **pPolicyTree,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_VALIDATE_H */
diff --git a/security/nss/lib/libpkix/pkix/top/top.gyp b/security/nss/lib/libpkix/pkix/top/top.gyp
new file mode 100644
index 000000000..fb1b08ecb
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix/top/top.gyp
@@ -0,0 +1,25 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pkixtop',
+ 'type': 'static_library',
+ 'sources': [
+ 'pkix_build.c',
+ 'pkix_lifecycle.c',
+ 'pkix_validate.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file