tor-browser

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

test_use_httpssvc.js (7496B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 let h2Port;
      8 
      9 const certOverrideService = Cc[
     10  "@mozilla.org/security/certoverride;1"
     11 ].getService(Ci.nsICertOverrideService);
     12 const { TestUtils } = ChromeUtils.importESModule(
     13  "resource://testing-common/TestUtils.sys.mjs"
     14 );
     15 
     16 let trrServer;
     17 add_setup(async function setup() {
     18  trr_test_setup();
     19 
     20  trrServer = new TRRServer();
     21  await trrServer.start();
     22  h2Port = trrServer.port();
     23 
     24  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
     25  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
     26  Services.prefs.setBoolPref(
     27    "network.dns.https_rr.check_record_with_cname",
     28    false
     29  );
     30 
     31  registerCleanupFunction(async () => {
     32    trr_clear_prefs();
     33    Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
     34    Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
     35    Services.prefs.clearUserPref(
     36      "network.dns.https_rr.check_record_with_cname"
     37    );
     38    await trrServer.stop();
     39  });
     40 
     41  if (mozinfo.socketprocess_networking) {
     42    Services.dns; // Needed to trigger socket process.
     43    await TestUtils.waitForCondition(() => Services.io.socketProcessLaunched);
     44  }
     45 
     46  Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRONLY);
     47 });
     48 
     49 function makeChan(url) {
     50  let chan = NetUtil.newChannel({
     51    uri: url,
     52    loadUsingSystemPrincipal: true,
     53    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     54  }).QueryInterface(Ci.nsIHttpChannel);
     55  return chan;
     56 }
     57 
     58 function channelOpenPromise(chan) {
     59  return new Promise(resolve => {
     60    function finish(req, buffer) {
     61      resolve([req, buffer]);
     62    }
     63    chan.asyncOpen(new ChannelListener(finish, null, CL_ALLOW_UNKNOWN_CL));
     64  });
     65 }
     66 
     67 // This is for testing when the HTTPSSVC record is not available when
     68 // the transaction is added in connection manager.
     69 add_task(async function testUseHTTPSSVCForHttpsUpgrade() {
     70  // use the h2 server as DOH provider
     71  Services.prefs.setCharPref(
     72    "network.trr.uri",
     73    "https://foo.example.com:" + h2Port + "/doh?httpssvc_as_altsvc=1"
     74  );
     75  Services.dns.clearCache(true);
     76 
     77  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     78    true
     79  );
     80 
     81  let chan = makeChan(`https://test.httpssvc.com:8080/`);
     82  let [req] = await channelOpenPromise(chan);
     83  Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
     84 
     85  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     86    false
     87  );
     88 });
     89 
     90 class EventSinkListener {
     91  getInterface(iid) {
     92    if (iid.equals(Ci.nsIChannelEventSink)) {
     93      return this;
     94    }
     95    throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
     96  }
     97  asyncOnChannelRedirect(oldChan, newChan, flags, callback) {
     98    Assert.equal(oldChan.URI.hostPort, newChan.URI.hostPort);
     99    Assert.equal(oldChan.URI.scheme, "http");
    100    Assert.equal(newChan.URI.scheme, "https");
    101    callback.onRedirectVerifyCallback(Cr.NS_OK);
    102  }
    103 }
    104 
    105 EventSinkListener.prototype.QueryInterface = ChromeUtils.generateQI([
    106  "nsIInterfaceRequestor",
    107  "nsIChannelEventSink",
    108 ]);
    109 
    110 // Test if the request is upgraded to https with a HTTPSSVC record.
    111 add_task(async function testUseHTTPSSVCAsHSTS() {
    112  // use the h2 server as DOH provider
    113  Services.prefs.setCharPref(
    114    "network.trr.uri",
    115    "https://foo.example.com:" + h2Port + "/doh?httpssvc_as_altsvc=1"
    116  );
    117  Services.dns.clearCache(true);
    118 
    119  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    120    true
    121  );
    122 
    123  // At this time, the DataStorage is not ready, so MaybeUseHTTPSRRForUpgrade()
    124  // is called from the callback of NS_ShouldSecureUpgrade().
    125  let chan = makeChan(`http://test.httpssvc.com:80/`);
    126  let listener = new EventSinkListener();
    127  chan.notificationCallbacks = listener;
    128 
    129  let [req] = await channelOpenPromise(chan);
    130 
    131  req.QueryInterface(Ci.nsIHttpChannel);
    132  Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
    133 
    134  // At this time, the DataStorage is ready, so MaybeUseHTTPSRRForUpgrade()
    135  // is called from nsHttpChannel::OnBeforeConnect().
    136  chan = makeChan(`http://test.httpssvc.com:80/`);
    137  listener = new EventSinkListener();
    138  chan.notificationCallbacks = listener;
    139 
    140  [req] = await channelOpenPromise(chan);
    141 
    142  req.QueryInterface(Ci.nsIHttpChannel);
    143  Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
    144 
    145  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    146    false
    147  );
    148 });
    149 
    150 // This is for testing when the HTTPSSVC record is already available before
    151 // the transaction is added in connection manager.
    152 add_task(async function testUseHTTPSSVC() {
    153  // use the h2 server as DOH provider
    154  Services.prefs.setCharPref(
    155    "network.trr.uri",
    156    "https://foo.example.com:" + h2Port + "/doh?httpssvc_as_altsvc=1"
    157  );
    158 
    159  // Do DNS resolution before creating the channel, so the HTTPSSVC record will
    160  // be resolved from the cache.
    161  await new TRRDNSListener("test.httpssvc.com", {
    162    type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
    163  });
    164 
    165  // We need to skip the security check, since our test cert is signed for
    166  // foo.example.com, not test.httpssvc.com.
    167  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    168    true
    169  );
    170 
    171  let chan = makeChan(`https://test.httpssvc.com:8888`);
    172  let [req] = await channelOpenPromise(chan);
    173  // Test if this request is done by h2.
    174  Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
    175 
    176  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    177    false
    178  );
    179 });
    180 
    181 // Test if we can successfully fallback to the original host and port.
    182 add_task(async function testFallback() {
    183  Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRONLY);
    184  Services.prefs.setCharPref(
    185    "network.trr.uri",
    186    `https://foo.example.com:${trrServer.port()}/dns-query`
    187  );
    188 
    189  await trrServer.registerDoHAnswers("test.fallback.com", "A", {
    190    answers: [
    191      {
    192        name: "test.fallback.com",
    193        ttl: 55,
    194        type: "A",
    195        flush: false,
    196        data: "127.0.0.1",
    197      },
    198    ],
    199  });
    200  // Use a wrong port number 8888, so this connection will be refused.
    201  await trrServer.registerDoHAnswers("test.fallback.com", "HTTPS", {
    202    answers: [
    203      {
    204        name: "test.fallback.com",
    205        ttl: 55,
    206        type: "HTTPS",
    207        flush: false,
    208        data: {
    209          priority: 1,
    210          name: "foo.example.com",
    211          values: [{ key: "port", value: 8888 }],
    212        },
    213      },
    214    ],
    215  });
    216 
    217  let { inRecord } = await new TRRDNSListener("test.fallback.com", {
    218    type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
    219  });
    220 
    221  let record = inRecord
    222    .QueryInterface(Ci.nsIDNSHTTPSSVCRecord)
    223    .GetServiceModeRecord(false, false);
    224  Assert.equal(record.priority, 1);
    225  Assert.equal(record.name, "foo.example.com");
    226 
    227  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    228    true
    229  );
    230 
    231  // When the connection with port 8888 failed, the correct h2Port will be used
    232  // to connect again.
    233  let chan = makeChan(`https://test.fallback.com:${h2Port}`);
    234  let [req] = await channelOpenPromise(chan);
    235  // Test if this request is done by h2.
    236  Assert.equal(req.getResponseHeader("x-connection-http2"), "yes");
    237 
    238  certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
    239    false
    240  );
    241 });