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