Exemple #1
0
/*
 * FUNCTION: pkix_pl_Date_CreateFromPRTime
 * DESCRIPTION:
 *
 *  Creates a new Date from the PRTime whose value is "prtime", and stores the
 *  result at "pDate".
 *
 * PARAMETERS
 *  "prtime"
 *      The PRTime value to be embodied in the new Date object.
 *  "pDate"
 *      Address where object pointer will be stored. Must be non-NULL.
 *  "plContext" - Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a Date 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_Date_CreateFromPRTime(
        PRTime prtime,
        PKIX_PL_Date **pDate,
        void *plContext)
{
        PKIX_PL_Date *date = NULL;

        PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime");
        PKIX_NULLCHECK_ONE(pDate);

        /* create a PKIX_PL_Date object */
        PKIX_CHECK(PKIX_PL_Object_Alloc
                    (PKIX_DATE_TYPE,
                    sizeof (PKIX_PL_Date),
                    (PKIX_PL_Object **)&date,
                    plContext),
                    PKIX_COULDNOTCREATEOBJECT);
        /* populate the nssTime field */
        date->nssTime = prtime;
        *pDate = date;
cleanup:
        PKIX_RETURN(DATE);
}
/*
 * FUNCTION: pkix_pl_CertBasicConstraints_Destroy
 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_pl_CertBasicConstraints_Destroy(
        PKIX_PL_Object *object,
        void *plContext)
{
        PKIX_PL_CertBasicConstraints *certB = NULL;

        PKIX_ENTER(CERTBASICCONSTRAINTS,
                "pkix_pl_CertBasicConstraints_Destroy");
        PKIX_NULLCHECK_ONE(object);

        PKIX_CHECK(pkix_CheckType
                    (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext),
                    PKIX_OBJECTNOTCERTBASICCONSTRAINTS);

        certB = (PKIX_PL_CertBasicConstraints*)object;

        certB->isCA = PKIX_FALSE;
        certB->pathLen = 0;

cleanup:

        PKIX_RETURN(CERTBASICCONSTRAINTS);
}
/*
 * FUNCTION: pkix_pl_OcspCertID_Destroy
 * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_pl_OcspCertID_Destroy(
        PKIX_PL_Object *object,
        void *plContext)
{
        PKIX_PL_OcspCertID *certID = NULL;

        PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_Destroy");

        PKIX_NULLCHECK_ONE(object);

        PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPCERTID_TYPE, plContext),
                    PKIX_OBJECTNOTOCSPCERTID);

        certID = (PKIX_PL_OcspCertID *)object;

        if (certID->certID) {
                CERT_DestroyOCSPCertID(certID->certID);
        }

cleanup:

        PKIX_RETURN(OCSPCERTID);
}
/*
 * FUNCTION: PKIX_ValidateParams_Create (see comments in pkix_params.h)
 */
PKIX_Error *
PKIX_ValidateParams_Create(
        PKIX_ProcessingParams *procParams,
        PKIX_List *chain,
        PKIX_ValidateParams **pParams,
        void *plContext)
{
        PKIX_ValidateParams *params = NULL;

        PKIX_ENTER(VALIDATEPARAMS, "PKIX_ValidateParams_Create");
        PKIX_NULLCHECK_THREE(procParams, chain, pParams);

        PKIX_CHECK(PKIX_PL_Object_Alloc
                    (PKIX_VALIDATEPARAMS_TYPE,
                    sizeof (PKIX_ValidateParams),
                    (PKIX_PL_Object **)&params,
                    plContext),
                    PKIX_COULDNOTCREATEVALIDATEPARAMSOBJECT);

        /* initialize fields */
        PKIX_INCREF(procParams);
        params->procParams = procParams;

        PKIX_INCREF(chain);
        params->chain = chain;

        *pParams = params;
        params = NULL;

cleanup:

        PKIX_DECREF(params);

        PKIX_RETURN(VALIDATEPARAMS);

}
/*
 * 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_TrustAnchor_ToString
 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_TrustAnchor_ToString(
        PKIX_PL_Object *object,
        PKIX_PL_String **pString,
        void *plContext)
{
        PKIX_TrustAnchor *anchor = NULL;
        char *asciiFormat = NULL;
        PKIX_PL_String *formatString = NULL;
        PKIX_PL_String *anchorString = NULL;
        PKIX_PL_String *certString = NULL;
        PKIX_PL_String *nameString = NULL;
        PKIX_PL_String *pubKeyString = NULL;
        PKIX_PL_String *nameConstraintsString = NULL;

        PKIX_ENTER(TRUSTANCHOR, "pkix_TrustAnchor_ToString");
        PKIX_NULLCHECK_TWO(object, pString);

        PKIX_CHECK(pkix_CheckType(object, PKIX_TRUSTANCHOR_TYPE, plContext),
                    PKIX_OBJECTNOTTRUSTANCHOR);

        anchor = (PKIX_TrustAnchor*)object;

        if (anchor->trustedCert){
                asciiFormat =
                        "[\n"
                        "\tTrusted Cert:	%s\n"
                        "]\n";

                PKIX_CHECK(PKIX_PL_String_Create
                            (PKIX_ESCASCII,
                            asciiFormat,
                            0,
                            &formatString,
                            plContext),
                            PKIX_STRINGCREATEFAILED);

                PKIX_CHECK(PKIX_PL_Object_ToString
                            ((PKIX_PL_Object *)anchor->trustedCert,
                            &certString,
                            plContext),
                            PKIX_OBJECTTOSTRINGFAILED);

                PKIX_CHECK(PKIX_PL_Sprintf
                            (&anchorString,
                            plContext,
                            formatString,
                            certString),
                            PKIX_SPRINTFFAILED);
        } else {
                asciiFormat =
                        "[\n"
                        "\tTrusted CA Name:         %s\n"
                        "\tTrusted CA PublicKey:    %s\n"
                        "\tInitial Name Constraints:%s\n"
                        "]\n";

                PKIX_CHECK(PKIX_PL_String_Create
                            (PKIX_ESCASCII,
                            asciiFormat,
                            0,
                            &formatString,
                            plContext),
                            PKIX_STRINGCREATEFAILED);

                PKIX_CHECK(PKIX_PL_Object_ToString
                            ((PKIX_PL_Object *)anchor->caName,
                            &nameString,
                            plContext),
                            PKIX_OBJECTTOSTRINGFAILED);

                PKIX_CHECK(PKIX_PL_Object_ToString
                            ((PKIX_PL_Object *)anchor->caPubKey,
                            &pubKeyString,
                            plContext),
                            PKIX_OBJECTTOSTRINGFAILED);

                PKIX_TOSTRING
                        (anchor->nameConstraints,
                        &nameConstraintsString,
                        plContext,
                        PKIX_OBJECTTOSTRINGFAILED);

                PKIX_CHECK(PKIX_PL_Sprintf
                            (&anchorString,
                            plContext,
                            formatString,
                            nameString,
                            pubKeyString,
                            nameConstraintsString),
                            PKIX_SPRINTFFAILED);
        }

        *pString = anchorString;

cleanup:

        PKIX_DECREF(formatString);
        PKIX_DECREF(certString);
        PKIX_DECREF(nameString);
        PKIX_DECREF(pubKeyString);
        PKIX_DECREF(nameConstraintsString);

        PKIX_RETURN(TRUSTANCHOR);
}
Exemple #7
0
/*
 * FUNCTION: pkix_Error_ToString
 * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_Error_ToString(
        PKIX_PL_Object *object,
        PKIX_PL_String **pString,
        void *plContext)
{
        PKIX_Error *error = NULL;
        PKIX_Error *cause = NULL;
        PKIX_PL_String *desc = NULL;
        PKIX_PL_String *formatString = NULL;
        PKIX_PL_String *causeString = NULL;
        PKIX_PL_String *optCauseString = NULL;
        PKIX_PL_String *errorNameString = NULL;
        char *format = NULL;
        PKIX_ERRORCLASS errClass;

        PKIX_ENTER(ERROR, "pkix_Error_ToString");
        PKIX_NULLCHECK_TWO(object, pString);

        PKIX_CHECK(pkix_CheckType(object, PKIX_ERROR_TYPE, plContext),
                PKIX_OBJECTNOTANERROR);

        error = (PKIX_Error *)object;

        /* Get this error's errClass, description and the string of its cause */
        errClass = error->errClass;

        /* Get the description string */
        PKIX_Error_GetDescription(error, &desc, plContext);
            
        /* Get the cause */
        cause = error->cause;

        /* Get the causes's description string */
        if (cause != NULL) {
                pkix_error_cause_depth++;

                /* Get the cause string */
                PKIX_CHECK(PKIX_PL_Object_ToString
                            ((PKIX_PL_Object*)cause, &causeString, plContext),
                            PKIX_ERRORGETTINGCAUSESTRING);

                format = "\n*** Cause (%d): %s";

                PKIX_CHECK(PKIX_PL_String_Create
                            (PKIX_ESCASCII,
                            format,
                            0,
                            &formatString,
                            plContext),
                            PKIX_STRINGCREATEFAILED);

                /* Create the optional Cause String */
                PKIX_CHECK(PKIX_PL_Sprintf
                            (&optCauseString,
                            plContext,
                            formatString,
                            pkix_error_cause_depth,
                            causeString),
                            PKIX_SPRINTFFAILED);

                PKIX_DECREF(formatString);

                pkix_error_cause_depth--;
        }

        /* Create the Format String */
        if (optCauseString != NULL) {
                format = "*** %s Error- %s%s";
        } else {
                format = "*** %s Error- %s";
        }

        /* Ensure that error errClass is known, otherwise default to Object */
        if (errClass >= PKIX_NUMERRORCLASSES) {
                errClass = 0;
        }

        PKIX_CHECK(PKIX_PL_String_Create
                    (PKIX_ESCASCII,
                    (void *)PKIX_ERRORCLASSNAMES[errClass],
                    0,
                    &errorNameString,
                    plContext),
                    PKIX_STRINGCREATEFAILED);

        PKIX_CHECK(PKIX_PL_String_Create
                    (PKIX_ESCASCII,
                    format,
                    0,
                    &formatString,
                    plContext),
                    PKIX_STRINGCREATEFAILED);

        /* Create the output String */
        PKIX_CHECK(PKIX_PL_Sprintf
                    (pString,
                    plContext,
                    formatString,
                    errorNameString,
                    desc,
                    optCauseString),
                    PKIX_SPRINTFFAILED);

cleanup:

        PKIX_DECREF(desc);
        PKIX_DECREF(causeString);
        PKIX_DECREF(formatString);
        PKIX_DECREF(optCauseString);
        PKIX_DECREF(errorNameString);

        PKIX_RETURN(ERROR);
}
/*
 * FUNCTION: PKIX_RevocationChecker_CreateAndAddMethod
 */
PKIX_Error *
PKIX_RevocationChecker_CreateAndAddMethod(
    PKIX_RevocationChecker *revChecker,
    PKIX_ProcessingParams *params,
    PKIX_RevocationMethodType methodType,
    PKIX_UInt32 flags,
    PKIX_UInt32 priority,
    PKIX_PL_VerifyCallback verificationFn,
    PKIX_Boolean isLeafMethod,
    void *plContext)
{
    PKIX_List **methodList = NULL;
    PKIX_List  *unsortedList = NULL;
    PKIX_List  *certStores = NULL;
    pkix_RevocationMethod *method = NULL;
    pkix_LocalRevocationCheckFn *localRevChecker = NULL;
    pkix_ExternalRevocationCheckFn *externRevChecker = NULL;
    PKIX_UInt32 miFlags;
    
    PKIX_ENTER(REVOCATIONCHECKER, "PKIX_RevocationChecker_CreateAndAddMethod");
    PKIX_NULLCHECK_ONE(revChecker);

    /* If the caller has said "Either one is sufficient, then don't let the 
     * absence of any one method's info lead to an overall failure.
     */
    miFlags = isLeafMethod ? revChecker->leafMethodListFlags 
	                   : revChecker->chainMethodListFlags;
    if (miFlags & PKIX_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE)
	flags &= ~PKIX_REV_M_FAIL_ON_MISSING_FRESH_INFO;

    switch (methodType) {
    case PKIX_RevocationMethod_CRL:
        localRevChecker = pkix_CrlChecker_CheckLocal;
        externRevChecker = pkix_CrlChecker_CheckExternal;
        PKIX_CHECK(
            PKIX_ProcessingParams_GetCertStores(params, &certStores,
                                                plContext),
            PKIX_PROCESSINGPARAMSGETCERTSTORESFAILED);
        PKIX_CHECK(
            pkix_CrlChecker_Create(methodType, flags, priority,
                                   localRevChecker, externRevChecker,
                                   certStores, verificationFn,
                                   &method,
                                   plContext),
            PKIX_COULDNOTCREATECRLCHECKEROBJECT);
        break;
    case PKIX_RevocationMethod_OCSP:
        localRevChecker = pkix_OcspChecker_CheckLocal;
        externRevChecker = pkix_OcspChecker_CheckExternal;
        PKIX_CHECK(
            pkix_OcspChecker_Create(methodType, flags, priority,
                                    localRevChecker, externRevChecker,
                                    verificationFn,
                                    &method,
                                    plContext),
            PKIX_COULDNOTCREATEOCSPCHECKEROBJECT);
        break;
    default:
        PKIX_ERROR(PKIX_INVALIDREVOCATIONMETHOD);
    }

    if (isLeafMethod) {
        methodList = &revChecker->leafMethodList;
    } else {
        methodList = &revChecker->chainMethodList;
    }
    
    if (*methodList == NULL) {
        PKIX_CHECK(
            PKIX_List_Create(methodList, plContext),
            PKIX_LISTCREATEFAILED);
    }
    unsortedList = *methodList;
    PKIX_CHECK(
        PKIX_List_AppendItem(unsortedList, (PKIX_PL_Object*)method, plContext),
        PKIX_LISTAPPENDITEMFAILED);
    PKIX_CHECK(
        pkix_List_BubbleSort(unsortedList, 
                             pkix_RevocationChecker_SortComparator,
                             methodList, plContext),
        PKIX_LISTBUBBLESORTFAILED);

cleanup:
    PKIX_DECREF(method);
    PKIX_DECREF(unsortedList);
    PKIX_DECREF(certStores);
    
    PKIX_RETURN(REVOCATIONCHECKER);
}
/*
 * 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_VerifyNode_ToString_Helper
 * DESCRIPTION:
 *
 *  Produces a String representation of a VerifyNode tree below the VerifyNode
 *  pointed to by "rootNode", with each line of output prefixed by the String
 *  pointed to by "indent", and stores the result at "pTreeString". It is
 *  called recursively, with ever-increasing indentation, for successively
 *  lower nodes on the tree.
 *
 * PARAMETERS:
 *  "rootNode"
 *      Address of VerifyNode subtree. Must be non-NULL.
 *  "indent"
 *      Address of String to be prefixed to each line of output. May be NULL
 *      if no indentation is desired
 *  "pTreeString"
 *      Address where the resulting String will be stored; must be non-NULL
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Conditionally Thread Safe
 *  (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a VerifyNode Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in an unrecoverable way.
 */
static PKIX_Error *
pkix_VerifyNode_ToString_Helper(
        PKIX_VerifyNode *rootNode,
        PKIX_PL_String *indent,
        PKIX_PL_String **pTreeString,
        void *plContext)
{
        PKIX_PL_String *nextIndentFormat = NULL;
        PKIX_PL_String *thisNodeFormat = NULL;
        PKIX_PL_String *childrenFormat = NULL;
        PKIX_PL_String *nextIndentString = NULL;
        PKIX_PL_String *resultString = NULL;
        PKIX_PL_String *thisItemString = NULL;
        PKIX_PL_String *childString = NULL;
        PKIX_VerifyNode *childNode = NULL;
        PKIX_UInt32 numberOfChildren = 0;
        PKIX_UInt32 childIndex = 0;

        PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_ToString_Helper");

        PKIX_NULLCHECK_TWO(rootNode, pTreeString);

        /* Create a string for this node */
        PKIX_CHECK(pkix_SingleVerifyNode_ToString
                (rootNode, &thisItemString, plContext),
                PKIX_ERRORINSINGLEVERIFYNODETOSTRING);

        if (indent) {
                PKIX_CHECK(PKIX_PL_String_Create
                        (PKIX_ESCASCII,
                        "%s%s",
                        0,
                        &thisNodeFormat,
                        plContext),
                        PKIX_ERRORCREATINGFORMATSTRING);

                PKIX_CHECK(PKIX_PL_Sprintf
                        (&resultString,
                        plContext,
                        thisNodeFormat,
                        indent,
                        thisItemString),
                        PKIX_ERRORINSPRINTF);
        } else {
                PKIX_CHECK(PKIX_PL_String_Create
                        (PKIX_ESCASCII,
                        "%s",
                        0,
                        &thisNodeFormat,
                        plContext),
                        PKIX_ERRORCREATINGFORMATSTRING);

                PKIX_CHECK(PKIX_PL_Sprintf
                        (&resultString,
                        plContext,
                        thisNodeFormat,
                        thisItemString),
                        PKIX_ERRORINSPRINTF);
        }

        PKIX_DECREF(thisItemString);
        thisItemString = resultString;

        /* if no children, we are done */
        if (rootNode->children) {
                PKIX_CHECK(PKIX_List_GetLength
                        (rootNode->children, &numberOfChildren, plContext),
                        PKIX_LISTGETLENGTHFAILED);
        }

        if (numberOfChildren != 0) {
                /*
                 * We create a string for each child in turn,
                 * concatenating them to thisItemString.
                 */

                /* Prepare an indent string for each child */
                if (indent) {
                        PKIX_CHECK(PKIX_PL_String_Create
                                (PKIX_ESCASCII,
                                "%s. ",
                                0,
                                &nextIndentFormat,
                                plContext),
                                PKIX_ERRORCREATINGFORMATSTRING);

                        PKIX_CHECK(PKIX_PL_Sprintf
                                (&nextIndentString,
                                plContext,
                                nextIndentFormat,
                                indent),
                                PKIX_ERRORINSPRINTF);
                } else {
                        PKIX_CHECK(PKIX_PL_String_Create
                                (PKIX_ESCASCII,
                                ". ",
                                0,
                                &nextIndentString,
                                plContext),
                                PKIX_ERRORCREATINGINDENTSTRING);
                }

                /* Prepare the format for concatenation. */
                PKIX_CHECK(PKIX_PL_String_Create
                        (PKIX_ESCASCII,
                        "%s\n%s",
                        0,
                        &childrenFormat,
                        plContext),
                        PKIX_ERRORCREATINGFORMATSTRING);

                for (childIndex = 0;
                        childIndex < numberOfChildren;
                        childIndex++) {
                        PKIX_CHECK(PKIX_List_GetItem
                                (rootNode->children,
                                childIndex,
                                (PKIX_PL_Object **)&childNode,
                                plContext),
                                PKIX_LISTGETITEMFAILED);

                        PKIX_CHECK(pkix_VerifyNode_ToString_Helper
                                (childNode,
                                nextIndentString,
                                &childString,
                                plContext),
                                PKIX_ERRORCREATINGCHILDSTRING);


                        PKIX_CHECK(PKIX_PL_Sprintf
                                (&resultString,
                                plContext,
                                childrenFormat,
                                thisItemString,
                                childString),
                        PKIX_ERRORINSPRINTF);

                        PKIX_DECREF(childNode);
                        PKIX_DECREF(childString);
                        PKIX_DECREF(thisItemString);

                        thisItemString = resultString;
                }
        }

        *pTreeString = thisItemString;

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

        PKIX_DECREF(nextIndentFormat);
        PKIX_DECREF(thisNodeFormat);
        PKIX_DECREF(childrenFormat);
        PKIX_DECREF(nextIndentString);
        PKIX_DECREF(childString);
        PKIX_DECREF(childNode);

        PKIX_RETURN(VERIFYNODE);
}
/*
 * FUNCTION: pkix_pl_PrimHashTable_Remove
 * DESCRIPTION:
 *
 *  Removes any objects with the key pointed to by "key" and hashCode value
 *  equal to "hashCode" from the PrimHashtable pointed to by "ht", using the
 *  function pointed to by "keyComp" to compare keys, and stores the object's
 *  value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object.
 *  This function sets "pResult" to NULL if the key is not in the hashtable.
 *
 * PARAMETERS:
 *  "ht"
 *      Address of PrimHashtable to remove object. Must be non-NULL.
 *  "key"
 *      Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object.
 *      Must be non-NULL.
 *  "value"
 *      Address of Object to be added to PrimHashtable. Must be non-NULL.
 *  "hashCode"
 *      Hashcode value of the key.
 *  "keyComp"
 *      Address of function used to determine if two keys are equal.
 *      If NULL, pkix_pl_KeyComparator_Default is used.
 *  "pResult"
 *      Address where value will be stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Not Thread Safe - assumes exclusive access to "ht"
 *  (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a HashTable 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_PrimHashTable_Remove(
        pkix_pl_PrimHashTable *ht,
        void *key,
        PKIX_UInt32 hashCode,
        PKIX_PL_EqualsCallback keyComp,
        void **pKey,
        void **pValue,
        void *plContext)
{
        pkix_pl_HT_Elem *element = NULL;
        pkix_pl_HT_Elem *prior = NULL;
        PKIX_Boolean compResult;

        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove");
        PKIX_NULLCHECK_FOUR(ht, key, pKey, pValue);

        *pKey = NULL;
        *pValue = NULL;

        for (element = ht->buckets[hashCode%ht->size], prior = element;
            (element != NULL);
            prior = element, element = element->next) {

                if (element->hashCode != hashCode){
                        /* no possibility of a match */
                        continue;
                }

                if (keyComp == NULL){
                        PKIX_CHECK(pkix_pl_KeyComparator_Default
                                ((PKIX_UInt32 *)key,
                                (PKIX_UInt32 *)(element->key),
                                &compResult,
                                plContext),
                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
                } else {
                        PKIX_CHECK(keyComp
                                ((PKIX_PL_Object *)key,
                                (PKIX_PL_Object *)(element->key),
                                &compResult,
                                plContext),
                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
                }

                if ((element->hashCode == hashCode) &&
                    (compResult == PKIX_TRUE)){
                        if (element != prior) {
                                prior->next = element->next;
                        } else {
                                ht->buckets[hashCode%ht->size] = element->next;
                        }
                        *pKey = element->key;
                        *pValue = element->value;
                        element->key = NULL;
                        element->value = NULL;
                        element->next = NULL;
                        PKIX_FREE(element);
                        goto cleanup;
                }
        }

cleanup:

        PKIX_RETURN(HASHTABLE);
}
/*
 * FUNCTION: pkix_pl_PrimHashTable_Add
 * DESCRIPTION:
 *
 *  Adds the value pointed to by "value" to the PrimHashTable pointed to by
 *  "ht" using the key pointed to by "key" and the hashCode value equal to
 *  "hashCode", using the function pointed to by "keyComp" to compare keys.
 *  Assumes the key is either a PKIX_UInt32 or a PKIX_PL_Object. If the value
 *  already exists in the hashtable, this function returns a non-fatal error.
 *
 * PARAMETERS:
 *  "ht"
 *      Address of PrimHashtable to insert into. Must be non-NULL.
 *  "key"
 *      Address of key. Typically a PKIX_UInt32 or PKIX_PL_Object.
 *      Must be non-NULL.
 *  "value"
 *      Address of Object to be added to PrimHashtable. Must be non-NULL.
 *  "hashCode"
 *      Hashcode value of the key.
 *  "keyComp"
 *      Address of function used to determine if two keys are equal.
 *      If NULL, pkix_pl_KeyComparator_Default is used.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Not Thread Safe - assumes exclusive access to "ht"
 *  (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a HashTable 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_PrimHashTable_Add(
        pkix_pl_PrimHashTable *ht,
        void *key,
        void *value,
        PKIX_UInt32 hashCode,
        PKIX_PL_EqualsCallback keyComp,
        void *plContext)
{
        pkix_pl_HT_Elem **elemPtr = NULL;
        pkix_pl_HT_Elem *element = NULL;
        PKIX_Boolean compResult = PKIX_FALSE;

        PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Add");
        PKIX_NULLCHECK_THREE(ht, key, value);

        for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr;
            element != NULL; elemPtr = &(element->next), element = *elemPtr) {

                if (element->hashCode != hashCode){
                        /* no possibility of a match */
                        continue;
                }

                if (keyComp == NULL){
                        PKIX_CHECK(pkix_pl_KeyComparator_Default
                                ((PKIX_UInt32 *)key,
                                (PKIX_UInt32 *)(element->key),
                                &compResult,
                                plContext),
                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
                } else {
                        PKIX_CHECK(keyComp
                                ((PKIX_PL_Object *)key,
                                (PKIX_PL_Object *)(element->key),
                                &compResult,
                                plContext),
                                PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
                }

                if ((element->hashCode == hashCode) &&
                    (compResult == PKIX_TRUE)){
                        /* Same key already exists in the table */
                    PKIX_ERROR(PKIX_ATTEMPTTOADDDUPLICATEKEY);
                }
        }

        /* Next Element should be NULL at this point */
        if (element != NULL) {
                PKIX_ERROR(PKIX_ERRORTRAVERSINGBUCKET);
        }

        /* Create a new HT_Elem */
        PKIX_CHECK(PKIX_PL_Malloc
                    (sizeof (pkix_pl_HT_Elem), (void **)elemPtr, plContext),
                    PKIX_MALLOCFAILED);

        element = *elemPtr;

        element->key = key;
        element->value = value;
        element->hashCode = hashCode;
        element->next = NULL;

cleanup:

        PKIX_RETURN(HASHTABLE);
}
/*
 * FUNCTION: pkix_EscASCII_to_UTF16
 * DESCRIPTION:
 *
 *  Converts array of bytes pointed to by "escAsciiString" with length of
 *  "escAsciiLength" into a freshly allocated UTF-16 string and stores a
 *  pointer to that string at "pDest" and stores the string's length at
 *  "pLength". The caller is responsible for freeing "pDest" using
 *  PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug encoding.
 *
 * PARAMETERS:
 *  "escAsciiString"
 *      Address of array of bytes representing data source. Must be non-NULL.
 *  "escAsciiLength"
 *      Length of data source. Must be even.
 *  "debug"
 *      Boolean value indicating whether debug mode is desired.
 *  "pDest"
 *      Address where data will be stored. Must be non-NULL.
 *  "pLength"
 *      Address where data length will be stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a String 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_EscASCII_to_UTF16(
        const char *escAsciiString,
        PKIX_UInt32 escAsciiLen,
        PKIX_Boolean debug,
        void **pDest,
        PKIX_UInt32 *pLength,
        void *plContext)
{
        PKIX_UInt32 newLen, i, j, charSize;
        PKIX_UInt32 x = 0, y = 0, z = 0;
        unsigned char *destPtr = NULL;
        unsigned char testChar, testChar2;
        unsigned char *stringData = (unsigned char *)escAsciiString;

        PKIX_ENTER(STRING, "pkix_EscASCII_to_UTF16");
        PKIX_NULLCHECK_THREE(escAsciiString, pDest, pLength);

        if (escAsciiLen == 0) {
                PKIX_CHECK(PKIX_PL_Malloc(escAsciiLen, pDest, plContext),
                            PKIX_MALLOCFAILED);
                goto cleanup;
        }

        /* Assume each unicode character takes two bytes */
        newLen = escAsciiLen*2;

        /* Count up number of unicode encoded  characters */
        for (i = 0; i < escAsciiLen; i++) {
                if (!pkix_isPlaintext(stringData[i], debug)&&
                    (stringData[i] != '&')) {
                        PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
                } else if (PL_strstr(escAsciiString+i, "&amp;") ==
                            escAsciiString+i) {
                        /* Convert EscAscii "&amp;" to two bytes */
                        newLen -= 8;
                        i += 4;
                } else if ((PL_strstr(escAsciiString+i, "&#x") ==
                            escAsciiString+i)||
                            (PL_strstr(escAsciiString+i, "&#X") ==
                            escAsciiString+i)) {
                        if (((i+7) <= escAsciiLen)&&
                            (escAsciiString[i+7] == ';')) {
                                /* Convert &#xNNNN; to two bytes */
                                newLen -= 14;
                                i += 7;
                        } else if (((i+11) <= escAsciiLen)&&
                                (escAsciiString[i+11] == ';')) {
                                /* Convert &#xNNNNNNNN; to four bytes */
                                newLen -= 20;
                                i += 11;
                        } else {
                                PKIX_ERROR(PKIX_ILLEGALUSEOFAMP);
                        }
                }
        }

        PKIX_CHECK(PKIX_PL_Malloc(newLen, pDest, plContext),
                    PKIX_MALLOCFAILED);

        /* Copy into newly allocated space */
        destPtr = (unsigned char *)*pDest;

        i = 0;
        while (i < escAsciiLen) {
                /* Copy each byte until you hit a &amp; */
                if (pkix_isPlaintext(escAsciiString[i], debug)) {
                        *destPtr++ = 0x00;
                        *destPtr++ = escAsciiString[i++];
                } else if (PL_strstr(escAsciiString+i, "&amp;") ==
                            escAsciiString+i) {
                        /* Convert EscAscii "&amp;" to two bytes */
                        *destPtr++ = 0x00;
                        *destPtr++ = '&';
                        i += 5;
                } else if (((PL_strstr(escAsciiString+i, "&#x") ==
                            escAsciiString+i)||
                            (PL_strstr(escAsciiString+i, "&#X") ==
                            escAsciiString+i))&&
                            ((i+7) <= escAsciiLen)) {

                        /* We're either looking at &#xNNNN; or &#xNNNNNNNN; */
                        charSize = (escAsciiString[i+7] == ';')?4:8;

                        /* Skip past the &#x */
                        i += 3;

                        /* Make sure there is a terminating semi-colon */
                        if (((i+charSize) > escAsciiLen)||
                            (escAsciiString[i+charSize] != ';')) {
                                PKIX_ERROR(PKIX_TRUNCATEDUNICODEINESCAPEDASCII);
                        }

                        for (j = 0; j < charSize; j++) {
                                if (!PKIX_ISXDIGIT
                                    (escAsciiString[i+j])) {
                                        PKIX_ERROR(PKIX_ILLEGALUNICODECHARACTER);
                                } else if (charSize == 8) {
                                        x |= (pkix_hex2i
                                                        (escAsciiString[i+j]))
                                                        <<(4*(7-j));
                                }
                        }

                        testChar =
                                (pkix_hex2i(escAsciiString[i])<<4)|
                                pkix_hex2i(escAsciiString[i+1]);
                        testChar2 =
                                (pkix_hex2i(escAsciiString[i+2])<<4)|
                                pkix_hex2i(escAsciiString[i+3]);

                        if (charSize == 4) {
                                if ((testChar >= 0xD8)&&
                                    (testChar <= 0xDF)) {
                                        PKIX_ERROR(PKIX_ILLEGALSURROGATEPAIR);
                                } else if ((testChar == 0x00)&&
                                  pkix_isPlaintext(testChar2, debug)) {
                                      PKIX_ERROR(
                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
                                }
                                *destPtr++ = testChar;
                                *destPtr++ = testChar2;
                        } else if (charSize == 8) {
                                /* First two chars must be 0001-0010 */
                                if (!((testChar == 0x00)&&
                                    ((testChar2 >= 0x01)&&
                                    (testChar2 <= 0x10)))) {
                                      PKIX_ERROR(
                                          PKIX_ILLEGALCHARACTERINESCAPEDASCII);
                                }
                                /*
                                 * Unicode Strings of the form:
                                 * x =  0001 0000..0010 FFFF
                                 * Encoded as pairs of UTF-16 where
                                 * y = ((x - 0001 0000) / 400) + D800
                                 * z = ((x - 0001 0000) % 400) + DC00
                                 */
                                x -= 0x00010000;
                                y = (x/0x400)+ 0xD800;
                                z = (x%0x400)+ 0xDC00;

                                /* Copy four bytes */
                                *destPtr++ = (y&0xFF00)>>8;
                                *destPtr++ = (y&0x00FF);
                                *destPtr++ = (z&0xFF00)>>8;
                                *destPtr++ = (z&0x00FF);
                        }
                        /* Move past the Hex digits and the semi-colon */
                        i += charSize+1;
                } else {
/*
 * FUNCTION: pkix_UTF16_to_EscASCII
 * DESCRIPTION:
 *
 *  Converts array of bytes pointed to by "utf16String" with length of
 *  "utf16Length" (which must be even) into a freshly allocated Escaped ASCII
 *  string and stores a pointer to that string at "pDest" and stores the
 *  string's length at "pLength". The Escaped ASCII string's length does not
 *  include the final NUL character. The caller is responsible for freeing
 *  "pDest" using PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug
 *  encoding.
 *
 * PARAMETERS:
 *  "utf16String"
 *      Address of array of bytes representing data source. Must be non-NULL.
 *  "utf16Length"
 *      Length of data source. Must be even.
 *  "debug"
 *      Boolean value indicating whether debug mode is desired.
 *  "pDest"
 *      Address where data will be stored. Must be non-NULL.
 *  "pLength"
 *      Address where data length will be stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns a String 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_UTF16_to_EscASCII(
        const void *utf16String,
        PKIX_UInt32 utf16Length,
        PKIX_Boolean debug,
        char **pDest,
        PKIX_UInt32 *pLength,
        void *plContext)
{
        char *destPtr = NULL;
        PKIX_UInt32 i, charLen;
        PKIX_UInt32 x = 0, y = 0, z = 0;
        unsigned char *utf16Char = (unsigned char *)utf16String;

        PKIX_ENTER(STRING, "pkix_UTF16_to_EscASCII");
        PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);

        /* Assume every pair of bytes becomes &#xNNNN; */
        charLen = 4*utf16Length;

        /* utf16Lenght must be even */
        if ((utf16Length % 2) != 0){
                PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
        }

        /* Count how many bytes we need */
        for (i = 0; i < utf16Length; i += 2) {
                if ((utf16Char[i] == 0x00)&&
                        pkix_isPlaintext(utf16Char[i+1], debug)) {
                        if (utf16Char[i+1] == '&') {
                                /* Need to convert this to &amp; */
                                charLen -= 3;
                        } else {
                                /* We can fit this into one char */
                                charLen -= 7;
                        }
                } else if ((utf16Char[i] >= 0xD8) && (utf16Char[i] <= 0xDB)) {
                        if ((i+3) >= utf16Length) {
                                PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
                        } else if ((utf16Char[i+2] >= 0xDC)&&
                                (utf16Char[i+2] <= 0xDF)) {
                                /* Quartet of bytes will become &#xNNNNNNNN; */
                                charLen -= 4;
                                /* Quartet of bytes will produce 12 chars */
                                i += 2;
                        } else {
                                /* Second pair should be DC00-DFFF */
                                PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
                        }
                }
        }

        *pLength = charLen;

        /* Ensure this string is null terminated */
        charLen++;

        /* Allocate space for character array */
        PKIX_CHECK(PKIX_PL_Malloc(charLen, (void **)pDest, plContext),
                    PKIX_MALLOCFAILED);

        destPtr = *pDest;
        for (i = 0; i < utf16Length; i += 2) {
                if ((utf16Char[i] == 0x00)&&
                    pkix_isPlaintext(utf16Char[i+1], debug)) {
                        /* Write a single character */
                        *destPtr++ = utf16Char[i+1];
                } else if ((utf16Char[i+1] == '&') && (utf16Char[i] == 0x00)){
                        *destPtr++ = '&';
                        *destPtr++ = 'a';
                        *destPtr++ = 'm';
                        *destPtr++ = 'p';
                        *destPtr++ = ';';
                } else if ((utf16Char[i] >= 0xD8)&&
                            (utf16Char[i] <= 0xDB)&&
                            (utf16Char[i+2] >= 0xDC)&&
                            (utf16Char[i+2] <= 0xDF)) {
                        /*
                         * Special UTF pairs are of the form:
                         * x = D800..DBFF; y = DC00..DFFF;
                         * The result is of the form:
                         * ((x - D800) * 400 + (y - DC00)) + 0001 0000
                         */
                        x = 0x0FFFF & ((utf16Char[i]<<8) | utf16Char[i+1]);
                        y = 0x0FFFF & ((utf16Char[i+2]<<8) | utf16Char[i+3]);
                        z = ((x - 0xD800) * 0x400 + (y - 0xDC00)) + 0x00010000;

                        /* Sprintf &#xNNNNNNNN; */
                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
                        if (PR_snprintf(destPtr, 13, "&#x%08X;", z) ==
                            (PKIX_UInt32)(-1)) {
                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
                        }
                        i += 2;
                        destPtr += 12;
                } else {
                        /* Sprintf &#xNNNN; */
                        PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
                        if (PR_snprintf
                            (destPtr,
                            9,
                            "&#x%02X%02X;",
                            utf16Char[i],
                            utf16Char[i+1]) ==
                            (PKIX_UInt32)(-1)) {
                                PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
                        }
                        destPtr += 8;
                }
        }
        *destPtr = '\0';

cleanup:

        if (PKIX_ERROR_RECEIVED){
                PKIX_FREE(*pDest);
        }

        PKIX_RETURN(STRING);
}
/*
 * FUNCTION: pkix_pl_oidBytes2Ascii
 * DESCRIPTION:
 *
 *  Converts the DER encoding of an OID pointed to by "secItem" to an ASCII
 *  representation and stores it at "pAscii". The ASCII representation is
 *  guaranteed to end with a NUL character. The input SECItem must contain
 *  non-NULL data and must have a positive length.
 *
 *  Example: the six bytes {2a 86 48 86 f7 0d} represent the
 *  four integer tokens {1, 2, 840, 113549}, which we will convert
 *  into ASCII yielding "1.2.840.113549"
 *
 *  The return value "pAscii" is not reference-counted and will need to
 *  be freed with PKIX_PL_Free.
 *
 * PARAMETERS
 *  "secItem"
 *      Address of SECItem which contains bytes and length of DER encoding.
 *      Must be non-NULL.
 *  "pAscii"
 *      Address where object pointer will be stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Thread Safe (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if the function succeeds.
 *  Returns an OID 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_oidBytes2Ascii(
        SECItem *secItem,
        char **pAscii,
        void *plContext)
{
        char *data = NULL;
        PKIX_UInt32 *tokens = NULL;
        PKIX_UInt32 token = 0;
        PKIX_UInt32 numBytes = 0;
        PKIX_UInt32 numTokens = 0;
        PKIX_UInt32 i = 0, x = 0, y = 0;
        PKIX_UInt32 index = 0;
        char *asciiString = NULL;

        PKIX_ENTER(OID, "pkix_pl_oidBytes2Ascii");
        PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);

        if (secItem->len == 0) {
                PKIX_ERROR_FATAL(PKIX_OIDBYTES2ASCIIDATALENGTHZERO);
        }

        data = (char *)(secItem->data);
        numBytes = secItem->len;
        numTokens = 0;

        /* calculate how many integer tokens are represented by the bytes. */
        for (i = 0; i < numBytes; i++){
                if ((data[i] & 0x080) == 0){
                        numTokens++;
                }
        }

        /* if we are unable to retrieve any tokens at all, we throw an error */
        if (numTokens == 0){
                PKIX_ERROR(PKIX_INVALIDDERENCODINGFOROID);
        }

        /* add one more token b/c the first byte always contains two tokens */
        numTokens++;

        /* allocate space for array of integers */
        PKIX_CHECK(PKIX_PL_Malloc
                    (numTokens * sizeof (PKIX_UInt32),
                    (void **)&tokens,
                    plContext),
                    PKIX_MALLOCFAILED);

        /* populate array of integers */
        for (i = 0; i < numTokens; i++){

                /* retrieve integer token */
                PKIX_CHECK(pkix_pl_getOIDToken
                            (data, index, &token, &index, plContext),
                            PKIX_GETOIDTOKENFAILED);

                if (i == 0){

                        /*
                         * special case: the first DER-encoded byte represents
                         * two tokens. We take advantage of fact that first
                         * token must be 0, 1, or 2; and second token must be
                         * between {0, 39} inclusive if first token is 0 or 1.
                         */

                        if (token < 40)
                                x = 0;
                        else if (token < 80)
                                x = 1;
                        else
                                x = 2;
                        y = token - (x * 40);

                        tokens[0] = x;
                        tokens[1] = y;
                        i++;
                } else {
                        tokens[i] = token;
                }
        }

        /* convert array of integers to ASCII */
        PKIX_CHECK(pkix_pl_helperBytes2Ascii
                    (tokens, numTokens, &asciiString, plContext),
                    PKIX_HELPERBYTES2ASCIIFAILED);

        *pAscii = asciiString;

cleanup:

        PKIX_FREE(tokens);
        PKIX_RETURN(OID);

}
/*
 * 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_SingleVerifyNode_ToString
 * DESCRIPTION:
 *
 *  Creates a String representation of the attributes of the VerifyNode pointed
 *  to by "node", other than its children, and stores the result at "pString".
 *
 * PARAMETERS:
 *  "node"
 *      Address of VerifyNode to be described by the string. Must be non-NULL.
 *  "pString"
 *      Address where object pointer will be stored. Must be non-NULL.
 *  "plContext"
 *      Platform-specific context pointer.
 * THREAD SAFETY:
 *  Conditionally Thread Safe
 *  (see Thread Safety Definitions in Programmer's Guide)
 * RETURNS:
 *  Returns NULL if function succeeds
 *  Returns a VerifyNode Error if the function fails in a non-fatal way.
 *  Returns a Fatal Error if the function fails in a fatal way
 */
PKIX_Error *
pkix_SingleVerifyNode_ToString(
        PKIX_VerifyNode *node,
        PKIX_PL_String **pString,
        void *plContext)
{
        PKIX_PL_String *fmtString = NULL;
        PKIX_PL_String *errorString = NULL;
        PKIX_PL_String *outString = NULL;

        PKIX_PL_X500Name *issuerName = NULL;
        PKIX_PL_X500Name *subjectName = NULL;
        PKIX_PL_String *issuerString = NULL;
        PKIX_PL_String *subjectString = NULL;

        PKIX_ENTER(VERIFYNODE, "pkix_SingleVerifyNode_ToString");
        PKIX_NULLCHECK_THREE(node, pString, node->verifyCert);

        PKIX_TOSTRING(node->error, &errorString, plContext,
                PKIX_ERRORTOSTRINGFAILED);

        PKIX_CHECK(PKIX_PL_Cert_GetIssuer
                (node->verifyCert, &issuerName, plContext),
                PKIX_CERTGETISSUERFAILED);

        PKIX_TOSTRING(issuerName, &issuerString, plContext,
                PKIX_X500NAMETOSTRINGFAILED);

        PKIX_CHECK(PKIX_PL_Cert_GetSubject
                (node->verifyCert, &subjectName, plContext),
                PKIX_CERTGETSUBJECTFAILED);

        PKIX_TOSTRING(subjectName, &subjectString, plContext,
                PKIX_X500NAMETOSTRINGFAILED);

        PKIX_CHECK(PKIX_PL_String_Create
                (PKIX_ESCASCII,
                "CERT[Issuer:%s, Subject:%s], depth=%d, error=%s",
                0,
                &fmtString,
                plContext),
                PKIX_CANTCREATESTRING);

        PKIX_CHECK(PKIX_PL_Sprintf
                (&outString,
                plContext,
                fmtString,
                issuerString,
                subjectString,
                node->depth,
                errorString),
                PKIX_SPRINTFFAILED);

        *pString = outString;

cleanup:

        PKIX_DECREF(fmtString);
        PKIX_DECREF(errorString);
        PKIX_DECREF(issuerName);
        PKIX_DECREF(subjectName);
        PKIX_DECREF(issuerString);
        PKIX_DECREF(subjectString);
        PKIX_RETURN(VERIFYNODE);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue
 *  (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
 */
PKIX_Error *
pkix_pl_LdapCertStore_GetCRLContinue(
        PKIX_CertStore *store,
        PKIX_CRLSelector *selector,
        void **pNBIOContext,
        PKIX_List **pCrlList,
        void *plContext)
{
        void *nbio = NULL;
        PKIX_PL_CRL *candidate = NULL;
        PKIX_List *responses = NULL;
        PKIX_PL_LdapCertStoreContext *lcs = NULL;
        PKIX_List *filteredCRLs = NULL;
        PKIX_List *unfilteredCRLs = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue");
        PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);

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

        PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
                ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext),
                PKIX_LDAPCLIENTRESUMEREQUESTFAILED);

        if (nbio != NULL) {
                /* client is waiting for non-blocking I/O to complete */
                *pNBIOContext = (void *)nbio;
                *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);

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

        }

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

        *pCrlList = filteredCRLs;

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

        PKIX_DECREF(candidate);
        PKIX_DECREF(responses);
        PKIX_DECREF(unfilteredCRLs);
        PKIX_DECREF(lcs);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: pkix_VerifyNode_Equals
 * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_VerifyNode_Equals(
        PKIX_PL_Object *firstObject,
        PKIX_PL_Object *secondObject,
        PKIX_Boolean *pResult,
        void *plContext)
{
        PKIX_VerifyNode *firstVN = NULL;
        PKIX_VerifyNode *secondVN = NULL;
        PKIX_UInt32 secondType;
        PKIX_Boolean compResult = PKIX_FALSE;

        PKIX_ENTER(VERIFYNODE, "pkix_VerifyNode_Equals");
        PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);

        /* test that firstObject is a VerifyNode */
        PKIX_CHECK(pkix_CheckType
                (firstObject, PKIX_VERIFYNODE_TYPE, plContext),
                PKIX_FIRSTOBJECTNOTVERIFYNODE);

        /*
         * Since we know firstObject is a VerifyNode,
         * if both references are identical, they must be equal
         */
        if (firstObject == secondObject){
                compResult = PKIX_TRUE;
                goto cleanup;
        }

        /*
         * If secondObject isn't a VerifyNode, we
         * don't throw an error. We simply return FALSE.
         */
        PKIX_CHECK(PKIX_PL_Object_GetType
                    (secondObject, &secondType, plContext),
                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);

        if (secondType != PKIX_VERIFYNODE_TYPE) {
                goto cleanup;
        }

        /*
         * Oh, well, we have to do the comparisons. Do
         * the easiest ones first.
         */
        firstVN = (PKIX_VerifyNode *)firstObject;
        secondVN = (PKIX_VerifyNode *)secondObject;

        PKIX_CHECK(pkix_SingleVerifyNode_Equals
                (firstVN, secondVN, &compResult, plContext),
                PKIX_SINGLEVERIFYNODEEQUALSFAILED);

        if (compResult == PKIX_FALSE) {
                goto cleanup;
        }

        PKIX_EQUALS
                (firstVN->children,
                secondVN->children,
                &compResult,
                plContext,
                PKIX_OBJECTEQUALSFAILEDONCHILDREN);

cleanup:

        *pResult = compResult;

        PKIX_RETURN(VERIFYNODE);
}
/*
 * FUNCTION: pkix_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_ComCertSelParams_Duplicate
 * (see comments for PKIX_PL_DuplicateCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_ComCertSelParams_Duplicate(
        PKIX_PL_Object *object,
        PKIX_PL_Object **pNewObject,
        void *plContext)
{
        PKIX_ComCertSelParams *params = NULL;
        PKIX_ComCertSelParams *paramsDuplicate = NULL;

        PKIX_ENTER(COMCERTSELPARAMS, "pkix_ComCertSelParams_Duplicate");
        PKIX_NULLCHECK_TWO(object, pNewObject);

        PKIX_CHECK(pkix_CheckType
                    (object, PKIX_COMCERTSELPARAMS_TYPE, plContext),
                    PKIX_OBJECTNOTCOMCERTSELPARAMS);

        params = (PKIX_ComCertSelParams *)object;

        PKIX_CHECK(PKIX_ComCertSelParams_Create(&paramsDuplicate, plContext),
                    PKIX_COMCERTSELPARAMSCREATEFAILED);

        paramsDuplicate->minPathLength = params->minPathLength;
        paramsDuplicate->matchAllSubjAltNames = params->matchAllSubjAltNames;

        PKIX_DUPLICATE(params->subject, &paramsDuplicate->subject, plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->policies, &paramsDuplicate->policies, plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        if (params->cert){
                PKIX_CHECK(PKIX_PL_Object_Duplicate
                            ((PKIX_PL_Object *)params->cert,
                            (PKIX_PL_Object **)&paramsDuplicate->cert,
                            plContext),
                            PKIX_OBJECTDUPLICATEFAILED);
        }

        PKIX_DUPLICATE
                (params->nameConstraints,
                &paramsDuplicate->nameConstraints,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE
                (params->pathToNames,
                &paramsDuplicate->pathToNames,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE
                (params->subjAltNames,
                &paramsDuplicate->subjAltNames,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        if (params->date){
                PKIX_CHECK(PKIX_PL_Object_Duplicate
                            ((PKIX_PL_Object *)params->date,
                            (PKIX_PL_Object **)&paramsDuplicate->date,
                            plContext),
                            PKIX_OBJECTDUPLICATEFAILED);
        }

        paramsDuplicate->keyUsage = params->keyUsage;

        PKIX_DUPLICATE(params->certValid,
                &paramsDuplicate->certValid,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->issuer,
                &paramsDuplicate->issuer,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->serialNumber,
                &paramsDuplicate->serialNumber,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->authKeyId,
                &paramsDuplicate->authKeyId,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->subjKeyId,
                &paramsDuplicate->subjKeyId,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->subjPubKey,
                &paramsDuplicate->subjPubKey,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        PKIX_DUPLICATE(params->subjPKAlgId,
                &paramsDuplicate->subjPKAlgId,
                plContext,
                PKIX_OBJECTDUPLICATEFAILED);

        paramsDuplicate->leafCertFlag = params->leafCertFlag;

        *pNewObject = (PKIX_PL_Object *)paramsDuplicate;

cleanup:

        if (PKIX_ERROR_RECEIVED){
                PKIX_DECREF(paramsDuplicate);
        }

        PKIX_RETURN(COMCERTSELPARAMS);
}
/*
 * 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_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);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_MakeNameAVAList
 * DESCRIPTION:
 *
 *  This function allocates space from the arena pointed to by "arena" to
 *  construct a filter that will match components of the X500Name pointed to
 *  by "name", and stores the resulting filter at "pFilter".
 *
 *  "name" is checked for commonName and organizationName components (cn=,
 *  and o=). The component strings are extracted using the family of
 *  CERT_Get* functions, and each must be freed with PORT_Free.
 *
 *  It is not clear which components should be in a request, so, for now,
 *  we stop adding components after we have found one.
 *
 * PARAMETERS:
 *  "arena"
 *      The address of the PRArenaPool used in creating the filter. Must be
 *       non-NULL.
 *  "name"
 *      The address of the X500Name whose components define the desired
 *      matches. Must be non-NULL.
 *  "pList"
 *      The address at which the result 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 CertStore 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_LdapCertStore_MakeNameAVAList(
        PRArenaPool *arena,
        PKIX_PL_X500Name *subjectName, 
        LDAPNameComponent ***pList,
        void *plContext)
{
        LDAPNameComponent **setOfNameComponents;
        LDAPNameComponent *currentNameComponent = NULL;
        PKIX_UInt32 componentsPresent = 0;
        void *v = NULL;
        unsigned char *component = NULL;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_MakeNameAVAList");
        PKIX_NULLCHECK_THREE(arena, subjectName, pList);

        /* Increase this if additional components may be extracted */
#define MAX_NUM_COMPONENTS 3

        /* Space for (MAX_NUM_COMPONENTS + 1) pointers to LDAPNameComponents */
        PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc,
                (arena, (MAX_NUM_COMPONENTS + 1)*sizeof(LDAPNameComponent *)));
        setOfNameComponents = (LDAPNameComponent **)v;

        /* Space for MAX_NUM_COMPONENTS LDAPNameComponents */
        PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray,
                (arena, LDAPNameComponent, MAX_NUM_COMPONENTS));

        currentNameComponent = (LDAPNameComponent *)v;

        /* Try for commonName */
        PKIX_CHECK(pkix_pl_X500Name_GetCommonName
                (subjectName, &component, plContext),
                PKIX_X500NAMEGETCOMMONNAMEFAILED);
        if (component) {
                setOfNameComponents[componentsPresent] = currentNameComponent;
                currentNameComponent->attrType = (unsigned char *)"cn";
                currentNameComponent->attrValue = component;
                componentsPresent++;
                currentNameComponent++;
        }

        /*
         * The LDAP specification says we can send multiple name components
         * in an "AND" filter, but the LDAP Servers don't seem to be able to
         * handle such requests. So we'll quit after the cn component.
         */
#if 0
        /* Try for orgName */
        PKIX_CHECK(pkix_pl_X500Name_GetOrgName
                (subjectName, &component, plContext),
                PKIX_X500NAMEGETORGNAMEFAILED);
        if (component) {
                setOfNameComponents[componentsPresent] = currentNameComponent;
                currentNameComponent->attrType = (unsigned char *)"o";
                currentNameComponent->attrValue = component;
                componentsPresent++;
                currentNameComponent++;
        }

        /* Try for countryName */
        PKIX_CHECK(pkix_pl_X500Name_GetCountryName
                (subjectName, &component, plContext),
                PKIX_X500NAMEGETCOUNTRYNAMEFAILED);
        if (component) {
                setOfNameComponents[componentsPresent] = currentNameComponent;
                currentNameComponent->attrType = (unsigned char *)"c";
                currentNameComponent->attrValue = component;
                componentsPresent++;
                currentNameComponent++;
        }
#endif

        setOfNameComponents[componentsPresent] = NULL;

        *pList = setOfNameComponents;

cleanup:

        PKIX_RETURN(CERTSTORE);

}
Exemple #25
0
/*
 * FUNCTION: pkix_Error_Equals
 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_Error_Equals(
        PKIX_PL_Object *firstObject,
        PKIX_PL_Object *secondObject,
        PKIX_Boolean *pResult,
        void *plContext)
{
        PKIX_Error *firstError = NULL;
        PKIX_Error *secondError = NULL;
        PKIX_Error *firstCause = NULL;
        PKIX_Error *secondCause = NULL;
        PKIX_PL_Object *firstInfo = NULL;
        PKIX_PL_Object *secondInfo = NULL;
        PKIX_ERRORCLASS firstClass, secondClass;
        PKIX_UInt32 secondType;
        PKIX_Boolean boolResult, unequalFlag;

        PKIX_ENTER(ERROR, "pkix_Error_Equals");
        PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);

        unequalFlag = PKIX_FALSE;

        /* First just compare pointer values to save time */
        if (firstObject == secondObject) {
                *pResult = PKIX_TRUE;
                goto cleanup;
        } else {
                /* Result will only be set to true if all tests pass */
                *pResult = PKIX_FALSE;
        }

        PKIX_CHECK(pkix_CheckType(firstObject, PKIX_ERROR_TYPE, plContext),
                    PKIX_FIRSTOBJECTNOTANERROROBJECT);

        PKIX_CHECK(PKIX_PL_Object_GetType
                    (secondObject, &secondType, plContext),
                    PKIX_ERRORGETTINGSECONDOBJECTTYPE);

        /* If types differ, then return false. Result is already set */
        if (secondType != PKIX_ERROR_TYPE) goto cleanup;

        /* It is safe to cast to PKIX_Error */
        firstError = (PKIX_Error *) firstObject;
        secondError = (PKIX_Error *) secondObject;

        /* Compare error codes */
        firstClass = firstError->errClass;
        secondClass = secondError->errClass;

        /* If codes differ, return false. Result is already set */
        if (firstClass != secondClass) goto cleanup;

        /* Compare causes */
        firstCause = firstError->cause;
        secondCause = secondError->cause;

        /* Ensure that either both or none of the causes are NULL */
        if (((firstCause != NULL) && (secondCause == NULL))||
            ((firstCause == NULL) && (secondCause != NULL)))
                unequalFlag = PKIX_TRUE;

        if ((firstCause != NULL) && (secondCause != NULL)) {
                PKIX_CHECK(PKIX_PL_Object_Equals
                            ((PKIX_PL_Object*)firstCause,
                            (PKIX_PL_Object*)secondCause,
                            &boolResult,
                            plContext),
                            PKIX_ERRORINRECURSIVEEQUALSCALL);

                /* Set the unequalFlag so that we return after dec refing */
                if (boolResult == 0) unequalFlag = PKIX_TRUE;
        }

        /* If the cause errors are not equal, return null */
        if (unequalFlag) goto cleanup;

        /* Compare info fields */
        firstInfo = firstError->info;
        secondInfo = secondError->info;

        if (firstInfo != secondInfo) goto cleanup;

        /* Ensure that either both or none of the infos are NULL */
        if (((firstInfo != NULL) && (secondInfo == NULL))||
            ((firstInfo == NULL) && (secondInfo != NULL)))
                unequalFlag = PKIX_TRUE;

        if ((firstInfo != NULL) && (secondInfo != NULL)) {

                PKIX_CHECK(PKIX_PL_Object_Equals
                            ((PKIX_PL_Object*)firstInfo,
                            (PKIX_PL_Object*)secondInfo,
                            &boolResult,
                            plContext),
                            PKIX_ERRORINRECURSIVEEQUALSCALL);

                /* Set the unequalFlag so that we return after dec refing */
                if (boolResult == 0) unequalFlag = PKIX_TRUE;
        }

        /* If the infos are not equal, return null */
        if (unequalFlag) goto cleanup;


        /* Compare descs */
        if (firstError->errCode != secondError->errCode) {
                unequalFlag = PKIX_TRUE;
        }

        if (firstError->plErr != secondError->plErr) {
                unequalFlag = PKIX_TRUE;
        }

        /* If the unequalFlag was set, return false */
        if (unequalFlag) goto cleanup;

        /* Errors are equal in all fields at this point */
        *pResult = PKIX_TRUE;

cleanup:

        PKIX_RETURN(ERROR);
}
/*
 * FUNCTION: pkix_pl_LdapCertStore_GetCert
 *  (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
 */
PKIX_Error *
pkix_pl_LdapCertStore_GetCert(
        PKIX_CertStore *store,
        PKIX_CertSelector *selector,
        PKIX_VerifyNode *verifyNode,
        void **pNBIOContext,
        PKIX_List **pCertList,
        void *plContext)
{
        PRArenaPool *requestArena = NULL;
        LDAPRequestParams requestParams;
        void *pollDesc = NULL;
        PKIX_Int32 minPathLen = 0;
        PKIX_Boolean cacheFlag = PKIX_FALSE;
        PKIX_ComCertSelParams *params = NULL;
        PKIX_PL_LdapCertStoreContext *lcs = NULL;
        PKIX_List *responses = NULL;
        PKIX_List *unfilteredCerts = NULL;
        PKIX_List *filteredCerts = NULL;
        PKIX_PL_X500Name *subjectName = 0;

        PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCert");
        PKIX_NULLCHECK_THREE(store, selector, pCertList);

        requestParams.baseObject = "c=US";
        requestParams.scope = WHOLE_SUBTREE;
        requestParams.derefAliases = NEVER_DEREF;
        requestParams.sizeLimit = 0;
        requestParams.timeLimit = 0;

        /* Prepare elements for request filter */

        /*
         * Get a short-lived arena. We'll be done with this space once
         * the request is encoded.
         */
        requestArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
        if (!requestArena) {
                PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
        }

        PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
                (selector, &params, plContext),
                PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);

        /*
         * If we have the subject name for the desired subject,
         * ask the server for Certs with that subject.
         */
        PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
                (params, &subjectName, plContext),
                PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);

        PKIX_CHECK(PKIX_ComCertSelParams_GetBasicConstraints
                (params, &minPathLen, plContext),
                PKIX_COMCERTSELPARAMSGETBASICCONSTRAINTSFAILED);

        if (subjectName) {
                PKIX_CHECK(pkix_pl_LdapCertStore_MakeNameAVAList
                        (requestArena,
                        subjectName,
                        &(requestParams.nc),
                        plContext),
                        PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);

                if (*requestParams.nc == NULL) {
                        /*
                         * The subjectName 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(&filteredCerts, plContext),
                                PKIX_LISTCREATEFAILED);

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

                        *pNBIOContext = NULL;
                        *pCertList = filteredCerts;
                        filteredCerts = NULL;
                        goto cleanup;
                }
        } else {
                PKIX_ERROR(PKIX_INSUFFICIENTCRITERIAFORCERTQUERY);
        }

        /* Prepare attribute field of request */

        requestParams.attributes = 0;

        if (minPathLen < 0) {
                requestParams.attributes |= LDAPATTR_USERCERT;
        }

        if (minPathLen > -2) {
                requestParams.attributes |=
                        LDAPATTR_CACERT | LDAPATTR_CROSSPAIRCERT;
        }

        /* 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));
                requestArena = NULL;
        }

        if (pollDesc != NULL) {
                /* client is waiting for non-blocking I/O to complete */
                *pNBIOContext = (void *)pollDesc;
                *pCertList = NULL;
                goto cleanup;
        }
        /* LdapClient has given us a response! */

        if (responses) {
                PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
                        (store, &cacheFlag, plContext),
                        PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);

                PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
                        (responses, &unfilteredCerts, plContext),
                        PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);

                PKIX_CHECK(pkix_CertSelector_Select
                        (selector, unfilteredCerts, &filteredCerts, plContext),
                        PKIX_CERTSELECTORSELECTFAILED);
        }

        *pNBIOContext = NULL;
        *pCertList = filteredCerts;
        filteredCerts = NULL;

cleanup:

        PKIX_DECREF(params);
        PKIX_DECREF(subjectName);
        PKIX_DECREF(responses);
        PKIX_DECREF(unfilteredCerts);
        PKIX_DECREF(filteredCerts);
        PKIX_DECREF(lcs);

        PKIX_RETURN(CERTSTORE);
}
/*
 * FUNCTION: pkix_TrustAnchor_Equals
 * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
 */
static PKIX_Error *
pkix_TrustAnchor_Equals(
        PKIX_PL_Object *first,
        PKIX_PL_Object *second,
        PKIX_Boolean *pResult,
        void *plContext)
{
        PKIX_UInt32 secondType;
        PKIX_Boolean cmpResult;
        PKIX_TrustAnchor *firstAnchor = NULL;
        PKIX_TrustAnchor *secondAnchor = NULL;
        PKIX_PL_Cert *firstCert = NULL;
        PKIX_PL_Cert *secondCert = NULL;

        PKIX_ENTER(TRUSTANCHOR, "pkix_TrustAnchor_Equals");
        PKIX_NULLCHECK_THREE(first, second, pResult);

        PKIX_CHECK(pkix_CheckType(first, PKIX_TRUSTANCHOR_TYPE, plContext),
                    PKIX_FIRSTOBJECTNOTTRUSTANCHOR);

        PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
                    PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);

        *pResult = PKIX_FALSE;

        if (secondType != PKIX_TRUSTANCHOR_TYPE) goto cleanup;

        firstAnchor = (PKIX_TrustAnchor *)first;
        secondAnchor = (PKIX_TrustAnchor *)second;

        firstCert = firstAnchor->trustedCert;
        secondCert = secondAnchor->trustedCert;

        if ((firstCert && !secondCert) || (!firstCert && secondCert)){
                goto cleanup;
        }

        if (firstCert && secondCert){
                PKIX_CHECK(PKIX_PL_Object_Equals
                            ((PKIX_PL_Object *)firstCert,
                            (PKIX_PL_Object *)secondCert,
                            &cmpResult,
                            plContext),
                            PKIX_OBJECTEQUALSFAILED);
        } else {
                PKIX_CHECK(PKIX_PL_Object_Equals
                            ((PKIX_PL_Object *)firstAnchor->caName,
                            (PKIX_PL_Object *)secondAnchor->caName,
                            &cmpResult,
                            plContext),
                            PKIX_OBJECTEQUALSFAILED);

                if (!cmpResult) goto cleanup;

                PKIX_CHECK(PKIX_PL_Object_Equals
                            ((PKIX_PL_Object *)firstAnchor->caPubKey,
                            (PKIX_PL_Object *)secondAnchor->caPubKey,
                            &cmpResult,
                            plContext),
                            PKIX_OBJECTEQUALSFAILED);

                if (!cmpResult) goto cleanup;

                PKIX_EQUALS
                        (firstAnchor->nameConstraints,
                        secondAnchor->nameConstraints,
                        &cmpResult,
                        plContext,
                        PKIX_OBJECTEQUALSFAILED);

                if (!cmpResult) goto cleanup;

        }

        *pResult = cmpResult;

cleanup:

        PKIX_RETURN(TRUSTANCHOR);
}
/*
 * 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);
}
/*
 * 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);
}
/*
 * PKIX_PL_Initialize (see comments in pkix_pl_system.h)
 */
PKIX_Error *
PKIX_PL_Initialize(
        PKIX_Boolean platformInitNeeded,
        PKIX_Boolean useArenas,
        void **pPlContext)
{
        void *plContext = NULL;

        PKIX_ENTER(OBJECT, "PKIX_PL_Initialize");

        /*
         * This function can only be called once. If it has already been
         * called, we return a positive status.
         */
        if (pkix_pl_initialized) {
            PKIX_RETURN(OBJECT);
        }

        classTableLock = PR_NewLock();
        if (classTableLock == NULL) {
            return PKIX_ALLOC_ERROR();
        }

        if (PR_GetEnv("NSS_STRICT_SHUTDOWN")) {
            pkixLog = PR_NewLogModule("pkix");
        }
        /*
         * Register Object, it is the base object of all other objects.
         */
        pkix_pl_Object_RegisterSelf(plContext);

        /*
         * Register Error and String, since they will be needed if
         * there is a problem in registering any other type.
         */
        pkix_Error_RegisterSelf(plContext);
        pkix_pl_String_RegisterSelf(plContext);


        /*
         * We register all other system types
         * (They don't need to be in order, but it's
         * easier to keep track of what types are registered
         * if we register them in the same order as their
         * numbers, defined in pkixt.h.
         */
        pkix_pl_BigInt_RegisterSelf(plContext);   /* 1-10 */
        pkix_pl_ByteArray_RegisterSelf(plContext);
        pkix_pl_HashTable_RegisterSelf(plContext);
        pkix_List_RegisterSelf(plContext);
        pkix_Logger_RegisterSelf(plContext);
        pkix_pl_Mutex_RegisterSelf(plContext);
        pkix_pl_OID_RegisterSelf(plContext);
        pkix_pl_RWLock_RegisterSelf(plContext);

        pkix_pl_CertBasicConstraints_RegisterSelf(plContext); /* 11-20 */
        pkix_pl_Cert_RegisterSelf(plContext);
        pkix_pl_CRL_RegisterSelf(plContext);
        pkix_pl_CRLEntry_RegisterSelf(plContext);
        pkix_pl_Date_RegisterSelf(plContext);
        pkix_pl_GeneralName_RegisterSelf(plContext);
        pkix_pl_CertNameConstraints_RegisterSelf(plContext);
        pkix_pl_PublicKey_RegisterSelf(plContext);
        pkix_TrustAnchor_RegisterSelf(plContext);

        pkix_pl_X500Name_RegisterSelf(plContext);   /* 21-30 */
        pkix_pl_HttpCertStoreContext_RegisterSelf(plContext);
        pkix_BuildResult_RegisterSelf(plContext);
        pkix_ProcessingParams_RegisterSelf(plContext);
        pkix_ValidateParams_RegisterSelf(plContext);
        pkix_ValidateResult_RegisterSelf(plContext);
        pkix_CertStore_RegisterSelf(plContext);
        pkix_CertChainChecker_RegisterSelf(plContext);
        pkix_RevocationChecker_RegisterSelf(plContext);
        pkix_CertSelector_RegisterSelf(plContext);

        pkix_ComCertSelParams_RegisterSelf(plContext);   /* 31-40 */
        pkix_CRLSelector_RegisterSelf(plContext);
        pkix_ComCRLSelParams_RegisterSelf(plContext);
        pkix_pl_CertPolicyInfo_RegisterSelf(plContext);
        pkix_pl_CertPolicyQualifier_RegisterSelf(plContext);
        pkix_pl_CertPolicyMap_RegisterSelf(plContext);
        pkix_PolicyNode_RegisterSelf(plContext);
        pkix_TargetCertCheckerState_RegisterSelf(plContext);
        pkix_BasicConstraintsCheckerState_RegisterSelf(plContext);
        pkix_PolicyCheckerState_RegisterSelf(plContext);

        pkix_pl_CollectionCertStoreContext_RegisterSelf(plContext); /* 41-50 */
        pkix_CrlChecker_RegisterSelf(plContext);
        pkix_ForwardBuilderState_RegisterSelf(plContext);
        pkix_SignatureCheckerState_RegisterSelf(plContext);
        pkix_NameConstraintsCheckerState_RegisterSelf(plContext);
#ifndef NSS_PKIX_NO_LDAP
        pkix_pl_LdapRequest_RegisterSelf(plContext);
        pkix_pl_LdapResponse_RegisterSelf(plContext);
        pkix_pl_LdapDefaultClient_RegisterSelf(plContext);
#endif
        pkix_pl_Socket_RegisterSelf(plContext);

        pkix_ResourceLimits_RegisterSelf(plContext); /* 51-59 */
        pkix_pl_MonitorLock_RegisterSelf(plContext);
        pkix_pl_InfoAccess_RegisterSelf(plContext);
        pkix_pl_AIAMgr_RegisterSelf(plContext);
        pkix_OcspChecker_RegisterSelf(plContext);
        pkix_pl_OcspCertID_RegisterSelf(plContext);
        pkix_pl_OcspRequest_RegisterSelf(plContext);
        pkix_pl_OcspResponse_RegisterSelf(plContext);
        pkix_pl_HttpDefaultClient_RegisterSelf(plContext);
        pkix_VerifyNode_RegisterSelf(plContext);
        pkix_EkuChecker_RegisterSelf(plContext);
        pkix_pl_CrlDp_RegisterSelf(plContext);

        if (pPlContext) {
            PKIX_CHECK(PKIX_PL_NssContext_Create
                       (0, useArenas, NULL, &plContext),
                       PKIX_NSSCONTEXTCREATEFAILED);
            
            *pPlContext = plContext;
        }

        pkix_pl_initialized = PKIX_TRUE;

cleanup:

        PKIX_RETURN(OBJECT);
}