tor-browser

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

test_signature_extraction.js (5959B)


      1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* Any copyright is dedicated to the Public Domain.
      4 * http://creativecommons.org/publicdomain/zero/1.0/ */
      5 
      6 /**
      7 * This file tests signature extraction using Windows Authenticode APIs of
      8 * downloaded files.
      9 */
     10 
     11 ////////////////////////////////////////////////////////////////////////////////
     12 //// Globals
     13 "use strict";
     14 
     15 ChromeUtils.defineESModuleGetters(this, {
     16  FileTestUtils: "resource://testing-common/FileTestUtils.sys.mjs",
     17 });
     18 
     19 const BackgroundFileSaverOutputStream = Components.Constructor(
     20  "@mozilla.org/network/background-file-saver;1?mode=outputstream",
     21  "nsIBackgroundFileSaver"
     22 );
     23 
     24 const StringInputStream = Components.Constructor(
     25  "@mozilla.org/io/string-input-stream;1",
     26  "nsIStringInputStream",
     27  "setByteStringData"
     28 );
     29 
     30 const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt";
     31 
     32 /**
     33 * Returns a reference to a temporary file that is guaranteed not to exist and
     34 * is cleaned up later. See FileTestUtils.getTempFile for details.
     35 */
     36 function getTempFile(leafName) {
     37  return FileTestUtils.getTempFile(leafName);
     38 }
     39 
     40 /**
     41 * Waits for the given saver object to complete.
     42 *
     43 * @param aSaver
     44 *        The saver, with the output stream or a stream listener implementation.
     45 * @param aOnTargetChangeFn
     46 *        Optional callback invoked with the target file name when it changes.
     47 *
     48 * @returns {Promise<void>}
     49 *   Resolves when onSaveComplete is called with a success code.
     50 * @rejects With an exception, if onSaveComplete is called with a failure code.
     51 */
     52 function promiseSaverComplete(aSaver, aOnTargetChangeFn) {
     53  return new Promise((resolve, reject) => {
     54    aSaver.observer = {
     55      onTargetChange: function BFSO_onSaveComplete(saver, aTarget) {
     56        if (aOnTargetChangeFn) {
     57          aOnTargetChangeFn(aTarget);
     58        }
     59      },
     60      onSaveComplete: function BFSO_onSaveComplete(saver, aStatus) {
     61        if (Components.isSuccessCode(aStatus)) {
     62          resolve();
     63        } else {
     64          reject(new Components.Exception("Saver failed.", aStatus));
     65        }
     66      },
     67    };
     68  });
     69 }
     70 
     71 /**
     72 * Feeds a string to a BackgroundFileSaverOutputStream.
     73 *
     74 * @param aSourceString
     75 *        The source data to copy.
     76 * @param aSaverOutputStream
     77 *        The BackgroundFileSaverOutputStream to feed.
     78 * @param aCloseWhenDone
     79 *        If true, the output stream will be closed when the copy finishes.
     80 *
     81 * @returns {Promise<void>}
     82 *   Resolves when the copy completes with a success code.
     83 * @rejects With an exception, if the copy fails.
     84 */
     85 function promiseCopyToSaver(aSourceString, aSaverOutputStream, aCloseWhenDone) {
     86  return new Promise((resolve, reject) => {
     87    let inputStream = new StringInputStream(aSourceString);
     88    let copier = Cc[
     89      "@mozilla.org/network/async-stream-copier;1"
     90    ].createInstance(Ci.nsIAsyncStreamCopier);
     91    copier.init(
     92      inputStream,
     93      aSaverOutputStream,
     94      null,
     95      false,
     96      true,
     97      0x8000,
     98      true,
     99      aCloseWhenDone
    100    );
    101    copier.asyncCopy(
    102      {
    103        onStartRequest() {},
    104        onStopRequest(aRequest, aContext, aStatusCode) {
    105          if (Components.isSuccessCode(aStatusCode)) {
    106            resolve();
    107          } else {
    108            reject(new Components.Exception(aStatusCode));
    109          }
    110        },
    111      },
    112      null
    113    );
    114  });
    115 }
    116 
    117 var gStillRunning = true;
    118 
    119 ////////////////////////////////////////////////////////////////////////////////
    120 //// Tests
    121 
    122 add_task(function test_setup() {
    123  // Wait 10 minutes, that is half of the external xpcshell timeout.
    124  do_timeout(10 * 60 * 1000, function () {
    125    if (gStillRunning) {
    126      do_throw("Test timed out.");
    127    }
    128  });
    129 });
    130 
    131 function readFileToString(aFilename) {
    132  let f = do_get_file(aFilename);
    133  let stream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
    134    Ci.nsIFileInputStream
    135  );
    136  stream.init(f, -1, 0, 0);
    137  let buf = NetUtil.readInputStreamToString(stream, stream.available());
    138  return buf;
    139 }
    140 
    141 add_task(async function test_signature() {
    142  // Check that we get a signature if the saver is finished on Windows.
    143  let destFile = getTempFile(TEST_FILE_NAME_1);
    144 
    145  let data = readFileToString("data/signed_win.exe");
    146  let saver = new BackgroundFileSaverOutputStream();
    147  let completionPromise = promiseSaverComplete(saver);
    148 
    149  try {
    150    saver.signatureInfo;
    151    do_throw("Can't get signature before saver is complete.");
    152  } catch (ex) {
    153    if (ex.result != Cr.NS_ERROR_NOT_AVAILABLE) {
    154      throw ex;
    155    }
    156  }
    157 
    158  saver.enableSignatureInfo();
    159  saver.setTarget(destFile, false);
    160  await promiseCopyToSaver(data, saver, true);
    161 
    162  saver.finish(Cr.NS_OK);
    163  await completionPromise;
    164 
    165  // There's only one Array of certs(raw bytes) in the signature array.
    166  Assert.equal(1, saver.signatureInfo.length);
    167  let certLists = saver.signatureInfo;
    168  Assert.strictEqual(certLists.length, 1);
    169 
    170  // Check that it has 3 certs(raw bytes).
    171  let certs = certLists[0];
    172  Assert.strictEqual(certs.length, 3);
    173 
    174  const certDB = Cc["@mozilla.org/security/x509certdb;1"].getService(
    175    Ci.nsIX509CertDB
    176  );
    177  let signer = certDB.constructX509(certs[0]);
    178  let issuer = certDB.constructX509(certs[1]);
    179  let root = certDB.constructX509(certs[2]);
    180 
    181  let organization = "Microsoft Corporation";
    182  Assert.equal("Microsoft Corporation", signer.commonName);
    183  Assert.equal(organization, signer.organization);
    184  Assert.equal("Copyright (c) 2002 Microsoft Corp.", signer.organizationalUnit);
    185 
    186  Assert.equal("Microsoft Code Signing PCA", issuer.commonName);
    187  Assert.equal(organization, issuer.organization);
    188  Assert.equal("Copyright (c) 2000 Microsoft Corp.", issuer.organizationalUnit);
    189 
    190  Assert.equal("Microsoft Root Authority", root.commonName);
    191  Assert.ok(!root.organization);
    192  Assert.equal("Copyright (c) 1997 Microsoft Corp.", root.organizationalUnit);
    193 
    194  // Clean up.
    195  destFile.remove(false);
    196 });
    197 
    198 add_task(function test_teardown() {
    199  gStillRunning = false;
    200 });