tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_ocsp_stapling_expired.js (10309B)


      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/.
      5 "use strict";
      6 
      7 // Enable the collection (during test) for all products so even products
      8 // that don't collect the data will be able to run the test without failure.
      9 Services.prefs.setBoolPref(
     10  "toolkit.telemetry.testing.overrideProductsCheck",
     11  true
     12 );
     13 
     14 // In which we connect to a number of domains (as faked by a server running
     15 // locally) with OCSP stapling enabled to determine that good things happen
     16 // and bad things don't, specifically with respect to various expired OCSP
     17 // responses (stapled and otherwise).
     18 // According to RFC 6066, if a stapled OCSP response can't be satisfactorilly
     19 // verified, the client should terminate the connection. Unfortunately, due to
     20 // some bugs where servers will staple any old garbage without verifying it, we
     21 // can't be this strict in practice. Originally this caveat only applied to
     22 // expired responses, but recent high-profile failures have caused us to expand
     23 // this to "try later" responses and responses where the signing certificate
     24 // doesn't verify successfully.
     25 
     26 var gCurrentOCSPResponse = null;
     27 var gOCSPRequestCount = 0;
     28 
     29 function add_ocsp_test(
     30  aHost,
     31  aExpectedResult,
     32  aOCSPResponseToServe,
     33  aExpectedRequestCount
     34 ) {
     35  add_connection_test(
     36    aHost,
     37    aExpectedResult,
     38    function () {
     39      clearOCSPCache();
     40      clearSessionCache();
     41      gCurrentOCSPResponse = aOCSPResponseToServe;
     42      gOCSPRequestCount = 0;
     43    },
     44    function () {
     45      equal(
     46        gOCSPRequestCount,
     47        aExpectedRequestCount,
     48        "Should have made " +
     49          aExpectedRequestCount +
     50          " fallback OCSP request" +
     51          (aExpectedRequestCount == 1 ? "" : "s")
     52      );
     53    }
     54  );
     55 }
     56 
     57 do_get_profile();
     58 Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
     59 Services.prefs.setIntPref("security.OCSP.enabled", 1);
     60 // Sometimes this test will fail on android due to an OCSP request timing out.
     61 // That aspect of OCSP requests is not what we're testing here, so we can just
     62 // bump the timeout and hopefully avoid these failures.
     63 Services.prefs.setIntPref("security.OCSP.timeoutMilliseconds.soft", 5000);
     64 var args = [
     65  ["good", "default-ee", "unused", 0],
     66  ["expiredresponse", "default-ee", "unused", 0],
     67  ["oldvalidperiod", "default-ee", "unused", 0],
     68  ["revoked", "default-ee", "unused", 0],
     69  ["unknown", "default-ee", "unused", 0],
     70  ["good", "must-staple-ee", "unused", 0],
     71 ];
     72 var ocspResponses = generateOCSPResponses(args, "ocsp_certs");
     73 // Fresh response, certificate is good.
     74 var ocspResponseGood = ocspResponses[0];
     75 // Expired response, certificate is good.
     76 var expiredOCSPResponseGood = ocspResponses[1];
     77 // Fresh signature, old validity period, certificate is good.
     78 var oldValidityPeriodOCSPResponseGood = ocspResponses[2];
     79 // Fresh signature, certificate is revoked.
     80 var ocspResponseRevoked = ocspResponses[3];
     81 // Fresh signature, certificate is unknown.
     82 var ocspResponseUnknown = ocspResponses[4];
     83 var ocspResponseGoodMustStaple = ocspResponses[5];
     84 
     85 // sometimes we expect a result without re-fetch
     86 var willNotRetry = 1;
     87 // but sometimes, since a bad response is in the cache, OCSP fetch will be
     88 // attempted for each validation - in practice, for these test certs, this
     89 // means 2 requests because various key sizes are tried.
     90 var willRetry = 2;
     91 
     92 function run_test() {
     93  let ocspResponder = new HttpServer();
     94  ocspResponder.registerPrefixHandler("/", function (request, response) {
     95    if (gCurrentOCSPResponse) {
     96      response.setStatusLine(request.httpVersion, 200, "OK");
     97      response.setHeader("Content-Type", "application/ocsp-response");
     98      response.write(gCurrentOCSPResponse);
     99    } else {
    100      response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
    101      response.write("Internal Server Error");
    102    }
    103    gOCSPRequestCount++;
    104  });
    105  ocspResponder.start(8888);
    106  add_tls_server_setup("OCSPStaplingServer", "ocsp_certs");
    107 
    108  // In these tests, the OCSP stapling server gives us a stapled
    109  // response based on the host name ("ocsp-stapling-expired" or
    110  // "ocsp-stapling-expired-fresh-ca"). We then ensure that we're
    111  // properly falling back to fetching revocation information.
    112  // For ocsp-stapling-expired.example.com, the OCSP stapling server
    113  // staples an expired OCSP response. The certificate has not expired.
    114  // For ocsp-stapling-expired-fresh-ca.example.com, the OCSP stapling
    115  // server staples an OCSP response with a recent signature but with an
    116  // out-of-date validity period. The certificate has not expired.
    117  add_ocsp_test(
    118    "ocsp-stapling-expired.example.com",
    119    PRErrorCodeSuccess,
    120    ocspResponseGood,
    121    willNotRetry
    122  );
    123  add_ocsp_test(
    124    "ocsp-stapling-expired-fresh-ca.example.com",
    125    PRErrorCodeSuccess,
    126    ocspResponseGood,
    127    willNotRetry
    128  );
    129  // if we can't fetch a more recent response when
    130  // given an expired stapled response, we terminate the connection.
    131  add_ocsp_test(
    132    "ocsp-stapling-expired.example.com",
    133    SEC_ERROR_OCSP_OLD_RESPONSE,
    134    expiredOCSPResponseGood,
    135    willRetry
    136  );
    137  add_ocsp_test(
    138    "ocsp-stapling-expired-fresh-ca.example.com",
    139    SEC_ERROR_OCSP_OLD_RESPONSE,
    140    expiredOCSPResponseGood,
    141    willRetry
    142  );
    143  add_ocsp_test(
    144    "ocsp-stapling-expired.example.com",
    145    SEC_ERROR_OCSP_OLD_RESPONSE,
    146    oldValidityPeriodOCSPResponseGood,
    147    willRetry
    148  );
    149  add_ocsp_test(
    150    "ocsp-stapling-expired-fresh-ca.example.com",
    151    SEC_ERROR_OCSP_OLD_RESPONSE,
    152    oldValidityPeriodOCSPResponseGood,
    153    willRetry
    154  );
    155  add_ocsp_test(
    156    "ocsp-stapling-expired.example.com",
    157    SEC_ERROR_OCSP_OLD_RESPONSE,
    158    null,
    159    willNotRetry
    160  );
    161  add_ocsp_test(
    162    "ocsp-stapling-expired.example.com",
    163    SEC_ERROR_OCSP_OLD_RESPONSE,
    164    null,
    165    willNotRetry
    166  );
    167  // Of course, if the newer response indicates Revoked or Unknown,
    168  // that status must be returned.
    169  add_ocsp_test(
    170    "ocsp-stapling-expired.example.com",
    171    SEC_ERROR_REVOKED_CERTIFICATE,
    172    ocspResponseRevoked,
    173    willNotRetry
    174  );
    175  add_ocsp_test(
    176    "ocsp-stapling-expired-fresh-ca.example.com",
    177    SEC_ERROR_REVOKED_CERTIFICATE,
    178    ocspResponseRevoked,
    179    willNotRetry
    180  );
    181  add_ocsp_test(
    182    "ocsp-stapling-expired.example.com",
    183    SEC_ERROR_OCSP_UNKNOWN_CERT,
    184    ocspResponseUnknown,
    185    willRetry
    186  );
    187  add_ocsp_test(
    188    "ocsp-stapling-expired-fresh-ca.example.com",
    189    SEC_ERROR_OCSP_UNKNOWN_CERT,
    190    ocspResponseUnknown,
    191    willRetry
    192  );
    193 
    194  // If the response is expired but indicates Revoked or Unknown and a
    195  // newer status can't be fetched, the Revoked or Unknown status will
    196  // be returned.
    197  add_ocsp_test(
    198    "ocsp-stapling-revoked-old.example.com",
    199    SEC_ERROR_REVOKED_CERTIFICATE,
    200    null,
    201    willNotRetry
    202  );
    203  add_ocsp_test(
    204    "ocsp-stapling-unknown-old.example.com",
    205    SEC_ERROR_OCSP_UNKNOWN_CERT,
    206    null,
    207    willNotRetry
    208  );
    209  // If the response is expired but indicates Revoked or Unknown and
    210  // a newer status can be fetched and successfully verified, this
    211  // should result in a successful certificate verification.
    212  add_ocsp_test(
    213    "ocsp-stapling-revoked-old.example.com",
    214    PRErrorCodeSuccess,
    215    ocspResponseGood,
    216    willNotRetry
    217  );
    218  add_ocsp_test(
    219    "ocsp-stapling-unknown-old.example.com",
    220    PRErrorCodeSuccess,
    221    ocspResponseGood,
    222    willNotRetry
    223  );
    224  // If a newer status can be fetched but it fails to verify, the
    225  // Revoked or Unknown status of the expired stapled response
    226  // should be returned.
    227  add_ocsp_test(
    228    "ocsp-stapling-revoked-old.example.com",
    229    SEC_ERROR_REVOKED_CERTIFICATE,
    230    expiredOCSPResponseGood,
    231    willRetry
    232  );
    233  add_ocsp_test(
    234    "ocsp-stapling-unknown-old.example.com",
    235    SEC_ERROR_OCSP_UNKNOWN_CERT,
    236    expiredOCSPResponseGood,
    237    willRetry
    238  );
    239 
    240  // These tests are verifying that an valid but very old response
    241  // is rejected as a valid stapled response, requiring a fetch
    242  // from the ocsp responder.
    243  add_ocsp_test(
    244    "ocsp-stapling-ancient-valid.example.com",
    245    PRErrorCodeSuccess,
    246    ocspResponseGood,
    247    willNotRetry
    248  );
    249  add_ocsp_test(
    250    "ocsp-stapling-ancient-valid.example.com",
    251    SEC_ERROR_REVOKED_CERTIFICATE,
    252    ocspResponseRevoked,
    253    willNotRetry
    254  );
    255  add_ocsp_test(
    256    "ocsp-stapling-ancient-valid.example.com",
    257    SEC_ERROR_OCSP_UNKNOWN_CERT,
    258    ocspResponseUnknown,
    259    willRetry
    260  );
    261 
    262  // Test how OCSP-must-staple (i.e. TLS feature) interacts with stapled OCSP
    263  // responses that don't successfully verify.
    264  // A strict reading of the relevant RFCs might say that these connections
    265  // should all fail because a satisfactory stapled OCSP response is not
    266  // present, but for compatibility reasons we fall back to active OCSP fetching
    267  // in these situations. If the fetch succeeds, then connection succeeds.
    268  add_ocsp_test(
    269    "ocsp-stapling-must-staple-expired.example.com",
    270    PRErrorCodeSuccess,
    271    ocspResponseGoodMustStaple,
    272    willNotRetry
    273  );
    274  add_ocsp_test(
    275    "ocsp-stapling-must-staple-try-later.example.com",
    276    PRErrorCodeSuccess,
    277    ocspResponseGoodMustStaple,
    278    willNotRetry
    279  );
    280  add_ocsp_test(
    281    "ocsp-stapling-must-staple-invalid-signer.example.com",
    282    PRErrorCodeSuccess,
    283    ocspResponseGoodMustStaple,
    284    willNotRetry
    285  );
    286 
    287  add_test(function () {
    288    ocspResponder.stop(run_next_test);
    289  });
    290  add_test(check_ocsp_stapling_telemetry);
    291  run_next_test();
    292 }
    293 
    294 function check_ocsp_stapling_telemetry() {
    295  let histogram = Services.telemetry
    296    .getHistogramById("SSL_OCSP_STAPLING")
    297    .snapshot();
    298  equal(
    299    histogram.values[0] || 0,
    300    0,
    301    "Should have 0 connections for unused histogram bucket 0"
    302  );
    303  equal(
    304    histogram.values[1] || 0,
    305    0,
    306    "Actual and expected connections with a good response should match"
    307  );
    308  equal(
    309    histogram.values[2] || 0,
    310    0,
    311    "Actual and expected connections with no stapled response should match"
    312  );
    313  equal(
    314    histogram.values[3],
    315    22,
    316    "Actual and expected connections with an expired response should match"
    317  );
    318  equal(
    319    histogram.values[4],
    320    2,
    321    "Actual and expected connections with bad responses should match"
    322  );
    323  run_next_test();
    324 }