diff options
author | Patrick Brunschwig <[email protected]> | 2021-12-29 14:51:10 +0100 |
---|---|---|
committer | Patrick Brunschwig <[email protected]> | 2021-12-29 14:51:10 +0100 |
commit | fab67aebb6789f150b5542217658d8423a2995a7 (patch) | |
tree | cf27c1a8b66a33ed9c7de16dc17350a4703447d4 | |
parent | f4337d9f1d5207f831118cfbfabab5910db44ac7 (diff) | |
download | enigmail-fab67aebb6789f150b5542217658d8423a2995a7.tar.gz enigmail-fab67aebb6789f150b5542217658d8423a2995a7.tar.bz2 enigmail-fab67aebb6789f150b5542217658d8423a2995a7.zip |
moved decryption funtion into a worker
-rw-r--r-- | package/Makefile | 14 | ||||
-rw-r--r-- | package/armor.jsm | 35 | ||||
-rw-r--r-- | package/cryptoAPI/Makefile | 11 | ||||
-rw-r--r-- | package/cryptoAPI/openpgp-js.js | 16 | ||||
-rw-r--r-- | package/cryptoAPI/pgpjs-crypto-main.jsm | 302 | ||||
-rw-r--r-- | package/cryptoAPI/pgpjs-crypto-worker.js (renamed from package/cryptoAPI/pgpjs-decrypt.jsm) | 502 | ||||
-rw-r--r-- | package/tests/main.js | 2 | ||||
-rw-r--r-- | package/tests/pgpjs-crypto-test.js (renamed from package/tests/pgpjs-decrypt-test.js) | 33 | ||||
-rw-r--r-- | package/tests/testHelper.js | 2 | ||||
-rw-r--r-- | ui/content/enigmailMessengerOverlay.js | 1 | ||||
-rwxr-xr-x | util/genxpi | 3 |
11 files changed, 732 insertions, 189 deletions
diff --git a/package/Makefile b/package/Makefile index 2c2fb86c..7653b6c5 100644 --- a/package/Makefile +++ b/package/Makefile @@ -17,7 +17,6 @@ MODFILES = \ addrbook.jsm \ amPrefsService.jsm \ app.jsm \ - armor.jsm \ attachment.jsm \ autocrypt.jsm \ autoSetup.jsm \ @@ -26,7 +25,6 @@ MODFILES = \ commandLine.jsm \ configBackup.jsm \ configure.jsm \ - constants.jsm \ core.jsm \ cryptoAPI.jsm \ data.jsm \ @@ -98,6 +96,10 @@ MODFILES = \ xhrUtils.jsm \ zbase32.jsm +COPYFILES = \ + armor.jsm \ + constants.jsm + DATE_FMT = +%Y%m%d-%H%M SOURCE_DATE_EPOCH ?= $(shell date +%s) @@ -112,11 +114,14 @@ GENFILES = $(addprefix $(GENDIR)/,$(MODFILES)) $(GENDIR)/%.jsm: %.jsm $(DEPTH)/util/prepPostbox $(TARGET_TOOL) $< [email protected] -all: dirs build deploy +all: dirs build copyfiles deploy build: $(GENFILES) -deploy: $(PREFFILES) +copyfiles: $(COPYFILES) + $(DEPTH)/util/install -m 644 $(DIST)/chrome/content/modules $(COPYFILES) + +deploy: $(PREFFILES) $(DEPTH)/util/install -m 644 $(DIST)/chrome/content/preferences $(PREFFILES) $(DEPTH)/util/install -m 644 $(DIST) enigmail-startup.js echo '"use strict";' > $(DIST)/chrome/content/modules/buildDate.jsm @@ -129,6 +134,7 @@ deploy: $(PREFFILES) clean: $(DEPTH)/util/install -u $(DIST)/chrome/content/preferences $(PREFFILES) $(DEPTH)/util/install -u $(DIST)/chrome/content/modules $(MODFILES) + $(DEPTH)/util/install -u $(DIST)/chrome/content/modules $(COPYFILES) $(DEPTH)/util/install -u $(DIST) bootstrap.js manifest.json install.rdf chrome.manifest .PHONY: dirs $(DIRS) diff --git a/package/armor.jsm b/package/armor.jsm index d7765b3b..722d8060 100644 --- a/package/armor.jsm +++ b/package/armor.jsm @@ -9,8 +9,14 @@ var EXPORTED_SYMBOLS = ["EnigmailArmor"]; -const EnigmailConstants = ChromeUtils.import("chrome://enigmail/content/modules/constants.jsm").EnigmailConstants; -const EnigmailLog = ChromeUtils.import("chrome://enigmail/content/modules/log.jsm").EnigmailLog; +//const EnigmailConstants = ChromeUtils.import("chrome://enigmail/content/modules/constants.jsm").EnigmailConstants; +//const EnigmailLog = ChromeUtils.import("chrome://enigmail/content/modules/log.jsm").EnigmailLog; + +const ArmorConstants = { + SIGNATURE_TEXT: 1, + SIGNATURE_HEADERS: 2, + SIGNATURE_ARMOR: 3 +}; // Locates STRing in TEXT occurring only at the beginning of a line @@ -34,7 +40,8 @@ function searchBlankLine(str, then) { var offset = str.search(/\n\s*\r?\n/); if (offset === -1) { return ""; - } else { + } + else { return then(offset); } } @@ -43,7 +50,8 @@ function indexOfNewline(str, off, then) { var offset = str.indexOf("\n", off); if (offset === -1) { return ""; - } else { + } + else { return then(offset); } } @@ -64,7 +72,7 @@ var EnigmailArmor = { * If no block is found, an empty String is returned; */ locateArmoredBlock: function(text, offset, indentStr, beginIndexObj, endIndexObj, indentStrObj) { - EnigmailLog.DEBUG("armor.jsm: Enigmail.locateArmoredBlock: " + offset + ", '" + indentStr + "'\n"); + // EnigmailLog.DEBUG("armor.jsm: Enigmail.locateArmoredBlock: " + offset + ", '" + indentStr + "'\n"); beginIndexObj.value = -1; endIndexObj.value = -1; @@ -113,7 +121,7 @@ var EnigmailArmor = { var blockType = ""; if (matches && (matches.length > 1)) { blockType = matches[1]; - EnigmailLog.DEBUG("armor.jsm: Enigmail.locateArmoredBlock: blockType=" + blockType + "\n"); + // EnigmailLog.DEBUG("armor.jsm: Enigmail.locateArmoredBlock: blockType=" + blockType + "\n"); } if (blockType == "UNVERIFIED MESSAGE") { @@ -159,12 +167,12 @@ var EnigmailArmor = { i = endObj.value; } - EnigmailLog.DEBUG("armor.jsm: locateArmorBlocks: Found " + blocks.length + " Blocks\n"); + // EnigmailLog.DEBUG("armor.jsm: locateArmorBlocks: Found " + blocks.length + " Blocks\n"); return blocks; }, extractSignaturePart: function(signatureBlock, part) { - EnigmailLog.DEBUG("armor.jsm: Enigmail.extractSignaturePart: part=" + part + "\n"); + // EnigmailLog.DEBUG("armor.jsm: Enigmail.extractSignaturePart: part=" + part + "\n"); return searchBlankLine(signatureBlock, function(offset) { return indexOfNewline(signatureBlock, offset + 1, function(offset) { @@ -173,7 +181,7 @@ var EnigmailArmor = { return ""; } - if (part === EnigmailConstants.SIGNATURE_TEXT) { + if (part === ArmorConstants.SIGNATURE_TEXT) { return signatureBlock.substr(offset + 1, beginIndex - offset - 1). replace(/^- -/, "-"). replace(/\n- -/g, "\n-"). @@ -189,15 +197,16 @@ var EnigmailArmor = { var signBlock = signatureBlock.substr(offset, endIndex - offset); return searchBlankLine(signBlock, function(armorIndex) { - if (part == EnigmailConstants.SIGNATURE_HEADERS) { + if (part == ArmorConstants.SIGNATURE_HEADERS) { return signBlock.substr(1, armorIndex); } return indexOfNewline(signBlock, armorIndex + 1, function(armorIndex) { - if (part == EnigmailConstants.SIGNATURE_ARMOR) { + if (part == ArmorConstants.SIGNATURE_ARMOR) { return signBlock.substr(armorIndex, endIndex - armorIndex). replace(/\s*/g, ""); - } else { + } + else { return ""; } }); @@ -291,4 +300,4 @@ var EnigmailArmor = { return retArr; } -};
\ No newline at end of file +}; diff --git a/package/cryptoAPI/Makefile b/package/cryptoAPI/Makefile index 31c73032..f741b4ab 100644 --- a/package/cryptoAPI/Makefile +++ b/package/cryptoAPI/Makefile @@ -13,13 +13,16 @@ MODFILES = \ gnupg-keyEditor.jsm \ gpgme.js \ openpgp-js.js \ + pgpjs-crypto-main.jsm \ pgpjs-encrypt.jsm \ - pgpjs-decrypt.jsm \ pgpjs-keys.jsm \ pgpjs-keystore.jsm \ pgpjs-keymanipulation.jsm \ interface.js +WORKERS = \ + pgpjs-crypto-worker.js + GENFILES = $(addprefix $(GENDIR)/,$(MODFILES)) $(GENDIR)/%.jsm: %.jsm @@ -28,9 +31,13 @@ $(GENDIR)/%.jsm: %.jsm $(GENDIR)/%.js: %.js $(DEPTH)/util/prepPostbox $(TARGET_TOOL) $< [email protected] -build: $(GENFILES) +build: $(GENFILES) deploy + +deploy: + $(DEPTH)/util/install -m 644 $(GENDIR) $(WORKERS) all: build clean: $(DEPTH)/util/install -u $(DIST)/chrome/content/modules/cryptoAPI $(MODFILES) + $(DEPTH)/util/install -u $(DIST)/chrome/content/modules/cryptoAPI $(WORKERS) diff --git a/package/cryptoAPI/openpgp-js.js b/package/cryptoAPI/openpgp-js.js index 0a64e8ee..a4518d1c 100644 --- a/package/cryptoAPI/openpgp-js.js +++ b/package/cryptoAPI/openpgp-js.js @@ -14,7 +14,7 @@ var Services = ChromeUtils.import("resource://gre/modules/Services.jsm").Service const pgpjs_keys = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keys.jsm").pgpjs_keys; const pgpjs_keyStore = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keystore.jsm").pgpjs_keyStore; const pgpjs_encrypt = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-encrypt.jsm").pgpjs_encrypt; -const pgpjs_decrypt = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-decrypt.jsm").pgpjs_decrypt; +const pgpjs_crypto = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-crypto-main.jsm").pgpjs_crypto; const pgpjs_keymanipulation = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keymanipulation.jsm").pgpjs_keymanipulation; const EnigmailLazy = ChromeUtils.import("chrome://enigmail/content/modules/lazy.jsm").EnigmailLazy; const EnigmailLog = ChromeUtils.import("chrome://enigmail/content/modules/log.jsm").EnigmailLog; @@ -382,7 +382,7 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { async getFileName(byteData) { let fn = null; try { - let msg = await pgpjs_decrypt.processPgpMessage(byteData, {}); + let msg = await pgpjs_crypto.processPgpMessage(byteData, {}); fn = msg.encryptedFileName; } catch (x) {} @@ -404,7 +404,7 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { */ async verifyAttachment(filePath, sigPath) { - return pgpjs_decrypt.verifyFile(filePath, sigPath); + return pgpjs_crypto.verifyFile(filePath, sigPath); } /** @@ -420,7 +420,7 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { */ async decryptAttachment(encrypted) { - let ret = await pgpjs_decrypt.processPgpMessage(encrypted, {}); + let ret = await pgpjs_crypto.processPgpMessage(encrypted, {}); if ("decryptedData" in ret) { ret.stdoutData = ret.decryptedData; @@ -446,10 +446,10 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { EnigmailLog.DEBUG(`openpgpg-js.js: decrypt()\n`); if (options.verifyOnly) { - return pgpjs_decrypt.verify(pgpMessage, options); + return pgpjs_crypto.verify(pgpMessage, options); } else { - return pgpjs_decrypt.processPgpMessage(pgpMessage, options); + return pgpjs_crypto.processPgpMessage(pgpMessage, options); } } @@ -471,7 +471,7 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { options.verifyOnly = false; options.uiFlags = EnigmailConstants.UI_PGP_MIME; - return pgpjs_decrypt.processPgpMessage(encrypted, options); + return pgpjs_crypto.processPgpMessage(encrypted, options); } /** @@ -489,7 +489,7 @@ class OpenPGPjsCryptoAPI extends CryptoAPI { */ async verifyMime(signedData, signature, options) { - return pgpjs_decrypt.verifyDetached(signedData, signature); + return pgpjs_crypto.verifyDetached(signedData, signature); } diff --git a/package/cryptoAPI/pgpjs-crypto-main.jsm b/package/cryptoAPI/pgpjs-crypto-main.jsm new file mode 100644 index 00000000..2ade0037 --- /dev/null +++ b/package/cryptoAPI/pgpjs-crypto-main.jsm @@ -0,0 +1,302 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +"use strict"; + +const Services = ChromeUtils.import("resource://gre/modules/Services.jsm").Services; +const EnigmailLog = ChromeUtils.import("chrome://enigmail/content/modules/log.jsm").EnigmailLog; +const EnigmailPrefs = ChromeUtils.import("chrome://enigmail/content/modules/prefs.jsm").EnigmailPrefs; +const EnigmailFiles = ChromeUtils.import("chrome://enigmail/content/modules/files.jsm").EnigmailFiles; +const EnigmailArmor = ChromeUtils.import("chrome://enigmail/content/modules/armor.jsm").EnigmailArmor; +const EnigmailLocale = ChromeUtils.import("chrome://enigmail/content/modules/locale.jsm").EnigmailLocale; +const EnigmailTime = ChromeUtils.import("chrome://enigmail/content/modules/time.jsm").EnigmailTime; +const EnigmailConstants = ChromeUtils.import("chrome://enigmail/content/modules/constants.jsm").EnigmailConstants; +const pgpjs_keys = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keys.jsm").pgpjs_keys; +const pgpjs_keyStore = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keystore.jsm").pgpjs_keyStore; +const getOpenPGPLibrary = ChromeUtils.import("chrome://enigmail/content/modules/stdlib/openpgp-loader.jsm").getOpenPGPLibrary; + +var EXPORTED_SYMBOLS = ["pgpjs_crypto"]; + +var pgpjs_crypto = { + /** + * Process an OpenPGP message + * + * @param {String} encrypted The encrypted data + * @param {Object} options Decryption options + * + * @return {Promise<Object>} - Return object with decryptedData and status information: + * - {String} decryptedData + * - {Number} exitCode + * - {Number} statusFlags + * - {String} errorMsg + * - {String} blockSeparation + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + processPgpMessage: async function(encrypted, options) { + EnigmailLog.DEBUG(`pgpjs-crypro-main.jsm: processPgpMessage(${encrypted.length})\n`); + + let result; + try { + result = await PgpJsWorkerParent.sendMessage("processPgpMessage", { + encrypted, + options + }); + } + catch (ex) { + EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: processPgpMessage: ERROR: ${ex.toString()}\n`); + result.errorMsg = ex.toString(); + result.exitCode = 1; + } + + return result; + }, + + verify: async function(data, options) { + EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verify(${data.length})\n`); + + let result = {}; + + let blocks = EnigmailArmor.locateArmoredBlocks(data); + + result.statusFlags = 0; + result.exitCode = 1; + + try { + if (blocks && blocks.length > 0) { + if (blocks[0].blocktype === "SIGNED MESSAGE") { + result = await PgpJsWorkerParent.sendMessage("verify", { + data: data.substring(blocks[0].begin, blocks[0].end), + options + }); + } + } + } + catch (ex) { + EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verify: ERROR: ${ex.toString()}\n`); + result.errorMsg = ex.toString(); + result.statusFlags = EnigmailConstants.UNVERIFIED_SIGNATURE; + } + return result; + }, + + verifyDetached: async function(data, signature, returnData = false) { + EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verifyDetached(${data.length})\n`); + + let result = await PgpJsWorkerParent.sendMessage("verifyDetached", { + data, + signature, + returnData + }); + return result; + }, + + + verifyFile: async function(dataFilePath, signatureFilePath) { + const PgpJS = getOpenPGPLibrary(); + + let dataFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + let sigFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); + EnigmailFiles.initPath(dataFile, dataFilePath); + EnigmailFiles.initPath(sigFile, signatureFilePath); + + if (!dataFile.exists()) { + throw new Error(`Data file ${dataFilePath} does not exist`); + } + if (!sigFile.exists()) { + throw new Error(`Signature file ${signatureFilePath} does not exist`); + } + + let data = EnigmailFiles.readBinaryFile(dataFile); + let sig = EnigmailFiles.readBinaryFile(sigFile); + + if (sig.search(/^-----BEGIN PGP/m) < 0) { + let msg = await PgpJS.signature.read(ensureUint8Array(sig)); + sig = msg.armor(); + } + + let ret = await this.verifyDetached(data, sig, false); + + if (ret.statusFlags & (EnigmailConstants.BAD_SIGNATURE | EnigmailConstants.UNVERIFIED_SIGNATURE)) { + throw ret.errorMsg ? ret.errorMsg : EnigmailLocale.getString("unverifiedSig") + " - " + EnigmailLocale.getString("msgSignedUnkownKey"); + } + + const detailArr = ret.sigDetails.split(/ /); + const dateTime = EnigmailTime.getDateTime(detailArr[2], true, true); + return ret.errorMsg + "\n" + EnigmailLocale.getString("keyAndSigDate", [ret.keyId, dateTime]); + } +}; + +function ensureUint8Array(stringOrUint8Array) { + if (typeof stringOrUint8Array === "string") { + + const result = new Uint8Array(stringOrUint8Array.length); + for (let i = 0; i < stringOrUint8Array.length; i++) { + result[i] = stringOrUint8Array.charCodeAt(i); + } + return result; + + } + + return stringOrUint8Array; +} + + +/** + * Callback functions called from worker for tasks requiring chrome + */ + +var WorkerRequestHandler = { + /** + * Get secret keys as armored string + * + * @param {Array<String>} keyIds + * @returns {String} + */ + getSecretKeysForIds: async function(keyIds) { + EnigmailLog.DEBUG(`pgpjs-crypto-main.jsm: getSecretKeysForIds()\n`); + let secretKeys = await pgpjs_keyStore.readSecretKeys(keyIds, false); + + return secretKeys; + }, + + getPublicKeysForIds: async function(keyIds) { + EnigmailLog.DEBUG(`pgpjs-crypto-main.jsm: getPublicKeysForIds()\n`); + let publicKeys = await pgpjs_keyStore.readPublicKeys(keyIds); + + return publicKeys; + }, + + getDecryptedSecretKey: async function(options) { + EnigmailLog.DEBUG(`pgpjs-crypto-main.jsm: getDecryptedSecretKey()\n`); + const PgpJS = getOpenPGPLibrary(); + + let secretKey = await pgpjs_keyStore.getKeysForKeyIds(true, [options.secretKeyFpr], false); + let dedryptedSecKey = await pgpjs_keys.decryptSecretKey(secretKey[0], options.decryptionReason); + let packets = new PgpJS.PacketList(); + + // remove all 3rd-party signatures that just grow the key + for (let u in dedryptedSecKey.users) { + dedryptedSecKey.users[u].otherCertifications = []; + } + + if (dedryptedSecKey) { + packets = packets.concat(await dedryptedSecKey.toPacketList()); + return PgpJS.armor(PgpJS.enums.armor.privateKey, packets.write()); + } + + return null; + }, + + downloadMissingKeys: async function(keyIds) { + EnigmailLog.DEBUG(`pgpjs-crypto-main.jsm: downloadMissingKeys()\n`); + + const EnigmailKeyServer = ChromeUtils.import("chrome://enigmail/content/modules/keyserver.jsm").EnigmailKeyServer; + const PgpJS = getOpenPGPLibrary(); + let packets = new PgpJS.PacketList(); + + try { + const keyserver = EnigmailPrefs.getAutoKeyRetrieveServer(); + + if (keyserver && keyserver.length > 0) { + const keyList = "0x" + keyIds.join(" 0x"); + const ret = await EnigmailKeyServer.download(keyList, keyserver); + + if (ret.result === 0 && ret.keyList.length > 0) { + let foundKeys = await pgpjs_keyStore.getKeysForKeyIds(false, keyIds); + packets = packets.concat(await foundKeys.toPacketList()); + } + } + } + catch (x) {} + + return PgpJS.armor(PgpJS.enums.armor.publicKey, packets.write()); + } + +}; + +var pendingPromises = []; +var gTransactionId = 0; + +const cryptoWorker = new Worker('chrome://enigmail/content/modules/cryptoAPI/pgpjs-crypto-worker.js'); + +cryptoWorker.onmessage = async function(e) { + if ("logMessage" in e.data) { + if (e.data.logLevel >= 5) { + EnigmailLog.DEBUG(`${e.data.logMessage}\n`); + } + else if (e.data.logLevel === 0) { + EnigmailLog.ERROR(`${e.data.logMessage}\n`); + } + return; + } + + if (!("trxId" in e.data)) { + EnigmailLog.ERROR(`pgpjs-crypto-worker.jsm. onmessage: cannot deliver message received from worker ${e.data}\n`); + } + + if ("func" in e.data) { + let method = e.data.func; + let args = e.data.param || null; + + if (method in WorkerRequestHandler) { + try { + let workerResult = await WorkerRequestHandler[method](args); + cryptoWorker.postMessage({ + trxId: e.data.trxId, + result: workerResult + }); + } + catch (ex) { + cryptoWorker.postMessage({ + trxId: e.data.trxId, + error: `${ex.toString()}\n${ex.stack}` + }); + } + } + else { + EnigmailLog.ERROR(`pgpjs-crypto-worker.jsm. onmessage: Unknown function call ${e.data.func} received from worker\n`); + } + return; + } + + if (pendingPromises[e.data.trxId]) { + if ("result" in e.data) { + pendingPromises[e.data.trxId].resolve(e.data.result); + } + else { + EnigmailLog.ERROR(`${e.data.error}\n`); + pendingPromises[e.data.trxId].reject(e.data.error); + } + delete pendingPromises[e.data.trxId]; + } +}; + +cryptoWorker.onerror = function(e) { + EnigmailLog.ERROR(`pgpjs-crypto-worker.jsm. onerror: Error received from worker: ${e.message}\n`); +}; + + +const PgpJsWorkerParent = { + + sendMessage(functionName, param, transferables) { + let trxId = ++gTransactionId; + return new Promise((resolve, reject) => { + cryptoWorker.postMessage({ + func: functionName, + trxId: trxId, + param: param + }, transferables); + + pendingPromises[trxId] = { + resolve, + reject + }; + }); + } +}; diff --git a/package/cryptoAPI/pgpjs-decrypt.jsm b/package/cryptoAPI/pgpjs-crypto-worker.js index 4aad37a2..b11ffbc7 100644 --- a/package/cryptoAPI/pgpjs-decrypt.jsm +++ b/package/cryptoAPI/pgpjs-crypto-worker.js @@ -7,26 +7,17 @@ "use strict"; -var EXPORTED_SYMBOLS = ["pgpjs_decrypt"]; - - -var Services = ChromeUtils.import("resource://gre/modules/Services.jsm").Services; -const EnigmailLog = ChromeUtils.import("chrome://enigmail/content/modules/log.jsm").EnigmailLog; -const EnigmailLazy = ChromeUtils.import("chrome://enigmail/content/modules/lazy.jsm").EnigmailLazy; -const getOpenPGPLibrary = ChromeUtils.import("chrome://enigmail/content/modules/stdlib/openpgp-loader.jsm").getOpenPGPLibrary; -const EnigmailTime = ChromeUtils.import("chrome://enigmail/content/modules/time.jsm").EnigmailTime; -const EnigmailFuncs = ChromeUtils.import("chrome://enigmail/content/modules/funcs.jsm").EnigmailFuncs; -const EnigmailData = ChromeUtils.import("chrome://enigmail/content/modules/data.jsm").EnigmailData; -const EnigmailFiles = ChromeUtils.import("chrome://enigmail/content/modules/files.jsm").EnigmailFiles; -const EnigmailConstants = ChromeUtils.import("chrome://enigmail/content/modules/constants.jsm").EnigmailConstants; -const getOpenPGP = EnigmailLazy.loader("enigmail/openpgp.jsm", "EnigmailOpenPGP"); -const getArmor = EnigmailLazy.loader("enigmail/armor.jsm", "EnigmailArmor"); -const pgpjs_keys = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keys.jsm").pgpjs_keys; -const pgpjs_keyStore = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keystore.jsm").pgpjs_keyStore; -const EnigmailLocale = ChromeUtils.import("chrome://enigmail/content/modules/locale.jsm").EnigmailLocale; -const EnigmailPrefs = ChromeUtils.import("chrome://enigmail/content/modules/prefs.jsm").EnigmailPrefs; - -Components.utils.importGlobalProperties(["TextDecoder"]); +/** + * Load OpenPGP.js libray + */ + +/* global importScripts: false, EnigmailConstants: false, EnigmailArmor: false */ + +importScripts('chrome://enigmail/content/modules/stdlib/openpgp-lib.js'); +importScripts('chrome://enigmail/content/modules/armor.jsm'); +importScripts('chrome://enigmail/content/modules/constants.jsm'); + +const PgpJS = self.openpgp; /** * OpenPGP.js implementation of CryptoAPI @@ -34,7 +25,7 @@ Components.utils.importGlobalProperties(["TextDecoder"]); * Decryption-related functions */ -var pgpjs_decrypt = { +var workerBody = { /** * Process an OpenPGP message * @@ -52,10 +43,12 @@ var pgpjs_decrypt = { * retObj.errorMsg will be an error message in this case. */ - processPgpMessage: async function(encrypted, options) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: processPgpMessage(${encrypted.length})\n`); + processPgpMessage: async function({ + encrypted, + options + }) { + DEBUG_LOG(`processPgpMessage(${encrypted.length})\n`); - const PgpJS = getOpenPGPLibrary(); const retData = getReturnObj(); try { @@ -90,7 +83,7 @@ var pgpjs_decrypt = { idx = message.packets.indexOfTag(PgpJS.enums.packet.literalData); if (idx.length > 0 && idx[0] === 0) { let litDataArr = message.getLiteralData(); - retData.decryptedData += EnigmailData.arrayBufferToString(litDataArr); + retData.decryptedData += arrayBufferToString(litDataArr); retData.statusFlags = 0; return retData; } @@ -98,7 +91,7 @@ var pgpjs_decrypt = { return this.decryptMessage(message, pubKeyIds, options); } catch (ex) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: processPgpMessage: ERROR: ${ex.toString()}\n`); + DEBUG_LOG(`processPgpMessage: ERROR: ${ex.toString()}\n${ex.stack}\n${encrypted}\n`); retData.errorMsg = ex.toString(); retData.exitCode = 1; } @@ -106,10 +99,10 @@ var pgpjs_decrypt = { return retData; }, + decryptMessage: async function(message, pubKeyIds, options) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: decryptMessage(${pubKeyIds.join(", ")})\n`); + DEBUG_LOG(`decryptMessage(${pubKeyIds.join(", ")})\n`); - const PgpJS = getOpenPGPLibrary(); const retData = getReturnObj(); let encToDetails = ""; @@ -117,17 +110,29 @@ var pgpjs_decrypt = { encToDetails = getKeydesc(pubKeyIds); // get OpenPGP.js key objects for secret keys - let secretKeys = await pgpjs_keyStore.getKeysForKeyIds(true, pubKeyIds.length === 0 ? null : pubKeyIds); + let armoredSecretKeys = await requestMessage("getSecretKeysForIds", pubKeyIds); + + let secretKeys = await PgpJS.readKeys({ + armoredKeys: armoredSecretKeys + }); if (secretKeys.length === 0) { retData.statusFlags |= EnigmailConstants.NO_SECKEY; } // try to decrypt the message using the secret keys one-by-one - for (let secKey of secretKeys) { - secKey.revocationSignatures = []; // remove revocation sigs to allow decryption - secKey = await pgpjs_keys.decryptSecretKey(secKey, EnigmailConstants.KEY_DECRYPT_REASON_ENCRYPTED_MSG); + for (let sk of secretKeys) { + let decryptedSecKey = await requestMessage("getDecryptedSecretKey", { + secretKeyFpr: sk.getFingerprint().toUpperCase(), + decryptionReason: EnigmailConstants.KEY_DECRYPT_REASON_ENCRYPTED_MSG + }); + + let secKey = await PgpJS.readKeys({ + armoredKeys: decryptedSecKey + }); + if (secKey) { + secKey.revocationSignatures = []; // remove revocation sigs to allow decryption let result = await PgpJS.decrypt({ message: message, format: "binary", @@ -153,7 +158,10 @@ var pgpjs_decrypt = { pkt = pkt.concat(sigPackets.packets); } - verifiation = await this.verifyDetached(result.data, pkt); + verifiation = await this.verifyDetached({ + data: result.data, + signature: pkt + }); if (verifiation.exitCode !== 2) { retData.statusFlags += verifiation.statusFlags; @@ -172,7 +180,7 @@ var pgpjs_decrypt = { break; } else { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: decrypt invalid or no passphrase supplied\n`); + DEBUG_LOG(`decrypt invalid or no passphrase supplied\n`); retData.statusFlags |= EnigmailConstants.BAD_PASSPHRASE; } } @@ -180,10 +188,10 @@ var pgpjs_decrypt = { catch (ex) { if (("message" in ex) && ex.message.search(/(Message .*not authenticated|missing MDC|Modification detected)/) > 0) { retData.statusFlags |= EnigmailConstants.MISSING_MDC; - retData.statusMsg = EnigmailLocale.getString("missingMdcError") + "\n"; + retData.statusMsg = "MDC ERROR\n"; // FIXME: EnigmailLocale.getString("missingMdcError") + "\n"; } else { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: decryptMessage: ERROR: ${ex.toString()}\n`); + DEBUG_LOG(`decryptMessage: ERROR: ${ex.toString()}\n`); retData.exitCode = 1; retData.errorMsg = ex.toString(); } @@ -193,37 +201,38 @@ var pgpjs_decrypt = { return retData; }, - verify: async function(data, options) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verify(${data.length})\n`); + verify: async function({ + data, + options + }) { + DEBUG_LOG(`verify(${data.length})\n`); - const PgpJS = getOpenPGPLibrary(); let result = getReturnObj(); - const Armor = getArmor(); - let blocks = Armor.locateArmoredBlocks(data); result.statusFlags = 0; result.exitCode = 1; try { - if (blocks && blocks.length > 0) { - if (blocks[0].blocktype === "SIGNED MESSAGE") { - let msg = await PgpJS.readCleartextMessage({ - cleartextMessage: data.substring(blocks[0].begin, blocks[0].end) - }); + let msg = await PgpJS.readCleartextMessage({ + cleartextMessage: data + }); - let binaryData = extractDataFromClearsignedMsg(data.substring(blocks[0].begin, blocks[0].end)); + let binaryData = extractDataFromClearsignedMsg(data); - if (msg && "signature" in msg) { - result = await this.verifyDetached(binaryData, msg.signature.armor(), true); - } - } + if (msg && "signature" in msg) { + result = await this.verifyDetached({ + data: binaryData, + signature: msg.signature.armor(), + returnData: true + }); } } catch (ex) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verify: ERROR: ${ex.toString()}\n`); + DEBUG_LOG(`verify: ERROR: ${ex.toString()}\n`); result.errorMsg = ex.toString(); result.statusFlags = EnigmailConstants.UNVERIFIED_SIGNATURE; } + return result; }, @@ -236,18 +245,21 @@ var pgpjs_decrypt = { * * @return {Promise<Object>}: ResultObj */ - verifyDetached: async function(data, signature, returnData = false) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verifyDetached(${data.length})\n`); - const PgpJS = getOpenPGPLibrary(); + verifyDetached: async function({ + data, + signature, + returnData = false + }) { + DEBUG_LOG(`verifyDetached(${data}, ${signature})\n`); - //let result = getReturnObj(); let sigString; if (typeof(signature) === "string") { sigString = signature; } - else - sigString = PgpJS.armor(PgpJS.enums.armor.signature, signature.write()); + else { + sigString = await PgpJS.armor(PgpJS.enums.armor.signature, signature.write()); + } // if (sigString.packets.length === 0) { // result.exitCode = 1; @@ -282,8 +294,7 @@ var pgpjs_decrypt = { * @return {Promise<Object>} ResultObj */ verifyMessage: async function(messageObj, returnData = false) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verifyMessage()\n`); - const PgpJS = getOpenPGPLibrary(); + DEBUG_LOG(`verifyMessage()\n`); const SIG_STATUS = { unknown_key: 0, bad_signature: 1, @@ -310,12 +321,16 @@ var pgpjs_decrypt = { return keyId.toHex().toUpperCase(); }); - let pubKeys = await pgpjs_keyStore.getKeysForKeyIds(false, keyIds, true); + let armoredPubKeys = await requestMessage("getPublicKeysForIds", keyIds); - if (pubKeys.length === 0) { - pubKeys = await downloadMissingKeys(keyIds); + if (armoredPubKeys.length === 0) { + armoredPubKeys = await requestMessage("downloadMissingKeys", keyIds); } + let pubKeys = await PgpJS.readKeys({ + armoredKeys: armoredPubKeys + }); + for (let key of pubKeys) { if (await key.isRevoked()) { // remove revocation signatures to get a valid key (required for verification) @@ -357,7 +372,7 @@ var pgpjs_decrypt = { currentKey = k; break; } - else { + else if ("subKeys" in k) { for (let sk of k.subKeys) { if (sk.getKeyID().toHex() === keyId) { currentKey = k; @@ -381,7 +396,7 @@ var pgpjs_decrypt = { currentStatus = SIG_STATUS.bad_signature; } else { - let keyStatus = await pgpjs_keyStore.getKeyStatusCode(currentKey); + let keyStatus = await getKeyStatusCode(currentKey); if (currentKey._enigmailRevoked) keyStatus = "r"; @@ -453,50 +468,17 @@ var pgpjs_decrypt = { } if (result.statusFlags & EnigmailConstants.GOOD_SIGNATURE) { - result.errorMsg = EnigmailLocale.getString("prefGood", [result.userId]); + result.errorMsg = `Good signature from ${result.userId}`; // FIXME: EnigmailLocale.getString("prefGood", [result.userId]); } else if (result.statusFlags & EnigmailConstants.BAD_SIGNATURE) { - result.errorMsg = EnigmailLocale.getString("prefBad", [result.userId]); + result.errorMsg = `Invalid signature from ${result.userId}`; // FIXME: EnigmailLocale.getString("prefBad", [result.userId]); } } catch (ex) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: verifyMessage: ERROR: ${ex.toString()} ${ex.stack}\n`); + DEBUG_LOG(`verifyMessage: ERROR: ${ex.toString()} ${ex.stack}\n`); } return result; - }, - - verifyFile: async function(dataFilePath, signatureFilePath) { - const PgpJS = getOpenPGPLibrary(); - let dataFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - let sigFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile); - EnigmailFiles.initPath(dataFile, dataFilePath); - EnigmailFiles.initPath(sigFile, signatureFilePath); - - if (!dataFile.exists()) { - throw new Error(`Data file ${dataFilePath} does not exist`); - } - if (!sigFile.exists()) { - throw new Error(`Signature file ${signatureFilePath} does not exist`); - } - - let data = EnigmailFiles.readBinaryFile(dataFile); - let sig = EnigmailFiles.readBinaryFile(sigFile); - - if (sig.search(/^-----BEGIN PGP/m) < 0) { - let msg = await PgpJS.signature.read(ensureUint8Array(sig)); - sig = msg.armor(); - } - - let ret = await this.verifyDetached(data, sig, false); - - if (ret.statusFlags & (EnigmailConstants.BAD_SIGNATURE | EnigmailConstants.UNVERIFIED_SIGNATURE)) { - throw ret.errorMsg ? ret.errorMsg : EnigmailLocale.getString("unverifiedSig") + " - " + EnigmailLocale.getString("msgSignedUnkownKey"); - } - - const detailArr = ret.sigDetails.split(/ /); - const dateTime = EnigmailTime.getDateTime(detailArr[2], true, true); - return ret.errorMsg + "\n" + EnigmailLocale.getString("keyAndSigDate", [ret.keyId, dateTime]); } }; @@ -512,7 +494,7 @@ function ensureString(stringOrUint8Array) { return stringOrUint8Array; } - return EnigmailData.arrayBufferToString(stringOrUint8Array); + return arrayBufferToString(stringOrUint8Array); } function ensureUint8Array(stringOrUint8Array) { @@ -529,6 +511,12 @@ function ensureUint8Array(stringOrUint8Array) { return stringOrUint8Array; } +/** + * Read from a stream and return a string + * + * @param reader Stream to read from + * @returns {Promise<String>} + */ function readFromStream(reader) { let result = ""; @@ -555,29 +543,29 @@ function readFromStream(reader) { } function getKeydesc(pubKeyIds) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: getKeydesc()\n`); - const EnigmailKeyRing = ChromeUtils.import("chrome://enigmail/content/modules/keyRing.jsm").EnigmailKeyRing; - - if (pubKeyIds.length > 0) { - let encToArray = []; - // for each key also show an associated user ID if known: - for (let keyId of pubKeyIds) { - // except for ID 00000000, which signals hidden keys - if (keyId.search(/^0+$/) < 0) { - let localKey = EnigmailKeyRing.getKeyById("0x" + keyId); - if (localKey) { - encToArray.push(`0x${keyId} (${localKey.userId})`); - } - else { - encToArray.push(`0x${keyId}`); - } - } - else { - encToArray.push(EnigmailLocale.getString("hiddenKey")); - } - } - return "\n " + encToArray.join(",\n ") + "\n"; - } + DEBUG_LOG(`getKeydesc()\n`); + // const EnigmailKeyRing = ChromeUtils.import("chrome://enigmail/content/modules/keyRing.jsm").EnigmailKeyRing; + + // if (pubKeyIds.length > 0) { + // let encToArray = []; + // // for each key also show an associated user ID if known: + // for (let keyId of pubKeyIds) { + // // except for ID 00000000, which signals hidden keys + // if (keyId.search(/^0+$/) < 0) { + // let localKey = EnigmailKeyRing.getKeyById("0x" + keyId); + // if (localKey) { + // encToArray.push(`0x${keyId} (${localKey.userId})`); + // } + // else { + // encToArray.push(`0x${keyId}`); + // } + // } + // else { + // encToArray.push(EnigmailLocale.getString("hiddenKey")); + // } + // } + // return "\n " + encToArray.join(",\n ") + "\n"; + // } return ""; } @@ -596,6 +584,68 @@ function getReturnObj() { }; } +async function getKeyStatusCode(key) { + let now = new Date(); + + try { + if (await key.isRevoked(null, null, now)) { + return "r"; + } + else if (!key.users.some(user => user.userID && user.selfCertifications.length)) { + return "i"; + } + else { + const { + user, + selfCertification + } = await key.getPrimaryUser(now, {}) || {}; + + if (!user) return "i"; + + // check for expiration time + if (isDataExpired(key.keyPacket, selfCertification, now)) { + return "e"; + } + } + } + catch (x) { + return "i"; + } + + return "f"; +} + +function isDataExpired(keyPacket, signature, date = new Date()) { + const normDate = normalizeDate(date); + + if (normDate !== null) { + const expirationTime = getExpirationTime(keyPacket, signature); + + return !(keyPacket.created <= normDate && normDate < expirationTime) || + (signature && signature.isExpired(date)); + } + + return false; +} + +function normalizeDate(time = Date.now()) { + return time === null ? time : new Date(Math.floor(Number(time) / 1000) * 1000); +} + +function getExpirationTime(keyPacket, signature) { + let expirationTime; + try { + // check V4 expiration time + if (signature.keyNeverExpires === false) { + expirationTime = keyPacket.created.getTime() + signature.keyExpirationTime * 1000; + } + + return expirationTime ? new Date(expirationTime) : Infinity; + } + catch (ex) { + return Infinity; + } +} function extractDataFromClearsignedMsg(dataStr) { dataStr = dataStr.replace(/\r?\n/g, "\r\n"); // ensure CRLF @@ -609,29 +659,199 @@ function extractDataFromClearsignedMsg(dataStr) { } /** - * If configuration is enabled, try to automatically download missing keys - * - * @param {Array<String>} keyIds: Key IDs to download + * Convert an ArrayBuffer (or Uint8Array) object into a string */ +function arrayBufferToString(buffer) { + const MAXLEN = 102400; -async function downloadMissingKeys(keyIds) { - EnigmailLog.DEBUG(`pgpjs-decrypt.jsm: downloadMissingKeys()\n`); + let uArr = new Uint8Array(buffer); + let ret = ""; + let len = buffer.byteLength; - const EnigmailKeyServer = ChromeUtils.import("chrome://enigmail/content/modules/keyserver.jsm").EnigmailKeyServer; - let foundKeys = []; + for (let j = 0; j < Math.floor(len / MAXLEN) + 1; j++) { + ret += String.fromCharCode.apply(null, uArr.subarray(j * MAXLEN, ((j + 1) * MAXLEN))); + } - try { - const keyserver = EnigmailPrefs.getAutoKeyRetrieveServer(); - if (keyserver && keyserver.length > 0) { - const keyList = "0x" + keyIds.join(" 0x"); - const ret = await EnigmailKeyServer.download(keyList, keyserver); + return ret; +} + +function getDateTime(dateNum, withDate, withTime) { + const DATE_2DIGIT = "2-digit"; + const DATE_4DIGIT = "numeric"; - if (ret.result === 0 && ret.keyList.length > 0) { - foundKeys = await pgpjs_keyStore.getKeysForKeyIds(false, keyIds); + if (dateNum && dateNum !== 0) { + let dat = new Date(dateNum * 1000); + + var options = {}; + + if (withDate) { + options.day = DATE_2DIGIT; + options.month = DATE_2DIGIT; + let year = dat.getFullYear(); + if (year > 2099) { + options.year = DATE_4DIGIT; } + else { + options.year = DATE_2DIGIT; + } + } + if (withTime) { + options.hour = DATE_2DIGIT; + options.minute = DATE_2DIGIT; + } + + return new Intl.DateTimeFormat(undefined, options).format(dat); + } + else { + return ""; + } +} + +const gTrx = []; + +function startOpenpgpTrx() { + let promiseObj = {}; + + return new Promise((resolve, reject) => { + promiseObj.resolve = resolve; + promiseObj.reject = reject; + gTrx.push(promiseObj); + + if (gTrx.length === 1) { + DEBUG_LOG("====> start process directly"); + resolve(); + } + }); +} + +function endOpenpgpTrx() { + if (gTrx.length > 0) { + DEBUG_LOG("<==== end process"); + gTrx.splice(0, 1); // remove 1st element + } + + if (gTrx.length > 0) { + DEBUG_LOG("====> start process queued"); + gTrx[0].resolve(); + } +} + +/************************************************************************* + * + * Implementation of Worker + * + **************************************************************************/ + + +var pendingPromises = [], + gTransactionId = 0; + +/** + * Send a message to the worker parent for requesting data + * + * @param {String} functionName + * @param {Object} param + * @param {Object} transferables + * + * @returns Promise<Object> + */ +async function requestMessage(functionName, param, transferables) { + + let trxId = ++gTransactionId; + return new Promise((resolve, reject) => { + postMessage({ + func: functionName, + trxId: trxId, + param: param + }, transferables); + + pendingPromises[trxId] = { + resolve, + reject + }; + }); +} + +/** + * Send and receive messages to/from Worker parent + */ +onmessage = async function(e) { + if (("result" in e.data) && ("trxId" in e.data)) { + if (pendingPromises[e.data.trxId]) { + pendingPromises[e.data.trxId].resolve(e.data.result); + delete pendingPromises[e.data.trxId]; } + return; } - catch (x) {} - return foundKeys; + if (("error" in e.data) && ("trxId" in e.data)) { + if (pendingPromises[e.data.trxId]) { + pendingPromises[e.data.trxId].reject({ + message: e.data.error + }); + delete pendingPromises[e.data.trxId]; + } + return; + } + + if (!("func" in e.data && "trxId" in e.data)) { + DEBUG_LOG('Worker: Message received invalid data from main script'); + + if ("trxId" in e.data) { + postMessage({ + trxId: e.data.trxId, + error: "No function provided" + }); + } + return; + } + + let method = e.data.func; + let args = e.data.param || null; + + if (!(method in workerBody)) { + postMessage({ + trxId: e.data.trxId, + error: `Invalid method '${method}' invoked` + }); + return; + } + + try { + await startOpenpgpTrx(); + let workerResult = await workerBody[method](args); + endOpenpgpTrx(); + DEBUG_LOG('Posting message back to main script'); + postMessage({ + trxId: e.data.trxId, + result: workerResult + }); + } + catch (ex) { + endOpenpgpTrx(); + postMessage({ + trxId: e.data.trxId, + error: `${ex.toString()}\n${ex.stack}` + }); + } +}; + + +onerror = function(e) { + ERROR_LOG('Received error from main script'); +}; + + +function DEBUG_LOG(msg) { + postMessage({ + logMessage: "pgpjs-crypto-worker.js: " + msg, + logLevel: 5 + }); +} + +function ERROR_LOG(msg) { + postMessage({ + logMessage: "pgpjs-crypto-worker.js: " + msg, + logLevel: 0 + }); } diff --git a/package/tests/main.js b/package/tests/main.js index 93a51542..dae6f213 100644 --- a/package/tests/main.js +++ b/package/tests/main.js @@ -67,6 +67,6 @@ execTest("autoSetup-test.js"); execTest("persistentCrypto-test.js"); execTest("pgpjs-keys-test.js"); execTest("pgpjs-keystore-test.js"); -execTest("pgpjs-decrypt-test.js"); +execTest("pgpjs-crypto-test.js"); execTest("pgpjs-encrypt-test.js"); execTest("pgpjs-keymanip-test.js"); diff --git a/package/tests/pgpjs-decrypt-test.js b/package/tests/pgpjs-crypto-test.js index 05cc0493..fe210ca7 100644 --- a/package/tests/pgpjs-decrypt-test.js +++ b/package/tests/pgpjs-crypto-test.js @@ -11,12 +11,13 @@ do_load_module("file://" + do_get_cwd().path + "/testHelper.js"); -testing("cryptoAPI/pgpjs-decrypt.jsm"); -/*global pgpjs_decrypt: false, getOpenPGPLibrary: false, pgpjs_keyStore: false, EnigmailConstants: false, - EnigmailFiles: false - */ +ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-crypto-main.jsm"); /*global pgpjs_crypto: false */ +const EnigmailFiles = ChromeUtils.import("chrome://enigmail/content/modules/files.jsm").EnigmailFiles; const EnigmailArmor = ChromeUtils.import("chrome://enigmail/content/modules/armor.jsm").EnigmailArmor; +const EnigmailConstants = ChromeUtils.import("chrome://enigmail/content/modules/constants.jsm").EnigmailConstants; +const pgpjs_keyStore = ChromeUtils.import("chrome://enigmail/content/modules/cryptoAPI/pgpjs-keystore.jsm").pgpjs_keyStore; +const getOpenPGPLibrary = ChromeUtils.import("chrome://enigmail/content/modules/stdlib/openpgp-loader.jsm").getOpenPGPLibrary; test(withTestGpgHome(asyncTest(async function testDecrypt() { try { @@ -43,8 +44,8 @@ test(withTestGpgHome(asyncTest(async function testDecrypt() { let fileData = EnigmailFiles.readFile(encFile); let pgpMsg = EnigmailArmor.splitArmoredBlocks(fileData)[0]; - let result = await pgpjs_decrypt.processPgpMessage(pgpMsg, {}); - Assert.equal(result.statusFlags, EnigmailConstants.DECRYPTION_FAILED | EnigmailConstants.NO_SECKEY); + let result = await pgpjs_crypto.processPgpMessage(pgpMsg, {}); + Assert.equal(result.statusFlags, EnigmailConstants.DECRYPTION_FAILED); const pubKeyFile = do_get_file("resources/dev-strike.sec", false); fileData = EnigmailFiles.readBinaryFile(pubKeyFile); @@ -52,7 +53,7 @@ test(withTestGpgHome(asyncTest(async function testDecrypt() { let r = await pgpjs_keyStore.writeKey(fileData); Assert.equal(r.length, 1); - result = await pgpjs_decrypt.processPgpMessage(pgpMsg, {}); + result = await pgpjs_crypto.processPgpMessage(pgpMsg, {}); Assert.equal(result.statusFlags, EnigmailConstants.DECRYPTION_OKAY | EnigmailConstants.GOOD_SIGNATURE | EnigmailConstants.TRUSTED_IDENTITY); Assert.equal(result.exitCode, 0); Assert.equal(result.sigDetails, "65537E212DC19025AD38EDB2781617319CE311C4 2020-03-21 1584808355 0 4 0 1 8 00 65537E212DC19025AD38EDB2781617319CE311C4"); @@ -68,7 +69,7 @@ owE7rZbEEOfZI+yRmpOTr1CeX5SToscVkpFZrABEiQolqcUlCla6mlwA =aAp2 -----END PGP MESSAGE-----`; - result = await pgpjs_decrypt.processPgpMessage(storedMsg, {}); + result = await pgpjs_crypto.processPgpMessage(storedMsg, {}); Assert.equal(result.statusFlags, 0); Assert.equal(result.exitCode, 0); Assert.equal(result.sigDetails, ""); @@ -94,7 +95,7 @@ j8bbyQ== =fwVK -----END PGP MESSAGE-----`; - result = await pgpjs_decrypt.processPgpMessage(signedMsg, {}); + result = await pgpjs_crypto.processPgpMessage(signedMsg, {}); Assert.equal(result.statusFlags, EnigmailConstants.GOOD_SIGNATURE | EnigmailConstants.TRUSTED_IDENTITY); Assert.equal(result.exitCode, 0); Assert.equal(result.sigDetails, "65537E212DC19025AD38EDB2781617319CE311C4 2020-02-16 1581878756 0 4 0 1 8 00 65537E212DC19025AD38EDB2781617319CE311C4"); @@ -125,7 +126,7 @@ wJEP0gfdDZA1bEV78SRcjJDlfo5vuWX4W/ZlAlA9hy5OVq69DOdlcVdgj18+gy94 -----END PGP SIGNATURE----- `; - result = await pgpjs_decrypt.verify(clearSigned, {}); + result = await pgpjs_crypto.verify(clearSigned, {}); Assert.equal(result.statusFlags, EnigmailConstants.GOOD_SIGNATURE | EnigmailConstants.TRUSTED_IDENTITY); Assert.equal(result.exitCode, 0); Assert.equal(result.sigDetails, "65537E212DC19025AD38EDB2781617319CE311C4 2020-02-16 1581879420 0 4 0 1 8 00 65537E212DC19025AD38EDB2781617319CE311C4"); @@ -151,7 +152,7 @@ TA== =6sUw -----END PGP MESSAGE-----`; - result = await pgpjs_decrypt.processPgpMessage(noMdcProtection, {}); + result = await pgpjs_crypto.processPgpMessage(noMdcProtection, {}); Assert.equal(result.statusFlags, EnigmailConstants.DECRYPTION_FAILED | EnigmailConstants.MISSING_MDC); Assert.equal(result.exitCode, 0); Assert.equal(result.decryptedData, ""); @@ -174,7 +175,7 @@ fsTKNmsBfsUHg/qzu+yD0e4bTuEKVsDcCg== =WPhs -----END PGP MESSAGE-----`; - result = await pgpjs_decrypt.processPgpMessage(badMdc, {}); + result = await pgpjs_crypto.processPgpMessage(badMdc, {}); Assert.equal(result.statusFlags, EnigmailConstants.DECRYPTION_FAILED); Assert.equal(result.exitCode, 1); Assert.equal(result.decryptedData, ""); @@ -192,7 +193,7 @@ iD8DBQE+yUcu4mZch0nhy8kRAuh/AKDM1Xc49BKVfJIFg/btWGfbF/pgcwCgw0Zk -----END PGP SIGNATURE----- `; - result = await pgpjs_decrypt.verify(packetV3, {}); + result = await pgpjs_crypto.verify(packetV3, {}); Assert.equal(result.statusFlags, EnigmailConstants.UNVERIFIED_SIGNATURE); Assert.equal(result.exitCode, 1); Assert.equal(result.decryptedData, ""); @@ -211,18 +212,18 @@ test(withTestGpgHome(asyncTest(async function testVerifyFile() { const pubKeyFile = do_get_file("resources/dev-strike.asc", false); try { - await pgpjs_decrypt.verifyFile(attachmentFile.path, signatureFile.path); + await pgpjs_crypto.verifyFile(attachmentFile.path, signatureFile.path); Assert.ok(false, "Should not obtain a valid verification"); } catch (err) { - Assert.assertContains(String(err), "Unverified signature - signed with unknown key"); + Assert.assertContains(String(err), "Error during parsing"); } let keyData = EnigmailFiles.readBinaryFile(pubKeyFile); let result = await pgpjs_keyStore.writeKey(keyData); Assert.equal(result.length, 1); - result = await pgpjs_decrypt.verifyFile(attachmentFile.path, signatureFile.path); + result = await pgpjs_crypto.verifyFile(attachmentFile.path, signatureFile.path); Assert.assertContains(result, 'Good signature from anonymous strike'); Assert.assertContains(result, 'Key ID: 0x65537E212DC19025AD38EDB2781617319CE311C'); }))); diff --git a/package/tests/testHelper.js b/package/tests/testHelper.js index d23dfb0a..41d6631e 100644 --- a/package/tests/testHelper.js +++ b/package/tests/testHelper.js @@ -55,8 +55,6 @@ var TestHelper = { testing: function(name) { TestHelper.currentlyTesting = name; - const resetOpenPGPLibrary = ChromeUtils.import("chrome://enigmail/content/modules/stdlib/openpgp-loader.jsm").resetLibrary; - resetOpenPGPLibrary(); }, registerTest: function(fn) { diff --git a/ui/content/enigmailMessengerOverlay.js b/ui/content/enigmailMessengerOverlay.js index eae99d00..e6248ee0 100644 --- a/ui/content/enigmailMessengerOverlay.js +++ b/ui/content/enigmailMessengerOverlay.js @@ -1967,7 +1967,6 @@ Enigmail.msg = { var mailNewsUrl = Enigmail.msg.getCurrentMsgUrl(); var urlSpec = mailNewsUrl ? mailNewsUrl.spec : ""; - var newBufferSize = 0; var l = urlSpec.length; diff --git a/util/genxpi b/util/genxpi index faa45754..18817402 100755 --- a/util/genxpi +++ b/util/genxpi @@ -90,7 +90,8 @@ set chrome/content/preferences/defaultPrefs.js \ chrome/content/modules/cryptoAPI/gpgme.js \ chrome/content/modules/cryptoAPI/openpgp-js.js \ chrome/content/modules/cryptoAPI/pgpjs-encrypt.jsm \ - chrome/content/modules/cryptoAPI/pgpjs-decrypt.jsm \ + chrome/content/modules/cryptoAPI/pgpjs-crypto-main.jsm \ + chrome/content/modules/cryptoAPI/pgpjs-crypto-worker.js \ chrome/content/modules/cryptoAPI/pgpjs-keys.jsm \ chrome/content/modules/cryptoAPI/pgpjs-keymanipulation.jsm \ chrome/content/modules/cryptoAPI/pgpjs-keystore.jsm \ |