Exemple #1
0
/*
 * FUNCTION: pkix_List_RemoveItems
 * DESCRIPTION:
 *
 *  Traverses the List pointed to by "list", to find and delete an entry
 *  that is equal to the Object in the "deleteList". If no such entry
 *  is found the function does not return an error.
 *
 * PARAMETERS:
 *  "list"
 *      Object in "list" is checked for object in "deleteList" and deleted if
 *      found; may be empty; must be non-NULL
 *  "deleteList"
 *      List of objects to be searched ; may be empty; 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 Validate Error if the functions fails in a non-fatal way
 *  Returns a Fatal Error if the function fails in an unrecoverable way
 */
PKIX_Error *
pkix_List_RemoveItems(
        PKIX_List *list,
        PKIX_List *deleteList,
        void *plContext)
{
        PKIX_PL_Object *current = NULL;
        PKIX_UInt32 numEntries = 0;
        PKIX_UInt32 index = 0;

        PKIX_ENTER(LIST, "pkix_List_RemoveItems");
        PKIX_NULLCHECK_TWO(list, deleteList);

        PKIX_CHECK(PKIX_List_GetLength(deleteList, &numEntries, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (index = 0; index < numEntries; index++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (deleteList, index, &current, plContext),
                        PKIX_LISTGETITEMFAILED);

                if (current) {
                        PKIX_CHECK(pkix_List_Remove
                                (list, current, plContext),
                                PKIX_OBJECTEQUALSFAILED);

                        PKIX_DECREF(current);
                }
        }

cleanup:

        PKIX_DECREF(current);
        PKIX_RETURN(LIST);
}
Exemple #2
0
/*
 * FUNCTION: PKIX_List_ReverseList (see comments in pkix_util.h)
 */
PKIX_Error *
PKIX_List_ReverseList(
        PKIX_List *list,
        PKIX_List **pReversedList,
        void *plContext)
{
        PKIX_List *reversedList = NULL;
        PKIX_PL_Object *item = NULL;
        PKIX_PL_Object *duplicateItem = NULL;
        PKIX_UInt32 length, i;

        PKIX_ENTER(LIST, "pkix_List_ReverseList");
        PKIX_NULLCHECK_TWO(list, pReversedList);

        if (!list->isHeader){
                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
        }

        length = list->length;

        /* Create a new list object */
        PKIX_CHECK(PKIX_List_Create(&reversedList, plContext),
                    PKIX_LISTCREATEINTERNALFAILED);

        /*
         * Starting with the last item and traversing backwards (from
         * the original list), append each item to the reversed list
         */

        for (i = 1; i <= length; i++){
                PKIX_CHECK(PKIX_List_GetItem
                            (list, (length - i), &item, plContext),
                            PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_PL_Object_Duplicate
                            (item, &duplicateItem, plContext),
                            PKIX_LISTDUPLICATEFAILED);

                PKIX_CHECK(PKIX_List_AppendItem
                            (reversedList, duplicateItem, plContext),
                            PKIX_LISTAPPENDITEMFAILED);

                PKIX_DECREF(item);
                PKIX_DECREF(duplicateItem);
        }

        *pReversedList = reversedList;

cleanup:

        PKIX_DECREF(item);
        PKIX_DECREF(duplicateItem);

        if (PKIX_ERROR_RECEIVED){
                PKIX_DECREF(reversedList);
        }

        PKIX_RETURN(LIST);
}
/*
 * 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) {
        PKIX_INCREF(node->error);
        *error = node->error;
    }

cleanup:
    PKIX_DECREF(childNode);
    
    PKIX_RETURN(VERIFYNODE);
}
Exemple #4
0
/*
 * FUNCTION: pkix_List_Hashcode
 * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_List_Hashcode(
        PKIX_PL_Object *object,
        PKIX_UInt32 *pHashcode,
        void *plContext)
{
        PKIX_List *list = NULL;
        PKIX_PL_Object *element = NULL;
        PKIX_UInt32 hash = 0;
        PKIX_UInt32 tempHash = 0;
        PKIX_UInt32 length, i;

        PKIX_ENTER(LIST, "pkix_List_Hashcode");
        PKIX_NULLCHECK_TWO(object, pHashcode);

        PKIX_CHECK(pkix_CheckType(object, PKIX_LIST_TYPE, plContext),
                    PKIX_OBJECTNOTLIST);

        list = (PKIX_List *)object;

        if (!list->isHeader){
                PKIX_ERROR(PKIX_INPUTLISTMUSTBEHEADER);
        }

        length = list->length;

        for (i = 0; i < length; i++){
                PKIX_CHECK(PKIX_List_GetItem(list, i, &element, plContext),
                            PKIX_LISTGETITEMFAILED);

                if (!element){
                        tempHash = 100;
                } else {
                        PKIX_CHECK(PKIX_PL_Object_Hashcode
                                    (element, &tempHash, plContext),
                                    PKIX_LISTHASHCODEFAILED);
                }

                hash = 31 * hash + tempHash;

                PKIX_DECREF(element);
        }

        *pHashcode = hash;

cleanup:

        PKIX_DECREF(element);
        PKIX_RETURN(LIST);
}
Exemple #5
0
/*
 * FUNCTION: pkix_List_AppendList
 * DESCRIPTION:
 *
 *  Append items on "fromList" to the "toList". Item reference count on
 *  "toList" is not incremented, but items appended from "fromList" are
 *  incremented.
 *
 * PARAMETERS:
 *  "toList"
 *      Address of list to be appended to. Must be non-NULL.
 *  "fromList"
 *      Address of list to be appended from. May be NULL or empty.
 *  "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 List Error if the functions fails in a non-fatal way
 *  Returns a Fatal Error if the function fails in an unrecoverable way
 */
PKIX_Error *
pkix_List_AppendList(
        PKIX_List *toList,
        PKIX_List *fromList,
        void *plContext)
{
        PKIX_PL_Object *item = NULL;
        PKIX_UInt32 numItems = 0;
        PKIX_UInt32 i;

        PKIX_ENTER(LIST, "pkix_List_AppendList");
        PKIX_NULLCHECK_ONE(toList);

        /* if fromList is NULL or is an empty list, no action */

        if (fromList == NULL) {
                goto cleanup;
        }

        PKIX_CHECK(PKIX_List_GetLength(fromList, &numItems, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (numItems == 0) {
                goto cleanup;
        }

        for (i = 0; i < numItems; i++) {

                PKIX_CHECK(PKIX_List_GetItem
                        (fromList, i, &item, plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_List_AppendItem(toList, item, plContext),
                            PKIX_LISTAPPENDITEMFAILED);

                PKIX_DECREF(item);
        }

cleanup:

        PKIX_DECREF(item);

        PKIX_RETURN(LIST);
}
static
void test_CreateOIDList(PKIX_List *certPolicyInfos, PKIX_List **pPolicyOIDs)
{
        PKIX_UInt32 i = 0;
        PKIX_UInt32 numInfos = 0;
        PKIX_PL_CertPolicyInfo *certPolicyInfo = NULL;
        PKIX_PL_OID *policyOID = NULL;
        PKIX_List *certPolicies = NULL;

        PKIX_TEST_STD_VARS();

        /* Convert from List of CertPolicyInfos to List of OIDs */
        if (certPolicyInfos) {
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength
                        (certPolicyInfos, &numInfos, plContext));
        }

        if (numInfos > 0) {
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create
                        (&certPolicies, plContext));
        }
        for (i = 0; i < numInfos; i++) {
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem
                (certPolicyInfos,
                i,
                (PKIX_PL_Object **)&certPolicyInfo,
                plContext));
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_CertPolicyInfo_GetPolicyId
                (certPolicyInfo, &policyOID, plContext));
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem
                (certPolicies, (PKIX_PL_Object *)policyOID, plContext));
            PKIX_TEST_DECREF_BC(certPolicyInfo);
            PKIX_TEST_DECREF_BC(policyOID);
        }

        *pPolicyOIDs = certPolicies;

cleanup:

        PKIX_TEST_DECREF_AC(certPolicyInfo);
        PKIX_TEST_DECREF_AC(policyOID);

        PKIX_TEST_RETURN();
}
Exemple #7
0
/*
 * FUNCTION: pkix_List_Remove
 * DESCRIPTION:
 *
 *  Traverses the List pointed to by "list", to find and delete an entry
 *  that is equal to the Object pointed to by "object". If no such entry
 *  is found the function does not return an error.
 *
 * PARAMETERS:
 *  "list"
 *      List to be searched; may be empty; must be non-NULL
 *  "object"
 *      Object to be checked for and deleted, if found; 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 Validate Error if the functions fails in a non-fatal way
 *  Returns a Fatal Error if the function fails in an unrecoverable way
 */
PKIX_Error *
pkix_List_Remove(
        PKIX_List *list,
        PKIX_PL_Object *object,
        void *plContext)
{
        PKIX_PL_Object *current = NULL;
        PKIX_UInt32 numEntries = 0;
        PKIX_UInt32 index = 0;
        PKIX_Boolean match = PKIX_FALSE;

        PKIX_ENTER(LIST, "pkix_List_Remove");
        PKIX_NULLCHECK_TWO(list, object);

        PKIX_CHECK(PKIX_List_GetLength(list, &numEntries, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (index = 0; index < numEntries; index++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (list, index, &current, plContext),
                        PKIX_LISTGETITEMFAILED);

                if (current) {
                        PKIX_CHECK(PKIX_PL_Object_Equals
                                (object, current, &match, plContext),
                                PKIX_OBJECTEQUALSFAILED);

                        PKIX_DECREF(current);
                }

                if (match) {
                        PKIX_CHECK(PKIX_List_DeleteItem
                                (list, index, plContext),
                                PKIX_LISTDELETEITEMFAILED);
                        break;
                }
        }

cleanup:

        PKIX_DECREF(current);
        PKIX_RETURN(LIST);
}
Exemple #8
0
/*
 * FUNCTION: pkix_List_AppendUnique
 * DESCRIPTION:
 *
 *  Adds each Object in the List pointed to by "fromList" to the List pointed
 *  to by "toList", if it is not already a member of that List. In other words,
 *  "toList" becomes the union of the two sets.
 *
 * PARAMETERS:
 *  "toList"
 *      Address of a List of Objects to be augmented by "fromList". Must be
 *      non-NULL, but may be empty.
 *  "fromList"
 *      Address of a List of Objects to be added, if not already present, to
 *      "toList". Must be non-NULL, but may be empty.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Not Thread Safe - assumes exclusive access to "toList"
 *  (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_List_AppendUnique(
        PKIX_List *toList,
        PKIX_List *fromList,
        void *plContext)
{
        PKIX_Boolean isContained = PKIX_FALSE;
        PKIX_UInt32 listLen = 0;
        PKIX_UInt32 listIx = 0;
        PKIX_PL_Object *object = NULL;

        PKIX_ENTER(BUILD, "pkix_List_AppendUnique");
        PKIX_NULLCHECK_TWO(fromList, toList);

        PKIX_CHECK(PKIX_List_GetLength(fromList, &listLen, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (listIx = 0; listIx < listLen; listIx++) {

                PKIX_CHECK(PKIX_List_GetItem
                        (fromList, listIx, &object, plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(pkix_List_Contains
                        (toList, object, &isContained, plContext),
                        PKIX_LISTCONTAINSFAILED);

                if (isContained == PKIX_FALSE) {
                        PKIX_CHECK(PKIX_List_AppendItem
                                (toList, object, plContext),
                                PKIX_LISTAPPENDITEMFAILED);
                }

                PKIX_DECREF(object);
        }

cleanup:

        PKIX_DECREF(object);

        PKIX_RETURN(LIST);
}
/*
 * 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_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
 */
PKIX_Error *
PKIX_PL_AIAMgr_GetAIACerts(
        PKIX_PL_AIAMgr *aiaMgr,
        PKIX_PL_Cert *prevCert,
        void **pNBIOContext,
        PKIX_List **pCerts,
        void *plContext)
{
        PKIX_UInt32 numAias = 0;
        PKIX_UInt32 aiaIndex = 0;
        PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
        PKIX_List *certs = NULL;
        PKIX_PL_InfoAccess *ia = NULL;
        void *nbio = NULL;

        PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
        PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);

        nbio = *pNBIOContext;
        *pCerts = NULL;
        *pNBIOContext = NULL;

        if (nbio == NULL) { /* a new request */

                /* Does this Cert have an AIA extension? */
                PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
                        (prevCert, &aiaMgr->aia, plContext),
                        PKIX_CERTGETAUTHORITYINFOACCESSFAILED);

                if (aiaMgr->aia != NULL) {
                        PKIX_CHECK(PKIX_List_GetLength
                                (aiaMgr->aia, &numAias, plContext),
                                PKIX_LISTGETLENGTHFAILED);
                }

                /* And if so, does it have any entries? */
                if ((aiaMgr->aia == NULL) || (numAias == 0)) {
                        *pCerts = NULL;
                        goto cleanup;
                }

                aiaMgr->aiaIndex = 0;
                aiaMgr->numAias = numAias;
                aiaMgr->results = NULL;

        }

        for (aiaIndex = aiaMgr->aiaIndex;
                aiaIndex < aiaMgr->numAias;
                aiaIndex ++) {
                PKIX_UInt32 method = 0;

                PKIX_CHECK(PKIX_List_GetItem
                        (aiaMgr->aia,
                        aiaIndex,
                        (PKIX_PL_Object **)&ia,
                        plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
                        (ia, &method, plContext),
                        PKIX_INFOACCESSGETMETHODFAILED);

                if (method != PKIX_INFOACCESS_CA_ISSUERS &&
                    method != PKIX_INFOACCESS_CA_REPOSITORY) {
                    PKIX_DECREF(ia);
                    continue;
                }
                
                PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
                        (ia, &iaType, plContext),
                        PKIX_INFOACCESSGETLOCATIONTYPEFAILED);

                if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
			PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
				(aiaMgr, ia, &nbio, &certs, plContext),
				PKIX_AIAMGRGETHTTPCERTSFAILED);
                } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
			PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
				(aiaMgr, ia, &nbio, &certs, plContext),
				PKIX_AIAMGRGETLDAPCERTSFAILED);
                } else {
                        /* We only support http and ldap requests. */
                        PKIX_DECREF(ia);
                        continue;
                }

                if (nbio != NULL) { /* WOULDBLOCK */
                        aiaMgr->aiaIndex = aiaIndex;
                        *pNBIOContext = nbio;
                        *pCerts = NULL;
                        goto cleanup;
                }

                /*
                 * We can't just use and modify the List we received.
                 * Because it's cached, it's set immutable.
                 */
                if (aiaMgr->results == NULL) {
                        PKIX_CHECK(PKIX_List_Create
                                (&(aiaMgr->results), plContext),
                                PKIX_LISTCREATEFAILED);
                }
                PKIX_CHECK(pkix_List_AppendList
                        (aiaMgr->results, certs, plContext),
                        PKIX_APPENDLISTFAILED);
                PKIX_DECREF(certs);

                PKIX_DECREF(ia);
        }

        PKIX_DECREF(aiaMgr->aia);

        *pNBIOContext = NULL;
        *pCerts = aiaMgr->results;
        aiaMgr->results = NULL;

cleanup:

        if (PKIX_ERROR_RECEIVED) {
                PKIX_DECREF(aiaMgr->aia);
                PKIX_DECREF(aiaMgr->results);
                PKIX_DECREF(aiaMgr->client.ldapClient);
        }

        PKIX_DECREF(certs);
        PKIX_DECREF(ia);

        PKIX_RETURN(AIAMGR);
}
/*
 * 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_pl_LdapCertStore_GetCRL
 *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
 */
PKIX_Error *
pkix_pl_LdapCertStore_GetCRL(
        PKIX_CertStore *store,
        PKIX_CRLSelector *selector,
        void **pNBIOContext,
        PKIX_List **pCrlList,
        void *plContext)
{
        LDAPRequestParams requestParams;
        void *pollDesc = NULL;
        PRArenaPool *requestArena = NULL;
        PKIX_UInt32 numNames = 0;
        PKIX_UInt32 thisName = 0;
        PKIX_PL_CRL *candidate = NULL;
        PKIX_List *responses = NULL;
        PKIX_List *issuerNames = NULL;
        PKIX_List *filteredCRLs = NULL;
        PKIX_List *unfilteredCRLs = NULL;
        PKIX_PL_X500Name *issuer = NULL;
        PKIX_PL_LdapCertStoreContext *lcs = NULL;
        PKIX_ComCRLSelParams *params = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRL");
        PKIX_NULLCHECK_THREE(store, selector, pCrlList);

        requestParams.baseObject = "c=US";
        requestParams.scope = WHOLE_SUBTREE;
        requestParams.derefAliases = NEVER_DEREF;
        requestParams.sizeLimit = 0;
        requestParams.timeLimit = 0;
        requestParams.attributes = LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST;
        /* Prepare elements for request filter */

        /* XXX Place CRLDP code here. Handle the case when */
        /* RFC 5280. Paragraph: 4.2.1.13: */
        /* If the distributionPoint field contains a directoryName, the entry */
        /* for that directoryName contains the current CRL for the associated */
        /* reasons and the CRL is issued by the associated cRLIssuer.  The CRL */
        /* may be stored in either the certificateRevocationList or */
        /* authorityRevocationList attribute.  The CRL is to be obtained by the */
        /* application from whatever directory server is locally configured. */
        /* The protocol the application uses to access the directory (e.g., DAP */
        /* or LDAP) is a local matter. */



        /*
         * Get a short-lived arena. We'll be done with this space once
         * the request is encoded.
         */
        PKIX_PL_NSSCALLRV
            (CERTSTORE, requestArena, PORT_NewArena, (DER_DEFAULT_CHUNKSIZE));

        if (!requestArena) {
                PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
        }

        PKIX_CHECK(PKIX_CRLSelector_GetCommonCRLSelectorParams
                (selector, &params, plContext),
                PKIX_CRLSELECTORGETCOMCERTSELPARAMSFAILED);

        PKIX_CHECK(PKIX_ComCRLSelParams_GetIssuerNames
                (params, &issuerNames, plContext),
                PKIX_COMCRLSELPARAMSGETISSUERNAMESFAILED);

        /*
         * The specification for PKIX_ComCRLSelParams_GetIssuerNames in
         * pkix_crlsel.h says that if the criterion is not set we get a null
         * pointer. If we get an empty List the criterion is impossible to
         * meet ("must match at least one of the names in the List").
         */
        if (issuerNames) {

                PKIX_CHECK(PKIX_List_GetLength
                        (issuerNames, &numNames, plContext),
                        PKIX_LISTGETLENGTHFAILED);

                if (numNames > 0) {
                        for (thisName = 0; thisName < numNames; thisName++) {
                                PKIX_CHECK(PKIX_List_GetItem
                                (issuerNames,
                                thisName,
                                (PKIX_PL_Object **)&issuer,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                                PKIX_CHECK
                                        (pkix_pl_LdapCertStore_MakeNameAVAList
                                        (requestArena,
                                        issuer,
                                        &(requestParams.nc),
                                        plContext),
                                        PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);

                                PKIX_DECREF(issuer);

                                if (*requestParams.nc == NULL) {
                                        /*
                                         * The issuer may not include any
                                         * components that we know how to
                                         * encode. We do not return an error,
                                         * because the caller did not
                                         * necessarily do anything wrong, but
                                         * we return an empty List.
                                         */
                                        PKIX_PL_NSSCALL
                                                (CERTSTORE, PORT_FreeArena,
                                                (requestArena, PR_FALSE));

                                        PKIX_CHECK(PKIX_List_Create
                                                (&filteredCRLs, plContext),
                                                PKIX_LISTCREATEFAILED);

                                        PKIX_CHECK(PKIX_List_SetImmutable
                                                (filteredCRLs, plContext),
                                               PKIX_LISTSETIMMUTABLEFAILED);

                                        *pNBIOContext = NULL;
                                        *pCrlList = filteredCRLs;
                                        goto cleanup;
                                }

                                /*
                                 * LDAP Servers don't seem to be able to handle
                                 * requests with more than more than one name.
                                 */
                                break;
                        }
                } else {
                        PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
                }
        } else {
                PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
        }

        /* All request fields are done */

        PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
                (store, (PKIX_PL_Object **)&lcs, plContext),
                PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);

        PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
                ((PKIX_PL_LdapClient *)lcs,
                &requestParams,
                &pollDesc,
                &responses,
                plContext),
                PKIX_LDAPCLIENTINITIATEREQUESTFAILED);

        PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList
                (requestParams.nc, plContext),
                PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED);

        if (requestArena) {
                PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
                        (requestArena, PR_FALSE));
        }

        if (pollDesc != NULL) {
                /* client is waiting for non-blocking I/O to complete */
                *pNBIOContext = (void *)pollDesc;
                *pCrlList = NULL;
                goto cleanup;
        }
        /* client has finished! */

        if (responses) {

                /*
                 * We have a List of LdapResponse objects that still have to be
                 * turned into Crls.
                 */
                PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
                        (responses, &unfilteredCRLs, plContext),
                        PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);

                PKIX_CHECK(pkix_CRLSelector_Select
                        (selector, unfilteredCRLs, &filteredCRLs, plContext),
                        PKIX_CRLSELECTORSELECTFAILED);

        }

        /* Don't throw away the list if one CRL was bad! */
        pkixTempErrorReceived = PKIX_FALSE;

        *pNBIOContext = NULL;
        *pCrlList = filteredCRLs;

cleanup:

        if (PKIX_ERROR_RECEIVED) {
                PKIX_DECREF(filteredCRLs);
        }

        PKIX_DECREF(params);
        PKIX_DECREF(issuerNames);
        PKIX_DECREF(issuer);
        PKIX_DECREF(candidate);
        PKIX_DECREF(responses);
        PKIX_DECREF(unfilteredCRLs);
        PKIX_DECREF(lcs);

        PKIX_RETURN(CERTSTORE);
}
int test_buildchain_uchecker(int argc, char *argv[])
{
        PKIX_BuildResult *buildResult = NULL;
        PKIX_ComCertSelParams *certSelParams = NULL;
        PKIX_CertSelector *certSelector = NULL;
        PKIX_TrustAnchor *anchor = NULL;
        PKIX_List *anchors = NULL;
        PKIX_List *certs = NULL;
        PKIX_PL_Cert *cert = NULL;
        PKIX_ProcessingParams *procParams = NULL;
        PKIX_CertChainChecker *checker = NULL;
        char *dirName = NULL;
        PKIX_PL_String *dirNameString = NULL;
        PKIX_PL_Cert *trustedCert = NULL;
        PKIX_PL_Cert *targetCert = NULL;
        PKIX_UInt32 numCerts = 0;
        PKIX_UInt32 i = 0;
        PKIX_UInt32 j = 0;
        PKIX_UInt32 k = 0;
        PKIX_UInt32 chainLength = 0;
        PKIX_CertStore *certStore = NULL;
        PKIX_List *certStores = NULL;
        char * asciiResult = NULL;
        PKIX_Boolean result;
        PKIX_Boolean testValid = PKIX_TRUE;
        PKIX_Boolean supportForward = PKIX_FALSE;
        PKIX_List *expectedCerts = NULL;
        PKIX_List *userOIDs = NULL;
        PKIX_PL_OID *oid = NULL;
        PKIX_PL_Cert *dirCert = NULL;
        PKIX_PL_String *actualCertsString = NULL;
        PKIX_PL_String *expectedCertsString = NULL;
        char *actualCertsAscii = NULL;
        char *expectedCertsAscii = NULL;
        char *oidString = NULL;
        void *buildState = NULL; /* needed by pkix_build for non-blocking I/O */
        void *nbioContext = NULL; /* needed by pkix_build for non-blocking I/O */

        PKIX_TEST_STD_VARS();

        if (argc < 5){
                printUsage();
                return (0);
        }

        startTests("BuildChain_UserChecker");

        PKIX_TEST_EXPECT_NO_ERROR(
            PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext));

        /* ENE = expect no error; EE = expect error */
        if (PORT_Strcmp(argv[2+j], "ENE") == 0) {
                testValid = PKIX_TRUE;
        } else if (PORT_Strcmp(argv[2+j], "EE") == 0) {
                testValid = PKIX_FALSE;
        } else {
                printUsage();
                return (0);
        }

        /* OID specified at argv[3+j] */

        if (*argv[3+j] != '-') {

                if (*argv[3+j] == 'F') {
                        supportForward = PKIX_TRUE;
                        oidString = argv[3+j]+1;
                } else {
                        oidString = argv[3+j];
                }

                PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create
                                (&userOIDs, plContext));
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_OID_Create
                                (oidString, &oid, plContext));
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem
                                (userOIDs, (PKIX_PL_Object *)oid, plContext));
                PKIX_TEST_DECREF_BC(oid);
        }

        subTest(argv[1+j]);

        dirName = argv[4+j];

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&expectedCerts, plContext));

        chainLength = argc - j - 5;

        for (k = 0; k < chainLength; k++){

                dirCert = createCert(dirName, argv[5+k+j], plContext);

                if (k == (chainLength - 1)){
                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_PL_Object_IncRef
                                ((PKIX_PL_Object *)dirCert, plContext));
                        trustedCert = dirCert;
                } else {

                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_List_AppendItem
                                (expectedCerts,
                                (PKIX_PL_Object *)dirCert,
                                plContext));

                        if (k == 0){
                                PKIX_TEST_EXPECT_NO_ERROR
                                        (PKIX_PL_Object_IncRef
                                        ((PKIX_PL_Object *)dirCert,
                                        plContext));
                                targetCert = dirCert;
                        }
                }

                PKIX_TEST_DECREF_BC(dirCert);
        }

        /* create processing params with list of trust anchors */

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_TrustAnchor_CreateWithCert
                                    (trustedCert, &anchor, plContext));
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&anchors, plContext));
        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_List_AppendItem
                (anchors, (PKIX_PL_Object *)anchor, plContext));
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_Create
                                    (anchors, &procParams, plContext));

        /* create CertSelector with target certificate in params */

        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_ComCertSelParams_Create(&certSelParams, plContext));

        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_ComCertSelParams_SetCertificate
                (certSelParams, targetCert, plContext));

        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_CertSelector_Create
                (NULL, NULL, &certSelector, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_CertSelector_SetCommonCertSelectorParams
                                (certSelector, certSelParams, plContext));

        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_ProcessingParams_SetTargetCertConstraints
                (procParams, certSelector, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_CertChainChecker_Create
                                    (testUserChecker,
                                    supportForward,
                                    PKIX_FALSE,
                                    userOIDs,
                                    NULL,
                                    &checker,
                                    plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_AddCertChainChecker
                                  (procParams, checker, plContext));


        /* create CertStores */

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_String_Create
                                    (PKIX_ESCASCII,
                                    dirName,
                                    0,
                                    &dirNameString,
                                    plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_CollectionCertStore_Create
                                    (dirNameString, &certStore, plContext));

#if 0
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Pk11CertStore_Create
                                    (&certStore, plContext));
#endif


        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&certStores, plContext));

        PKIX_TEST_EXPECT_NO_ERROR
                (PKIX_List_AppendItem
                (certStores, (PKIX_PL_Object *)certStore, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_SetCertStores
                                    (procParams, certStores, plContext));

        /* build cert chain using processing params and return buildResult */

        pkixTestErrorResult = PKIX_BuildChain
                (procParams,
                &nbioContext,
                &buildState,
                &buildResult,
                NULL,
                plContext);

        if (testValid == PKIX_TRUE) { /* ENE */
                if (pkixTestErrorResult){
                        (void) printf("UNEXPECTED RESULT RECEIVED!\n");
                } else {
                        (void) printf("EXPECTED RESULT RECEIVED!\n");
                        PKIX_TEST_DECREF_BC(pkixTestErrorResult);
                }
        } else { /* EE */
                if (pkixTestErrorResult){
                        (void) printf("EXPECTED RESULT RECEIVED!\n");
                        PKIX_TEST_DECREF_BC(pkixTestErrorResult);
                } else {
                        testError("UNEXPECTED RESULT RECEIVED");
                }
        }

        if (buildResult){

                PKIX_TEST_EXPECT_NO_ERROR
                        (PKIX_BuildResult_GetCertChain
                        (buildResult, &certs, NULL));

                PKIX_TEST_EXPECT_NO_ERROR
                        (PKIX_List_GetLength(certs, &numCerts, plContext));

                printf("\n");

                for (i = 0; i < numCerts; i++){
                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_List_GetItem
                                (certs,
                                i,
                                (PKIX_PL_Object**)&cert,
                                plContext));

                        asciiResult = PKIX_Cert2ASCII(cert);

                        printf("CERT[%d]:\n%s\n", i, asciiResult);

                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_PL_Free(asciiResult, plContext));
                        asciiResult = NULL;

                        PKIX_TEST_DECREF_BC(cert);
                }

                PKIX_TEST_EXPECT_NO_ERROR
                        (PKIX_PL_Object_Equals
                        ((PKIX_PL_Object*)certs,
                        (PKIX_PL_Object*)expectedCerts,
                        &result,
                        plContext));

                if (!result){
                        testError("BUILT CERTCHAIN IS "
                                    "NOT THE ONE THAT WAS EXPECTED");

                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_PL_Object_ToString
                                ((PKIX_PL_Object *)certs,
                                &actualCertsString,
                                plContext));

                        actualCertsAscii = PKIX_String2ASCII
                                (actualCertsString, plContext);
                        if (actualCertsAscii == NULL){
                                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                                goto cleanup;
                        }

                        PKIX_TEST_EXPECT_NO_ERROR
                                (PKIX_PL_Object_ToString
                                ((PKIX_PL_Object *)expectedCerts,
                                &expectedCertsString,
                                plContext));

                        expectedCertsAscii = PKIX_String2ASCII
                                (expectedCertsString, plContext);
                        if (expectedCertsAscii == NULL){
                                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                                goto cleanup;
                        }

                        (void) printf("Actual value:\t%s\n", actualCertsAscii);
                        (void) printf("Expected value:\t%s\n",
                                        expectedCertsAscii);

                        if (chainLength - 1 != numUserCheckerCalled) {
                                pkixTestErrorMsg =
                                    "PKIX user defined checker not called";
                        }

                        goto cleanup;
                }

        }

cleanup:
        PKIX_PL_Free(asciiResult, plContext);
        PKIX_PL_Free(actualCertsAscii, plContext);
        PKIX_PL_Free(expectedCertsAscii, plContext);

        PKIX_TEST_DECREF_AC(actualCertsString);
        PKIX_TEST_DECREF_AC(expectedCertsString);
        PKIX_TEST_DECREF_AC(expectedCerts);
        PKIX_TEST_DECREF_AC(certs);
        PKIX_TEST_DECREF_AC(cert);
        PKIX_TEST_DECREF_AC(certStore);
        PKIX_TEST_DECREF_AC(certStores);
        PKIX_TEST_DECREF_AC(dirNameString);
        PKIX_TEST_DECREF_AC(trustedCert);
        PKIX_TEST_DECREF_AC(targetCert);
        PKIX_TEST_DECREF_AC(anchor);
        PKIX_TEST_DECREF_AC(anchors);
        PKIX_TEST_DECREF_AC(procParams);
        PKIX_TEST_DECREF_AC(certSelParams);
        PKIX_TEST_DECREF_AC(certSelector);
        PKIX_TEST_DECREF_AC(buildResult);
        PKIX_TEST_DECREF_AC(procParams);
        PKIX_TEST_DECREF_AC(userOIDs);
        PKIX_TEST_DECREF_AC(checker);

        PKIX_TEST_RETURN();

        PKIX_Shutdown(plContext);

        endTests("BuildChain_UserChecker");

        return (0);

}
/*
 * FUNCTION: pkix_pl_LdapCertStore_BuildCertList
 * DESCRIPTION:
 *
 *  This function takes a List of LdapResponse objects pointed to by
 *  "responseList" and extracts and decodes the Certificates in those responses,
 *  storing the List of those Certificates at "pCerts". If none of the objects
 *  can be decoded into a Cert, the returned List is empty.
 *
 * PARAMETERS:
 *  "responseList"
 *      The address of the List of LdapResponses. Must be non-NULL.
 *  "pCerts"
 *      The address at which the result is 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 CertStore 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_pl_LdapCertStore_BuildCertList(
        PKIX_List *responseList,
        PKIX_List **pCerts,
        void *plContext)
{
        PKIX_UInt32 numResponses = 0;
        PKIX_UInt32 respIx = 0;
        LdapAttrMask attrBits = 0;
        PKIX_PL_LdapResponse *response = NULL;
        PKIX_List *certList = NULL;
        LDAPMessage *message = NULL;
        LDAPSearchResponseEntry *sre = NULL;
        LDAPSearchResponseAttr **sreAttrArray = NULL;
        LDAPSearchResponseAttr *sreAttr = NULL;
        SECItem *attrType = NULL;
        SECItem **attrVal = NULL;
        SECItem *derCertItem = NULL;


        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCertList");
        PKIX_NULLCHECK_TWO(responseList, pCerts);

        PKIX_CHECK(PKIX_List_Create(&certList, plContext),
                PKIX_LISTCREATEFAILED);

        /* extract certs from response */
        PKIX_CHECK(PKIX_List_GetLength
                (responseList, &numResponses, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (respIx = 0; respIx < numResponses; respIx++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (responseList,
                        respIx,
                        (PKIX_PL_Object **)&response,
                        plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
                        (response, &message, plContext),
                        PKIX_LDAPRESPONSEGETMESSAGEFAILED);

                sre = &(message->protocolOp.op.searchResponseEntryMsg);
                sreAttrArray = sre->attributes;

                /* Get next element of null-terminated array */
                sreAttr = *sreAttrArray++;
                while (sreAttr != NULL) {
                    attrType = &(sreAttr->attrType);
                    PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
                        (attrType, &attrBits, plContext),
                        PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
                    /* Is this attrVal a Certificate? */
                    if (((LDAPATTR_CACERT | LDAPATTR_USERCERT) &
                            attrBits) == attrBits) {
                        attrVal = sreAttr->val;
                        derCertItem = *attrVal++;
                        while (derCertItem != 0) {
                            /* create a PKIX_PL_Cert from derCert */
                            PKIX_CHECK(pkix_pl_Cert_CreateToList
                                (derCertItem, certList, plContext),
                                PKIX_CERTCREATETOLISTFAILED);
                            derCertItem = *attrVal++;
                        }
                    } else if ((LDAPATTR_CROSSPAIRCERT & attrBits) == attrBits){
                        /* Is this attrVal a CrossPairCertificate? */
                        attrVal = sreAttr->val;
                        derCertItem = *attrVal++;
                        while (derCertItem != 0) {
                            /* create PKIX_PL_Certs from derCert */
                            PKIX_CHECK(pkix_pl_LdapCertStore_DecodeCrossCertPair
                                (derCertItem, certList, plContext),
                                PKIX_LDAPCERTSTOREDECODECROSSCERTPAIRFAILED);
                            derCertItem = *attrVal++;
                        }
                    }
                    sreAttr = *sreAttrArray++;
                }
                PKIX_DECREF(response);
        }

        *pCerts = certList;

cleanup:
        if (PKIX_ERROR_RECEIVED) {
                PKIX_DECREF(certList);
        }

        PKIX_DECREF(response);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_BuildCrlList
 * DESCRIPTION:
 *
 *  This function takes a List of LdapResponse objects pointed to by
 *  "responseList" and extracts and decodes the CRLs in those responses, storing
 *  the List of those CRLs at "pCrls". If none of the objects can be decoded
 *  into a CRL, the returned List is empty.
 *
 * PARAMETERS:
 *  "responseList"
 *      The address of the List of LdapResponses. Must be non-NULL.
 *  "pCrls"
 *      The address at which the result is 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 CertStore 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_pl_LdapCertStore_BuildCrlList(
        PKIX_List *responseList,
        PKIX_List **pCrls,
        void *plContext)
{
        PKIX_UInt32 numResponses = 0;
        PKIX_UInt32 respIx = 0;
        LdapAttrMask attrBits = 0;
        CERTSignedCrl *nssCrl = NULL;
        PKIX_PL_LdapResponse *response = NULL;
        PKIX_List *crlList = NULL;
        PKIX_PL_CRL *crl = NULL;
        LDAPMessage *message = NULL;
        LDAPSearchResponseEntry *sre = NULL;
        LDAPSearchResponseAttr **sreAttrArray = NULL;
        LDAPSearchResponseAttr *sreAttr = NULL;
        SECItem *attrType = NULL;
        SECItem **attrVal = NULL;
        SECItem *derCrlCopy = NULL;
        SECItem *derCrlItem = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCrlList");
        PKIX_NULLCHECK_TWO(responseList, pCrls);

        PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
                PKIX_LISTCREATEFAILED);

        /* extract crls from response */
        PKIX_CHECK(PKIX_List_GetLength
                (responseList, &numResponses, plContext),
                PKIX_LISTGETLENGTHFAILED);

        for (respIx = 0; respIx < numResponses; respIx++) {
                PKIX_CHECK(PKIX_List_GetItem
                        (responseList,
                        respIx,
                        (PKIX_PL_Object **)&response,
                        plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
                        (response, &message, plContext),
                        PKIX_LDAPRESPONSEGETMESSAGEFAILED);

                sre = &(message->protocolOp.op.searchResponseEntryMsg);
                sreAttrArray = sre->attributes;

                /* Get next element of null-terminated array */
                sreAttr = *sreAttrArray++;
                while (sreAttr != NULL) {
                    attrType = &(sreAttr->attrType);
                    PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
                        (attrType, &attrBits, plContext),
                        PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
                    /* Is this attrVal a Revocation List? */
                    if (((LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST) &
                            attrBits) == attrBits) {
                        attrVal = sreAttr->val;
                        derCrlItem = *attrVal++;
                        while (derCrlItem != 0) {
                            /* create a PKIX_PL_Crl from derCrl */
                            derCrlCopy = SECITEM_DupItem(derCrlItem);
                            if (!derCrlCopy) {
                                PKIX_ERROR(PKIX_ALLOCERROR);
                            }
                            /* crl will be based on derCrlCopy, but wont
                             * own the der. */
                            nssCrl =
                                CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy,
                                                       SEC_CRL_TYPE,
                                                       CRL_DECODE_DONT_COPY_DER |
                                                       CRL_DECODE_SKIP_ENTRIES);
                            if (!nssCrl) {
                                SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
                                continue;
                            }
                            /* pkix crl own the der. */
                            PKIX_CHECK(
                                pkix_pl_CRL_CreateWithSignedCRL(nssCrl, 
                                       derCrlCopy, NULL, &crl, plContext),
                                PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
                            /* Left control over memory pointed by derCrlCopy and
                             * nssCrl to pkix crl. */
                            derCrlCopy = NULL;
                            nssCrl = NULL;
                            PKIX_CHECK(PKIX_List_AppendItem
                                       (crlList, (PKIX_PL_Object *) crl, plContext),
                                       PKIX_LISTAPPENDITEMFAILED);
                            PKIX_DECREF(crl);
                            derCrlItem = *attrVal++;
                        }
                        /* Clean up after PKIX_CHECK_ONLY_FATAL */
                        pkixTempErrorReceived = PKIX_FALSE;
                    }
                    sreAttr = *sreAttrArray++;
                }
                PKIX_DECREF(response);
        }

        *pCrls = crlList;
        crlList = NULL;
cleanup:
        if (derCrlCopy) {
            SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
        }
        if (nssCrl) {
            SEC_DestroyCrl(nssCrl);
        }
        PKIX_DECREF(crl);
        PKIX_DECREF(crlList);
        PKIX_DECREF(response);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: pkix_TargetCertChecker_Check
 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h)
 */
PKIX_Error *
pkix_TargetCertChecker_Check(
        PKIX_CertChainChecker *checker,
        PKIX_PL_Cert *cert,
        PKIX_List *unresolvedCriticalExtensions,
        void **pNBIOContext,
        void *plContext)
{
        pkix_TargetCertCheckerState *state = NULL;
        PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
        PKIX_PL_CertNameConstraints *nameConstraints = NULL;
        PKIX_List *certSubjAltNames = NULL;
        PKIX_List *certExtKeyUsageList = NULL;
        PKIX_PL_GeneralName *name = NULL;
        PKIX_PL_X500Name *certSubjectName = NULL;
        PKIX_Boolean checkPassed = PKIX_FALSE;
        PKIX_UInt32 numItems, i;
        PKIX_UInt32 matchCount = 0;

        PKIX_ENTER(CERTCHAINCHECKER, "pkix_TargetCertChecker_Check");
        PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);

        *pNBIOContext = NULL; /* we never block on pending I/O */

        PKIX_CHECK(PKIX_CertChainChecker_GetCertChainCheckerState
                    (checker, (PKIX_PL_Object **)&state, plContext),
                    PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);

        (state->certsRemaining)--;

        if (state->pathToNameList != NULL) {

                PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
                    (cert, &nameConstraints, plContext),
                    PKIX_CERTGETNAMECONSTRAINTSFAILED);

                /*
                 * XXX We should either make the following call a public one
                 * so it is legal to call from the portability layer or we
                 * should try to create pathToNameList as CertNameConstraints
                 * then call the existing check function.
                 */
                PKIX_CHECK(PKIX_PL_CertNameConstraints_CheckNamesInNameSpace
                    (state->pathToNameList,
                    nameConstraints,
                    &checkPassed,
                    plContext),
                    PKIX_CERTNAMECONSTRAINTSCHECKNAMEINNAMESPACEFAILED);

                if (checkPassed != PKIX_TRUE) {
                    PKIX_ERROR(PKIX_VALIDATIONFAILEDPATHTONAMECHECKFAILED);
                }

        }

        PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
                    (cert, &certSubjAltNames, plContext),
                    PKIX_CERTGETSUBJALTNAMESFAILED);

        if (state->subjAltNameList != NULL && certSubjAltNames != NULL) {

                PKIX_CHECK(PKIX_List_GetLength
                        (state->subjAltNameList, &numItems, plContext),
                        PKIX_LISTGETLENGTHFAILED);

                for (i = 0; i < numItems; i++) {

                        PKIX_CHECK(PKIX_List_GetItem
                            (state->subjAltNameList,
                            i,
                            (PKIX_PL_Object **) &name,
                            plContext),
                            PKIX_LISTGETITEMFAILED);

                        PKIX_CHECK(pkix_List_Contains
                            (certSubjAltNames,
                            (PKIX_PL_Object *) name,
                            &checkPassed,
                            plContext),
                            PKIX_LISTCONTAINSFAILED);

                        PKIX_DECREF(name);

                        if (checkPassed == PKIX_TRUE) {

                            if (state->subjAltNameMatchAll == PKIX_FALSE) {
                                matchCount = numItems;
                                break;
                            } else {
                                /* else continue checking next */
                                matchCount++;
                            }

                        }
                }

                if (matchCount != numItems) {
                        PKIX_ERROR(PKIX_SUBJALTNAMECHECKFAILED);

                }
        }

        if (state->certsRemaining == 0) {

            if (state->certSelector != NULL) {
                PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
                           (state->certSelector,
                            &certSelectorMatch,
                            plContext),
                           PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);

                PKIX_CHECK(certSelectorMatch
                           (state->certSelector,
                            cert,
                            plContext),
                           PKIX_CERTSELECTORMATCHFAILED);
            } else {
                /* Check at least cert/key usages if target cert selector
                 * is not set. */
                PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert,
                                         PKIX_FALSE  /* is chain cert*/,
                                         plContext),
                           PKIX_CERTVERIFYCERTTYPEFAILED);
            }
            /*
             * There are two Extended Key Usage Checkings
             * available :
             * 1) here at the targetcertchecker where we
             *    verify the Extended Key Usage OIDs application
             *    specifies via ComCertSelParams are included
             *    in Cert's Extended Key Usage OID's. Note,
             *    this is an OID to OID comparison and only last
             *    Cert is checked.
             * 2) at user defined ekuchecker where checking
             *    is applied to all Certs on the chain and
             *    the NSS Extended Key Usage algorithm is
             *    used. In order to invoke this checking, not
             *    only does the ComCertSelparams needs to be
             *    set, the EKU initialize call is required to
             *    activate the checking.
             *
             * XXX We use the same ComCertSelParams Set/Get
             * functions to set the parameters for both cases.
             * We may want to separate them in the future.
             */
            
            PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
                       (cert, &certExtKeyUsageList, plContext),
                       PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
            
            
            if (state->extKeyUsageList != NULL &&
                certExtKeyUsageList != NULL) {
                
                PKIX_CHECK(PKIX_List_GetLength
                           (state->extKeyUsageList, &numItems, plContext),
                           PKIX_LISTGETLENGTHFAILED);
                
                for (i = 0; i < numItems; i++) {
                    
                    PKIX_CHECK(PKIX_List_GetItem
                               (state->extKeyUsageList,
                                i,
                                (PKIX_PL_Object **) &name,
                                plContext),
                               PKIX_LISTGETITEMFAILED);
                    
                    PKIX_CHECK(pkix_List_Contains
                               (certExtKeyUsageList,
                                (PKIX_PL_Object *) name,
                                &checkPassed,
                                plContext),
                               PKIX_LISTCONTAINSFAILED);
                    
                    PKIX_DECREF(name);
                    
                    if (checkPassed != PKIX_TRUE) {
                        PKIX_ERROR
                            (PKIX_EXTENDEDKEYUSAGECHECKINGFAILED);
                        
                    }
                }
            }
        } else {
            /* Check key usage and cert type based on certificate usage. */
            PKIX_CHECK(PKIX_PL_Cert_VerifyCertAndKeyType(cert, PKIX_TRUE,
                                                         plContext),
                       PKIX_CERTVERIFYCERTTYPEFAILED);
        }

        /* Remove Critical Extension OID from list */
        if (unresolvedCriticalExtensions != NULL) {

                PKIX_CHECK(pkix_List_Remove
                            (unresolvedCriticalExtensions,
                            (PKIX_PL_Object *) state->extKeyUsageOID,
                            plContext),
                            PKIX_LISTREMOVEFAILED);

                PKIX_CHECK(PKIX_PL_Cert_GetSubject
                            (cert, &certSubjectName, plContext),
                            PKIX_CERTGETSUBJECTFAILED);

                if (certSubjAltNames != NULL) {
                        PKIX_CHECK(pkix_List_Remove
                            (unresolvedCriticalExtensions,
                            (PKIX_PL_Object *) state->subjAltNameOID,
                            plContext),
                            PKIX_LISTREMOVEFAILED);
                }

        }

cleanup:

        PKIX_DECREF(name);
        PKIX_DECREF(nameConstraints);
        PKIX_DECREF(certSubjAltNames);
        PKIX_DECREF(certExtKeyUsageList);
        PKIX_DECREF(certSubjectName);
        PKIX_DECREF(state);

        PKIX_RETURN(CERTCHAINCHECKER);

}
/*
 * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCRL
 * DESCRIPTION:
 *
 *  Finds the CRLs that match the criterion of the CRLSelector pointed
 *  to by "selector" using the List of CRLs pointed to by "crlList" and
 *  stores the matching CRLs at "pSelectedCrlList".
 *
 *  Not recursive to sub-directory.
 *
 * PARAMETERS
 *  "crlList" - Address of List of CRLs to be searched. Must be non-NULL
 *  "selector" - CRLSelector for chosing CRL based on Params set
 *  "pSelectedCrlList" - CRLs that qualified by selector.
 *  "plContext" - Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Not Thread Safe - A lock at top level is required.
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CollectionCertStoreContext 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_pl_CollectionCertStoreContext_GetSelectedCRL(
        PKIX_List *crlList,
        PKIX_CRLSelector *selector,
        PKIX_List **pSelectedCrlList,
        void *plContext)
{
        PKIX_List *selectCrlList = NULL;
        PKIX_PL_CRL *crlItem = NULL;
        PKIX_CRLSelector_MatchCallback crlSelectorMatch = NULL;
        PKIX_UInt32 numCrls = 0;
        PKIX_UInt32 i = 0;
        PKIX_Boolean match = PKIX_FALSE;

        PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
                    "pkix_pl_CollectionCertStoreContext_GetSelectedCRL");
        PKIX_NULLCHECK_THREE(crlList, selector, pSelectedCrlList);

        PKIX_CHECK(PKIX_CRLSelector_GetMatchCallback
                    (selector, &crlSelectorMatch, plContext),
                    PKIX_CRLSELECTORGETMATCHCALLBACKFAILED);

        PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (crlSelectorMatch) {

                PKIX_CHECK(PKIX_List_Create(&selectCrlList, plContext),
                            PKIX_LISTCREATEFAILED);

                for (i = 0; i < numCrls; i++) {
                        PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
                                (crlList,
                                i,
                                (PKIX_PL_Object **) &crlItem,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                        if (!PKIX_ERROR_RECEIVED){
                                PKIX_CHECK_ONLY_FATAL
                                        (crlSelectorMatch
                                        (selector, crlItem, &match, plContext),
                                        PKIX_CRLSELECTORMATCHFAILED);

                                if (!(PKIX_ERROR_RECEIVED) && match) {
                                        PKIX_CHECK_ONLY_FATAL
                                                (PKIX_List_AppendItem
                                                (selectCrlList,
                                                (PKIX_PL_Object *)crlItem,
                                                plContext),
                                                PKIX_LISTAPPENDITEMFAILED);
                                }
                        }

                        PKIX_DECREF(crlItem);
                }
        } else {

                PKIX_INCREF(crlList);

                selectCrlList = crlList;
        }

        /* Don't throw away the list if one CRL was bad! */
        pkixTempErrorReceived = PKIX_FALSE;

        *pSelectedCrlList = selectCrlList;

cleanup:
        PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
}
int
test_buildchain(int argc, char *argv[])
{
    PKIX_BuildResult *buildResult = NULL;
    PKIX_ComCertSelParams *certSelParams = NULL;
    PKIX_CertSelector *certSelector = NULL;
    PKIX_TrustAnchor *anchor = NULL;
    PKIX_PL_PublicKey *trustedPubKey = NULL;
    PKIX_List *anchors = NULL;
    PKIX_List *certs = NULL;
    PKIX_RevocationChecker *revChecker = NULL;
    PKIX_PL_Cert *cert = NULL;
    PKIX_ProcessingParams *procParams = NULL;
    char *dirName = NULL;
    PKIX_PL_String *dirNameString = NULL;
    PKIX_PL_Cert *trustedCert = NULL;
    PKIX_PL_Cert *targetCert = NULL;
    PKIX_UInt32 actualMinorVersion = 0;
    PKIX_UInt32 numCerts = 0;
    PKIX_UInt32 i = 0;
    PKIX_UInt32 j = 0;
    PKIX_UInt32 k = 0;
    PKIX_CertStore *ldapCertStore = NULL;
    PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT; /* blocking */
    /* PRIntervalTime timeout = PR_INTERVAL_NO_WAIT; =0 for non-blocking */
    PKIX_CertStore *certStore = NULL;
    PKIX_List *certStores = NULL;
    PKIX_List *revCheckers = NULL;
    char *asciiResult = NULL;
    PKIX_Boolean result = PKIX_FALSE;
    PKIX_Boolean testValid = PKIX_TRUE;
    PKIX_List *expectedCerts = NULL;
    PKIX_PL_Cert *dirCert = NULL;
    PKIX_VerifyNode *verifyTree = NULL;
    PKIX_PL_String *verifyString = NULL;
    PKIX_PL_String *actualCertsString = NULL;
    PKIX_PL_String *expectedCertsString = NULL;
    void *state = NULL;
    char *actualCertsAscii = NULL;
    char *expectedCertsAscii = NULL;
    PRPollDesc *pollDesc = NULL;

    PKIX_TEST_STD_VARS();

    if (argc < 5) {
        printUsage();
        return (0);
    }

    startTests("BuildChain");

    PKIX_TEST_EXPECT_NO_ERROR(
        PKIX_PL_NssContext_Create(0, PKIX_FALSE, NULL, &plContext));

    /*
         * arguments:
         * [optional] -arenas
         * [optional] usebind
         *            servername or servername:port ( - for no server)
         *            testname
         *            EE or ENE
         *            cert directory
         *            target cert (end entity)
         *            intermediate certs
         *            trust anchor
         */

    /* optional argument "usebind" for Ldap CertStore */
    if (argv[j + 1]) {
        if (PORT_Strcmp(argv[j + 1], "usebind") == 0) {
            usebind = PKIX_TRUE;
            j++;
        }
    }

    if (PORT_Strcmp(argv[++j], "-") == 0) {
        useLDAP = PKIX_FALSE;
    } else {
        serverName = argv[j];
        useLDAP = PKIX_TRUE;
    }

    subTest(argv[++j]);

    /* ENE = expect no error; EE = expect error */
    if (PORT_Strcmp(argv[++j], "ENE") == 0) {
        testValid = PKIX_TRUE;
    } else if (PORT_Strcmp(argv[j], "EE") == 0) {
        testValid = PKIX_FALSE;
    } else {
        printUsage();
        return (0);
    }

    dirName = argv[++j];

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&expectedCerts, plContext));

    for (k = ++j; k < (PKIX_UInt32)argc; k++) {

        dirCert = createCert(dirName, argv[k], plContext);

        if (k == (PKIX_UInt32)(argc - 1)) {
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_IncRef((PKIX_PL_Object *)dirCert, plContext));
            trustedCert = dirCert;
        } else {

            PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem(expectedCerts,
                                                           (PKIX_PL_Object *)dirCert,
                                                           plContext));

            if (k == j) {
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_IncRef((PKIX_PL_Object *)dirCert, plContext));
                targetCert = dirCert;
            }
        }

        PKIX_TEST_DECREF_BC(dirCert);
    }

    /* create processing params with list of trust anchors */

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_TrustAnchor_CreateWithCert(trustedCert, &anchor, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&anchors, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem(anchors, (PKIX_PL_Object *)anchor, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_Create(anchors, &procParams, plContext));

    /* create CertSelector with target certificate in params */

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_Create(&certSelParams, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetCertificate(certSelParams, targetCert, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_CertSelector_SetCommonCertSelectorParams(certSelector, certSelParams, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_SetTargetCertConstraints(procParams, certSelector, plContext));

    /* create CertStores */

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_String_Create(PKIX_ESCASCII, dirName, 0, &dirNameString, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&certStores, plContext));

    if (useLDAP == PKIX_TRUE) {
        PKIX_TEST_EXPECT_NO_ERROR(createLdapCertStore(serverName, timeout, &ldapCertStore, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem(certStores,
                                                       (PKIX_PL_Object *)ldapCertStore,
                                                       plContext));
    } else {
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_CollectionCertStore_Create(dirNameString, &certStore, plContext));
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem(certStores, (PKIX_PL_Object *)certStore, plContext));
    }

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_SetCertStores(procParams, certStores, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_Create(&revCheckers, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubjectPublicKey(trustedCert, &trustedPubKey, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength(expectedCerts, &numCerts, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(pkix_DefaultRevChecker_Initialize(certStores,
                                                                NULL, /* testDate, may be NULL */
                                                                trustedPubKey,
                                                                numCerts,
                                                                &revChecker,
                                                                plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_AppendItem(revCheckers, (PKIX_PL_Object *)revChecker, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_SetRevocationCheckers(procParams, revCheckers, plContext));

#ifdef debuggingWithoutRevocation
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ProcessingParams_SetRevocationEnabled(procParams, PKIX_FALSE, plContext));
#endif

    /* build cert chain using processing params and return buildResult */

    pkixTestErrorResult = PKIX_BuildChain(procParams,
                                          (void **)&pollDesc,
                                          &state,
                                          &buildResult,
                                          &verifyTree,
                                          plContext);

    while (pollDesc != NULL) {

        if (PR_Poll(pollDesc, 1, 0) < 0) {
            testError("PR_Poll failed");
        }

        pkixTestErrorResult = PKIX_BuildChain(procParams,
                                              (void **)&pollDesc,
                                              &state,
                                              &buildResult,
                                              &verifyTree,
                                              plContext);
    }

    if (pkixTestErrorResult) {
        if (testValid == PKIX_FALSE) { /* EE */
            (void)printf("EXPECTED ERROR RECEIVED!\n");
        } else { /* ENE */
            testError("UNEXPECTED ERROR RECEIVED");
        }
    } else {
        if (testValid == PKIX_TRUE) { /* ENE */
            (void)printf("EXPECTED NON-ERROR RECEIVED!\n");
        } else { /* EE */
            (void)printf("UNEXPECTED NON-ERROR RECEIVED!\n");
        }
    }

    subTest("Displaying VerifyNode objects");

    if (verifyTree == NULL) {
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_String_Create(PKIX_ESCASCII, "(null)", 0, &verifyString, plContext));
    } else {
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString((PKIX_PL_Object *)verifyTree, &verifyString, plContext));
    }

    (void)printf("verifyTree is\n%s\n", verifyString->escAsciiString);

    if (pkixTestErrorResult) {
        PKIX_TEST_DECREF_BC(pkixTestErrorResult);
        goto cleanup;
    }

    if (buildResult) {

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_BuildResult_GetCertChain(buildResult, &certs, plContext));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength(certs, &numCerts, plContext));

        printf("\n");

        for (i = 0; i < numCerts; i++) {
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem(certs,
                                                        i,
                                                        (PKIX_PL_Object **)&cert,
                                                        plContext));

            asciiResult = PKIX_Cert2ASCII(cert);

            printf("CERT[%d]:\n%s\n", i, asciiResult);

            /* PKIX_Cert2ASCII used PKIX_PL_Malloc(...,,NULL) */
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Free(asciiResult, NULL));
            asciiResult = NULL;

            PKIX_TEST_DECREF_BC(cert);
        }

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_Equals((PKIX_PL_Object *)certs,
                                                        (PKIX_PL_Object *)expectedCerts,
                                                        &result,
                                                        plContext));

        if (!result) {
            testError("BUILT CERTCHAIN IS "
                      "NOT THE ONE THAT WAS EXPECTED");

            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString((PKIX_PL_Object *)certs,
                                                              &actualCertsString,
                                                              plContext));

            actualCertsAscii = PKIX_String2ASCII(actualCertsString, plContext);
            if (actualCertsAscii == NULL) {
                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                goto cleanup;
            }

            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString((PKIX_PL_Object *)expectedCerts,
                                                              &expectedCertsString,
                                                              plContext));

            expectedCertsAscii = PKIX_String2ASCII(expectedCertsString, plContext);
            if (expectedCertsAscii == NULL) {
                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                goto cleanup;
            }

            (void)printf("Actual value:\t%s\n", actualCertsAscii);
            (void)printf("Expected value:\t%s\n",
                         expectedCertsAscii);
        }
    }

cleanup:
    PKIX_TEST_DECREF_AC(verifyString);
    PKIX_TEST_DECREF_AC(verifyTree);

    PKIX_PL_Free(asciiResult, NULL);
    PKIX_PL_Free(actualCertsAscii, plContext);
    PKIX_PL_Free(expectedCertsAscii, plContext);

    PKIX_TEST_DECREF_AC(state);
    PKIX_TEST_DECREF_AC(actualCertsString);
    PKIX_TEST_DECREF_AC(expectedCertsString);
    PKIX_TEST_DECREF_AC(expectedCerts);
    PKIX_TEST_DECREF_AC(buildResult);
    PKIX_TEST_DECREF_AC(procParams);
    PKIX_TEST_DECREF_AC(certStores);
    PKIX_TEST_DECREF_AC(revCheckers);
    PKIX_TEST_DECREF_AC(revChecker);
    PKIX_TEST_DECREF_AC(ldapCertStore);
    PKIX_TEST_DECREF_AC(certStore);
    PKIX_TEST_DECREF_AC(dirNameString);
    PKIX_TEST_DECREF_AC(certSelParams);
    PKIX_TEST_DECREF_AC(certSelector);
    PKIX_TEST_DECREF_AC(anchors);
    PKIX_TEST_DECREF_AC(anchor);
    PKIX_TEST_DECREF_AC(trustedCert);
    PKIX_TEST_DECREF_AC(trustedPubKey);

    PKIX_TEST_DECREF_AC(certs);
    PKIX_TEST_DECREF_AC(cert);
    PKIX_TEST_DECREF_AC(targetCert);

    PKIX_TEST_RETURN();

    PKIX_Shutdown(plContext);

    endTests("BuildChain");

    return (0);
}
/*
 * FUNCTION: pkix_CrlChecker_CheckLocal
 *
 * DESCRIPTION:
 *  Check if the Cert has been revoked based the CRLs data.  This function
 *  maintains the checker state to be current.
 *
 * PARAMETERS
 *  "checker"
 *      Address of CertChainChecker which has the state data.
 *      Must be non-NULL.
 *  "cert"
 *      Address of Certificate that is to be validated. Must be non-NULL.
 *  "unreslvdCrtExts"
 *      A List OIDs. Not **yet** used in this checker function.
 *  "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 CertChainChecker Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error
 */
PKIX_Error *
pkix_CrlChecker_CheckLocal(
        PKIX_PL_Cert *cert,
        PKIX_PL_Cert *issuer,
        PKIX_PL_Date *date,
        pkix_RevocationMethod *checkerObject,
        PKIX_ProcessingParams *procParams,
        PKIX_UInt32 methodFlags,
        PKIX_Boolean chainVerificationState,
        PKIX_RevocationStatus *pRevStatus,
        PKIX_UInt32 *pReasonCode,
        void *plContext)
{
    PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn;
    PKIX_CertStore *certStore = NULL;
    pkix_CrlChecker *state = NULL;
    PKIX_UInt32 reasonCode = 0;
    PKIX_UInt32 crlStoreIndex = 0;
    PKIX_UInt32 numCrlStores = 0;
    PKIX_Boolean storeIsLocal = PKIX_FALSE;
    PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;

    PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckLocal");
    PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, checkerObject);
    
    state = (pkix_CrlChecker*)checkerObject;

    PKIX_CHECK(
        PKIX_List_GetLength(state->certStores, &numCrlStores, plContext),
        PKIX_LISTGETLENGTHFAILED);

    for (;crlStoreIndex < numCrlStores;crlStoreIndex++) {
        PKIX_CHECK(
            PKIX_List_GetItem(state->certStores, crlStoreIndex,
                              (PKIX_PL_Object **)&certStore,
                              plContext),
            PKIX_LISTGETITEMFAILED);
        
        PKIX_CHECK(
            PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal,
                                        plContext),
            PKIX_CERTSTOREGETLOCALFLAGFAILED);
        if (storeIsLocal) {
            PKIX_CHECK(
                PKIX_CertStore_GetCrlCheckerFn(certStore,
                                               &storeCheckRevocationFn,
                                               plContext),
                PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);

            if (storeCheckRevocationFn) {
                PKIX_CHECK(
                    (*storeCheckRevocationFn)(certStore, cert, issuer,
                                         /* delay sig check if building
                                          * a chain by not specifying the time*/
                                          chainVerificationState ? date : NULL,
                                         /* crl downloading is not done. */
                                          PKIX_FALSE,   
                                          &reasonCode, &revStatus, plContext),
                    PKIX_CERTSTORECRLCHECKFAILED);
                if (revStatus == PKIX_RevStatus_Revoked) {
                    break;
                }
            }
        }
        PKIX_DECREF(certStore);
    } /* while */

cleanup:
    *pRevStatus = revStatus;
    PKIX_DECREF(certStore);

    PKIX_RETURN(CERTCHAINCHECKER);
}
/*
 * 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);
}
Exemple #21
0
/*
 * FUNCTION: pkix_List_QuickSort
 * DESCRIPTION:
 *
 *  Sorts List of Objects "fromList" using "comparatorCallback"'s result as
 *  comasrison key and returns the sorted List at "pSortedList". The sorting
 *  algorithm used is quick sort (n*logn).
 *
 * PARAMETERS:
 *  "fromList"
 *      Address of a List of Objects to be sorted. Must be non-NULL, but may be
 *      empty.
 *  "comparatorCallback"
 *      Address of callback function that will compare two Objects on the List.
 *      It should return -1 for less, 0 for equal and 1 for greater. The
 *      callback implementation chooses what in Objects to be compared. Must be
 *      non-NULL.
 *  "pSortedList"
 *      Address of a List of Objects that shall be sorted and returned. Must be
 *      non-NULL, but may be empty.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Not Thread Safe - assumes exclusive access to "toList"
 *  (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_List_QuickSort(
        PKIX_List *fromList,
        PKIX_List_SortComparatorCallback comparator,
        PKIX_List **pSortedList,
        void *plContext)
{
        PKIX_List *sortedList = NULL;
        PKIX_List *lessList = NULL;
        PKIX_List *greaterList = NULL;
        PKIX_List *sortedLessList = NULL;
        PKIX_List *sortedGreaterList = NULL;
        PKIX_PL_Object *object = NULL;
        PKIX_PL_Object *cmpObj = NULL;
        PKIX_Int32 cmpResult = 0;
        PKIX_UInt32 size = 0;
        PKIX_UInt32 i;

        PKIX_ENTER(BUILD, "pkix_List_QuickSort");
        PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);

        PKIX_CHECK(PKIX_List_GetLength(fromList, &size, plContext),
                PKIX_LISTGETLENGTHFAILED);

        PKIX_CHECK(PKIX_List_Create(&lessList, plContext),
                    PKIX_LISTCREATEFAILED);

        PKIX_CHECK(PKIX_List_Create(&greaterList, plContext),
                    PKIX_LISTCREATEFAILED);

        PKIX_CHECK(PKIX_List_GetItem
                (fromList, 0, &object, plContext),
                PKIX_LISTGETITEMFAILED);

        /*
         * Pick the first item on the list as the one to be compared.
         * Separate rest of the itmes into two lists: less-than or greater-
         * than lists. Sort those two lists recursively. Insert sorted
         * less-than list before the picked item and append the greater-
         * than list after the picked item.
         */
        for (i = 1; i < size; i++) {

                PKIX_CHECK(PKIX_List_GetItem
                        (fromList, i, &cmpObj, plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(comparator(object, cmpObj, &cmpResult, plContext),
                        PKIX_COMPARATORCALLBACKFAILED);

                if (cmpResult >= 0) {
                        PKIX_CHECK(PKIX_List_AppendItem
                                (lessList, cmpObj, plContext),
                                PKIX_LISTAPPENDITEMFAILED);
                } else {
                        PKIX_CHECK(PKIX_List_AppendItem
                                (greaterList, cmpObj, plContext),
                                PKIX_LISTAPPENDITEMFAILED);
                }
                PKIX_DECREF(cmpObj);
        }

        PKIX_CHECK(PKIX_List_Create(&sortedList, plContext),
                    PKIX_LISTCREATEFAILED);

        PKIX_CHECK(PKIX_List_GetLength(lessList, &size, plContext),
                PKIX_LISTGETLENGTHFAILED);

        if (size > 1) {

                PKIX_CHECK(pkix_List_QuickSort
                        (lessList, comparator, &sortedLessList, plContext),
                        PKIX_LISTQUICKSORTFAILED);

                PKIX_CHECK(pkix_List_AppendList
                        (sortedList, sortedLessList, plContext),
                        PKIX_LISTAPPENDLISTFAILED);
        } else {
                PKIX_CHECK(pkix_List_AppendList
                        (sortedList, lessList, plContext),
                        PKIX_LISTAPPENDLISTFAILED);
        }

        PKIX_CHECK(PKIX_List_AppendItem(sortedList, object, plContext),
                PKIX_LISTAPPENDFAILED);

        PKIX_CHECK(PKIX_List_GetLength(greaterList, &size, plContext),
                PKIX_LISTGETLENGTHFAILED);

        if (size > 1) {

                PKIX_CHECK(pkix_List_QuickSort
                        (greaterList, comparator, &sortedGreaterList, plContext),
                        PKIX_LISTQUICKSORTFAILED);

                PKIX_CHECK(pkix_List_AppendList
                        (sortedList, sortedGreaterList, plContext),
                        PKIX_LISTAPPENDLISTFAILED);
        } else {
                PKIX_CHECK(pkix_List_AppendList
                        (sortedList, greaterList, plContext),
                        PKIX_LISTAPPENDLISTFAILED);
        }

        *pSortedList = sortedList;

cleanup:

        PKIX_DECREF(cmpObj);
        PKIX_DECREF(object);
        PKIX_DECREF(sortedGreaterList);
        PKIX_DECREF(sortedLessList);
        PKIX_DECREF(greaterList);
        PKIX_DECREF(lessList);

        PKIX_RETURN(LIST);
}
Exemple #22
0
/*
 * FUNCTION: pkix_List_MergeLists
 * DESCRIPTION:
 *
 *  Creates a new list consisting of the items from "firstList", followed by
 *  the items on "secondList", returns the new list at "pMergedList". If
 *  both input lists are NULL or empty, the result is an empty list. If an error
 *  occurs, the result is NULL.
 *
 * PARAMETERS:
 *  "firstList"
 *      Address of list to be merged from. May be NULL or empty.
 *  "secondList"
 *      Address of list to be merged from. May be NULL or empty.
 *  "pMergedList"
 *      Address where returned object is 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 List Error if the functions fails in a non-fatal way
 *  Returns a Fatal Error if the function fails in an unrecoverable way
 */
PKIX_Error *
pkix_List_MergeLists(
        PKIX_List *firstList,
        PKIX_List *secondList,
        PKIX_List **pMergedList,
        void *plContext)
{
        PKIX_List *list = NULL;
        PKIX_PL_Object *item = NULL;
        PKIX_UInt32 numItems = 0;
        PKIX_UInt32 i;

        PKIX_ENTER(LIST, "pkix_List_MergeLists");
        PKIX_NULLCHECK_ONE(pMergedList);

        *pMergedList = NULL;

        PKIX_CHECK(PKIX_List_Create(&list, plContext),
                    PKIX_LISTCREATEFAILED);

        if (firstList != NULL) {

                PKIX_CHECK(PKIX_List_GetLength(firstList, &numItems, plContext),
                    PKIX_LISTGETLENGTHFAILED);
        }

        for (i = 0; i < numItems; i++) {

                PKIX_CHECK(PKIX_List_GetItem(firstList, i, &item, plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_List_AppendItem(list, item, plContext),
                        PKIX_LISTAPPENDITEMFAILED);

                PKIX_DECREF(item);
        }

        numItems = 0;
        if (secondList != NULL) {

                PKIX_CHECK(PKIX_List_GetLength
                        (secondList,
                        &numItems,
                        plContext),
                        PKIX_LISTGETLENGTHFAILED);

        }

        for (i = 0; i < numItems; i++) {

                PKIX_CHECK(PKIX_List_GetItem
                        (secondList, i, &item, plContext),
                        PKIX_LISTGETITEMFAILED);

                PKIX_CHECK(PKIX_List_AppendItem
                        (list, item, plContext), PKIX_LISTAPPENDITEMFAILED);

                PKIX_DECREF(item);
        }

        *pMergedList = list;
        list = NULL;

cleanup:
        PKIX_DECREF(list);
        PKIX_DECREF(item);
 
        PKIX_RETURN(LIST);
}
Exemple #23
0
/*
 * FUNCTION: pkix_List_BubbleSort
 * DESCRIPTION:
 *
 *  Sorts List of Objects "fromList" using "comparatorCallback"'s result as
 *  comasrison key and returns the sorted List at "pSortedList". The sorting
 *  algorithm used is bubble sort (n*n).
 *
 * PARAMETERS:
 *  "fromList"
 *      Address of a List of Objects to be sorted. Must be non-NULL, but may be
 *      empty.
 *  "comparatorCallback"
 *      Address of callback function that will compare two Objects on the List.
 *      It should return -1 for less, 0 for equal and 1 for greater. The
 *      callback implementation chooses what in Objects to be compared. Must be
 *      non-NULL.
 *  "pSortedList"
 *      Address of a List of Objects that shall be sorted and returned. Must be
 *      non-NULL, but may be empty.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Not Thread Safe - assumes exclusive access to "toList"
 *  (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_List_BubbleSort(
        PKIX_List *fromList,
        PKIX_List_SortComparatorCallback comparator,
        PKIX_List **pSortedList,
        void *plContext)
{
        PKIX_List *sortedList = NULL;
        PKIX_PL_Object *cmpObj = NULL;
        PKIX_PL_Object *leastObj = NULL;
        PKIX_Int32 cmpResult = 0;
        PKIX_UInt32 size = 0;
        PKIX_UInt32 i, j;

        PKIX_ENTER(BUILD, "pkix_List_BubbleSort");
        PKIX_NULLCHECK_THREE(fromList, comparator, pSortedList);
        
        if (fromList->immutable) {
            PKIX_ERROR(PKIX_CANNOTSORTIMMUTABLELIST);
        }
        PKIX_CHECK(pkix_List_Duplicate
                ((PKIX_PL_Object *) fromList,
                (PKIX_PL_Object **) &sortedList,
                 plContext),
                PKIX_LISTDUPLICATEFAILED);

        PKIX_CHECK(PKIX_List_GetLength(sortedList, &size, plContext),
                PKIX_LISTGETLENGTHFAILED);

        if (size > 1) {

        /*
         * Move from the first of the item on the list, For each iteration,
         * compare and swap the least value to the head of the comparisoning
         * sub-list.
         */
            for (i = 0; i < size - 1; i++) {

                PKIX_CHECK(PKIX_List_GetItem
                        (sortedList, i, &leastObj, plContext),
                        PKIX_LISTGETITEMFAILED);

                for (j = i + 1; j < size; j++) {
                        PKIX_CHECK(PKIX_List_GetItem
                                (sortedList, j, &cmpObj, plContext),
                                PKIX_LISTGETITEMFAILED);
                        PKIX_CHECK(comparator
                                (leastObj, cmpObj, &cmpResult, plContext),
                                PKIX_COMPARATORCALLBACKFAILED);
                        if (cmpResult > 0) {
                                PKIX_CHECK(PKIX_List_SetItem
                                           (sortedList, j, leastObj, plContext),
                                           PKIX_LISTSETITEMFAILED);

                                PKIX_DECREF(leastObj);
                                leastObj = cmpObj;
                                cmpObj = NULL;
                        } else {
                                PKIX_DECREF(cmpObj);
                        }
                }
                PKIX_CHECK(PKIX_List_SetItem
                           (sortedList, i, leastObj, plContext),
                           PKIX_LISTSETITEMFAILED);

                PKIX_DECREF(leastObj);
            }
                
        }

        *pSortedList = sortedList;
        sortedList = NULL;
cleanup:

        PKIX_DECREF(sortedList);
        PKIX_DECREF(leastObj);
        PKIX_DECREF(cmpObj);

        PKIX_RETURN(LIST);
}
Exemple #24
0
/*
 * FUNCTION: pkix_List_Equals
 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_List_Equals(
        PKIX_PL_Object *first,
        PKIX_PL_Object *second,
        PKIX_Boolean *pResult,
        void *plContext)
{
        PKIX_UInt32 secondType;
        PKIX_Boolean cmpResult;
        PKIX_List *firstList = NULL;
        PKIX_List *secondList = NULL;
        PKIX_UInt32 firstLength = 0;
        PKIX_UInt32 secondLength = 0;
        PKIX_PL_Object *firstItem = NULL;
        PKIX_PL_Object *secondItem = NULL;
        PKIX_UInt32 i = 0;

        PKIX_ENTER(LIST, "pkix_List_Equals");
        PKIX_NULLCHECK_THREE(first, second, pResult);

        /* test that first is a List */
        PKIX_CHECK(pkix_CheckType(first, PKIX_LIST_TYPE, plContext),
                PKIX_FIRSTOBJECTNOTLIST);

        /*
         * Since we know first is a List, if both references are
         * identical, they must be equal
         */
        if (first == second){
                *pResult = PKIX_TRUE;
                goto cleanup;
        }

        /*
         * If second isn't a List, we don't throw an error.
         * We simply return a Boolean result of FALSE
         */
        *pResult = PKIX_FALSE;
        PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
        if (secondType != PKIX_LIST_TYPE) goto cleanup;

        firstList = (PKIX_List *)first;
        secondList = (PKIX_List *)second;

        if ((!firstList->isHeader) && (!secondList->isHeader)){
                PKIX_ERROR(PKIX_INPUTLISTSMUSTBELISTHEADERS);
        }

        firstLength = firstList->length;
        secondLength = secondList->length;

        cmpResult = PKIX_FALSE;
        if (firstLength == secondLength){
                for (i = 0, cmpResult = PKIX_TRUE;
                    ((i < firstLength) && cmpResult);
                    i++){
                        PKIX_CHECK(PKIX_List_GetItem
                                    (firstList, i, &firstItem, plContext),
                                    PKIX_LISTGETITEMFAILED);

                        PKIX_CHECK(PKIX_List_GetItem
                                    (secondList, i, &secondItem, plContext),
                                    PKIX_LISTGETITEMFAILED);

                        if ((!firstItem && secondItem) ||
                            (firstItem && !secondItem)){
                                        cmpResult = PKIX_FALSE;
                        } else if (!firstItem && !secondItem){
                                continue;
                        } else {
                                PKIX_CHECK(PKIX_PL_Object_Equals
                                            (firstItem,
                                            secondItem,
                                            &cmpResult,
                                            plContext),
                                            PKIX_OBJECTEQUALSFAILED);

                                PKIX_DECREF(firstItem);
                                PKIX_DECREF(secondItem);
                        }
                }
        }

        *pResult = cmpResult;

cleanup:

        PKIX_DECREF(firstItem);
        PKIX_DECREF(secondItem);

        PKIX_RETURN(LIST);
}
/*
 * 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,
                &copy,
                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_EkuChecker_Check
 * DESCRIPTION:
 *
 *  This function determines the Extended Key Usage OIDs specified by the
 *  application is included in the Extended Key Usage OIDs of this "cert".
 *
 * PARAMETERS:
 *  "checker"
 *      Address of CertChainChecker which has the state data.
 *      Must be non-NULL.
 *  "cert"
 *      Address of Certificate that is to be validated. Must be non-NULL.
 *  "unresolvedCriticalExtensions"
 *      A List OIDs. The OID for Extended Key Usage is removed.
 *  "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 UserDefinedModules 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_EkuChecker_Check(
        PKIX_CertChainChecker *checker,
        PKIX_PL_Cert *cert,
        PKIX_List *unresolvedCriticalExtensions,
        void **pNBIOContext,
        void *plContext)
{
        pkix_EkuChecker *state = NULL;
        PKIX_List *requiredExtKeyUsageList = NULL;
        PKIX_List *certExtKeyUsageList = NULL;
        PKIX_PL_OID *ekuOid = NULL;
        PKIX_Boolean isContained = PKIX_FALSE;
        PKIX_UInt32 numItems = 0;
        PKIX_UInt32 i;
        PKIX_Boolean checkResult = PKIX_TRUE;

        PKIX_ENTER(EKUCHECKER, "pkix_EkuChecker_Check");
        PKIX_NULLCHECK_THREE(checker, cert, pNBIOContext);

        *pNBIOContext = NULL; /* no non-blocking IO */

        PKIX_CHECK(
            PKIX_CertChainChecker_GetCertChainCheckerState
            (checker, (PKIX_PL_Object **)&state, plContext),
            PKIX_CERTCHAINCHECKERGETCERTCHAINCHECKERSTATEFAILED);

        requiredExtKeyUsageList = state->requiredExtKeyUsageOids;
        if (requiredExtKeyUsageList == NULL) {
            goto cleanup;
        }

        PKIX_CHECK(
            PKIX_List_GetLength(requiredExtKeyUsageList, &numItems,
                                plContext),
            PKIX_LISTGETLENGTHFAILED);
        if (numItems == 0) {
            goto cleanup;
        }

        PKIX_CHECK(
            PKIX_PL_Cert_GetExtendedKeyUsage(cert, &certExtKeyUsageList,
                                             plContext),
            PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);

        if (certExtKeyUsageList == NULL) {
            goto cleanup;
        }
        
        for (i = 0; i < numItems; i++) {
            
            PKIX_CHECK(
                PKIX_List_GetItem(requiredExtKeyUsageList, i,
                                  (PKIX_PL_Object **)&ekuOid, plContext),
                PKIX_LISTGETITEMFAILED);

            PKIX_CHECK(
                pkix_List_Contains(certExtKeyUsageList,
                                   (PKIX_PL_Object *)ekuOid,
                                   &isContained,
                                   plContext),
                PKIX_LISTCONTAINSFAILED);
            
            PKIX_DECREF(ekuOid);
            if (isContained != PKIX_TRUE) {
                checkResult = PKIX_FALSE;
                goto cleanup;
            }
        }

cleanup:
        if (!pkixErrorResult && checkResult == PKIX_FALSE) {
            pkixErrorReceived = PKIX_TRUE;
            pkixErrorCode = PKIX_EXTENDEDKEYUSAGECHECKINGFAILED;
        }
        
        PKIX_DECREF(ekuOid);
        PKIX_DECREF(certExtKeyUsageList);
        PKIX_DECREF(state);

        PKIX_RETURN(EKUCHECKER);
}
/*
 * FUNCTION: PKIX_RevocationChecker_Check
 */
PKIX_Error *
PKIX_RevocationChecker_Check(
    PKIX_PL_Cert *cert,
    PKIX_PL_Cert *issuer,
    PKIX_RevocationChecker *revChecker,
    PKIX_ProcessingParams *procParams,
    PKIX_Boolean chainVerificationState,
    PKIX_Boolean testingLeafCert,
    PKIX_RevocationStatus *pRevStatus,
    PKIX_UInt32 *pReasonCode,
    void **pNbioContext,
    void *plContext)
{
    PKIX_RevocationStatus overallStatus = PKIX_RevStatus_NoInfo;
    PKIX_RevocationStatus methodStatus[PKIX_RevocationMethod_MAX];
    PKIX_Boolean onlyUseRemoteMethods = PKIX_FALSE;
    PKIX_UInt32 revFlags = 0;
    PKIX_List *revList = NULL;
    PKIX_PL_Date *date = NULL;
    pkix_RevocationMethod *method = NULL;
    void *nbioContext;
    int tries;
    
    PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_Check");
    PKIX_NULLCHECK_TWO(revChecker, procParams);

    nbioContext = *pNbioContext;
    *pNbioContext = NULL;
    
    if (testingLeafCert) {
        revList = revChecker->leafMethodList;
        revFlags = revChecker->leafMethodListFlags;        
    } else {
        revList = revChecker->chainMethodList;
        revFlags = revChecker->chainMethodListFlags;
    }
    if (!revList) {
        /* Return NoInfo status */
        goto cleanup;
    }

    PORT_Memset(methodStatus, PKIX_RevStatus_NoInfo,
                sizeof(PKIX_RevocationStatus) * PKIX_RevocationMethod_MAX);

    date = procParams->date;

    /* Need to have two loops if we testing all local info first:
     *    first we are going to test all local(cached) info
     *    second, all remote info(fetching) */
    for (tries = 0;tries < 2;tries++) {
        int methodNum = 0;
        for (;methodNum < revList->length;methodNum++) {
            PKIX_UInt32 methodFlags = 0;

            PKIX_DECREF(method);
            PKIX_CHECK(
                PKIX_List_GetItem(revList, methodNum,
                                  (PKIX_PL_Object**)&method, plContext),
                PKIX_LISTGETITEMFAILED);
            methodFlags = method->flags;
            if (!(methodFlags & PKIX_REV_M_TEST_USING_THIS_METHOD)) {
                /* Will not check with this method. Skipping... */
                continue;
            }
            if (!onlyUseRemoteMethods &&
                methodStatus[methodNum] == PKIX_RevStatus_NoInfo) {
                PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
                PKIX_CHECK_NO_GOTO(
                    (*method->localRevChecker)(cert, issuer, date,
                                               method, procParams,
                                               methodFlags, 
                                               chainVerificationState,
                                               &revStatus,
                                               pReasonCode, plContext),
                    PKIX_REVCHECKERCHECKFAILED);
                methodStatus[methodNum] = revStatus;
                if (revStatus == PKIX_RevStatus_Revoked) {
                    /* if error was generated use it as final error. */
                    overallStatus = PKIX_RevStatus_Revoked;
                    goto cleanup;
                }
                if (pkixErrorResult) {
                    /* Disregard errors. Only returned revStatus matters. */
                    PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult,
                                          plContext);
                    pkixErrorResult = NULL;
                }
            }
            if ((!(revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST) ||
                 onlyUseRemoteMethods) &&
                chainVerificationState &&
                methodStatus[methodNum] == PKIX_RevStatus_NoInfo) {
                if (!(methodFlags & PKIX_REV_M_FORBID_NETWORK_FETCHING)) {
                    PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
                    PKIX_CHECK_NO_GOTO(
                        (*method->externalRevChecker)(cert, issuer, date,
                                                      method,
                                                      procParams, methodFlags,
                                                      &revStatus, pReasonCode,
                                                      &nbioContext, plContext),
                        PKIX_REVCHECKERCHECKFAILED);
                    methodStatus[methodNum] = revStatus;
                    if (revStatus == PKIX_RevStatus_Revoked) {
                        /* if error was generated use it as final error. */
                        overallStatus = PKIX_RevStatus_Revoked;
                        goto cleanup;
                    }
                    if (pkixErrorResult) {
                        /* Disregard errors. Only returned revStatus matters. */
                        PKIX_PL_Object_DecRef((PKIX_PL_Object*)pkixErrorResult,
                                              plContext);
                        pkixErrorResult = NULL;
                    }
                } else if (methodFlags &
                           PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
                    /* Info is not in the local cache. Network fetching is not
                     * allowed. If need to fail on missing fresh info for the
                     * the method, then we should fail right here.*/
                    overallStatus = PKIX_RevStatus_Revoked;
                    goto cleanup;
                }
            }
            /* If success and we should not check the next method, then
             * return a success. */
            if (methodStatus[methodNum] == PKIX_RevStatus_Success &&
                !(methodFlags & PKIX_REV_M_CONTINUE_TESTING_ON_FRESH_INFO)) {
                overallStatus = PKIX_RevStatus_Success;
                goto cleanup;
            }
        } /* inner loop */
        if (!onlyUseRemoteMethods &&
            revFlags & PKIX_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST &&
            chainVerificationState) {
            onlyUseRemoteMethods = PKIX_TRUE;
            continue;
        }
        break;
    } /* outer loop */
    
    if (overallStatus == PKIX_RevStatus_NoInfo &&
        chainVerificationState) {
        /* The following check makes sence only for chain
         * validation step, sinse we do not fetch info while
         * in the process of finding trusted anchor. 
         * For chain building step it is enough to know, that
         * the cert was not directly revoked by any of the
         * methods. */

        /* Still have no info. But one of the method could
         * have returned success status(possible if CONTINUE
         * TESTING ON FRESH INFO flag was used).
         * If any of the methods have returned Success status,
         * the overallStatus should be success. */
        int methodNum = 0;
        for (;methodNum < PKIX_RevocationMethod_MAX;methodNum++) {
            if (methodStatus[methodNum] == PKIX_RevStatus_Success) {
                overallStatus = PKIX_RevStatus_Success;
                goto cleanup;
            }
        }
        if (revFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE) {
            overallStatus = PKIX_RevStatus_Revoked;
        }
    }

cleanup:
    *pRevStatus = overallStatus;
    PKIX_DECREF(method);

    PKIX_RETURN(REVOCATIONCHECKER);
}
static void
Test_BuildResult(
    PKIX_ProcessingParams *procParams,
    PKIX_Boolean testValid,
    PKIX_List *expectedCerts,
    void *plContext)
{
    PKIX_PL_Cert *cert = NULL;
    PKIX_List *certs = NULL;
    PKIX_PL_String *actualCertsString = NULL;
    PKIX_PL_String *expectedCertsString = NULL;
    PKIX_BuildResult *buildResult = NULL;
    PKIX_Boolean result;
    PKIX_Boolean supportForward = PKIX_FALSE;
    PKIX_UInt32 numCerts, i;
    char *asciiResult = NULL;
    char *actualCertsAscii = NULL;
    char *expectedCertsAscii = NULL;
    void *state = NULL;
    PRPollDesc *pollDesc = NULL;

    PKIX_TEST_STD_VARS();

    pkixTestErrorResult = PKIX_BuildChain(procParams,
                                          (void **)&pollDesc,
                                          &state,
                                          &buildResult,
                                          NULL,
                                          plContext);

    while (pollDesc != NULL) {

        if (PR_Poll(pollDesc, 1, 0) < 0) {
            testError("PR_Poll failed");
        }

        pkixTestErrorResult = PKIX_BuildChain(procParams,
                                              (void **)&pollDesc,
                                              &state,
                                              &buildResult,
                                              NULL,
                                              plContext);
    }

    if (pkixTestErrorResult) {
        if (testValid == PKIX_FALSE) { /* EE */
            (void)printf("EXPECTED ERROR RECEIVED!\n");
        } else { /* ENE */
            testError("UNEXPECTED ERROR RECEIVED!\n");
        }
        PKIX_TEST_DECREF_BC(pkixTestErrorResult);
        goto cleanup;
    }

    if (testValid == PKIX_TRUE) { /* ENE */
        (void)printf("EXPECTED NON-ERROR RECEIVED!\n");
    } else { /* EE */
        testError("UNEXPECTED NON-ERROR RECEIVED!\n");
    }

    if (buildResult) {

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_BuildResult_GetCertChain(buildResult, &certs, NULL));

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetLength(certs, &numCerts, plContext));

        printf("\n");

        for (i = 0; i < numCerts; i++) {
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_List_GetItem(certs,
                                                        i,
                                                        (PKIX_PL_Object **)&cert,
                                                        plContext));

            asciiResult = PKIX_Cert2ASCII(cert);

            printf("CERT[%d]:\n%s\n", i, asciiResult);

            /* PKIX_Cert2ASCII used PKIX_PL_Malloc(...,,NULL) */
            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Free(asciiResult, NULL));
            asciiResult = NULL;

            PKIX_TEST_DECREF_BC(cert);
        }

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_Equals((PKIX_PL_Object *)certs,
                                                        (PKIX_PL_Object *)expectedCerts,
                                                        &result,
                                                        plContext));

        if (!result) {
            testError("BUILT CERTCHAIN IS "
                      "NOT THE ONE THAT WAS EXPECTED");

            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString((PKIX_PL_Object *)certs,
                                                              &actualCertsString,
                                                              plContext));

            actualCertsAscii = PKIX_String2ASCII(actualCertsString, plContext);
            if (actualCertsAscii == NULL) {
                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                goto cleanup;
            }

            PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_ToString((PKIX_PL_Object *)expectedCerts,
                                                              &expectedCertsString,
                                                              plContext));

            expectedCertsAscii = PKIX_String2ASCII(expectedCertsString, plContext);
            if (expectedCertsAscii == NULL) {
                pkixTestErrorMsg = "PKIX_String2ASCII Failed";
                goto cleanup;
            }

            (void)printf("Actual value:\t%s\n", actualCertsAscii);
            (void)printf("Expected value:\t%s\n",
                         expectedCertsAscii);
        }
    }

cleanup:

    PKIX_PL_Free(asciiResult, NULL);
    PKIX_PL_Free(actualCertsAscii, plContext);
    PKIX_PL_Free(expectedCertsAscii, plContext);
    PKIX_TEST_DECREF_AC(state);
    PKIX_TEST_DECREF_AC(buildResult);
    PKIX_TEST_DECREF_AC(certs);
    PKIX_TEST_DECREF_AC(cert);
    PKIX_TEST_DECREF_AC(actualCertsString);
    PKIX_TEST_DECREF_AC(expectedCertsString);

    PKIX_TEST_RETURN();
}
/*
 * FUNCTION: pkix_CrlChecker_CheckRemote
 *
 * DESCRIPTION:
 *  Check if the Cert has been revoked based the CRLs data.  This function
 *  maintains the checker state to be current.
 *
 * PARAMETERS
 *  "checker"
 *      Address of CertChainChecker which has the state data.
 *      Must be non-NULL.
 *  "cert"
 *      Address of Certificate that is to be validated. Must be non-NULL.
 *  "unreslvdCrtExts"
 *      A List OIDs. Not **yet** used in this checker function.
 *  "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 CertChainChecker Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error
 */
PKIX_Error *
pkix_CrlChecker_CheckExternal(
        PKIX_PL_Cert *cert,
        PKIX_PL_Cert *issuer,
        PKIX_PL_Date *date,
        pkix_RevocationMethod *checkerObject,
        PKIX_ProcessingParams *procParams,
        PKIX_UInt32 methodFlags,
        PKIX_RevocationStatus *pRevStatus,
        PKIX_UInt32 *pReasonCode,
        void **pNBIOContext,
        void *plContext)
{
    PKIX_CertStore_CheckRevokationByCrlCallback storeCheckRevocationFn = NULL;
    PKIX_CertStore_ImportCrlCallback storeImportCrlFn = NULL;
    PKIX_RevocationStatus revStatus = PKIX_RevStatus_NoInfo;
    PKIX_CertStore *certStore = NULL;
    PKIX_CertStore *localStore = NULL;
    PKIX_CRLSelector *crlSelector = NULL;
    PKIX_PL_X500Name *issuerName = NULL;
    pkix_CrlChecker *state = NULL; 
    PKIX_UInt32 reasonCode = 0;
    PKIX_UInt32 crlStoreIndex = 0;
    PKIX_UInt32 numCrlStores = 0;
    PKIX_Boolean storeIsLocal = PKIX_FALSE;
    PKIX_List *crlList = NULL;
    PKIX_List *dpList = NULL;
    void *nbioContext = NULL;

    PKIX_ENTER(CERTCHAINCHECKER, "pkix_CrlChecker_CheckExternal");
    PKIX_NULLCHECK_FOUR(cert, issuer, checkerObject, pNBIOContext);
    
    nbioContext = *pNBIOContext;
    *pNBIOContext = NULL; /* prepare for Error exit */

    state = (pkix_CrlChecker*)checkerObject;
    
    PKIX_CHECK(
        PKIX_List_GetLength(state->certStores, &numCrlStores, plContext),
        PKIX_LISTGETLENGTHFAILED);

    /* Find a cert store that is capable of storing crls */
    for (;crlStoreIndex < numCrlStores;crlStoreIndex++) {
        PKIX_CHECK(
            PKIX_List_GetItem(state->certStores, crlStoreIndex,
                              (PKIX_PL_Object **)&certStore,
                              plContext),
            PKIX_LISTGETITEMFAILED);
        
        PKIX_CHECK(
            PKIX_CertStore_GetLocalFlag(certStore, &storeIsLocal,
                                        plContext),
            PKIX_CERTSTOREGETLOCALFLAGFAILED);
        if (storeIsLocal) {
            PKIX_CHECK(
                PKIX_CertStore_GetImportCrlCallback(certStore,
                                                    &storeImportCrlFn,
                                                    plContext),
                PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);
            
            PKIX_CHECK(
                PKIX_CertStore_GetCrlCheckerFn(certStore,
                                               &storeCheckRevocationFn,
                                               plContext),
                PKIX_CERTSTOREGETCHECKREVBYCRLFAILED);
            
            if (storeImportCrlFn && storeCheckRevocationFn) {
                localStore = certStore;
                certStore = NULL;
                break;
            }
        }
        PKIX_DECREF(certStore);
    } /* while */

    /* Report unknown status if we can not check crl in one of the
     * local stores. */
    if (!localStore) {
        PKIX_ERROR_FATAL(PKIX_CRLCHECKERNOLOCALCERTSTOREFOUND);
    }
    PKIX_CHECK(
        PKIX_PL_Cert_VerifyKeyUsage(issuer, PKIX_CRL_SIGN, plContext),
        PKIX_CERTCHECKKEYUSAGEFAILED);
    PKIX_CHECK(
        PKIX_PL_Cert_GetCrlDp(cert, &dpList, plContext),
        PKIX_CERTGETCRLDPFAILED);
    if (!(methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE) &&
        (!dpList || !dpList->length)) {
        goto cleanup;
    }
    PKIX_CHECK(
        PKIX_PL_Cert_GetIssuer(cert, &issuerName, plContext),
        PKIX_CERTGETISSUERFAILED);
    PKIX_CHECK(
        PKIX_CRLSelector_Create(issuer, dpList, date, &crlSelector, plContext),
        PKIX_CRLCHECKERSETSELECTORFAILED);
    /* Fetch crl and store in a local cert store */
    for (crlStoreIndex = 0;crlStoreIndex < numCrlStores;crlStoreIndex++) {
        PKIX_CertStore_CRLCallback getCrlsFn;

        PKIX_CHECK(
            PKIX_List_GetItem(state->certStores, crlStoreIndex,
                              (PKIX_PL_Object **)&certStore,
                              plContext),
            PKIX_LISTGETITEMFAILED);
        
        PKIX_CHECK(
            PKIX_CertStore_GetCRLCallback(certStore, &getCrlsFn,
                                          plContext),
            PKIX_CERTSTOREGETCRLCALLBACKFAILED);
        
        PKIX_CHECK(
            (*getCrlsFn)(certStore, crlSelector, &nbioContext,
                      &crlList, plContext),
            PKIX_GETCRLSFAILED);

        PKIX_CHECK(
            (*storeImportCrlFn)(localStore, issuerName, crlList, plContext),
            PKIX_CERTSTOREFAILTOIMPORTCRLLIST);
        
        PKIX_CHECK(
            (*storeCheckRevocationFn)(certStore, cert, issuer, date,
                                      /* done with crl downloading */
                                      PKIX_TRUE,
                                      &reasonCode, &revStatus, plContext),
            PKIX_CERTSTORECRLCHECKFAILED);
        if (revStatus != PKIX_RevStatus_NoInfo) {
            break;
        }
        PKIX_DECREF(crlList);
        PKIX_DECREF(certStore);
    } /* while */

cleanup:
    /* Update return flags */
    if (revStatus == PKIX_RevStatus_NoInfo && 
	((dpList && dpList->length > 0) ||
	 (methodFlags & PKIX_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE)) &&
        methodFlags & PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO) {
        revStatus = PKIX_RevStatus_Revoked;
    }
    *pRevStatus = revStatus;

    PKIX_DECREF(dpList);
    PKIX_DECREF(crlList);
    PKIX_DECREF(certStore);
    PKIX_DECREF(issuerName);
    PKIX_DECREF(localStore);
    PKIX_DECREF(crlSelector);

    PKIX_RETURN(CERTCHAINCHECKER);
}
/*
 * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCert
 * DESCRIPTION:
 *
 *  Finds the Certs that match the criterion of the CertSelector pointed
 *  to by "selector" using the List of Certs pointed to by "certList" and
 *  stores the matching Certs at "pSelectedCertList".
 *
 *  Not recursive to sub-directory.
 *
 * PARAMETERS
 *  "certList" - Address of List of Certs to be searched. Must be non-NULL.
 *  "colCertStoreContext" - Address of CollectionCertStoreContext
 *              where the cached Certs are stored.
 *  "selector" - CertSelector for chosing Cert based on Params set
 *  "pSelectedCertList" - Certs that qualified by selector.
 *  "plContext" - Platform-specific context pointer.
 *
 * THREAD SAFETY:
 *  Not Thread Safe - A lock at top level is required.
 *
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a CollectionCertStoreContext 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_pl_CollectionCertStoreContext_GetSelectedCert(
        PKIX_List *certList,
        PKIX_CertSelector *selector,
        PKIX_List **pSelectedCertList,
        void *plContext)
{
        PKIX_List *selectCertList = NULL;
        PKIX_PL_Cert *certItem = NULL;
        PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
        PKIX_UInt32 numCerts = 0;
        PKIX_UInt32 i = 0;

        PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
                    "pkix_pl_CollectionCertStoreContext_GetSelectedCert");
        PKIX_NULLCHECK_THREE(certList, selector, pSelectedCertList);

        PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
                    (selector, &certSelectorMatch, plContext),
                    PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);

        PKIX_CHECK(PKIX_List_GetLength(certList, &numCerts, plContext),
                    PKIX_LISTGETLENGTHFAILED);

        if (certSelectorMatch) {

                PKIX_CHECK(PKIX_List_Create(&selectCertList, plContext),
                            PKIX_LISTCREATEFAILED);

                for (i = 0; i < numCerts; i++) {
                        PKIX_CHECK_ONLY_FATAL
                                (PKIX_List_GetItem
                                (certList,
                                i,
                                (PKIX_PL_Object **) &certItem,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                        if (!PKIX_ERROR_RECEIVED){
                                PKIX_CHECK_ONLY_FATAL
                                        (certSelectorMatch
                                        (selector, certItem, plContext),
                                        PKIX_CERTSELECTORMATCHFAILED);

                                if (!PKIX_ERROR_RECEIVED){
                                        PKIX_CHECK_ONLY_FATAL
                                                (PKIX_List_AppendItem
                                                (selectCertList,
                                                (PKIX_PL_Object *)certItem,
                                                plContext),
                                                PKIX_LISTAPPENDITEMFAILED);
                                }
                        }

                        PKIX_DECREF(certItem);
                }

        } else {

                PKIX_INCREF(certList);

                selectCertList = certList;
        }

        *pSelectedCertList = selectCertList;

cleanup:
        PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
}