/*
 * 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);
}
int
test_comcertselparams(int argc, char *argv[])
{

    PKIX_UInt32 actualMinorVersion;
    PKIX_UInt32 j = 0;

    PKIX_PL_Cert *testCert = NULL;
    PKIX_PL_Cert *goodCert = NULL;
    PKIX_PL_Cert *equalCert = NULL;
    PKIX_PL_Cert *diffCert = NULL;
    PKIX_PL_CertBasicConstraints *goodBasicConstraints = NULL;
    PKIX_PL_CertBasicConstraints *diffBasicConstraints = NULL;
    PKIX_List *testPolicyInfos = NULL;  /* CertPolicyInfos */
    PKIX_List *cert2PolicyInfos = NULL; /* CertPolicyInfos */

    PKIX_ComCertSelParams *goodParams = NULL;
    PKIX_ComCertSelParams *equalParams = NULL;
    PKIX_PL_X500Name *goodSubject = NULL;
    PKIX_PL_X500Name *equalSubject = NULL;
    PKIX_PL_X500Name *diffSubject = NULL;
    PKIX_PL_X500Name *testSubject = NULL;
    PKIX_Int32 goodMinPathLength = 0;
    PKIX_Int32 equalMinPathLength = 0;
    PKIX_Int32 diffMinPathLength = 0;
    PKIX_Int32 testMinPathLength = 0;
    PKIX_List *goodPolicies = NULL;  /* OIDs */
    PKIX_List *equalPolicies = NULL; /* OIDs */
    PKIX_List *testPolicies = NULL;  /* OIDs */
    PKIX_List *cert2Policies = NULL; /* OIDs */

    PKIX_PL_Date *testDate = NULL;
    PKIX_PL_Date *goodDate = NULL;
    PKIX_PL_Date *equalDate = NULL;
    PKIX_PL_String *stringRep = NULL;
    char *asciiRep = NULL;
    char *dirName = NULL;

    PKIX_TEST_STD_VARS();

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

    startTests("ComCertSelParams");

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

    dirName = argv[j + 1];

    asciiRep = "050501000000Z";

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_String_Create(PKIX_ESCASCII, asciiRep, 0, &stringRep, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Date_Create_UTCTime(stringRep, &testDate, plContext));

    testCert = createCert(dirName, "PoliciesP1234CACert.crt", plContext);

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubject(testCert, &testSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetBasicConstraints(testCert, &goodBasicConstraints, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_BasicConstraints_GetPathLenConstraint(goodBasicConstraints, &testMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetPolicyInformation(testCert, &testPolicyInfos, plContext));

    /* Convert from List of CertPolicyInfos to List of OIDs */
    test_CreateOIDList(testPolicyInfos, &testPolicies);

    subTest("Create goodParams and set its fields");
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_Create(&goodParams, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetSubject(goodParams, testSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetBasicConstraints(goodParams, testMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetCertificateValid(goodParams, testDate, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetPolicy(goodParams, testPolicies, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetCertificate(goodParams, testCert, plContext));

    subTest("Duplicate goodParams and verify copy");
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Object_Duplicate((PKIX_PL_Object *)goodParams,
                                                       (PKIX_PL_Object **)&equalParams,
                                                       plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetSubject(goodParams, &goodSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetBasicConstraints(goodParams, &goodMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetCertificate(goodParams, &goodCert, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetCertificateValid(goodParams, &goodDate, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetPolicy(goodParams, &goodPolicies, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetSubject(equalParams, &equalSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetBasicConstraints(equalParams, &equalMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetPolicy(equalParams, &equalPolicies, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetCertificate(equalParams, &equalCert, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetCertificateValid(equalParams, &equalDate, plContext));

    testEqualsHelper((PKIX_PL_Object *)goodSubject,
                     (PKIX_PL_Object *)equalSubject,
                     PKIX_TRUE,
                     plContext);

    if (goodMinPathLength != equalMinPathLength) {
        testError("unexpected mismatch");
        (void)printf("goodMinPathLength:\t%d\n", goodMinPathLength);
        (void)printf("equalMinPathLength:\t%d\n", equalMinPathLength);
    }

    testEqualsHelper((PKIX_PL_Object *)goodPolicies,
                     (PKIX_PL_Object *)equalPolicies,
                     PKIX_TRUE,
                     plContext);

    testEqualsHelper((PKIX_PL_Object *)goodCert,
                     (PKIX_PL_Object *)equalCert,
                     PKIX_TRUE,
                     plContext);

    testEqualsHelper((PKIX_PL_Object *)goodDate,
                     (PKIX_PL_Object *)equalDate,
                     PKIX_TRUE,
                     plContext);

    PKIX_TEST_DECREF_BC(equalSubject);
    PKIX_TEST_DECREF_BC(equalPolicies);
    PKIX_TEST_DECREF_BC(equalCert);
    PKIX_TEST_DECREF_AC(equalDate);

    subTest("Set different values and verify differences");

    diffCert = createCert(dirName, "pathLenConstraint6CACert.crt", plContext);

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubject(diffCert, &diffSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetBasicConstraints(diffCert, &diffBasicConstraints, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_BasicConstraints_GetPathLenConstraint(diffBasicConstraints, &diffMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetPolicyInformation(diffCert, &cert2PolicyInfos, plContext));
    test_CreateOIDList(cert2PolicyInfos, &cert2Policies);

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetSubject(
        equalParams, diffSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetBasicConstraints(equalParams, diffMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetPolicy(equalParams, cert2Policies, plContext));

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetSubject(equalParams, &equalSubject, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetBasicConstraints(equalParams, &equalMinPathLength, plContext));
    PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetPolicy(equalParams, &equalPolicies, plContext));

    testEqualsHelper((PKIX_PL_Object *)goodSubject,
                     (PKIX_PL_Object *)equalSubject,
                     PKIX_FALSE,
                     plContext);

    if (goodMinPathLength == equalMinPathLength) {
        testError("unexpected match");
        (void)printf("goodMinPathLength:\t%d\n", goodMinPathLength);
        (void)printf("equalMinPathLength:\t%d\n", equalMinPathLength);
    }

    testEqualsHelper((PKIX_PL_Object *)goodPolicies,
                     (PKIX_PL_Object *)equalPolicies,
                     PKIX_FALSE,
                     plContext);

    test_NameConstraints(dirName);
    test_PathToNames();
    test_SubjAltNames();
    test_KeyUsages();
    test_Version_Issuer_SerialNumber();
    test_SubjKeyId_AuthKeyId();
    test_SubjAlgId_SubjPublicKey(dirName);

cleanup:

    PKIX_TEST_DECREF_AC(testSubject);
    PKIX_TEST_DECREF_AC(goodSubject);
    PKIX_TEST_DECREF_AC(equalSubject);
    PKIX_TEST_DECREF_AC(diffSubject);
    PKIX_TEST_DECREF_AC(testSubject);
    PKIX_TEST_DECREF_AC(goodPolicies);
    PKIX_TEST_DECREF_AC(equalPolicies);
    PKIX_TEST_DECREF_AC(testPolicies);
    PKIX_TEST_DECREF_AC(cert2Policies);
    PKIX_TEST_DECREF_AC(goodParams);
    PKIX_TEST_DECREF_AC(equalParams);
    PKIX_TEST_DECREF_AC(goodCert);
    PKIX_TEST_DECREF_AC(diffCert);
    PKIX_TEST_DECREF_AC(testCert);
    PKIX_TEST_DECREF_AC(goodBasicConstraints);
    PKIX_TEST_DECREF_AC(diffBasicConstraints);
    PKIX_TEST_DECREF_AC(testPolicyInfos);
    PKIX_TEST_DECREF_AC(cert2PolicyInfos);
    PKIX_TEST_DECREF_AC(stringRep);
    PKIX_TEST_DECREF_AC(testDate);
    PKIX_TEST_DECREF_AC(goodDate);

    PKIX_Shutdown(plContext);

    PKIX_TEST_RETURN();

    endTests("ComCertSelParams");

    return (0);
}