static void
testNameConstraints(char *dataDir)
{
        char *goodPname = "nameConstraintsDN5CACert.crt";
        PKIX_PL_Cert *goodCert = NULL;
        PKIX_PL_CertNameConstraints *goodNC = NULL;
        char *expectedAscii =
                "[\n"
                "\t\tPermitted Name:  (OU=permittedSubtree1,"
                "O=Test Certificates,C=US)\n"
                "\t\tExcluded Name:   (OU=excludedSubtree1,"
                "OU=permittedSubtree1,O=Test Certificates,C=US)\n"
                "\t]\n";

        PKIX_TEST_STD_VARS();

        subTest("PKIX_PL_CertNameConstraints");

        goodCert = createCert(dataDir, goodPname, plContext);

        subTest("PKIX_PL_Cert_GetNameConstraints");

        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetNameConstraints
                (goodCert, &goodNC, plContext));

        testToStringHelper
                ((PKIX_PL_Object *)goodNC, expectedAscii, plContext);

cleanup:

        PKIX_TEST_DECREF_AC(goodNC);
        PKIX_TEST_DECREF_AC(goodCert);

        PKIX_TEST_RETURN();
}
static
void test_NameConstraints(char *dirName)
{
        PKIX_PL_Cert *goodCert = NULL;
        PKIX_PL_CertNameConstraints *getNameConstraints = NULL;
        PKIX_PL_CertNameConstraints *setNameConstraints = NULL;
        PKIX_ComCertSelParams *goodParams = NULL;
        char *expectedAscii =
                "[\n"
                "\t\tPermitted Name:  (OU=permittedSubtree1,"
                "O=Test Certificates,C=US, OU=permittedSubtree2,"
                "O=Test Certificates,C=US)\n"
                "\t\tExcluded Name:   (EMPTY)\n"
                "\t]\n";

        PKIX_TEST_STD_VARS();

        subTest("Create Cert for NameConstraints test");

        goodCert = createCert
                (dirName, "nameConstraintsDN2CACert.crt", plContext);

        subTest("PKIX_PL_Cert_GetNameConstraints");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetNameConstraints
                (goodCert, &setNameConstraints, plContext));

        subTest("PKIX_ComCertSelParams_Create");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_Create
                (&goodParams, plContext));

        subTest("PKIX_ComCertSelParams_SetNameConstraints");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_SetNameConstraints
                (goodParams, setNameConstraints, plContext));

        subTest("PKIX_ComCertSelParams_GetNameConstraints");
        PKIX_TEST_EXPECT_NO_ERROR(PKIX_ComCertSelParams_GetNameConstraints
                (goodParams, &getNameConstraints, plContext));

        subTest("Compare NameConstraints");
        testEqualsHelper((PKIX_PL_Object *)setNameConstraints,
                (PKIX_PL_Object *)getNameConstraints,
                PKIX_TRUE,
                plContext);

        subTest("Compare NameConstraints with canned string");
        testToStringHelper
                ((PKIX_PL_Object *)getNameConstraints,
                expectedAscii,
                plContext);

cleanup:

        PKIX_TEST_DECREF_AC(goodCert);
        PKIX_TEST_DECREF_AC(getNameConstraints);
        PKIX_TEST_DECREF_AC(setNameConstraints);
        PKIX_TEST_DECREF_AC(goodParams);

        PKIX_TEST_RETURN();
}
PKIX_TrustAnchor *
createTrustAnchor(
        char *dirName,
        char *certFileName,
        PKIX_Boolean useCert,
        void *plContext)
{
        PKIX_TrustAnchor *anchor = NULL;
        PKIX_PL_Cert *cert = NULL;
        PKIX_PL_X500Name *name = NULL;
        PKIX_PL_PublicKey *pubKey = NULL;
        PKIX_PL_CertNameConstraints *nameConstraints = NULL;

        PKIX_TEST_STD_VARS();

        cert = createCert(dirName, certFileName, plContext);

        if (useCert){
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_TrustAnchor_CreateWithCert
                                        (cert, &anchor, plContext));
        } else {
                PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubject
                                        (cert, &name, plContext));

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

                PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetSubjectPublicKey
                                        (cert, &pubKey, plContext));

                PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetNameConstraints
                                        (cert, &nameConstraints, NULL));

                PKIX_TEST_EXPECT_NO_ERROR
                        (PKIX_TrustAnchor_CreateWithNameKeyPair
                        (name, pubKey, nameConstraints, &anchor, plContext));
        }

cleanup:

        if (PKIX_TEST_ERROR_RECEIVED){
                PKIX_TEST_DECREF_AC(anchor);
        }

        PKIX_TEST_DECREF_AC(cert);
        PKIX_TEST_DECREF_AC(name);
        PKIX_TEST_DECREF_AC(pubKey);
        PKIX_TEST_DECREF_AC(nameConstraints);

        PKIX_TEST_RETURN();

        return (anchor);
}
/*
 * FUNCTION: PKIX_TrustAnchor_CreateWithCert (see comments in pkix_params.h)
 */
PKIX_Error *
PKIX_TrustAnchor_CreateWithCert(
        PKIX_PL_Cert *cert,
        PKIX_TrustAnchor **pAnchor,
        void *plContext)
{
        PKIX_TrustAnchor *anchor = NULL;

        PKIX_ENTER(TRUSTANCHOR, "PKIX_TrustAnchor_CreateWithCert");
        PKIX_NULLCHECK_TWO(cert, pAnchor);

        PKIX_CHECK(PKIX_PL_Object_Alloc
                    (PKIX_TRUSTANCHOR_TYPE,
                    sizeof (PKIX_TrustAnchor),
                    (PKIX_PL_Object **)&anchor,
                    plContext),
                    PKIX_COULDNOTCREATETRUSTANCHOROBJECT);

        /* initialize fields */
        PKIX_CHECK(
            PKIX_PL_Cert_SetAsTrustAnchor(cert, plContext),
            PKIX_CERTSETASTRUSTANCHORFAILED);

        PKIX_INCREF(cert);
        anchor->trustedCert = cert;

        anchor->caName = NULL;
        anchor->caPubKey = NULL;

        PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
                    (anchor->trustedCert, &anchor->nameConstraints, plContext),
                    PKIX_CERTGETNAMECONSTRAINTSFAILED);


        *pAnchor = anchor;
        anchor = NULL;

cleanup:

        PKIX_DECREF(anchor);

        PKIX_RETURN(TRUSTANCHOR);

}
static void
testGetNameConstraints(char *dirName)
{
    PKIX_TrustAnchor *goodObject = NULL;
    PKIX_TrustAnchor *equalObject = NULL;
    PKIX_TrustAnchor *diffObject = NULL;
    PKIX_PL_Cert *diffCert;
    PKIX_PL_CertNameConstraints *diffNC = NULL;
    PKIX_PL_CertNameConstraints *equalNC = NULL;
    char *goodInput = "nameConstraintsDN5CACert.crt";
    char *expectedAscii =
        "[\n"
        "\tTrusted CA Name:         CN=nameConstraints DN5 CA,"
        "O=Test Certificates,C=US\n"
        "\tTrusted CA PublicKey:    PKCS #1 RSA Encryption\n"
        "\tInitial Name Constraints:[\n"
        "\t\tPermitted Name:  (OU=permittedSubtree1,"
        "O=Test Certificates,C=US)\n"
        "\t\tExcluded Name:   (OU=excludedSubtree1,"
        "OU=permittedSubtree1,O=Test Certificates,C=US)\n"
        "\t]\n"
        "\n"
        "]\n";

    PKIX_TEST_STD_VARS();

    subTest("Create TrustAnchors and compare");

    createTrustAnchors(dirName, goodInput, &goodObject, &equalObject, &diffObject);

    PKIX_TEST_EQ_HASH_TOSTR_DUP(goodObject,
                                equalObject,
                                diffObject,
                                expectedAscii,
                                TrustAnchor,
                                PKIX_TRUE);

    subTest("PKIX_TrustAnchor_GetTrustedCert");

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_TrustAnchor_GetTrustedCert(diffObject, &diffCert, plContext));

    subTest("PKIX_PL_Cert_GetNameConstraints");

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_PL_Cert_GetNameConstraints(diffCert, &diffNC, plContext));

    subTest("PKIX_TrustAnchor_GetNameConstraints");

    PKIX_TEST_EXPECT_NO_ERROR(PKIX_TrustAnchor_GetNameConstraints(equalObject, &equalNC, plContext));

    testEqualsHelper((PKIX_PL_Object *)diffNC,
                     (PKIX_PL_Object *)equalNC,
                     PKIX_TRUE,
                     plContext);

cleanup:

    PKIX_TEST_DECREF_AC(diffNC);
    PKIX_TEST_DECREF_AC(equalNC);
    PKIX_TEST_DECREF_BC(diffCert);
    PKIX_TEST_DECREF_BC(goodObject);
    PKIX_TEST_DECREF_BC(equalObject);
    PKIX_TEST_DECREF_BC(diffObject);

    PKIX_TEST_RETURN();
}
/*
 * FUNCTION: pkix_NameConstraintsChecker_Check
 * (see comments for PKIX_CertChainChecker_CheckCallback in pkix_checker.h)
 */
static PKIX_Error *
pkix_NameConstraintsChecker_Check(
        PKIX_CertChainChecker *checker,
        PKIX_PL_Cert *cert,
        PKIX_List *unresolvedCriticalExtensions,
        void **pNBIOContext,
        void *plContext)
{
        pkix_NameConstraintsCheckerState *state = NULL;
        PKIX_PL_CertNameConstraints *nameConstraints = NULL;
        PKIX_PL_CertNameConstraints *mergedNameConstraints = NULL;
        PKIX_Boolean selfIssued = PKIX_FALSE;
        PKIX_Boolean lastCert = PKIX_FALSE;

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

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

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

        state->certsRemaining--;
        lastCert = state->certsRemaining == 0;

        /* Get status of self issued */
        PKIX_CHECK(pkix_IsCertSelfIssued(cert, &selfIssued, plContext),
                    PKIX_ISCERTSELFISSUEDFAILED);

        /* Check on non self-issued and if so only for last cert */
        if (selfIssued == PKIX_FALSE ||
            (selfIssued == PKIX_TRUE && lastCert)) {
                PKIX_CHECK(PKIX_PL_Cert_CheckNameConstraints
                    (cert, state->nameConstraints, lastCert,
                      plContext),
                    PKIX_CERTCHECKNAMECONSTRAINTSFAILED);
        }

        if (!lastCert) {

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

            /* Merge with previous name constraints kept in state */

            if (nameConstraints != NULL) {

                if (state->nameConstraints == NULL) {

                        state->nameConstraints = nameConstraints;

                } else {

                        PKIX_CHECK(PKIX_PL_Cert_MergeNameConstraints
                                (nameConstraints,
                                state->nameConstraints,
                                &mergedNameConstraints,
                                plContext),
                                PKIX_CERTMERGENAMECONSTRAINTSFAILED);

                        PKIX_DECREF(nameConstraints);
                        PKIX_DECREF(state->nameConstraints);

                        state->nameConstraints = mergedNameConstraints;
                }

                /* Remove Name Constraints Extension OID from list */
                if (unresolvedCriticalExtensions != NULL) {
                        PKIX_CHECK(pkix_List_Remove
                                    (unresolvedCriticalExtensions,
                                    (PKIX_PL_Object *)state->nameConstraintsOID,
                                    plContext),
                                    PKIX_LISTREMOVEFAILED);
                }
            }
        }

        PKIX_CHECK(PKIX_CertChainChecker_SetCertChainCheckerState
                    (checker, (PKIX_PL_Object *)state, plContext),
                    PKIX_CERTCHAINCHECKERSETCERTCHAINCHECKERSTATEFAILED);

cleanup:

        PKIX_DECREF(state);

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

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

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

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

        (state->certsRemaining)--;

        if (state->pathToNameList != NULL) {

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

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

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

        }

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

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

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

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

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

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

                        PKIX_DECREF(name);

                        if (checkPassed == PKIX_TRUE) {

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

                        }
                }

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

                }
        }

        if (state->certsRemaining == 0) {

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

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

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

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

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

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

        }

cleanup:

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

        PKIX_RETURN(CERTCHAINCHECKER);

}