summaryrefslogtreecommitdiff
path: root/mozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c
diff options
context:
space:
mode:
Diffstat (limited to 'mozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c')
-rwxr-xr-xmozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c2816
1 files changed, 2816 insertions, 0 deletions
diff --git a/mozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c b/mozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c
new file mode 100755
index 0000000..541402d
--- /dev/null
+++ b/mozilla/security/nss/lib/libpkix/pkix/checker/pkix_policychecker.c
@@ -0,0 +1,2816 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the PKIX-C library.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are
+ * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Sun Microsystems, Inc.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/*
+ * pkix_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);
+
+}