400 lines
9.7 KiB
JavaScript
400 lines
9.7 KiB
JavaScript
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
"use strict";
|
|
|
|
// In which we connect to a number of domains (as faked by a server running
|
|
// locally) with and without OCSP stapling enabled to determine that good
|
|
// things happen and bad things don't.
|
|
|
|
// Enable the collection (during test) for all products so even products
|
|
// that don't collect the data will be able to run the test without failure.
|
|
Services.prefs.setBoolPref(
|
|
"toolkit.telemetry.testing.overrideProductsCheck",
|
|
true
|
|
);
|
|
|
|
var gExpectOCSPRequest;
|
|
|
|
function add_ocsp_test(
|
|
aHost,
|
|
aExpectedResult,
|
|
aStaplingEnabled,
|
|
aExpectOCSPRequest = false
|
|
) {
|
|
add_connection_test(aHost, aExpectedResult, function () {
|
|
gExpectOCSPRequest = aExpectOCSPRequest;
|
|
clearOCSPCache();
|
|
clearSessionCache();
|
|
Services.prefs.setBoolPref(
|
|
"security.ssl.enable_ocsp_stapling",
|
|
aStaplingEnabled
|
|
);
|
|
});
|
|
}
|
|
|
|
function add_tests() {
|
|
// In the absence of OCSP stapling, these should actually all work.
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-revoked.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good-other-ca.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-malformed.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-srverr.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-trylater.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-needssig.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-unauthorized.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-unknown.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good-other.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-none.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-expired.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-expired-fresh-ca.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-skip-responseBytes.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-critical-extension.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-noncritical-extension.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-empty-extensions.example.com",
|
|
PRErrorCodeSuccess,
|
|
false,
|
|
true
|
|
);
|
|
|
|
// Now test OCSP stapling
|
|
// The following error codes are defined in security/nss/lib/util/SECerrs.h
|
|
|
|
add_ocsp_test("ocsp-stapling-good.example.com", PRErrorCodeSuccess, true);
|
|
|
|
add_ocsp_test(
|
|
"ocsp-stapling-revoked.example.com",
|
|
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
true
|
|
);
|
|
|
|
// This stapled response is from a CA that is untrusted and did not issue
|
|
// the server's certificate.
|
|
let certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
|
|
Ci.nsIX509CertDB
|
|
);
|
|
let otherTestCA = constructCertFromFile("ocsp_certs/other-test-ca.pem");
|
|
add_test(function () {
|
|
certDB.setCertTrust(
|
|
otherTestCA,
|
|
Ci.nsIX509Cert.CA_CERT,
|
|
Ci.nsIX509CertDB.UNTRUSTED
|
|
);
|
|
run_next_test();
|
|
});
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good-other-ca.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
|
|
// The stapled response is from a CA that is trusted but did not issue the
|
|
// server's certificate.
|
|
add_test(function () {
|
|
certDB.setCertTrust(
|
|
otherTestCA,
|
|
Ci.nsIX509Cert.CA_CERT,
|
|
Ci.nsIX509CertDB.TRUSTED_SSL
|
|
);
|
|
run_next_test();
|
|
});
|
|
// TODO(bug 979055): When using ByName instead of ByKey, the error here is
|
|
// SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE. We should be testing both cases.
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good-other-ca.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
|
|
// TODO: Test the case where the signing cert can't be found at all, which
|
|
// will result in SEC_ERROR_BAD_DATABASE in the NSS classic case.
|
|
|
|
add_ocsp_test(
|
|
"ocsp-stapling-malformed.example.com",
|
|
SEC_ERROR_OCSP_MALFORMED_REQUEST,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-srverr.example.com",
|
|
SEC_ERROR_OCSP_SERVER_ERROR,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-trylater.example.com",
|
|
SEC_ERROR_OCSP_TRY_SERVER_LATER,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-needssig.example.com",
|
|
SEC_ERROR_OCSP_REQUEST_NEEDS_SIG,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-unauthorized.example.com",
|
|
SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-unknown.example.com",
|
|
SEC_ERROR_OCSP_UNKNOWN_CERT,
|
|
true
|
|
);
|
|
// If the server staples an OCSP response that doesn't contain a status for
|
|
// the server certificate, we defer returning the error and attempt to fetch
|
|
// a more suitable response. If that fails, the deferred error is returned.
|
|
add_ocsp_test(
|
|
"ocsp-stapling-good-other.example.com",
|
|
MOZILLA_PKIX_ERROR_OCSP_RESPONSE_FOR_CERT_MISSING,
|
|
true,
|
|
true
|
|
);
|
|
// If the server doesn't staple an OCSP response, we continue as normal
|
|
// (this means that even though stapling is enabled, we expect an OCSP
|
|
// request).
|
|
add_ocsp_test(
|
|
"ocsp-stapling-none.example.com",
|
|
PRErrorCodeSuccess,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-empty.example.com",
|
|
SEC_ERROR_OCSP_MALFORMED_RESPONSE,
|
|
true
|
|
);
|
|
|
|
add_ocsp_test(
|
|
"ocsp-stapling-skip-responseBytes.example.com",
|
|
SEC_ERROR_OCSP_MALFORMED_RESPONSE,
|
|
true
|
|
);
|
|
|
|
add_ocsp_test(
|
|
"ocsp-stapling-critical-extension.example.com",
|
|
SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-noncritical-extension.example.com",
|
|
PRErrorCodeSuccess,
|
|
true
|
|
);
|
|
// TODO(bug 997994): Disallow empty Extensions in responses
|
|
add_ocsp_test(
|
|
"ocsp-stapling-empty-extensions.example.com",
|
|
PRErrorCodeSuccess,
|
|
true
|
|
);
|
|
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-included.example.com",
|
|
PRErrorCodeSuccess,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-included-last.example.com",
|
|
PRErrorCodeSuccess,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-missing.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-missing-multiple.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-no-extKeyUsage.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-from-intermediate.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-keyUsage-crlSigning.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
add_ocsp_test(
|
|
"ocsp-stapling-delegated-wrong-extKeyUsage.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
|
|
// ocsp-stapling-expired.example.com and
|
|
// ocsp-stapling-expired-fresh-ca.example.com are handled in
|
|
// test_ocsp_stapling_expired.js
|
|
|
|
// Check that OCSP responder certificates with key sizes below 1024 bits are
|
|
// rejected, even when the main certificate chain keys are at least 1024 bits.
|
|
add_ocsp_test(
|
|
"keysize-ocsp-delegated.example.com",
|
|
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
|
|
true,
|
|
true
|
|
);
|
|
|
|
add_ocsp_test(
|
|
"revoked-ca-cert-used-as-end-entity.example.com",
|
|
SEC_ERROR_REVOKED_CERTIFICATE,
|
|
true
|
|
);
|
|
}
|
|
|
|
function check_ocsp_stapling_telemetry() {
|
|
let histogram = Services.telemetry
|
|
.getHistogramById("SSL_OCSP_STAPLING")
|
|
.snapshot();
|
|
equal(
|
|
histogram.values[0],
|
|
0,
|
|
"Should have 0 connections for unused histogram bucket 0"
|
|
);
|
|
equal(
|
|
histogram.values[1],
|
|
5,
|
|
"Actual and expected connections with a good response should match"
|
|
);
|
|
equal(
|
|
histogram.values[2],
|
|
18,
|
|
"Actual and expected connections with no stapled response should match"
|
|
);
|
|
equal(
|
|
histogram.values[3] || 0,
|
|
0,
|
|
"Actual and expected connections with an expired response should match"
|
|
);
|
|
equal(
|
|
histogram.values[4],
|
|
21,
|
|
"Actual and expected connections with bad responses should match"
|
|
);
|
|
run_next_test();
|
|
}
|
|
|
|
function run_test() {
|
|
do_get_profile();
|
|
Services.prefs.setIntPref("security.OCSP.enabled", 1);
|
|
// This test may sometimes fail on android due to an OCSP request timing out.
|
|
// That aspect of OCSP requests is not what we're testing here, so we can just
|
|
// bump the timeout and hopefully avoid these failures.
|
|
Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
|
|
|
|
let fakeOCSPResponder = new HttpServer();
|
|
fakeOCSPResponder.registerPrefixHandler("/", function (request, response) {
|
|
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
|
|
ok(
|
|
gExpectOCSPRequest,
|
|
"Should be getting an OCSP request only when expected"
|
|
);
|
|
});
|
|
fakeOCSPResponder.start(8888);
|
|
|
|
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
|
|
|
|
add_tests();
|
|
|
|
add_test(function () {
|
|
fakeOCSPResponder.stop(check_ocsp_stapling_telemetry);
|
|
});
|
|
|
|
run_next_test();
|
|
}
|