tor-browser

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

test_httpssvc_ech_with_alpn.js (7136B)


      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 trrServer;
      8 
      9 const certOverrideService = Cc[
     10  "@mozilla.org/security/certoverride;1"
     11 ].getService(Ci.nsICertOverrideService);
     12 
     13 add_setup(async function setup() {
     14  // Allow telemetry probes which may otherwise be disabled for some
     15  // applications (e.g. Thunderbird).
     16  Services.prefs.setBoolPref(
     17    "toolkit.telemetry.testing.overrideProductsCheck",
     18    true
     19  );
     20 
     21  trr_test_setup();
     22 
     23  Services.prefs.setBoolPref("network.dns.upgrade_with_https_rr", true);
     24  Services.prefs.setBoolPref("network.dns.use_https_rr_as_altsvc", true);
     25  Services.prefs.setBoolPref("network.dns.echconfig.enabled", true);
     26  Services.prefs.setBoolPref("network.dns.http3_echconfig.enabled", false);
     27  Services.prefs.setIntPref("network.http.speculative-parallel-limit", 0);
     28  Services.prefs.setIntPref("network.trr.mode", Ci.nsIDNSService.MODE_TRRONLY);
     29 
     30  // Set the server to always select http/1.1
     31  Services.env.set("MOZ_TLS_ECH_ALPN_FLAG", 1);
     32 
     33  await asyncStartTLSTestServer(
     34    "EncryptedClientHelloServer",
     35    "../../../security/manager/ssl/tests/unit/test_encrypted_client_hello"
     36  );
     37 });
     38 
     39 registerCleanupFunction(async () => {
     40  trr_clear_prefs();
     41  Services.prefs.clearUserPref("network.trr.mode");
     42  Services.prefs.clearUserPref("network.trr.uri");
     43  Services.prefs.clearUserPref("network.dns.upgrade_with_https_rr");
     44  Services.prefs.clearUserPref("network.dns.use_https_rr_as_altsvc");
     45  Services.prefs.clearUserPref("network.dns.echconfig.enabled");
     46  Services.prefs.clearUserPref("network.dns.http3_echconfig.enabled");
     47  Services.prefs.clearUserPref(
     48    "network.dns.echconfig.fallback_to_origin_when_all_failed"
     49  );
     50  Services.prefs.clearUserPref("network.http.speculative-parallel-limit");
     51  Services.prefs.clearUserPref("network.dns.port_prefixed_qname_https_rr");
     52  Services.env.set("MOZ_TLS_ECH_ALPN_FLAG", "");
     53  if (trrServer) {
     54    await trrServer.stop();
     55  }
     56 });
     57 
     58 function makeChan(url) {
     59  let chan = NetUtil.newChannel({
     60    uri: url,
     61    loadUsingSystemPrincipal: true,
     62    contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
     63  }).QueryInterface(Ci.nsIHttpChannel);
     64  return chan;
     65 }
     66 
     67 function channelOpenPromise(chan, flags) {
     68  return new Promise(resolve => {
     69    function finish(req, buffer) {
     70      certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     71        false
     72      );
     73      resolve([req, buffer]);
     74    }
     75    certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
     76      true
     77    );
     78    chan.asyncOpen(new ChannelListener(finish, null, flags));
     79  });
     80 }
     81 
     82 function ActivityObserver() {}
     83 
     84 ActivityObserver.prototype = {
     85  activites: [],
     86  observeConnectionActivity(
     87    aHost,
     88    aPort,
     89    aSSL,
     90    aHasECH,
     91    aIsHttp3,
     92    aActivityType,
     93    aActivitySubtype,
     94    aTimestamp,
     95    aExtraStringData
     96  ) {
     97    dump(
     98      "*** Connection Activity 0x" +
     99        aActivityType.toString(16) +
    100        " 0x" +
    101        aActivitySubtype.toString(16) +
    102        " " +
    103        aExtraStringData +
    104        "\n"
    105    );
    106    this.activites.push({ host: aHost, subType: aActivitySubtype });
    107  },
    108 };
    109 
    110 function checkHttpActivities(activites) {
    111  let foundDNSAndSocket = false;
    112  let foundSettingECH = false;
    113  let foundConnectionCreated = false;
    114  for (let activity of activites) {
    115    switch (activity.subType) {
    116      case Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_DNSANDSOCKET_CREATED:
    117      case Ci.nsIHttpActivityObserver
    118        .ACTIVITY_SUBTYPE_SPECULATIVE_DNSANDSOCKET_CREATED:
    119        foundDNSAndSocket = true;
    120        break;
    121      case Ci.nsIHttpActivityDistributor.ACTIVITY_SUBTYPE_ECH_SET:
    122        foundSettingECH = true;
    123        break;
    124      case Ci.nsIHttpActivityDistributor.ACTIVITY_SUBTYPE_CONNECTION_CREATED:
    125        foundConnectionCreated = true;
    126        break;
    127      default:
    128        break;
    129    }
    130  }
    131 
    132  Assert.equal(foundDNSAndSocket, true, "Should have one DnsAndSock created");
    133  Assert.equal(foundSettingECH, true, "Should have echConfig");
    134  Assert.equal(
    135    foundConnectionCreated,
    136    true,
    137    "Should have one connection created"
    138  );
    139 }
    140 
    141 async function testWrapper(alpnAdvertisement) {
    142  const ECH_CONFIG_FIXED =
    143    "AEn+DQBFTQAgACCKB1Y5SfrGIyk27W82xPpzWTDs3q72c04xSurDWlb9CgAEAAEAA2QWZWNoLXB1YmxpYy5leGFtcGxlLmNvbQAA";
    144  trrServer = new TRRServer();
    145  await trrServer.start();
    146 
    147  let observerService = Cc[
    148    "@mozilla.org/network/http-activity-distributor;1"
    149  ].getService(Ci.nsIHttpActivityDistributor);
    150  let observer = new ActivityObserver();
    151  observerService.addObserver(observer);
    152  observerService.observeConnection = true;
    153 
    154  Services.prefs.setCharPref(
    155    "network.trr.uri",
    156    `https://foo.example.com:${trrServer.port()}/dns-query`
    157  );
    158 
    159  // Only the last record is valid to use.
    160  await trrServer.registerDoHAnswers("ech-private.example.com", "HTTPS", {
    161    answers: [
    162      {
    163        name: "ech-private.example.com",
    164        ttl: 55,
    165        type: "HTTPS",
    166        flush: false,
    167        data: {
    168          priority: 1,
    169          name: "ech-private.example.com",
    170          values: [
    171            { key: "alpn", value: alpnAdvertisement },
    172            { key: "port", value: 8443 },
    173            {
    174              key: "echconfig",
    175              value: ECH_CONFIG_FIXED,
    176              needBase64Decode: true,
    177            },
    178          ],
    179        },
    180      },
    181    ],
    182  });
    183 
    184  await trrServer.registerDoHAnswers("ech-private.example.com", "A", {
    185    answers: [
    186      {
    187        name: "ech-private.example.com",
    188        ttl: 55,
    189        type: "A",
    190        flush: false,
    191        data: "127.0.0.1",
    192      },
    193    ],
    194  });
    195 
    196  await new TRRDNSListener("ech-private.example.com", {
    197    type: Ci.nsIDNSService.RESOLVE_TYPE_HTTPSSVC,
    198  });
    199 
    200  HandshakeTelemetryHelpers.resetHistograms();
    201  let chan = makeChan(`https://ech-private.example.com`);
    202  await channelOpenPromise(chan, CL_ALLOW_UNKNOWN_CL);
    203  let securityInfo = chan.securityInfo;
    204  Assert.ok(securityInfo.isAcceptedEch, "This host should have accepted ECH");
    205 
    206  // Only check telemetry if network process is disabled.
    207  if (!mozinfo.socketprocess_networking) {
    208    HandshakeTelemetryHelpers.checkSuccess(["", "_ECH", "_FIRST_TRY"]);
    209    HandshakeTelemetryHelpers.checkEmpty(["_CONSERVATIVE", "_ECH_GREASE"]);
    210  }
    211 
    212  await trrServer.stop();
    213  observerService.removeObserver(observer);
    214  observerService.observeConnection = false;
    215 
    216  let filtered = observer.activites.filter(
    217    activity => activity.host === "ech-private.example.com"
    218  );
    219  checkHttpActivities(filtered);
    220 }
    221 
    222 add_task(async function h1Advertised() {
    223  await testWrapper(["http/1.1"]);
    224 });
    225 
    226 add_task(async function h2Advertised() {
    227  await testWrapper(["h2"]);
    228 });
    229 
    230 add_task(async function h3Advertised() {
    231  await testWrapper(["h3"]);
    232 });
    233 
    234 add_task(async function h1h2Advertised() {
    235  await testWrapper(["http/1.1", "h2"]);
    236 });
    237 
    238 add_task(async function h2h3Advertised() {
    239  await testWrapper(["h3", "h2"]);
    240 });
    241 
    242 add_task(async function unknownAdvertised() {
    243  await testWrapper(["foo"]);
    244 });