/* 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_verifynode.c * * Verify Node Object Type Definition * */ #include "pkix_verifynode.h" /* --Private-VerifyNode-Functions---------------------------------- */ /* * FUNCTION: pkix_VerifyNode_Create * DESCRIPTION: * * This function creates a VerifyNode using the Cert pointed to by "cert", * the depth given by "depth", and the Error pointed to by "error", storing * the result at "pObject". * * PARAMETERS * "cert" * Address of Cert for the node. Must be non-NULL * "depth" * UInt32 value of the depth for this node. * "error" * Address of Error for the node. * "pObject" * Address where the VerifyNode 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 Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_VerifyNode_Create( PKIX_PL_Cert *cert, PKIX_UInt32 depth, PKIX_Error *error, PKIX_VerifyNode **pObject, void *plContext) { PKIX_VerifyNode *node = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Create"); PKIX_NULLCHECK_TWO(cert, pObject); PKIX_CHECK(PKIX_PL_Object_Alloc (PKIX_VERIFYNODE_TYPE, sizeof (PKIX_VerifyNode), (PKIX_PL_Object **)&node, plContext), PKIX_COULDNOTCREATEVERIFYNODEOBJECT); PKIX_INCREF(cert); node->verifyCert = cert; PKIX_INCREF(error); node->error = error; node->depth = depth; node->children = NULL; *pObject = node; node = NULL; cleanup: PKIX_DECREF(node); PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_AddToChain * DESCRIPTION: * * Adds the VerifyNode pointed to by "child", at the appropriate depth, to the * List of children of the VerifyNode pointed to by "parentNode". The chain of * VerifyNodes is traversed until a VerifyNode is found at a depth one less * than that specified in "child". An Error is returned if there is no parent * at a suitable depth. * * If "parentNode" has a NULL pointer for the List of children, a new List is * created containing "child". Otherwise "child" is appended to the existing * List. * * Depth, in this context, means distance from the root node, which * is at depth zero. * * PARAMETERS: * "parentNode" * Address of VerifyNode whose List of child VerifyNodes is to be * created or appended to. Must be non-NULL. * "child" * Address of VerifyNode 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 VerifyNode 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_VerifyNode_AddToChain( PKIX_VerifyNode *parentNode, PKIX_VerifyNode *child, void *plContext) { PKIX_VerifyNode *successor = NULL; PKIX_List *listOfChildren = NULL; PKIX_UInt32 numChildren = 0; PKIX_UInt32 parentDepth = 0; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_AddToChain"); PKIX_NULLCHECK_TWO(parentNode, child); parentDepth = parentNode->depth; listOfChildren = parentNode->children; if (listOfChildren == NULL) { if (parentDepth != (child->depth - 1)) { PKIX_ERROR(PKIX_NODESMISSINGFROMCHAIN); } PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext), PKIX_LISTCREATEFAILED); PKIX_CHECK(PKIX_List_AppendItem (listOfChildren, (PKIX_PL_Object *)child, plContext), PKIX_COULDNOTAPPENDCHILDTOPARENTSVERIFYNODELIST); parentNode->children = listOfChildren; } else { /* get number of children */ PKIX_CHECK(PKIX_List_GetLength (listOfChildren, &numChildren, plContext), PKIX_LISTGETLENGTHFAILED); if (numChildren != 1) { PKIX_ERROR(PKIX_AMBIGUOUSPARENTAGEOFVERIFYNODE); } /* successor = listOfChildren[0] */ PKIX_CHECK(PKIX_List_GetItem (listOfChildren, 0, (PKIX_PL_Object **)&successor, plContext), PKIX_LISTGETITEMFAILED); PKIX_CHECK(pkix_VerifyNode_AddToChain (successor, child, plContext), PKIX_VERIFYNODEADDTOCHAINFAILED); } PKIX_CHECK(PKIX_PL_Object_InvalidateCache ((PKIX_PL_Object *)parentNode, plContext), PKIX_OBJECTINVALIDATECACHEFAILED); cleanup: PKIX_DECREF(successor); PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_SetDepth * DESCRIPTION: * * The function sets the depth field of each VerifyNode in the List "children" * to the value given by "depth", and recursively sets the depth of any * successive generations to the successive values. * * PARAMETERS: * "children" * The List of VerifyNodes. Must be non-NULL. * "depth" * The value of the depth field to be set in members of the List. * "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 Fatal Error if the function fails in an unrecoverable way. */ static PKIX_Error * pkix_VerifyNode_SetDepth(PKIX_List *children, PKIX_UInt32 depth, void *plContext) { PKIX_UInt32 numChildren = 0; PKIX_UInt32 chIx = 0; PKIX_VerifyNode *child = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_SetDepth"); PKIX_NULLCHECK_ONE(children); PKIX_CHECK(PKIX_List_GetLength(children, &numChildren, plContext), PKIX_LISTGETLENGTHFAILED); for (chIx = 0; chIx < numChildren; chIx++) { PKIX_CHECK(PKIX_List_GetItem (children, chIx, (PKIX_PL_Object **)&child, plContext), PKIX_LISTGETITEMFAILED); child->depth = depth; if (child->children != NULL) { PKIX_CHECK(pkix_VerifyNode_SetDepth (child->children, depth + 1, plContext), PKIX_VERIFYNODESETDEPTHFAILED); } PKIX_DECREF(child); } cleanup: PKIX_DECREF(child); PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_AddToTree * DESCRIPTION: * * Adds the VerifyNode pointed to by "child" to the List of children of the * VerifyNode pointed to by "parentNode". If "parentNode" has a NULL pointer * for the List of children, a new List is created containing "child". * Otherwise "child" is appended to the existing List. The depth field of * "child" is set to one more than the corresponding value in "parent", and * if the "child" itself has child nodes, their depth fields are updated * accordingly. * * Depth, in this context, means distance from the root node, which * is at depth zero. * * PARAMETERS: * "parentNode" * Address of VerifyNode whose List of child VerifyNodes is to be * created or appended to. Must be non-NULL. * "child" * Address of VerifyNode 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 Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_VerifyNode_AddToTree( PKIX_VerifyNode *parentNode, PKIX_VerifyNode *child, void *plContext) { PKIX_List *listOfChildren = NULL; PKIX_UInt32 parentDepth = 0; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_AddToTree"); PKIX_NULLCHECK_TWO(parentNode, child); parentDepth = parentNode->depth; listOfChildren = parentNode->children; if (listOfChildren == NULL) { PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext), PKIX_LISTCREATEFAILED); parentNode->children = listOfChildren; } child->depth = parentDepth + 1; PKIX_CHECK(PKIX_List_AppendItem (parentNode->children, (PKIX_PL_Object *)child, plContext), PKIX_COULDNOTAPPENDCHILDTOPARENTSVERIFYNODELIST); if (child->children != NULL) { PKIX_CHECK(pkix_VerifyNode_SetDepth (child->children, child->depth + 1, plContext), PKIX_VERIFYNODESETDEPTHFAILED); } cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_SingleVerifyNode_ToString * DESCRIPTION: * * Creates a String representation of the attributes of the VerifyNode pointed * to by "node", other than its children, and stores the result at "pString". * * PARAMETERS: * "node" * Address of VerifyNode 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 VerifyNode 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_SingleVerifyNode_ToString( PKIX_VerifyNode *node, PKIX_PL_String **pString, void *plContext) { PKIX_PL_String *fmtString = NULL; PKIX_PL_String *errorString = NULL; PKIX_PL_String *outString = NULL; PKIX_PL_X500Name *issuerName = NULL; PKIX_PL_X500Name *subjectName = NULL; PKIX_PL_String *issuerString = NULL; PKIX_PL_String *subjectString = NULL; PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_ToString"); PKIX_NULLCHECK_THREE(node, pString, node->verifyCert); PKIX_TOSTRING(node->error, &errorString, plContext, PKIX_ERRORTOSTRINGFAILED); PKIX_CHECK(PKIX_PL_Cert_GetIssuer (node->verifyCert, &issuerName, plContext), PKIX_CERTGETISSUERFAILED); PKIX_TOSTRING(issuerName, &issuerString, plContext, PKIX_X500NAMETOSTRINGFAILED); PKIX_CHECK(PKIX_PL_Cert_GetSubject (node->verifyCert, &subjectName, plContext), PKIX_CERTGETSUBJECTFAILED); PKIX_TOSTRING(subjectName, &subjectString, plContext, PKIX_X500NAMETOSTRINGFAILED); PKIX_CHECK(PKIX_PL_String_Create (PKIX_ESCASCII, "CERT[Issuer:%s, Subject:%s], depth=%d, error=%s", 0, &fmtString, plContext), PKIX_CANTCREATESTRING); PKIX_CHECK(PKIX_PL_Sprintf (&outString, plContext, fmtString, issuerString, subjectString, node->depth, errorString), PKIX_SPRINTFFAILED); *pString = outString; cleanup: PKIX_DECREF(fmtString); PKIX_DECREF(errorString); PKIX_DECREF(issuerName); PKIX_DECREF(subjectName); PKIX_DECREF(issuerString); PKIX_DECREF(subjectString); PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_ToString_Helper * DESCRIPTION: * * Produces a String representation of a VerifyNode tree below the VerifyNode * 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 VerifyNode 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 VerifyNode 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_VerifyNode_ToString_Helper( PKIX_VerifyNode *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_VerifyNode *childNode = NULL; PKIX_UInt32 numberOfChildren = 0; PKIX_UInt32 childIndex = 0; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_ToString_Helper"); PKIX_NULLCHECK_TWO(rootNode, pTreeString); /* Create a string for this node */ PKIX_CHECK(pkix_SingleVerifyNode_ToString (rootNode, &thisItemString, plContext), PKIX_ERRORINSINGLEVERIFYNODETOSTRING); 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_VerifyNode_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(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_ToString * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_VerifyNode_ToString( PKIX_PL_Object *object, PKIX_PL_String **pTreeString, void *plContext) { PKIX_VerifyNode *rootNode = NULL; PKIX_PL_String *resultString = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_ToString"); PKIX_NULLCHECK_TWO(object, pTreeString); PKIX_CHECK(pkix_CheckType(object, PKIX_VERIFYNODE_TYPE, plContext), PKIX_OBJECTNOTVERIFYNODE); rootNode = (PKIX_VerifyNode *)object; PKIX_CHECK(pkix_VerifyNode_ToString_Helper (rootNode, NULL, &resultString, plContext), PKIX_ERRORCREATINGSUBTREESTRING); *pTreeString = resultString; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_Destroy * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_VerifyNode_Destroy( PKIX_PL_Object *object, void *plContext) { PKIX_VerifyNode *node = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Destroy"); PKIX_NULLCHECK_ONE(object); PKIX_CHECK(pkix_CheckType(object, PKIX_VERIFYNODE_TYPE, plContext), PKIX_OBJECTNOTVERIFYNODE); node = (PKIX_VerifyNode*)object; PKIX_DECREF(node->verifyCert); PKIX_DECREF(node->children); PKIX_DECREF(node->error); node->depth = 0; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_SingleVerifyNode_Hashcode * DESCRIPTION: * * Computes the hashcode of the attributes of the VerifyNode pointed to by * "node", other than its parents and children, and stores the result at * "pHashcode". * * PARAMETERS: * "node" * Address of VerifyNode 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 VerifyNode 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_SingleVerifyNode_Hashcode( PKIX_VerifyNode *node, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_UInt32 errorHash = 0; PKIX_UInt32 nodeHash = 0; PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_Hashcode"); PKIX_NULLCHECK_TWO(node, pHashcode); PKIX_HASHCODE (node->verifyCert, &nodeHash, plContext, PKIX_FAILUREHASHINGCERT); PKIX_CHECK(PKIX_PL_Object_Hashcode ((PKIX_PL_Object *)node->error, &errorHash, plContext), PKIX_FAILUREHASHINGERROR); nodeHash = 31*nodeHash + errorHash; *pHashcode = nodeHash; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_Hashcode * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) */ static PKIX_Error * pkix_VerifyNode_Hashcode( PKIX_PL_Object *object, PKIX_UInt32 *pHashcode, void *plContext) { PKIX_VerifyNode *node = NULL; PKIX_UInt32 childrenHash = 0; PKIX_UInt32 nodeHash = 0; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Hashcode"); PKIX_NULLCHECK_TWO(object, pHashcode); PKIX_CHECK(pkix_CheckType (object, PKIX_VERIFYNODE_TYPE, plContext), PKIX_OBJECTNOTVERIFYNODE); node = (PKIX_VerifyNode *)object; PKIX_CHECK(pkix_SingleVerifyNode_Hashcode (node, &nodeHash, plContext), PKIX_SINGLEVERIFYNODEHASHCODEFAILED); PKIX_HASHCODE (node->children, &childrenHash, plContext, PKIX_OBJECTHASHCODEFAILED); nodeHash = 31*nodeHash + childrenHash; *pHashcode = nodeHash; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_SingleVerifyNode_Equals * DESCRIPTION: * * Compares for equality the components of the VerifyNode pointed to by * "firstPN", other than its parents and children, with those of the * VerifyNode 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 VerifyNodes to be compared; must be non-NULL * "secondPN" * Address of second of the VerifyNodes 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 VerifyNode 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_SingleVerifyNode_Equals( PKIX_VerifyNode *firstVN, PKIX_VerifyNode *secondVN, PKIX_Boolean *pResult, void *plContext) { PKIX_Boolean compResult = PKIX_FALSE; PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_Equals"); PKIX_NULLCHECK_THREE(firstVN, secondVN, pResult); /* If both references are identical, they must be equal */ if (firstVN == secondVN) { compResult = PKIX_TRUE; goto cleanup; } /* * It seems we have to do the comparisons. Do * the easiest ones first. */ if ((firstVN->depth) != (secondVN->depth)) { goto cleanup; } /* These fields must be non-NULL */ PKIX_NULLCHECK_TWO(firstVN->verifyCert, secondVN->verifyCert); PKIX_EQUALS (firstVN->verifyCert, secondVN->verifyCert, &compResult, plContext, PKIX_OBJECTEQUALSFAILED); if (compResult == PKIX_FALSE) { goto cleanup; } PKIX_EQUALS (firstVN->error, secondVN->error, &compResult, plContext, PKIX_OBJECTEQUALSFAILED); cleanup: *pResult = compResult; PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_Equals * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_VerifyNode_Equals( PKIX_PL_Object *firstObject, PKIX_PL_Object *secondObject, PKIX_Boolean *pResult, void *plContext) { PKIX_VerifyNode *firstVN = NULL; PKIX_VerifyNode *secondVN = NULL; PKIX_UInt32 secondType; PKIX_Boolean compResult = PKIX_FALSE; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Equals"); PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); /* test that firstObject is a VerifyNode */ PKIX_CHECK(pkix_CheckType (firstObject, PKIX_VERIFYNODE_TYPE, plContext), PKIX_FIRSTOBJECTNOTVERIFYNODE); /* * Since we know firstObject is a VerifyNode, * if both references are identical, they must be equal */ if (firstObject == secondObject){ compResult = PKIX_TRUE; goto cleanup; } /* * If secondObject isn't a VerifyNode, we * don't throw an error. We simply return FALSE. */ PKIX_CHECK(PKIX_PL_Object_GetType (secondObject, &secondType, plContext), PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); if (secondType != PKIX_VERIFYNODE_TYPE) { goto cleanup; } /* * Oh, well, we have to do the comparisons. Do * the easiest ones first. */ firstVN = (PKIX_VerifyNode *)firstObject; secondVN = (PKIX_VerifyNode *)secondObject; PKIX_CHECK(pkix_SingleVerifyNode_Equals (firstVN, secondVN, &compResult, plContext), PKIX_SINGLEVERIFYNODEEQUALSFAILED); if (compResult == PKIX_FALSE) { goto cleanup; } PKIX_EQUALS (firstVN->children, secondVN->children, &compResult, plContext, PKIX_OBJECTEQUALSFAILEDONCHILDREN); cleanup: *pResult = compResult; PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_DuplicateHelper * DESCRIPTION: * * Duplicates the VerifyNode 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 VerifyNode 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 VerifyNode to be copied; must be non-NULL * "parent" * Address of VerifyNode 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 VerifyNode 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_VerifyNode_DuplicateHelper( PKIX_VerifyNode *original, PKIX_VerifyNode *parent, PKIX_VerifyNode **pNewNode, void *plContext) { PKIX_UInt32 numChildren = 0; PKIX_UInt32 childIndex = 0; PKIX_List *children = NULL; /* List of PKIX_VerifyNode */ PKIX_VerifyNode *copy = NULL; PKIX_VerifyNode *child = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_DuplicateHelper"); PKIX_NULLCHECK_TWO (original, original->verifyCert); /* * 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_VerifyNode_Create (original->verifyCert, original->depth, original->error, ©, plContext), PKIX_VERIFYNODECREATEFAILED); /* 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_VerifyNode_DuplicateHelper (child, copy, NULL, plContext), PKIX_VERIFYNODEDUPLICATEHELPERFAILED); 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(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_Duplicate * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h) */ static PKIX_Error * pkix_VerifyNode_Duplicate( PKIX_PL_Object *object, PKIX_PL_Object **pNewObject, void *plContext) { PKIX_VerifyNode *original = NULL; PKIX_VerifyNode *copy = NULL; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Duplicate"); PKIX_NULLCHECK_TWO(object, pNewObject); PKIX_CHECK(pkix_CheckType (object, PKIX_VERIFYNODE_TYPE, plContext), PKIX_OBJECTNOTVERIFYNODE); original = (PKIX_VerifyNode *)object; PKIX_CHECK(pkix_VerifyNode_DuplicateHelper (original, NULL, ©, plContext), PKIX_VERIFYNODEDUPLICATEHELPERFAILED); *pNewObject = (PKIX_PL_Object *)copy; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: pkix_VerifyNode_RegisterSelf * DESCRIPTION: * * Registers PKIX_VERIFYNODE_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_VerifyNode_RegisterSelf(void *plContext) { extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; pkix_ClassTable_Entry entry; PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_RegisterSelf"); entry.description = "VerifyNode"; entry.objCounter = 0; entry.typeObjectSize = sizeof(PKIX_VerifyNode); entry.destructor = pkix_VerifyNode_Destroy; entry.equalsFunction = pkix_VerifyNode_Equals; entry.hashcodeFunction = pkix_VerifyNode_Hashcode; entry.toStringFunction = pkix_VerifyNode_ToString; entry.comparator = NULL; entry.duplicateFunction = pkix_VerifyNode_Duplicate; systemClasses[PKIX_VERIFYNODE_TYPE] = entry; PKIX_RETURN(VERIFYNODE); } /* --Public-VerifyNode-Functions----------------------------------- */ /* * FUNCTION: PKIX_VerifyNode_SetError * DESCRIPTION: * * This function sets the Error field of the VerifyNode pointed to by "node" * to contain the Error pointed to by "error". * * PARAMETERS: * "node" * The address of the VerifyNode to be modified. Must be non-NULL. * "error" * The address of the Error to be stored. * "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 Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_VerifyNode_SetError( PKIX_VerifyNode *node, PKIX_Error *error, void *plContext) { PKIX_ENTER(VERIFYNODE, "PKIX_VerifyNode_SetError"); PKIX_NULLCHECK_TWO(node, error); PKIX_DECREF(node->error); /* should have been NULL */ PKIX_INCREF(error); node->error = error; cleanup: PKIX_RETURN(VERIFYNODE); } /* * FUNCTION: PKIX_VerifyNode_FindError * DESCRIPTION: * * Finds meaningful error in the log. For now, just returns the first * error it finds in. In the future the function should be changed to * return a top priority error. * * PARAMETERS: * "node" * The address of the VerifyNode to be modified. Must be non-NULL. * "error" * The address of a pointer the error will be returned to. * "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 Fatal Error if the function fails in an unrecoverable way. */ PKIX_Error * pkix_VerifyNode_FindError( PKIX_VerifyNode *node, PKIX_Error **error, void *plContext) { PKIX_VerifyNode *childNode = NULL; PKIX_ENTER(VERIFYNODE, "PKIX_VerifyNode_FindError"); /* Make sure the return address is initialized with NULL */ PKIX_DECREF(*error); if (!node) goto cleanup; /* First, try to get error from lowest level. */ if (node->children) { PKIX_UInt32 length = 0; PKIX_UInt32 index = 0; PKIX_CHECK( PKIX_List_GetLength(node->children, &length, plContext), PKIX_LISTGETLENGTHFAILED); for (index = 0;index < length;index++) { PKIX_CHECK( PKIX_List_GetItem(node->children, index, (PKIX_PL_Object**)&childNode, plContext), PKIX_LISTGETITEMFAILED); if (!childNode) continue; PKIX_CHECK( pkix_VerifyNode_FindError(childNode, error, plContext), PKIX_VERIFYNODEFINDERRORFAILED); PKIX_DECREF(childNode); if (*error) { goto cleanup; } } } if (node->error && node->error->plErr) { PKIX_INCREF(node->error); *error = node->error; } cleanup: PKIX_DECREF(childNode); PKIX_RETURN(VERIFYNODE); }