1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/manager/ssl/tests/unit/test_ev_certs.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,299 @@ 1.4 +// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 +// This Source Code Form is subject to the terms of the Mozilla Public 1.6 +// License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 +// file, You can obtain one at http://mozilla.org/MPL/2.0/. 1.8 + 1.9 +"use strict"; 1.10 + 1.11 +// XXX: The isDebugBuild tests you see are here because the test EV root is 1.12 +// only enabled for EV in debug builds, as a security measure. An ugly hack. 1.13 + 1.14 +do_get_profile(); // must be called before getting nsIX509CertDB 1.15 +const certdb = Cc["@mozilla.org/security/x509certdb;1"] 1.16 + .getService(Ci.nsIX509CertDB); 1.17 + 1.18 +const evrootnick = "XPCShell EV Testing (untrustworthy) CA - Mozilla - " + 1.19 + "EV debug test CA"; 1.20 + 1.21 +// This is the list of certificates needed for the test 1.22 +// The certificates prefixed by 'int-' are intermediates 1.23 +let certList = [ 1.24 + // Test for successful EV validation 1.25 + 'int-ev-valid', 1.26 + 'ev-valid', 1.27 + 'ev-valid-anypolicy-int', 1.28 + 'int-ev-valid-anypolicy-int', 1.29 + 'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url 1.30 + // but that contains a valid CRLDP. 1.31 + 1.32 + // Testing a root that looks like EV but is not EV enabled 1.33 + 'int-non-ev-root', 1.34 + 'non-ev-root', 1.35 +] 1.36 + 1.37 +function load_ca(ca_name) { 1.38 + var ca_filename = ca_name + ".der"; 1.39 + addCertFromFile(certdb, "test_ev_certs/" + ca_filename, 'CTu,CTu,CTu'); 1.40 +} 1.41 + 1.42 +const SERVER_PORT = 8888; 1.43 + 1.44 +function failingOCSPResponder() { 1.45 + return getFailingHttpServer(SERVER_PORT, 1.46 + ["www.example.com", "crl.example.com"]); 1.47 +} 1.48 + 1.49 +function start_ocsp_responder(expectedCertNames) { 1.50 + let expectedPaths = expectedCertNames.slice(); 1.51 + return startOCSPResponder(SERVER_PORT, "www.example.com", ["crl.example.com"], 1.52 + "test_ev_certs", expectedCertNames, expectedPaths); 1.53 +} 1.54 + 1.55 +function check_cert_err(cert_name, expected_error) { 1.56 + let cert = certdb.findCertByNickname(null, cert_name); 1.57 + let hasEVPolicy = {}; 1.58 + let verifiedChain = {}; 1.59 + let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, 1.60 + NO_FLAGS, verifiedChain, hasEVPolicy); 1.61 + do_check_eq(error, expected_error); 1.62 +} 1.63 + 1.64 + 1.65 +function check_ee_for_ev(cert_name, expected_ev) { 1.66 + let cert = certdb.findCertByNickname(null, cert_name); 1.67 + let hasEVPolicy = {}; 1.68 + let verifiedChain = {}; 1.69 + let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, 1.70 + NO_FLAGS, verifiedChain, hasEVPolicy); 1.71 + do_check_eq(hasEVPolicy.value, expected_ev); 1.72 + do_check_eq(0, error); 1.73 +} 1.74 + 1.75 +function run_test() { 1.76 + for (let i = 0 ; i < certList.length; i++) { 1.77 + let cert_filename = certList[i] + ".der"; 1.78 + addCertFromFile(certdb, "test_ev_certs/" + cert_filename, ',,'); 1.79 + } 1.80 + load_ca("evroot"); 1.81 + load_ca("non-evroot-ca"); 1.82 + 1.83 + // setup and start ocsp responder 1.84 + Services.prefs.setCharPref("network.dns.localDomains", 1.85 + 'www.example.com, crl.example.com'); 1.86 + add_tests_in_mode(true); 1.87 + add_tests_in_mode(false); 1.88 + run_next_test(); 1.89 +} 1.90 + 1.91 +function add_tests_in_mode(useMozillaPKIX) 1.92 +{ 1.93 + add_test(function () { 1.94 + Services.prefs.setBoolPref("security.use_mozillapkix_verification", 1.95 + useMozillaPKIX); 1.96 + run_next_test(); 1.97 + }); 1.98 + 1.99 + add_test(function () { 1.100 + clearOCSPCache(); 1.101 + let ocspResponder = start_ocsp_responder( 1.102 + isDebugBuild ? ["int-ev-valid", "ev-valid"] 1.103 + : ["ev-valid"]); 1.104 + check_ee_for_ev("ev-valid", isDebugBuild); 1.105 + ocspResponder.stop(run_next_test); 1.106 + }); 1.107 + 1.108 + 1.109 + add_test(function () { 1.110 + clearOCSPCache(); 1.111 + 1.112 + let ocspResponder = start_ocsp_responder( 1.113 + isDebugBuild ? ["int-ev-valid-anypolicy-int", "ev-valid-anypolicy-int"] 1.114 + : ["ev-valid-anypolicy-int"]); 1.115 + check_ee_for_ev("ev-valid-anypolicy-int", isDebugBuild); 1.116 + ocspResponder.stop(run_next_test); 1.117 + }); 1.118 + 1.119 + add_test(function() { 1.120 + clearOCSPCache(); 1.121 + let ocspResponder = start_ocsp_responder(["non-ev-root"]); 1.122 + check_ee_for_ev("non-ev-root", false); 1.123 + ocspResponder.stop(run_next_test); 1.124 + }); 1.125 + 1.126 + add_test(function() { 1.127 + clearOCSPCache(); 1.128 + // libpkix will attempt to validate the intermediate, which does have an 1.129 + // OCSP URL. 1.130 + let ocspResponder = isDebugBuild ? start_ocsp_responder(["int-ev-valid"]) 1.131 + : failingOCSPResponder(); 1.132 + check_ee_for_ev("no-ocsp-url-cert", false); 1.133 + ocspResponder.stop(run_next_test); 1.134 + }); 1.135 + 1.136 + // bug 917380: Chcek that an untrusted EV root is untrusted. 1.137 + const nsIX509Cert = Ci.nsIX509Cert; 1.138 + add_test(function() { 1.139 + let evRootCA = certdb.findCertByNickname(null, evrootnick); 1.140 + certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, 0); 1.141 + 1.142 + clearOCSPCache(); 1.143 + let ocspResponder = failingOCSPResponder(); 1.144 + check_cert_err("ev-valid", 1.145 + useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER 1.146 + : SEC_ERROR_UNTRUSTED_ISSUER); 1.147 + ocspResponder.stop(run_next_test); 1.148 + }); 1.149 + 1.150 + // bug 917380: Chcek that a trusted EV root is trusted after disabling and 1.151 + // re-enabling trust. 1.152 + add_test(function() { 1.153 + let evRootCA = certdb.findCertByNickname(null, evrootnick); 1.154 + certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, 1.155 + Ci.nsIX509CertDB.TRUSTED_SSL | 1.156 + Ci.nsIX509CertDB.TRUSTED_EMAIL | 1.157 + Ci.nsIX509CertDB.TRUSTED_OBJSIGN); 1.158 + 1.159 + clearOCSPCache(); 1.160 + let ocspResponder = start_ocsp_responder( 1.161 + isDebugBuild ? ["int-ev-valid", "ev-valid"] 1.162 + : ["ev-valid"]); 1.163 + check_ee_for_ev("ev-valid", isDebugBuild); 1.164 + ocspResponder.stop(run_next_test); 1.165 + }); 1.166 + 1.167 + add_test(function () { 1.168 + check_no_ocsp_requests("ev-valid", 1.169 + useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED 1.170 + : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE 1.171 + : SEC_ERROR_EXTENSION_NOT_FOUND)); 1.172 + }); 1.173 + 1.174 + add_test(function () { 1.175 + check_no_ocsp_requests("non-ev-root", 1.176 + useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED 1.177 + : (isDebugBuild ? SEC_ERROR_UNTRUSTED_ISSUER 1.178 + : SEC_ERROR_EXTENSION_NOT_FOUND)); 1.179 + }); 1.180 + 1.181 + add_test(function () { 1.182 + check_no_ocsp_requests("no-ocsp-url-cert", 1.183 + useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED 1.184 + : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE 1.185 + : SEC_ERROR_EXTENSION_NOT_FOUND)); 1.186 + }); 1.187 + 1.188 + 1.189 + // Test the EV continues to work with flags after successful EV verification 1.190 + add_test(function () { 1.191 + clearOCSPCache(); 1.192 + let ocspResponder = start_ocsp_responder( 1.193 + isDebugBuild ? ["int-ev-valid", "ev-valid"] 1.194 + : ["ev-valid"]); 1.195 + check_ee_for_ev("ev-valid", isDebugBuild); 1.196 + ocspResponder.stop(function () { 1.197 + // without net it must be able to EV verify 1.198 + let failingOcspResponder = failingOCSPResponder(); 1.199 + let cert = certdb.findCertByNickname(null, "ev-valid"); 1.200 + let hasEVPolicy = {}; 1.201 + let verifiedChain = {}; 1.202 + let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | 1.203 + Ci.nsIX509CertDB.FLAG_MUST_BE_EV; 1.204 + 1.205 + let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, 1.206 + flags, verifiedChain, hasEVPolicy); 1.207 + do_check_eq(hasEVPolicy.value, isDebugBuild); 1.208 + do_check_eq(error, 1.209 + isDebugBuild ? 0 1.210 + : (useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED 1.211 + : SEC_ERROR_EXTENSION_NOT_FOUND)); 1.212 + failingOcspResponder.stop(run_next_test); 1.213 + }); 1.214 + }); 1.215 + 1.216 + // Bug 991815 old but valid intermediates are OK 1.217 + add_test(function () { 1.218 + clearOCSPCache(); 1.219 + let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], 1.220 + "test_ev_certs", 1.221 + isDebugBuild ? ["int-ev-valid", "ev-valid"] 1.222 + : ["ev-valid"], 1.223 + [], [], 1.224 + isDebugBuild ? ["longvalidityalmostold", "good"] 1.225 + : ["good"]); 1.226 + check_ee_for_ev("ev-valid", isDebugBuild); 1.227 + ocspResponder.stop(run_next_test); 1.228 + }); 1.229 + 1.230 + // Bug 991815 old but valid end-entities are NOT OK for EV 1.231 + // Unfortunatelly because of soft-fail we consider these OK for DV 1.232 + // libpkix does not enforce the age restriction and thus EV is valid 1.233 + add_test(function () { 1.234 + clearOCSPCache(); 1.235 + // Since Mozilla::pkix does not consider the old amost invalid OCSP 1.236 + // response valid, it does not cache the old response and thus 1.237 + // makes a separate request for DV 1.238 + let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; 1.239 + let debugResponseArray = ["good", "longvalidityalmostold", 1.240 + "longvalidityalmostold"]; 1.241 + if (!useMozillaPKIX) { 1.242 + debugCertNickArray = ["int-ev-valid", "ev-valid"]; 1.243 + debugResponseArray = ["good", "longvalidityalmostold"]; 1.244 + } 1.245 + let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], 1.246 + "test_ev_certs", 1.247 + isDebugBuild ? debugCertNickArray : ["ev-valid"], 1.248 + [], [], 1.249 + isDebugBuild ? debugResponseArray 1.250 + : ["longvalidityalmostold"]); 1.251 + check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); 1.252 + ocspResponder.stop(run_next_test); 1.253 + }); 1.254 + 1.255 + // Bug 991815 Valid but Ancient (almost two year old) responses are Not OK for 1.256 + // EV (still OK for soft fail DV) 1.257 + add_test(function () { 1.258 + clearOCSPCache(); 1.259 + let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; 1.260 + let debugResponseArray = ["good", "ancientstillvalid", 1.261 + "ancientstillvalid"]; 1.262 + if (!useMozillaPKIX) { 1.263 + debugCertNickArray = ["int-ev-valid", "ev-valid"]; 1.264 + debugResponseArray = ["good", "ancientstillvalid"]; 1.265 + } 1.266 + let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], 1.267 + "test_ev_certs", 1.268 + isDebugBuild ? debugCertNickArray : ["ev-valid"], 1.269 + [], [], 1.270 + isDebugBuild ? debugResponseArray 1.271 + : ["ancientstillvalid"]); 1.272 + check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); 1.273 + ocspResponder.stop(run_next_test); 1.274 + }); 1.275 +} 1.276 + 1.277 +// bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert 1.278 +// to prevent spurious OCSP requests that race with OCSP stapling. 1.279 +// This has the side-effect of saying an EV certificate is not EV if 1.280 +// it hasn't already been verified (e.g. on the verification thread when 1.281 +// connecting to a site). 1.282 +// This flag is mostly a hack that should be removed once FLAG_LOCAL_ONLY 1.283 +// works as intended. 1.284 +function check_no_ocsp_requests(cert_name, expected_error) { 1.285 + clearOCSPCache(); 1.286 + let ocspResponder = failingOCSPResponder(); 1.287 + let cert = certdb.findCertByNickname(null, cert_name); 1.288 + let hasEVPolicy = {}; 1.289 + let verifiedChain = {}; 1.290 + let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | 1.291 + Ci.nsIX509CertDB.FLAG_MUST_BE_EV; 1.292 + let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, flags, 1.293 + verifiedChain, hasEVPolicy); 1.294 + // Since we're not doing OCSP requests, no certificate will be EV. 1.295 + do_check_eq(hasEVPolicy.value, false); 1.296 + do_check_eq(expected_error, error); 1.297 + // Also check that isExtendedValidation doesn't cause OCSP requests. 1.298 + let identityInfo = cert.QueryInterface(Ci.nsIIdentityInfo); 1.299 + do_check_eq(identityInfo.isExtendedValidation, false); 1.300 + ocspResponder.stop(run_next_test); 1.301 +} 1.302 +