michael@0: // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: // This Source Code Form is subject to the terms of the Mozilla Public michael@0: // License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: // file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: michael@0: "use strict"; michael@0: michael@0: // XXX: The isDebugBuild tests you see are here because the test EV root is michael@0: // only enabled for EV in debug builds, as a security measure. An ugly hack. michael@0: michael@0: do_get_profile(); // must be called before getting nsIX509CertDB michael@0: const certdb = Cc["@mozilla.org/security/x509certdb;1"] michael@0: .getService(Ci.nsIX509CertDB); michael@0: michael@0: const evrootnick = "XPCShell EV Testing (untrustworthy) CA - Mozilla - " + michael@0: "EV debug test CA"; michael@0: michael@0: // This is the list of certificates needed for the test michael@0: // The certificates prefixed by 'int-' are intermediates michael@0: let certList = [ michael@0: // Test for successful EV validation michael@0: 'int-ev-valid', michael@0: 'ev-valid', michael@0: 'ev-valid-anypolicy-int', michael@0: 'int-ev-valid-anypolicy-int', michael@0: 'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url michael@0: // but that contains a valid CRLDP. michael@0: michael@0: // Testing a root that looks like EV but is not EV enabled michael@0: 'int-non-ev-root', michael@0: 'non-ev-root', michael@0: ] michael@0: michael@0: function load_ca(ca_name) { michael@0: var ca_filename = ca_name + ".der"; michael@0: addCertFromFile(certdb, "test_ev_certs/" + ca_filename, 'CTu,CTu,CTu'); michael@0: } michael@0: michael@0: const SERVER_PORT = 8888; michael@0: michael@0: function failingOCSPResponder() { michael@0: return getFailingHttpServer(SERVER_PORT, michael@0: ["www.example.com", "crl.example.com"]); michael@0: } michael@0: michael@0: function start_ocsp_responder(expectedCertNames) { michael@0: let expectedPaths = expectedCertNames.slice(); michael@0: return startOCSPResponder(SERVER_PORT, "www.example.com", ["crl.example.com"], michael@0: "test_ev_certs", expectedCertNames, expectedPaths); michael@0: } michael@0: michael@0: function check_cert_err(cert_name, expected_error) { michael@0: let cert = certdb.findCertByNickname(null, cert_name); michael@0: let hasEVPolicy = {}; michael@0: let verifiedChain = {}; michael@0: let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, michael@0: NO_FLAGS, verifiedChain, hasEVPolicy); michael@0: do_check_eq(error, expected_error); michael@0: } michael@0: michael@0: michael@0: function check_ee_for_ev(cert_name, expected_ev) { michael@0: let cert = certdb.findCertByNickname(null, cert_name); michael@0: let hasEVPolicy = {}; michael@0: let verifiedChain = {}; michael@0: let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, michael@0: NO_FLAGS, verifiedChain, hasEVPolicy); michael@0: do_check_eq(hasEVPolicy.value, expected_ev); michael@0: do_check_eq(0, error); michael@0: } michael@0: michael@0: function run_test() { michael@0: for (let i = 0 ; i < certList.length; i++) { michael@0: let cert_filename = certList[i] + ".der"; michael@0: addCertFromFile(certdb, "test_ev_certs/" + cert_filename, ',,'); michael@0: } michael@0: load_ca("evroot"); michael@0: load_ca("non-evroot-ca"); michael@0: michael@0: // setup and start ocsp responder michael@0: Services.prefs.setCharPref("network.dns.localDomains", michael@0: 'www.example.com, crl.example.com'); michael@0: add_tests_in_mode(true); michael@0: add_tests_in_mode(false); michael@0: run_next_test(); michael@0: } michael@0: michael@0: function add_tests_in_mode(useMozillaPKIX) michael@0: { michael@0: add_test(function () { michael@0: Services.prefs.setBoolPref("security.use_mozillapkix_verification", michael@0: useMozillaPKIX); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: let ocspResponder = start_ocsp_responder( michael@0: isDebugBuild ? ["int-ev-valid", "ev-valid"] michael@0: : ["ev-valid"]); michael@0: check_ee_for_ev("ev-valid", isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: michael@0: let ocspResponder = start_ocsp_responder( michael@0: isDebugBuild ? ["int-ev-valid-anypolicy-int", "ev-valid-anypolicy-int"] michael@0: : ["ev-valid-anypolicy-int"]); michael@0: check_ee_for_ev("ev-valid-anypolicy-int", isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: add_test(function() { michael@0: clearOCSPCache(); michael@0: let ocspResponder = start_ocsp_responder(["non-ev-root"]); michael@0: check_ee_for_ev("non-ev-root", false); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: add_test(function() { michael@0: clearOCSPCache(); michael@0: // libpkix will attempt to validate the intermediate, which does have an michael@0: // OCSP URL. michael@0: let ocspResponder = isDebugBuild ? start_ocsp_responder(["int-ev-valid"]) michael@0: : failingOCSPResponder(); michael@0: check_ee_for_ev("no-ocsp-url-cert", false); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: // bug 917380: Chcek that an untrusted EV root is untrusted. michael@0: const nsIX509Cert = Ci.nsIX509Cert; michael@0: add_test(function() { michael@0: let evRootCA = certdb.findCertByNickname(null, evrootnick); michael@0: certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, 0); michael@0: michael@0: clearOCSPCache(); michael@0: let ocspResponder = failingOCSPResponder(); michael@0: check_cert_err("ev-valid", michael@0: useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER michael@0: : SEC_ERROR_UNTRUSTED_ISSUER); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: // bug 917380: Chcek that a trusted EV root is trusted after disabling and michael@0: // re-enabling trust. michael@0: add_test(function() { michael@0: let evRootCA = certdb.findCertByNickname(null, evrootnick); michael@0: certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, michael@0: Ci.nsIX509CertDB.TRUSTED_SSL | michael@0: Ci.nsIX509CertDB.TRUSTED_EMAIL | michael@0: Ci.nsIX509CertDB.TRUSTED_OBJSIGN); michael@0: michael@0: clearOCSPCache(); michael@0: let ocspResponder = start_ocsp_responder( michael@0: isDebugBuild ? ["int-ev-valid", "ev-valid"] michael@0: : ["ev-valid"]); michael@0: check_ee_for_ev("ev-valid", isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: add_test(function () { michael@0: check_no_ocsp_requests("ev-valid", michael@0: useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED michael@0: : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE michael@0: : SEC_ERROR_EXTENSION_NOT_FOUND)); michael@0: }); michael@0: michael@0: add_test(function () { michael@0: check_no_ocsp_requests("non-ev-root", michael@0: useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED michael@0: : (isDebugBuild ? SEC_ERROR_UNTRUSTED_ISSUER michael@0: : SEC_ERROR_EXTENSION_NOT_FOUND)); michael@0: }); michael@0: michael@0: add_test(function () { michael@0: check_no_ocsp_requests("no-ocsp-url-cert", michael@0: useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED michael@0: : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE michael@0: : SEC_ERROR_EXTENSION_NOT_FOUND)); michael@0: }); michael@0: michael@0: michael@0: // Test the EV continues to work with flags after successful EV verification michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: let ocspResponder = start_ocsp_responder( michael@0: isDebugBuild ? ["int-ev-valid", "ev-valid"] michael@0: : ["ev-valid"]); michael@0: check_ee_for_ev("ev-valid", isDebugBuild); michael@0: ocspResponder.stop(function () { michael@0: // without net it must be able to EV verify michael@0: let failingOcspResponder = failingOCSPResponder(); michael@0: let cert = certdb.findCertByNickname(null, "ev-valid"); michael@0: let hasEVPolicy = {}; michael@0: let verifiedChain = {}; michael@0: let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | michael@0: Ci.nsIX509CertDB.FLAG_MUST_BE_EV; michael@0: michael@0: let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, michael@0: flags, verifiedChain, hasEVPolicy); michael@0: do_check_eq(hasEVPolicy.value, isDebugBuild); michael@0: do_check_eq(error, michael@0: isDebugBuild ? 0 michael@0: : (useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED michael@0: : SEC_ERROR_EXTENSION_NOT_FOUND)); michael@0: failingOcspResponder.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: // Bug 991815 old but valid intermediates are OK michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], michael@0: "test_ev_certs", michael@0: isDebugBuild ? ["int-ev-valid", "ev-valid"] michael@0: : ["ev-valid"], michael@0: [], [], michael@0: isDebugBuild ? ["longvalidityalmostold", "good"] michael@0: : ["good"]); michael@0: check_ee_for_ev("ev-valid", isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: // Bug 991815 old but valid end-entities are NOT OK for EV michael@0: // Unfortunatelly because of soft-fail we consider these OK for DV michael@0: // libpkix does not enforce the age restriction and thus EV is valid michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: // Since Mozilla::pkix does not consider the old amost invalid OCSP michael@0: // response valid, it does not cache the old response and thus michael@0: // makes a separate request for DV michael@0: let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; michael@0: let debugResponseArray = ["good", "longvalidityalmostold", michael@0: "longvalidityalmostold"]; michael@0: if (!useMozillaPKIX) { michael@0: debugCertNickArray = ["int-ev-valid", "ev-valid"]; michael@0: debugResponseArray = ["good", "longvalidityalmostold"]; michael@0: } michael@0: let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], michael@0: "test_ev_certs", michael@0: isDebugBuild ? debugCertNickArray : ["ev-valid"], michael@0: [], [], michael@0: isDebugBuild ? debugResponseArray michael@0: : ["longvalidityalmostold"]); michael@0: check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: michael@0: // Bug 991815 Valid but Ancient (almost two year old) responses are Not OK for michael@0: // EV (still OK for soft fail DV) michael@0: add_test(function () { michael@0: clearOCSPCache(); michael@0: let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; michael@0: let debugResponseArray = ["good", "ancientstillvalid", michael@0: "ancientstillvalid"]; michael@0: if (!useMozillaPKIX) { michael@0: debugCertNickArray = ["int-ev-valid", "ev-valid"]; michael@0: debugResponseArray = ["good", "ancientstillvalid"]; michael@0: } michael@0: let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], michael@0: "test_ev_certs", michael@0: isDebugBuild ? debugCertNickArray : ["ev-valid"], michael@0: [], [], michael@0: isDebugBuild ? debugResponseArray michael@0: : ["ancientstillvalid"]); michael@0: check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); michael@0: ocspResponder.stop(run_next_test); michael@0: }); michael@0: } michael@0: michael@0: // bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert michael@0: // to prevent spurious OCSP requests that race with OCSP stapling. michael@0: // This has the side-effect of saying an EV certificate is not EV if michael@0: // it hasn't already been verified (e.g. on the verification thread when michael@0: // connecting to a site). michael@0: // This flag is mostly a hack that should be removed once FLAG_LOCAL_ONLY michael@0: // works as intended. michael@0: function check_no_ocsp_requests(cert_name, expected_error) { michael@0: clearOCSPCache(); michael@0: let ocspResponder = failingOCSPResponder(); michael@0: let cert = certdb.findCertByNickname(null, cert_name); michael@0: let hasEVPolicy = {}; michael@0: let verifiedChain = {}; michael@0: let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | michael@0: Ci.nsIX509CertDB.FLAG_MUST_BE_EV; michael@0: let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, flags, michael@0: verifiedChain, hasEVPolicy); michael@0: // Since we're not doing OCSP requests, no certificate will be EV. michael@0: do_check_eq(hasEVPolicy.value, false); michael@0: do_check_eq(expected_error, error); michael@0: // Also check that isExtendedValidation doesn't cause OCSP requests. michael@0: let identityInfo = cert.QueryInterface(Ci.nsIIdentityInfo); michael@0: do_check_eq(identityInfo.isExtendedValidation, false); michael@0: ocspResponder.stop(run_next_test); michael@0: } michael@0: