netwerk/test/unit/test_signature_extraction.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/netwerk/test/unit/test_signature_extraction.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,206 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* Any copyright is dedicated to the Public Domain.
     1.7 + * http://creativecommons.org/publicdomain/zero/1.0/ */
     1.8 +
     1.9 +/**
    1.10 + * This file tests signature extraction using Windows Authenticode APIs of
    1.11 + * downloaded files.
    1.12 + */
    1.13 +
    1.14 +////////////////////////////////////////////////////////////////////////////////
    1.15 +//// Globals
    1.16 +
    1.17 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.18 +
    1.19 +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
    1.20 +                                  "resource://gre/modules/FileUtils.jsm");
    1.21 +XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
    1.22 +                                  "resource://gre/modules/NetUtil.jsm");
    1.23 +XPCOMUtils.defineLazyModuleGetter(this, "Promise",
    1.24 +                                  "resource://gre/modules/Promise.jsm");
    1.25 +XPCOMUtils.defineLazyModuleGetter(this, "Task",
    1.26 +                                  "resource://gre/modules/Task.jsm");
    1.27 +
    1.28 +const BackgroundFileSaverOutputStream = Components.Constructor(
    1.29 +      "@mozilla.org/network/background-file-saver;1?mode=outputstream",
    1.30 +      "nsIBackgroundFileSaver");
    1.31 +
    1.32 +const StringInputStream = Components.Constructor(
    1.33 +      "@mozilla.org/io/string-input-stream;1",
    1.34 +      "nsIStringInputStream",
    1.35 +      "setData");
    1.36 +
    1.37 +const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt";
    1.38 +
    1.39 +/**
    1.40 + * Returns a reference to a temporary file.  If the file is then created, it
    1.41 + * will be removed when tests in this file finish.
    1.42 + */
    1.43 +function getTempFile(aLeafName) {
    1.44 +  let file = FileUtils.getFile("TmpD", [aLeafName]);
    1.45 +  do_register_cleanup(function GTF_cleanup() {
    1.46 +    if (file.exists()) {
    1.47 +      file.remove(false);
    1.48 +    }
    1.49 +  });
    1.50 +  return file;
    1.51 +}
    1.52 +
    1.53 +/**
    1.54 + * Waits for the given saver object to complete.
    1.55 + *
    1.56 + * @param aSaver
    1.57 + *        The saver, with the output stream or a stream listener implementation.
    1.58 + * @param aOnTargetChangeFn
    1.59 + *        Optional callback invoked with the target file name when it changes.
    1.60 + *
    1.61 + * @return {Promise}
    1.62 + * @resolves When onSaveComplete is called with a success code.
    1.63 + * @rejects With an exception, if onSaveComplete is called with a failure code.
    1.64 + */
    1.65 +function promiseSaverComplete(aSaver, aOnTargetChangeFn) {
    1.66 +  let deferred = Promise.defer();
    1.67 +  aSaver.observer = {
    1.68 +    onTargetChange: function BFSO_onSaveComplete(aSaver, aTarget)
    1.69 +    {
    1.70 +      if (aOnTargetChangeFn) {
    1.71 +        aOnTargetChangeFn(aTarget);
    1.72 +      }
    1.73 +    },
    1.74 +    onSaveComplete: function BFSO_onSaveComplete(aSaver, aStatus)
    1.75 +    {
    1.76 +      if (Components.isSuccessCode(aStatus)) {
    1.77 +        deferred.resolve();
    1.78 +      } else {
    1.79 +        deferred.reject(new Components.Exception("Saver failed.", aStatus));
    1.80 +      }
    1.81 +    },
    1.82 +  };
    1.83 +  return deferred.promise;
    1.84 +}
    1.85 +
    1.86 +/**
    1.87 + * Feeds a string to a BackgroundFileSaverOutputStream.
    1.88 + *
    1.89 + * @param aSourceString
    1.90 + *        The source data to copy.
    1.91 + * @param aSaverOutputStream
    1.92 + *        The BackgroundFileSaverOutputStream to feed.
    1.93 + * @param aCloseWhenDone
    1.94 + *        If true, the output stream will be closed when the copy finishes.
    1.95 + *
    1.96 + * @return {Promise}
    1.97 + * @resolves When the copy completes with a success code.
    1.98 + * @rejects With an exception, if the copy fails.
    1.99 + */
   1.100 +function promiseCopyToSaver(aSourceString, aSaverOutputStream, aCloseWhenDone) {
   1.101 +  let deferred = Promise.defer();
   1.102 +  let inputStream = new StringInputStream(aSourceString, aSourceString.length);
   1.103 +  let copier = Cc["@mozilla.org/network/async-stream-copier;1"]
   1.104 +               .createInstance(Ci.nsIAsyncStreamCopier);
   1.105 +  copier.init(inputStream, aSaverOutputStream, null, false, true, 0x8000, true,
   1.106 +              aCloseWhenDone);
   1.107 +  copier.asyncCopy({
   1.108 +    onStartRequest: function () { },
   1.109 +    onStopRequest: function (aRequest, aContext, aStatusCode)
   1.110 +    {
   1.111 +      if (Components.isSuccessCode(aStatusCode)) {
   1.112 +        deferred.resolve();
   1.113 +      } else {
   1.114 +        deferred.reject(new Components.Exception(aResult));
   1.115 +      }
   1.116 +    },
   1.117 +  }, null);
   1.118 +  return deferred.promise;
   1.119 +}
   1.120 +
   1.121 +let gStillRunning = true;
   1.122 +
   1.123 +////////////////////////////////////////////////////////////////////////////////
   1.124 +//// Tests
   1.125 +
   1.126 +function run_test()
   1.127 +{
   1.128 +  run_next_test();
   1.129 +}
   1.130 +
   1.131 +add_task(function test_setup()
   1.132 +{
   1.133 +  // Wait 10 minutes, that is half of the external xpcshell timeout.
   1.134 +  do_timeout(10 * 60 * 1000, function() {
   1.135 +    if (gStillRunning) {
   1.136 +      do_throw("Test timed out.");
   1.137 +    }
   1.138 +  })
   1.139 +});
   1.140 +
   1.141 +function readFileToString(aFilename) {
   1.142 +  let f = do_get_file(aFilename);
   1.143 +  let stream = Cc["@mozilla.org/network/file-input-stream;1"]
   1.144 +                 .createInstance(Ci.nsIFileInputStream);
   1.145 +  stream.init(f, -1, 0, 0);
   1.146 +  let buf = NetUtil.readInputStreamToString(stream, stream.available());
   1.147 +  return buf;
   1.148 +}
   1.149 +
   1.150 +add_task(function test_signature()
   1.151 +{
   1.152 +  // Check that we get a signature if the saver is finished on Windows.
   1.153 +  let destFile = getTempFile(TEST_FILE_NAME_1);
   1.154 +
   1.155 +  let data = readFileToString("data/signed_win.exe");
   1.156 +  let saver = new BackgroundFileSaverOutputStream();
   1.157 +  let completionPromise = promiseSaverComplete(saver);
   1.158 +
   1.159 +  try {
   1.160 +    let signatureInfo = saver.signatureInfo;
   1.161 +    do_throw("Can't get signature before saver is complete.");
   1.162 +  } catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
   1.163 +
   1.164 +  saver.enableSignatureInfo();
   1.165 +  saver.setTarget(destFile, false);
   1.166 +  yield promiseCopyToSaver(data, saver, true);
   1.167 +
   1.168 +  saver.finish(Cr.NS_OK);
   1.169 +  yield completionPromise;
   1.170 +
   1.171 +  // There's only one nsIX509CertList in the signature array.
   1.172 +  do_check_eq(1, saver.signatureInfo.length);
   1.173 +  let certLists = saver.signatureInfo.enumerate();
   1.174 +  do_check_true(certLists.hasMoreElements());
   1.175 +  let certList = certLists.getNext().QueryInterface(Ci.nsIX509CertList);
   1.176 +  do_check_false(certLists.hasMoreElements());
   1.177 +
   1.178 +  // Check that it has 3 certs.
   1.179 +  let certs = certList.getEnumerator();
   1.180 +  do_check_true(certs.hasMoreElements());
   1.181 +  let signer = certs.getNext().QueryInterface(Ci.nsIX509Cert);
   1.182 +  do_check_true(certs.hasMoreElements());
   1.183 +  let issuer = certs.getNext().QueryInterface(Ci.nsIX509Cert);
   1.184 +  do_check_true(certs.hasMoreElements());
   1.185 +  let root = certs.getNext().QueryInterface(Ci.nsIX509Cert);
   1.186 +  do_check_false(certs.hasMoreElements());
   1.187 +
   1.188 +  // Check that the certs have expected strings attached.
   1.189 +  let organization = "Microsoft Corporation";
   1.190 +  do_check_eq("Microsoft Corporation", signer.commonName);
   1.191 +  do_check_eq(organization, signer.organization);
   1.192 +  do_check_eq("Copyright (c) 2002 Microsoft Corp.", signer.organizationalUnit);
   1.193 +
   1.194 +  do_check_eq("Microsoft Code Signing PCA", issuer.commonName);
   1.195 +  do_check_eq(organization, issuer.organization);
   1.196 +  do_check_eq("Copyright (c) 2000 Microsoft Corp.", issuer.organizationalUnit);
   1.197 +
   1.198 +  do_check_eq("Microsoft Root Authority", root.commonName);
   1.199 +  do_check_false(root.organization);
   1.200 +  do_check_eq("Copyright (c) 1997 Microsoft Corp.", root.organizationalUnit);
   1.201 +
   1.202 +  // Clean up.
   1.203 +  destFile.remove(false);
   1.204 +});
   1.205 +
   1.206 +add_task(function test_teardown()
   1.207 +{
   1.208 +  gStillRunning = false;
   1.209 +});

mercurial