andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: /* andre@0: * pkix_verifynode.c andre@0: * andre@0: * Verify Node Object Type Definition andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_verifynode.h" andre@0: andre@0: /* --Private-VerifyNode-Functions---------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_Create andre@0: * DESCRIPTION: andre@0: * andre@0: * This function creates a VerifyNode using the Cert pointed to by "cert", andre@0: * the depth given by "depth", and the Error pointed to by "error", storing andre@0: * the result at "pObject". andre@0: * andre@0: * PARAMETERS andre@0: * "cert" andre@0: * Address of Cert for the node. Must be non-NULL andre@0: * "depth" andre@0: * UInt32 value of the depth for this node. andre@0: * "error" andre@0: * Address of Error for the node. andre@0: * "pObject" andre@0: * Address where the VerifyNode pointer will be stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_Create( andre@0: PKIX_PL_Cert *cert, andre@0: PKIX_UInt32 depth, andre@0: PKIX_Error *error, andre@0: PKIX_VerifyNode **pObject, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *node = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Create"); andre@0: PKIX_NULLCHECK_TWO(cert, pObject); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_VERIFYNODE_TYPE, andre@0: sizeof (PKIX_VerifyNode), andre@0: (PKIX_PL_Object **)&node, andre@0: plContext), andre@0: PKIX_COULDNOTCREATEVERIFYNODEOBJECT); andre@0: andre@0: PKIX_INCREF(cert); andre@0: node->verifyCert = cert; andre@0: andre@0: PKIX_INCREF(error); andre@0: node->error = error; andre@0: andre@0: node->depth = depth; andre@0: andre@0: node->children = NULL; andre@0: andre@0: *pObject = node; andre@0: node = NULL; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(node); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_AddToChain andre@0: * DESCRIPTION: andre@0: * andre@0: * Adds the VerifyNode pointed to by "child", at the appropriate depth, to the andre@0: * List of children of the VerifyNode pointed to by "parentNode". The chain of andre@0: * VerifyNodes is traversed until a VerifyNode is found at a depth one less andre@0: * than that specified in "child". An Error is returned if there is no parent andre@0: * at a suitable depth. andre@0: * andre@0: * If "parentNode" has a NULL pointer for the List of children, a new List is andre@0: * created containing "child". Otherwise "child" is appended to the existing andre@0: * List. andre@0: * andre@0: * Depth, in this context, means distance from the root node, which andre@0: * is at depth zero. andre@0: * andre@0: * PARAMETERS: andre@0: * "parentNode" andre@0: * Address of VerifyNode whose List of child VerifyNodes is to be andre@0: * created or appended to. Must be non-NULL. andre@0: * "child" andre@0: * Address of VerifyNode to be added to parentNode's List. Must be andre@0: * non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_AddToChain( andre@0: PKIX_VerifyNode *parentNode, andre@0: PKIX_VerifyNode *child, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *successor = NULL; andre@0: PKIX_List *listOfChildren = NULL; andre@0: PKIX_UInt32 numChildren = 0; andre@0: PKIX_UInt32 parentDepth = 0; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_AddToChain"); andre@0: PKIX_NULLCHECK_TWO(parentNode, child); andre@0: andre@0: parentDepth = parentNode->depth; andre@0: listOfChildren = parentNode->children; andre@0: if (listOfChildren == NULL) { andre@0: andre@0: if (parentDepth != (child->depth - 1)) { andre@0: PKIX_ERROR(PKIX_NODESMISSINGFROMCHAIN); andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext), andre@0: PKIX_LISTCREATEFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_List_AppendItem andre@0: (listOfChildren, (PKIX_PL_Object *)child, plContext), andre@0: PKIX_COULDNOTAPPENDCHILDTOPARENTSVERIFYNODELIST); andre@0: andre@0: parentNode->children = listOfChildren; andre@0: } else { andre@0: /* get number of children */ andre@0: PKIX_CHECK(PKIX_List_GetLength andre@0: (listOfChildren, &numChildren, plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: andre@0: if (numChildren != 1) { andre@0: PKIX_ERROR(PKIX_AMBIGUOUSPARENTAGEOFVERIFYNODE); andre@0: } andre@0: andre@0: /* successor = listOfChildren[0] */ andre@0: PKIX_CHECK(PKIX_List_GetItem andre@0: (listOfChildren, andre@0: 0, andre@0: (PKIX_PL_Object **)&successor, andre@0: plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: andre@0: PKIX_CHECK(pkix_VerifyNode_AddToChain andre@0: (successor, child, plContext), andre@0: PKIX_VERIFYNODEADDTOCHAINFAILED); andre@0: } andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_InvalidateCache andre@0: ((PKIX_PL_Object *)parentNode, plContext), andre@0: PKIX_OBJECTINVALIDATECACHEFAILED); andre@0: andre@0: cleanup: andre@0: PKIX_DECREF(successor); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_SetDepth andre@0: * DESCRIPTION: andre@0: * andre@0: * The function sets the depth field of each VerifyNode in the List "children" andre@0: * to the value given by "depth", and recursively sets the depth of any andre@0: * successive generations to the successive values. andre@0: * andre@0: * PARAMETERS: andre@0: * "children" andre@0: * The List of VerifyNodes. Must be non-NULL. andre@0: * "depth" andre@0: * The value of the depth field to be set in members of the List. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_SetDepth(PKIX_List *children, andre@0: PKIX_UInt32 depth, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 numChildren = 0; andre@0: PKIX_UInt32 chIx = 0; andre@0: PKIX_VerifyNode *child = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_SetDepth"); andre@0: PKIX_NULLCHECK_ONE(children); andre@0: andre@0: PKIX_CHECK(PKIX_List_GetLength(children, &numChildren, plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: andre@0: for (chIx = 0; chIx < numChildren; chIx++) { andre@0: PKIX_CHECK(PKIX_List_GetItem andre@0: (children, chIx, (PKIX_PL_Object **)&child, plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: andre@0: child->depth = depth; andre@0: andre@0: if (child->children != NULL) { andre@0: PKIX_CHECK(pkix_VerifyNode_SetDepth andre@0: (child->children, depth + 1, plContext), andre@0: PKIX_VERIFYNODESETDEPTHFAILED); andre@0: } andre@0: andre@0: PKIX_DECREF(child); andre@0: } andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(child); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_AddToTree andre@0: * DESCRIPTION: andre@0: * andre@0: * Adds the VerifyNode pointed to by "child" to the List of children of the andre@0: * VerifyNode pointed to by "parentNode". If "parentNode" has a NULL pointer andre@0: * for the List of children, a new List is created containing "child". andre@0: * Otherwise "child" is appended to the existing List. The depth field of andre@0: * "child" is set to one more than the corresponding value in "parent", and andre@0: * if the "child" itself has child nodes, their depth fields are updated andre@0: * accordingly. andre@0: * andre@0: * Depth, in this context, means distance from the root node, which andre@0: * is at depth zero. andre@0: * andre@0: * PARAMETERS: andre@0: * "parentNode" andre@0: * Address of VerifyNode whose List of child VerifyNodes is to be andre@0: * created or appended to. Must be non-NULL. andre@0: * "child" andre@0: * Address of VerifyNode to be added to parentNode's List. Must be andre@0: * non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_AddToTree( andre@0: PKIX_VerifyNode *parentNode, andre@0: PKIX_VerifyNode *child, andre@0: void *plContext) andre@0: { andre@0: PKIX_List *listOfChildren = NULL; andre@0: PKIX_UInt32 parentDepth = 0; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_AddToTree"); andre@0: PKIX_NULLCHECK_TWO(parentNode, child); andre@0: andre@0: parentDepth = parentNode->depth; andre@0: listOfChildren = parentNode->children; andre@0: if (listOfChildren == NULL) { andre@0: andre@0: PKIX_CHECK(PKIX_List_Create(&listOfChildren, plContext), andre@0: PKIX_LISTCREATEFAILED); andre@0: andre@0: parentNode->children = listOfChildren; andre@0: } andre@0: andre@0: child->depth = parentDepth + 1; andre@0: andre@0: PKIX_CHECK(PKIX_List_AppendItem andre@0: (parentNode->children, (PKIX_PL_Object *)child, plContext), andre@0: PKIX_COULDNOTAPPENDCHILDTOPARENTSVERIFYNODELIST); andre@0: andre@0: if (child->children != NULL) { andre@0: PKIX_CHECK(pkix_VerifyNode_SetDepth andre@0: (child->children, child->depth + 1, plContext), andre@0: PKIX_VERIFYNODESETDEPTHFAILED); andre@0: } andre@0: andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_SingleVerifyNode_ToString andre@0: * DESCRIPTION: andre@0: * andre@0: * Creates a String representation of the attributes of the VerifyNode pointed andre@0: * to by "node", other than its children, and stores the result at "pString". andre@0: * andre@0: * PARAMETERS: andre@0: * "node" andre@0: * Address of VerifyNode to be described by the string. Must be non-NULL. andre@0: * "pString" andre@0: * Address where object pointer will be stored. Must be non-NULL. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Conditionally Thread Safe andre@0: * (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if function succeeds andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in a fatal way andre@0: */ andre@0: PKIX_Error * andre@0: pkix_SingleVerifyNode_ToString( andre@0: PKIX_VerifyNode *node, andre@0: PKIX_PL_String **pString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *fmtString = NULL; andre@0: PKIX_PL_String *errorString = NULL; andre@0: PKIX_PL_String *outString = NULL; andre@0: andre@0: PKIX_PL_X500Name *issuerName = NULL; andre@0: PKIX_PL_X500Name *subjectName = NULL; andre@0: PKIX_PL_String *issuerString = NULL; andre@0: PKIX_PL_String *subjectString = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_ToString"); andre@0: PKIX_NULLCHECK_THREE(node, pString, node->verifyCert); andre@0: andre@0: PKIX_TOSTRING(node->error, &errorString, plContext, andre@0: PKIX_ERRORTOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Cert_GetIssuer andre@0: (node->verifyCert, &issuerName, plContext), andre@0: PKIX_CERTGETISSUERFAILED); andre@0: andre@0: PKIX_TOSTRING(issuerName, &issuerString, plContext, andre@0: PKIX_X500NAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Cert_GetSubject andre@0: (node->verifyCert, &subjectName, plContext), andre@0: PKIX_CERTGETSUBJECTFAILED); andre@0: andre@0: PKIX_TOSTRING(subjectName, &subjectString, plContext, andre@0: PKIX_X500NAMETOSTRINGFAILED); andre@0: andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: "CERT[Issuer:%s, Subject:%s], depth=%d, error=%s", andre@0: 0, andre@0: &fmtString, andre@0: plContext), andre@0: PKIX_CANTCREATESTRING); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&outString, andre@0: plContext, andre@0: fmtString, andre@0: issuerString, andre@0: subjectString, andre@0: node->depth, andre@0: errorString), andre@0: PKIX_SPRINTFFAILED); andre@0: andre@0: *pString = outString; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_DECREF(fmtString); andre@0: PKIX_DECREF(errorString); andre@0: PKIX_DECREF(issuerName); andre@0: PKIX_DECREF(subjectName); andre@0: PKIX_DECREF(issuerString); andre@0: PKIX_DECREF(subjectString); andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_ToString_Helper andre@0: * DESCRIPTION: andre@0: * andre@0: * Produces a String representation of a VerifyNode tree below the VerifyNode andre@0: * pointed to by "rootNode", with each line of output prefixed by the String andre@0: * pointed to by "indent", and stores the result at "pTreeString". It is andre@0: * called recursively, with ever-increasing indentation, for successively andre@0: * lower nodes on the tree. andre@0: * andre@0: * PARAMETERS: andre@0: * "rootNode" andre@0: * Address of VerifyNode subtree. Must be non-NULL. andre@0: * "indent" andre@0: * Address of String to be prefixed to each line of output. May be NULL andre@0: * if no indentation is desired andre@0: * "pTreeString" andre@0: * Address where the resulting String will be stored; must be non-NULL andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Conditionally Thread Safe andre@0: * (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_ToString_Helper( andre@0: PKIX_VerifyNode *rootNode, andre@0: PKIX_PL_String *indent, andre@0: PKIX_PL_String **pTreeString, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_String *nextIndentFormat = NULL; andre@0: PKIX_PL_String *thisNodeFormat = NULL; andre@0: PKIX_PL_String *childrenFormat = NULL; andre@0: PKIX_PL_String *nextIndentString = NULL; andre@0: PKIX_PL_String *resultString = NULL; andre@0: PKIX_PL_String *thisItemString = NULL; andre@0: PKIX_PL_String *childString = NULL; andre@0: PKIX_VerifyNode *childNode = NULL; andre@0: PKIX_UInt32 numberOfChildren = 0; andre@0: PKIX_UInt32 childIndex = 0; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_ToString_Helper"); andre@0: andre@0: PKIX_NULLCHECK_TWO(rootNode, pTreeString); andre@0: andre@0: /* Create a string for this node */ andre@0: PKIX_CHECK(pkix_SingleVerifyNode_ToString andre@0: (rootNode, &thisItemString, plContext), andre@0: PKIX_ERRORINSINGLEVERIFYNODETOSTRING); andre@0: andre@0: if (indent) { andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: "%s%s", andre@0: 0, andre@0: &thisNodeFormat, andre@0: plContext), andre@0: PKIX_ERRORCREATINGFORMATSTRING); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&resultString, andre@0: plContext, andre@0: thisNodeFormat, andre@0: indent, andre@0: thisItemString), andre@0: PKIX_ERRORINSPRINTF); andre@0: } else { andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: "%s", andre@0: 0, andre@0: &thisNodeFormat, andre@0: plContext), andre@0: PKIX_ERRORCREATINGFORMATSTRING); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&resultString, andre@0: plContext, andre@0: thisNodeFormat, andre@0: thisItemString), andre@0: PKIX_ERRORINSPRINTF); andre@0: } andre@0: andre@0: PKIX_DECREF(thisItemString); andre@0: thisItemString = resultString; andre@0: andre@0: /* if no children, we are done */ andre@0: if (rootNode->children) { andre@0: PKIX_CHECK(PKIX_List_GetLength andre@0: (rootNode->children, &numberOfChildren, plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: } andre@0: andre@0: if (numberOfChildren != 0) { andre@0: /* andre@0: * We create a string for each child in turn, andre@0: * concatenating them to thisItemString. andre@0: */ andre@0: andre@0: /* Prepare an indent string for each child */ andre@0: if (indent) { andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: "%s. ", andre@0: 0, andre@0: &nextIndentFormat, andre@0: plContext), andre@0: PKIX_ERRORCREATINGFORMATSTRING); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&nextIndentString, andre@0: plContext, andre@0: nextIndentFormat, andre@0: indent), andre@0: PKIX_ERRORINSPRINTF); andre@0: } else { andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: ". ", andre@0: 0, andre@0: &nextIndentString, andre@0: plContext), andre@0: PKIX_ERRORCREATINGINDENTSTRING); andre@0: } andre@0: andre@0: /* Prepare the format for concatenation. */ andre@0: PKIX_CHECK(PKIX_PL_String_Create andre@0: (PKIX_ESCASCII, andre@0: "%s\n%s", andre@0: 0, andre@0: &childrenFormat, andre@0: plContext), andre@0: PKIX_ERRORCREATINGFORMATSTRING); andre@0: andre@0: for (childIndex = 0; andre@0: childIndex < numberOfChildren; andre@0: childIndex++) { andre@0: PKIX_CHECK(PKIX_List_GetItem andre@0: (rootNode->children, andre@0: childIndex, andre@0: (PKIX_PL_Object **)&childNode, andre@0: plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: andre@0: PKIX_CHECK(pkix_VerifyNode_ToString_Helper andre@0: (childNode, andre@0: nextIndentString, andre@0: &childString, andre@0: plContext), andre@0: PKIX_ERRORCREATINGCHILDSTRING); andre@0: andre@0: andre@0: PKIX_CHECK(PKIX_PL_Sprintf andre@0: (&resultString, andre@0: plContext, andre@0: childrenFormat, andre@0: thisItemString, andre@0: childString), andre@0: PKIX_ERRORINSPRINTF); andre@0: andre@0: PKIX_DECREF(childNode); andre@0: PKIX_DECREF(childString); andre@0: PKIX_DECREF(thisItemString); andre@0: andre@0: thisItemString = resultString; andre@0: } andre@0: } andre@0: andre@0: *pTreeString = thisItemString; andre@0: andre@0: cleanup: andre@0: if (PKIX_ERROR_RECEIVED) { andre@0: PKIX_DECREF(thisItemString); andre@0: } andre@0: andre@0: PKIX_DECREF(nextIndentFormat); andre@0: PKIX_DECREF(thisNodeFormat); andre@0: PKIX_DECREF(childrenFormat); andre@0: PKIX_DECREF(nextIndentString); andre@0: PKIX_DECREF(childString); andre@0: PKIX_DECREF(childNode); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_ToString andre@0: * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_ToString( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_String **pTreeString, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *rootNode = NULL; andre@0: PKIX_PL_String *resultString = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_ToString"); andre@0: andre@0: PKIX_NULLCHECK_TWO(object, pTreeString); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_VERIFYNODE_TYPE, plContext), andre@0: PKIX_OBJECTNOTVERIFYNODE); andre@0: andre@0: rootNode = (PKIX_VerifyNode *)object; andre@0: andre@0: PKIX_CHECK(pkix_VerifyNode_ToString_Helper andre@0: (rootNode, NULL, &resultString, plContext), andre@0: PKIX_ERRORCREATINGSUBTREESTRING); andre@0: andre@0: *pTreeString = resultString; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_Destroy andre@0: * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *node = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Destroy"); andre@0: andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_VERIFYNODE_TYPE, plContext), andre@0: PKIX_OBJECTNOTVERIFYNODE); andre@0: andre@0: node = (PKIX_VerifyNode*)object; andre@0: andre@0: PKIX_DECREF(node->verifyCert); andre@0: PKIX_DECREF(node->children); andre@0: PKIX_DECREF(node->error); andre@0: andre@0: node->depth = 0; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_SingleVerifyNode_Hashcode andre@0: * DESCRIPTION: andre@0: * andre@0: * Computes the hashcode of the attributes of the VerifyNode pointed to by andre@0: * "node", other than its parents and children, and stores the result at andre@0: * "pHashcode". andre@0: * andre@0: * PARAMETERS: andre@0: * "node" andre@0: * Address of VerifyNode to be hashcoded; must be non-NULL andre@0: * "pHashcode" andre@0: * Address where UInt32 result will be stored; must be non-NULL andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Conditionally Thread Safe andre@0: * (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if function succeeds andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in a fatal way andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_SingleVerifyNode_Hashcode( andre@0: PKIX_VerifyNode *node, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 errorHash = 0; andre@0: PKIX_UInt32 nodeHash = 0; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(node, pHashcode); andre@0: andre@0: PKIX_HASHCODE andre@0: (node->verifyCert, andre@0: &nodeHash, andre@0: plContext, andre@0: PKIX_FAILUREHASHINGCERT); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Hashcode andre@0: ((PKIX_PL_Object *)node->error, andre@0: &errorHash, andre@0: plContext), andre@0: PKIX_FAILUREHASHINGERROR); andre@0: andre@0: nodeHash = 31*nodeHash + errorHash; andre@0: *pHashcode = nodeHash; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_Hashcode andre@0: * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_Hashcode( andre@0: PKIX_PL_Object *object, andre@0: PKIX_UInt32 *pHashcode, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *node = NULL; andre@0: PKIX_UInt32 childrenHash = 0; andre@0: PKIX_UInt32 nodeHash = 0; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Hashcode"); andre@0: PKIX_NULLCHECK_TWO(object, pHashcode); andre@0: andre@0: PKIX_CHECK(pkix_CheckType andre@0: (object, PKIX_VERIFYNODE_TYPE, plContext), andre@0: PKIX_OBJECTNOTVERIFYNODE); andre@0: andre@0: node = (PKIX_VerifyNode *)object; andre@0: andre@0: PKIX_CHECK(pkix_SingleVerifyNode_Hashcode andre@0: (node, &nodeHash, plContext), andre@0: PKIX_SINGLEVERIFYNODEHASHCODEFAILED); andre@0: andre@0: PKIX_HASHCODE andre@0: (node->children, andre@0: &childrenHash, andre@0: plContext, andre@0: PKIX_OBJECTHASHCODEFAILED); andre@0: andre@0: nodeHash = 31*nodeHash + childrenHash; andre@0: andre@0: *pHashcode = nodeHash; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_SingleVerifyNode_Equals andre@0: * DESCRIPTION: andre@0: * andre@0: * Compares for equality the components of the VerifyNode pointed to by andre@0: * "firstPN", other than its parents and children, with those of the andre@0: * VerifyNode pointed to by "secondPN" and stores the result at "pResult" andre@0: * (PKIX_TRUE if equal; PKIX_FALSE if not). andre@0: * andre@0: * PARAMETERS: andre@0: * "firstPN" andre@0: * Address of first of the VerifyNodes to be compared; must be non-NULL andre@0: * "secondPN" andre@0: * Address of second of the VerifyNodes to be compared; must be non-NULL andre@0: * "pResult" andre@0: * Address where Boolean will be stored; must be non-NULL andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Conditionally Thread Safe andre@0: * (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if function succeeds andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in a fatal way andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_SingleVerifyNode_Equals( andre@0: PKIX_VerifyNode *firstVN, andre@0: PKIX_VerifyNode *secondVN, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_Boolean compResult = PKIX_FALSE; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstVN, secondVN, pResult); andre@0: andre@0: /* If both references are identical, they must be equal */ andre@0: if (firstVN == secondVN) { andre@0: compResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * It seems we have to do the comparisons. Do andre@0: * the easiest ones first. andre@0: */ andre@0: if ((firstVN->depth) != (secondVN->depth)) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* These fields must be non-NULL */ andre@0: PKIX_NULLCHECK_TWO(firstVN->verifyCert, secondVN->verifyCert); andre@0: andre@0: PKIX_EQUALS andre@0: (firstVN->verifyCert, andre@0: secondVN->verifyCert, andre@0: &compResult, andre@0: plContext, andre@0: PKIX_OBJECTEQUALSFAILED); andre@0: andre@0: if (compResult == PKIX_FALSE) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: PKIX_EQUALS andre@0: (firstVN->error, andre@0: secondVN->error, andre@0: &compResult, andre@0: plContext, andre@0: PKIX_OBJECTEQUALSFAILED); andre@0: andre@0: cleanup: andre@0: andre@0: *pResult = compResult; andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_Equals andre@0: * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_Equals( andre@0: PKIX_PL_Object *firstObject, andre@0: PKIX_PL_Object *secondObject, andre@0: PKIX_Boolean *pResult, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *firstVN = NULL; andre@0: PKIX_VerifyNode *secondVN = NULL; andre@0: PKIX_UInt32 secondType; andre@0: PKIX_Boolean compResult = PKIX_FALSE; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Equals"); andre@0: PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult); andre@0: andre@0: /* test that firstObject is a VerifyNode */ andre@0: PKIX_CHECK(pkix_CheckType andre@0: (firstObject, PKIX_VERIFYNODE_TYPE, plContext), andre@0: PKIX_FIRSTOBJECTNOTVERIFYNODE); andre@0: andre@0: /* andre@0: * Since we know firstObject is a VerifyNode, andre@0: * if both references are identical, they must be equal andre@0: */ andre@0: if (firstObject == secondObject){ andre@0: compResult = PKIX_TRUE; andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * If secondObject isn't a VerifyNode, we andre@0: * don't throw an error. We simply return FALSE. andre@0: */ andre@0: PKIX_CHECK(PKIX_PL_Object_GetType andre@0: (secondObject, &secondType, plContext), andre@0: PKIX_COULDNOTGETTYPEOFSECONDARGUMENT); andre@0: andre@0: if (secondType != PKIX_VERIFYNODE_TYPE) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: /* andre@0: * Oh, well, we have to do the comparisons. Do andre@0: * the easiest ones first. andre@0: */ andre@0: firstVN = (PKIX_VerifyNode *)firstObject; andre@0: secondVN = (PKIX_VerifyNode *)secondObject; andre@0: andre@0: PKIX_CHECK(pkix_SingleVerifyNode_Equals andre@0: (firstVN, secondVN, &compResult, plContext), andre@0: PKIX_SINGLEVERIFYNODEEQUALSFAILED); andre@0: andre@0: if (compResult == PKIX_FALSE) { andre@0: goto cleanup; andre@0: } andre@0: andre@0: PKIX_EQUALS andre@0: (firstVN->children, andre@0: secondVN->children, andre@0: &compResult, andre@0: plContext, andre@0: PKIX_OBJECTEQUALSFAILEDONCHILDREN); andre@0: andre@0: cleanup: andre@0: andre@0: *pResult = compResult; andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_DuplicateHelper andre@0: * DESCRIPTION: andre@0: * andre@0: * Duplicates the VerifyNode whose address is pointed to by "original", andre@0: * and stores the result at "pNewNode", if a non-NULL pointer is provided andre@0: * for "pNewNode". In addition, the created VerifyNode is added as a child andre@0: * to "parent", if a non-NULL pointer is provided for "parent". Then this andre@0: * function is called recursively to duplicate each of the children of andre@0: * "original". At the top level this function is called with a null andre@0: * "parent" and a non-NULL "pNewNode". Below the top level "parent" will andre@0: * be non-NULL and "pNewNode" will be NULL. andre@0: * andre@0: * PARAMETERS: andre@0: * "original" andre@0: * Address of VerifyNode to be copied; must be non-NULL andre@0: * "parent" andre@0: * Address of VerifyNode to which the created node is to be added as a andre@0: * child; NULL for the top-level call and non-NULL below the top level andre@0: * "pNewNode" andre@0: * Address to store the node created; should be NULL if "parent" is andre@0: * non-NULL and vice versa andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Conditionally Thread Safe andre@0: * (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if function succeeds andre@0: * Returns a VerifyNode Error if the function fails in a non-fatal way. andre@0: * Returns a Fatal Error if the function fails in a fatal way andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_DuplicateHelper( andre@0: PKIX_VerifyNode *original, andre@0: PKIX_VerifyNode *parent, andre@0: PKIX_VerifyNode **pNewNode, andre@0: void *plContext) andre@0: { andre@0: PKIX_UInt32 numChildren = 0; andre@0: PKIX_UInt32 childIndex = 0; andre@0: PKIX_List *children = NULL; /* List of PKIX_VerifyNode */ andre@0: PKIX_VerifyNode *copy = NULL; andre@0: PKIX_VerifyNode *child = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_DuplicateHelper"); andre@0: andre@0: PKIX_NULLCHECK_TWO andre@0: (original, original->verifyCert); andre@0: andre@0: /* andre@0: * These components are immutable, so copying the pointers andre@0: * is sufficient. The create function increments the reference andre@0: * counts as it stores the pointers into the new object. andre@0: */ andre@0: PKIX_CHECK(pkix_VerifyNode_Create andre@0: (original->verifyCert, andre@0: original->depth, andre@0: original->error, andre@0: ©, andre@0: plContext), andre@0: PKIX_VERIFYNODECREATEFAILED); andre@0: andre@0: /* Are there any children to duplicate? */ andre@0: children = original->children; andre@0: andre@0: if (children) { andre@0: PKIX_CHECK(PKIX_List_GetLength(children, &numChildren, plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: } andre@0: andre@0: for (childIndex = 0; childIndex < numChildren; childIndex++) { andre@0: PKIX_CHECK(PKIX_List_GetItem andre@0: (children, andre@0: childIndex, andre@0: (PKIX_PL_Object **)&child, andre@0: plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: andre@0: PKIX_CHECK(pkix_VerifyNode_DuplicateHelper andre@0: (child, copy, NULL, plContext), andre@0: PKIX_VERIFYNODEDUPLICATEHELPERFAILED); andre@0: andre@0: PKIX_DECREF(child); andre@0: } andre@0: andre@0: if (pNewNode) { andre@0: *pNewNode = copy; andre@0: copy = NULL; /* no DecRef if we give our handle away */ andre@0: } andre@0: andre@0: cleanup: andre@0: PKIX_DECREF(copy); andre@0: PKIX_DECREF(child); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_Duplicate andre@0: * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h) andre@0: */ andre@0: static PKIX_Error * andre@0: pkix_VerifyNode_Duplicate( andre@0: PKIX_PL_Object *object, andre@0: PKIX_PL_Object **pNewObject, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *original = NULL; andre@0: PKIX_VerifyNode *copy = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Duplicate"); andre@0: andre@0: PKIX_NULLCHECK_TWO(object, pNewObject); andre@0: andre@0: PKIX_CHECK(pkix_CheckType andre@0: (object, PKIX_VERIFYNODE_TYPE, plContext), andre@0: PKIX_OBJECTNOTVERIFYNODE); andre@0: andre@0: original = (PKIX_VerifyNode *)object; andre@0: andre@0: PKIX_CHECK(pkix_VerifyNode_DuplicateHelper andre@0: (original, NULL, ©, plContext), andre@0: PKIX_VERIFYNODEDUPLICATEHELPERFAILED); andre@0: andre@0: *pNewObject = (PKIX_PL_Object *)copy; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_VerifyNode_RegisterSelf andre@0: * DESCRIPTION: andre@0: * andre@0: * Registers PKIX_VERIFYNODE_TYPE and its related andre@0: * functions with systemClasses[] andre@0: * andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, andre@0: * which should only be called once, it is acceptable that andre@0: * this function is not thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_RegisterSelf(void *plContext) andre@0: { andre@0: andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_RegisterSelf"); andre@0: andre@0: entry.description = "VerifyNode"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_VerifyNode); andre@0: entry.destructor = pkix_VerifyNode_Destroy; andre@0: entry.equalsFunction = pkix_VerifyNode_Equals; andre@0: entry.hashcodeFunction = pkix_VerifyNode_Hashcode; andre@0: entry.toStringFunction = pkix_VerifyNode_ToString; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = pkix_VerifyNode_Duplicate; andre@0: andre@0: systemClasses[PKIX_VERIFYNODE_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* --Public-VerifyNode-Functions----------------------------------- */ andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_VerifyNode_SetError andre@0: * DESCRIPTION: andre@0: * andre@0: * This function sets the Error field of the VerifyNode pointed to by "node" andre@0: * to contain the Error pointed to by "error". andre@0: * andre@0: * PARAMETERS: andre@0: * "node" andre@0: * The address of the VerifyNode to be modified. Must be non-NULL. andre@0: * "error" andre@0: * The address of the Error to be stored. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_SetError( andre@0: PKIX_VerifyNode *node, andre@0: PKIX_Error *error, andre@0: void *plContext) andre@0: { andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "PKIX_VerifyNode_SetError"); andre@0: andre@0: PKIX_NULLCHECK_TWO(node, error); andre@0: andre@0: PKIX_DECREF(node->error); /* should have been NULL */ andre@0: PKIX_INCREF(error); andre@0: node->error = error; andre@0: andre@0: cleanup: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: PKIX_VerifyNode_FindError andre@0: * DESCRIPTION: andre@0: * andre@0: * Finds meaningful error in the log. For now, just returns the first andre@0: * error it finds in. In the future the function should be changed to andre@0: * return a top priority error. andre@0: * andre@0: * PARAMETERS: andre@0: * "node" andre@0: * The address of the VerifyNode to be modified. Must be non-NULL. andre@0: * "error" andre@0: * The address of a pointer the error will be returned to. andre@0: * "plContext" andre@0: * Platform-specific context pointer. andre@0: * THREAD SAFETY: andre@0: * Thread Safe (see Thread Safety Definitions in Programmer's Guide) andre@0: * RETURNS: andre@0: * Returns NULL if the function succeeds. andre@0: * Returns a Fatal Error if the function fails in an unrecoverable way. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_VerifyNode_FindError( andre@0: PKIX_VerifyNode *node, andre@0: PKIX_Error **error, andre@0: void *plContext) andre@0: { andre@0: PKIX_VerifyNode *childNode = NULL; andre@0: andre@0: PKIX_ENTER(VERIFYNODE, "PKIX_VerifyNode_FindError"); andre@0: andre@0: /* Make sure the return address is initialized with NULL */ andre@0: PKIX_DECREF(*error); andre@0: andre@0: if (!node) andre@0: goto cleanup; andre@0: andre@0: /* First, try to get error from lowest level. */ andre@0: if (node->children) { andre@0: PKIX_UInt32 length = 0; andre@0: PKIX_UInt32 index = 0; andre@0: andre@0: PKIX_CHECK( andre@0: PKIX_List_GetLength(node->children, &length, andre@0: plContext), andre@0: PKIX_LISTGETLENGTHFAILED); andre@0: for (index = 0;index < length;index++) { andre@0: PKIX_CHECK( andre@0: PKIX_List_GetItem(node->children, index, andre@0: (PKIX_PL_Object**)&childNode, plContext), andre@0: PKIX_LISTGETITEMFAILED); andre@0: if (!childNode) andre@0: continue; andre@0: PKIX_CHECK( andre@0: pkix_VerifyNode_FindError(childNode, error, andre@0: plContext), andre@0: PKIX_VERIFYNODEFINDERRORFAILED); andre@0: PKIX_DECREF(childNode); andre@0: if (*error) { andre@0: goto cleanup; andre@0: } andre@0: } andre@0: } andre@0: andre@0: if (node->error && node->error->plErr) { andre@0: PKIX_INCREF(node->error); andre@0: *error = node->error; andre@0: } andre@0: andre@0: cleanup: andre@0: PKIX_DECREF(childNode); andre@0: andre@0: PKIX_RETURN(VERIFYNODE); andre@0: }