tor-browser

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

test_tls_flags.js (6885B)


      1 // -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
      2 // Any copyright is dedicated to the Public Domain.
      3 // http://creativecommons.org/publicdomain/zero/1.0/
      4 
      5 "use strict";
      6 
      7 // a fork of test_be_conservative
      8 
      9 // Tests that nsIHttpChannelInternal.tlsFlags can be used to set the
     10 // client max version level. Flags can also be used to set the
     11 // level of intolerance rollback and to test out an experimental 1.3
     12 // hello, though they are not tested here.
     13 
     14 // Get a profile directory and ensure PSM initializes NSS.
     15 do_get_profile();
     16 Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
     17 
     18 class InputStreamCallback {
     19  constructor(output) {
     20    this.output = output;
     21    this.stopped = false;
     22  }
     23 
     24  onInputStreamReady(stream) {
     25    info("input stream ready");
     26    if (this.stopped) {
     27      info("input stream callback stopped - bailing");
     28      return;
     29    }
     30    let available = 0;
     31    try {
     32      available = stream.available();
     33    } catch (e) {
     34      // onInputStreamReady may fire when the stream has been closed.
     35      equal(
     36        e.result,
     37        Cr.NS_BASE_STREAM_CLOSED,
     38        "error should be NS_BASE_STREAM_CLOSED"
     39      );
     40    }
     41    if (available > 0) {
     42      let request = NetUtil.readInputStreamToString(stream, available, {
     43        charset: "utf8",
     44      });
     45      ok(
     46        request.startsWith("GET / HTTP/1.1\r\n"),
     47        "Should get a simple GET / HTTP/1.1 request"
     48      );
     49      let response =
     50        "HTTP/1.1 200 OK\r\n" +
     51        "Content-Length: 2\r\n" +
     52        "Content-Type: text/plain\r\n" +
     53        "\r\nOK";
     54      let written = this.output.write(response, response.length);
     55      equal(
     56        written,
     57        response.length,
     58        "should have been able to write entire response"
     59      );
     60    }
     61    this.output.close();
     62    info("done with input stream ready");
     63  }
     64 
     65  stop() {
     66    this.stopped = true;
     67    this.output.close();
     68  }
     69 }
     70 
     71 class TLSServerSecurityObserver {
     72  constructor(input, output, expectedVersion) {
     73    this.input = input;
     74    this.output = output;
     75    this.expectedVersion = expectedVersion;
     76    this.callbacks = [];
     77    this.stopped = false;
     78  }
     79 
     80  onHandshakeDone(socket, status) {
     81    info("TLS handshake done");
     82    info(`TLS version used: ${status.tlsVersionUsed}`);
     83    info(this.expectedVersion);
     84    equal(
     85      status.tlsVersionUsed,
     86      this.expectedVersion,
     87      "expected version check"
     88    );
     89    if (this.stopped) {
     90      info("handshake done callback stopped - bailing");
     91      return;
     92    }
     93 
     94    let callback = new InputStreamCallback(this.output);
     95    this.callbacks.push(callback);
     96    this.input.asyncWait(callback, 0, 0, Services.tm.currentThread);
     97  }
     98 
     99  stop() {
    100    this.stopped = true;
    101    this.input.close();
    102    this.output.close();
    103    this.callbacks.forEach(callback => {
    104      callback.stop();
    105    });
    106  }
    107 }
    108 
    109 function startServer(
    110  cert,
    111  minServerVersion,
    112  maxServerVersion,
    113  expectedVersion
    114 ) {
    115  let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
    116    Ci.nsITLSServerSocket
    117  );
    118  tlsServer.init(-1, true, -1);
    119  tlsServer.serverCert = cert;
    120  tlsServer.setVersionRange(minServerVersion, maxServerVersion);
    121  tlsServer.setSessionTickets(false);
    122 
    123  let listener = {
    124    securityObservers: [],
    125 
    126    onSocketAccepted(socket, transport) {
    127      info("accepted TLS client connection");
    128      let connectionInfo = transport.securityCallbacks.getInterface(
    129        Ci.nsITLSServerConnectionInfo
    130      );
    131      let input = transport.openInputStream(0, 0, 0);
    132      let output = transport.openOutputStream(0, 0, 0);
    133      let securityObserver = new TLSServerSecurityObserver(
    134        input,
    135        output,
    136        expectedVersion
    137      );
    138      this.securityObservers.push(securityObserver);
    139      connectionInfo.setSecurityObserver(securityObserver);
    140    },
    141 
    142    // For some reason we get input stream callback events after we've stopped
    143    // listening, so this ensures we just drop those events.
    144    onStopListening() {
    145      info("onStopListening");
    146      this.securityObservers.forEach(observer => {
    147        observer.stop();
    148      });
    149    },
    150  };
    151  tlsServer.asyncListen(listener);
    152  return tlsServer;
    153 }
    154 
    155 const hostname = "example.com";
    156 
    157 function storeCertOverride(port, cert) {
    158  let certOverrideService = Cc[
    159    "@mozilla.org/security/certoverride;1"
    160  ].getService(Ci.nsICertOverrideService);
    161  certOverrideService.rememberValidityOverride(hostname, port, {}, cert, true);
    162 }
    163 
    164 function startClient(port, tlsFlags, expectSuccess) {
    165  let req = new XMLHttpRequest();
    166  req.open("GET", `https://${hostname}:${port}`);
    167  let internalChannel = req.channel.QueryInterface(Ci.nsIHttpChannelInternal);
    168  internalChannel.tlsFlags = tlsFlags;
    169  return new Promise(resolve => {
    170    req.onload = () => {
    171      ok(
    172        expectSuccess,
    173        `should ${expectSuccess ? "" : "not "}have gotten load event`
    174      );
    175      equal(req.responseText, "OK", "response text should be 'OK'");
    176      resolve();
    177    };
    178    req.onerror = () => {
    179      ok(
    180        !expectSuccess,
    181        `should ${!expectSuccess ? "" : "not "}have gotten an error`
    182      );
    183      resolve();
    184    };
    185 
    186    req.send();
    187  });
    188 }
    189 
    190 add_task(async function () {
    191  Services.prefs.setIntPref("security.tls.version.max", 4);
    192  Services.prefs.setCharPref("network.dns.localDomains", hostname);
    193  let cert = getTestServerCertificate();
    194 
    195  // server that accepts 1.1->1.3 and a client max 1.3. expect 1.3
    196  info("TEST 1");
    197  let server = startServer(
    198    cert,
    199    Ci.nsITLSClientStatus.TLS_VERSION_1_1,
    200    Ci.nsITLSClientStatus.TLS_VERSION_1_3,
    201    Ci.nsITLSClientStatus.TLS_VERSION_1_3
    202  );
    203  storeCertOverride(server.port, cert);
    204  await startClient(server.port, 4, true /*should succeed*/);
    205  server.close();
    206 
    207  // server that accepts 1.1->1.3 and a client max 1.1. expect 1.1
    208  info("TEST 2");
    209  server = startServer(
    210    cert,
    211    Ci.nsITLSClientStatus.TLS_VERSION_1_1,
    212    Ci.nsITLSClientStatus.TLS_VERSION_1_3,
    213    Ci.nsITLSClientStatus.TLS_VERSION_1_1
    214  );
    215  storeCertOverride(server.port, cert);
    216  await startClient(server.port, 2, true);
    217  server.close();
    218 
    219  // server that accepts 1.2->1.2 and a client max 1.3. expect 1.2
    220  info("TEST 3");
    221  server = startServer(
    222    cert,
    223    Ci.nsITLSClientStatus.TLS_VERSION_1_2,
    224    Ci.nsITLSClientStatus.TLS_VERSION_1_2,
    225    Ci.nsITLSClientStatus.TLS_VERSION_1_2
    226  );
    227  storeCertOverride(server.port, cert);
    228  await startClient(server.port, 4, true);
    229  server.close();
    230 
    231  // server that accepts 1.2->1.2 and a client max 1.1. expect fail
    232  info("TEST 4");
    233  server = startServer(
    234    cert,
    235    Ci.nsITLSClientStatus.TLS_VERSION_1_2,
    236    Ci.nsITLSClientStatus.TLS_VERSION_1_2,
    237    0
    238  );
    239  storeCertOverride(server.port, cert);
    240  await startClient(server.port, 2, false);
    241 
    242  server.close();
    243 });
    244 
    245 registerCleanupFunction(function () {
    246  Services.prefs.clearUserPref("security.tls.version.max");
    247  Services.prefs.clearUserPref("network.dns.localDomains");
    248 });