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 +});