diff nss/lib/libpkix/pkix/checker/pkix_policychecker.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/checker/pkix_policychecker.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,2783 @@
+/* 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_policychecker.c
+ *
+ * Functions for Policy Checker
+ *
+ */
+#include "pkix_policychecker.h"
+
+/* --Forward declarations----------------------------------------------- */
+
+static PKIX_Error *
+pkix_PolicyChecker_MakeSingleton(
+        PKIX_PL_Object *listItem,
+        PKIX_Boolean immutability,
+        PKIX_List **pList,
+        void *plContext);
+
+/* --Private-PolicyCheckerState-Functions---------------------------------- */
+
+/*
+ * FUNCTION:pkix_PolicyCheckerState_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_PolicyCheckerState_Destroy(
+        PKIX_PL_Object *object,
+        void *plContext)
+{
+        PKIX_PolicyCheckerState *checkerState = NULL;
+
+        PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_Destroy");
+        PKIX_NULLCHECK_ONE(object);
+
+        PKIX_CHECK(pkix_CheckType
+                (object, PKIX_CERTPOLICYCHECKERSTATE_TYPE, plContext),
+                PKIX_OBJECTNOTPOLICYCHECKERSTATE);
+
+        checkerState = (PKIX_PolicyCheckerState *)object;
+
+        PKIX_DECREF(checkerState->certPoliciesExtension);
+        PKIX_DECREF(checkerState->policyMappingsExtension);
+        PKIX_DECREF(checkerState->policyConstraintsExtension);
+        PKIX_DECREF(checkerState->inhibitAnyPolicyExtension);
+        PKIX_DECREF(checkerState->anyPolicyOID);
+        PKIX_DECREF(checkerState->validPolicyTree);
+        PKIX_DECREF(checkerState->userInitialPolicySet);
+        PKIX_DECREF(checkerState->mappedUserInitialPolicySet);
+
+        checkerState->policyQualifiersRejected = PKIX_FALSE;
+        checkerState->explicitPolicy = 0;
+        checkerState->inhibitAnyPolicy = 0;
+        checkerState->policyMapping = 0;
+        checkerState->numCerts = 0;
+        checkerState->certsProcessed = 0;
+        checkerState->certPoliciesCritical = PKIX_FALSE;
+
+        PKIX_DECREF(checkerState->anyPolicyNodeAtBottom);
+        PKIX_DECREF(checkerState->newAnyPolicyNode);
+        PKIX_DECREF(checkerState->mappedPolicyOIDs);
+
+cleanup:
+
+        PKIX_RETURN(CERTPOLICYCHECKERSTATE);
+}
+
+/*
+ * FUNCTION: pkix_PolicyCheckerState_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_PolicyCheckerState_ToString(
+        PKIX_PL_Object *object,
+        PKIX_PL_String **pCheckerStateString,
+        void *plContext)
+{
+        PKIX_PolicyCheckerState *state = NULL;
+        PKIX_PL_String *resultString = NULL;
+        PKIX_PL_String *policiesExtOIDString = NULL;
+        PKIX_PL_String *policyMapOIDString = NULL;
+        PKIX_PL_String *policyConstrOIDString = NULL;
+        PKIX_PL_String *inhAnyPolOIDString = NULL;
+        PKIX_PL_String *anyPolicyOIDString = NULL;
+        PKIX_PL_String *validPolicyTreeString = NULL;
+        PKIX_PL_String *userInitialPolicySetString = NULL;
+        PKIX_PL_String *mappedUserPolicySetString = NULL;
+        PKIX_PL_String *mappedPolicyOIDsString = NULL;
+        PKIX_PL_String *anyAtBottomString = NULL;
+        PKIX_PL_String *newAnyPolicyString = NULL;
+        PKIX_PL_String *formatString = NULL;
+        PKIX_PL_String *trueString = NULL;
+        PKIX_PL_String *falseString = NULL;
+        PKIX_PL_String *nullString = NULL;
+        PKIX_Boolean initialPolicyMappingInhibit = PKIX_FALSE;
+        PKIX_Boolean initialExplicitPolicy = PKIX_FALSE;
+        PKIX_Boolean initialAnyPolicyInhibit = PKIX_FALSE;
+        PKIX_Boolean initialIsAnyPolicy = PKIX_FALSE;
+        PKIX_Boolean policyQualifiersRejected = PKIX_FALSE;
+        PKIX_Boolean certPoliciesCritical = PKIX_FALSE;
+        char *asciiFormat =
+                "{\n"
+                "\tcertPoliciesExtension:    \t%s\n"
+                "\tpolicyMappingsExtension:  \t%s\n"
+                "\tpolicyConstraintsExtension:\t%s\n"
+                "\tinhibitAnyPolicyExtension:\t%s\n"
+                "\tanyPolicyOID:             \t%s\n"
+                "\tinitialIsAnyPolicy:       \t%s\n"
+                "\tvalidPolicyTree:          \t%s\n"
+                "\tuserInitialPolicySet:     \t%s\n"
+                "\tmappedUserPolicySet:      \t%s\n"
+                "\tpolicyQualifiersRejected: \t%s\n"
+                "\tinitialPolMappingInhibit: \t%s\n"
+                "\tinitialExplicitPolicy:    \t%s\n"
+                "\tinitialAnyPolicyInhibit:  \t%s\n"
+                "\texplicitPolicy:           \t%d\n"
+                "\tinhibitAnyPolicy:         \t%d\n"
+                "\tpolicyMapping:            \t%d\n"
+                "\tnumCerts:                 \t%d\n"
+                "\tcertsProcessed:           \t%d\n"
+                "\tanyPolicyNodeAtBottom:    \t%s\n"
+                "\tnewAnyPolicyNode:         \t%s\n"
+                "\tcertPoliciesCritical:     \t%s\n"
+                "\tmappedPolicyOIDs:         \t%s\n"
+                "}";
+
+        PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_ToString");
+
+        PKIX_NULLCHECK_TWO(object, pCheckerStateString);
+
+        PKIX_CHECK(pkix_CheckType
+                (object, PKIX_CERTPOLICYCHECKERSTATE_TYPE, plContext),
+                PKIX_OBJECTNOTPOLICYCHECKERSTATE);
+
+        state = (PKIX_PolicyCheckerState *)object;
+        PKIX_NULLCHECK_THREE
+                (state->certPoliciesExtension,
+                state->policyMappingsExtension,
+                state->policyConstraintsExtension);
+        PKIX_NULLCHECK_THREE
+                (state->inhibitAnyPolicyExtension,
+                state->anyPolicyOID,
+                state->userInitialPolicySet);
+
+        PKIX_CHECK(PKIX_PL_String_Create
+                (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
+                PKIX_STRINGCREATEFAILED);
+        /*
+         * Create TRUE, FALSE, and "NULL" PKIX_PL_Strings. But creating a
+         * PKIX_PL_String is complicated enough, it's worth checking, for
+         * each, to make sure the string is needed.
+         */
+        initialPolicyMappingInhibit = state->initialPolicyMappingInhibit;
+        initialExplicitPolicy = state->initialExplicitPolicy;
+        initialAnyPolicyInhibit = state->initialAnyPolicyInhibit;
+        initialIsAnyPolicy = state->initialIsAnyPolicy;
+        policyQualifiersRejected = state->policyQualifiersRejected;
+        certPoliciesCritical = state->certPoliciesCritical;
+
+        if (initialPolicyMappingInhibit || initialExplicitPolicy ||
+            initialAnyPolicyInhibit || initialIsAnyPolicy ||
+            policyQualifiersRejected || certPoliciesCritical) {
+                PKIX_CHECK(PKIX_PL_String_Create
+                        (PKIX_ESCASCII, "TRUE", 0, &trueString, plContext),
+                        PKIX_STRINGCREATEFAILED);
+        }
+        if (!initialPolicyMappingInhibit || !initialExplicitPolicy ||
+            !initialAnyPolicyInhibit || !initialIsAnyPolicy ||
+            !policyQualifiersRejected || !certPoliciesCritical) {
+                PKIX_CHECK(PKIX_PL_String_Create
+                        (PKIX_ESCASCII, "FALSE", 0, &falseString, plContext),
+                        PKIX_STRINGCREATEFAILED);
+        }
+        if (!(state->anyPolicyNodeAtBottom) || !(state->newAnyPolicyNode)) {
+                PKIX_CHECK(PKIX_PL_String_Create
+                        (PKIX_ESCASCII, "(null)", 0, &nullString, plContext),
+                        PKIX_STRINGCREATEFAILED);
+        }
+
+        PKIX_TOSTRING
+                (state->certPoliciesExtension, &policiesExtOIDString, plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING
+                (state->policyMappingsExtension,
+                &policyMapOIDString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING
+                (state->policyConstraintsExtension,
+                &policyConstrOIDString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING
+                (state->inhibitAnyPolicyExtension,
+                &inhAnyPolOIDString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING(state->anyPolicyOID, &anyPolicyOIDString, plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING(state->validPolicyTree, &validPolicyTreeString, plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING
+                (state->userInitialPolicySet,
+                &userInitialPolicySetString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_TOSTRING
+                (state->mappedUserInitialPolicySet,
+                &mappedUserPolicySetString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        if (state->anyPolicyNodeAtBottom) {
+                PKIX_CHECK(pkix_SinglePolicyNode_ToString
+                        (state->anyPolicyNodeAtBottom,
+                        &anyAtBottomString,
+                        plContext),
+                        PKIX_SINGLEPOLICYNODETOSTRINGFAILED);
+        } else {
+                PKIX_INCREF(nullString);
+                anyAtBottomString = nullString;
+        }
+
+        if (state->newAnyPolicyNode) {
+                PKIX_CHECK(pkix_SinglePolicyNode_ToString
+                        (state->newAnyPolicyNode,
+                        &newAnyPolicyString,
+                        plContext),
+                        PKIX_SINGLEPOLICYNODETOSTRINGFAILED);
+        } else {
+                PKIX_INCREF(nullString);
+                newAnyPolicyString = nullString;
+        }
+
+        PKIX_TOSTRING
+                (state->mappedPolicyOIDs,
+                &mappedPolicyOIDsString,
+                plContext,
+                PKIX_OBJECTTOSTRINGFAILED);
+
+        PKIX_CHECK(PKIX_PL_Sprintf
+                (&resultString,
+                plContext,
+                formatString,
+                policiesExtOIDString,
+                policyMapOIDString,
+                policyConstrOIDString,
+                inhAnyPolOIDString,
+                anyPolicyOIDString,
+                initialIsAnyPolicy?trueString:falseString,
+                validPolicyTreeString,
+                userInitialPolicySetString,
+                mappedUserPolicySetString,
+                policyQualifiersRejected?trueString:falseString,
+                initialPolicyMappingInhibit?trueString:falseString,
+                initialExplicitPolicy?trueString:falseString,
+                initialAnyPolicyInhibit?trueString:falseString,
+                state->explicitPolicy,
+                state->inhibitAnyPolicy,
+                state->policyMapping,
+                state->numCerts,
+                state->certsProcessed,
+                anyAtBottomString,
+                newAnyPolicyString,
+                certPoliciesCritical?trueString:falseString,
+                mappedPolicyOIDsString),
+                PKIX_SPRINTFFAILED);
+
+        *pCheckerStateString = resultString;
+
+cleanup:
+        PKIX_DECREF(policiesExtOIDString);
+        PKIX_DECREF(policyMapOIDString);
+        PKIX_DECREF(policyConstrOIDString);
+        PKIX_DECREF(inhAnyPolOIDString);
+        PKIX_DECREF(anyPolicyOIDString);
+        PKIX_DECREF(validPolicyTreeString);
+        PKIX_DECREF(userInitialPolicySetString);
+        PKIX_DECREF(mappedUserPolicySetString);
+        PKIX_DECREF(anyAtBottomString);
+        PKIX_DECREF(newAnyPolicyString);
+        PKIX_DECREF(mappedPolicyOIDsString);
+        PKIX_DECREF(formatString);
+        PKIX_DECREF(trueString);
+        PKIX_DECREF(falseString);
+        PKIX_DECREF(nullString);
+
+        PKIX_RETURN(CERTPOLICYCHECKERSTATE);
+}
+
+/*
+ * FUNCTION: pkix_PolicyCheckerState_RegisterSelf
+ * DESCRIPTION:
+ *
+ *  Registers PKIX_POLICYCHECKERSTATE_TYPE and its related functions
+ *      with systemClasses[]
+ *
+ * PARAMETERS:
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe - for performance and complexity reasons
+ *
+ *  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_PolicyCheckerState_RegisterSelf(void *plContext)
+{
+        extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+        pkix_ClassTable_Entry entry;
+
+        PKIX_ENTER
+                (CERTPOLICYCHECKERSTATE,
+                "pkix_PolicyCheckerState_RegisterSelf");
+
+        entry.description = "PolicyCheckerState";
+        entry.objCounter = 0;
+        entry.typeObjectSize = sizeof(PKIX_PolicyCheckerState);
+        entry.destructor = pkix_PolicyCheckerState_Destroy;
+        entry.equalsFunction = NULL;
+        entry.hashcodeFunction = NULL;
+        entry.toStringFunction = pkix_PolicyCheckerState_ToString;
+        entry.comparator = NULL;
+        entry.duplicateFunction = NULL;
+
+        systemClasses[PKIX_CERTPOLICYCHECKERSTATE_TYPE] = entry;
+
+        PKIX_RETURN(CERTPOLICYCHECKERSTATE);
+}
+
+/*
+ * FUNCTION:pkix_PolicyCheckerState_Create
+ * DESCRIPTION:
+ *
+ *  Creates a PolicyCheckerState Object, using the List pointed to
+ *  by "initialPolicies" for the user-initial-policy-set, the Boolean value
+ *  of "policyQualifiersRejected" for the policyQualifiersRejected parameter,
+ *  the Boolean value of "initialPolicyMappingInhibit" for the
+ *  inhibitPolicyMappings parameter, the Boolean value of
+ *  "initialExplicitPolicy" for the initialExplicitPolicy parameter, the
+ *  Boolean value of "initialAnyPolicyInhibit" for the inhibitAnyPolicy
+ *  parameter, and the UInt32 value of "numCerts" as the number of
+ *  certificates in the chain; and stores the Object at "pCheckerState".
+ *
+ * PARAMETERS:
+ *  "initialPolicies"
+ *      Address of List of OIDs comprising the user-initial-policy-set; the List
+ *      may be empty, but must be non-NULL
+ *  "policyQualifiersRejected"
+ *      Boolean value of the policyQualifiersRejected parameter
+ *  "initialPolicyMappingInhibit"
+ *      Boolean value of the inhibitPolicyMappings parameter
+ *  "initialExplicitPolicy"
+ *      Boolean value of the initialExplicitPolicy parameter
+ *  "initialAnyPolicyInhibit"
+ *      Boolean value of the inhibitAnyPolicy parameter
+ *  "numCerts"
+ *      Number of certificates in the chain to be validated
+ *  "pCheckerState"
+ *      Address where PolicyCheckerState 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 CertPolicyCheckerState Error if the functions fails in a
+ *      non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyCheckerState_Create(
+        PKIX_List *initialPolicies,
+        PKIX_Boolean policyQualifiersRejected,
+        PKIX_Boolean initialPolicyMappingInhibit,
+        PKIX_Boolean initialExplicitPolicy,
+        PKIX_Boolean initialAnyPolicyInhibit,
+        PKIX_UInt32 numCerts,
+        PKIX_PolicyCheckerState **pCheckerState,
+        void *plContext)
+{
+        PKIX_PolicyCheckerState *checkerState = NULL;
+        PKIX_PolicyNode *policyNode = NULL;
+        PKIX_List *anyPolicyList = NULL;
+        PKIX_Boolean initialPoliciesIsEmpty = PKIX_FALSE;
+
+        PKIX_ENTER(CERTPOLICYCHECKERSTATE, "pkix_PolicyCheckerState_Create");
+        PKIX_NULLCHECK_TWO(initialPolicies, pCheckerState);
+
+        PKIX_CHECK(PKIX_PL_Object_Alloc
+                (PKIX_CERTPOLICYCHECKERSTATE_TYPE,
+                sizeof (PKIX_PolicyCheckerState),
+                (PKIX_PL_Object **)&checkerState,
+                plContext),
+                PKIX_COULDNOTCREATEPOLICYCHECKERSTATEOBJECT);
+
+        /* Create constant PKIX_PL_OIDs: */
+
+        PKIX_CHECK(PKIX_PL_OID_Create
+                (PKIX_CERTIFICATEPOLICIES_OID,
+                &(checkerState->certPoliciesExtension),
+                plContext),
+                PKIX_OIDCREATEFAILED);
+
+        PKIX_CHECK(PKIX_PL_OID_Create
+                (PKIX_POLICYMAPPINGS_OID,
+                &(checkerState->policyMappingsExtension),
+                plContext),
+                PKIX_OIDCREATEFAILED);
+
+        PKIX_CHECK(PKIX_PL_OID_Create
+                (PKIX_POLICYCONSTRAINTS_OID,
+                &(checkerState->policyConstraintsExtension),
+                plContext),
+                PKIX_OIDCREATEFAILED);
+
+        PKIX_CHECK(PKIX_PL_OID_Create
+                (PKIX_INHIBITANYPOLICY_OID,
+                &(checkerState->inhibitAnyPolicyExtension),
+                plContext),
+                PKIX_OIDCREATEFAILED);
+
+        PKIX_CHECK(PKIX_PL_OID_Create
+                (PKIX_CERTIFICATEPOLICIES_ANYPOLICY_OID,
+                &(checkerState->anyPolicyOID),
+                plContext),
+                PKIX_OIDCREATEFAILED);
+
+        /* Create an initial policy set from argument supplied */
+        PKIX_INCREF(initialPolicies);
+        checkerState->userInitialPolicySet = initialPolicies;
+        PKIX_INCREF(initialPolicies);
+        checkerState->mappedUserInitialPolicySet = initialPolicies;
+
+        PKIX_CHECK(PKIX_List_IsEmpty
+                (initialPolicies,
+                &initialPoliciesIsEmpty,
+                plContext),
+                PKIX_LISTISEMPTYFAILED);
+        if (initialPoliciesIsEmpty) {
+                checkerState->initialIsAnyPolicy = PKIX_TRUE;
+        } else {
+                PKIX_CHECK(pkix_List_Contains
+                        (initialPolicies,
+                        (PKIX_PL_Object *)(checkerState->anyPolicyOID),
+                        &(checkerState->initialIsAnyPolicy),
+                        plContext),
+                        PKIX_LISTCONTAINSFAILED);
+        }
+
+        checkerState->policyQualifiersRejected =
+                policyQualifiersRejected;
+        checkerState->initialExplicitPolicy = initialExplicitPolicy;
+        checkerState->explicitPolicy =
+                (initialExplicitPolicy? 0: numCerts + 1);
+        checkerState->initialAnyPolicyInhibit = initialAnyPolicyInhibit;
+        checkerState->inhibitAnyPolicy =
+                (initialAnyPolicyInhibit? 0: numCerts + 1);
+        checkerState->initialPolicyMappingInhibit = initialPolicyMappingInhibit;
+        checkerState->policyMapping =
+                (initialPolicyMappingInhibit? 0: numCerts + 1);
+                ;
+        checkerState->numCerts = numCerts;
+        checkerState->certsProcessed = 0;
+        checkerState->certPoliciesCritical = PKIX_FALSE;
+
+        /* Create a valid_policy_tree as in RFC3280 6.1.2(a) */
+        PKIX_CHECK(pkix_PolicyChecker_MakeSingleton
+                ((PKIX_PL_Object *)(checkerState->anyPolicyOID),
+                PKIX_TRUE,
+                &anyPolicyList,
+                plContext),
+                PKIX_POLICYCHECKERMAKESINGLETONFAILED);
+
+        PKIX_CHECK(pkix_PolicyNode_Create
+                (checkerState->anyPolicyOID,    /* validPolicy */
+                NULL,                           /* qualifier set */
+                PKIX_FALSE,                     /* criticality */
+                anyPolicyList,                  /* expectedPolicySet */
+                &policyNode,
+                plContext),
+                PKIX_POLICYNODECREATEFAILED);
+        checkerState->validPolicyTree = policyNode;
+
+        /*
+         * Since the initial validPolicyTree specifies
+         * ANY_POLICY, begin with a pointer to the root node.
+         */
+        PKIX_INCREF(policyNode);
+        checkerState->anyPolicyNodeAtBottom = policyNode;
+
+        checkerState->newAnyPolicyNode = NULL;
+
+        checkerState->mappedPolicyOIDs = NULL;
+
+        *pCheckerState = checkerState;
+        checkerState = NULL;
+
+cleanup:
+
+        PKIX_DECREF(checkerState);
+
+        PKIX_DECREF(anyPolicyList);
+
+        PKIX_RETURN(CERTPOLICYCHECKERSTATE);
+}
+
+/* --Private-PolicyChecker-Functions--------------------------------------- */
+
+/*
+ * FUNCTION: pkix_PolicyChecker_MapContains
+ * DESCRIPTION:
+ *
+ *  Checks the List of CertPolicyMaps pointed to by "certPolicyMaps", to
+ *  determine whether the OID pointed to by "policy" is among the
+ *  issuerDomainPolicies or subjectDomainPolicies of "certPolicyMaps", and
+ *  stores the result in "pFound".
+ *
+ *  This function is intended to allow an efficient check that the proscription
+ *  against anyPolicy being mapped, described in RFC3280 Section 6.1.4(a), is
+ *  not violated.
+ *
+ * PARAMETERS:
+ *  "certPolicyMaps"
+ *      Address of List of CertPolicyMaps to be searched. May be empty, but
+ *      must be non-NULL
+ *  "policy"
+ *      Address of OID to be checked for. Must be non-NULL
+ *  "pFound"
+ *      Address where the result of the search 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 CertChainChecker 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_PolicyChecker_MapContains(
+        PKIX_List *certPolicyMaps,
+        PKIX_PL_OID *policy,
+        PKIX_Boolean *pFound,
+        void *plContext)
+{
+        PKIX_PL_CertPolicyMap *map = NULL;
+        PKIX_UInt32 numEntries = 0;
+        PKIX_UInt32 index = 0;
+        PKIX_Boolean match = PKIX_FALSE;
+        PKIX_PL_OID *issuerDomainPolicy = NULL;
+        PKIX_PL_OID *subjectDomainPolicy = NULL;
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MapContains");
+        PKIX_NULLCHECK_THREE(certPolicyMaps, policy, pFound);
+
+        PKIX_CHECK(PKIX_List_GetLength(certPolicyMaps, &numEntries, plContext),
+                PKIX_LISTGETLENGTHFAILED);
+
+        for (index = 0; (!match) && (index < numEntries); index++) {
+                PKIX_CHECK(PKIX_List_GetItem
+                    (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext),
+                    PKIX_LISTGETITEMFAILED);
+
+                PKIX_NULLCHECK_ONE(map);
+
+                PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy
+                        (map, &issuerDomainPolicy, plContext),
+                        PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED);
+
+                PKIX_EQUALS
+                        (policy, issuerDomainPolicy, &match, plContext,
+                        PKIX_OBJECTEQUALSFAILED);
+
+                if (!match) {
+                        PKIX_CHECK(PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy
+                                (map, &subjectDomainPolicy, plContext),
+                                PKIX_CERTPOLICYMAPGETSUBJECTDOMAINPOLICYFAILED);
+
+                        PKIX_EQUALS
+                                (policy, subjectDomainPolicy, &match, plContext,
+                                PKIX_OBJECTEQUALSFAILED);
+                }
+
+                PKIX_DECREF(map);
+                PKIX_DECREF(issuerDomainPolicy);
+                PKIX_DECREF(subjectDomainPolicy);
+        }
+
+        *pFound = match;
+
+cleanup:
+
+        PKIX_DECREF(map);
+        PKIX_DECREF(issuerDomainPolicy);
+        PKIX_DECREF(subjectDomainPolicy);
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_MapGetSubjectDomainPolicies
+ * DESCRIPTION:
+ *
+ *  Checks the List of CertPolicyMaps pointed to by "certPolicyMaps", to create
+ *  a list of all SubjectDomainPolicies for which the IssuerDomainPolicy is the
+ *  policy pointed to by "policy", and stores the result in
+ *  "pSubjectDomainPolicies".
+ *
+ *  If the List of CertPolicyMaps provided in "certPolicyMaps" is NULL, the
+ *  resulting List will be NULL. If there are CertPolicyMaps, but none that
+ *  include "policy" as an IssuerDomainPolicy, the returned List pointer will
+ *  be NULL. Otherwise, the returned List will contain the SubjectDomainPolicies
+ *  of all CertPolicyMaps for which "policy" is the IssuerDomainPolicy. If a
+ *  List is returned it will be immutable.
+ *
+ * PARAMETERS:
+ *  "certPolicyMaps"
+ *      Address of List of CertPolicyMaps to be searched. May be empty or NULL.
+ *  "policy"
+ *      Address of OID to be checked for. Must be non-NULL
+ *  "pSubjectDomainPolicies"
+ *      Address where the result of the search 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 CertChainChecker 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_PolicyChecker_MapGetSubjectDomainPolicies(
+        PKIX_List *certPolicyMaps,
+        PKIX_PL_OID *policy,
+        PKIX_List **pSubjectDomainPolicies,
+        void *plContext)
+{
+        PKIX_PL_CertPolicyMap *map = NULL;
+        PKIX_List *subjectList = NULL;
+        PKIX_UInt32 numEntries = 0;
+        PKIX_UInt32 index = 0;
+        PKIX_Boolean match = PKIX_FALSE;
+        PKIX_PL_OID *issuerDomainPolicy = NULL;
+        PKIX_PL_OID *subjectDomainPolicy = NULL;
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER,
+                "pkix_PolicyChecker_MapGetSubjectDomainPolicies");
+        PKIX_NULLCHECK_TWO(policy, pSubjectDomainPolicies);
+
+        if (certPolicyMaps) {
+                PKIX_CHECK(PKIX_List_GetLength
+                    (certPolicyMaps,
+                    &numEntries,
+                    plContext),
+                    PKIX_LISTGETLENGTHFAILED);
+        }
+
+        for (index = 0; index < numEntries; index++) {
+                PKIX_CHECK(PKIX_List_GetItem
+                    (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext),
+                    PKIX_LISTGETITEMFAILED);
+
+                PKIX_NULLCHECK_ONE(map);
+
+                PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy
+                        (map, &issuerDomainPolicy, plContext),
+                        PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED);
+
+                PKIX_EQUALS
+                    (policy, issuerDomainPolicy, &match, plContext,
+                    PKIX_OBJECTEQUALSFAILED);
+
+                if (match) {
+                    if (!subjectList) {
+                        PKIX_CHECK(PKIX_List_Create(&subjectList, plContext),
+                                PKIX_LISTCREATEFAILED);
+                    }
+
+                    PKIX_CHECK(PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy
+                        (map, &subjectDomainPolicy, plContext),
+                        PKIX_CERTPOLICYMAPGETSUBJECTDOMAINPOLICYFAILED);
+
+                    PKIX_CHECK(PKIX_List_AppendItem
+                        (subjectList,
+                        (PKIX_PL_Object *)subjectDomainPolicy,
+                        plContext),
+                        PKIX_LISTAPPENDITEMFAILED);
+                }
+
+                PKIX_DECREF(map);
+                PKIX_DECREF(issuerDomainPolicy);
+                PKIX_DECREF(subjectDomainPolicy);
+        }
+
+        if (subjectList) {
+                PKIX_CHECK(PKIX_List_SetImmutable(subjectList, plContext),
+                        PKIX_LISTSETIMMUTABLEFAILED);
+        }
+
+        *pSubjectDomainPolicies = subjectList;
+
+cleanup:
+
+        if (PKIX_ERROR_RECEIVED) {
+                PKIX_DECREF(subjectList);
+        }
+
+        PKIX_DECREF(map);
+        PKIX_DECREF(issuerDomainPolicy);
+        PKIX_DECREF(subjectDomainPolicy);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_MapGetMappedPolicies
+ * DESCRIPTION:
+ *
+ *  Checks the List of CertPolicyMaps pointed to by "certPolicyMaps" to create a
+ *  List of all IssuerDomainPolicies, and stores the result in
+ * "pMappedPolicies".
+ *
+ *  The caller may not rely on the IssuerDomainPolicies to be in any particular
+ *  order. IssuerDomainPolicies that appear in more than one CertPolicyMap will
+ *  only appear once in "pMappedPolicies". If "certPolicyMaps" is empty the
+ *  result will be an empty List. The created List is mutable.
+ *
+ * PARAMETERS:
+ *  "certPolicyMaps"
+ *      Address of List of CertPolicyMaps to be searched. May be empty, but
+ *      must be non-NULL.
+ *  "pMappedPolicies"
+ *      Address where the result 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 CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+PKIX_Error *
+pkix_PolicyChecker_MapGetMappedPolicies(
+        PKIX_List *certPolicyMaps,
+        PKIX_List **pMappedPolicies,
+        void *plContext)
+{
+        PKIX_PL_CertPolicyMap *map = NULL;
+        PKIX_List *mappedList = NULL;
+        PKIX_UInt32 numEntries = 0;
+        PKIX_UInt32 index = 0;
+        PKIX_Boolean isContained = PKIX_FALSE;
+        PKIX_PL_OID *issuerDomainPolicy = NULL;
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER, "pkix_PolicyChecker_MapGetMappedPolicies");
+        PKIX_NULLCHECK_TWO(certPolicyMaps, pMappedPolicies);
+
+        PKIX_CHECK(PKIX_List_Create(&mappedList, plContext),
+                PKIX_LISTCREATEFAILED);
+
+        PKIX_CHECK(PKIX_List_GetLength(certPolicyMaps, &numEntries, plContext),
+                PKIX_LISTGETLENGTHFAILED);
+
+        for (index = 0; index < numEntries; index++) {
+                PKIX_CHECK(PKIX_List_GetItem
+                    (certPolicyMaps, index, (PKIX_PL_Object **)&map, plContext),
+                    PKIX_LISTGETITEMFAILED);
+
+                PKIX_NULLCHECK_ONE(map);
+
+                PKIX_CHECK(PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy
+                        (map, &issuerDomainPolicy, plContext),
+                        PKIX_CERTPOLICYMAPGETISSUERDOMAINPOLICYFAILED);
+
+                PKIX_CHECK(pkix_List_Contains
+                        (mappedList,
+                        (PKIX_PL_Object *)issuerDomainPolicy,
+                        &isContained,
+                        plContext),
+                        PKIX_LISTCONTAINSFAILED);
+
+                if (isContained == PKIX_FALSE) {
+                        PKIX_CHECK(PKIX_List_AppendItem
+                                (mappedList,
+                                (PKIX_PL_Object *)issuerDomainPolicy,
+                                plContext),
+                                PKIX_LISTAPPENDITEMFAILED);
+                }
+
+                PKIX_DECREF(map);
+                PKIX_DECREF(issuerDomainPolicy);
+        }
+
+        *pMappedPolicies = mappedList;
+
+cleanup:
+
+        if (PKIX_ERROR_RECEIVED) {
+                PKIX_DECREF(mappedList);
+        }
+
+        PKIX_DECREF(map);
+        PKIX_DECREF(issuerDomainPolicy);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_MakeMutableCopy
+ * DESCRIPTION:
+ *
+ *  Creates a mutable copy of the List pointed to by "list", which may or may
+ *  not be immutable, and stores the address at "pMutableCopy".
+ *
+ * PARAMETERS:
+ *  "list"
+ *      Address of List to be copied. Must be non-NULL.
+ *  "pMutableCopy"
+ *      Address where mutable copy 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 CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_MakeMutableCopy(
+        PKIX_List *list,
+        PKIX_List **pMutableCopy,
+        void *plContext)
+{
+        PKIX_List *newList = NULL;
+        PKIX_UInt32 listLen = 0;
+        PKIX_UInt32 listIx = 0;
+        PKIX_PL_Object *object = NULL;
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MakeMutableCopy");
+        PKIX_NULLCHECK_TWO(list, pMutableCopy);
+
+        PKIX_CHECK(PKIX_List_Create(&newList, plContext),
+                PKIX_LISTCREATEFAILED);
+
+        PKIX_CHECK(PKIX_List_GetLength(list, &listLen, plContext),
+                PKIX_LISTGETLENGTHFAILED);
+
+        for (listIx = 0; listIx < listLen; listIx++) {
+
+                PKIX_CHECK(PKIX_List_GetItem(list, listIx, &object, plContext),
+                        PKIX_LISTGETITEMFAILED);
+
+                PKIX_CHECK(PKIX_List_AppendItem(newList, object, plContext),
+                        PKIX_LISTAPPENDITEMFAILED);
+
+                PKIX_DECREF(object);
+        }
+
+        *pMutableCopy = newList;
+        newList = NULL;
+        
+cleanup:
+        PKIX_DECREF(newList);
+        PKIX_DECREF(object);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_MakeSingleton
+ * DESCRIPTION:
+ *
+ *  Creates a new List containing the Object pointed to by "listItem", using
+ *  the Boolean value of "immutability" to determine whether to set the List
+ *  immutable, and stores the address at "pList".
+ *
+ * PARAMETERS:
+ *  "listItem"
+ *      Address of Object to be inserted into the new List. Must be non-NULL.
+ *  "immutability"
+ *      Boolean value indicating whether new List is to be immutable
+ *  "pList"
+ *      Address where List 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 CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_MakeSingleton(
+        PKIX_PL_Object *listItem,
+        PKIX_Boolean immutability,
+        PKIX_List **pList,
+        void *plContext)
+{
+        PKIX_List *newList = NULL;
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_MakeSingleton");
+        PKIX_NULLCHECK_TWO(listItem, pList);
+
+        PKIX_CHECK(PKIX_List_Create(&newList, plContext),
+                PKIX_LISTCREATEFAILED);
+
+        PKIX_CHECK(PKIX_List_AppendItem
+                (newList, (PKIX_PL_Object *)listItem, plContext),
+                PKIX_LISTAPPENDITEMFAILED);
+
+        if (immutability) {
+                PKIX_CHECK(PKIX_List_SetImmutable(newList, plContext),
+                        PKIX_LISTSETIMMUTABLEFAILED);
+        }
+
+        *pList = newList;
+
+cleanup:
+        if (PKIX_ERROR_RECEIVED) {
+                PKIX_DECREF(newList);
+        }
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_Spawn
+ * DESCRIPTION:
+ *
+ *  Creates a new childNode for the parent pointed to by "parent", using
+ *  the OID pointed to by "policyOID", the List of CertPolicyQualifiers
+ *  pointed to by "qualifiers", the List of OIDs pointed to by
+ *  "subjectDomainPolicies", and the PolicyCheckerState pointed to by
+ *  "state". The new node will be added to "parent".
+ *
+ *  The validPolicy of the new node is set from the OID pointed to by
+ *  "policyOID". The policy qualifiers for the new node is set from the
+ *  List of qualifiers pointed to by "qualifiers", and may be NULL or
+ *  empty if the argument provided was NULL or empty. The criticality is
+ *  set according to the criticality obtained from the PolicyCheckerState.
+ *  If "subjectDomainPolicies" is NULL, the expectedPolicySet of the
+ *  child is set to contain the same policy as the validPolicy. If
+ *  "subjectDomainPolicies" is not NULL, it is used as the value for
+ *  the expectedPolicySet.
+ *
+ *  The PolicyCheckerState also contains a constant, anyPolicy, which is
+ *  compared to "policyOID". If they match, the address of the childNode
+ * is saved in the state's newAnyPolicyNode.
+ *
+ * PARAMETERS:
+ *  "parent"
+ *      Address of PolicyNode to which the child will be linked. Must be
+ *      non-NULL.
+ *  "policyOID"
+ *      Address of OID of the new child's validPolicy and also, if
+ *      subjectDomainPolicies is NULL, of the new child's expectedPolicySet.
+ *      Must be non-NULL.
+ *  "qualifiers"
+ *      Address of List of CertPolicyQualifiers. May be NULL or empty.
+ *  "subjectDomainPolicies"
+ *      Address of List of OIDs indicating the policies to which "policy" is
+ *      mapped. May be empty or NULL.
+ *  "state"
+ *      Address of the current PKIX_PolicyCheckerState. Must be non-NULL..
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_Spawn(
+        PKIX_PolicyNode *parent,
+        PKIX_PL_OID *policyOID,
+        PKIX_List *qualifiers,  /* CertPolicyQualifiers */
+        PKIX_List *subjectDomainPolicies,
+        PKIX_PolicyCheckerState *state,
+        void *plContext)
+{
+        PKIX_List *expectedSet = NULL; /* OIDs */
+        PKIX_PolicyNode *childNode = NULL;
+        PKIX_Boolean match = PKIX_FALSE;
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Spawn");
+        PKIX_NULLCHECK_THREE(policyOID, parent, state);
+
+        if (subjectDomainPolicies) {
+
+                PKIX_INCREF(subjectDomainPolicies);
+                expectedSet = subjectDomainPolicies;
+
+        } else {
+                /* Create the child's ExpectedPolicy Set */
+                PKIX_CHECK(pkix_PolicyChecker_MakeSingleton
+                        ((PKIX_PL_Object *)policyOID,
+                        PKIX_TRUE,      /* make expectedPolicySet immutable */
+                        &expectedSet,
+                        plContext),
+                        PKIX_POLICYCHECKERMAKESINGLETONFAILED);
+        }
+
+        PKIX_CHECK(pkix_PolicyNode_Create
+                (policyOID,
+                qualifiers,
+                state->certPoliciesCritical,
+                expectedSet,
+                &childNode,
+                plContext),
+                PKIX_POLICYNODECREATEFAILED);
+
+        /*
+         * If we had a non-empty mapping, we know the new node could not
+         * have been created with a validPolicy of anyPolicy. Otherwise,
+         * check whether we just created a new node with anyPolicy, because
+         * in that case we want to save the child pointer in newAnyPolicyNode.
+         */
+        if (!subjectDomainPolicies) {
+                PKIX_EQUALS(policyOID, state->anyPolicyOID, &match, plContext,
+                        PKIX_OBJECTEQUALSFAILED);
+
+                if (match) {
+                        PKIX_DECREF(state->newAnyPolicyNode);
+                        PKIX_INCREF(childNode);
+                        state->newAnyPolicyNode = childNode;
+                }
+        }
+
+        PKIX_CHECK(pkix_PolicyNode_AddToParent(parent, childNode, plContext),
+                PKIX_POLICYNODEADDTOPARENTFAILED);
+
+        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                ((PKIX_PL_Object *)state, plContext),
+                PKIX_OBJECTINVALIDATECACHEFAILED);
+
+cleanup:
+        PKIX_DECREF(childNode);
+        PKIX_DECREF(expectedSet);
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_CheckPolicyRecursive
+ * DESCRIPTION:
+ *
+ *  Performs policy processing for the policy whose OID is pointed to by
+ *  "policyOID" and whose List of CertPolicyQualifiers is pointed to by
+ *  "policyQualifiers", using the List of policy OIDs pointed to by
+ *  "subjectDomainPolicies" and the PolicyNode pointed to by "currentNode",
+ *  in accordance with the current PolicyCheckerState pointed to by "state",
+ *  and setting "pChildNodeCreated" to TRUE if a new childNode is created.
+ *  Note: "pChildNodeCreated" is not set to FALSE if no childNode is created.
+ *  The intent of the design is that the caller can set a variable to FALSE
+ *  initially, prior to a recursive set of calls. At the end, the variable
+ *  can be tested to see whether *any* of the calls created a child node.
+ *
+ *  If the currentNode is not at the bottom of the tree, this function
+ *  calls itself recursively for each child of currentNode. At the bottom of
+ *  the tree, it creates new child nodes as appropriate. This function will
+ *  never be called with policy = anyPolicy.
+ *
+ *  This function implements the processing described in RFC3280
+ *  Section 6.1.3(d)(1)(i).
+ *
+ * PARAMETERS:
+ *  "policyOID"
+ *      Address of OID of the policy to be checked for. Must be non-NULL.
+ *  "policyQualifiers"
+ *      Address of List of CertPolicyQualifiers of the policy to be checked for.
+ *      May be empty or NULL.
+ *  "subjectDomainPolicies"
+ *      Address of List of OIDs indicating the policies to which "policy" is
+ *      mapped. May be empty or NULL.
+ *  "currentNode"
+ *      Address of PolicyNode whose descendants will be checked, if not at the
+ *      bottom of the tree; or whose expectedPolicySet will be compared to
+ *      "policy", if at the bottom. Must be non-NULL.
+ *  "state"
+ *      Address of PolicyCheckerState of the current PolicyChecker. Must be
+ *      non-NULL.
+ *  "pChildNodeCreated"
+ *      Address of the Boolean that will be set TRUE if this function
+ *      creates a child node. Must be non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_CheckPolicyRecursive(
+        PKIX_PL_OID *policyOID,
+        PKIX_List *policyQualifiers,
+        PKIX_List *subjectDomainPolicies,
+        PKIX_PolicyNode *currentNode,
+        PKIX_PolicyCheckerState *state,
+        PKIX_Boolean *pChildNodeCreated,
+        void *plContext)
+{
+        PKIX_UInt32 depth = 0;
+        PKIX_UInt32 numChildren = 0;
+        PKIX_UInt32 childIx = 0;
+        PKIX_Boolean isIncluded = PKIX_FALSE;
+        PKIX_List *children = NULL;     /* PolicyNodes */
+        PKIX_PolicyNode *childNode = NULL;
+        PKIX_List *expectedPolicies = NULL; /* OIDs */
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER,
+                "pkix_PolicyChecker_CheckPolicyRecursive");
+        PKIX_NULLCHECK_FOUR(policyOID, currentNode, state, pChildNodeCreated);
+
+        /* if not at the bottom of the tree */
+        PKIX_CHECK(PKIX_PolicyNode_GetDepth
+                (currentNode, &depth, plContext),
+                PKIX_POLICYNODEGETDEPTHFAILED);
+
+        if (depth < (state->certsProcessed)) {
+                PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable
+                        (currentNode, &children, plContext),
+                        PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED);
+
+                if (children) {
+                        PKIX_CHECK(PKIX_List_GetLength
+                                (children, &numChildren, plContext),
+                                PKIX_LISTGETLENGTHFAILED);
+                }
+
+                for (childIx = 0; childIx < numChildren; childIx++) {
+
+                        PKIX_CHECK(PKIX_List_GetItem
+                            (children,
+                            childIx,
+                            (PKIX_PL_Object **)&childNode,
+                            plContext),
+                            PKIX_LISTGETITEMFAILED);
+
+                        PKIX_CHECK(pkix_PolicyChecker_CheckPolicyRecursive
+                            (policyOID,
+                            policyQualifiers,
+                            subjectDomainPolicies,
+                            childNode,
+                            state,
+                            pChildNodeCreated,
+                            plContext),
+                            PKIX_POLICYCHECKERCHECKPOLICYRECURSIVEFAILED);
+
+                        PKIX_DECREF(childNode);
+                }
+        } else { /* if at the bottom of the tree */
+
+                /* Check whether policy is in this node's expectedPolicySet */
+                PKIX_CHECK(PKIX_PolicyNode_GetExpectedPolicies
+                        (currentNode, &expectedPolicies, plContext),
+                        PKIX_POLICYNODEGETEXPECTEDPOLICIESFAILED);
+
+                PKIX_NULLCHECK_ONE(expectedPolicies);
+
+                PKIX_CHECK(pkix_List_Contains
+                        (expectedPolicies,
+                        (PKIX_PL_Object *)policyOID,
+                        &isIncluded,
+                        plContext),
+                        PKIX_LISTCONTAINSFAILED);
+
+                if (isIncluded) {
+                        PKIX_CHECK(pkix_PolicyChecker_Spawn
+                                (currentNode,
+                                policyOID,
+                                policyQualifiers,
+                                subjectDomainPolicies,
+                                state,
+                                plContext),
+                                PKIX_POLICYCHECKERSPAWNFAILED);
+
+                        *pChildNodeCreated = PKIX_TRUE;
+                }
+        }
+
+cleanup:
+
+        PKIX_DECREF(children);
+        PKIX_DECREF(childNode);
+        PKIX_DECREF(expectedPolicies);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_CheckPolicy
+ * DESCRIPTION:
+ *
+ *  Performs the non-recursive portion of the policy processing for the policy
+ *  whose OID is pointed to by "policyOID" and whose List of
+ *  CertPolicyQualifiers is pointed to by "policyQualifiers", for the
+ *  Certificate pointed to by "cert" with the List of CertPolicyMaps pointed
+ *  to by "maps", in accordance with the current PolicyCheckerState pointed
+ *  to by "state".
+ *
+ *  This function implements the processing described in RFC3280
+ *  Section 6.1.3(d)(1)(i).
+ *
+ * PARAMETERS:
+ *  "policyOID"
+ *      Address of OID of the policy to be checked for. Must be non-NULL.
+ *  "policyQualifiers"
+ *      Address of List of CertPolicyQualifiers of the policy to be checked for.
+ *      May be empty or NULL.
+ *  "cert"
+ *      Address of the current certificate. Must be non-NULL.
+ *  "maps"
+ *      Address of List of CertPolicyMaps for the current certificate
+ *  "state"
+ *      Address of PolicyCheckerState of the current PolicyChecker. Must be
+ *      non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_CheckPolicy(
+        PKIX_PL_OID *policyOID,
+        PKIX_List *policyQualifiers,
+        PKIX_PL_Cert *cert,
+        PKIX_List *maps,
+        PKIX_PolicyCheckerState *state,
+        void *plContext)
+{
+        PKIX_Boolean childNodeCreated = PKIX_FALSE;
+        PKIX_Boolean okToSpawn = PKIX_FALSE;
+        PKIX_Boolean found = PKIX_FALSE;
+        PKIX_List *subjectDomainPolicies = NULL;
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_CheckPolicy");
+        PKIX_NULLCHECK_THREE(policyOID, cert, state);
+
+        /*
+         * If this is not the last certificate, get the set of
+         * subjectDomainPolicies that "policy" maps to, according to the
+         * current cert's policy mapping extension. That set will be NULL
+         * if the current cert does not have a policy mapping extension,
+         * or if the current policy is not mapped.
+         */
+        if (state->certsProcessed != (state->numCerts - 1)) {
+            PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies
+                (maps, policyOID, &subjectDomainPolicies, plContext),
+                PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED);
+        }
+
+        /*
+         * Section 6.1.4(b)(2) tells us that if policyMapping is zero, we
+         * will have to delete any nodes created with validPolicies equal to
+         * policies that appear as issuerDomainPolicies in a policy mapping
+         * extension. Let's avoid creating any such nodes.
+         */
+        if ((state->policyMapping) == 0) {
+                if (subjectDomainPolicies) {
+                        goto cleanup;
+                }
+        }
+
+        PKIX_CHECK(pkix_PolicyChecker_CheckPolicyRecursive
+                (policyOID,
+                policyQualifiers,
+                subjectDomainPolicies,
+                state->validPolicyTree,
+                state,
+                &childNodeCreated,
+                plContext),
+                PKIX_POLICYCHECKERCHECKPOLICYRECURSIVEFAILED);
+
+        if (!childNodeCreated) {
+                /*
+                 * Section 6.1.3(d)(1)(ii)
+                 * There was no match. If there was a node at
+                 * depth i-1 with valid policy anyPolicy,
+                 * generate a node subordinate to that.
+                 *
+                 * But that means this created node would be in
+                 * the valid-policy-node-set, and will be
+                 * pruned in 6.1.5(g)(iii)(2) unless it is in
+                 * the user-initial-policy-set or the user-
+                 * initial-policy-set is {anyPolicy}. So check,
+                 * and don't create it if it will be pruned.
+                 */
+                if (state->anyPolicyNodeAtBottom) {
+                        if (state->initialIsAnyPolicy) {
+                                okToSpawn = PKIX_TRUE;
+                        } else {
+                                PKIX_CHECK(pkix_List_Contains
+                                        (state->mappedUserInitialPolicySet,
+                                        (PKIX_PL_Object *)policyOID,
+                                        &okToSpawn,
+                                        plContext),
+                                        PKIX_LISTCONTAINSFAILED);
+                        }
+                        if (okToSpawn) {
+                                PKIX_CHECK(pkix_PolicyChecker_Spawn
+                                        (state->anyPolicyNodeAtBottom,
+                                        policyOID,
+                                        policyQualifiers,
+                                        subjectDomainPolicies,
+                                        state,
+                                        plContext),
+                                        PKIX_POLICYCHECKERSPAWNFAILED);
+                                childNodeCreated = PKIX_TRUE;
+                        }
+                }
+        }
+
+        if (childNodeCreated) {
+                /*
+                 * If this policy had qualifiers, and the certificate policies
+                 * extension was marked critical, and the user cannot deal with
+                 * policy qualifiers, throw an error.
+                 */
+                if (policyQualifiers &&
+                    state->certPoliciesCritical &&
+                    state->policyQualifiersRejected) {
+                    PKIX_ERROR
+                        (PKIX_QUALIFIERSINCRITICALCERTIFICATEPOLICYEXTENSION);
+                }
+                /*
+                 * If the policy we just propagated was in the list of mapped
+                 * policies, remove it from the list. That list is used, at the
+                 * end, to determine policies that have not been propagated.
+                 */
+                if (state->mappedPolicyOIDs) {
+                        PKIX_CHECK(pkix_List_Contains
+                                (state->mappedPolicyOIDs,
+                                (PKIX_PL_Object *)policyOID,
+                                &found,
+                                plContext),
+                                PKIX_LISTCONTAINSFAILED);
+                        if (found) {
+                                PKIX_CHECK(pkix_List_Remove
+                                        (state->mappedPolicyOIDs,
+                                        (PKIX_PL_Object *)policyOID,
+                                        plContext),
+                                        PKIX_LISTREMOVEFAILED);
+                        }
+                }
+        }
+
+cleanup:
+
+        PKIX_DECREF(subjectDomainPolicies);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_CheckAny
+ * DESCRIPTION:
+ *  Performs the creation of PolicyNodes, for the PolicyNode pointed to by
+ *  "currentNode" and PolicyNodes subordinate to it, using the List of
+ *  qualifiers pointed to by "qualsOfAny", in accordance with the current
+ *  certificate's PolicyMaps pointed to by "policyMaps" and the current
+ *  PolicyCheckerState pointed to by "state".
+ *
+ *  If the currentNode is not just above the bottom of the validPolicyTree, this
+ *  function calls itself recursively for each child of currentNode. At the
+ *  level just above the bottom, for each policy in the currentNode's
+ *  expectedPolicySet not already present in a child node, it creates a new
+ *  child node. The validPolicy of the child created, and its expectedPolicySet,
+ *  will be the policy from the currentNode's expectedPolicySet. The policy
+ *  qualifiers will be the qualifiers from the current certificate's anyPolicy,
+ *  the "qualsOfAny" parameter. If the currentNode's expectedSet includes
+ *  anyPolicy, a childNode will be created with a policy of anyPolicy. This is
+ *  the only way such a node can be created.
+ *
+ *  This function is called only when anyPolicy is one of the current
+ *  certificate's policies. This function implements the processing described
+ *  in RFC3280 Section 6.1.3(d)(2).
+ *
+ * PARAMETERS:
+ *  "currentNode"
+ *      Address of PolicyNode whose descendants will be checked, if not at the
+ *      bottom of the tree; or whose expectedPolicySet will be compared to those
+ *      in "alreadyPresent", if at the bottom. Must be non-NULL.
+ *  "qualsOfAny"
+ *      Address of List of qualifiers of the anyPolicy in the current
+ *      certificate. May be empty or NULL.
+ *  "policyMaps"
+ *      Address of the List of PolicyMaps of the current certificate. May be
+ *      empty or NULL.
+ *  "state"
+ *      Address of the current state of the PKIX_PolicyChecker.
+ *      Must be non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_CheckAny(
+        PKIX_PolicyNode *currentNode,
+        PKIX_List *qualsOfAny,  /* CertPolicyQualifiers */
+        PKIX_List *policyMaps,  /* CertPolicyMaps */
+        PKIX_PolicyCheckerState *state,
+        void *plContext)
+{
+        PKIX_UInt32 depth = 0;
+        PKIX_UInt32 numChildren = 0;
+        PKIX_UInt32 childIx = 0;
+        PKIX_UInt32 numPolicies = 0;
+        PKIX_UInt32 polx = 0;
+        PKIX_Boolean isIncluded = PKIX_FALSE;
+        PKIX_List *children = NULL;     /* PolicyNodes */
+        PKIX_PolicyNode *childNode = NULL;
+        PKIX_List *expectedPolicies = NULL; /* OIDs */
+        PKIX_PL_OID *policyOID = NULL;
+        PKIX_PL_OID *childPolicy = NULL;
+        PKIX_List *subjectDomainPolicies = NULL;  /* OIDs */
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_CheckAny");
+        PKIX_NULLCHECK_TWO(currentNode, state);
+
+        PKIX_CHECK(PKIX_PolicyNode_GetDepth
+                (currentNode, &depth, plContext),
+                PKIX_POLICYNODEGETDEPTHFAILED);
+
+        PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable
+                (currentNode, &children, plContext),
+                PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED);
+
+        if (children) {
+                PKIX_CHECK(PKIX_List_GetLength
+                        (children, &numChildren, plContext),
+                        PKIX_LISTGETLENGTHFAILED);
+        }
+
+        if (depth < (state->certsProcessed)) {
+                for (childIx = 0; childIx < numChildren; childIx++) {
+
+                        PKIX_CHECK(PKIX_List_GetItem
+                                (children,
+                                childIx,
+                                (PKIX_PL_Object **)&childNode,
+                                plContext),
+                                PKIX_LISTGETITEMFAILED);
+
+                        PKIX_NULLCHECK_ONE(childNode);
+                        PKIX_CHECK(pkix_PolicyChecker_CheckAny
+                                (childNode,
+                                qualsOfAny,
+                                policyMaps,
+                                state,
+                                plContext),
+                                PKIX_POLICYCHECKERCHECKANYFAILED);
+
+                        PKIX_DECREF(childNode);
+                }
+        } else { /* if at the bottom of the tree */
+
+            PKIX_CHECK(PKIX_PolicyNode_GetExpectedPolicies
+                (currentNode, &expectedPolicies, plContext),
+                PKIX_POLICYNODEGETEXPECTEDPOLICIESFAILED);
+
+            /* Expected Policy Set is not allowed to be NULL */
+            PKIX_NULLCHECK_ONE(expectedPolicies);
+
+            PKIX_CHECK(PKIX_List_GetLength
+                (expectedPolicies, &numPolicies, plContext),
+                PKIX_LISTGETLENGTHFAILED);
+
+            for (polx = 0; polx < numPolicies; polx++) {
+                PKIX_CHECK(PKIX_List_GetItem
+                    (expectedPolicies,
+                    polx,
+                    (PKIX_PL_Object **)&policyOID,
+                    plContext),
+                    PKIX_LISTGETITEMFAILED);
+
+                PKIX_NULLCHECK_ONE(policyOID);
+
+                isIncluded = PKIX_FALSE;
+
+                for (childIx = 0;
+                    (!isIncluded && (childIx < numChildren));
+                    childIx++) {
+
+                    PKIX_CHECK(PKIX_List_GetItem
+                        (children,
+                        childIx,
+                        (PKIX_PL_Object **)&childNode,
+                        plContext),
+                        PKIX_LISTGETITEMFAILED);
+
+                    PKIX_NULLCHECK_ONE(childNode);
+
+                    PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy
+                        (childNode, &childPolicy, plContext),
+                        PKIX_POLICYNODEGETVALIDPOLICYFAILED);
+
+                    PKIX_NULLCHECK_ONE(childPolicy);
+
+                    PKIX_EQUALS(policyOID, childPolicy, &isIncluded, plContext,
+                        PKIX_OBJECTEQUALSFAILED);
+
+                    PKIX_DECREF(childNode);
+                    PKIX_DECREF(childPolicy);
+                }
+
+                if (!isIncluded) {
+                    if (policyMaps) {
+                        PKIX_CHECK
+                          (pkix_PolicyChecker_MapGetSubjectDomainPolicies
+                          (policyMaps,
+                          policyOID,
+                          &subjectDomainPolicies,
+                          plContext),
+                          PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED);
+                    }
+                    PKIX_CHECK(pkix_PolicyChecker_Spawn
+                        (currentNode,
+                        policyOID,
+                        qualsOfAny,
+                        subjectDomainPolicies,
+                        state,
+                        plContext),
+                        PKIX_POLICYCHECKERSPAWNFAILED);
+                    PKIX_DECREF(subjectDomainPolicies);
+                }
+
+                PKIX_DECREF(policyOID);
+            }
+        }
+
+cleanup:
+
+        PKIX_DECREF(children);
+        PKIX_DECREF(childNode);
+        PKIX_DECREF(expectedPolicies);
+        PKIX_DECREF(policyOID);
+        PKIX_DECREF(childPolicy);
+        PKIX_DECREF(subjectDomainPolicies);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_CalculateIntersection
+ * DESCRIPTION:
+ *
+ *  Processes the PolicyNode pointed to by "currentNode", and its descendants,
+ *  using the PolicyCheckerState pointed to by "state", using the List at
+ *  the address pointed to by "nominees" the OIDs of policies that are in the
+ *  user-initial-policy-set but are not represented among the nodes at the
+ *  bottom of the tree, and storing at "pShouldBePruned" the value TRUE if
+ *  currentNode is childless at the end of this processing, FALSE if it has
+ *  children or is at the bottom of the tree.
+ *
+ *  When this function is called at the top level, "nominees" should be the List
+ *  of all policies in the user-initial-policy-set. Policies that are
+ *  represented in the valid-policy-node-set are removed from this List. As a
+ *  result when nodes are created according to 6.1.5.(g)(iii)(3)(b), a node will
+ *  be created for each policy remaining in this List.
+ *
+ *  This function implements the calculation of the intersection of the
+ *  validPolicyTree with the user-initial-policy-set, as described in
+ *  RFC 3280 6.1.5(g)(iii).
+ *
+ * PARAMETERS:
+ *  "currentNode"
+ *      Address of PolicyNode whose descendants will be processed as described.
+ *      Must be non-NULL.
+ *  "state"
+ *      Address of the current state of the PKIX_PolicyChecker. Must be non-NULL
+ *  "nominees"
+ *      Address of List of the OIDs for which nodes should be created to replace
+ *      anyPolicy nodes. Must be non-NULL but may be empty.
+ *  "pShouldBePruned"
+ *      Address where Boolean return value, set to TRUE if this PolicyNode
+ *      should be deleted, is stored. Must be non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_CalculateIntersection(
+        PKIX_PolicyNode *currentNode,
+        PKIX_PolicyCheckerState *state,
+        PKIX_List *nominees, /* OIDs */
+        PKIX_Boolean *pShouldBePruned,
+        void *plContext)
+{
+        PKIX_Boolean currentPolicyIsAny = PKIX_FALSE;
+        PKIX_Boolean parentPolicyIsAny = PKIX_FALSE;
+        PKIX_Boolean currentPolicyIsValid = PKIX_FALSE;
+        PKIX_Boolean shouldBePruned = PKIX_FALSE;
+        PKIX_Boolean priorCriticality = PKIX_FALSE;
+        PKIX_UInt32 depth = 0;
+        PKIX_UInt32 numChildren = 0;
+        PKIX_UInt32 childIndex = 0;
+        PKIX_UInt32 numNominees = 0;
+        PKIX_UInt32 polIx = 0;
+        PKIX_PL_OID *currentPolicy = NULL;
+        PKIX_PL_OID *parentPolicy = NULL;
+        PKIX_PL_OID *substPolicy = NULL;
+        PKIX_PolicyNode *parent = NULL;
+        PKIX_PolicyNode *child = NULL;
+        PKIX_List *children = NULL; /* PolicyNodes */
+        PKIX_List *policyQualifiers = NULL;
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER,
+                "pkix_PolicyChecker_CalculateIntersection");
+
+        /*
+         * We call this function if the valid_policy_tree is not NULL and
+         * the user-initial-policy-set is not any-policy.
+         */
+        if (!state->validPolicyTree || state->initialIsAnyPolicy) {
+                PKIX_ERROR(PKIX_PRECONDITIONFAILED);
+        }
+
+        PKIX_NULLCHECK_FOUR(currentNode, state, nominees, pShouldBePruned);
+
+        PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy
+                (currentNode, &currentPolicy, plContext),
+                PKIX_POLICYNODEGETVALIDPOLICYFAILED);
+
+        PKIX_NULLCHECK_TWO(state->anyPolicyOID, currentPolicy);
+
+        PKIX_EQUALS
+                (state->anyPolicyOID,
+                currentPolicy,
+                &currentPolicyIsAny,
+                plContext,
+                PKIX_OBJECTEQUALSFAILED);
+
+        PKIX_CHECK(PKIX_PolicyNode_GetParent(currentNode, &parent, plContext),
+                PKIX_POLICYNODEGETPARENTFAILED);
+
+        if (currentPolicyIsAny == PKIX_FALSE) {
+
+                /*
+                 * If we are at the top of the tree, or if our
+                 * parent's validPolicy is anyPolicy, we are in
+                 * the valid policy node set.
+                 */
+                if (parent) {
+                        PKIX_CHECK(PKIX_PolicyNode_GetValidPolicy
+                                (parent, &parentPolicy, plContext),
+                                PKIX_POLICYNODEGETVALIDPOLICYFAILED);
+
+                        PKIX_NULLCHECK_ONE(parentPolicy);
+
+                        PKIX_EQUALS
+                                (state->anyPolicyOID,
+                                parentPolicy,
+                                &parentPolicyIsAny,
+                                plContext,
+                                PKIX_OBJECTEQUALSFAILED);
+                }
+
+                /*
+                 * Section 6.1.5(g)(iii)(2)
+                 * If this node's policy is not in the user-initial-policy-set,
+                 * it is not in the intersection. Prune it.
+                 */
+                if (!parent || parentPolicyIsAny) {
+                        PKIX_CHECK(pkix_List_Contains
+                                (state->userInitialPolicySet,
+                                (PKIX_PL_Object *)currentPolicy,
+                                &currentPolicyIsValid,
+                                plContext),
+                                PKIX_LISTCONTAINSFAILED);
+                        if (!currentPolicyIsValid) {
+                                *pShouldBePruned = PKIX_TRUE;
+                                goto cleanup;
+                        }
+
+                        /*
+                         * If this node's policy is in the user-initial-policy-
+                         * set, it will propagate that policy into the next
+                         * level of the tree. Remove the policy from the list
+                         * of policies that an anyPolicy will spawn.
+                         */
+                        PKIX_CHECK(pkix_List_Remove
+                                (nominees,
+                                (PKIX_PL_Object *)currentPolicy,
+                                plContext),
+                                PKIX_LISTREMOVEFAILED);
+                }
+        }
+
+
+        /* Are we at the bottom of the tree? */
+
+        PKIX_CHECK(PKIX_PolicyNode_GetDepth
+                (currentNode, &depth, plContext),
+                PKIX_POLICYNODEGETDEPTHFAILED);
+
+        if (depth == (state->numCerts)) {
+                /*
+                 * Section 6.1.5(g)(iii)(3)
+                 * Replace anyPolicy nodes...
+                 */
+                if (currentPolicyIsAny == PKIX_TRUE) {
+
+                        /* replace this node */
+
+                        PKIX_CHECK(PKIX_List_GetLength
+                            (nominees, &numNominees, plContext),
+                            PKIX_LISTGETLENGTHFAILED);
+
+                        if (numNominees) {
+
+                            PKIX_CHECK(PKIX_PolicyNode_GetPolicyQualifiers
+                                (currentNode,
+                                &policyQualifiers,
+                                plContext),
+                                PKIX_POLICYNODEGETPOLICYQUALIFIERSFAILED);
+
+                            PKIX_CHECK(PKIX_PolicyNode_IsCritical
+                                (currentNode, &priorCriticality, plContext),
+                                PKIX_POLICYNODEISCRITICALFAILED);
+                        }
+
+                        PKIX_NULLCHECK_ONE(parent);
+
+                        for (polIx = 0; polIx < numNominees; polIx++) {
+
+                            PKIX_CHECK(PKIX_List_GetItem
+                                (nominees,
+                                polIx,
+                                (PKIX_PL_Object **)&substPolicy,
+                                plContext),
+                                PKIX_LISTGETITEMFAILED);
+
+                            PKIX_CHECK(pkix_PolicyChecker_Spawn
+                                (parent,
+                                substPolicy,
+                                policyQualifiers,
+                                NULL,
+                                state,
+                                plContext),
+                                PKIX_POLICYCHECKERSPAWNFAILED);
+
+                            PKIX_DECREF(substPolicy);
+
+                        }
+                        /* remove currentNode from parent */
+                        *pShouldBePruned = PKIX_TRUE;
+                        /*
+                         * We can get away with augmenting the parent's List
+                         * of children because we started at the end and went
+                         * toward the beginning. New nodes are added at the end.
+                         */
+                }
+        } else {
+                /*
+                 * Section 6.1.5(g)(iii)(4)
+                 * Prune any childless nodes above the bottom level
+                 */
+                PKIX_CHECK(pkix_PolicyNode_GetChildrenMutable
+                        (currentNode, &children, plContext),
+                        PKIX_POLICYNODEGETCHILDRENMUTABLEFAILED);
+
+                /* CurrentNode should have been pruned if childless. */
+                PKIX_NULLCHECK_ONE(children);
+
+                PKIX_CHECK(PKIX_List_GetLength
+                        (children, &numChildren, plContext),
+                        PKIX_LISTGETLENGTHFAILED);
+
+                for (childIndex = numChildren; childIndex > 0; childIndex--) {
+
+                    PKIX_CHECK(PKIX_List_GetItem
+                        (children,
+                        childIndex - 1,
+                        (PKIX_PL_Object **)&child,
+                        plContext),
+                        PKIX_LISTGETITEMFAILED);
+
+                    PKIX_CHECK(pkix_PolicyChecker_CalculateIntersection
+                        (child, state, nominees, &shouldBePruned, plContext),
+                        PKIX_POLICYCHECKERCALCULATEINTERSECTIONFAILED);
+
+                    if (PKIX_TRUE == shouldBePruned) {
+
+                        PKIX_CHECK(PKIX_List_DeleteItem
+                                (children, childIndex - 1, plContext),
+                                PKIX_LISTDELETEITEMFAILED);
+                        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                                ((PKIX_PL_Object *)state, plContext),
+                                PKIX_OBJECTINVALIDATECACHEFAILED);
+                    }
+
+                    PKIX_DECREF(child);
+                }
+
+                PKIX_CHECK(PKIX_List_GetLength
+                        (children, &numChildren, plContext),
+                        PKIX_LISTGETLENGTHFAILED);
+
+                if (numChildren == 0) {
+                        *pShouldBePruned = PKIX_TRUE;
+                }
+        }
+cleanup:
+        PKIX_DECREF(currentPolicy);
+        PKIX_DECREF(parentPolicy);
+        PKIX_DECREF(substPolicy);
+        PKIX_DECREF(parent);
+        PKIX_DECREF(child);
+        PKIX_DECREF(children);
+        PKIX_DECREF(policyQualifiers);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_PolicyMapProcessing
+ * DESCRIPTION:
+ *
+ *  Performs the processing of Policies in the List of CertPolicyMaps pointed
+ *  to by "policyMaps", using and updating the PolicyCheckerState pointed to by
+ *  "state".
+ *
+ *  This function implements the policyMap processing described in RFC3280
+ *  Section 6.1.4(b)(1), after certificate i has been processed, in preparation
+ *  for certificate i+1. Section references are to that document.
+ *
+ * PARAMETERS:
+ *  "policyMaps"
+ *      Address of the List of CertPolicyMaps presented by certificate i.
+ *      Must be non-NULL.
+ *  "certPoliciesIncludeAny"
+ *      Boolean value which is PKIX_TRUE if the current certificate asserts
+ *      anyPolicy, PKIX_FALSE otherwise.
+ *  "qualsOfAny"
+ *      Address of List of qualifiers of the anyPolicy in the current
+ *      certificate. May be empty or NULL.
+ *  "state"
+ *      Address of the current state of the PKIX_PolicyChecker.
+ *      Must be non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_PolicyMapProcessing(
+        PKIX_List *policyMaps,  /* CertPolicyMaps */
+        PKIX_Boolean certPoliciesIncludeAny,
+        PKIX_List *qualsOfAny,
+        PKIX_PolicyCheckerState *state,
+        void *plContext)
+{
+        PKIX_UInt32 numPolicies = 0;
+        PKIX_UInt32 polX = 0;
+        PKIX_PL_OID *policyOID = NULL;
+        PKIX_List *newMappedPolicies = NULL;  /* OIDs */
+        PKIX_List *subjectDomainPolicies = NULL;  /* OIDs */
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER,
+                "pkix_PolicyChecker_PolicyMapProcessing");
+        PKIX_NULLCHECK_THREE
+                (policyMaps,
+                state,
+                state->mappedUserInitialPolicySet);
+
+        /*
+         * For each policy in mappedUserInitialPolicySet, if it is not mapped,
+         * append it to new policySet; if it is mapped, append its
+         * subjectDomainPolicies to new policySet. When done, this new
+         * policySet will replace mappedUserInitialPolicySet.
+         */
+        PKIX_CHECK(PKIX_List_Create
+                (&newMappedPolicies, plContext),
+                PKIX_LISTCREATEFAILED);
+
+        PKIX_CHECK(PKIX_List_GetLength
+                (state->mappedUserInitialPolicySet,
+                &numPolicies,
+                plContext),
+                PKIX_LISTGETLENGTHFAILED);
+
+        for (polX = 0; polX < numPolicies; polX++) {
+
+            PKIX_CHECK(PKIX_List_GetItem
+                (state->mappedUserInitialPolicySet,
+                polX,
+                (PKIX_PL_Object **)&policyOID,
+                plContext),
+                PKIX_LISTGETITEMFAILED);
+
+            PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies
+                (policyMaps,
+                policyOID,
+                &subjectDomainPolicies,
+                plContext),
+                PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED);
+
+            if (subjectDomainPolicies) {
+
+                PKIX_CHECK(pkix_List_AppendUnique
+                        (newMappedPolicies,
+                        subjectDomainPolicies,
+                        plContext),
+                        PKIX_LISTAPPENDUNIQUEFAILED);
+
+                PKIX_DECREF(subjectDomainPolicies);
+
+            } else {
+                PKIX_CHECK(PKIX_List_AppendItem
+                        (newMappedPolicies,
+                        (PKIX_PL_Object *)policyOID,
+                        plContext),
+                        PKIX_LISTAPPENDITEMFAILED);
+            }
+            PKIX_DECREF(policyOID);
+        }
+
+        /*
+         * For each policy ID-P remaining in mappedPolicyOIDs, it has not been
+         * propagated to the bottom of the tree (depth i). If policyMapping
+         * is greater than zero and this cert contains anyPolicy and the tree
+         * contains an anyPolicy node at depth i-1, then we must create a node
+         * with validPolicy ID-P, the policy qualifiers of anyPolicy in
+         * this certificate, and expectedPolicySet the subjectDomainPolicies
+         * that ID-P maps to. We also then add those subjectDomainPolicies to
+         * the list of policies that will be accepted in the next certificate,
+         * the mappedUserInitialPolicySet.
+         */
+
+        if ((state->policyMapping > 0) && (certPoliciesIncludeAny) &&
+            (state->anyPolicyNodeAtBottom) && (state->mappedPolicyOIDs)) {
+
+                PKIX_CHECK(PKIX_List_GetLength
+                    (state->mappedPolicyOIDs,
+                    &numPolicies,
+                    plContext),
+                    PKIX_LISTGETLENGTHFAILED);
+
+                for (polX = 0; polX < numPolicies; polX++) {
+
+                    PKIX_CHECK(PKIX_List_GetItem
+                        (state->mappedPolicyOIDs,
+                        polX,
+                        (PKIX_PL_Object **)&policyOID,
+                        plContext),
+                        PKIX_LISTGETITEMFAILED);
+
+                    PKIX_CHECK(pkix_PolicyChecker_MapGetSubjectDomainPolicies
+                        (policyMaps,
+                        policyOID,
+                        &subjectDomainPolicies,
+                        plContext),
+                        PKIX_POLICYCHECKERMAPGETSUBJECTDOMAINPOLICIESFAILED);
+
+                    PKIX_CHECK(pkix_PolicyChecker_Spawn
+                        (state->anyPolicyNodeAtBottom,
+                        policyOID,
+                        qualsOfAny,
+                        subjectDomainPolicies,
+                        state,
+                        plContext),
+                        PKIX_POLICYCHECKERSPAWNFAILED);
+
+                    PKIX_CHECK(pkix_List_AppendUnique
+                        (newMappedPolicies,
+                        subjectDomainPolicies,
+                        plContext),
+                        PKIX_LISTAPPENDUNIQUEFAILED);
+
+                    PKIX_DECREF(subjectDomainPolicies);
+                    PKIX_DECREF(policyOID);
+                }
+        }
+
+        PKIX_CHECK(PKIX_List_SetImmutable(newMappedPolicies, plContext),
+                PKIX_LISTSETIMMUTABLEFAILED);
+
+        PKIX_DECREF(state->mappedUserInitialPolicySet);
+        PKIX_INCREF(newMappedPolicies);
+
+        state->mappedUserInitialPolicySet = newMappedPolicies;
+
+cleanup:
+
+        PKIX_DECREF(policyOID);
+        PKIX_DECREF(newMappedPolicies);
+        PKIX_DECREF(subjectDomainPolicies);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_WrapUpProcessing
+ * DESCRIPTION:
+ *
+ *  Performs the wrap-up processing for the Cert pointed to by "cert",
+ *  using and updating the PolicyCheckerState pointed to by "state".
+ *
+ *  This function implements the wrap-up processing described in RFC3280
+ *  Section 6.1.5, after the final certificate has been processed. Section
+ *  references in the comments are to that document.
+ *
+ * PARAMETERS:
+ *  "cert"
+ *      Address of the current (presumably the end entity) certificate.
+ *      Must be non-NULL.
+ *  "state"
+ *      Address of the current state of the PKIX_PolicyChecker.
+ *      Must be non-NULL.
+ *  "plContext"
+ *      Platform-specific context pointer.
+ * THREAD SAFETY:
+ *  Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ *  Returns NULL if the function succeeds
+ *  Returns a CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+static PKIX_Error *
+pkix_PolicyChecker_WrapUpProcessing(
+        PKIX_PL_Cert *cert,
+        PKIX_PolicyCheckerState *state,
+        void *plContext)
+{
+        PKIX_Int32 explicitPolicySkipCerts = 0;
+        PKIX_Boolean isSelfIssued = PKIX_FALSE;
+        PKIX_Boolean shouldBePruned = PKIX_FALSE;
+        PKIX_List *nominees = NULL; /* OIDs */
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        PKIX_PL_String *stateString = NULL;
+        char *stateAscii = NULL;
+        PKIX_UInt32 length;
+#endif
+
+        PKIX_ENTER
+                (CERTCHAINCHECKER,
+                "pkix_PolicyChecker_WrapUpProcessing");
+        PKIX_NULLCHECK_THREE(cert, state, state->userInitialPolicySet);
+
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        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("%s\n", stateAscii);
+
+        PKIX_FREE(stateAscii);
+        PKIX_DECREF(stateString);
+#endif
+
+        /* Section 6.1.5(a) ... */
+        PKIX_CHECK(pkix_IsCertSelfIssued
+                (cert, &isSelfIssued, plContext),
+                PKIX_ISCERTSELFISSUEDFAILED);
+
+        if (!isSelfIssued) {
+                if (state->explicitPolicy > 0) {
+
+                        state->explicitPolicy--;
+
+                        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                                ((PKIX_PL_Object *)state, plContext),
+                                PKIX_OBJECTINVALIDATECACHEFAILED);
+                }
+        }
+
+        /* Section 6.1.5(b) ... */
+        PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy
+                (cert, &explicitPolicySkipCerts, plContext),
+                PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED);
+
+        if (explicitPolicySkipCerts  == 0) {
+                state->explicitPolicy = 0;
+        }
+
+        /* Section 6.1.5(g)(i) ... */
+
+        if (!(state->validPolicyTree)) {
+                goto cleanup;
+        }
+
+        /* Section 6.1.5(g)(ii) ... */
+
+        if (state->initialIsAnyPolicy) {
+                goto cleanup;
+        }
+
+        /*
+         * Section 6.1.5(g)(iii) ...
+         * Create a list of policies which could be substituted for anyPolicy.
+         * Start with a (mutable) copy of user-initial-policy-set.
+         */
+        PKIX_CHECK(pkix_PolicyChecker_MakeMutableCopy
+                (state->userInitialPolicySet, &nominees, plContext),
+                PKIX_POLICYCHECKERMAKEMUTABLECOPYFAILED);
+
+        PKIX_CHECK(pkix_PolicyChecker_CalculateIntersection
+                (state->validPolicyTree, /* node at top of tree */
+                state,
+                nominees,
+                &shouldBePruned,
+                plContext),
+                PKIX_POLICYCHECKERCALCULATEINTERSECTIONFAILED);
+
+        if (PKIX_TRUE == shouldBePruned) {
+                PKIX_DECREF(state->validPolicyTree);
+        }
+
+        if (state->validPolicyTree) {
+                PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                        ((PKIX_PL_Object *)state->validPolicyTree, plContext),
+                        PKIX_OBJECTINVALIDATECACHEFAILED);
+        }
+
+        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                ((PKIX_PL_Object *)state, plContext),
+                PKIX_OBJECTINVALIDATECACHEFAILED);
+
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        if (state->validPolicyTree) {
+                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
+                        ("After CalculateIntersection:\n%s\n", stateAscii);
+
+                PKIX_FREE(stateAscii);
+                PKIX_DECREF(stateString);
+        } else {
+                PKIX_DEBUG("validPolicyTree is NULL\n");
+        }
+#endif
+
+        /* Section 6.1.5(g)(iii)(4) ... */
+
+        if (state->validPolicyTree) {
+
+                PKIX_CHECK(pkix_PolicyNode_Prune
+                        (state->validPolicyTree,
+                        state->numCerts,
+                        &shouldBePruned,
+                        plContext),
+                        PKIX_POLICYNODEPRUNEFAILED);
+
+                if (shouldBePruned) {
+                        PKIX_DECREF(state->validPolicyTree);
+                }
+        }
+
+        if (state->validPolicyTree) {
+                PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                        ((PKIX_PL_Object *)state->validPolicyTree, plContext),
+                        PKIX_OBJECTINVALIDATECACHEFAILED);
+        }
+
+        PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                ((PKIX_PL_Object *)state, plContext),
+                PKIX_OBJECTINVALIDATECACHEFAILED);
+
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        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("%s\n", stateAscii);
+
+        PKIX_FREE(stateAscii);
+        PKIX_DECREF(stateString);
+#endif
+
+cleanup:
+
+        PKIX_DECREF(nominees);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+
+/*
+ * FUNCTION: pkix_PolicyChecker_Check
+ * (see comments in pkix_checker.h for PKIX_CertChainChecker_CheckCallback)
+ *
+ * Labels referring to sections, such as "Section 6.1.3(d)", refer to
+ * sections of RFC3280, Section 6.1.3 Basic Certificate Processing.
+ *
+ * If a non-fatal error occurs, it is unlikely that policy processing can
+ * continue. But it is still possible that chain validation could succeed if
+ * policy processing is non-critical. So if this function receives a non-fatal
+ * error from a lower level routine, it aborts policy processing by setting
+ * the validPolicyTree to NULL and tries to continue.
+ *
+ */
+static PKIX_Error *
+pkix_PolicyChecker_Check(
+        PKIX_CertChainChecker *checker,
+        PKIX_PL_Cert *cert,
+        PKIX_List *unresolvedCriticals,  /* OIDs */
+        void **pNBIOContext,
+        void *plContext)
+{
+        PKIX_UInt32 numPolicies = 0;
+        PKIX_UInt32 polX = 0;
+        PKIX_Boolean result = PKIX_FALSE;
+        PKIX_Int32 inhibitMappingSkipCerts = 0;
+        PKIX_Int32 explicitPolicySkipCerts = 0;
+        PKIX_Int32 inhibitAnyPolicySkipCerts = 0;
+        PKIX_Boolean shouldBePruned = PKIX_FALSE;
+        PKIX_Boolean isSelfIssued = PKIX_FALSE;
+        PKIX_Boolean certPoliciesIncludeAny = PKIX_FALSE;
+        PKIX_Boolean doAnyPolicyProcessing = PKIX_FALSE;
+
+        PKIX_PolicyCheckerState *state = NULL;
+        PKIX_List *certPolicyInfos = NULL; /* CertPolicyInfos */
+        PKIX_PL_CertPolicyInfo *policy = NULL;
+        PKIX_PL_OID *policyOID = NULL;
+        PKIX_List *qualsOfAny = NULL; /* CertPolicyQualifiers */
+        PKIX_List *policyQualifiers = NULL; /* CertPolicyQualifiers */
+        PKIX_List *policyMaps = NULL; /* CertPolicyMaps */
+        PKIX_List *mappedPolicies = NULL; /* OIDs */
+        PKIX_Error *subroutineErr = NULL;
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        PKIX_PL_String *stateString = NULL;
+        char *stateAscii = NULL;
+        PKIX_PL_String *certString = NULL;
+        char *certAscii = NULL;
+        PKIX_UInt32 length;
+#endif
+
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Check");
+        PKIX_NULLCHECK_FOUR(checker, cert, unresolvedCriticals, pNBIOContext);
+
+        *pNBIOContext = NULL; /* we never block on pending I/O */
+
+        PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
+                    (checker, (PKIX_PL_Object **)&state, plContext),
+                    PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);
+
+        PKIX_NULLCHECK_TWO(state, state->certPoliciesExtension);
+
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        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("On entry %s\n", stateAscii);
+        PKIX_FREE(stateAscii);
+        PKIX_DECREF(stateString);
+#endif
+
+        /*
+         * Section 6.1.4(a)
+         * If this is not the last certificate, and if
+         * policyMapping extension is present, check that no
+         * issuerDomainPolicy or subjectDomainPolicy is equal to the
+         * special policy anyPolicy.
+         */
+        if (state->certsProcessed != (state->numCerts - 1)) {
+                PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings
+                        (cert, &policyMaps, plContext),
+                        PKIX_CERTGETPOLICYMAPPINGSFAILED);
+        }
+
+        if (policyMaps) {
+
+                PKIX_CHECK(pkix_PolicyChecker_MapContains
+                        (policyMaps, state->anyPolicyOID, &result, plContext),
+                        PKIX_POLICYCHECKERMAPCONTAINSFAILED);
+
+                if (result) {
+                        PKIX_ERROR(PKIX_INVALIDPOLICYMAPPINGINCLUDESANYPOLICY);
+                }
+
+                PKIX_CHECK(pkix_PolicyChecker_MapGetMappedPolicies
+                        (policyMaps, &mappedPolicies, plContext),
+                        PKIX_POLICYCHECKERMAPGETMAPPEDPOLICIESFAILED);
+
+                PKIX_DECREF(state->mappedPolicyOIDs);
+                PKIX_INCREF(mappedPolicies);
+                state->mappedPolicyOIDs = mappedPolicies;
+        }
+
+        /* Section 6.1.3(d) */
+        if (state->validPolicyTree) {
+
+            PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation
+                (cert, &certPolicyInfos, plContext),
+                PKIX_CERTGETPOLICYINFORMATIONFAILED);
+
+            if (certPolicyInfos) {
+                PKIX_CHECK(PKIX_List_GetLength
+                        (certPolicyInfos, &numPolicies, plContext),
+                        PKIX_LISTGETLENGTHFAILED);
+            }
+
+            if (numPolicies > 0) {
+
+                PKIX_CHECK(PKIX_PL_Cert_AreCertPoliciesCritical
+                        (cert, &(state->certPoliciesCritical), plContext),
+                        PKIX_CERTARECERTPOLICIESCRITICALFAILED);
+
+                /* Section 6.1.3(d)(1) For each policy not equal to anyPolicy */
+                for (polX = 0; polX < numPolicies; polX++) {
+
+                    PKIX_CHECK(PKIX_List_GetItem
+                        (certPolicyInfos,
+                        polX,
+                        (PKIX_PL_Object **)&policy,
+                        plContext),
+                        PKIX_LISTGETITEMFAILED);
+
+                    PKIX_CHECK(PKIX_PL_CertPolicyInfo_GetPolicyId
+                        (policy, &policyOID, plContext),
+                        PKIX_CERTPOLICYINFOGETPOLICYIDFAILED);
+
+                    PKIX_CHECK(PKIX_PL_CertPolicyInfo_GetPolQualifiers
+                        (policy, &policyQualifiers, plContext),
+                        PKIX_CERTPOLICYINFOGETPOLQUALIFIERSFAILED);
+
+                    PKIX_EQUALS
+                        (state->anyPolicyOID,
+                        policyOID,
+                        &result,
+                        plContext,
+                        PKIX_OIDEQUALFAILED);
+
+                    if (result == PKIX_FALSE) {
+
+                        /* Section 6.1.3(d)(1)(i) */
+                        subroutineErr = pkix_PolicyChecker_CheckPolicy
+                                (policyOID,
+                                policyQualifiers,
+                                cert,
+                                policyMaps,
+                                state,
+                                plContext);
+                        if (subroutineErr) {
+                                goto subrErrorCleanup;
+                        }
+
+                    } else {
+                        /*
+                         * No descent (yet) for anyPolicy, but we will need
+                         * the policyQualifiers for anyPolicy in 6.1.3(d)(2)
+                         */
+                        PKIX_DECREF(qualsOfAny);
+                        PKIX_INCREF(policyQualifiers);
+                        qualsOfAny = policyQualifiers;
+                        certPoliciesIncludeAny = PKIX_TRUE;
+                    }
+                    PKIX_DECREF(policy);
+                    PKIX_DECREF(policyOID);
+                    PKIX_DECREF(policyQualifiers);
+                }
+
+                /* Section 6.1.3(d)(2) */
+                if (certPoliciesIncludeAny == PKIX_TRUE) {
+                        if (state->inhibitAnyPolicy > 0) {
+                                doAnyPolicyProcessing = PKIX_TRUE;
+                        } else {
+                            /* We haven't yet counted the current cert */
+                            if (((state->certsProcessed) + 1) <
+                                (state->numCerts)) {
+
+                                PKIX_CHECK(pkix_IsCertSelfIssued
+                                        (cert,
+                                        &doAnyPolicyProcessing,
+                                        plContext),
+                                        PKIX_ISCERTSELFISSUEDFAILED);
+                            }
+                        }
+                        if (doAnyPolicyProcessing) {
+                            subroutineErr = pkix_PolicyChecker_CheckAny
+                                (state->validPolicyTree,
+                                qualsOfAny,
+                                policyMaps,
+                                state,
+                                plContext);
+                            if (subroutineErr) {
+                                goto subrErrorCleanup;
+                            }
+                        }
+                }
+
+                /* Section 6.1.3(d)(3) */
+                if (state->validPolicyTree) {
+                        subroutineErr = pkix_PolicyNode_Prune
+                                (state->validPolicyTree,
+                                state->certsProcessed + 1,
+                                &shouldBePruned,
+                                plContext);
+                        if (subroutineErr) {
+                                goto subrErrorCleanup;
+                        }
+                        if (shouldBePruned) {
+                                PKIX_DECREF(state->validPolicyTree);
+                                PKIX_DECREF(state->anyPolicyNodeAtBottom);
+                        }
+                }
+
+                PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                        ((PKIX_PL_Object *)state, plContext),
+                        PKIX_OBJECTINVALIDATECACHEFAILED);
+
+            } else {
+                /* Section 6.1.3(e) */
+                PKIX_DECREF(state->validPolicyTree);
+                PKIX_DECREF(state->anyPolicyNodeAtBottom);
+                PKIX_DECREF(state->newAnyPolicyNode);
+
+                PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                        ((PKIX_PL_Object *)state, plContext),
+                        PKIX_OBJECTINVALIDATECACHEFAILED);
+            }
+        }
+
+        /* Section 6.1.3(f) */
+        if ((0 == state->explicitPolicy) && (!state->validPolicyTree)) {
+                PKIX_ERROR(PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION);
+        }
+
+        /*
+         * Remove Policy OIDs from list of unresolved critical
+         * extensions, if present.
+         */
+        PKIX_CHECK(pkix_List_Remove
+                (unresolvedCriticals,
+                (PKIX_PL_Object *)state->certPoliciesExtension,
+                plContext),
+                PKIX_LISTREMOVEFAILED);
+
+        PKIX_CHECK(pkix_List_Remove
+                (unresolvedCriticals,
+                (PKIX_PL_Object *)state->policyMappingsExtension,
+                plContext),
+                PKIX_LISTREMOVEFAILED);
+
+        PKIX_CHECK(pkix_List_Remove
+                (unresolvedCriticals,
+                (PKIX_PL_Object *)state->policyConstraintsExtension,
+                plContext),
+                PKIX_LISTREMOVEFAILED);
+
+        PKIX_CHECK(pkix_List_Remove
+                (unresolvedCriticals,
+                (PKIX_PL_Object *)state->inhibitAnyPolicyExtension,
+                plContext),
+                PKIX_LISTREMOVEFAILED);
+
+        state->certsProcessed++;
+
+        /* If this was not the last certificate, do next-cert preparation */
+        if (state->certsProcessed != state->numCerts) {
+
+                if (policyMaps) {
+                        subroutineErr = pkix_PolicyChecker_PolicyMapProcessing
+                                (policyMaps,
+                                certPoliciesIncludeAny,
+                                qualsOfAny,
+                                state,
+                                plContext);
+                        if (subroutineErr) {
+                                goto subrErrorCleanup;
+                        }
+                }
+
+                /* update anyPolicyNodeAtBottom pointer */
+                PKIX_DECREF(state->anyPolicyNodeAtBottom);
+                state->anyPolicyNodeAtBottom = state->newAnyPolicyNode;
+                state->newAnyPolicyNode = NULL;
+
+                /* Section 6.1.4(h) */
+                PKIX_CHECK(pkix_IsCertSelfIssued
+                        (cert, &isSelfIssued, plContext),
+                        PKIX_ISCERTSELFISSUEDFAILED);
+
+                if (!isSelfIssued) {
+                        if (state->explicitPolicy > 0) {
+                            state->explicitPolicy--;
+                        }
+                        if (state->policyMapping > 0) {
+                            state->policyMapping--;
+                        }
+                        if (state->inhibitAnyPolicy > 0) {
+                            state->inhibitAnyPolicy--;
+                        }
+                }
+
+                /* Section 6.1.4(i) */
+                PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy
+                        (cert, &explicitPolicySkipCerts, plContext),
+                        PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED);
+
+                if (explicitPolicySkipCerts != -1) {
+                        if (((PKIX_UInt32)explicitPolicySkipCerts) <
+                            (state->explicitPolicy)) {
+                                state->explicitPolicy =
+                                   ((PKIX_UInt32) explicitPolicySkipCerts);
+                        }
+                }
+
+                PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited
+                        (cert, &inhibitMappingSkipCerts, plContext),
+                        PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED);
+
+                if (inhibitMappingSkipCerts != -1) {
+                        if (((PKIX_UInt32)inhibitMappingSkipCerts) <
+                            (state->policyMapping)) {
+                                state->policyMapping =
+                                    ((PKIX_UInt32)inhibitMappingSkipCerts);
+                        }
+                }
+
+                PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy
+                        (cert, &inhibitAnyPolicySkipCerts, plContext),
+                        PKIX_CERTGETINHIBITANYPOLICYFAILED);
+
+                if (inhibitAnyPolicySkipCerts != -1) {
+                        if (((PKIX_UInt32)inhibitAnyPolicySkipCerts) <
+                            (state->inhibitAnyPolicy)) {
+                                state->inhibitAnyPolicy =
+                                    ((PKIX_UInt32)inhibitAnyPolicySkipCerts);
+                        }
+                }
+
+                PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+                        ((PKIX_PL_Object *)state, plContext),
+                        PKIX_OBJECTINVALIDATECACHEFAILED);
+
+        } else { /* If this was the last certificate, do wrap-up processing */
+
+                /* Section 6.1.5 */
+                subroutineErr = pkix_PolicyChecker_WrapUpProcessing
+                        (cert, state, plContext);
+                if (subroutineErr) {
+                        goto subrErrorCleanup;
+                }
+
+                if ((0 == state->explicitPolicy) && (!state->validPolicyTree)) {
+                    PKIX_ERROR(PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION);
+                }
+
+                PKIX_DECREF(state->anyPolicyNodeAtBottom);
+                PKIX_DECREF(state->newAnyPolicyNode);
+        }
+
+
+        if (subroutineErr) {
+
+subrErrorCleanup:
+                /* We had an error. Was it a fatal error? */
+                pkixErrorClass = subroutineErr->errClass;
+                if (pkixErrorClass == PKIX_FATAL_ERROR) {
+                    pkixErrorResult = subroutineErr;
+                    subroutineErr = NULL;
+                    goto cleanup;
+                }
+                /*
+                 * Abort policy processing, and then determine whether
+                 * we can continue without policy processing.
+                 */
+                PKIX_DECREF(state->validPolicyTree);
+                PKIX_DECREF(state->anyPolicyNodeAtBottom);
+                PKIX_DECREF(state->newAnyPolicyNode);
+                if (state->explicitPolicy == 0) {
+                    PKIX_ERROR
+                        (PKIX_CERTCHAINFAILSCERTIFICATEPOLICYVALIDATION);
+                }
+        }
+
+        /* Checking is complete. Save state for the next certificate. */
+        PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState
+                (checker, (PKIX_PL_Object *)state, plContext),
+                PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED);
+
+cleanup:
+
+#if PKIX_CERTPOLICYCHECKERSTATEDEBUG
+        if (cert) {
+                PKIX_CHECK(PKIX_PL_Object_ToString
+                        ((PKIX_PL_Object*)cert, &certString, plContext),
+                        PKIX_OBJECTTOSTRINGFAILED);
+                PKIX_CHECK(PKIX_PL_String_GetEncoded
+                            (certString,
+                            PKIX_ESCASCII,
+                            (void **)&certAscii,
+                            &length,
+                            plContext),
+                            PKIX_STRINGGETENCODEDFAILED);
+                PKIX_DEBUG_ARG("Cert was %s\n", certAscii);
+                PKIX_FREE(certAscii);
+                PKIX_DECREF(certString);
+        }
+        if (state) {
+                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("On exit %s\n", stateAscii);
+                PKIX_FREE(stateAscii);
+                PKIX_DECREF(stateString);
+        }
+#endif
+
+        PKIX_DECREF(state);
+        PKIX_DECREF(certPolicyInfos);
+        PKIX_DECREF(policy);
+        PKIX_DECREF(qualsOfAny);
+        PKIX_DECREF(policyQualifiers);
+        PKIX_DECREF(policyOID);
+        PKIX_DECREF(subroutineErr);
+        PKIX_DECREF(policyMaps);
+        PKIX_DECREF(mappedPolicies);
+
+        PKIX_RETURN(CERTCHAINCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_PolicyChecker_Initialize
+ * DESCRIPTION:
+ *
+ *  Creates and initializes a PolicyChecker, using the List pointed to
+ *  by "initialPolicies" for the user-initial-policy-set, the Boolean value
+ *  of "policyQualifiersRejected" for the policyQualifiersRejected parameter,
+ *  the Boolean value of "initialPolicyMappingInhibit" for the
+ *  inhibitPolicyMappings parameter, the Boolean value of
+ *  "initialExplicitPolicy" for the initialExplicitPolicy parameter, the
+ *  Boolean value of "initialAnyPolicyInhibit" for the inhibitAnyPolicy
+ *  parameter, and the UInt32 value of "numCerts" as the number of
+ *  certificates in the chain; and stores the Checker at "pChecker".
+ *
+ * PARAMETERS:
+ *  "initialPolicies"
+ *      Address of List of OIDs comprising the user-initial-policy-set; the List
+ *      may be empty or NULL
+ *  "policyQualifiersRejected"
+ *      Boolean value of the policyQualifiersRejected parameter
+ *  "initialPolicyMappingInhibit"
+ *      Boolean value of the inhibitPolicyMappings parameter
+ *  "initialExplicitPolicy"
+ *      Boolean value of the initialExplicitPolicy parameter
+ *  "initialAnyPolicyInhibit"
+ *      Boolean value of the inhibitAnyPolicy parameter
+ *  "numCerts"
+ *      Number of certificates in the chain to be validated
+ *  "pChecker"
+ *      Address to store the created PolicyChecker. 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 CertChainChecker Error if the functions fails in a non-fatal way
+ *  Returns a Fatal Error if the function fails in an unrecoverable way
+ */
+PKIX_Error *
+pkix_PolicyChecker_Initialize(
+        PKIX_List *initialPolicies,
+        PKIX_Boolean policyQualifiersRejected,
+        PKIX_Boolean initialPolicyMappingInhibit,
+        PKIX_Boolean initialExplicitPolicy,
+        PKIX_Boolean initialAnyPolicyInhibit,
+        PKIX_UInt32 numCerts,
+        PKIX_CertChainChecker **pChecker,
+        void *plContext)
+{
+        PKIX_PolicyCheckerState *polCheckerState = NULL;
+        PKIX_List *policyExtensions = NULL;     /* OIDs */
+        PKIX_ENTER(CERTCHAINCHECKER, "pkix_PolicyChecker_Initialize");
+        PKIX_NULLCHECK_ONE(pChecker);
+
+        PKIX_CHECK(pkix_PolicyCheckerState_Create
+                (initialPolicies,
+                policyQualifiersRejected,
+                initialPolicyMappingInhibit,
+                initialExplicitPolicy,
+                initialAnyPolicyInhibit,
+                numCerts,
+                &polCheckerState,
+                plContext),
+                PKIX_POLICYCHECKERSTATECREATEFAILED);
+
+        /* Create the list of extensions that we handle */
+        PKIX_CHECK(pkix_PolicyChecker_MakeSingleton
+                ((PKIX_PL_Object *)(polCheckerState->certPoliciesExtension),
+                PKIX_TRUE,
+                &policyExtensions,
+                plContext),
+                PKIX_POLICYCHECKERMAKESINGLETONFAILED);
+
+        PKIX_CHECK(PKIX_CertChainChecker_Create
+                (pkix_PolicyChecker_Check,
+                PKIX_FALSE,     /* forwardCheckingSupported */
+                PKIX_FALSE,
+                policyExtensions,
+                (PKIX_PL_Object *)polCheckerState,
+                pChecker,
+                plContext),
+                PKIX_CERTCHAINCHECKERCREATEFAILED);
+
+cleanup:
+        PKIX_DECREF(polCheckerState);
+        PKIX_DECREF(policyExtensions);
+        PKIX_RETURN(CERTCHAINCHECKER);
+
+}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)