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 | // In which we connect to a number of domains (as faked by a server running |
michael@0 | 8 | // locally) with and without OCSP stapling enabled to determine that good |
michael@0 | 9 | // things happen and bad things don't. |
michael@0 | 10 | |
michael@0 | 11 | let gExpectOCSPRequest; |
michael@0 | 12 | |
michael@0 | 13 | function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled) { |
michael@0 | 14 | add_connection_test(aHost, aExpectedResult, |
michael@0 | 15 | function() { |
michael@0 | 16 | gExpectOCSPRequest = !aStaplingEnabled; |
michael@0 | 17 | clearOCSPCache(); |
michael@0 | 18 | clearSessionCache(); |
michael@0 | 19 | Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", |
michael@0 | 20 | aStaplingEnabled); |
michael@0 | 21 | }); |
michael@0 | 22 | } |
michael@0 | 23 | |
michael@0 | 24 | function add_tests_in_mode(useMozillaPKIX, certDB, otherTestCA) { |
michael@0 | 25 | add_test(function () { |
michael@0 | 26 | Services.prefs.setBoolPref("security.use_mozillapkix_verification", |
michael@0 | 27 | useMozillaPKIX); |
michael@0 | 28 | run_next_test(); |
michael@0 | 29 | }); |
michael@0 | 30 | |
michael@0 | 31 | // In the absence of OCSP stapling, these should actually all work. |
michael@0 | 32 | add_ocsp_test("ocsp-stapling-good.example.com", Cr.NS_OK, false); |
michael@0 | 33 | add_ocsp_test("ocsp-stapling-revoked.example.com", Cr.NS_OK, false); |
michael@0 | 34 | add_ocsp_test("ocsp-stapling-good-other-ca.example.com", Cr.NS_OK, false); |
michael@0 | 35 | add_ocsp_test("ocsp-stapling-malformed.example.com", Cr.NS_OK, false); |
michael@0 | 36 | add_ocsp_test("ocsp-stapling-srverr.example.com", Cr.NS_OK, false); |
michael@0 | 37 | add_ocsp_test("ocsp-stapling-trylater.example.com", Cr.NS_OK, false); |
michael@0 | 38 | add_ocsp_test("ocsp-stapling-needssig.example.com", Cr.NS_OK, false); |
michael@0 | 39 | add_ocsp_test("ocsp-stapling-unauthorized.example.com", Cr.NS_OK, false); |
michael@0 | 40 | add_ocsp_test("ocsp-stapling-unknown.example.com", Cr.NS_OK, false); |
michael@0 | 41 | add_ocsp_test("ocsp-stapling-good-other.example.com", Cr.NS_OK, false); |
michael@0 | 42 | add_ocsp_test("ocsp-stapling-none.example.com", Cr.NS_OK, false); |
michael@0 | 43 | add_ocsp_test("ocsp-stapling-expired.example.com", Cr.NS_OK, false); |
michael@0 | 44 | add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", Cr.NS_OK, false); |
michael@0 | 45 | add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com", Cr.NS_OK, false); |
michael@0 | 46 | add_ocsp_test("ocsp-stapling-critical-extension.example.com", Cr.NS_OK, false); |
michael@0 | 47 | add_ocsp_test("ocsp-stapling-noncritical-extension.example.com", Cr.NS_OK, false); |
michael@0 | 48 | add_ocsp_test("ocsp-stapling-empty-extensions.example.com", Cr.NS_OK, false); |
michael@0 | 49 | |
michael@0 | 50 | // Now test OCSP stapling |
michael@0 | 51 | // The following error codes are defined in security/nss/lib/util/SECerrs.h |
michael@0 | 52 | |
michael@0 | 53 | add_ocsp_test("ocsp-stapling-good.example.com", Cr.NS_OK, true); |
michael@0 | 54 | |
michael@0 | 55 | add_ocsp_test("ocsp-stapling-revoked.example.com", |
michael@0 | 56 | getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), true); |
michael@0 | 57 | |
michael@0 | 58 | // SEC_ERROR_OCSP_INVALID_SIGNING_CERT vs SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE |
michael@0 | 59 | // depends on whether the CA that signed the response is a trusted CA |
michael@0 | 60 | // (but only with the classic implementation - mozilla::pkix always |
michael@0 | 61 | // results in the error SEC_ERROR_OCSP_INVALID_SIGNING_CERT). |
michael@0 | 62 | |
michael@0 | 63 | // This stapled response is from a CA that is untrusted and did not issue |
michael@0 | 64 | // the server's certificate. |
michael@0 | 65 | add_test(function() { |
michael@0 | 66 | certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT, |
michael@0 | 67 | Ci.nsIX509CertDB.UNTRUSTED); |
michael@0 | 68 | run_next_test(); |
michael@0 | 69 | }); |
michael@0 | 70 | add_ocsp_test("ocsp-stapling-good-other-ca.example.com", |
michael@0 | 71 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 72 | |
michael@0 | 73 | // The stapled response is from a CA that is trusted but did not issue the |
michael@0 | 74 | // server's certificate. |
michael@0 | 75 | add_test(function() { |
michael@0 | 76 | certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT, |
michael@0 | 77 | Ci.nsIX509CertDB.TRUSTED_SSL); |
michael@0 | 78 | run_next_test(); |
michael@0 | 79 | }); |
michael@0 | 80 | // TODO(bug 979055): When using ByName instead of ByKey, the error here is |
michael@0 | 81 | // SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE. We should be testing both cases. |
michael@0 | 82 | add_ocsp_test("ocsp-stapling-good-other-ca.example.com", |
michael@0 | 83 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), |
michael@0 | 84 | true); |
michael@0 | 85 | |
michael@0 | 86 | // TODO: Test the case where the signing cert can't be found at all, which |
michael@0 | 87 | // will result in SEC_ERROR_BAD_DATABASE in the NSS classic case. |
michael@0 | 88 | |
michael@0 | 89 | add_ocsp_test("ocsp-stapling-malformed.example.com", |
michael@0 | 90 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_REQUEST), true); |
michael@0 | 91 | add_ocsp_test("ocsp-stapling-srverr.example.com", |
michael@0 | 92 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_SERVER_ERROR), true); |
michael@0 | 93 | add_ocsp_test("ocsp-stapling-trylater.example.com", |
michael@0 | 94 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_TRY_SERVER_LATER), true); |
michael@0 | 95 | add_ocsp_test("ocsp-stapling-needssig.example.com", |
michael@0 | 96 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG), true); |
michael@0 | 97 | add_ocsp_test("ocsp-stapling-unauthorized.example.com", |
michael@0 | 98 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST), |
michael@0 | 99 | true); |
michael@0 | 100 | add_ocsp_test("ocsp-stapling-unknown.example.com", |
michael@0 | 101 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), true); |
michael@0 | 102 | add_ocsp_test("ocsp-stapling-good-other.example.com", |
michael@0 | 103 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), true); |
michael@0 | 104 | // If the server doesn't staple an OCSP response, we continue as normal |
michael@0 | 105 | // (this means that even though stapling is enabled, we expect an OCSP |
michael@0 | 106 | // request). |
michael@0 | 107 | add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, |
michael@0 | 108 | function() { |
michael@0 | 109 | gExpectOCSPRequest = true; |
michael@0 | 110 | clearOCSPCache(); |
michael@0 | 111 | clearSessionCache(); |
michael@0 | 112 | Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true); |
michael@0 | 113 | } |
michael@0 | 114 | ); |
michael@0 | 115 | add_ocsp_test("ocsp-stapling-empty.example.com", |
michael@0 | 116 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_RESPONSE), true); |
michael@0 | 117 | |
michael@0 | 118 | // TODO(bug 979070): NSS can't handle this yet. |
michael@0 | 119 | if (useMozillaPKIX) { |
michael@0 | 120 | add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com", |
michael@0 | 121 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_RESPONSE), true); |
michael@0 | 122 | } |
michael@0 | 123 | |
michael@0 | 124 | add_ocsp_test("ocsp-stapling-critical-extension.example.com", |
michael@0 | 125 | useMozillaPKIX |
michael@0 | 126 | ? getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) |
michael@0 | 127 | : Cr.NS_OK, // TODO(bug 987426): NSS doesn't handle unknown critical extensions |
michael@0 | 128 | true); |
michael@0 | 129 | add_ocsp_test("ocsp-stapling-noncritical-extension.example.com", Cr.NS_OK, true); |
michael@0 | 130 | // TODO(bug 997994): Disallow empty Extensions in responses |
michael@0 | 131 | add_ocsp_test("ocsp-stapling-empty-extensions.example.com", Cr.NS_OK, true); |
michael@0 | 132 | |
michael@0 | 133 | add_ocsp_test("ocsp-stapling-delegated-included.example.com", Cr.NS_OK, true); |
michael@0 | 134 | add_ocsp_test("ocsp-stapling-delegated-included-last.example.com", Cr.NS_OK, true); |
michael@0 | 135 | add_ocsp_test("ocsp-stapling-delegated-missing.example.com", |
michael@0 | 136 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 137 | add_ocsp_test("ocsp-stapling-delegated-missing-multiple.example.com", |
michael@0 | 138 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 139 | add_ocsp_test("ocsp-stapling-delegated-no-extKeyUsage.example.com", |
michael@0 | 140 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 141 | add_ocsp_test("ocsp-stapling-delegated-from-intermediate.example.com", |
michael@0 | 142 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 143 | add_ocsp_test("ocsp-stapling-delegated-keyUsage-crlSigning.example.com", |
michael@0 | 144 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 145 | add_ocsp_test("ocsp-stapling-delegated-wrong-extKeyUsage.example.com", |
michael@0 | 146 | getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); |
michael@0 | 147 | |
michael@0 | 148 | // ocsp-stapling-expired.example.com and |
michael@0 | 149 | // ocsp-stapling-expired-fresh-ca.example.com are handled in |
michael@0 | 150 | // test_ocsp_stapling_expired.js |
michael@0 | 151 | } |
michael@0 | 152 | |
michael@0 | 153 | function check_ocsp_stapling_telemetry() { |
michael@0 | 154 | let histogram = Cc["@mozilla.org/base/telemetry;1"] |
michael@0 | 155 | .getService(Ci.nsITelemetry) |
michael@0 | 156 | .getHistogramById("SSL_OCSP_STAPLING") |
michael@0 | 157 | .snapshot(); |
michael@0 | 158 | do_check_eq(histogram.counts[0], 2 * 0); // histogram bucket 0 is unused |
michael@0 | 159 | do_check_eq(histogram.counts[1], 5 + 6); // 5 or 6 connections with a good response (bug 987426) |
michael@0 | 160 | do_check_eq(histogram.counts[2], 2 * 18); // 18 connections with no stapled resp. |
michael@0 | 161 | do_check_eq(histogram.counts[3], 2 * 0); // 0 connections with an expired response |
michael@0 | 162 | do_check_eq(histogram.counts[4], 19 + 17); // 19 or 17 connections with bad responses (bug 979070, bug 987426) |
michael@0 | 163 | run_next_test(); |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | function run_test() { |
michael@0 | 167 | do_get_profile(); |
michael@0 | 168 | |
michael@0 | 169 | let certDB = Cc["@mozilla.org/security/x509certdb;1"] |
michael@0 | 170 | .getService(Ci.nsIX509CertDB); |
michael@0 | 171 | let otherTestCAFile = do_get_file("tlsserver/other-test-ca.der", false); |
michael@0 | 172 | let otherTestCADER = readFile(otherTestCAFile); |
michael@0 | 173 | let otherTestCA = certDB.constructX509(otherTestCADER, otherTestCADER.length); |
michael@0 | 174 | |
michael@0 | 175 | let fakeOCSPResponder = new HttpServer(); |
michael@0 | 176 | fakeOCSPResponder.registerPrefixHandler("/", function (request, response) { |
michael@0 | 177 | response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); |
michael@0 | 178 | do_check_true(gExpectOCSPRequest); |
michael@0 | 179 | }); |
michael@0 | 180 | fakeOCSPResponder.start(8080); |
michael@0 | 181 | |
michael@0 | 182 | add_tls_server_setup("OCSPStaplingServer"); |
michael@0 | 183 | |
michael@0 | 184 | add_tests_in_mode(true, certDB, otherTestCA); |
michael@0 | 185 | add_tests_in_mode(false, certDB, otherTestCA); |
michael@0 | 186 | |
michael@0 | 187 | add_test(function () { |
michael@0 | 188 | fakeOCSPResponder.stop(check_ocsp_stapling_telemetry); |
michael@0 | 189 | }); |
michael@0 | 190 | |
michael@0 | 191 | run_next_test(); |
michael@0 | 192 | } |