1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 // Checks various aspects of the OCSP cache, mainly to to ensure we do not fetch
8 // responses more than necessary.
11 var gGoodOCSPResponse = null;
12 var gResponsePattern = [];
14 function respondWithGoodOCSP(request, response) {
15 info("returning 200 OK");
16 response.setStatusLine(request.httpVersion, 200, "OK");
17 response.setHeader("Content-Type", "application/ocsp-response");
18 response.write(gGoodOCSPResponse);
21 function respondWithSHA1OCSP(request, response) {
22 info("returning 200 OK with sha-1 delegated response");
23 response.setStatusLine(request.httpVersion, 200, "OK");
24 response.setHeader("Content-Type", "application/ocsp-response");
26 let args = [["good-delegated", "default-ee", "delegatedSHA1Signer", 0]];
27 let responses = generateOCSPResponses(args, "ocsp_certs");
28 response.write(responses[0]);
31 function respondWithError(request, response) {
32 info("returning 500 Internal Server Error");
33 response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
34 let body = "Refusing to return a response";
35 response.bodyOutputStream.write(body, body.length);
38 function generateGoodOCSPResponse(thisUpdateSkew) {
39 let args = [["good", "default-ee", "unused", thisUpdateSkew]];
40 let responses = generateOCSPResponses(args, "ocsp_certs");
44 function add_ocsp_test(
57 gResponsePattern = aResponses;
60 // check the number of requests matches the size of aResponses
61 equal(gFetchCount, aResponses.length, aMessage);
70 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
71 Services.prefs.setIntPref("security.OCSP.enabled", 1);
72 add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
74 let ocspResponder = new HttpServer();
75 ocspResponder.registerPrefixHandler("/", function (request, response) {
76 info("gFetchCount: " + gFetchCount);
77 let responseFunction = gResponsePattern[gFetchCount];
78 Assert.notEqual(undefined, responseFunction);
81 responseFunction(request, response);
83 ocspResponder.start(8888);
87 add_test(function () {
88 ocspResponder.stop(run_next_test);
93 function add_tests() {
94 // Test that verifying a certificate with a "short lifetime" doesn't result
95 // in OCSP fetching. Due to longevity requirements in our testing
96 // infrastructure, the certificate we encounter is valid for a very long
97 // time, so we have to define a "short lifetime" as something very long.
98 add_test(function () {
99 Services.prefs.setIntPref(
100 "security.pki.cert_short_lifetime_in_days",
107 "ocsp-stapling-none.example.com",
110 "expected zero OCSP requests for a short-lived certificate"
113 add_test(function () {
114 Services.prefs.setIntPref("security.pki.cert_short_lifetime_in_days", 100);
118 // If a "short lifetime" is something more reasonable, ensure that we do OCSP
119 // fetching for this long-lived certificate.
122 "ocsp-stapling-none.example.com",
125 "expected one OCSP request for a long-lived certificate"
127 add_test(function () {
128 Services.prefs.clearUserPref("security.pki.cert_short_lifetime_in_days");
131 // ---------------------------------------------------------------------------
134 add_test(function () {
139 // This test assumes that OCSPStaplingServer uses the same cert for
140 // ocsp-stapling-unknown.example.com and ocsp-stapling-none.example.com.
142 // Get an Unknown response for the *.example.com cert and put it in the
145 "ocsp-stapling-unknown.example.com",
146 SEC_ERROR_OCSP_UNKNOWN_CERT,
148 "Stapled Unknown response -> a fetch should not have been attempted"
151 // A failure to retrieve an OCSP response must result in the cached Unknown
152 // response being recognized and honored.
154 "ocsp-stapling-none.example.com",
155 SEC_ERROR_OCSP_UNKNOWN_CERT,
156 [respondWithError, respondWithError],
157 "No stapled response -> a fetch should have been attempted"
160 // A valid Good response from the OCSP responder must override the cached
163 // Note that We need to make sure that the Unknown response and the Good
164 // response have different thisUpdate timestamps; otherwise, the Good
165 // response will be seen as "not newer" and it won't replace the existing
167 add_test(function () {
168 gGoodOCSPResponse = generateGoodOCSPResponse(1200);
172 "ocsp-stapling-none.example.com",
174 [respondWithGoodOCSP],
175 "Cached Unknown response, no stapled response -> a fetch" +
176 " should have been attempted"
179 // The Good response retrieved from the previous fetch must have replaced
180 // the Unknown response in the cache, resulting in the catched Good response
181 // being returned and no fetch.
183 "ocsp-stapling-none.example.com",
186 "Cached Good response -> a fetch should not have been attempted"
189 // ---------------------------------------------------------------------------
192 add_test(function () {
197 // A failure to retrieve an OCSP response will result in an error entry being
198 // added to the cache.
200 "ocsp-stapling-none.example.com",
203 "No stapled response -> a fetch should have been attempted"
206 // The error entry will prevent a fetch from happening for a while.
208 "ocsp-stapling-none.example.com",
211 "Noted OCSP server failure -> a fetch should not have been attempted"
214 // The error entry must not prevent a stapled OCSP response from being
217 "ocsp-stapling-revoked.example.com",
218 SEC_ERROR_REVOKED_CERTIFICATE,
220 "Stapled Revoked response -> a fetch should not have been attempted"
223 // ---------------------------------------------------------------------------
225 // Ensure OCSP responses from signers with SHA1 certificates are OK. This
226 // is included in the OCSP caching tests since there were OCSP cache-related
227 // regressions when sha-1 telemetry probes were added.
228 add_test(function () {
230 // set security.OCSP.require so that checking the OCSP signature fails
231 Services.prefs.setBoolPref("security.OCSP.require", true);
236 "ocsp-stapling-none.example.com",
237 SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
238 [respondWithSHA1OCSP],
239 "OCSP signing cert was issued with sha1 - should fail"
242 add_test(function () {
243 Services.prefs.setBoolPref("security.OCSP.require", false);
247 // ---------------------------------------------------------------------------
250 add_test(function () {
255 // This test makes sure that OCSP cache are isolated by firstPartyDomain.
257 let gObservedCnt = 0;
258 let protocolProxyService = Cc[
259 "@mozilla.org/network/protocol-proxy-service;1"
260 ].getService(Ci.nsIProtocolProxyService);
262 // Observe all channels and make sure the firstPartyDomain in their loadInfo's
263 // origin attributes are aFirstPartyDomain.
264 function startObservingChannels(aFirstPartyDomain) {
265 // We use a dummy proxy filter to catch all channels, even those that do not
266 // generate an "http-on-modify-request" notification.
268 applyFilter(aChannel, aProxy, aCallback) {
269 // We have the channel; provide it to the callback.
270 if (aChannel.originalURI.spec == "http://localhost:8888/") {
273 aChannel.loadInfo.originAttributes.firstPartyDomain,
275 "firstPartyDomain should match"
278 // Pass on aProxy unmodified.
279 aCallback.onProxyFilterResult(aProxy);
282 protocolProxyService.registerChannelFilter(proxyFilter, 0);
283 // Return the stop() function:
284 return () => protocolProxyService.unregisterChannelFilter(proxyFilter);
287 let stopObservingChannels;
288 add_test(function () {
289 stopObservingChannels = startObservingChannels("foo.com");
293 // A good OCSP response will be cached.
295 "ocsp-stapling-none.example.com",
297 [respondWithGoodOCSP],
298 "No stapled response (firstPartyDomain = foo.com) -> a fetch " +
299 "should have been attempted",
300 { firstPartyDomain: "foo.com" }
303 // The cache will prevent a fetch from happening.
305 "ocsp-stapling-none.example.com",
308 "Noted OCSP server failure (firstPartyDomain = foo.com) -> a " +
309 "fetch should not have been attempted",
310 { firstPartyDomain: "foo.com" }
313 add_test(function () {
314 stopObservingChannels();
315 equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
320 add_test(function () {
321 stopObservingChannels = startObservingChannels("bar.com");
325 // But using a different firstPartyDomain should result in a fetch.
327 "ocsp-stapling-none.example.com",
329 [respondWithGoodOCSP],
330 "No stapled response (firstPartyDomain = bar.com) -> a fetch " +
331 "should have been attempted",
332 { firstPartyDomain: "bar.com" }
335 add_test(function () {
336 stopObservingChannels();
337 equal(gObservedCnt, 1, "should have observed only 1 OCSP requests");
342 // ---------------------------------------------------------------------------
345 add_test(function () {
350 // Test that the OCSP cache is not isolated by userContextId.
352 // A good OCSP response will be cached.
354 "ocsp-stapling-none.example.com",
356 [respondWithGoodOCSP],
357 "No stapled response (userContextId = 1) -> a fetch " +
358 "should have been attempted",
362 // The cache will prevent a fetch from happening.
364 "ocsp-stapling-none.example.com",
367 "Noted OCSP server failure (userContextId = 1) -> a " +
368 "fetch should not have been attempted",
372 // Fetching is prevented even if in a different userContextId.
374 "ocsp-stapling-none.example.com",
377 "Noted OCSP server failure (userContextId = 2) -> a " +
378 "fetch should not have been attempted",
382 // ---------------------------------------------------------------------------
385 add_test(function () {
390 // This test makes sure that OCSP cache are isolated by partitionKey.
392 add_test(function () {
393 Services.prefs.setBoolPref(
394 "privacy.partition.network_state.ocsp_cache",
400 // A good OCSP response will be cached.
402 "ocsp-stapling-none.example.com",
404 [respondWithGoodOCSP],
405 "No stapled response (partitionKey = (https,foo.com)) -> a fetch " +
406 "should have been attempted",
407 { partitionKey: "(https,foo.com)" }
410 // The cache will prevent a fetch from happening.
412 "ocsp-stapling-none.example.com",
415 "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " +
416 "fetch should not have been attempted",
417 { partitionKey: "(https,foo.com)" }
420 // Using a different partitionKey should result in a fetch.
422 "ocsp-stapling-none.example.com",
424 [respondWithGoodOCSP],
425 "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " +
426 "fetch should have been attempted",
427 { partitionKey: "(https,bar.com)" }
430 // ---------------------------------------------------------------------------
433 add_test(function () {
434 Services.prefs.clearUserPref("privacy.partition.network_state.ocsp_cache");
439 // This test makes sure that OCSP cache are isolated by partitionKey in
442 // A good OCSP response will be cached.
444 "ocsp-stapling-none.example.com",
446 [respondWithGoodOCSP],
447 "No stapled response (partitionKey = (https,foo.com)) -> a fetch " +
448 "should have been attempted",
449 { partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
452 // The cache will prevent a fetch from happening.
454 "ocsp-stapling-none.example.com",
457 "Noted OCSP server failure (partitionKey = (https,foo.com)) -> a " +
458 "fetch should not have been attempted",
459 { partitionKey: "(https,foo.com)", privateBrowsingId: 1 }
462 // Using a different partitionKey should result in a fetch.
464 "ocsp-stapling-none.example.com",
466 [respondWithGoodOCSP],
467 "Noted OCSP server failure (partitionKey = (https,bar.com)) -> a " +
468 "fetch should have been attempted",
469 { partitionKey: "(https,bar.com)", privateBrowsingId: 1 }
472 // ---------------------------------------------------------------------------
475 add_test(function () {