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