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: let gFetchCount = 0; michael@0: let gGoodOCSPResponse = null; michael@0: michael@0: function generateGoodOCSPResponse() { michael@0: let args = [ ["good", "localhostAndExampleCom", "unused" ] ]; michael@0: let responses = generateOCSPResponses(args, "tlsserver"); michael@0: return responses[0]; michael@0: } michael@0: michael@0: function run_test() { michael@0: do_get_profile(); michael@0: Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true); michael@0: add_tls_server_setup("OCSPStaplingServer"); michael@0: michael@0: let ocspResponder = new HttpServer(); michael@0: ocspResponder.registerPrefixHandler("/", function(request, response) { michael@0: ++gFetchCount; michael@0: michael@0: do_print("gFetchCount: " + gFetchCount); michael@0: michael@0: if (gFetchCount != 2) { michael@0: do_print("returning 500 Internal Server Error"); michael@0: michael@0: response.setStatusLine(request.httpVersion, 500, "Internal Server Error"); michael@0: let body = "Refusing to return a response"; michael@0: response.bodyOutputStream.write(body, body.length); michael@0: return; michael@0: } michael@0: michael@0: do_print("returning 200 OK"); michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/ocsp-response"); michael@0: response.write(gGoodOCSPResponse); michael@0: }); michael@0: ocspResponder.start(8080); michael@0: michael@0: add_tests_in_mode(true); michael@0: add_tests_in_mode(false); michael@0: michael@0: add_test(function() { ocspResponder.stop(run_next_test); }); michael@0: run_next_test(); michael@0: } michael@0: michael@0: function add_tests_in_mode(useMozillaPKIX) { 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: // This test assumes that OCSPStaplingServer uses the same cert for michael@0: // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com. michael@0: michael@0: // Get an Unknown response for the *.exmaple.com cert and put it in the michael@0: // OCSP cache. michael@0: add_connection_test("ocsp-stapling-unknown.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 0); run_next_test(); }); michael@0: michael@0: // A failure to retrieve an OCSP response must result in the cached Unkown michael@0: // response being recognized and honored. michael@0: add_connection_test("ocsp-stapling-none.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_OCSP_UNKNOWN_CERT), michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); }); michael@0: michael@0: // A valid Good response from the OCSP responder must override the cached michael@0: // Unknown response. michael@0: // michael@0: // Note that We need to make sure that the Unknown response and the Good michael@0: // response have different thisUpdate timestamps; otherwise, the Good michael@0: // response will be seen as "not newer" and it won't replace the existing michael@0: // entry. michael@0: add_test(function() { michael@0: let duration = 1200; michael@0: do_print("Sleeping for " + duration + "ms"); michael@0: let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); michael@0: timer.initWithCallback(run_next_test, duration, Ci.nsITimer.TYPE_ONE_SHOT); michael@0: }); michael@0: add_test(function() { michael@0: gGoodOCSPResponse = generateGoodOCSPResponse(); michael@0: run_next_test(); michael@0: }); michael@0: add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); }); michael@0: michael@0: // The Good response retrieved from the previous fetch must have replaced michael@0: // the Unknown response in the cache, resulting in the catched Good response michael@0: // being returned and no fetch. michael@0: add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); }); michael@0: michael@0: michael@0: //--------------------------------------------------------------------------- michael@0: michael@0: // Reset state michael@0: add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); }); michael@0: michael@0: // A failure to retrieve an OCSP response will result in an error entry being michael@0: // added to the cache. michael@0: add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); }); michael@0: michael@0: // The error entry will prevent a fetch from happening for a while. michael@0: add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK, michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); }); michael@0: michael@0: // The error entry must not prevent a stapled OCSP response from being michael@0: // honored. michael@0: add_connection_test("ocsp-stapling-revoked.example.com", michael@0: getXPCOMStatusFromNSS(SEC_ERROR_REVOKED_CERTIFICATE), michael@0: clearSessionCache); michael@0: add_test(function() { do_check_eq(gFetchCount, 1); run_next_test(); }); michael@0: michael@0: //--------------------------------------------------------------------------- michael@0: michael@0: // Reset state michael@0: add_test(function() { clearOCSPCache(); gFetchCount = 0; run_next_test(); }); michael@0: }