|
1 // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- |
|
2 // This Source Code Form is subject to the terms of the Mozilla Public |
|
3 // License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/. |
|
5 |
|
6 "use strict"; |
|
7 |
|
8 // XXX: The isDebugBuild tests you see are here because the test EV root is |
|
9 // only enabled for EV in debug builds, as a security measure. An ugly hack. |
|
10 |
|
11 do_get_profile(); // must be called before getting nsIX509CertDB |
|
12 const certdb = Cc["@mozilla.org/security/x509certdb;1"] |
|
13 .getService(Ci.nsIX509CertDB); |
|
14 |
|
15 const evrootnick = "XPCShell EV Testing (untrustworthy) CA - Mozilla - " + |
|
16 "EV debug test CA"; |
|
17 |
|
18 // This is the list of certificates needed for the test |
|
19 // The certificates prefixed by 'int-' are intermediates |
|
20 let certList = [ |
|
21 // Test for successful EV validation |
|
22 'int-ev-valid', |
|
23 'ev-valid', |
|
24 'ev-valid-anypolicy-int', |
|
25 'int-ev-valid-anypolicy-int', |
|
26 'no-ocsp-url-cert', // a cert signed by the EV auth that has no OCSP url |
|
27 // but that contains a valid CRLDP. |
|
28 |
|
29 // Testing a root that looks like EV but is not EV enabled |
|
30 'int-non-ev-root', |
|
31 'non-ev-root', |
|
32 ] |
|
33 |
|
34 function load_ca(ca_name) { |
|
35 var ca_filename = ca_name + ".der"; |
|
36 addCertFromFile(certdb, "test_ev_certs/" + ca_filename, 'CTu,CTu,CTu'); |
|
37 } |
|
38 |
|
39 const SERVER_PORT = 8888; |
|
40 |
|
41 function failingOCSPResponder() { |
|
42 return getFailingHttpServer(SERVER_PORT, |
|
43 ["www.example.com", "crl.example.com"]); |
|
44 } |
|
45 |
|
46 function start_ocsp_responder(expectedCertNames) { |
|
47 let expectedPaths = expectedCertNames.slice(); |
|
48 return startOCSPResponder(SERVER_PORT, "www.example.com", ["crl.example.com"], |
|
49 "test_ev_certs", expectedCertNames, expectedPaths); |
|
50 } |
|
51 |
|
52 function check_cert_err(cert_name, expected_error) { |
|
53 let cert = certdb.findCertByNickname(null, cert_name); |
|
54 let hasEVPolicy = {}; |
|
55 let verifiedChain = {}; |
|
56 let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, |
|
57 NO_FLAGS, verifiedChain, hasEVPolicy); |
|
58 do_check_eq(error, expected_error); |
|
59 } |
|
60 |
|
61 |
|
62 function check_ee_for_ev(cert_name, expected_ev) { |
|
63 let cert = certdb.findCertByNickname(null, cert_name); |
|
64 let hasEVPolicy = {}; |
|
65 let verifiedChain = {}; |
|
66 let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, |
|
67 NO_FLAGS, verifiedChain, hasEVPolicy); |
|
68 do_check_eq(hasEVPolicy.value, expected_ev); |
|
69 do_check_eq(0, error); |
|
70 } |
|
71 |
|
72 function run_test() { |
|
73 for (let i = 0 ; i < certList.length; i++) { |
|
74 let cert_filename = certList[i] + ".der"; |
|
75 addCertFromFile(certdb, "test_ev_certs/" + cert_filename, ',,'); |
|
76 } |
|
77 load_ca("evroot"); |
|
78 load_ca("non-evroot-ca"); |
|
79 |
|
80 // setup and start ocsp responder |
|
81 Services.prefs.setCharPref("network.dns.localDomains", |
|
82 'www.example.com, crl.example.com'); |
|
83 add_tests_in_mode(true); |
|
84 add_tests_in_mode(false); |
|
85 run_next_test(); |
|
86 } |
|
87 |
|
88 function add_tests_in_mode(useMozillaPKIX) |
|
89 { |
|
90 add_test(function () { |
|
91 Services.prefs.setBoolPref("security.use_mozillapkix_verification", |
|
92 useMozillaPKIX); |
|
93 run_next_test(); |
|
94 }); |
|
95 |
|
96 add_test(function () { |
|
97 clearOCSPCache(); |
|
98 let ocspResponder = start_ocsp_responder( |
|
99 isDebugBuild ? ["int-ev-valid", "ev-valid"] |
|
100 : ["ev-valid"]); |
|
101 check_ee_for_ev("ev-valid", isDebugBuild); |
|
102 ocspResponder.stop(run_next_test); |
|
103 }); |
|
104 |
|
105 |
|
106 add_test(function () { |
|
107 clearOCSPCache(); |
|
108 |
|
109 let ocspResponder = start_ocsp_responder( |
|
110 isDebugBuild ? ["int-ev-valid-anypolicy-int", "ev-valid-anypolicy-int"] |
|
111 : ["ev-valid-anypolicy-int"]); |
|
112 check_ee_for_ev("ev-valid-anypolicy-int", isDebugBuild); |
|
113 ocspResponder.stop(run_next_test); |
|
114 }); |
|
115 |
|
116 add_test(function() { |
|
117 clearOCSPCache(); |
|
118 let ocspResponder = start_ocsp_responder(["non-ev-root"]); |
|
119 check_ee_for_ev("non-ev-root", false); |
|
120 ocspResponder.stop(run_next_test); |
|
121 }); |
|
122 |
|
123 add_test(function() { |
|
124 clearOCSPCache(); |
|
125 // libpkix will attempt to validate the intermediate, which does have an |
|
126 // OCSP URL. |
|
127 let ocspResponder = isDebugBuild ? start_ocsp_responder(["int-ev-valid"]) |
|
128 : failingOCSPResponder(); |
|
129 check_ee_for_ev("no-ocsp-url-cert", false); |
|
130 ocspResponder.stop(run_next_test); |
|
131 }); |
|
132 |
|
133 // bug 917380: Chcek that an untrusted EV root is untrusted. |
|
134 const nsIX509Cert = Ci.nsIX509Cert; |
|
135 add_test(function() { |
|
136 let evRootCA = certdb.findCertByNickname(null, evrootnick); |
|
137 certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, 0); |
|
138 |
|
139 clearOCSPCache(); |
|
140 let ocspResponder = failingOCSPResponder(); |
|
141 check_cert_err("ev-valid", |
|
142 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
143 : SEC_ERROR_UNTRUSTED_ISSUER); |
|
144 ocspResponder.stop(run_next_test); |
|
145 }); |
|
146 |
|
147 // bug 917380: Chcek that a trusted EV root is trusted after disabling and |
|
148 // re-enabling trust. |
|
149 add_test(function() { |
|
150 let evRootCA = certdb.findCertByNickname(null, evrootnick); |
|
151 certdb.setCertTrust(evRootCA, nsIX509Cert.CA_CERT, |
|
152 Ci.nsIX509CertDB.TRUSTED_SSL | |
|
153 Ci.nsIX509CertDB.TRUSTED_EMAIL | |
|
154 Ci.nsIX509CertDB.TRUSTED_OBJSIGN); |
|
155 |
|
156 clearOCSPCache(); |
|
157 let ocspResponder = start_ocsp_responder( |
|
158 isDebugBuild ? ["int-ev-valid", "ev-valid"] |
|
159 : ["ev-valid"]); |
|
160 check_ee_for_ev("ev-valid", isDebugBuild); |
|
161 ocspResponder.stop(run_next_test); |
|
162 }); |
|
163 |
|
164 add_test(function () { |
|
165 check_no_ocsp_requests("ev-valid", |
|
166 useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED |
|
167 : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE |
|
168 : SEC_ERROR_EXTENSION_NOT_FOUND)); |
|
169 }); |
|
170 |
|
171 add_test(function () { |
|
172 check_no_ocsp_requests("non-ev-root", |
|
173 useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED |
|
174 : (isDebugBuild ? SEC_ERROR_UNTRUSTED_ISSUER |
|
175 : SEC_ERROR_EXTENSION_NOT_FOUND)); |
|
176 }); |
|
177 |
|
178 add_test(function () { |
|
179 check_no_ocsp_requests("no-ocsp-url-cert", |
|
180 useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED |
|
181 : (isDebugBuild ? SEC_ERROR_REVOKED_CERTIFICATE |
|
182 : SEC_ERROR_EXTENSION_NOT_FOUND)); |
|
183 }); |
|
184 |
|
185 |
|
186 // Test the EV continues to work with flags after successful EV verification |
|
187 add_test(function () { |
|
188 clearOCSPCache(); |
|
189 let ocspResponder = start_ocsp_responder( |
|
190 isDebugBuild ? ["int-ev-valid", "ev-valid"] |
|
191 : ["ev-valid"]); |
|
192 check_ee_for_ev("ev-valid", isDebugBuild); |
|
193 ocspResponder.stop(function () { |
|
194 // without net it must be able to EV verify |
|
195 let failingOcspResponder = failingOCSPResponder(); |
|
196 let cert = certdb.findCertByNickname(null, "ev-valid"); |
|
197 let hasEVPolicy = {}; |
|
198 let verifiedChain = {}; |
|
199 let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | |
|
200 Ci.nsIX509CertDB.FLAG_MUST_BE_EV; |
|
201 |
|
202 let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, |
|
203 flags, verifiedChain, hasEVPolicy); |
|
204 do_check_eq(hasEVPolicy.value, isDebugBuild); |
|
205 do_check_eq(error, |
|
206 isDebugBuild ? 0 |
|
207 : (useMozillaPKIX ? SEC_ERROR_POLICY_VALIDATION_FAILED |
|
208 : SEC_ERROR_EXTENSION_NOT_FOUND)); |
|
209 failingOcspResponder.stop(run_next_test); |
|
210 }); |
|
211 }); |
|
212 |
|
213 // Bug 991815 old but valid intermediates are OK |
|
214 add_test(function () { |
|
215 clearOCSPCache(); |
|
216 let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], |
|
217 "test_ev_certs", |
|
218 isDebugBuild ? ["int-ev-valid", "ev-valid"] |
|
219 : ["ev-valid"], |
|
220 [], [], |
|
221 isDebugBuild ? ["longvalidityalmostold", "good"] |
|
222 : ["good"]); |
|
223 check_ee_for_ev("ev-valid", isDebugBuild); |
|
224 ocspResponder.stop(run_next_test); |
|
225 }); |
|
226 |
|
227 // Bug 991815 old but valid end-entities are NOT OK for EV |
|
228 // Unfortunatelly because of soft-fail we consider these OK for DV |
|
229 // libpkix does not enforce the age restriction and thus EV is valid |
|
230 add_test(function () { |
|
231 clearOCSPCache(); |
|
232 // Since Mozilla::pkix does not consider the old amost invalid OCSP |
|
233 // response valid, it does not cache the old response and thus |
|
234 // makes a separate request for DV |
|
235 let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; |
|
236 let debugResponseArray = ["good", "longvalidityalmostold", |
|
237 "longvalidityalmostold"]; |
|
238 if (!useMozillaPKIX) { |
|
239 debugCertNickArray = ["int-ev-valid", "ev-valid"]; |
|
240 debugResponseArray = ["good", "longvalidityalmostold"]; |
|
241 } |
|
242 let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], |
|
243 "test_ev_certs", |
|
244 isDebugBuild ? debugCertNickArray : ["ev-valid"], |
|
245 [], [], |
|
246 isDebugBuild ? debugResponseArray |
|
247 : ["longvalidityalmostold"]); |
|
248 check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); |
|
249 ocspResponder.stop(run_next_test); |
|
250 }); |
|
251 |
|
252 // Bug 991815 Valid but Ancient (almost two year old) responses are Not OK for |
|
253 // EV (still OK for soft fail DV) |
|
254 add_test(function () { |
|
255 clearOCSPCache(); |
|
256 let debugCertNickArray = ["int-ev-valid", "ev-valid", "ev-valid"]; |
|
257 let debugResponseArray = ["good", "ancientstillvalid", |
|
258 "ancientstillvalid"]; |
|
259 if (!useMozillaPKIX) { |
|
260 debugCertNickArray = ["int-ev-valid", "ev-valid"]; |
|
261 debugResponseArray = ["good", "ancientstillvalid"]; |
|
262 } |
|
263 let ocspResponder = startOCSPResponder(SERVER_PORT, "www.example.com", [], |
|
264 "test_ev_certs", |
|
265 isDebugBuild ? debugCertNickArray : ["ev-valid"], |
|
266 [], [], |
|
267 isDebugBuild ? debugResponseArray |
|
268 : ["ancientstillvalid"]); |
|
269 check_ee_for_ev("ev-valid", !useMozillaPKIX && isDebugBuild); |
|
270 ocspResponder.stop(run_next_test); |
|
271 }); |
|
272 } |
|
273 |
|
274 // bug 950240: add FLAG_MUST_BE_EV to CertVerifier::VerifyCert |
|
275 // to prevent spurious OCSP requests that race with OCSP stapling. |
|
276 // This has the side-effect of saying an EV certificate is not EV if |
|
277 // it hasn't already been verified (e.g. on the verification thread when |
|
278 // connecting to a site). |
|
279 // This flag is mostly a hack that should be removed once FLAG_LOCAL_ONLY |
|
280 // works as intended. |
|
281 function check_no_ocsp_requests(cert_name, expected_error) { |
|
282 clearOCSPCache(); |
|
283 let ocspResponder = failingOCSPResponder(); |
|
284 let cert = certdb.findCertByNickname(null, cert_name); |
|
285 let hasEVPolicy = {}; |
|
286 let verifiedChain = {}; |
|
287 let flags = Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | |
|
288 Ci.nsIX509CertDB.FLAG_MUST_BE_EV; |
|
289 let error = certdb.verifyCertNow(cert, certificateUsageSSLServer, flags, |
|
290 verifiedChain, hasEVPolicy); |
|
291 // Since we're not doing OCSP requests, no certificate will be EV. |
|
292 do_check_eq(hasEVPolicy.value, false); |
|
293 do_check_eq(expected_error, error); |
|
294 // Also check that isExtendedValidation doesn't cause OCSP requests. |
|
295 let identityInfo = cert.QueryInterface(Ci.nsIIdentityInfo); |
|
296 do_check_eq(identityInfo.isExtendedValidation, false); |
|
297 ocspResponder.stop(run_next_test); |
|
298 } |
|
299 |