Bug 1940967 - Vendor glean_parser v16.2.0 r=TravisLong,mach-reviewers,ahal
[gecko.git] / security / manager / ssl / tests / unit / test_pinning.js
blob1a0fa866aa98c7a743c2cb993bb89ecc2aaa8069
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/.
5 //
6 // For all cases, the acceptable pinset includes only certificates pinned to
7 // Test End Entity Cert (signed by issuer testCA). Other certificates
8 // are issued by otherCA, which is never in the pinset but is a user-specified
9 // trust anchor. This test covers multiple cases:
11 // Pinned domain include-subdomains.pinning.example.com includes subdomains
12 // - PASS: include-subdomains.pinning.example.com serves a correct cert
13 // - PASS: good.include-subdomains.pinning.example.com serves a correct cert
14 // - FAIL (strict): bad.include-subdomains.pinning.example.com serves a cert
15 // not in the pinset
16 // - PASS (mitm): bad.include-subdomains.pinning.example.com serves a cert not
17 // in the pinset, but issued by a user-specified trust domain
19 // Pinned domain exclude-subdomains.pinning.example.com excludes subdomains
20 // - PASS: exclude-subdomains.pinning.example.com serves a correct cert
21 // - FAIL: exclude-subdomains.pinning.example.com serves an incorrect cert
22 // (TODO: test using verifyCertNow)
23 // - PASS: sub.exclude-subdomains.pinning.example.com serves an incorrect cert
25 "use strict";
27 // Enable the collection (during test) for all products so even products
28 // that don't collect the data will be able to run the test without failure.
29 Services.prefs.setBoolPref(
30   "toolkit.telemetry.testing.overrideProductsCheck",
31   true
34 do_get_profile(); // must be called before getting nsIX509CertDB
35 const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
36   Ci.nsIX509CertDB
39 function add_clear_override(host) {
40   add_test(function () {
41     let certOverrideService = Cc[
42       "@mozilla.org/security/certoverride;1"
43     ].getService(Ci.nsICertOverrideService);
44     certOverrideService.clearValidityOverride(host, 8443, {});
45     run_next_test();
46   });
49 function test_strict() {
50   // In strict mode, we always evaluate pinning data, regardless of whether the
51   // issuer is a built-in trust anchor. We only enforce pins that are not in
52   // test mode.
53   add_test(function () {
54     Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
55     run_next_test();
56   });
58   // Normally this is overridable. But, since we have pinning information for
59   // this host, we don't allow overrides.
60   add_prevented_cert_override_test(
61     "unknownissuer.include-subdomains.pinning.example.com",
62     SEC_ERROR_UNKNOWN_ISSUER
63   );
64   add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
66   // Issued by otherCA, which is not in the pinset for pinning.example.com.
67   add_connection_test(
68     "bad.include-subdomains.pinning.example.com",
69     MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
70   );
72   // Check that using a FQDN doesn't bypass pinning.
73   add_connection_test(
74     "bad.include-subdomains.pinning.example.com.",
75     MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
76   );
77   // For some reason this is also navigable (see bug 1118522).
78   add_connection_test(
79     "bad.include-subdomains.pinning.example.com..",
80     MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
81   );
83   // These domains serve certs that match the pinset.
84   add_connection_test(
85     "include-subdomains.pinning.example.com",
86     PRErrorCodeSuccess
87   );
88   add_connection_test(
89     "good.include-subdomains.pinning.example.com",
90     PRErrorCodeSuccess
91   );
92   add_connection_test(
93     "exclude-subdomains.pinning.example.com",
94     PRErrorCodeSuccess
95   );
97   // This domain serves a cert that doesn't match the pinset, but subdomains
98   // are excluded.
99   add_connection_test(
100     "sub.exclude-subdomains.pinning.example.com",
101     PRErrorCodeSuccess
102   );
104   // This domain's pinset is exactly the same as
105   // include-subdomains.pinning.example.com, serves the same cert as
106   // bad.include-subdomains.pinning.example.com, but it should pass because
107   // it's in test_mode.
108   add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
109   // Similarly, this pin is in test-mode, so it should be overridable.
110   add_cert_override_test(
111     "unknownissuer.test-mode.pinning.example.com",
112     SEC_ERROR_UNKNOWN_ISSUER
113   );
114   add_clear_override("unknownissuer.test-mode.pinning.example.com");
117 function test_mitm() {
118   // In MITM mode, we allow pinning to pass if the chain resolves to any
119   // user-specified trust anchor, even if it is not in the pinset.
120   add_test(function () {
121     Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1);
122     run_next_test();
123   });
125   add_connection_test(
126     "include-subdomains.pinning.example.com",
127     PRErrorCodeSuccess
128   );
129   add_connection_test(
130     "good.include-subdomains.pinning.example.com",
131     PRErrorCodeSuccess
132   );
134   // Normally this is overridable. But, since we have pinning information for
135   // this host, we don't allow overrides (since building a trusted chain fails,
136   // we have no reason to believe this was issued by a user-added trust
137   // anchor, so we can't allow overrides for it).
138   add_prevented_cert_override_test(
139     "unknownissuer.include-subdomains.pinning.example.com",
140     SEC_ERROR_UNKNOWN_ISSUER
141   );
142   add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
144   // In this case, even though otherCA is not in the pinset, it is a
145   // user-specified trust anchor and the pinning check succeeds.
146   add_connection_test(
147     "bad.include-subdomains.pinning.example.com",
148     PRErrorCodeSuccess
149   );
151   add_connection_test(
152     "exclude-subdomains.pinning.example.com",
153     PRErrorCodeSuccess
154   );
155   add_connection_test(
156     "sub.exclude-subdomains.pinning.example.com",
157     PRErrorCodeSuccess
158   );
159   add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
160   add_cert_override_test(
161     "unknownissuer.test-mode.pinning.example.com",
162     SEC_ERROR_UNKNOWN_ISSUER
163   );
164   add_clear_override("unknownissuer.test-mode.pinning.example.com");
167 function test_disabled() {
168   // Disable pinning.
169   add_test(function () {
170     Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
171     run_next_test();
172   });
174   add_connection_test(
175     "include-subdomains.pinning.example.com",
176     PRErrorCodeSuccess
177   );
178   add_connection_test(
179     "good.include-subdomains.pinning.example.com",
180     PRErrorCodeSuccess
181   );
182   add_connection_test(
183     "bad.include-subdomains.pinning.example.com",
184     PRErrorCodeSuccess
185   );
186   add_connection_test(
187     "exclude-subdomains.pinning.example.com",
188     PRErrorCodeSuccess
189   );
190   add_connection_test(
191     "sub.exclude-subdomains.pinning.example.com",
192     PRErrorCodeSuccess
193   );
194   add_connection_test("test-mode.pinning.example.com", PRErrorCodeSuccess);
196   add_cert_override_test(
197     "unknownissuer.include-subdomains.pinning.example.com",
198     SEC_ERROR_UNKNOWN_ISSUER
199   );
200   add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
201   add_cert_override_test(
202     "unknownissuer.test-mode.pinning.example.com",
203     SEC_ERROR_UNKNOWN_ISSUER
204   );
205   add_clear_override("unknownissuer.test-mode.pinning.example.com");
208 function test_enforce_test_mode() {
209   // In enforce test mode, we always enforce all pins, even test pins.
210   add_test(function () {
211     Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 3);
212     run_next_test();
213   });
215   // Normally this is overridable. But, since we have pinning information for
216   // this host, we don't allow overrides.
217   add_prevented_cert_override_test(
218     "unknownissuer.include-subdomains.pinning.example.com",
219     SEC_ERROR_UNKNOWN_ISSUER
220   );
221   add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
223   // Issued by otherCA, which is not in the pinset for pinning.example.com.
224   add_connection_test(
225     "bad.include-subdomains.pinning.example.com",
226     MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
227   );
229   // These domains serve certs that match the pinset.
230   add_connection_test(
231     "include-subdomains.pinning.example.com",
232     PRErrorCodeSuccess
233   );
234   add_connection_test(
235     "good.include-subdomains.pinning.example.com",
236     PRErrorCodeSuccess
237   );
238   add_connection_test(
239     "exclude-subdomains.pinning.example.com",
240     PRErrorCodeSuccess
241   );
243   // This domain serves a cert that doesn't match the pinset, but subdomains
244   // are excluded.
245   add_connection_test(
246     "sub.exclude-subdomains.pinning.example.com",
247     PRErrorCodeSuccess
248   );
250   // This domain's pinset is exactly the same as
251   // include-subdomains.pinning.example.com, serves the same cert as
252   // bad.include-subdomains.pinning.example.com, is in test-mode, but we are
253   // enforcing test mode pins.
254   add_connection_test(
255     "test-mode.pinning.example.com",
256     MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
257   );
258   // Normally this is overridable. But, since we have pinning information for
259   // this host (and since we're enforcing test mode), we don't allow overrides.
260   add_prevented_cert_override_test(
261     "unknownissuer.test-mode.pinning.example.com",
262     SEC_ERROR_UNKNOWN_ISSUER
263   );
264   add_clear_override("unknownissuer.test-mode.pinning.example.com");
267 function check_pinning_telemetry() {
268   let prod_histogram = Services.telemetry
269     .getHistogramById("CERT_PINNING_RESULTS")
270     .snapshot();
271   let test_histogram = Services.telemetry
272     .getHistogramById("CERT_PINNING_TEST_RESULTS")
273     .snapshot();
274   // Because all of our test domains are pinned to user-specified trust
275   // anchors, effectively only strict mode and enforce test-mode get evaluated
276   equal(
277     prod_histogram.values[0],
278     4,
279     "Actual and expected prod (non-Mozilla) failure count should match"
280   );
281   equal(
282     prod_histogram.values[1],
283     6,
284     "Actual and expected prod (non-Mozilla) success count should match"
285   );
286   equal(
287     test_histogram.values[0],
288     2,
289     "Actual and expected test (non-Mozilla) failure count should match"
290   );
291   equal(
292     test_histogram.values[1] || 0,
293     0,
294     "Actual and expected test (non-Mozilla) success count should match"
295   );
297   run_next_test();
300 function run_test() {
301   // Ensure that static pinning works when HPKP is disabled.
302   Services.prefs.setBoolPref("security.cert_pinning.hpkp.enabled", false);
304   add_tls_server_setup("BadCertAndPinningServer", "bad_certs");
306   // Add a user-specified trust anchor.
307   addCertFromFile(certdb, "bad_certs/other-test-ca.pem", "CTu,u,u");
309   test_strict();
310   test_mitm();
311   test_disabled();
312   test_enforce_test_mode();
314   add_test(function () {
315     check_pinning_telemetry();
316   });
317   run_next_test();