From b4319451b5f51eedf93a48cc56e173f95cd07e45 Mon Sep 17 00:00:00 2001 From: Kathy Brade Date: Mon, 23 Apr 2018 15:22:57 -0400 Subject: [PATCH] Bug 19121: reinstate the update.xml hash check Revert most changes from Mozilla Bug 1373267 "Remove hashFunction and hashValue attributes from nsIUpdatePatch and code related to these attributes." Changes to the tests were not reverted; the tests have been changed significantly and we do not run automated updater tests for Tor Browser at this time. --- toolkit/modules/AppConstants.jsm | 7 +++ toolkit/mozapps/update/UpdateService.jsm | 70 ++++++++++++++++++++- toolkit/mozapps/update/UpdateTelemetry.jsm | 1 + toolkit/mozapps/update/nsIUpdateService.idl | 11 ++++ 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/toolkit/modules/AppConstants.jsm b/toolkit/modules/AppConstants.jsm index 5346cac59d4ab..43ab09f8b7de0 100644 --- a/toolkit/modules/AppConstants.jsm +++ b/toolkit/modules/AppConstants.jsm @@ -194,6 +194,13 @@ this.AppConstants = Object.freeze({ false, #endif + MOZ_VERIFY_MAR_SIGNATURE: +#ifdef MOZ_VERIFY_MAR_SIGNATURE + true, +#else + false, +#endif + MOZ_MAINTENANCE_SERVICE: #ifdef MOZ_MAINTENANCE_SERVICE true, diff --git a/toolkit/mozapps/update/UpdateService.jsm b/toolkit/mozapps/update/UpdateService.jsm index ef16763092d86..8b0597ce57979 100644 --- a/toolkit/mozapps/update/UpdateService.jsm +++ b/toolkit/mozapps/update/UpdateService.jsm @@ -751,6 +751,20 @@ function LOG(string) { } } +/** + * Convert a string containing binary values to hex. + */ +function binaryToHex(input) { + var result = ""; + for (var i = 0; i < input.length; ++i) { + var hex = input.charCodeAt(i).toString(16); + if (hex.length == 1) + hex = "0" + hex; + result += hex; + } + return result; +} + /** * Gets the specified directory at the specified hierarchy under the * update root directory and creates it if it doesn't exist. @@ -1527,6 +1541,8 @@ function UpdatePatch(patch) { } break; case "finalURL": + case "hashFunction": + case "hashValue": case "state": case "type": case "URL": @@ -1546,6 +1562,8 @@ UpdatePatch.prototype = { // over writing nsIUpdatePatch attributes. _attrNames: [ "errorCode", + "hashFunction", + "hashValue", "finalURL", "selected", "size", @@ -1559,6 +1577,8 @@ UpdatePatch.prototype = { */ serialize: function UpdatePatch_serialize(updates) { var patch = updates.createElementNS(URI_UPDATE_NS, "patch"); + patch.setAttribute("hashFunction", this.hashFunction); + patch.setAttribute("hashValue", this.hashValue); patch.setAttribute("size", this.size); patch.setAttribute("type", this.type); patch.setAttribute("URL", this.URL); @@ -4383,7 +4403,49 @@ Downloader.prototype = { } LOG("Downloader:_verifyDownload downloaded size == expected size."); - return true; + + // The hash check is not necessary when mar signatures are used to verify + // the downloaded mar file. + if (AppConstants.MOZ_VERIFY_MAR_SIGNATURE) { + return true; + } + + let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fileStream.init(destination, FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); + + let digest; + try { + let hash = Cc["@mozilla.org/security/hash;1"]. + createInstance(Ci.nsICryptoHash); + var hashFunction = Ci.nsICryptoHash[this._patch.hashFunction.toUpperCase()]; + if (hashFunction == undefined) { + throw Cr.NS_ERROR_UNEXPECTED; + } + hash.init(hashFunction); + hash.updateFromStream(fileStream, -1); + // NOTE: For now, we assume that the format of _patch.hashValue is hex + // encoded binary (such as what is typically output by programs like + // sha1sum). In the future, this may change to base64 depending on how + // we choose to compute these hashes. + digest = binaryToHex(hash.finish(false)); + } catch (e) { + LOG("Downloader:_verifyDownload - failed to compute hash of the " + + "downloaded update archive"); + digest = ""; + } + + fileStream.close(); + + if (digest == this._patch.hashValue.toLowerCase()) { + LOG("Downloader:_verifyDownload hashes match."); + return true; + } + + LOG("Downloader:_verifyDownload hashes do not match. "); + AUSTLMY.pingDownloadCode(this.isCompleteUpdate, + AUSTLMY.DWNLD_ERR_VERIFY_NO_HASH_MATCH); + return false; }, /** @@ -4972,6 +5034,9 @@ Downloader.prototype = { " is higher than patch size: " + this._patch.size ); + // It's important that we use a different code than + // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference + // between a hash error and a wrong download error. AUSTLMY.pingDownloadCode( this.isCompleteUpdate, AUSTLMY.DWNLD_ERR_PATCH_SIZE_LARGER @@ -4990,6 +5055,9 @@ Downloader.prototype = { " is not equal to expected patch size: " + this._patch.size ); + // It's important that we use a different code than + // NS_ERROR_CORRUPTED_CONTENT so that tests can verify the difference + // between a hash error and a wrong download error. AUSTLMY.pingDownloadCode( this.isCompleteUpdate, AUSTLMY.DWNLD_ERR_PATCH_SIZE_NOT_EQUAL diff --git a/toolkit/mozapps/update/UpdateTelemetry.jsm b/toolkit/mozapps/update/UpdateTelemetry.jsm index d9a119c58496a..15e0354c80f1a 100644 --- a/toolkit/mozapps/update/UpdateTelemetry.jsm +++ b/toolkit/mozapps/update/UpdateTelemetry.jsm @@ -188,6 +188,7 @@ var AUSTLMY = { DWNLD_ERR_VERIFY_NO_REQUEST: 13, DWNLD_ERR_VERIFY_PATCH_SIZE_NOT_EQUAL: 14, DWNLD_ERR_WRITE_FAILURE: 15, + DWNLD_ERR_VERIFY_NO_HASH_MATCH: 16, // Temporary failure code to see if there are failures without an update phase DWNLD_UNKNOWN_PHASE_ERR_WRITE_FAILURE: 40, diff --git a/toolkit/mozapps/update/nsIUpdateService.idl b/toolkit/mozapps/update/nsIUpdateService.idl index 7f928b33b7d0a..2111c4f47744c 100644 --- a/toolkit/mozapps/update/nsIUpdateService.idl +++ b/toolkit/mozapps/update/nsIUpdateService.idl @@ -40,6 +40,17 @@ interface nsIUpdatePatch : nsISupports */ attribute AString finalURL; + /** + * The hash function to use when determining this file's integrity + */ + attribute AString hashFunction; + + /** + * The value of the hash function named above that should be computed if + * this file is not corrupt. + */ + attribute AString hashValue; + /** * The size of this file, in bytes. */ -- GitLab