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 OCSP stapling enabled to determine that good things happen michael@0: // and bad things don't, specifically with respect to various expired OCSP michael@0: // responses (stapled and otherwise). michael@0: michael@0: let gCurrentOCSPResponse = null; michael@0: let gOCSPRequestCount = 0; michael@0: michael@0: function add_ocsp_test(aHost, aExpectedResult, aOCSPResponseToServe) { michael@0: add_connection_test(aHost, aExpectedResult, michael@0: function() { michael@0: clearOCSPCache(); michael@0: clearSessionCache(); michael@0: gCurrentOCSPResponse = aOCSPResponseToServe; michael@0: gOCSPRequestCount = 0; michael@0: }, michael@0: function() { michael@0: do_check_eq(gOCSPRequestCount, 1); michael@0: }); michael@0: } michael@0: michael@0: do_get_profile(); michael@0: Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true); michael@0: let args = [["good", "localhostAndExampleCom", "unused"], michael@0: ["expiredresponse", "localhostAndExampleCom", "unused"], michael@0: ["oldvalidperiod", "localhostAndExampleCom", "unused"], michael@0: ["revoked", "localhostAndExampleCom", "unused"], michael@0: ["unknown", "localhostAndExampleCom", "unused"], michael@0: ]; michael@0: let ocspResponses = generateOCSPResponses(args, "tlsserver"); michael@0: // Fresh response, certificate is good. michael@0: let ocspResponseGood = ocspResponses[0]; michael@0: // Expired response, certificate is good. michael@0: let expiredOCSPResponseGood = ocspResponses[1]; michael@0: // Fresh signature, old validity period, certificate is good. michael@0: let oldValidityPeriodOCSPResponseGood = ocspResponses[2]; michael@0: // Fresh signature, certificate is revoked. michael@0: let ocspResponseRevoked = ocspResponses[3]; michael@0: // Fresh signature, certificate is unknown. michael@0: let ocspResponseUnknown = ocspResponses[4]; michael@0: michael@0: function run_test() { michael@0: let ocspResponder = new HttpServer(); michael@0: ocspResponder.registerPrefixHandler("/", function(request, response) { michael@0: if (gCurrentOCSPResponse) { michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/ocsp-response"); michael@0: response.write(gCurrentOCSPResponse); michael@0: } else { michael@0: response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); michael@0: response.write("Internal Server Error"); michael@0: } michael@0: gOCSPRequestCount++; michael@0: }); michael@0: ocspResponder.start(8080); michael@0: add_tls_server_setup("OCSPStaplingServer"); michael@0: add_tests_in_mode(true); michael@0: add_tests_in_mode(false); michael@0: add_test(function () { ocspResponder.stop(run_next_test); }); michael@0: add_test(check_ocsp_stapling_telemetry); michael@0: run_next_test(); michael@0: } michael@0: michael@0: function add_tests_in_mode(useMozillaPKIX) michael@0: { 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 these tests, the OCSP stapling server gives us a stapled michael@0: // response based on the host name ("ocsp-stapling-expired" or michael@0: // "ocsp-stapling-expired-fresh-ca"). We then ensure that we're michael@0: // properly falling back to fetching revocation information. michael@0: // For ocsp-stapling-expired.example.com, the OCSP stapling server michael@0: // staples an expired OCSP response. The certificate has not expired. michael@0: // For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling michael@0: // server staples an OCSP response with a recent signature but with an michael@0: // out-of-date validity period. The certificate has not expired. michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", Cr.NS_OK, michael@0: ocspResponseGood); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", Cr.NS_OK, michael@0: ocspResponseGood); michael@0: // With mozilla::pkix, if we can't fetch a more recent response when michael@0: // given an expired stapled response, we terminate the connection. michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: expiredOCSPResponseGood); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: expiredOCSPResponseGood); michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: oldValidityPeriodOCSPResponseGood); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: oldValidityPeriodOCSPResponseGood); michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: null); michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: useMozillaPKIX michael@0: ? getXPCOMStatusFromNSS(SEC_ERROR_OCSP_OLD_RESPONSE) michael@0: : Cr.NS_OK, michael@0: null); michael@0: // Of course, if the newer response indicates Revoked or Unknown, michael@0: // that status must be returned. michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: ocspResponseRevoked); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: ocspResponseRevoked); michael@0: add_ocsp_test("ocsp-stapling-expired.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: ocspResponseUnknown); michael@0: add_ocsp_test("ocsp-stapling-expired-fresh-ca.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: ocspResponseUnknown); michael@0: michael@0: if (useMozillaPKIX) { michael@0: // If the response is expired but indicates Revoked or Unknown and a michael@0: // newer status can't be fetched, the Revoked or Unknown status will michael@0: // be returned. michael@0: add_ocsp_test("ocsp-stapling-revoked-old.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: null); michael@0: add_ocsp_test("ocsp-stapling-unknown-old.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: null); michael@0: // If the response is expired but indicates Revoked or Unknown and michael@0: // a newer status can be fetched and successfully verified, this michael@0: // should result in a successful certificate verification. michael@0: add_ocsp_test("ocsp-stapling-revoked-old.example.com", Cr.NS_OK, michael@0: ocspResponseGood); michael@0: add_ocsp_test("ocsp-stapling-unknown-old.example.com", Cr.NS_OK, michael@0: ocspResponseGood); michael@0: // If a newer status can be fetched but it fails to verify, the michael@0: // Revoked or Unknown status of the expired stapled response michael@0: // should be returned. michael@0: add_ocsp_test("ocsp-stapling-revoked-old.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: expiredOCSPResponseGood); michael@0: add_ocsp_test("ocsp-stapling-unknown-old.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: expiredOCSPResponseGood); michael@0: } michael@0: michael@0: if (useMozillaPKIX) { michael@0: // These tests are verifying that an valid but very old response michael@0: // is rejected as a valid stapled response, requiring a fetch michael@0: // from the ocsp responder. michael@0: add_ocsp_test("ocsp-stapling-ancient-valid.example.com", Cr.NS_OK, michael@0: ocspResponseGood); michael@0: add_ocsp_test("ocsp-stapling-ancient-valid.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: ocspResponseRevoked); michael@0: add_ocsp_test("ocsp-stapling-ancient-valid.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: ocspResponseUnknown); michael@0: } 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], 2 * 0); // 0 connections with a good response michael@0: do_check_eq(histogram.counts[2], 2 * 0); // 0 connections with no stapled resp. michael@0: do_check_eq(histogram.counts[3], 2 * 12 + 9); // 12 connections with an expired response michael@0: // +9 more mozilla::pkix-only expired responses michael@0: do_check_eq(histogram.counts[4], 2 * 0); // 0 connections with bad responses michael@0: run_next_test(); michael@0: }