tor-browser

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

test_tls_server.js (8394B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 "use strict";
      5 
      6 // Need profile dir to store the key / cert
      7 do_get_profile();
      8 // Ensure PSM is initialized
      9 Cc["@mozilla.org/psm;1"].getService(Ci.nsISupports);
     10 
     11 const { MockRegistrar } = ChromeUtils.importESModule(
     12  "resource://testing-common/MockRegistrar.sys.mjs"
     13 );
     14 const certOverrideService = Cc[
     15  "@mozilla.org/security/certoverride;1"
     16 ].getService(Ci.nsICertOverrideService);
     17 const socketTransportService = Cc[
     18  "@mozilla.org/network/socket-transport-service;1"
     19 ].getService(Ci.nsISocketTransportService);
     20 
     21 const prefs = Services.prefs;
     22 
     23 function areCertsEqual(certA, certB) {
     24  let derA = certA.getRawDER();
     25  let derB = certB.getRawDER();
     26  if (derA.length != derB.length) {
     27    return false;
     28  }
     29  for (let i = 0; i < derA.length; i++) {
     30    if (derA[i] != derB[i]) {
     31      return false;
     32    }
     33  }
     34  return true;
     35 }
     36 
     37 function startServer(
     38  cert,
     39  expectingPeerCert,
     40  clientCertificateConfig,
     41  expectedVersion,
     42  expectedVersionStr
     43 ) {
     44  let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"].createInstance(
     45    Ci.nsITLSServerSocket
     46  );
     47  tlsServer.init(-1, true, -1);
     48  tlsServer.serverCert = cert;
     49 
     50  let input, output;
     51 
     52  let listener = {
     53    onSocketAccepted(socket, transport) {
     54      info("Accept TLS client connection");
     55      let connectionInfo = transport.securityCallbacks.getInterface(
     56        Ci.nsITLSServerConnectionInfo
     57      );
     58      connectionInfo.setSecurityObserver(listener);
     59      input = transport.openInputStream(0, 0, 0);
     60      output = transport.openOutputStream(0, 0, 0);
     61    },
     62    onHandshakeDone(socket, status) {
     63      info("TLS handshake done");
     64      if (expectingPeerCert) {
     65        ok(!!status.peerCert, "Has peer cert");
     66        ok(
     67          areCertsEqual(status.peerCert, cert),
     68          "Peer cert matches expected cert"
     69        );
     70      } else {
     71        ok(!status.peerCert, "No peer cert (as expected)");
     72      }
     73 
     74      equal(
     75        status.tlsVersionUsed,
     76        expectedVersion,
     77        "Using " + expectedVersionStr
     78      );
     79      let expectedCipher;
     80      if (expectedVersion >= 772) {
     81        expectedCipher = "TLS_AES_128_GCM_SHA256";
     82      } else {
     83        expectedCipher = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
     84      }
     85      equal(status.cipherName, expectedCipher, "Using expected cipher");
     86      equal(status.keyLength, 128, "Using 128-bit key");
     87      equal(status.macLength, 128, "Using 128-bit MAC");
     88 
     89      input.asyncWait(
     90        {
     91          onInputStreamReady(input1) {
     92            NetUtil.asyncCopy(input1, output);
     93          },
     94        },
     95        0,
     96        0,
     97        Services.tm.currentThread
     98      );
     99    },
    100    onStopListening() {
    101      info("onStopListening");
    102      input.close();
    103      output.close();
    104    },
    105  };
    106 
    107  tlsServer.setSessionTickets(false);
    108  tlsServer.setRequestClientCertificate(clientCertificateConfig);
    109 
    110  tlsServer.asyncListen(listener);
    111 
    112  return tlsServer;
    113 }
    114 
    115 function storeCertOverride(port, cert) {
    116  certOverrideService.rememberValidityOverride(
    117    "127.0.0.1",
    118    port,
    119    {},
    120    cert,
    121    true
    122  );
    123 }
    124 
    125 function startClient(port, sendClientCert, expectingAlert, tlsVersion) {
    126  gClientAuthDialogService.selectCertificate = sendClientCert;
    127  let SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
    128  let SSL_ERROR_BAD_CERT_ALERT = SSL_ERROR_BASE + 17;
    129  let SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT = SSL_ERROR_BASE + 181;
    130  let transport = socketTransportService.createTransport(
    131    ["ssl"],
    132    "127.0.0.1",
    133    port,
    134    null,
    135    null
    136  );
    137  let input;
    138  let output;
    139 
    140  let inputDeferred = Promise.withResolvers();
    141  let outputDeferred = Promise.withResolvers();
    142 
    143  let handler = {
    144    onTransportStatus(transport1, status) {
    145      if (status === Ci.nsISocketTransport.STATUS_CONNECTED_TO) {
    146        output.asyncWait(handler, 0, 0, Services.tm.currentThread);
    147      }
    148    },
    149 
    150    onInputStreamReady(input1) {
    151      try {
    152        let data = NetUtil.readInputStreamToString(input1, input1.available());
    153        equal(data, "HELLO", "Echoed data received");
    154        input1.close();
    155        output.close();
    156        ok(!expectingAlert, "No cert alert expected");
    157        inputDeferred.resolve();
    158      } catch (e) {
    159        let errorCode = -1 * (e.result & 0xffff);
    160        if (expectingAlert) {
    161          if (
    162            tlsVersion == Ci.nsITLSClientStatus.TLS_VERSION_1_2 &&
    163            errorCode == SSL_ERROR_BAD_CERT_ALERT
    164          ) {
    165            info("Got bad cert alert as expected for tls 1.2");
    166            input1.close();
    167            output.close();
    168            inputDeferred.resolve();
    169            return;
    170          }
    171          if (
    172            tlsVersion == Ci.nsITLSClientStatus.TLS_VERSION_1_3 &&
    173            errorCode == SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT
    174          ) {
    175            info("Got cert required alert as expected for tls 1.3");
    176            input1.close();
    177            output.close();
    178            inputDeferred.resolve();
    179            return;
    180          }
    181        }
    182        inputDeferred.reject(e);
    183      }
    184    },
    185 
    186    onOutputStreamReady(output1) {
    187      try {
    188        output1.write("HELLO", 5);
    189        info("Output to server written");
    190        outputDeferred.resolve();
    191        input = transport.openInputStream(0, 0, 0);
    192        input.asyncWait(handler, 0, 0, Services.tm.currentThread);
    193      } catch (e) {
    194        let errorCode = -1 * (e.result & 0xffff);
    195        if (errorCode == SSL_ERROR_BAD_CERT_ALERT) {
    196          info("Server doesn't like client cert");
    197        }
    198        outputDeferred.reject(e);
    199      }
    200    },
    201  };
    202 
    203  transport.setEventSink(handler, Services.tm.currentThread);
    204  output = transport.openOutputStream(0, 0, 0);
    205 
    206  return Promise.all([inputDeferred.promise, outputDeferred.promise]);
    207 }
    208 
    209 // Replace the UI dialog that prompts the user to pick a client certificate.
    210 const gClientAuthDialogService = {
    211  _selectCertificate: false,
    212 
    213  set selectCertificate(value) {
    214    this._selectCertificate = value;
    215  },
    216 
    217  chooseCertificate(hostname, certArray, loadContext, caNames, callback) {
    218    if (this._selectCertificate) {
    219      callback.certificateChosen(certArray[0], false);
    220    } else {
    221      callback.certificateChose(null, false);
    222    }
    223  },
    224 
    225  QueryInterface: ChromeUtils.generateQI([Ci.nsIClientAuthDialogService]),
    226 };
    227 
    228 const ClientAuthDialogServiceContractID =
    229  "@mozilla.org/security/ClientAuthDialogService;1";
    230 MockRegistrar.register(
    231  ClientAuthDialogServiceContractID,
    232  gClientAuthDialogService
    233 );
    234 
    235 const tests = [
    236  {
    237    expectingPeerCert: true,
    238    clientCertificateConfig: Ci.nsITLSServerSocket.REQUIRE_ALWAYS,
    239    sendClientCert: true,
    240    expectingAlert: false,
    241  },
    242  {
    243    expectingPeerCert: true,
    244    clientCertificateConfig: Ci.nsITLSServerSocket.REQUIRE_ALWAYS,
    245    sendClientCert: false,
    246    expectingAlert: true,
    247  },
    248  {
    249    expectingPeerCert: true,
    250    clientCertificateConfig: Ci.nsITLSServerSocket.REQUEST_ALWAYS,
    251    sendClientCert: true,
    252    expectingAlert: false,
    253  },
    254  {
    255    expectingPeerCert: false,
    256    clientCertificateConfig: Ci.nsITLSServerSocket.REQUEST_ALWAYS,
    257    sendClientCert: false,
    258    expectingAlert: false,
    259  },
    260  {
    261    expectingPeerCert: false,
    262    clientCertificateConfig: Ci.nsITLSServerSocket.REQUEST_NEVER,
    263    sendClientCert: true,
    264    expectingAlert: false,
    265  },
    266  {
    267    expectingPeerCert: false,
    268    clientCertificateConfig: Ci.nsITLSServerSocket.REQUEST_NEVER,
    269    sendClientCert: false,
    270    expectingAlert: false,
    271  },
    272 ];
    273 
    274 const versions = [
    275  {
    276    prefValue: 3,
    277    version: Ci.nsITLSClientStatus.TLS_VERSION_1_2,
    278    versionStr: "TLS 1.2",
    279  },
    280  {
    281    prefValue: 4,
    282    version: Ci.nsITLSClientStatus.TLS_VERSION_1_3,
    283    versionStr: "TLS 1.3",
    284  },
    285 ];
    286 
    287 add_task(async function () {
    288  let cert = getTestServerCertificate();
    289  ok(!!cert, "Got self-signed cert");
    290  for (let v of versions) {
    291    prefs.setIntPref("security.tls.version.max", v.prefValue);
    292    for (let t of tests) {
    293      let server = startServer(
    294        cert,
    295        t.expectingPeerCert,
    296        t.clientCertificateConfig,
    297        v.version,
    298        v.versionStr
    299      );
    300      storeCertOverride(server.port, cert);
    301      await startClient(
    302        server.port,
    303        t.sendClientCert,
    304        t.expectingAlert,
    305        v.version
    306      );
    307      server.close();
    308    }
    309  }
    310 });
    311 
    312 registerCleanupFunction(function () {
    313  prefs.clearUserPref("security.tls.version.max");
    314 });