diff nss/lib/libpkix/pkix/top/pkix_validate.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nss/lib/libpkix/pkix/top/pkix_validate.c	Mon Jul 28 10:47:06 2014 +0200
@@ -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);
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)