/* 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_policynode.c * * Policy Node Object Type Definition * */ #include "pkix_policynode.h" /* --Private-PolicyNode-Functions---------------------------------- */ /* * FUNCTION: pkix_PolicyNode_GetChildrenMutable * DESCRIPTION: * * Retrieves the List of PolicyNodes representing the child nodes of the * Policy Node pointed to by "node" and stores it at "pChildren". If "node" * has no List of child nodes, this function stores NULL at "pChildren". * * Note that the List returned by this function may be mutable. This function * differs from the public function PKIX_PolicyNode_GetChildren in that * respect. (It also differs in that the public function creates an empty * List, if necessary, rather than storing NULL.) * * During certificate processing, children Lists are created and modified. * Once the list is accessed using the public call, the List is set immutable. * * PARAMETERS: * "node" * Address of PolicyNode whose child nodes are to be stored. * Must be non-NULL. * "pChildren" * Address where object pointer will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a PolicyNode 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_PolicyNode_GetChildrenMutable( PKIX_PolicyNode *node, PKIX_List **pChildren, /* list of PKIX_PolicyNode */ void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_GetChildrenMutable"); PKIX_NULLCHECK_TWO(node, pChildren); PKIX_INCREF(node->children); *pChildren = node->children; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Create * DESCRIPTION: * * Creates a new PolicyNode using the OID pointed to by "validPolicy", the List * of CertPolicyQualifiers pointed to by "qualifierSet", the criticality * indicated by the Boolean value of "criticality", and the List of OIDs * pointed to by "expectedPolicySet", and stores the result at "pObject". The * criticality should be derived from whether the certificate policy extension * was marked as critical in the certificate that led to creation of this * PolicyNode. The "qualifierSet" and "expectedPolicySet" Lists are made * immutable. The PolicyNode pointers to parent and to children are initialized * to NULL, and the depth is set to zero; those values should be set by using * the pkix_PolicyNode_AddToParent function. * * PARAMETERS * "validPolicy" * Address of OID of the valid policy for the path. Must be non-NULL * "qualifierSet" * Address of List of CertPolicyQualifiers associated with the validpolicy. * May be NULL * "criticality" * Boolean indicator of whether the criticality should be set in this * PolicyNode * "expectedPolicySet" * Address of List of OIDs that would satisfy this policy in the next * certificate. Must be non-NULL * "pObject" * Address where the PolicyNode pointer will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a PolicyNode 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_PolicyNode_Create( PKIX_PL_OID *validPolicy, PKIX_List *qualifierSet, PKIX_Boolean criticality, PKIX_List *expectedPolicySet, PKIX_PolicyNode **pObject, void *plContext) { PKIX_PolicyNode *node = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Create"); PKIX_NULLCHECK_THREE(validPolicy, expectedPolicySet, pObject); PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_CERTPOLICYNODE_TYPE, sizeof (PKIX_PolicyNode), (PKIX_PL_Object **)&node, plContext), PKIX_COULDNOTCREATEPOLICYNODEOBJECT); PKIX_INCREF(validPolicy); node->validPolicy = validPolicy; PKIX_INCREF(qualifierSet); node->qualifierSet = qualifierSet; if (qualifierSet) { PKIX_CHECK(PKIX_List_SetImmutable(qualifierSet, plContext), PKIX_LISTSETIMMUTABLEFAILED); } node->criticality = criticality; PKIX_INCREF(expectedPolicySet); node->expectedPolicySet = expectedPolicySet; PKIX_CHECK(PKIX_List_SetImmutable(expectedPolicySet, plContext), PKIX_LISTSETIMMUTABLEFAILED); node->parent = NULL; node->children = NULL; node->depth = 0; *pObject = node; node = NULL; cleanup: PKIX_DECREF(node); PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_AddToParent * DESCRIPTION: * * Adds the PolicyNode pointed to by "child" to the List of children of * the PolicyNode pointed to by "parentNode". If "parentNode" had a * NULL pointer for the List of children, a new List is created containing * "child". Otherwise "child" is appended to the existing List. The * parent field in "child" is set to "parent", and the depth field is * set to one more than the corresponding value in "parent". * * Depth, in this context, means distance from the root node, which * is at depth zero. * * PARAMETERS: * "parentNode" * Address of PolicyNode whose List of child PolicyNodes is to be * created or appended to. Must be non-NULL. * "child" * Address of PolicyNode to be added to parentNode's List. 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 PolicyNode 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_PolicyNode_AddToParent( PKIX_PolicyNode *parentNode, PKIX_PolicyNode *child, void *plContext) { PKIX_List *listOfChildren = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_AddToParent"); PKIX_NULLCHECK_TWO(parentNode, child); listOfChildren = parentNode->children; if (listOfChildren == NULL) { PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext), PKIX_LISTCREATEFAILED); parentNode->children = listOfChildren; } /* * Note: this link is not reference-counted. The link from parent * to child is counted (actually, the parent "owns" a List which * "owns" children), but the children do not "own" the parent. * Otherwise, there would be loops. */ child->parent = parentNode; child->depth = 1 + (parentNode->depth); PKIX_CHECK(PKIX_List_AppendItem (listOfChildren, (PKIX_PL_Object *)child, plContext), PKIX_COULDNOTAPPENDCHILDTOPARENTSPOLICYNODELIST); PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)parentNode, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)child, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Prune * DESCRIPTION: * * Prunes a tree below the PolicyNode whose address is pointed to by "node", * using the UInt32 value of "height" as the distance from the leaf level, * and storing at "pDelete" the Boolean value of whether this PolicyNode is, * after pruning, childless and should be pruned. * * Any PolicyNode at height 0 is allowed to survive. If the height is greater * than zero, pkix_PolicyNode_Prune is called recursively for each child of * the current PolicyNode. After this process, a node with no children * stores PKIX_TRUE in "pDelete" to indicate that it should be deleted. * * PARAMETERS: * "node" * Address of the PolicyNode to be pruned. Must be non-NULL. * "height" * UInt32 value for the distance from the leaf level * "pDelete" * Address to store the Boolean return value of PKIX_TRUE if this node * should be pruned, or PKIX_FALSE if there remains at least one * branch of the required height. 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 PolicyNode 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_PolicyNode_Prune( PKIX_PolicyNode *node, PKIX_UInt32 height, PKIX_Boolean *pDelete, void *plContext) { PKIX_Boolean childless = PKIX_FALSE; PKIX_Boolean shouldBePruned = PKIX_FALSE; PKIX_UInt32 listSize = 0; PKIX_UInt32 listIndex = 0; PKIX_PolicyNode *candidate = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Prune"); PKIX_NULLCHECK_TWO(node, pDelete); /* Don't prune at the leaf */ if (height == 0) { goto cleanup; } /* Above the bottom level, childless nodes get pruned */ if (!(node->children)) { childless = PKIX_TRUE; goto cleanup; } /* * This node has children. If they are leaf nodes, * we know they will live. Otherwise, check them out. */ if (height > 1) { PKIX_CHECK(PKIX_List_GetLength (node->children, &listSize, plContext), PKIX_LISTGETLENGTHFAILED); /* * By working backwards from the end of the list, * we avoid having to worry about possible * decreases in the size of the list, as we * delete items. The only nuisance is that since the * index is UInt32, we can't check for it to reach -1; * we have to use the 1-based index, rather than the * 0-based index that PKIX_List functions require. */ for (listIndex = listSize; listIndex > 0; listIndex--) { PKIX_CHECK(PKIX_List_GetItem (node->children, (listIndex - 1), (PKIX_PL_Object **)&candidate, plContext), PKIX_LISTGETITEMFAILED); PKIX_CHECK(pkix_PolicyNode_Prune (candidate, height - 1, &shouldBePruned, plContext), PKIX_POLICYNODEPRUNEFAILED); if (shouldBePruned == PKIX_TRUE) { PKIX_CHECK(PKIX_List_DeleteItem (node->children, (listIndex - 1), plContext), PKIX_LISTDELETEITEMFAILED); } PKIX_DECREF(candidate); } } /* Prune if this node has *become* childless */ PKIX_CHECK(PKIX_List_GetLength (node->children, &listSize, plContext), PKIX_LISTGETLENGTHFAILED); if (listSize == 0) { childless = PKIX_TRUE; } /* * Even if we did not change this node, or any of its children, * maybe a [great-]*grandchild was pruned. */ PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)node, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); cleanup: *pDelete = childless; PKIX_DECREF(candidate); PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_SinglePolicyNode_ToString * DESCRIPTION: * * Creates a String representation of the attributes of the PolicyNode * pointed to by "node", other than its parents or children, and * stores the result at "pString". * * PARAMETERS: * "node" * Address of PolicyNode to be described by the string. Must be non-NULL. * "pString" * Address where object pointer will be stored. Must be non-NULL. * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if function succeeds * Returns a PolicyNode Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in a fatal way */ PKIX_Error * pkix_SinglePolicyNode_ToString( PKIX_PolicyNode *node, PKIX_PL_String **pString, void *plContext) { PKIX_PL_String *fmtString = NULL; PKIX_PL_String *validString = NULL; PKIX_PL_String *qualifierString = NULL; PKIX_PL_String *criticalityString = NULL; PKIX_PL_String *expectedString = NULL; PKIX_PL_String *outString = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_ToString"); PKIX_NULLCHECK_TWO(node, pString); PKIX_NULLCHECK_TWO(node->validPolicy, node->expectedPolicySet); PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "{%s,%s,%s,%s,%d}", 0, &fmtString, plContext), PKIX_CANTCREATESTRING); PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)(node->validPolicy), &validString, plContext), PKIX_OIDTOSTRINGFAILED); PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)(node->expectedPolicySet), &expectedString, plContext), PKIX_LISTTOSTRINGFAILED); if (node->qualifierSet) { PKIX_CHECK(PKIX_PL_Object_ToString ((PKIX_PL_Object *)(node->qualifierSet), &qualifierString, plContext), PKIX_LISTTOSTRINGFAILED); } else { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "{}", 0, &qualifierString, plContext), PKIX_CANTCREATESTRING); } PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, (node->criticality)?"Critical":"Not Critical", 0, &criticalityString, plContext), PKIX_CANTCREATESTRING); PKIX_CHECK(PKIX_PL_Sprintf (&outString, plContext, fmtString, validString, qualifierString, criticalityString, expectedString, node->depth), PKIX_SPRINTFFAILED); *pString = outString; cleanup: PKIX_DECREF(fmtString); PKIX_DECREF(validString); PKIX_DECREF(qualifierString); PKIX_DECREF(criticalityString); PKIX_DECREF(expectedString); PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_ToString_Helper * DESCRIPTION: * * Produces a String representation of a PolicyNode tree below the PolicyNode * pointed to by "rootNode", with each line of output prefixed by the String * pointed to by "indent", and stores the result at "pTreeString". It is * called recursively, with ever-increasing indentation, for successively * lower nodes on the tree. * * PARAMETERS: * "rootNode" * Address of PolicyNode subtree. Must be non-NULL. * "indent" * Address of String to be prefixed to each line of output. May be NULL * if no indentation is desired * "pTreeString" * Address where the resulting String will be stored; must be non-NULL * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if the function succeeds. * Returns a PolicyNode Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_PolicyNode_ToString_Helper( PKIX_PolicyNode *rootNode, PKIX_PL_String *indent, PKIX_PL_String **pTreeString, void *plContext) { PKIX_PL_String *nextIndentFormat = NULL; PKIX_PL_String *thisNodeFormat = NULL; PKIX_PL_String *childrenFormat = NULL; PKIX_PL_String *nextIndentString = NULL; PKIX_PL_String *resultString = NULL; PKIX_PL_String *thisItemString = NULL; PKIX_PL_String *childString = NULL; PKIX_PolicyNode *childNode = NULL; PKIX_UInt32 numberOfChildren = 0; PKIX_UInt32 childIndex = 0; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_ToString_Helper"); PKIX_NULLCHECK_TWO(rootNode, pTreeString); /* Create a string for this node */ PKIX_CHECK(pkix_SinglePolicyNode_ToString (rootNode, &thisItemString, plContext), PKIX_ERRORINSINGLEPOLICYNODETOSTRING); if (indent) { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "%s%s", 0, &thisNodeFormat, plContext), PKIX_ERRORCREATINGFORMATSTRING); PKIX_CHECK(PKIX_PL_Sprintf (&resultString, plContext, thisNodeFormat, indent, thisItemString), PKIX_ERRORINSPRINTF); } else { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "%s", 0, &thisNodeFormat, plContext), PKIX_ERRORCREATINGFORMATSTRING); PKIX_CHECK(PKIX_PL_Sprintf (&resultString, plContext, thisNodeFormat, thisItemString), PKIX_ERRORINSPRINTF); } PKIX_DECREF(thisItemString); thisItemString = resultString; /* if no children, we are done */ if (rootNode->children) { PKIX_CHECK(PKIX_List_GetLength (rootNode->children, &numberOfChildren, plContext), PKIX_LISTGETLENGTHFAILED); } if (numberOfChildren != 0) { /* * We create a string for each child in turn, * concatenating them to thisItemString. */ /* Prepare an indent string for each child */ if (indent) { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "%s. ", 0, &nextIndentFormat, plContext), PKIX_ERRORCREATINGFORMATSTRING); PKIX_CHECK(PKIX_PL_Sprintf (&nextIndentString, plContext, nextIndentFormat, indent), PKIX_ERRORINSPRINTF); } else { PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, ". ", 0, &nextIndentString, plContext), PKIX_ERRORCREATINGINDENTSTRING); } /* Prepare the format for concatenation. */ PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "%s\n%s", 0, &childrenFormat, plContext), PKIX_ERRORCREATINGFORMATSTRING); for (childIndex = 0; childIndex < numberOfChildren; childIndex++) { PKIX_CHECK(PKIX_List_GetItem (rootNode->children, childIndex, (PKIX_PL_Object **)&childNode, plContext), PKIX_LISTGETITEMFAILED); PKIX_CHECK(pkix_PolicyNode_ToString_Helper (childNode, nextIndentString, &childString, plContext), PKIX_ERRORCREATINGCHILDSTRING); PKIX_CHECK(PKIX_PL_Sprintf (&resultString, plContext, childrenFormat, thisItemString, childString), PKIX_ERRORINSPRINTF); PKIX_DECREF(childNode); PKIX_DECREF(childString); PKIX_DECREF(thisItemString); thisItemString = resultString; } } *pTreeString = thisItemString; cleanup: if (PKIX_ERROR_RECEIVED) { PKIX_DECREF(thisItemString); } PKIX_DECREF(nextIndentFormat); PKIX_DECREF(thisNodeFormat); PKIX_DECREF(childrenFormat); PKIX_DECREF(nextIndentString); PKIX_DECREF(childString); PKIX_DECREF(childNode); PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_ToString * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_PolicyNode_ToString( PKIX_PL_Object *object, PKIX_PL_String **pTreeString, void *plContext) { PKIX_PolicyNode *rootNode = NULL; PKIX_PL_String *resultString = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_ToString"); PKIX_NULLCHECK_TWO(object, pTreeString); PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYNODE_TYPE, plContext), PKIX_OBJECTNOTPOLICYNODE); rootNode = (PKIX_PolicyNode *)object; PKIX_CHECK(pkix_PolicyNode_ToString_Helper (rootNode, NULL, &resultString, plContext), PKIX_ERRORCREATINGSUBTREESTRING); *pTreeString = resultString; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Destroy * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_PolicyNode_Destroy( PKIX_PL_Object *object, void *plContext) { PKIX_PolicyNode *node = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Destroy"); PKIX_NULLCHECK_ONE(object); PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYNODE_TYPE, plContext), PKIX_OBJECTNOTPOLICYNODE); node = (PKIX_PolicyNode*)object; node->criticality = PKIX_FALSE; PKIX_DECREF(node->validPolicy); PKIX_DECREF(node->qualifierSet); PKIX_DECREF(node->expectedPolicySet); PKIX_DECREF(node->children); /* * Note: the link to parent is not reference-counted. See comment * in pkix_PolicyNode_AddToParent for more details. */ node->parent = NULL; node->depth = 0; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_SinglePolicyNode_Hashcode * DESCRIPTION: * * Computes the hashcode of the attributes of the PolicyNode pointed to by * "node", other than its parents and children, and stores the result at * "pHashcode". * * PARAMETERS: * "node" * Address of PolicyNode to be hashcoded; must be non-NULL * "pHashcode" * Address where UInt32 result will be stored; must be non-NULL * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if function succeeds * Returns a PolicyNode Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in a fatal way */ static PKIX_Error * pkix_SinglePolicyNode_Hashcode( PKIX_PolicyNode *node, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_UInt32 componentHash = 0; PKIX_UInt32 nodeHash = 0; PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_Hashcode"); PKIX_NULLCHECK_TWO(node, pHashcode); PKIX_NULLCHECK_TWO(node->validPolicy, node->expectedPolicySet); PKIX_HASHCODE (node->qualifierSet, &nodeHash, plContext, PKIX_FAILUREHASHINGLISTQUALIFIERSET); if (PKIX_TRUE == (node->criticality)) { nodeHash = 31*nodeHash + 0xff; } else { nodeHash = 31*nodeHash + 0x00; } PKIX_CHECK(PKIX_PL_Object_Hashcode ((PKIX_PL_Object *)node->validPolicy, &componentHash, plContext), PKIX_FAILUREHASHINGOIDVALIDPOLICY); nodeHash = 31*nodeHash + componentHash; PKIX_CHECK(PKIX_PL_Object_Hashcode ((PKIX_PL_Object *)node->expectedPolicySet, &componentHash, plContext), PKIX_FAILUREHASHINGLISTEXPECTEDPOLICYSET); nodeHash = 31*nodeHash + componentHash; *pHashcode = nodeHash; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Hashcode * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_PolicyNode_Hashcode( PKIX_PL_Object *object, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_PolicyNode *node = NULL; PKIX_UInt32 childrenHash = 0; PKIX_UInt32 nodeHash = 0; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Hashcode"); PKIX_NULLCHECK_TWO(object, pHashcode); PKIX_CHECK(pkix_CheckType (object, PKIX_CERTPOLICYNODE_TYPE, plContext), PKIX_OBJECTNOTPOLICYNODE); node = (PKIX_PolicyNode *)object; PKIX_CHECK(pkix_SinglePolicyNode_Hashcode (node, &nodeHash, plContext), PKIX_SINGLEPOLICYNODEHASHCODEFAILED); nodeHash = 31*nodeHash + (PKIX_UInt32)(node->parent); PKIX_HASHCODE (node->children, &childrenHash, plContext, PKIX_OBJECTHASHCODEFAILED); nodeHash = 31*nodeHash + childrenHash; *pHashcode = nodeHash; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_SinglePolicyNode_Equals * DESCRIPTION: * * Compares for equality the components of the PolicyNode pointed to by * "firstPN", other than its parents and children, with those of the * PolicyNode pointed to by "secondPN" and stores the result at "pResult" * (PKIX_TRUE if equal; PKIX_FALSE if not). * * PARAMETERS: * "firstPN" * Address of first of the PolicyNodes to be compared; must be non-NULL * "secondPN" * Address of second of the PolicyNodes to be compared; must be non-NULL * "pResult" * Address where Boolean will be stored; must be non-NULL * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if function succeeds * Returns a PolicyNode Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in a fatal way */ static PKIX_Error * pkix_SinglePolicyNode_Equals( PKIX_PolicyNode *firstPN, PKIX_PolicyNode *secondPN, PKIX_Boolean *pResult, void *plContext) { PKIX_Boolean compResult = PKIX_FALSE; PKIX_ENTER(CERTPOLICYNODE, "pkix_SinglePolicyNode_Equals"); PKIX_NULLCHECK_THREE(firstPN, secondPN, pResult); /* If both references are identical, they must be equal */ if (firstPN == secondPN) { compResult = PKIX_TRUE; goto cleanup; } /* * It seems we have to do the comparisons. Do * the easiest ones first. */ if ((firstPN->criticality) != (secondPN->criticality)) { goto cleanup; } if ((firstPN->depth) != (secondPN->depth)) { goto cleanup; } PKIX_EQUALS (firstPN->qualifierSet, secondPN->qualifierSet, &compResult, plContext, PKIX_OBJECTEQUALSFAILED); if (compResult == PKIX_FALSE) { goto cleanup; } /* These fields must be non-NULL */ PKIX_NULLCHECK_TWO(firstPN->validPolicy, secondPN->validPolicy); PKIX_EQUALS (firstPN->validPolicy, secondPN->validPolicy, &compResult, plContext, PKIX_OBJECTEQUALSFAILED); if (compResult == PKIX_FALSE) { goto cleanup; } /* These fields must be non-NULL */ PKIX_NULLCHECK_TWO (firstPN->expectedPolicySet, secondPN->expectedPolicySet); PKIX_EQUALS (firstPN->expectedPolicySet, secondPN->expectedPolicySet, &compResult, plContext, PKIX_OBJECTEQUALSFAILEDONEXPECTEDPOLICYSETS); cleanup: *pResult = compResult; PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Equals * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_PolicyNode_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Boolean *pResult, void *plContext) { PKIX_PolicyNode *firstPN = NULL; PKIX_PolicyNode *secondPN = NULL; PKIX_UInt32 secondType; PKIX_Boolean compResult = PKIX_FALSE; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); /* test that firstObject is a PolicyNode */ PKIX_CHECK(pkix_CheckType (firstObject, PKIX_CERTPOLICYNODE_TYPE, plContext), PKIX_FIRSTOBJECTNOTPOLICYNODE); /* * Since we know firstObject is a PolicyNode, * if both references are identical, they must be equal */ if (firstObject == secondObject){ compResult = PKIX_TRUE; goto cleanup; } /* * If secondObject isn't a PolicyNode, we * don't throw an error. We simply return FALSE. */ PKIX_CHECK(PKIX_PL_Object_GetType (secondObject, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); if (secondType != PKIX_CERTPOLICYNODE_TYPE) { goto cleanup; } /* * Oh, well, we have to do the comparisons. Do * the easiest ones first. */ firstPN = (PKIX_PolicyNode *)firstObject; secondPN = (PKIX_PolicyNode *)secondObject; /* * We don't require the parents to be identical. In the * course of traversing the tree, we will have checked the * attributes of the parent nodes, and checking the lists * of children will determine whether they match. */ PKIX_EQUALS (firstPN->children, secondPN->children, &compResult, plContext, PKIX_OBJECTEQUALSFAILEDONCHILDREN); if (compResult == PKIX_FALSE) { goto cleanup; } PKIX_CHECK(pkix_SinglePolicyNode_Equals (firstPN, secondPN, &compResult, plContext), PKIX_SINGLEPOLICYNODEEQUALSFAILED); cleanup: *pResult = compResult; PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_DuplicateHelper * DESCRIPTION: * * Duplicates the PolicyNode whose address is pointed to by "original", * and stores the result at "pNewNode", if a non-NULL pointer is provided * for "pNewNode". In addition, the created PolicyNode is added as a child * to "parent", if a non-NULL pointer is provided for "parent". Then this * function is called recursively to duplicate each of the children of * "original". At the top level this function is called with a null * "parent" and a non-NULL "pNewNode". Below the top level "parent" will * be non-NULL and "pNewNode" will be NULL. * * PARAMETERS: * "original" * Address of PolicyNode to be copied; must be non-NULL * "parent" * Address of PolicyNode to which the created node is to be added as a * child; NULL for the top-level call and non-NULL below the top level * "pNewNode" * Address to store the node created; should be NULL if "parent" is * non-NULL and vice versa * "plContext" * Platform-specific context pointer. * THREAD SAFETY: * Conditionally Thread Safe * (see Thread Safety Definitions in Programmer's Guide) * RETURNS: * Returns NULL if function succeeds * Returns a PolicyNode Error if the function fails in a non-fatal way. * Returns a Fatal Error if the function fails in a fatal way */ static PKIX_Error * pkix_PolicyNode_DuplicateHelper( PKIX_PolicyNode *original, PKIX_PolicyNode *parent, PKIX_PolicyNode **pNewNode, void *plContext) { PKIX_UInt32 numChildren = 0; PKIX_UInt32 childIndex = 0; PKIX_List *children = NULL; /* List of PKIX_PolicyNode */ PKIX_PolicyNode *copy = NULL; PKIX_PolicyNode *child = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_DuplicateHelper"); PKIX_NULLCHECK_THREE (original, original->validPolicy, original->expectedPolicySet); /* * These components are immutable, so copying the pointers * is sufficient. The create function increments the reference * counts as it stores the pointers into the new object. */ PKIX_CHECK(pkix_PolicyNode_Create (original->validPolicy, original->qualifierSet, original->criticality, original->expectedPolicySet, ©, plContext), PKIX_POLICYNODECREATEFAILED); if (parent) { PKIX_CHECK(pkix_PolicyNode_AddToParent(parent, copy, plContext), PKIX_POLICYNODEADDTOPARENTFAILED); } /* Are there any children to duplicate? */ children = original->children; if (children) { PKIX_CHECK(PKIX_List_GetLength(children, &numChildren, plContext), PKIX_LISTGETLENGTHFAILED); } for (childIndex = 0; childIndex < numChildren; childIndex++) { PKIX_CHECK(PKIX_List_GetItem (children, childIndex, (PKIX_PL_Object **)&child, plContext), PKIX_LISTGETITEMFAILED); PKIX_CHECK(pkix_PolicyNode_DuplicateHelper (child, copy, NULL, plContext), PKIX_POLICYNODEDUPLICATEHELPERFAILED); PKIX_DECREF(child); } if (pNewNode) { *pNewNode = copy; copy = NULL; /* no DecRef if we give our handle away */ } cleanup: PKIX_DECREF(copy); PKIX_DECREF(child); PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_Duplicate * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_PolicyNode_Duplicate( PKIX_PL_Object *object, PKIX_PL_Object **pNewObject, void *plContext) { PKIX_PolicyNode *original = NULL; PKIX_PolicyNode *copy = NULL; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_Duplicate"); PKIX_NULLCHECK_TWO(object, pNewObject); PKIX_CHECK(pkix_CheckType (object, PKIX_CERTPOLICYNODE_TYPE, plContext), PKIX_OBJECTNOTPOLICYNODE); original = (PKIX_PolicyNode *)object; PKIX_CHECK(pkix_PolicyNode_DuplicateHelper (original, NULL, ©, plContext), PKIX_POLICYNODEDUPLICATEHELPERFAILED); *pNewObject = (PKIX_PL_Object *)copy; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: pkix_PolicyNode_RegisterSelf * DESCRIPTION: * * Registers PKIX_CERTPOLICYNODE_TYPE and its related * functions with systemClasses[] * * 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_PolicyNode_RegisterSelf(void *plContext) { extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; pkix_ClassTable_Entry entry; PKIX_ENTER(CERTPOLICYNODE, "pkix_PolicyNode_RegisterSelf"); entry.description = "PolicyNode"; entry.objCounter = 0; entry.typeObjectSize = sizeof(PKIX_PolicyNode); entry.destructor = pkix_PolicyNode_Destroy; entry.equalsFunction = pkix_PolicyNode_Equals; entry.hashcodeFunction = pkix_PolicyNode_Hashcode; entry.toStringFunction = pkix_PolicyNode_ToString; entry.comparator = NULL; entry.duplicateFunction = pkix_PolicyNode_Duplicate; systemClasses[PKIX_CERTPOLICYNODE_TYPE] = entry; PKIX_RETURN(CERTPOLICYNODE); } /* --Public-PolicyNode-Functions----------------------------------- */ /* * FUNCTION: PKIX_PolicyNode_GetChildren * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetChildren( PKIX_PolicyNode *node, PKIX_List **pChildren, /* list of PKIX_PolicyNode */ void *plContext) { PKIX_List *children = NULL; PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetChildren"); PKIX_NULLCHECK_TWO(node, pChildren); PKIX_INCREF(node->children); children = node->children; if (!children) { PKIX_CHECK(PKIX_List_Create(&children, plContext), PKIX_LISTCREATEFAILED); } PKIX_CHECK(PKIX_List_SetImmutable(children, plContext), PKIX_LISTSETIMMUTABLEFAILED); *pChildren = children; cleanup: if (PKIX_ERROR_RECEIVED) { PKIX_DECREF(children); } PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_GetParent * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetParent( PKIX_PolicyNode *node, PKIX_PolicyNode **pParent, void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetParent"); PKIX_NULLCHECK_TWO(node, pParent); PKIX_INCREF(node->parent); *pParent = node->parent; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_GetValidPolicy * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetValidPolicy( PKIX_PolicyNode *node, PKIX_PL_OID **pValidPolicy, void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetValidPolicy"); PKIX_NULLCHECK_TWO(node, pValidPolicy); PKIX_INCREF(node->validPolicy); *pValidPolicy = node->validPolicy; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_GetPolicyQualifiers * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetPolicyQualifiers( PKIX_PolicyNode *node, PKIX_List **pQualifiers, /* list of PKIX_PL_CertPolicyQualifier */ void *plContext) { PKIX_List *qualifiers = NULL; PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetPolicyQualifiers"); PKIX_NULLCHECK_TWO(node, pQualifiers); PKIX_INCREF(node->qualifierSet); qualifiers = node->qualifierSet; if (!qualifiers) { PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext), PKIX_LISTCREATEFAILED); } PKIX_CHECK(PKIX_List_SetImmutable(qualifiers, plContext), PKIX_LISTSETIMMUTABLEFAILED); *pQualifiers = qualifiers; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_GetExpectedPolicies * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetExpectedPolicies( PKIX_PolicyNode *node, PKIX_List **pExpPolicies, /* list of PKIX_PL_OID */ void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetExpectedPolicies"); PKIX_NULLCHECK_TWO(node, pExpPolicies); PKIX_INCREF(node->expectedPolicySet); *pExpPolicies = node->expectedPolicySet; cleanup: PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_IsCritical * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_IsCritical( PKIX_PolicyNode *node, PKIX_Boolean *pCritical, void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_IsCritical"); PKIX_NULLCHECK_TWO(node, pCritical); *pCritical = node->criticality; PKIX_RETURN(CERTPOLICYNODE); } /* * FUNCTION: PKIX_PolicyNode_GetDepth * (see description of this function in pkix_results.h) */ PKIX_Error * PKIX_PolicyNode_GetDepth( PKIX_PolicyNode *node, PKIX_UInt32 *pDepth, void *plContext) { PKIX_ENTER(CERTPOLICYNODE, "PKIX_PolicyNode_GetDepth"); PKIX_NULLCHECK_TWO(node, pDepth); *pDepth = node->depth; PKIX_RETURN(CERTPOLICYNODE); }