// -*- 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";
// Checks various aspects of the OCSP cache, mainly to to ensure we do not fetch // responses more than necessary.
var gFetchCount = 0; var gGoodOCSPResponse = null; var gResponsePattern = [];
function respondWithSHA1OCSP(request, response) {
info("returning 200 OK with sha-1 delegated response");
response.setStatusLine(request.httpVersion, 200, "OK");
response.setHeader("Content-Type", "application/ocsp-response");
let args = [["good-delegated", "default-ee", "delegatedSHA1Signer", 0]];
let responses = generateOCSPResponses(args, "ocsp_certs");
response.write(responses[0]);
}
function respondWithError(request, response) {
info("returning 500 Internal Server Error");
response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
let body = "Refusing to return a response";
response.bodyOutputStream.write(body, body.length);
}
function generateGoodOCSPResponse(thisUpdateSkew) {
let args = [["good", "default-ee", "unused", thisUpdateSkew]];
let responses = generateOCSPResponses(args, "ocsp_certs"); return responses[0];
}
function add_ocsp_test(
aHost,
aExpectedResult,
aResponses,
aMessage,
aOriginAttributes
) {
add_connection_test(
aHost,
aExpectedResult, function () {
clearSessionCache();
gFetchCount = 0;
gResponsePattern = aResponses;
}, function () { // check the number of requests matches the size of aResponses
equal(gFetchCount, aResponses.length, aMessage);
}, null,
aOriginAttributes
);
}
function run_test() {
do_get_profile();
Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
Services.prefs.setIntPref("security.OCSP.enabled", 1);
add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
let ocspResponder = new HttpServer();
ocspResponder.registerPrefixHandler("/", function (request, response) {
info("gFetchCount: " + gFetchCount);
let responseFunction = gResponsePattern[gFetchCount]; Assert.notEqual(undefined, responseFunction);
function add_tests() { // Test that verifying a certificate with a "short lifetime" doesn't result // in OCSP fetching. Due to longevity requirements in our testing // infrastructure, the certificate we encounter is valid for a very long // time, so we have to define a "short lifetime" as something very long.
add_test(function () {
Services.prefs.setIntPref( "security.pki.cert_short_lifetime_in_days",
12000
);
run_next_test();
});
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "expected zero OCSP requests for a short-lived certificate"
);
// If a "short lifetime" is something more reasonable, ensure that we do OCSP // fetching for this long-lived certificate.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithError], "expected one OCSP request for a long-lived certificate"
);
add_test(function () {
Services.prefs.clearUserPref("security.pki.cert_short_lifetime_in_days");
run_next_test();
}); // ---------------------------------------------------------------------------
// Reset state
add_test(function () {
clearOCSPCache();
run_next_test();
});
// This test assumes that OCSPStaplingServer uses the same cert for // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
// Get an Unknown response for the *.example.com cert and put it in the // OCSP cache.
add_ocsp_test( "ocsp-stapling-unknown.example.com",
SEC_ERROR_OCSP_UNKNOWN_CERT,
[], "Stapled Unknown response -> a fetch should not have been attempted"
);
// A failure to retrieve an OCSP response must result in the cached Unknown // response being recognized and honored.
add_ocsp_test( "ocsp-stapling-none.example.com",
SEC_ERROR_OCSP_UNKNOWN_CERT,
[respondWithError, respondWithError], "No stapled response -> a fetch should have been attempted"
);
// A valid Good response from the OCSP responder must override the cached // Unknown response. // // Note that We need to make sure that the Unknown response and the Good // response have different thisUpdate timestamps; otherwise, the Good // response will be seen as "not newer" and it won't replace the existing // entry.
add_test(function () {
gGoodOCSPResponse = generateGoodOCSPResponse(1200);
run_next_test();
});
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "Cached Unknown response, no stapled response -> a fetch" + " should have been attempted"
);
// The Good response retrieved from the previous fetch must have replaced // the Unknown response in the cache, resulting in the catched Good response // being returned and no fetch.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Cached Good response -> a fetch should not have been attempted"
);
// Reset state
add_test(function () {
clearOCSPCache();
run_next_test();
});
// A failure to retrieve an OCSP response will result in an error entry being // added to the cache.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithError], "No stapled response -> a fetch should have been attempted"
);
// The error entry will prevent a fetch from happening for a while.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure -> a fetch should not have been attempted"
);
// The error entry must not prevent a stapled OCSP response from being // honored.
add_ocsp_test( "ocsp-stapling-revoked.example.com",
SEC_ERROR_REVOKED_CERTIFICATE,
[], "Stapled Revoked response -> a fetch should not have been attempted"
);
// Ensure OCSP responses from signers with SHA1 certificates are OK. This // is included in the OCSP caching tests since there were OCSP cache-related // regressions when sha-1 telemetry probes were added.
add_test(function () {
clearOCSPCache(); // set security.OCSP.require so that checking the OCSP signature fails
Services.prefs.setBoolPref("security.OCSP.require", true);
run_next_test();
});
add_ocsp_test( "ocsp-stapling-none.example.com",
SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
[respondWithSHA1OCSP], "OCSP signing cert was issued with sha1 - should fail"
);
// Reset state
add_test(function () {
clearOCSPCache();
run_next_test();
});
// This test makes sure that OCSP cache are isolated by firstPartyDomain.
let gObservedCnt = 0;
let protocolProxyService = Cc[ "@mozilla.org/network/protocol-proxy-service;1"
].getService(Ci.nsIProtocolProxyService);
// Observe all channels and make sure the firstPartyDomain in their loadInfo's // origin attributes are aFirstPartyDomain. function startObservingChannels(aFirstPartyDomain) { // We use a dummy proxy filter to catch all channels, even those that do not // generate an "http-on-modify-request" notification.
let proxyFilter = {
applyFilter(aChannel, aProxy, aCallback) { // We have the channel; provide it to the callback. if (aChannel.originalURI.spec == "http://localhost:8888/") {
gObservedCnt++;
equal(
aChannel.loadInfo.originAttributes.firstPartyDomain,
aFirstPartyDomain, "firstPartyDomain should match"
);
} // Pass on aProxy unmodified.
aCallback.onProxyFilterResult(aProxy);
},
};
protocolProxyService.registerChannelFilter(proxyFilter, 0); // Return the stop() function: return () => protocolProxyService.unregisterChannelFilter(proxyFilter);
}
let stopObservingChannels;
add_test(function () {
stopObservingChannels = startObservingChannels("foo.com");
run_next_test();
});
// A good OCSP response will be cached.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "No stapled response (firstPartyDomain = foo.com) -> a fetch " + "should have been attempted",
{ firstPartyDomain: "foo.com" }
);
// The cache will prevent a fetch from happening.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure (firstPartyDomain = foo.com) -> a " + "fetch should not have been attempted",
{ firstPartyDomain: "foo.com" }
);
add_test(function () {
stopObservingChannels();
equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
gObservedCnt = 0;
run_next_test();
});
// But using a different firstPartyDomain should result in a fetch.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "No stapled response (firstPartyDomain = bar.com) -> a fetch " + "should have been attempted",
{ firstPartyDomain: "bar.com" }
);
add_test(function () {
stopObservingChannels();
equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
gObservedCnt = 0;
run_next_test();
});
// Reset state
add_test(function () {
clearOCSPCache();
run_next_test();
});
// Test that the OCSP cache is not isolated by userContextId.
// A good OCSP response will be cached.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "No stapled response (userContextId = 1) -> a fetch " + "should have been attempted",
{ userContextId: 1 }
);
// The cache will prevent a fetch from happening.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure (userContextId = 1) -> a " + "fetch should not have been attempted",
{ userContextId: 1 }
);
// Fetching is prevented even if in a different userContextId.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure (userContextId = 2) -> a " + "fetch should not have been attempted",
{ userContextId: 2 }
);
// A good OCSP response will be cached.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "No stapled response (partitionKey = (https,foo.com)) -> a fetch " + "should have been attempted",
{ partitionKey: "(https,foo.com)" }
);
// The cache will prevent a fetch from happening.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " + "fetch should not have been attempted",
{ partitionKey: "(https,foo.com)" }
);
// Using a different partitionKey should result in a fetch.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " + "fetch should have been attempted",
{ partitionKey: "(https,bar.com)" }
);
// Reset state
add_test(function () {
Services.prefs.clearUserPref("privacy.partition.network_state.ocsp_cache");
clearOCSPCache();
run_next_test();
});
// This test makes sure that OCSP cache are isolated by partitionKey in // private mode.
// A good OCSP response will be cached.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "No stapled response (partitionKey = (https,foo.com)) -> a fetch " + "should have been attempted",
{ partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
);
// The cache will prevent a fetch from happening.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[], "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " + "fetch should not have been attempted",
{ partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
);
// Using a different partitionKey should result in a fetch.
add_ocsp_test( "ocsp-stapling-none.example.com",
PRErrorCodeSuccess,
[respondWithGoodOCSP], "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " + "fetch should have been attempted",
{ partitionKey: "(https,bar.com)", privateBrowsingId: 1 }
);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.