Bug 928536: Integrate signature verification info into application reputation call in download manager (r=paolo)

This commit is contained in:
Monica Chew 2014-01-27 13:39:00 -08:00
parent 8a4507d7a1
commit 85de3a65ab
10 changed files with 117 additions and 11 deletions

View File

@ -7,6 +7,7 @@
#include "mozIStorageService.h"
#include "nsIAlertsService.h"
#include "nsIArray.h"
#include "nsIClassInfoImpl.h"
#include "nsIDOMWindow.h"
#include "nsIDownloadHistory.h"
@ -2609,6 +2610,13 @@ 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

@ -31,6 +31,7 @@
typedef int16_t DownloadState;
typedef int16_t DownloadType;
class nsIArray;
class nsDownload;
#ifdef DOWNLOAD_SCANNER
@ -427,6 +428,12 @@ 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,6 +154,12 @@ 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

@ -1401,7 +1401,12 @@ this.DownloadSaver.prototype = {
getSha256Hash: function ()
{
throw new Error("Not implemented.");
}
},
getSignatureInfo: function ()
{
throw new Error("Not implemented.");
},
}; // DownloadSaver
/**
@ -1460,6 +1465,13 @@ 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.
*/
@ -1536,6 +1548,7 @@ 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
@ -1643,8 +1656,10 @@ this.DownloadCopySaver.prototype = {
}
}
// Enable hashing before setting the target.
// Enable hashing and signature verification before setting the
// target.
backgroundFileSaver.enableSha256();
backgroundFileSaver.enableSignatureInfo();
if (partFilePath) {
// If we actually resumed a request, append to the partial data.
if (resumeAttempted) {
@ -1770,6 +1785,14 @@ this.DownloadCopySaver.prototype = {
getSha256Hash: function ()
{
return this._sha256Hash;
},
/*
* Implements DownloadSaver.getSignatureInfo.
*/
getSignatureInfo: function ()
{
return this._signatureInfo;
}
};
@ -1818,6 +1841,13 @@ 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
@ -2088,6 +2118,25 @@ 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,20 +493,23 @@ 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) {
if (!hash || !sigInfo) {
return Promise.resolve(false);
}
let deferred = Promise.defer();
gApplicationReputationService.queryReputation({
sourceURI: NetUtil.newURI(aDownload.source.url),
fileSize: aDownload.currentBytes,
sha256Hash: hash },
sha256Hash: hash,
signatureInfo: sigInfo },
function onComplete(aShouldBlock, aRv) {
deferred.resolve(aShouldBlock);
});

View File

@ -117,10 +117,11 @@ 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);
@ -242,6 +243,11 @@ DownloadLegacyTransfer.prototype = {
this._sha256Hash = hash;
},
setSignatureInfo: function (signatureInfo)
{
this._signatureInfo = signatureInfo;
},
//////////////////////////////////////////////////////////////////////////////
//// Private methods and properties
@ -268,6 +274,11 @@ 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,7 +53,8 @@ MockTransfer.prototype = {
/* nsITransfer */
init: function() {},
setSha256Hash: function() {}
setSha256Hash: function() {},
setSignatureInfo: function() {}
};
// Create an instance of a MockObjectRegisterer whose methods can be used to

View File

@ -5,12 +5,13 @@
#include "nsIWebProgressListener2.idl"
interface nsIArray;
interface nsIURI;
interface nsICancelable;
interface nsIMIMEInfo;
interface nsIFile;
[scriptable, uuid(b1c81100-9d66-11e2-9e96-0800200c9a66)]
[scriptable, uuid(0c81b265-34b8-472d-be98-099b2512e3ec)]
interface nsITransfer : nsIWebProgressListener2 {
/**
@ -65,6 +66,16 @@ 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,7 +1495,10 @@ nsresult nsExternalAppHandler::SetUpTempFile(nsIChannel * aChannel)
rv = mSaver->EnableSha256();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Enabled hashing"));
rv = mSaver->EnableSignatureInfo();
NS_ENSURE_SUCCESS(rv, rv);
LOG(("Enabled hashing and signature verification"));
rv = mSaver->SetTarget(mTempFile, false);
NS_ENSURE_SUCCESS(rv, rv);
@ -1935,6 +1938,7 @@ 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;
@ -1968,6 +1972,7 @@ 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,7 +326,12 @@ 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.