| /* 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)((char *)node->parent - (char *)NULL); |
| |
| 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); |
| } |