|
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 "use strict"; |
|
6 |
|
7 // Tests the certificate overrides we allow. |
|
8 // add_cert_override_test will queue a test that does the following: |
|
9 // 1. Attempt to connect to the given host. This should fail with the |
|
10 // given error and override bits. |
|
11 // 2. Add an override for that host/port/certificate/override bits. |
|
12 // 3. Connect again. This should succeed. |
|
13 |
|
14 do_get_profile(); |
|
15 let certOverrideService = Cc["@mozilla.org/security/certoverride;1"] |
|
16 .getService(Ci.nsICertOverrideService); |
|
17 |
|
18 function add_cert_override(aHost, aExpectedBits, aSecurityInfo) { |
|
19 let sslstatus = aSecurityInfo.QueryInterface(Ci.nsISSLStatusProvider) |
|
20 .SSLStatus; |
|
21 let bits = |
|
22 (sslstatus.isUntrusted ? Ci.nsICertOverrideService.ERROR_UNTRUSTED : 0) | |
|
23 (sslstatus.isDomainMismatch ? Ci.nsICertOverrideService.ERROR_MISMATCH : 0) | |
|
24 (sslstatus.isNotValidAtThisTime ? Ci.nsICertOverrideService.ERROR_TIME : 0); |
|
25 do_check_eq(bits, aExpectedBits); |
|
26 let cert = sslstatus.serverCert; |
|
27 certOverrideService.rememberValidityOverride(aHost, 8443, cert, aExpectedBits, |
|
28 true); |
|
29 } |
|
30 |
|
31 function add_cert_override_test(aHost, aExpectedBits, aExpectedError) { |
|
32 add_connection_test(aHost, aExpectedError, null, |
|
33 add_cert_override.bind(this, aHost, aExpectedBits)); |
|
34 add_connection_test(aHost, Cr.NS_OK); |
|
35 } |
|
36 |
|
37 function add_non_overridable_test(aHost, aExpectedError) { |
|
38 add_connection_test( |
|
39 aHost, getXPCOMStatusFromNSS(aExpectedError), null, |
|
40 function (securityInfo) { |
|
41 // bug 754369 - no SSLStatus probably means this is a non-overridable |
|
42 // error, which is what we're testing (although it would be best to test |
|
43 // this directly). |
|
44 securityInfo.QueryInterface(Ci.nsISSLStatusProvider); |
|
45 do_check_eq(securityInfo.SSLStatus, null); |
|
46 }); |
|
47 } |
|
48 |
|
49 function check_telemetry() { |
|
50 let histogram = Cc["@mozilla.org/base/telemetry;1"] |
|
51 .getService(Ci.nsITelemetry) |
|
52 .getHistogramById("SSL_CERT_ERROR_OVERRIDES") |
|
53 .snapshot(); |
|
54 do_check_eq(histogram.counts[ 0], 0); |
|
55 do_check_eq(histogram.counts[ 2], 8 + 1); // SEC_ERROR_UNKNOWN_ISSUER |
|
56 do_check_eq(histogram.counts[ 3], 2); // SEC_ERROR_CA_CERT_INVALID |
|
57 do_check_eq(histogram.counts[ 4], 0 + 5); // SEC_ERROR_UNTRUSTED_ISSUER |
|
58 do_check_eq(histogram.counts[ 5], 0 + 1); // SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE |
|
59 do_check_eq(histogram.counts[ 6], 0 + 1); // SEC_ERROR_UNTRUSTED_CERT |
|
60 do_check_eq(histogram.counts[ 7], 0 + 1); // SEC_ERROR_INADEQUATE_KEY_USAGE |
|
61 do_check_eq(histogram.counts[ 8], 2 + 2); // SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED |
|
62 do_check_eq(histogram.counts[ 9], 4 + 4); // SSL_ERROR_BAD_CERT_DOMAIN |
|
63 do_check_eq(histogram.counts[10], 5 + 5); // SEC_ERROR_EXPIRED_CERTIFICATE |
|
64 run_next_test(); |
|
65 } |
|
66 |
|
67 function run_test() { |
|
68 add_tls_server_setup("BadCertServer"); |
|
69 |
|
70 let fakeOCSPResponder = new HttpServer(); |
|
71 fakeOCSPResponder.registerPrefixHandler("/", function (request, response) { |
|
72 response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); |
|
73 }); |
|
74 fakeOCSPResponder.start(8080); |
|
75 |
|
76 add_tests_in_mode(true); |
|
77 add_tests_in_mode(false); |
|
78 |
|
79 add_test(function () { |
|
80 fakeOCSPResponder.stop(check_telemetry); |
|
81 }); |
|
82 |
|
83 run_next_test(); |
|
84 } |
|
85 |
|
86 function add_tests_in_mode(useMozillaPKIX) { |
|
87 add_test(function () { |
|
88 Services.prefs.setBoolPref("security.use_mozillapkix_verification", |
|
89 useMozillaPKIX); |
|
90 run_next_test(); |
|
91 }); |
|
92 |
|
93 add_simple_tests(useMozillaPKIX); |
|
94 add_combo_tests(useMozillaPKIX); |
|
95 add_distrust_tests(useMozillaPKIX); |
|
96 |
|
97 add_test(function () { |
|
98 certOverrideService.clearValidityOverride("all:temporary-certificates", 0); |
|
99 run_next_test(); |
|
100 }); |
|
101 } |
|
102 |
|
103 function add_simple_tests(useMozillaPKIX) { |
|
104 add_cert_override_test("expired.example.com", |
|
105 Ci.nsICertOverrideService.ERROR_TIME, |
|
106 getXPCOMStatusFromNSS(SEC_ERROR_EXPIRED_CERTIFICATE)); |
|
107 if (useMozillaPKIX) { |
|
108 add_cert_override_test("selfsigned.example.com", |
|
109 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
110 getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)); |
|
111 } else { |
|
112 add_cert_override_test("selfsigned.example.com", |
|
113 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
114 getXPCOMStatusFromNSS(SEC_ERROR_CA_CERT_INVALID)); |
|
115 } |
|
116 add_cert_override_test("unknownissuer.example.com", |
|
117 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
118 getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)); |
|
119 add_cert_override_test("expiredissuer.example.com", |
|
120 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
121 getXPCOMStatusFromNSS( |
|
122 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
123 : SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE)); |
|
124 add_cert_override_test("md5signature.example.com", |
|
125 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
126 getXPCOMStatusFromNSS( |
|
127 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED)); |
|
128 add_cert_override_test("mismatch.example.com", |
|
129 Ci.nsICertOverrideService.ERROR_MISMATCH, |
|
130 getXPCOMStatusFromNSS(SSL_ERROR_BAD_CERT_DOMAIN)); |
|
131 |
|
132 // A Microsoft IIS utility generates self-signed certificates with |
|
133 // properties similar to the one this "host" will present (see |
|
134 // tlsserver/generate_certs.sh). |
|
135 // One of the errors classic verification collects is that this |
|
136 // certificate has an inadequate key usage to sign a certificate |
|
137 // (i.e. itself). As a result, to be able to override this, |
|
138 // SEC_ERROR_INADEQUATE_KEY_USAGE must be overridable (although, |
|
139 // confusingly, this isn't the main error reported). |
|
140 // mozilla::pkix just says this certificate's issuer is unknown. |
|
141 if (useMozillaPKIX) { |
|
142 add_cert_override_test("selfsigned-inadequateEKU.example.com", |
|
143 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
144 getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_ISSUER)); |
|
145 } else { |
|
146 add_cert_override_test("selfsigned-inadequateEKU.example.com", |
|
147 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
148 getXPCOMStatusFromNSS(SEC_ERROR_CA_CERT_INVALID)); |
|
149 } |
|
150 |
|
151 // SEC_ERROR_INADEQUATE_KEY_USAGE is overridable in general for |
|
152 // classic verification, but not for mozilla::pkix verification. |
|
153 if (useMozillaPKIX) { |
|
154 add_non_overridable_test("inadequatekeyusage.example.com", |
|
155 SEC_ERROR_INADEQUATE_KEY_USAGE); |
|
156 } else { |
|
157 add_cert_override_test("inadequatekeyusage.example.com", |
|
158 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
159 getXPCOMStatusFromNSS(SEC_ERROR_INADEQUATE_KEY_USAGE)); |
|
160 } |
|
161 |
|
162 // Bug 990603: Apache documentation has recommended generating a self-signed |
|
163 // test certificate with basic constraints: CA:true. For compatibility, this |
|
164 // is a scenario in which an override is allowed. |
|
165 add_cert_override_test("self-signed-end-entity-with-cA-true.example.com", |
|
166 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
167 getXPCOMStatusFromNSS( |
|
168 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
169 : SEC_ERROR_UNTRUSTED_ISSUER)); |
|
170 } |
|
171 |
|
172 function add_combo_tests(useMozillaPKIX) { |
|
173 // Note that "untrusted" here really is "unknown issuer" in the |
|
174 // mozilla::pkix case. |
|
175 |
|
176 add_cert_override_test("mismatch-expired.example.com", |
|
177 Ci.nsICertOverrideService.ERROR_MISMATCH | |
|
178 Ci.nsICertOverrideService.ERROR_TIME, |
|
179 getXPCOMStatusFromNSS(SSL_ERROR_BAD_CERT_DOMAIN)); |
|
180 add_cert_override_test("mismatch-untrusted.example.com", |
|
181 Ci.nsICertOverrideService.ERROR_MISMATCH | |
|
182 Ci.nsICertOverrideService.ERROR_UNTRUSTED, |
|
183 getXPCOMStatusFromNSS( |
|
184 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
185 : SEC_ERROR_UNTRUSTED_ISSUER)); |
|
186 add_cert_override_test("untrusted-expired.example.com", |
|
187 Ci.nsICertOverrideService.ERROR_UNTRUSTED | |
|
188 Ci.nsICertOverrideService.ERROR_TIME, |
|
189 getXPCOMStatusFromNSS( |
|
190 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
191 : SEC_ERROR_UNTRUSTED_ISSUER)); |
|
192 add_cert_override_test("mismatch-untrusted-expired.example.com", |
|
193 Ci.nsICertOverrideService.ERROR_MISMATCH | |
|
194 Ci.nsICertOverrideService.ERROR_UNTRUSTED | |
|
195 Ci.nsICertOverrideService.ERROR_TIME, |
|
196 getXPCOMStatusFromNSS( |
|
197 useMozillaPKIX ? SEC_ERROR_UNKNOWN_ISSUER |
|
198 : SEC_ERROR_UNTRUSTED_ISSUER)); |
|
199 |
|
200 add_cert_override_test("md5signature-expired.example.com", |
|
201 Ci.nsICertOverrideService.ERROR_UNTRUSTED | |
|
202 Ci.nsICertOverrideService.ERROR_TIME, |
|
203 getXPCOMStatusFromNSS( |
|
204 SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED)); |
|
205 } |
|
206 |
|
207 function add_distrust_tests(useMozillaPKIX) { |
|
208 // Before we specifically distrust this certificate, it should be trusted. |
|
209 add_connection_test("untrusted.example.com", Cr.NS_OK); |
|
210 |
|
211 // XXX(Bug 975777): Active distrust is an overridable error when NSS-based |
|
212 // verification is used. |
|
213 add_distrust_override_test("tlsserver/default-ee.der", |
|
214 "untrusted.example.com", |
|
215 getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_CERT), |
|
216 useMozillaPKIX |
|
217 ? getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_CERT) |
|
218 : Cr.NS_OK); |
|
219 |
|
220 // XXX(Bug 975777): Active distrust is an overridable error when NSS-based |
|
221 // verification is used. |
|
222 add_distrust_override_test("tlsserver/other-test-ca.der", |
|
223 "untrustedissuer.example.com", |
|
224 getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_ISSUER), |
|
225 useMozillaPKIX |
|
226 ? getXPCOMStatusFromNSS(SEC_ERROR_UNTRUSTED_ISSUER) |
|
227 : Cr.NS_OK); |
|
228 } |
|
229 |
|
230 function add_distrust_override_test(certFileName, hostName, |
|
231 expectedResultBefore, expectedResultAfter) { |
|
232 let certToDistrust = constructCertFromFile(certFileName); |
|
233 |
|
234 add_test(function () { |
|
235 // Add an entry to the NSS certDB that says to distrust the cert |
|
236 setCertTrust(certToDistrust, "pu,,"); |
|
237 clearSessionCache(); |
|
238 run_next_test(); |
|
239 }); |
|
240 add_connection_test(hostName, expectedResultBefore, null, |
|
241 function (securityInfo) { |
|
242 securityInfo.QueryInterface(Ci.nsISSLStatusProvider); |
|
243 // XXX(Bug 754369): SSLStatus isn't available for |
|
244 // non-overridable errors. |
|
245 if (securityInfo.SSLStatus) { |
|
246 certOverrideService.rememberValidityOverride( |
|
247 hostName, 8443, securityInfo.SSLStatus.serverCert, |
|
248 Ci.nsICertOverrideService.ERROR_UNTRUSTED, true); |
|
249 } else { |
|
250 // A missing SSLStatus probably means (due to bug |
|
251 // 754369) that the error was non-overridable, which |
|
252 // is what we're trying to test, though we'd rather |
|
253 // not test it this way. |
|
254 do_check_neq(expectedResultAfter, Cr.NS_OK); |
|
255 } |
|
256 clearSessionCache(); |
|
257 }); |
|
258 add_connection_test(hostName, expectedResultAfter, null, |
|
259 function () { |
|
260 setCertTrust(certToDistrust, "u,,"); |
|
261 }); |
|
262 } |