bug 284531 Design new interfaces for certificate path building and verification for libPKIX
authorrrelyea%redhat.com
Tue, 25 Sep 2007 23:48:04 +0000
changeset 8073 6e0353f34c75f20022706c1716621be028d04fd6
parent 8072 c13e8eb5fca49049c1d3e27920525ffaf7b22e61
child 8076 d34b59658e43766ef20513239a1d36c2bd1eb745
push idunknown
push userunknown
push dateunknown
bugs284531
bug 284531 Design new interfaces for certificate path building and verification for libPKIX patch by stevep review by rrelyea.
security/nss/lib/certdb/cert.h
security/nss/lib/certdb/certt.h
security/nss/lib/certhigh/certvfy.c
security/nss/lib/nss/nss.def
--- a/security/nss/lib/certdb/cert.h
+++ b/security/nss/lib/certdb/cert.h
@@ -1591,11 +1591,36 @@ extern SECStatus
 CERT_EncodeCertPoliciesExtension(PRArenaPool *arena,
                                  CERTPolicyInfo **info,
                                  SECItem *dest);
 extern SECStatus
 CERT_EncodeNoticeReference(PRArenaPool *arena,
                            CERTNoticeReference *reference,
                            SECItem *dest);
 
+
+/*
+ * Verify a Cert with libpkix
+ *  paramsIn control the verification options. If a value isn't specified
+ *   in paramsIn, it reverts to the application default.
+ *  paramsOut specifies the parameters the caller would like to get back.
+ *   the caller may pass NULL, in which case no parameters are returned.
+ */
+extern SECStatus CERT_PKIXVerifyCert(
+	CERTCertificate *cert,
+	SECCertificateUsage usages,
+	CERTValInParam *paramsIn,
+	CERTValOutParam *paramsOut,
+	void *wincx);
+/*
+ * This function changes the application defaults for the Verify function.
+ * It should be called once at app initialization time, and only changes
+ * if the default configuration changes.
+ *
+ * This changes the default values for the parameters specified. These
+ * defaults can be overridden in CERT_PKIXVerifyCert() by explicitly 
+ * setting the value in paramsIn.
+ */
+extern SECStatus CERT_PKIXSetDefaults(CERTValInParam *paramsIn);
+
 SEC_END_PROTOS
 
 #endif /* _CERT_H_ */
--- a/security/nss/lib/certdb/certt.h
+++ b/security/nss/lib/certdb/certt.h
@@ -881,16 +881,207 @@ typedef struct {
 /*
  * these types are for the PKIX Policy Constraints extension
  */
 typedef struct {
     SECItem explicitPolicySkipCerts;
     SECItem inhibitMappingSkipCerts;
 } CERTCertificatePolicyConstraints;
 
+
+/*
+ * these types are for the CERT_PKIX* Verification functions
+ * These are all optional parameters.
+ */
+
+typedef enum {
+   cert_pi_end             = 0, /* SPECIAL: signifies end of array of  
+				 * CERTValParam* */
+   cert_pi_nbioContext     = 1, /* specify a non-blocking IO context used to
+			         * resume a session. If this argument is 
+				 * specified, no other arguments should be.
+				 * Specified in value.pointer.p. If the 
+				 * operation completes the context will be 
+				 * freed. */
+   cert_pi_nbioAbort       = 2, /* specify a non-blocking IO context for an 
+				 * existing operation which the caller wants
+			         * to abort. If this argument is 
+				 * specified, no other arguments should be.
+				 * Specified in value.pointer.p. If the 
+			         * operation succeeds the context will be 
+				 * freed. */
+   cert_pi_certList        = 3, /* specify the chain to validate against. If
+				 * this value is given, then the path 
+				 * construction step in the validation is 
+				 * skipped. Specified in value.pointer.chain */
+   cert_pi_policyOID       = 4, /* validate certificate for policy OID.
+				 * Specified in value.array.oids. Cert must
+				 * be good for at least one OID in order
+				 * to validate. Default is no policyOID */
+   cert_pi_policyFlags     = 5, /* flags for each policy specified in policyOID.
+				 * Specified in value.scalar.ul. Policy flags
+				 * apply to all specified oids. 
+				 * Use CERT_POLICY_FLAG_* macros below. If not
+				 * specified policy flags default to 0 */
+   cert_pi_keyusage        = 6, /* specify what the keyusages the certificate 
+				 * will be evaluated against, specified in
+				 * value.scalar.ui. The cert must validate for
+				 * at least one of the specified key usages.
+				 * Values match the KU_  bit flags defined
+				 * in this file. Default is derived from
+				 * the 'usages' function argument */
+   cert_pi_extendedKeyusage= 7, /* specify what the required extended key 
+				 * usage of the certificate. Specified as
+				 * an array of oidTags in value.array.oids.
+				 * The cert must validate for at least one
+				 * of the specified extended key usages.
+				 * If not specified, no extended key usages
+				 * will be checked. */
+   cert_pi_date            = 8, /* validate certificate is valid as of date 
+				 * specified in value.scalar.time. A special 
+				 * value '0' indicates 'now'. default is '0' */
+   cert_pi_revocationFlags = 9, /* Specify what revocation checking to do.
+				 * See CERT_REV_FLAG_* macros below
+				 * Set in value.scalar.ul */
+   cert_pi_certStores      = 10,/* Bitmask of Cert Store flags (see below)
+				 * Set in value.scalar.ui */
+   
+   cert_pi_max                  /* SPECIAL: signifies maximum allowed value,
+				 *  can increase in future releases */
+} CERTValParamInType;
+
+/*
+ * for all out parameters:
+ *  out parameters are only returned if the caller asks for them in
+ *  the CERTValOutParam array. Caller is responsible for the CERTValOutParam
+ *  array itself. The pkix verify function will allocate and other arrays
+ *  pointers, or objects. The Caller is responsible for freeing those results.
+ * If SECWouldBlock is returned, only cert_pi_nbioContext is returned.
+ */
+typedef enum {
+   cert_po_end             = 0, /* SPECIAL: signifies end of array of  
+				 * CERTValParam* */
+   cert_po_nbioContext     = 1, /* Return a nonblocking context. If no
+				 * non-blocking context is specified, then
+				 * blocking IO will be used. 
+				 * Returned in value.pointer.p. The context is 
+				 * freed after an abort or a complete operation.
+				 * This value is only returned on SECWouldBlock.
+				 */
+   cert_po_trustAnchor     = 2, /* Return the trust anchor for the chain that
+				 * was validated. Returned in 
+				 * value.pointer.cert, this value is only 
+				 * returned on SECSuccess. */
+   cert_po_certList        = 3, /* Return the entire chain that was validated.
+				 * Returned in value.pointer.certList. If no 
+				 * chain could be constructed, this value 
+				 * would be NULL. */
+   cert_po_policyOID       = 4, /* Return the policies that were found to be
+				 * valid. Returned in value.array.oids as an 
+				 * array. This is only returned on 
+				 * SECSuccess. */
+   cert_po_errorLog        = 5, /* Return a log of problems with the chain.
+				 * Returned in value.pointer.log  */
+   cert_po_usages          = 6, /* Return what usages the certificate is valid
+				   for. Returned in value.scalar.usages */
+   cert_po_keyUsage        = 7, /* Return what key usages the certificate
+				 * is valid for.
+				 * Returned in value.scalar.usage */
+   cert_po_extendedKeyusage= 8, /* Return what extended key usages the
+				 * certificate is valid for.
+				 * Returned in value.array.oids */
+   cert_po_max                  /* SPECIAL: signifies maximum allowed value,
+				 *  can increase in future releases */
+
+} CERTValParamOutType;
+
+typedef struct CERTValParamInValueStr {
+    union {
+        PRBool   b;
+        PRInt32  i;
+        PRUint32 ui;
+        PRInt64  l;
+        PRUint64 ul;
+        PRTime time;
+    } scalar;
+    union {
+        const void*    p;
+        const char*    s;
+        const CERTCertificate* cert;
+	const CERTCertList *chain;
+    } pointer;
+    union {
+        const PRInt32  *pi;
+        const PRUint32 *pui;
+        const PRInt64  *pl;
+        const PRUint64 *pul;
+	const SECOidTag *oids;
+    } array;
+    int arraySize;
+} CERTValParamInValue;
+
+
+typedef struct CERTValParamOutValueStr {
+    union {
+        PRBool   b;
+        PRInt32  i;
+        PRUint32 ui;
+        PRInt64  l;
+        PRUint64 ul;
+        SECCertificateUsage usages;
+    } scalar;
+    union {
+        void*    p;
+        char*    s;
+	CERTVerifyLog *log;
+        CERTCertificate* cert;
+	CERTCertList *chain;
+    } pointer;
+    union {
+	void 	  *p;
+	SECOidTag *oids;
+    } array;
+    int arraySize;
+} CERTValParamOutValue;
+
+typedef struct {
+    CERTValParamInType type;
+    CERTValParamInValue value;
+} CERTValInParam;
+
+typedef struct {
+    CERTValParamOutType type;
+    CERTValParamOutValue value;
+} CERTValOutParam;
+
+/*
+ * policy flag defines
+ */
+#define CERT_POLICY_FLAG_NO_MAPPING    1
+#define CERT_POLICY_FLAG_EXPLICIT      2
+#define CERT_POLICY_FLAG_NO_ANY        4
+
+/*
+ * revocation flags 
+ */
+#define CERT_REV_FLAG_OCSP              1
+#define CERT_REV_FLAG_OCSP_LEAF_ONLY    2
+#define CERT_REV_FLAG_CRL               4
+#define CERT_REV_FLAG_CRL_LEAF_ONLY     8
+/* set if we don't want to fail because we were unable to get revocation
+ * data */
+#define CERT_REV_FAIL_SOFT           0x10
+#define CERT_REV_NIST		(CERT_REV_FLAG_OCSP|CERT_REV_FLAG_CRL)
+
+/*
+ * CertStore flags
+ */
+#define CERT_ENABLE_LDAP_FETCH          1
+#define CERT_ENABLE_HTTP_FETCH          2
+
 /* XXX Lisa thinks the template declarations belong in cert.h, not here? */
 
 #include "secasn1t.h"	/* way down here because I expect template stuff to
 			 * move out of here anyway */
 
 SEC_BEGIN_PROTOS
 
 extern const SEC_ASN1Template CERT_CertificateRequestTemplate[];
--- a/security/nss/lib/certhigh/certvfy.c
+++ b/security/nss/lib/certhigh/certvfy.c
@@ -40,27 +40,30 @@
 #include "secoid.h"
 #include "sslerr.h"
 #include "genname.h"
 #include "keyhi.h"
 #include "cert.h"
 #include "certdb.h"
 #include "certi.h"
 #include "cryptohi.h"
+#include "pkix.h"
+/*#include "pkix_sample_modules.h" */
+#include "pkix_pl_cert.h"
+
 
 #ifndef NSS_3_4_CODE
 #define NSS_3_4_CODE
 #endif /* NSS_3_4_CODE */
 #include "nsspki.h"
 #include "pkitm.h"
 #include "pkim.h"
 #include "pki3hack.h"
 #include "base.h"
 
-
 /*
  * Check the validity times of a certificate
  */
 SECStatus
 CERT_CertTimesValid(CERTCertificate *c)
 {
     SECCertTimeValidity valid = CERT_CheckCertValidTimes(c, PR_Now(), PR_TRUE);
     return (valid == secCertTimeValid) ? SECSuccess : SECFailure;
@@ -2054,8 +2057,600 @@ CERT_GetCertChainFromCert(CERTCertificat
 
 	cert = CERT_FindCertIssuer(cert, time, usage);
     }
 
     /* return partial chain */
     PORT_SetError(SEC_ERROR_UNKNOWN_ISSUER);
     return chain;
 }
+
+
+
+PKIX_CertSelector *
+cert_GetTargetCertConstraints(CERTCertificate *target, void *plContext) 
+{
+    PKIX_ComCertSelParams *certSelParams = NULL;
+    PKIX_CertSelector *certSelector = NULL;
+    PKIX_CertSelector *r= NULL;
+    PKIX_PL_Cert *eeCert = NULL;
+    PKIX_Error *error = NULL;
+
+    pkix_pl_Cert_CreateWithNSSCert
+	(target, &eeCert, plContext);
+
+
+    error = PKIX_ComCertSelParams_Create(&certSelParams, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_ComCertSelParams_SetCertificate(
+				certSelParams, eeCert, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_CertSelector_Create(NULL, NULL, &certSelector, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_CertSelector_SetCommonCertSelectorParams
+	(certSelector, certSelParams, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certSelParams, plContext);
+    if (error == NULL) r = certSelParams;
+
+cleanup:
+    if (certSelParams != NULL) 
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelParams, plContext);
+
+    if (eeCert != NULL) 
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)eeCert, plContext);
+
+    if (certSelParams != NULL) 
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelParams, plContext);
+
+    return r;
+}
+
+
+PKIX_List *
+CERT_GetCertStores(void *plContext)
+{
+    PKIX_CertStore *certStore = NULL;
+    PKIX_List *certStores = NULL;
+    PKIX_List *r = NULL;
+    PKIX_Error *error = NULL;
+
+    error = PKIX_PL_Pk11CertStore_Create(&certStore, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_List_Create(&certStores, plContext);
+    if (error != NULL)  goto cleanup;
+
+    error = PKIX_List_AppendItem( certStores, 
+			  (PKIX_PL_Object *)certStore, plContext);
+    if (error != NULL)  goto cleanup;
+
+    error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)certStores, plContext);
+    if (error == NULL) r = certStores;
+
+cleanup:
+    if (certStores != NULL) 
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
+
+    if (certStore != NULL) 
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStore, plContext);
+
+    return r;
+}
+
+
+/* XXX
+ *  There is no NSS SECItem -> PKIX OID
+ *  conversion function. For now, I go via the ascii
+ *  representation 
+ *  this should be in PKIX_PL_*
+ */
+
+PKIX_PL_OID *
+CERT_PKIXOIDFromNSSOid(SECOidTag tag, void*plContext)
+{
+    char *oidstring = NULL;
+    char *oidstring_adj = NULL;
+    PKIX_PL_OID *policyOID = NULL;
+    SECOidData *data;
+
+    data =  SECOID_FindOIDByTag(tag);
+    if (data != NULL) {
+	oidstring = CERT_GetOidString(&data->oid);
+	if (oidstring == NULL) {
+	    goto cleanup;
+	}
+	oidstring_adj = oidstring;
+	if (PORT_Strncmp("OID.",oidstring_adj,4) == 0) {
+	    oidstring_adj += 4;
+	}
+
+	PKIX_PL_OID_Create(oidstring_adj, &policyOID, plContext);
+    }
+cleanup:
+    if (oidstring != NULL) PR_smprintf_free(oidstring);
+
+    return policyOID;
+}
+
+
+struct fake_PKIX_PL_CertStruct {
+	CERTCertificate *nssCert;
+};
+
+/* This needs to be part of the PKIX_PL_* */
+/* This definitely needs to go away, and be replaced with
+   a real accessor function in PKIX */
+CERTCertificate *
+cert_NSSCertFromPKIXCert(const PKIX_PL_Cert *pkix_cert, void *plContext)
+{
+    struct fake_PKIX_PL_CertStruct *fcert = NULL;
+
+    fcert = (struct fake_PKIX_PL_CertStruct*)pkix_cert;
+
+    return CERT_DupCertificate(fcert->nssCert);
+}
+
+
+
+
+PKIX_List *cert_PKIXMakeOIDList(const SECOidTag *oids, int oidCount, void *plContext)
+{
+    PKIX_List *r = NULL;
+    PKIX_List *policyList = NULL;
+    PKIX_PL_OID *policyOID = NULL;
+    PKIX_Error *error = NULL;
+    int i;
+
+    PKIX_List_Create(&policyList, plContext);
+
+    for (i=0; i<oidCount; i++) {
+	policyOID = CERT_PKIXOIDFromNSSOid(oids[i],plContext);
+	if (policyOID == NULL) {
+	    goto cleanup;
+	}
+	error = PKIX_List_AppendItem(policyList, 
+		(PKIX_PL_Object *)policyOID, plContext);
+	if (error != NULL) {
+	    PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOID, plContext);
+	    goto cleanup;
+	}
+    }
+
+    error = PKIX_List_SetImmutable(policyList, plContext);
+    if (error != NULL) goto cleanup;
+
+    error = PKIX_PL_Object_IncRef((PKIX_PL_Object *)policyList, plContext);
+    if (error == NULL) r = policyList;
+
+cleanup:
+    if (policyList != NULL)  {
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyList, plContext);
+    }
+
+    return r;
+}
+
+CERTValOutParam *
+cert_pkix_FindOutputParam(const CERTValOutParam *params, const CERTValParamOutType t)
+{
+    CERTValOutParam *i;
+    if (params == NULL) {
+	return NULL;
+    }
+    for (i = params; i->type != cert_po_end; i++) {
+	if (i->type == t) {
+	     return i;
+	}
+    }
+    return NULL;
+}
+
+
+
+
+
+SECStatus
+cert_pkixSetParam(PKIX_ProcessingParams *procParams, 
+  const CERTValInParam *param, void *plContext)
+{
+    PKIX_Error * error = NULL;
+    SECStatus r=SECSuccess;
+    PKIX_PL_Date *d = NULL;
+    PKIX_List *policyOIDList = NULL;
+
+    /* XXX we need a way to map generic PKIX error to generic NSS errors */
+
+    switch (param->type) {
+
+	case cert_pi_policyOID:
+
+	    /* needed? */
+	    error = PKIX_ProcessingParams_SetExplicitPolicyRequired(
+		    		procParams, PKIX_TRUE, plContext);
+
+	    if (error != NULL) { 
+		r = SECFailure;
+		break;
+	    }
+
+	    policyOIDList = cert_PKIXMakeOIDList(param->value.array.oids,
+				param->value.arraySize,plContext);
+
+	    error = PKIX_ProcessingParams_SetInitialPolicies(
+				procParams,policyOIDList,plContext);
+	    if (error != NULL)  {
+		r = SECFailure;
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	    }
+	    break;
+
+	case cert_pi_date:
+	    if (param->value.scalar.time == 0) {
+		error = PKIX_PL_Date_Create_UTCTime(NULL, &d, plContext);
+	    } else {
+		error = pkix_pl_Date_CreateFromPRTime( param->value.scalar.time,
+						       &d, plContext);
+		if (error != NULL) {
+		    PORT_SetError(SEC_ERROR_INVALID_TIME);
+		    r = SECFailure;
+		}
+	    }
+
+	    error = PKIX_ProcessingParams_SetDate( procParams, d, plContext );
+	    if (error != NULL) {
+		PORT_SetError(SEC_ERROR_INVALID_TIME);
+		r = SECFailure;
+	    }
+	    break;
+	    /*
+	       case cvpt_revCheckRequired:
+	       error = PKIX_ProcessingParams_SetRevocationEnabled(
+	       procParams, param->value.b?PKIX_TRUE:PKIX_FALSE, plContext);
+
+	       if (error != NULL) r = SECFailure;
+	       break;
+	     */
+
+	default:
+	    r = SECFailure;
+	    PORT_SetError(SEC_ERROR_INVALID_ARGS);
+    }
+
+    if (policyOIDList != NULL)
+	PKIX_PL_Object_DecRef((PKIX_PL_Object *)policyOIDList, plContext);
+
+    if (d != NULL) PKIX_PL_Object_DecRef((PKIX_PL_Object *)d, plContext);
+
+    return r; 
+
+    }
+
+#define EV_TEST_HACK 1
+#ifdef EV_TEST_HACK
+
+/*  This function checks if the certificate asserts the given policy oid.
+ *  It does not check if the certificate is authorized to assert that oid.
+ *
+ *  This function is mainly here for testing purposes, to support the
+ *  EV_HACK_INSECURE_OID_CHECK mode.
+ *
+ */
+
+SECStatus
+cert_hasPolicy(CERTCertificate *cert, SECOidTag tag)
+{
+    SECStatus r=SECFailure;
+    SECStatus rv=SECFailure;
+    SECItem policyItem = {siBuffer,0};
+    CERTPolicyInfo **cpi=NULL;
+    CERTCertificatePolicies *policyExt = NULL;
+    SECOidTag tagincert;
+
+
+    rv = CERT_FindCertExtension(cert, SEC_OID_X509_CERTIFICATE_POLICIES,
+				&policyItem);
+    if (rv != SECSuccess) {
+	PORT_SetError(SEC_ERROR_EXTENSION_NOT_FOUND);
+	return SECFailure;
+    }
+
+    policyExt = CERT_DecodeCertificatePoliciesExtension(&policyItem);
+    if (policyExt == NULL) goto loser;
+
+    for (cpi = policyExt->policyInfos; *cpi; cpi++) {
+	tagincert = SECOID_FindOIDTag(&(*cpi)->policyID);
+	if (tagincert == tag) {
+	    r = SECSuccess; 
+	    break;
+	}
+    }
+
+loser:
+    if (policyExt != NULL) CERT_DestroyCertificatePoliciesExtension(policyExt);
+    if (policyItem.data) PORT_Free(policyItem.data);
+    return r;
+
+}
+
+
+/* determine which EV test mode we are in by reading an environment variable
+ * 'NSS_EV_TEST_HACK'.
+ */
+#define EV_HACK_ALWAYS_FAIL 0
+#define EV_HACK_USE_PKIX 1
+#define EV_HACK_INSECURE_OID_CHECK 2
+
+int cert_GetEVMode()
+{
+    static int firsttime = 1;
+    static char *mode_string = NULL;
+    static int mode = EV_HACK_ALWAYS_FAIL;
+
+    if (firsttime) {
+	firsttime = 0;
+#if (defined(XP_UNIX) || defined(XP_WIN32) || defined(XP_BEOS)) && !defined(_WIN32_WCE)
+	mode_string = getenv("NSS_EV_TEST_HACK");
+#endif
+	if (mode_string != NULL) {
+	    if (PORT_Strcmp(mode_string, "ALWAYS_FAIL") == 0) {
+		mode = EV_HACK_ALWAYS_FAIL;
+	    } else if (PORT_Strcmp(mode_string, "USE_PKIX") == 0) {
+		mode = EV_HACK_USE_PKIX;
+	    } else if (PORT_Strcmp(mode_string, "INSECURE_OID_CHECK") == 0) {
+		mode = EV_HACK_INSECURE_OID_CHECK;
+	    }
+	}
+    }
+    return mode;
+}
+
+#endif
+
+/*
+ * CERT_PKIXVerifyCert
+ *
+ * Verify a Certificate using the PKIX library.
+ *
+ * Parameters:
+ *  cert    - the target certificate to verify. Must be non-null
+ *  params  - an array of type/value parameters which can be
+ *            used to modify the behavior of the validation
+ *            algorithm, or supply additional constraints.
+ *
+ *  outputTrustAnchor - the trust anchor which the certificate
+ *                      chains to. The caller is responsible
+ *                      for freeing this.
+ *
+ * Example Usage:
+ *    CERTValParam args[3];
+ *    args[0].type = cvpt_policyOID;
+ *    args[0].value.si = oid;
+ *    args[1].type = revCheckRequired;
+ *    args[1].value.b = PR_TRUE;
+ *    args[2].type = cvpt_end;
+ *
+ *    CERT_PKIXVerifyCert(cert, &output, args
+ *
+ *
+ * NOTE: Currently, the behavior of this function can be modified
+ *  to allow for testing, using the environment variable
+ *  'NSS_EV_TEST_HACK'. This variable can have the following values,
+ *
+ *    ALWAYS_FAIL  - always returns SECFailure (default)
+ *
+ *    INSECURE_OID_CHECK  - do no validation, just check if the
+ *                          target cert has the policy OID, if
+ *                          specified
+ *
+ *    USE_PKIX     - use PKIX calls, validating the full chain
+ *  
+ */
+SECStatus CERT_PKIXVerifyCert(
+ CERTCertificate *cert,
+ SECCertificateUsage usages,
+ CERTValInParam *paramsIn,
+ CERTValOutParam *paramsOut,
+ void *wincx)
+{
+    SECStatus             r = SECFailure;
+    PKIX_List *           anchors = NULL;
+    PKIX_Error *          error = NULL;
+    PKIX_ProcessingParams *procParams = NULL;
+    PKIX_BuildResult *    buildResult = NULL;
+    void *                nbioContext = NULL;  /* for non-blocking IO */
+    void *                buildState = NULL;   /* for non-blocking IO */
+    PKIX_CertSelector *   certSelector = NULL;
+    PKIX_List *           certStores = NULL;
+    PKIX_ValidateResult * valResult = NULL;
+    PKIX_TrustAnchor *    trustAnchor = NULL;
+    PKIX_PL_Cert *        trustAnchorCert = NULL;
+    CERTValInParam *      param = NULL;
+    CERTValOutParam *     oparam = NULL;
+    int                   mode = EV_HACK_ALWAYS_FAIL;
+    int i=0;
+
+    void *plContext = NULL;
+
+#ifdef EV_TEST_HACK
+
+    /* XXX - check temporary env variable - this needs to go away */
+    mode = cert_GetEVMode();
+
+    if (mode == EV_HACK_ALWAYS_FAIL) {
+	/* this error is probably too generic - need to create specific
+     policy error codes */
+	PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
+	goto cleanup;
+    }
+
+    /* XXX This needs to go away */
+    if (mode == EV_HACK_INSECURE_OID_CHECK) {
+	if (paramsIn != NULL) {
+	    for (i=0; paramsIn[i].type != cert_pi_end; i++) {
+		if (paramsIn[i].type == cert_pi_policyOID) {
+		    param = &paramsIn[i];
+		}
+	    }
+	    if (param == NULL) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		goto cleanup;
+	    }
+	    for (i=0; i<param->value.arraySize; i++) {
+		if (cert_hasPolicy(cert,param->value.array.oids[i]) == SECSuccess) {
+		    CERTCertList *certChain = NULL;
+		    CERTCertListNode *node = NULL;
+		    CERTCertListNode *next_node = NULL;
+
+		    oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_trustAnchor);
+		    if (oparam != NULL) {
+			certChain = CERT_GetCertChainFromCert(cert, PR_Now(), 
+				usages);
+			for (node = CERT_LIST_HEAD(certChain);
+				!CERT_LIST_END(node, certChain);
+				node = next_node) {
+			    next_node = CERT_LIST_NEXT(node);
+			    if (CERT_LIST_END(next_node, certChain)) {
+				/* We arrived at the top level cert */
+				oparam->value.pointer.cert = 
+				    CERT_DupCertificate(node->cert);
+			    }
+			}
+			CERT_DestroyCertList(certChain);
+		    }
+		    r = SECSuccess;
+		    goto cleanup;
+		}
+	    }
+	    PORT_SetError(SEC_ERROR_INADEQUATE_CERT_TYPE);
+	    goto cleanup;
+	}
+    }
+
+    if (mode != EV_HACK_USE_PKIX) {
+	PORT_SetError(SEC_ERROR_INVALID_ARGS);
+	goto cleanup;
+    }
+#endif
+
+    /* From this point on, we are going to do a PKIX validation */
+
+    error = PKIX_PL_NssContext_Create(
+            0, PR_FALSE /*use arena*/, wincx, &plContext);
+    if (error != NULL) {        /* need pkix->nss error map */
+	PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
+	goto cleanup;
+    }
+
+
+    /* The 'anchors' parameter must be supplied, but it can be an 
+       empty list. PKIX will use the NSS trust database to form
+       the anchors list */
+    PKIX_List_Create(&anchors, plContext);
+    error = PKIX_ProcessingParams_Create(anchors, &procParams, plContext);
+    if (error != NULL) {              /* need pkix->nss error map */
+	PORT_SetError(SEC_ERROR_CERT_NOT_VALID);
+	goto cleanup;
+    }
+
+
+    /* now process the extensible input parameters structure */
+    if (paramsIn != NULL) {
+	i=0;
+	while (paramsIn[i].type != cert_pi_end) {
+	    if (paramsIn[i].type >= cert_pi_max) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		goto cleanup;
+	    }
+	    if (cert_pkixSetParam(procParams,
+                     &paramsIn[i],plContext) != SECSuccess) {
+		PORT_SetError(SEC_ERROR_INVALID_ARGS);
+		goto cleanup;
+	    }
+	    i++;
+	}
+    }
+
+
+    certSelector = cert_GetTargetCertConstraints(cert, plContext);
+    error = PKIX_ProcessingParams_SetTargetCertConstraints
+	(procParams, certSelector, plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);    /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    certStores = CERT_GetCertStores(plContext);
+    error = PKIX_ProcessingParams_SetCertStores
+	(procParams, certStores, plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);   /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    error = PKIX_BuildChain( procParams, &nbioContext,
+                             &buildState, &buildResult, NULL,
+	    plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);  /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    error = PKIX_BuildResult_GetValidateResult( buildResult, &valResult,
+                                                plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);  /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    error = PKIX_ValidateResult_GetTrustAnchor( valResult, &trustAnchor,
+                                                plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);  /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    error = PKIX_TrustAnchor_GetTrustedCert( trustAnchor, &trustAnchorCert,
+                                                plContext);
+    if (error != NULL) {
+	PORT_SetError(SEC_ERROR_IO);   /* need pkix->nss error map */
+	goto cleanup;
+    }
+
+    oparam = cert_pkix_FindOutputParam(paramsOut, cert_po_trustAnchor);
+    if (oparam != NULL) {
+	oparam->value.pointer.cert = 
+		cert_NSSCertFromPKIXCert(trustAnchorCert,plContext);
+    }
+
+    r = SECSuccess;
+
+cleanup:
+    if (procParams != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)procParams, plContext);
+
+    if (trustAnchorCert != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchorCert, plContext);
+
+    if (trustAnchor != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)trustAnchor, plContext);
+
+    if (valResult != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)valResult, plContext);
+
+    if (buildResult != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)buildResult, plContext);
+
+    if (certStores != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)certStores, plContext);
+
+    if (certSelector != NULL) 
+       PKIX_PL_Object_DecRef((PKIX_PL_Object *)certSelector, plContext);
+
+    PKIX_PL_NssContext_Destroy(plContext);
+
+    return r;
+}
+
--- a/security/nss/lib/nss/nss.def
+++ b/security/nss/lib/nss/nss.def
@@ -907,16 +907,17 @@ CERT_EncodeInfoAccessExtension;
 CERT_EncodeInhibitAnyExtension;
 CERT_EncodeNoticeReference;
 CERT_EncodePolicyConstraintsExtension;
 CERT_EncodePolicyMappingExtension;
 CERT_EncodeUserNotice;
 CERT_FindCRLEntryReasonExten;
 CERT_FindCRLNumberExten;
 CERT_FindNameConstraintsExten;
+CERT_PKIXVerifyCert;
 PK11_GetAllSlotsForCert;
 PK11_GenerateKeyPairWithOpFlags;
 SEC_GetRegisteredHttpClient;
 SEC_StringToOID;
 SECKEY_ECParamsToKeySize;
 SECKEY_ECParamsToBasePointOrderLen;
 SECMOD_DeleteModuleEx;
 VFY_CreateContextDirect;