Backed out 3 changesets (bug 928536) for build bustage

CLOSED TREE

Backed out changeset 750054102e68 (bug 928536)
Backed out changeset baa309383864 (bug 928536)
Backed out changeset 1ff2aed7f76f (bug 928536)
This commit is contained in:
Phil Ringnalda 2014-02-05 08:29:17 -08:00
parent c1bbda36fe
commit bbae79c349
20 changed files with 36 additions and 764 deletions

View File

@ -6,7 +6,6 @@
#include "nsISupports.idl"
interface nsIArray;
interface nsIBackgroundFileSaverObserver;
interface nsIFile;
@ -39,7 +38,7 @@ interface nsIFile;
* public methods of the interface may only be called from the main
* thread.
*/
[scriptable, uuid(c43544a4-682c-4262-b407-2453d26e660d)]
[scriptable, uuid(581a99ca-dc8d-4cee-ac95-99156e7517ed)]
interface nsIBackgroundFileSaver : nsISupports
{
/**
@ -53,16 +52,13 @@ interface nsIBackgroundFileSaver : nsISupports
attribute nsIBackgroundFileSaverObserver observer;
/**
* An nsIArray of nsIX509CertList, representing a chain of X.509 signatures on
* the downloaded file. Each list may belong to a different signer and contain
* certificates all the way up to the root.
* Instructs the component to compute the SHA-256 hash of the target file, and
* make it available in the sha256Hash property.
*
* @throws NS_ERROR_NOT_AVAILABLE
* In case this is called before the onSaveComplete method has been
* called to notify success, or enableSignatureInfo has not been
* called.
* @remarks This must be set on the main thread before the first call to
* setTarget.
*/
readonly attribute nsIArray signatureInfo;
void enableSha256();
/**
* The SHA-256 hash, in raw bytes, associated with the data that was saved.
@ -76,24 +72,6 @@ interface nsIBackgroundFileSaver : nsISupports
*/
readonly attribute ACString sha256Hash;
/**
* Instructs the component to compute the signatureInfo of the target file,
* and make it available in the signatureInfo property.
*
* @remarks This must be set on the main thread before the first call to
* setTarget.
*/
void enableSignatureInfo();
/**
* Instructs the component to compute the SHA-256 hash of the target file, and
* make it available in the sha256Hash property.
*
* @remarks This must be set on the main thread before the first call to
* setTarget.
*/
void enableSha256();
/**
* Instructs the component to append data to the initial target file, that
* will be specified by the first call to the setTarget method, instead of

View File

@ -5,45 +5,21 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "pk11pub.h"
#include "prlog.h"
#include "ScopedNSSTypes.h"
#include "secoidt.h"
#include "nsIAsyncInputStream.h"
#include "nsIFile.h"
#include "nsIMutableArray.h"
#include "nsIPipe.h"
#include "nsIX509Cert.h"
#include "nsIX509CertDB.h"
#include "nsIX509CertList.h"
#include "nsCOMArray.h"
#include "nsNetUtil.h"
#include "nsThreadUtils.h"
#include "BackgroundFileSaver.h"
#include "mozilla/Telemetry.h"
#ifdef XP_WIN
#include <windows.h>
#include <softpub.h>
#include <wintrust.h>
#pragma comment(lib, "wintrust.lib")
#endif // XP_WIN
#include "nsIAsyncInputStream.h"
namespace mozilla {
namespace net {
// NSPR_LOG_MODULES=BackgroundFileSaver:5
#if defined(PR_LOGGING)
PRLogModuleInfo *BackgroundFileSaver::prlog = nullptr;
#define LOG(args) PR_LOG(BackgroundFileSaver::prlog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(BackgroundFileSaver::prlog, 4)
#else
#define LOG(args)
#define LOG_ENABLED() (false)
#endif
////////////////////////////////////////////////////////////////////////////////
//// Globals
@ -112,21 +88,14 @@ BackgroundFileSaver::BackgroundFileSaver()
, mRenamedTargetKeepPartial(false)
, mAsyncCopyContext(nullptr)
, mSha256Enabled(false)
, mSignatureInfoEnabled(false)
, mActualTarget(nullptr)
, mActualTargetKeepPartial(false)
, mDigestContext(nullptr)
{
#if defined(PR_LOGGING)
if (!prlog)
prlog = PR_NewLogModule("BackgroundFileSaver");
#endif
LOG(("Created BackgroundFileSaver [this = %p]", this));
}
BackgroundFileSaver::~BackgroundFileSaver()
{
LOG(("Destroying BackgroundFileSaver [this = %p]", this));
nsNSSShutDownPreventionLock lock;
if (isAlreadyShutDown()) {
return;
@ -262,12 +231,12 @@ BackgroundFileSaver::EnableSha256()
{
MOZ_ASSERT(NS_IsMainThread(),
"Can't enable sha256 or initialize NSS off the main thread");
mSha256Enabled = true;
// Ensure Personal Security Manager is initialized. This is required for
// PK11_* operations to work.
nsresult rv;
nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
mSha256Enabled = true;
return NS_OK;
}
@ -284,37 +253,6 @@ BackgroundFileSaver::GetSha256Hash(nsACString& aHash)
return NS_OK;
}
NS_IMETHODIMP
BackgroundFileSaver::EnableSignatureInfo()
{
MOZ_ASSERT(NS_IsMainThread(),
"Can't enable signature extraction off the main thread");
// Ensure Personal Security Manager is initialized.
nsresult rv;
nsCOMPtr<nsISupports> nssDummy = do_GetService("@mozilla.org/psm;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
mSignatureInfoEnabled = true;
return NS_OK;
}
NS_IMETHODIMP
BackgroundFileSaver::GetSignatureInfo(nsIArray** aSignatureInfo)
{
MOZ_ASSERT(NS_IsMainThread(), "Can't inspect signature off the main thread");
// We acquire a lock because mSignatureInfo is written on the worker thread.
MutexAutoLock lock(mLock);
if (!mComplete || !mSignatureInfoEnabled) {
return NS_ERROR_NOT_AVAILABLE;
}
nsCOMPtr<nsIMutableArray> sigArray = do_CreateInstance(NS_ARRAY_CONTRACTID);
for (int i = 0; i < mSignatureInfo.Count(); ++i) {
sigArray->AppendElement(mSignatureInfo[i], false);
}
*aSignatureInfo = sigArray;
NS_IF_ADDREF(*aSignatureInfo);
return NS_OK;
}
// Called on the control thread.
nsresult
BackgroundFileSaver::GetWorkerThreadAttention(bool aShouldInterruptCopy)
@ -741,19 +679,6 @@ BackgroundFileSaver::CheckCompletion()
}
}
// Compute the signature of the binary. ExtractSignatureInfo doesn't do
// anything on non-Windows platforms except return an empty nsIArray.
if (!failed && mActualTarget) {
nsString filePath;
mActualTarget->GetTarget(filePath);
nsresult rv = ExtractSignatureInfo(filePath);
if (NS_FAILED(rv)) {
LOG(("Unable to extract signature information [this = %p].", this));
} else {
LOG(("Signature extraction success! [this = %p]", this));
}
}
// Post an event to notify that the operation completed.
nsCOMPtr<nsIRunnable> event =
NS_NewRunnableMethod(this, &BackgroundFileSaver::NotifySaveComplete);
@ -816,124 +741,6 @@ BackgroundFileSaver::NotifySaveComplete()
return NS_OK;
}
nsresult
BackgroundFileSaver::ExtractSignatureInfo(const nsAString& filePath)
{
MOZ_ASSERT(!NS_IsMainThread(), "Cannot extract signature on main thread");
nsNSSShutDownPreventionLock nssLock;
if (isAlreadyShutDown()) {
return NS_ERROR_NOT_AVAILABLE;
}
{
MutexAutoLock lock(mLock);
if (!mSignatureInfoEnabled) {
return NS_OK;
}
}
nsresult rv;
nsCOMPtr<nsIX509CertDB> certDB = do_GetService(NS_X509CERTDB_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef XP_WIN
// Setup the file to check.
WINTRUST_FILE_INFO fileToCheck = {0};
fileToCheck.cbStruct = sizeof(WINTRUST_FILE_INFO);
fileToCheck.pcwszFilePath = filePath.Data();
fileToCheck.hFile = nullptr;
fileToCheck.pgKnownSubject = nullptr;
// We want to check it is signed and trusted.
WINTRUST_DATA trustData = {0};
trustData.cbStruct = sizeof(trustData);
trustData.pPolicyCallbackData = nullptr;
trustData.pSIPClientData = nullptr;
trustData.dwUIChoice = WTD_UI_NONE;
trustData.fdwRevocationChecks = WTD_REVOKE_NONE;
trustData.dwUnionChoice = WTD_CHOICE_FILE;
trustData.dwStateAction = WTD_STATEACTION_VERIFY;
trustData.hWVTStateData = nullptr;
trustData.pwszURLReference = nullptr;
// Disallow revocation checks over the network
trustData.dwProvFlags = WTD_CACHE_ONLY_URL_RETRIEVAL;
// no UI
trustData.dwUIContext = 0;
trustData.pFile = &fileToCheck;
// The WINTRUST_ACTION_GENERIC_VERIFY_V2 policy verifies that the certificate
// chains up to a trusted root CA and has appropriate permissions to sign
// code.
GUID policyGUID = WINTRUST_ACTION_GENERIC_VERIFY_V2;
// Check if the file is signed by something that is trusted. If the file is
// not signed, this is a no-op.
LONG ret = WinVerifyTrust(nullptr, &policyGUID, &trustData);
CRYPT_PROVIDER_DATA* cryptoProviderData = nullptr;
// According to the Windows documentation, we should check against 0 instead
// of ERROR_SUCCESS, which is an HRESULT.
if (ret == 0) {
cryptoProviderData = WTHelperProvDataFromStateData(trustData.hWVTStateData);
}
if (cryptoProviderData) {
// Lock because signature information is read on the main thread.
MutexAutoLock lock(mLock);
LOG(("Downloaded trusted and signed file [this = %p].", this));
// A binary may have multiple signers. Each signer may have multiple certs
// in the chain.
for (DWORD i = 0; i < cryptoProviderData->csSigners; ++i) {
const CERT_CHAIN_CONTEXT* certChainContext =
cryptoProviderData->pasSigners[i].pChainContext;
if (!certChainContext) {
break;
}
for (DWORD j = 0; j < certChainContext->cChain; ++j) {
const CERT_SIMPLE_CHAIN* certSimpleChain =
certChainContext->rgpChain[j];
if (!certSimpleChain) {
break;
}
nsCOMPtr<nsIX509CertList> nssCertList =
do_CreateInstance(NS_X509CERTLIST_CONTRACTID);
if (!nssCertList) {
break;
}
bool extractionSuccess = true;
for (DWORD k = 0; k < certSimpleChain->cElement; ++k) {
CERT_CHAIN_ELEMENT* certChainElement = certSimpleChain->rgpElement[k];
if (certChainElement->pCertContext->dwCertEncodingType !=
X509_ASN_ENCODING) {
continue;
}
nsCOMPtr<nsIX509Cert> nssCert = nullptr;
rv = certDB->ConstructX509(
reinterpret_cast<char *>(
certChainElement->pCertContext->pbCertEncoded),
certChainElement->pCertContext->cbCertEncoded,
getter_AddRefs(nssCert));
if (!nssCert) {
extractionSuccess = false;
LOG(("Couldn't create NSS cert [this = %p]", this));
break;
}
nssCertList->AddCert(nssCert);
nsString subjectName;
nssCert->GetSubjectName(subjectName);
LOG(("Adding cert %s [this = %p]",
NS_ConvertUTF16toUTF8(subjectName).get(), this));
}
if (extractionSuccess) {
mSignatureInfo.AppendObject(nssCertList);
}
}
}
// Free the provider data if cryptoProviderData is not null.
trustData.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust(nullptr, &policyGUID, &trustData);
} else {
LOG(("Downloaded unsigned or untrusted file [this = %p].", this));
}
#endif
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// BackgroundFileSaverOutputStream
@ -1272,5 +1079,6 @@ DigestOutputStream::IsNonBlocking(bool *retval)
return mOutputStream->IsNonBlocking(retval);
}
} // namespace net
} // namespace mozilla

View File

@ -13,7 +13,6 @@
#define BackgroundFileSaver_h__
#include "mozilla/Mutex.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "nsNSSShutDown.h"
#include "nsIAsyncOutputStream.h"
@ -24,8 +23,6 @@
class nsIAsyncInputStream;
class nsIThread;
class nsIX509CertList;
class PRLogModuleInfo;
namespace mozilla {
namespace net {
@ -74,8 +71,6 @@ public:
protected:
virtual ~BackgroundFileSaver();
static PRLogModuleInfo *prlog;
/**
* Helper function for managing NSS objects (mDigestContext).
*/
@ -216,17 +211,6 @@ private:
*/
bool mSha256Enabled;
/**
* Store the signature info.
*/
nsCOMArray<nsIX509CertList> mSignatureInfo;
/**
* Whether or not to extract the signature. Must be set on the main thread
* before setTarget is called.
*/
bool mSignatureInfoEnabled;
//////////////////////////////////////////////////////////////////////////////
//// State handled exclusively by the worker thread
@ -297,13 +281,6 @@ private:
* Event called on the control thread to send the final notification.
*/
nsresult NotifySaveComplete();
/**
* Verifies the signature of the binary at the specified file path and stores
* the signature data in mSignatureInfo. We extract only X.509 certificates,
* since that is what Google's Safebrowsing protocol specifies.
*/
nsresult ExtractSignatureInfo(const nsAString& filePath);
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -295,14 +295,6 @@ add_task(function test_combinations()
let initialFile = getTempFile(TEST_FILE_NAME_1);
let renamedFile = getTempFile(TEST_FILE_NAME_2);
// Keep track of the current file.
let currentFile = null;
function onTargetChange(aTarget) {
currentFile = null;
do_print("Target file changed to: " + aTarget.leafName);
currentFile = aTarget;
}
// Tests various combinations of events and behaviors for both the stream
// listener and the output stream implementations.
for (let testFlags = 0; testFlags < 32; testFlags++) {
@ -319,8 +311,14 @@ add_task(function test_combinations()
", useStreamListener = " + useStreamListener +
", useLongData = " + useLongData);
// Keep track of the current file.
let currentFile = null;
function onTargetChange(aTarget) {
do_print("Target file changed to: " + aTarget.leafName);
currentFile = aTarget;
}
// Create the object and register the observers.
currentFile = null;
let saver = useStreamListener
? new BackgroundFileSaverStreamListener()
: new BackgroundFileSaverOutputStream();
@ -367,7 +365,7 @@ add_task(function test_combinations()
if (!cancelAtSomePoint) {
// In this case, the file must exist.
do_check_true(currentFile.exists());
let expectedContents = testData + testData;
expectedContents = testData + testData;
yield promiseVerifyContents(currentFile, expectedContents);
do_check_eq(EXPECTED_HASHES[expectedContents.length],
toHex(saver.sha256Hash));
@ -670,55 +668,6 @@ add_task(function test_invalid_hash()
} catch (ex if ex.result == Cr.NS_ERROR_FAILURE) { }
});
add_task(function test_signature()
{
// Check that we get a signature if the saver is finished.
let destFile = getTempFile(TEST_FILE_NAME_1);
let saver = new BackgroundFileSaverOutputStream();
let completionPromise = promiseSaverComplete(saver);
try {
let signatureInfo = saver.signatureInfo;
do_throw("Can't get signature if saver is not complete");
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
saver.enableSignatureInfo();
saver.setTarget(destFile, false);
yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
saver.finish(Cr.NS_OK);
yield completionPromise;
yield promiseVerifyContents(destFile, TEST_DATA_SHORT);
// signatureInfo is an empty nsIArray
do_check_eq(0, saver.signatureInfo.length);
// Clean up.
destFile.remove(false);
});
add_task(function test_signature_not_enabled()
{
// Check that we get a signature if the saver is finished on Windows.
let destFile = getTempFile(TEST_FILE_NAME_1);
let saver = new BackgroundFileSaverOutputStream();
let completionPromise = promiseSaverComplete(saver);
saver.setTarget(destFile, false);
yield promiseCopyToSaver(TEST_DATA_SHORT, saver, true);
saver.finish(Cr.NS_OK);
yield completionPromise;
try {
let signatureInfo = saver.signatureInfo;
do_throw("Can't get signature if not enabled");
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
// Clean up.
destFile.remove(false);
});
add_task(function test_teardown()
{
gStillRunning = false;

View File

@ -1,206 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This file tests signature extraction using Windows Authenticode APIs of
* downloaded files.
*/
////////////////////////////////////////////////////////////////////////////////
//// Globals
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
"resource://gre/modules/FileUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/commonjs/sdk/core/promise.js");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
const BackgroundFileSaverOutputStream = Components.Constructor(
"@mozilla.org/network/background-file-saver;1?mode=outputstream",
"nsIBackgroundFileSaver");
const StringInputStream = Components.Constructor(
"@mozilla.org/io/string-input-stream;1",
"nsIStringInputStream",
"setData");
const TEST_FILE_NAME_1 = "test-backgroundfilesaver-1.txt";
/**
* Returns a reference to a temporary file. If the file is then created, it
* will be removed when tests in this file finish.
*/
function getTempFile(aLeafName) {
let file = FileUtils.getFile("TmpD", [aLeafName]);
do_register_cleanup(function GTF_cleanup() {
if (file.exists()) {
file.remove(false);
}
});
return file;
}
/**
* Waits for the given saver object to complete.
*
* @param aSaver
* The saver, with the output stream or a stream listener implementation.
* @param aOnTargetChangeFn
* Optional callback invoked with the target file name when it changes.
*
* @return {Promise}
* @resolves When onSaveComplete is called with a success code.
* @rejects With an exception, if onSaveComplete is called with a failure code.
*/
function promiseSaverComplete(aSaver, aOnTargetChangeFn) {
let deferred = Promise.defer();
aSaver.observer = {
onTargetChange: function BFSO_onSaveComplete(aSaver, aTarget)
{
if (aOnTargetChangeFn) {
aOnTargetChangeFn(aTarget);
}
},
onSaveComplete: function BFSO_onSaveComplete(aSaver, aStatus)
{
if (Components.isSuccessCode(aStatus)) {
deferred.resolve();
} else {
deferred.reject(new Components.Exception("Saver failed.", aStatus));
}
},
};
return deferred.promise;
}
/**
* Feeds a string to a BackgroundFileSaverOutputStream.
*
* @param aSourceString
* The source data to copy.
* @param aSaverOutputStream
* The BackgroundFileSaverOutputStream to feed.
* @param aCloseWhenDone
* If true, the output stream will be closed when the copy finishes.
*
* @return {Promise}
* @resolves When the copy completes with a success code.
* @rejects With an exception, if the copy fails.
*/
function promiseCopyToSaver(aSourceString, aSaverOutputStream, aCloseWhenDone) {
let deferred = Promise.defer();
let inputStream = new StringInputStream(aSourceString, aSourceString.length);
let copier = Cc["@mozilla.org/network/async-stream-copier;1"]
.createInstance(Ci.nsIAsyncStreamCopier);
copier.init(inputStream, aSaverOutputStream, null, false, true, 0x8000, true,
aCloseWhenDone);
copier.asyncCopy({
onStartRequest: function () { },
onStopRequest: function (aRequest, aContext, aStatusCode)
{
if (Components.isSuccessCode(aStatusCode)) {
deferred.resolve();
} else {
deferred.reject(new Components.Exception(aResult));
}
},
}, null);
return deferred.promise;
}
let gStillRunning = true;
////////////////////////////////////////////////////////////////////////////////
//// Tests
function run_test()
{
run_next_test();
}
add_task(function test_setup()
{
// Wait 10 minutes, that is half of the external xpcshell timeout.
do_timeout(10 * 60 * 1000, function() {
if (gStillRunning) {
do_throw("Test timed out.");
}
})
});
function readFileToString(aFilename) {
let f = do_get_file(aFilename);
let stream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
stream.init(f, -1, 0, 0);
let buf = NetUtil.readInputStreamToString(stream, stream.available());
return buf;
}
add_task(function test_signature()
{
// Check that we get a signature if the saver is finished on Windows.
let destFile = getTempFile(TEST_FILE_NAME_1);
let data = readFileToString("data/signed_win.exe");
let saver = new BackgroundFileSaverOutputStream();
let completionPromise = promiseSaverComplete(saver);
try {
let signatureInfo = saver.signatureInfo;
do_throw("Can't get signature before saver is complete.");
} catch (ex if ex.result == Cr.NS_ERROR_NOT_AVAILABLE) { }
saver.enableSignatureInfo();
saver.setTarget(destFile, false);
yield promiseCopyToSaver(data, saver, true);
saver.finish(Cr.NS_OK);
yield completionPromise;
// There's only one nsIX509CertList in the signature array.
do_check_eq(1, saver.signatureInfo.length);
let certLists = saver.signatureInfo.enumerate();
do_check_true(certLists.hasMoreElements());
let certList = certLists.getNext().QueryInterface(Ci.nsIX509CertList);
do_check_false(certLists.hasMoreElements());
// Check that it has 3 certs.
let certs = certList.getEnumerator();
do_check_true(certs.hasMoreElements());
let signer = certs.getNext().QueryInterface(Ci.nsIX509Cert);
do_check_true(certs.hasMoreElements());
let issuer = certs.getNext().QueryInterface(Ci.nsIX509Cert);
do_check_true(certs.hasMoreElements());
let root = certs.getNext().QueryInterface(Ci.nsIX509Cert);
do_check_false(certs.hasMoreElements());
// Check that the certs have expected strings attached.
let organization = "Microsoft Corporation";
do_check_eq("Microsoft Corporation", signer.commonName);
do_check_eq(organization, signer.organization);
do_check_eq("Copyright (c) 2002 Microsoft Corp.", signer.organizationalUnit);
do_check_eq("Microsoft Code Signing PCA", issuer.commonName);
do_check_eq(organization, issuer.organization);
do_check_eq("Copyright (c) 2000 Microsoft Corp.", issuer.organizationalUnit);
do_check_eq("Microsoft Root Authority", root.commonName);
do_check_false(root.organization);
do_check_eq("Copyright (c) 1997 Microsoft Corp.", root.organizationalUnit);
// Clean up.
destFile.remove(false);
});
add_task(function test_teardown()
{
gStillRunning = false;
});

View File

@ -13,7 +13,6 @@ support-files =
data/test_readline6.txt
data/test_readline7.txt
data/test_readline8.txt
data/signed_win.exe
socks_client_subprocess.js
test_link.desktop
test_link.url
@ -310,5 +309,3 @@ skip-if = os == "android"
# disable this test on all android versions, even though it's enabled on 2.3+ in
# the wild.
skip-if = os == "android"
[test_signature_extraction.js]
run-if = os == "win"

View File

@ -7,7 +7,6 @@
#include "ApplicationReputation.h"
#include "csd.pb.h"
#include "nsIArray.h"
#include "nsIApplicationReputation.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
@ -19,8 +18,6 @@
#include "nsIUploadChannel2.h"
#include "nsIURI.h"
#include "nsIUrlClassifierDBService.h"
#include "nsIX509Cert.h"
#include "nsIX509CertList.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
@ -38,7 +35,6 @@
using mozilla::Preferences;
using mozilla::Telemetry::Accumulate;
using safe_browsing::ClientDownloadRequest_SignatureInfo;
// Preferences that we need to initialize the query. We may need another
// preference than browser.safebrowsing.malware.enabled, or simply use
@ -49,15 +45,6 @@ using safe_browsing::ClientDownloadRequest_SignatureInfo;
#define PREF_DOWNLOAD_BLOCK_TABLE "urlclassifier.download_block_table"
#define PREF_DOWNLOAD_ALLOW_TABLE "urlclassifier.download_allow_table"
// NSPR_LOG_MODULES=ApplicationReputation:5
#if defined(PR_LOGGING)
PRLogModuleInfo *ApplicationReputationService::prlog = nullptr;
#define LOG(args) PR_LOG(ApplicationReputationService::prlog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(ApplicationReputationService::prlog, 4)
#else
#define LOG(args)
#define LOG_ENABLED() (false)
#endif
/**
* Keep track of pending lookups. Once the ApplicationReputationService creates
* this, it is guaranteed to call mCallback. This class is private to
@ -118,12 +105,6 @@ private:
nsISupports *aContext,
nsresult aResult,
bool* aShouldBlock);
/**
* Parse the XPCOM certificate lists and stick them into the protocol buffer
* version.
*/
nsresult ParseCertificates(nsIArray* aSigArray,
ClientDownloadRequest_SignatureInfo* aSigInfo);
/**
* Sends a query to the remote application reputation service. Returns NS_OK
* on success.
@ -139,27 +120,16 @@ NS_IMPL_ISUPPORTS3(PendingLookup,
PendingLookup::PendingLookup(nsIApplicationReputationQuery* aQuery,
nsIApplicationReputationCallback* aCallback) :
mQuery(aQuery),
mCallback(aCallback)
{
LOG(("Created pending lookup [this = %p]", this));
mCallback(aCallback) {
}
PendingLookup::~PendingLookup()
{
LOG(("Destroying pending lookup [this = %p]", this));
PendingLookup::~PendingLookup() {
}
nsresult
PendingLookup::OnComplete(bool shouldBlock, nsresult rv)
{
PendingLookup::OnComplete(bool shouldBlock, nsresult rv) {
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_SHOULD_BLOCK,
shouldBlock);
if (shouldBlock) {
LOG(("Application Reputation check failed, blocking bad binary "
"[this = %p]", this));
} else {
LOG(("Application Reputation check passed [this = %p]", this));
}
nsresult res = mCallback->OnComplete(shouldBlock, rv);
return res;
}
@ -167,8 +137,7 @@ PendingLookup::OnComplete(bool shouldBlock, nsresult rv)
////////////////////////////////////////////////////////////////////////////////
//// nsIUrlClassifierCallback
NS_IMETHODIMP
PendingLookup::HandleEvent(const nsACString& tables)
{
PendingLookup::HandleEvent(const nsACString& tables) {
// HandleEvent is guaranteed to call the callback if either the URL can be
// classified locally, or if there is an error sending the remote lookup.
// Allow listing trumps block listing.
@ -176,7 +145,6 @@ PendingLookup::HandleEvent(const nsACString& tables)
Preferences::GetCString(PREF_DOWNLOAD_ALLOW_TABLE, &allow_list);
if (FindInReadable(tables, allow_list)) {
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, ALLOW_LIST);
LOG(("Found principal on allowlist [this = %p]", this));
return OnComplete(false, NS_OK);
}
@ -184,83 +152,24 @@ PendingLookup::HandleEvent(const nsACString& tables)
Preferences::GetCString(PREF_DOWNLOAD_BLOCK_TABLE, &block_list);
if (FindInReadable(tables, block_list)) {
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, BLOCK_LIST);
LOG(("Found principal on blocklist [this = %p]", this));
return OnComplete(true, NS_OK);
}
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_LOCAL, NO_LIST);
// Revert to just ifdef XP_WIN when remote lookups are enabled (bug 933432)
#if 0 and defined(XP_WIN)
#if 0
nsresult rv = SendRemoteQuery();
if (NS_FAILED(rv)) {
return OnComplete(false, rv);
}
return NS_OK;
#else
// Revert when remote lookups are enabled (bug 933432)
return OnComplete(false, NS_OK);
#endif
}
nsresult
PendingLookup::ParseCertificates(
nsIArray* aSigArray,
ClientDownloadRequest_SignatureInfo* aSignatureInfo)
{
// Binaries may be signed by multiple chains of certificates. If there are no
// chains, the binary is unsiged (or we were unable to extract signature
// information on a non-Windows platform)
nsCOMPtr<nsISimpleEnumerator> chains = nullptr;
nsresult rv = aSigArray->Enumerate(getter_AddRefs(chains));
NS_ENSURE_SUCCESS(rv, rv);
bool hasMoreChains = false;
rv = chains->HasMoreElements(&hasMoreChains);
NS_ENSURE_SUCCESS(rv, rv);
while (hasMoreChains) {
nsCOMPtr<nsIX509CertList> certList = nullptr;
rv = chains->GetNext(getter_AddRefs(certList));
NS_ENSURE_SUCCESS(rv, rv);
safe_browsing::ClientDownloadRequest_CertificateChain* certChain =
aSignatureInfo->add_certificate_chain();
nsCOMPtr<nsISimpleEnumerator> chainElt = nullptr;
rv = certList->GetEnumerator(getter_AddRefs(chainElt));
NS_ENSURE_SUCCESS(rv, rv);
// Each chain may have multiple certificates.
bool hasMoreCerts = false;
rv = chainElt->HasMoreElements(&hasMoreCerts);
while (hasMoreCerts) {
nsCOMPtr<nsIX509Cert> cert = nullptr;
rv = chainElt->GetNext(getter_AddRefs(cert));
NS_ENSURE_SUCCESS(rv, rv);
uint8_t* data = nullptr;
uint32_t len = 0;
rv = cert->GetRawDER(&len, &data);
NS_ENSURE_SUCCESS(rv, rv);
// Add this certificate to the protobuf to send remotely.
certChain->add_element()->set_certificate(data, len);
nsMemory::Free(data);
rv = chainElt->HasMoreElements(&hasMoreCerts);
NS_ENSURE_SUCCESS(rv, rv);
}
rv = chains->HasMoreElements(&hasMoreChains);
NS_ENSURE_SUCCESS(rv, rv);
}
if (aSignatureInfo->certificate_chain_size() > 0) {
aSignatureInfo->set_trusted(true);
}
return NS_OK;
}
nsresult
PendingLookup::SendRemoteQuery()
{
LOG(("Sending remote query for application reputation [this = %p]", this));
PendingLookup::SendRemoteQuery() {
// We did not find a local result, so fire off the query to the application
// reputation service.
safe_browsing::ClientDownloadRequest req;
@ -293,22 +202,6 @@ PendingLookup::SendRemoteQuery()
NS_ENSURE_SUCCESS(rv, rv);
req.set_file_basename(NS_ConvertUTF16toUTF8(fileName).get());
// Extract the signature and parse certificates so we can use it to check
// whitelists.
nsCOMPtr<nsIArray> sigArray = nullptr;
rv = mQuery->GetSignatureInfo(getter_AddRefs(sigArray));
NS_ENSURE_SUCCESS(rv, rv);
// This actually needs to be further up, but it can wait until bug 964465
rv = ParseCertificates(sigArray, req.mutable_signature());
NS_ENSURE_SUCCESS(rv, rv);
if (req.signature().trusted()) {
LOG(("Got signed binary for application reputation [this = %p]", this));
} else {
LOG(("Got unsigned binary for application reputation [this = %p]", this));
}
// Serialize the protocol buffer to a string. This can only fail if we are
// out of memory, or if the protocol buffer req is missing required fields
// (only the URL for now).
@ -478,12 +371,6 @@ ApplicationReputationService::GetSingleton()
ApplicationReputationService::ApplicationReputationService() :
mDBService(nullptr),
mSecurityManager(nullptr) {
#if defined(PR_LOGGING)
if (!prlog) {
prlog = PR_NewLogModule("ApplicationReputation");
}
#endif
LOG(("Application reputation service started up"));
}
ApplicationReputationService::~ApplicationReputationService() {
@ -496,7 +383,6 @@ ApplicationReputationService::QueryReputation(
NS_ENSURE_ARG_POINTER(aQuery);
NS_ENSURE_ARG_POINTER(aCallback);
LOG(("Sending application reputation query"));
Accumulate(mozilla::Telemetry::APPLICATION_REPUTATION_COUNT, true);
nsresult rv = QueryReputationInternal(aQuery, aCallback);
if (NS_FAILED(rv)) {

View File

@ -19,7 +19,6 @@ class nsIRequest;
class nsIUrlClassifierDBService;
class nsIScriptSecurityManager;
class PendingLookup;
class PRLogModuleInfo;
class ApplicationReputationService MOZ_FINAL :
public nsIApplicationReputationService {
@ -31,15 +30,10 @@ public:
static ApplicationReputationService* GetSingleton();
private:
friend class PendingLookup;
/**
* Global singleton object for holding this factory service.
*/
static ApplicationReputationService* gApplicationReputationService;
/**
* NSPR_LOG_MODULES=ApplicationReputation:5
*/
static PRLogModuleInfo* prlog;
/**
* Keeps track of services used to query the local database of URLs.
*/

View File

@ -2609,13 +2609,6 @@ NS_IMETHODIMP nsDownload::SetSha256Hash(const nsACString& aHash) {
return NS_OK;
}
NS_IMETHODIMP nsDownload::SetSignatureInfo(nsIArray* aSignatureInfo) {
MOZ_ASSERT(NS_IsMainThread(), "Must call SetSignatureInfo on main thread");
// This will be used later to query the application reputation service.
mSignatureInfo = aSignatureInfo;
return NS_OK;
}
#ifdef MOZ_ENABLE_GIO
static void gio_set_metadata_done(GObject *source_obj, GAsyncResult *res, gpointer user_data)
{

View File

@ -427,12 +427,6 @@ private:
*/
nsAutoCString mHash;
/**
* Stores the certificate chains in an nsIArray of nsIX509CertList of
* nsIX509Cert, if this binary is signed.
*/
nsCOMPtr<nsIArray> mSignatureInfo;
friend class nsDownloadManager;
};

View File

@ -154,12 +154,6 @@ public:
return mInner->SetSha256Hash(aHash);
}
NS_IMETHODIMP SetSignatureInfo(nsIArray* aSignatureInfo)
{
NS_ENSURE_TRUE(mInner, NS_ERROR_NOT_INITIALIZED);
return mInner->SetSignatureInfo(aSignatureInfo);
}
private:
nsCOMPtr<nsIDownload> mInner;
};

View File

@ -8,14 +8,13 @@
interface nsIApplicationReputationCallback;
interface nsIApplicationReputationQuery;
interface nsIArray;
interface nsIURI;
/*
* A service for asynchronously querying an application reputation service
* based on metadata of the downloaded file.
*/
[scriptable, uuid(c9f03479-fd68-4393-acb2-c88d4f563174)]
[scriptable, uuid(9c12a510-eb1c-11e2-a98a-fa916188709b)]
interface nsIApplicationReputationService : nsISupports {
/**
* Start querying the application reputation service.
@ -70,12 +69,6 @@ interface nsIApplicationReputationQuery : nsISupports {
* produce any useful information.
*/
readonly attribute ACString sha256Hash;
/*
* The nsIArray of nsIX509CertList of nsIX509Cert that verify for this
* binary, if it is signed.
*/
readonly attribute nsIArray signatureInfo;
};
[scriptable, function, uuid(9a228470-cfe5-11e2-8b8b-0800200c9a66)]

View File

@ -1401,12 +1401,7 @@ this.DownloadSaver.prototype = {
getSha256Hash: function ()
{
throw new Error("Not implemented.");
},
getSignatureInfo: function ()
{
throw new Error("Not implemented.");
},
}
}; // DownloadSaver
/**
@ -1465,13 +1460,6 @@ this.DownloadCopySaver.prototype = {
*/
_sha256Hash: null,
/**
* Save the signature info as an nsIArray of nsIX509CertList of nsIX509Cert
* if the file is signed. This is empty if the file is unsigned, and null
* unless BackgroundFileSaver has successfully completed saving the file.
*/
_signatureInfo: null,
/**
* True if the associated download has already been added to browsing history.
*/
@ -1548,7 +1536,6 @@ this.DownloadCopySaver.prototype = {
if (Components.isSuccessCode(aStatus)) {
// Save the hash before freeing backgroundFileSaver.
this._sha256Hash = aSaver.sha256Hash;
this._signatureInfo = aSaver.signatureInfo;
deferSaveComplete.resolve();
} else {
// Infer the origin of the error from the failure code, because
@ -1656,10 +1643,8 @@ this.DownloadCopySaver.prototype = {
}
}
// Enable hashing and signature verification before setting the
// target.
// Enable hashing before setting the target.
backgroundFileSaver.enableSha256();
backgroundFileSaver.enableSignatureInfo();
if (partFilePath) {
// If we actually resumed a request, append to the partial data.
if (resumeAttempted) {
@ -1785,14 +1770,6 @@ this.DownloadCopySaver.prototype = {
getSha256Hash: function ()
{
return this._sha256Hash;
},
/*
* Implements DownloadSaver.getSignatureInfo.
*/
getSignatureInfo: function ()
{
return this._signatureInfo;
}
};
@ -1841,13 +1818,6 @@ this.DownloadLegacySaver.prototype = {
*/
_sha256Hash: null,
/**
* Save the signature info as an nsIArray of nsIX509CertList of nsIX509Cert
* if the file is signed. This is empty if the file is unsigned, and null
* unless BackgroundFileSaver has successfully completed saving the file.
*/
_signatureInfo: null,
/**
* nsIRequest object associated to the status and progress updates we
* received. This object is null before we receive the first status and
@ -2118,25 +2088,6 @@ this.DownloadLegacySaver.prototype = {
{
this._sha256Hash = hash;
},
/**
* Implements "DownloadSaver.getSignatureInfo".
*/
getSignatureInfo: function ()
{
if (this.copySaver) {
return this.copySaver.getSignatureInfo();
}
return this._signatureInfo;
},
/**
* Called by the nsITransfer implementation when the hash is available.
*/
setSignatureInfo: function (signatureInfo)
{
this._signatureInfo = signatureInfo;
},
};
/**

View File

@ -493,23 +493,20 @@ this.DownloadIntegration = {
return Promise.resolve(this.shouldBlockInTestForApplicationReputation);
}
let hash;
let sigInfo;
try {
hash = aDownload.saver.getSha256Hash();
sigInfo = aDownload.saver.getSignatureInfo();
} catch (ex) {
// Bail if DownloadSaver doesn't have a hash.
return Promise.resolve(false);
}
if (!hash || !sigInfo) {
if (!hash) {
return Promise.resolve(false);
}
let deferred = Promise.defer();
gApplicationReputationService.queryReputation({
sourceURI: NetUtil.newURI(aDownload.source.url),
fileSize: aDownload.currentBytes,
sha256Hash: hash,
signatureInfo: sigInfo },
sha256Hash: hash },
function onComplete(aShouldBlock, aRv) {
deferred.resolve(aShouldBlock);
});

View File

@ -117,11 +117,10 @@ DownloadLegacyTransfer.prototype = {
// The last file has been received, or the download failed. Wait for the
// associated Download object to be available before notifying.
this._deferDownload.promise.then(download => {
// At this point, the hash has been set and we need to copy it to the
// DownloadSaver.
if (Components.isSuccessCode(aStatus)) {
// At this point, the hash has been set and we need to copy it to the
// DownloadSaver.
if (Components.isSuccessCode(aStatus)) {
download.saver.setSha256Hash(this._sha256Hash);
download.saver.setSignatureInfo(this._signatureInfo);
}
download.saver.onTransferFinished(aRequest, aStatus);
}).then(null, Cu.reportError);
@ -243,11 +242,6 @@ DownloadLegacyTransfer.prototype = {
this._sha256Hash = hash;
},
setSignatureInfo: function (signatureInfo)
{
this._signatureInfo = signatureInfo;
},
//////////////////////////////////////////////////////////////////////////////
//// Private methods and properties
@ -274,11 +268,6 @@ DownloadLegacyTransfer.prototype = {
* Save the SHA-256 hash in raw bytes of the downloaded file.
*/
_sha256Hash: null,
/**
* Save the signature info in a serialized protobuf of the downloaded file.
*/
_signatureInfo: null,
};
////////////////////////////////////////////////////////////////////////////////

View File

@ -53,8 +53,7 @@ MockTransfer.prototype = {
/* nsITransfer */
init: function() {},
setSha256Hash: function() {},
setSignatureInfo: function() {}
setSha256Hash: function() {}
};
// Create an instance of a MockObjectRegisterer whose methods can be used to

View File

@ -5,13 +5,12 @@
#include "nsIWebProgressListener2.idl"
interface nsIArray;
interface nsIURI;
interface nsICancelable;
interface nsIMIMEInfo;
interface nsIFile;
[scriptable, uuid(0c81b265-34b8-472d-be98-099b2512e3ec)]
[scriptable, uuid(b1c81100-9d66-11e2-9e96-0800200c9a66)]
interface nsITransfer : nsIWebProgressListener2 {
/**
@ -66,16 +65,6 @@ interface nsITransfer : nsIWebProgressListener2 {
* @param aHash The SHA-256 hash in raw bytes of the downloaded file.
*/
void setSha256Hash(in ACString aHash);
/*
* Used to notify the transfer object of the signature of the downloaded
* file. Must be called on the main thread, only after the download has
* finished successfully.
* @param aSignatureInfo The nsIArray of nsIX509CertList of nsIX509Cert
* certificates of the downloaded file.
*/
void setSignatureInfo(in nsIArray aSignatureInfo);
};
%{C++

View File

@ -1495,10 +1495,7 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
rv = mSaver->EnableSha256();
NS_ENSURE_SUCCESS(rv, rv);
rv = mSaver->EnableSignatureInfo();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Enabled hashing and signature verification"));
LOG(("Enabled hashing"));
rv = mSaver->SetTarget(mTempFile, false);
NS_ENSURE_SUCCESS(rv, rv);
@ -1938,7 +1935,6 @@ nsExternalAppHandler::OnSaveComplete(nsIBackgroundFileSaver *aSaver,
if (!mCanceled) {
// Save the hash
(void)mSaver->GetSha256Hash(mHash);
(void)mSaver->GetSignatureInfo(getter_AddRefs(mSignatureInfo));
// Free the reference that the saver keeps on us, even if we couldn't get
// the hash.
mSaver = nullptr;
@ -1972,7 +1968,6 @@ void nsExternalAppHandler::NotifyTransfer(nsresult aStatus)
if (NS_SUCCEEDED(aStatus)) {
(void)mTransfer->SetSha256Hash(mHash);
(void)mTransfer->SetSignatureInfo(mSignatureInfo);
(void)mTransfer->OnProgressChange64(nullptr, nullptr, mProgress,
mContentLength, mProgress, mContentLength);
}

View File

@ -326,12 +326,7 @@ protected:
* Stores the SHA-256 hash associated with the file that we downloaded.
*/
nsAutoCString mHash;
/**
* Stores the signature information of the downloaded file in an nsIArray of
* nsIX509CertList of nsIX509Cert. If the file is unsigned this will be
* empty.
*/
nsCOMPtr<nsIArray> mSignatureInfo;
/**
* Creates the temporary file for the download and an output stream for it.
* Upon successful return, both mTempFile and mSaver will be valid.