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 // 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
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
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",
34 do_get_profile(); // must be called before getting nsIX509CertDB
35 const certdb = Cc["@mozilla.org/security/x509certdb;1"].getService(
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, {});
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
53 add_test(function () {
54 Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
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
64 add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
66 // Issued by otherCA, which is not in the pinset for pinning.example.com.
68 "bad.include-subdomains.pinning.example.com",
69 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
72 // Check that using a FQDN doesn't bypass pinning.
74 "bad.include-subdomains.pinning.example.com.",
75 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
77 // For some reason this is also navigable (see bug 1118522).
79 "bad.include-subdomains.pinning.example.com..",
80 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
83 // These domains serve certs that match the pinset.
85 "include-subdomains.pinning.example.com",
89 "good.include-subdomains.pinning.example.com",
93 "exclude-subdomains.pinning.example.com",
97 // This domain serves a cert that doesn't match the pinset, but subdomains
100 "sub.exclude-subdomains.pinning.example.com",
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
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);
126 "include-subdomains.pinning.example.com",
130 "good.include-subdomains.pinning.example.com",
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
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.
147 "bad.include-subdomains.pinning.example.com",
152 "exclude-subdomains.pinning.example.com",
156 "sub.exclude-subdomains.pinning.example.com",
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
164 add_clear_override("unknownissuer.test-mode.pinning.example.com");
167 function test_disabled() {
169 add_test(function () {
170 Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
175 "include-subdomains.pinning.example.com",
179 "good.include-subdomains.pinning.example.com",
183 "bad.include-subdomains.pinning.example.com",
187 "exclude-subdomains.pinning.example.com",
191 "sub.exclude-subdomains.pinning.example.com",
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
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
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);
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
221 add_clear_override("unknownissuer.include-subdomains.pinning.example.com");
223 // Issued by otherCA, which is not in the pinset for pinning.example.com.
225 "bad.include-subdomains.pinning.example.com",
226 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
229 // These domains serve certs that match the pinset.
231 "include-subdomains.pinning.example.com",
235 "good.include-subdomains.pinning.example.com",
239 "exclude-subdomains.pinning.example.com",
243 // This domain serves a cert that doesn't match the pinset, but subdomains
246 "sub.exclude-subdomains.pinning.example.com",
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.
255 "test-mode.pinning.example.com",
256 MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE
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
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")
271 let test_histogram = Services.telemetry
272 .getHistogramById("CERT_PINNING_TEST_RESULTS")
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
277 prod_histogram.values[0],
279 "Actual and expected prod (non-Mozilla) failure count should match"
282 prod_histogram.values[1],
284 "Actual and expected prod (non-Mozilla) success count should match"
287 test_histogram.values[0],
289 "Actual and expected test (non-Mozilla) failure count should match"
292 test_histogram.values[1] || 0,
294 "Actual and expected test (non-Mozilla) success count should match"
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");
312 test_enforce_test_mode();
314 add_test(function () {
315 check_pinning_telemetry();