| /* 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, ¤tPolicy, plContext), |
| PKIX_POLICYNODEGETVALIDPOLICYFAILED); |
| |
| PKIX_NULLCHECK_TWO(state->anyPolicyOID, currentPolicy); |
| |
| PKIX_EQUALS |
| (state->anyPolicyOID, |
| currentPolicy, |
| ¤tPolicyIsAny, |
| 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, |
| ¤tPolicyIsValid, |
| 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); |
| |
| } |