michael@0: // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: // This Source Code Form is subject to the terms of the Mozilla Public michael@0: // License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: // file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: "use strict"; michael@0: michael@0: // In which we connect to a number of domains (as faked by a server running michael@0: // locally) with and without OCSP stapling enabled to determine that good michael@0: // things happen and bad things don't. michael@0: michael@0: let gExpectOCSPRequest; michael@0: michael@0: function add_ocsp_test(aHost, aExpectedResult, aStaplingEnabled) { michael@0: add_connection_test(aHost, aExpectedResult, michael@0: function() { michael@0: gExpectOCSPRequest = !aStaplingEnabled; michael@0: clearOCSPCache(); michael@0: clearSessionCache(); michael@0: Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", michael@0: aStaplingEnabled); michael@0: }); michael@0: } michael@0: michael@0: function add_tests_in_mode(useMozillaPKIX, certDB, otherTestCA) { michael@0: add_test(function () { michael@0: Services.prefs.setBoolPref("security.use_mozillapkix_verification", michael@0: useMozillaPKIX); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: // In the absence of OCSP stapling, these should actually all work. michael@0: add_ocsp_test("ocsp-stapling-good.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-revoked.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-good-other-ca.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-malformed.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-srverr.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-trylater.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-needssig.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-unauthorized.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-unknown.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-good-other.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-none.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-critical-extension.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-noncritical-extension.example.com", Cr.NS_OK, false); michael@0: add_ocsp_test("ocsp-stapling-empty-extensions.example.com", Cr.NS_OK, false); michael@0: michael@0: // Now test OCSP stapling michael@0: // The following error codes are defined in security/nss/lib/util/SECerrs.h michael@0: michael@0: add_ocsp_test("ocsp-stapling-good.example.com", Cr.NS_OK, true); michael@0: michael@0: add_ocsp_test("ocsp-stapling-revoked.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), true); michael@0: michael@0: // SEC_ERROR_OCSP_INVALID_SIGNING_CERT vs SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE michael@0: // depends on whether the CA that signed the response is a trusted CA michael@0: // (but only with the classic implementation - mozilla::pkix always michael@0: // results in the error SEC_ERROR_OCSP_INVALID_SIGNING_CERT). michael@0: michael@0: // This stapled response is from a CA that is untrusted and did not issue michael@0: // the server's certificate. michael@0: add_test(function() { michael@0: certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT, michael@0: Ci.nsIX509CertDB.UNTRUSTED); michael@0: run_next_test(); michael@0: }); michael@0: add_ocsp_test("ocsp-stapling-good-other-ca.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: michael@0: // The stapled response is from a CA that is trusted but did not issue the michael@0: // server's certificate. michael@0: add_test(function() { michael@0: certDB.setCertTrust(otherTestCA, Ci.nsIX509Cert.CA_CERT, michael@0: Ci.nsIX509CertDB.TRUSTED_SSL); michael@0: run_next_test(); michael@0: }); michael@0: // TODO(bug 979055): When using ByName instead of ByKey, the error here is michael@0: // SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE. We should be testing both cases. michael@0: add_ocsp_test("ocsp-stapling-good-other-ca.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), michael@0: true); michael@0: michael@0: // TODO: Test the case where the signing cert can't be found at all, which michael@0: // will result in SEC_ERROR_BAD_DATABASE in the NSS classic case. michael@0: michael@0: add_ocsp_test("ocsp-stapling-malformed.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_REQUEST), true); michael@0: add_ocsp_test("ocsp-stapling-srverr.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_SERVER_ERROR), true); michael@0: add_ocsp_test("ocsp-stapling-trylater.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_TRY_SERVER_LATER), true); michael@0: add_ocsp_test("ocsp-stapling-needssig.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG), true); michael@0: add_ocsp_test("ocsp-stapling-unauthorized.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST), michael@0: true); michael@0: add_ocsp_test("ocsp-stapling-unknown.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-good-other.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), true); michael@0: // If the server doesn't staple an OCSP response, we continue as normal michael@0: // (this means that even though stapling is enabled, we expect an OCSP michael@0: // request). michael@0: add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, michael@0: function() { michael@0: gExpectOCSPRequest = true; michael@0: clearOCSPCache(); michael@0: clearSessionCache(); michael@0: Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true); michael@0: } michael@0: ); michael@0: add_ocsp_test("ocsp-stapling-empty.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_RESPONSE), true); michael@0: michael@0: // TODO(bug 979070): NSS can't handle this yet. michael@0: if (useMozillaPKIX) { michael@0: add_ocsp_test("ocsp-stapling-skip-responseBytes.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_MALFORMED_RESPONSE), true); michael@0: } michael@0: michael@0: add_ocsp_test("ocsp-stapling-critical-extension.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) michael@0: : Cr.NS_OK, // TODO(bug 987426): NSS doesn't handle unknown critical extensions michael@0: true); michael@0: add_ocsp_test("ocsp-stapling-noncritical-extension.example.com", Cr.NS_OK, true); michael@0: // TODO(bug 997994): Disallow empty Extensions in responses michael@0: add_ocsp_test("ocsp-stapling-empty-extensions.example.com", Cr.NS_OK, true); michael@0: michael@0: add_ocsp_test("ocsp-stapling-delegated-included.example.com", Cr.NS_OK, true); michael@0: add_ocsp_test("ocsp-stapling-delegated-included-last.example.com", Cr.NS_OK, true); michael@0: add_ocsp_test("ocsp-stapling-delegated-missing.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-delegated-missing-multiple.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-delegated-no-extKeyUsage.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-delegated-from-intermediate.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-delegated-keyUsage-crlSigning.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: add_ocsp_test("ocsp-stapling-delegated-wrong-extKeyUsage.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_INVALID_SIGNING_CERT), true); michael@0: michael@0: // ocsp-stapling-expired.example.com and michael@0: // ocsp-stapling-expired-fresh-ca.example.com are handled in michael@0: // test_ocsp_stapling_expired.js michael@0: } michael@0: michael@0: function check_ocsp_stapling_telemetry() { michael@0: let histogram = Cc["@mozilla.org/base/telemetry;1"] michael@0: .getService(Ci.nsITelemetry) michael@0: .getHistogramById("SSL_OCSP_STAPLING") michael@0: .snapshot(); michael@0: do_check_eq(histogram.counts[0], 2 * 0); // histogram bucket 0 is unused michael@0: do_check_eq(histogram.counts[1], 5 + 6); // 5 or 6 connections with a good response (bug 987426) michael@0: do_check_eq(histogram.counts[2], 2 * 18); // 18 connections with no stapled resp. michael@0: do_check_eq(histogram.counts[3], 2 * 0); // 0 connections with an expired response michael@0: do_check_eq(histogram.counts[4], 19 + 17); // 19 or 17 connections with bad responses (bug 979070, bug 987426) michael@0: run_next_test(); michael@0: } michael@0: michael@0: function run_test() { michael@0: do_get_profile(); michael@0: michael@0: let certDB = Cc["@mozilla.org/security/x509certdb;1"] michael@0: .getService(Ci.nsIX509CertDB); michael@0: let otherTestCAFile = do_get_file("tlsserver/other-test-ca.der", false); michael@0: let otherTestCADER = readFile(otherTestCAFile); michael@0: let otherTestCA = certDB.constructX509(otherTestCADER, otherTestCADER.length); michael@0: michael@0: let fakeOCSPResponder = new HttpServer(); michael@0: fakeOCSPResponder.registerPrefixHandler("/", function (request, response) { michael@0: response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); michael@0: do_check_true(gExpectOCSPRequest); michael@0: }); michael@0: fakeOCSPResponder.start(8080); michael@0: michael@0: add_tls_server_setup("OCSPStaplingServer"); michael@0: michael@0: add_tests_in_mode(true, certDB, otherTestCA); michael@0: add_tests_in_mode(false, certDB, otherTestCA); michael@0: michael@0: add_test(function () { michael@0: fakeOCSPResponder.stop(check_ocsp_stapling_telemetry); michael@0: }); michael@0: michael@0: run_next_test(); michael@0: }