no bug - Import translations from android-l10n r=release a=l10n CLOSED TREE
[gecko.git] / security / manager / ssl / tests / unit / test_ev_certs.js
blob99b5bda0f0cac8c55ce6eccc479223138894738b
1 // -*- indent-tabs-mode: nil; js-indent-level: 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/.
6 "use strict";
8 // Tests that end-entity certificates that should successfully verify as EV
9 // (Extended Validation) do so and that end-entity certificates that should not
10 // successfully verify as EV do not. Also tests related situations (e.g. that
11 // failure to fetch an OCSP response results in no EV treatment).
13 // A quick note about the certificates in these tests: generally, an EV
14 // certificate chain will have an end-entity with a specific policy OID followed
15 // by an intermediate with the anyPolicy OID chaining to a root with no policy
16 // OID (since it's a trust anchor, it can be omitted). In these tests, the
17 // specific policy OID is 1.3.6.1.4.1.13769.666.666.666.1.500.9.1 and is
18 // referred to as the test OID. In order to reflect what will commonly be
19 // encountered, the end-entity of any given test path will have the test OID
20 // unless otherwise specified in the name of the test path. Similarly, the
21 // intermediate will have the anyPolicy OID, again unless otherwise specified.
22 // For example, for the path where the end-entity does not have an OCSP URI
23 // (referred to as "no-ocsp-ee-path-{ee,int}", the end-entity has the test OID
24 // whereas the intermediate has the anyPolicy OID.
25 // For another example, for the test OID path ("test-oid-path-{ee,int}"), both
26 // the end-entity and the intermediate have the test OID.
28 do_get_profile(); // must be called before getting nsIX509CertDB
29 const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
30   Ci.nsIX509CertDB
33 registerCleanupFunction(() => {
34   Services.prefs.clearUserPref("network.dns.localDomains");
35   Services.prefs.clearUserPref("security.OCSP.enabled");
36 });
38 Services.prefs.setCharPref("network.dns.localDomains", "www.example.com");
39 Services.prefs.setIntPref("security.OCSP.enabled", 1);
40 const evroot = addCertFromFile(certdb, "test_ev_certs/evroot.pem", "CTu,,");
41 addCertFromFile(certdb, "test_ev_certs/non-evroot-ca.pem", "CTu,,");
43 const SERVER_PORT = 8888;
45 function failingOCSPResponder() {
46   return getFailingHttpServer(SERVER_PORT, ["www.example.com"]);
49 class EVCertVerificationResult {
50   constructor(
51     testcase,
52     expectedPRErrorCode,
53     expectedEV,
54     resolve,
55     ocspResponder
56   ) {
57     this.testcase = testcase;
58     this.expectedPRErrorCode = expectedPRErrorCode;
59     this.expectedEV = expectedEV;
60     this.resolve = resolve;
61     this.ocspResponder = ocspResponder;
62   }
64   verifyCertFinished(prErrorCode, verifiedChain, hasEVPolicy) {
65     equal(
66       prErrorCode,
67       this.expectedPRErrorCode,
68       `${this.testcase} should have expected error code`
69     );
70     equal(
71       hasEVPolicy,
72       this.expectedEV,
73       `${this.testcase} should result in expected EV status`
74     );
75     this.ocspResponder.stop(this.resolve);
76   }
79 function asyncTestEV(
80   cert,
81   expectedPRErrorCode,
82   expectedEV,
83   expectedOCSPRequestPaths,
84   ocspResponseTypes = undefined
85 ) {
86   let now = Date.now() / 1000;
87   return new Promise(resolve => {
88     let ocspResponder = expectedOCSPRequestPaths.length
89       ? startOCSPResponder(
90           SERVER_PORT,
91           "www.example.com",
92           "test_ev_certs",
93           expectedOCSPRequestPaths,
94           expectedOCSPRequestPaths.slice(),
95           null,
96           ocspResponseTypes
97         )
98       : failingOCSPResponder();
99     let result = new EVCertVerificationResult(
100       cert.subjectName,
101       expectedPRErrorCode,
102       expectedEV,
103       resolve,
104       ocspResponder
105     );
106     certdb.asyncVerifyCertAtTime(
107       cert,
108       certificateUsageSSLServer,
109       0,
110       "ev-test.example.com",
111       now,
112       result
113     );
114   });
117 function ensureVerifiesAsEV(testcase) {
118   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
119   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
120   let expectedOCSPRequestPaths = [`${testcase}-ee`];
121   return asyncTestEV(
122     cert,
123     PRErrorCodeSuccess,
124     gEVExpected,
125     expectedOCSPRequestPaths
126   );
129 function ensureVerifiesAsEVWithNoOCSPRequests(testcase) {
130   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
131   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
132   return asyncTestEV(cert, PRErrorCodeSuccess, gEVExpected, []);
135 function ensureVerifiesAsDV(testcase, expectedOCSPRequestPaths = undefined) {
136   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
137   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
138   return asyncTestEV(
139     cert,
140     PRErrorCodeSuccess,
141     false,
142     expectedOCSPRequestPaths ? expectedOCSPRequestPaths : [`${testcase}-ee`]
143   );
146 function ensureVerificationFails(testcase, expectedPRErrorCode) {
147   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
148   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
149   return asyncTestEV(cert, expectedPRErrorCode, false, []);
152 function verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, expectSuccess) {
153   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
154   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
155   let now = Date.now() / 1000;
156   let expectedErrorCode = SEC_ERROR_POLICY_VALIDATION_FAILED;
157   if (expectSuccess && gEVExpected) {
158     expectedErrorCode = PRErrorCodeSuccess;
159   }
160   return new Promise(resolve => {
161     let ocspResponder = failingOCSPResponder();
162     let result = new EVCertVerificationResult(
163       cert.subjectName,
164       expectedErrorCode,
165       expectSuccess && gEVExpected,
166       resolve,
167       ocspResponder
168     );
169     let flags =
170       Ci.nsIX509CertDB.FLAG_LOCAL_ONLY | Ci.nsIX509CertDB.FLAG_MUST_BE_EV;
171     certdb.asyncVerifyCertAtTime(
172       cert,
173       certificateUsageSSLServer,
174       flags,
175       "ev-test.example.com",
176       now,
177       result
178     );
179   });
182 function ensureNoOCSPMeansNoEV(testcase) {
183   return verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, false);
186 function ensureVerifiesAsEVWithFLAG_LOCAL_ONLY(testcase) {
187   return verifyWithFlags_LOCAL_ONLY_and_MUST_BE_EV(testcase, true);
190 function verifyWithOCSPResponseType(testcase, response, expectEV) {
191   let cert = constructCertFromFile(`test_ev_certs/${testcase}-ee.pem`);
192   addCertFromFile(certdb, `test_ev_certs/${testcase}-int.pem`, ",,");
193   let expectedOCSPRequestPaths = [`${testcase}-ee`];
194   let ocspResponseTypes = [response];
195   return asyncTestEV(
196     cert,
197     PRErrorCodeSuccess,
198     gEVExpected && expectEV,
199     expectedOCSPRequestPaths,
200     ocspResponseTypes
201   );
204 function ensureVerifiesAsDVWithOldEndEntityOCSPResponse(testcase) {
205   return verifyWithOCSPResponseType(testcase, "longvalidityalmostold", false);
208 function ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(testcase) {
209   return verifyWithOCSPResponseType(testcase, "ancientstillvalid", false);
212 // These should all verify as EV.
213 add_task(async function plainExpectSuccessEVTests() {
214   await ensureVerifiesAsEV("anyPolicy-int-path");
215   await ensureVerifiesAsEV("test-oid-path");
216   await ensureVerifiesAsEV("cabforum-oid-path");
217   await ensureVerifiesAsEV("cabforum-and-test-oid-ee-path");
218   await ensureVerifiesAsEV("test-and-cabforum-oid-ee-path");
219   await ensureVerifiesAsEV("reverse-order-oids-path");
220   // In this case, the end-entity has both the CA/B Forum OID and the test OID
221   // (in that order). The intermediate has the CA/B Forum OID. Since the
222   // implementation tries all EV policies it encounters, this successfully
223   // verifies as EV.
224   await ensureVerifiesAsEV("cabforum-and-test-oid-ee-cabforum-oid-int-path");
225   // In this case, the end-entity has both the test OID and the CA/B Forum OID
226   // (in that order). The intermediate has only the CA/B Forum OID. Since the
227   // implementation tries all EV policies it encounters, this successfully
228   // verifies as EV.
229   await ensureVerifiesAsEV("test-and-cabforum-oid-ee-cabforum-oid-int-path");
232 // These fail for various reasons to verify as EV, but fallback to DV should
233 // succeed.
234 add_task(async function expectDVFallbackTests() {
235   await ensureVerifiesAsDV("anyPolicy-ee-path");
236   await ensureVerifiesAsDV("non-ev-root-path");
237   await ensureVerifiesAsDV("no-ocsp-ee-path", []);
238   await ensureVerifiesAsEV("no-ocsp-int-path");
239   // In this case, the end-entity has the test OID and the intermediate has the
240   // CA/B Forum OID. Since the CA/B Forum OID is not treated the same as the
241   // anyPolicy OID, this will not verify as EV.
242   await ensureVerifiesAsDV("test-oid-ee-cabforum-oid-int-path");
245 // Test that removing the trust bits from an EV root causes verifications
246 // relying on that root to fail (and then test that adding back the trust bits
247 // causes the verifications to succeed again).
248 add_task(async function evRootTrustTests() {
249   clearOCSPCache();
250   info("untrusting evroot");
251   certdb.setCertTrust(
252     evroot,
253     Ci.nsIX509Cert.CA_CERT,
254     Ci.nsIX509CertDB.UNTRUSTED
255   );
256   await ensureVerificationFails("test-oid-path", SEC_ERROR_UNKNOWN_ISSUER);
257   info("re-trusting evroot");
258   certdb.setCertTrust(
259     evroot,
260     Ci.nsIX509Cert.CA_CERT,
261     Ci.nsIX509CertDB.TRUSTED_SSL
262   );
263   await ensureVerifiesAsEV("test-oid-path");
266 // Test that if FLAG_LOCAL_ONLY and FLAG_MUST_BE_EV are specified, that no OCSP
267 // requests are made (this also means that nothing will verify as EV).
268 add_task(async function localOnlyMustBeEVTests() {
269   clearOCSPCache();
270   await ensureNoOCSPMeansNoEV("anyPolicy-ee-path");
271   await ensureNoOCSPMeansNoEV("anyPolicy-int-path");
272   await ensureNoOCSPMeansNoEV("non-ev-root-path");
273   await ensureNoOCSPMeansNoEV("no-ocsp-ee-path");
274   await ensureNoOCSPMeansNoEV("no-ocsp-int-path");
275   await ensureNoOCSPMeansNoEV("test-oid-path");
278 // Prime the OCSP cache and then ensure that we can validate certificates as EV
279 // without hitting the network. There's two cases here: one where we simply
280 // validate like normal and then check that the network was never accessed and
281 // another where we use flags to mandate that the network not be used.
282 add_task(async function ocspCachingTests() {
283   clearOCSPCache();
285   await ensureVerifiesAsEV("anyPolicy-int-path");
286   await ensureVerifiesAsEV("test-oid-path");
288   await ensureVerifiesAsEVWithNoOCSPRequests("anyPolicy-int-path");
289   await ensureVerifiesAsEVWithNoOCSPRequests("test-oid-path");
291   await ensureVerifiesAsEVWithFLAG_LOCAL_ONLY("anyPolicy-int-path");
292   await ensureVerifiesAsEVWithFLAG_LOCAL_ONLY("test-oid-path");
295 // Old-but-still-valid OCSP responses are accepted for intermediates but not
296 // end-entity certificates (because of OCSP soft-fail this results in DV
297 // fallback).
298 add_task(async function oldOCSPResponseTests() {
299   clearOCSPCache();
301   clearOCSPCache();
302   await ensureVerifiesAsDVWithOldEndEntityOCSPResponse("anyPolicy-int-path");
303   await ensureVerifiesAsDVWithOldEndEntityOCSPResponse("test-oid-path");
305   clearOCSPCache();
306   await ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse(
307     "anyPolicy-int-path"
308   );
309   await ensureVerifiesAsDVWithVeryOldEndEntityOCSPResponse("test-oid-path");