diff options
Diffstat (limited to 'comm/mail/extensions/openpgp/content/modules/cryptoAPI')
3 files changed, 808 insertions, 0 deletions
diff --git a/comm/mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm new file mode 100644 index 0000000000..475108292d --- /dev/null +++ b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/GnuPGCryptoAPI.jsm @@ -0,0 +1,238 @@ +/* + * 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"; + +var EXPORTED_SYMBOLS = ["getGnuPGAPI"]; + +Services.scriptloader.loadSubScript( + "chrome://openpgp/content/modules/cryptoAPI/interface.js", + null, + "UTF-8" +); /* global CryptoAPI */ + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +const lazy = {}; + +XPCOMUtils.defineLazyModuleGetters(lazy, { + EnigmailConstants: "chrome://openpgp/content/modules/constants.jsm", + EnigmailLog: "chrome://openpgp/content/modules/log.jsm", +}); + +/** + * GnuPG implementation of CryptoAPI + */ + +class GnuPGCryptoAPI extends CryptoAPI { + constructor() { + super(); + this.api_name = "GnuPG"; + } + + /** + * Get the list of all knwn keys (including their secret keys) + * + * @param {Array of String} onlyKeys: [optional] only load data for specified key IDs + * + * @returns {Promise<Array of Object>} + */ + async getKeys(onlyKeys = null) { + throw new Error("Not implemented"); + } + + /** + * Obtain signatures for a given set of key IDs. + * + * @param {string} keyId: space-separated list of key IDs + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeySignatures(keyId, ignoreUnknownUid = false) { + lazy.EnigmailLog.DEBUG(`gnupg.js: getKeySignatures: ${keyId}\n`); + throw new Error("Not implemented"); + } + + /** + * Obtain signatures for a given key. + * + * @param {KeyObj} keyObj: the signatures of this key will be returned + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeyObjSignatures(keyObj, ignoreUnknownUid = false) { + throw new Error("Not implemented"); + } + + /** + * Export the minimum key for the public key object: + * public key, primary user ID, newest encryption subkey + * + * @param {string} fpr: - a single FPR + * @param {string} email: - [optional] the email address of the desired user ID. + * If the desired user ID cannot be found or is not valid, use the primary UID instead + * @param {Array<number>} subkeyDates: [optional] remove subkeys with specific creation Dates + * + * @returns {Promise<object>}: + * - exitCode (0 = success) + * - errorMsg (if exitCode != 0) + * - keyData: BASE64-encded string of key data + */ + async getMinimalPubKey(fpr, email, subkeyDates) { + lazy.EnigmailLog.DEBUG(`gnupg.js: getMinimalPubKey: ${fpr}\n`); + throw new Error("Not implemented"); + } + + /** + * Export secret key(s) to a file + * + * @param {string} keyId Specification by fingerprint or keyID + * @param {boolean} minimalKey - if true, reduce key to minimum required + * + * @returns {object}: + * - {Number} exitCode: result code (0: OK) + * - {String} keyData: ASCII armored key data material + * - {String} errorMsg: error message in case exitCode !== 0 + */ + + async extractSecretKey(keyId, minimalKey) { + throw new Error("Not implemented"); + } + + /** + * + * @param {byte} byteData - The encrypted data + * + * @returns {String or null} - the name of the attached file + */ + + async getFileName(byteData) { + lazy.EnigmailLog.DEBUG(`gnupg.js: getFileName()\n`); + throw new Error("Not implemented"); + } + + /** + * + * @param {Path} filePath - The signed file + * @param {Path} sigPath - The signature to verify + * + * @returns {Promise<string>} - A message from the verification. + * + * Use Promise.catch to handle failed verifications. + * The message will be an error message in this case. + */ + + async verifyAttachment(filePath, sigPath) { + lazy.EnigmailLog.DEBUG(`gnupg.js: verifyAttachment()\n`); + throw new Error("Not implemented"); + } + + /** + * + * @param {Bytes} encrypted The encrypted data + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptAttachment(encrypted) { + lazy.EnigmailLog.DEBUG(`gnupg.js: decryptAttachment()\n`); + throw new Error("Not implemented"); + } + + /** + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decrypt(encrypted, options) { + lazy.EnigmailLog.DEBUG(`gnupg.js: decrypt()\n`); + throw new Error("Not implemented"); + } + + /** + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptMime(encrypted, options) { + lazy.EnigmailLog.DEBUG(`gnupg.js: decryptMime()\n`); + + // write something to gpg such that the process doesn't get stuck + if (encrypted.length === 0) { + encrypted = "NO DATA\n"; + } + + options.noOutput = false; + options.verifyOnly = false; + options.uiFlags = lazy.EnigmailConstants.UI_PGP_MIME; + + return this.decrypt(encrypted, options); + } + + /** + * + * @param {string} signed - The signed data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async verifyMime(signed, options) { + lazy.EnigmailLog.DEBUG(`gnupg.js: verifyMime()\n`); + + options.noOutput = true; + options.verifyOnly = true; + options.uiFlags = lazy.EnigmailConstants.UI_PGP_MIME; + + return this.decrypt(signed, options); + } + + async getKeyListFromKeyBlockAPI(keyBlockStr) { + throw new Error("Not implemented"); + } + + async genKey(userId, keyType, keySize, expiryTime, passphrase) { + throw new Error("GnuPG genKey() not implemented"); + } + + async deleteKey(keyFingerprint, deleteSecret) { + return null; + } + + async encryptAndOrSign(plaintext, args, resultStatus) { + return null; + } +} + +function getGnuPGAPI() { + return new GnuPGCryptoAPI(); +} diff --git a/comm/mail/extensions/openpgp/content/modules/cryptoAPI/RNPCryptoAPI.jsm b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/RNPCryptoAPI.jsm new file mode 100644 index 0000000000..6b03bf3c6f --- /dev/null +++ b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/RNPCryptoAPI.jsm @@ -0,0 +1,282 @@ +/* + * 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"; + +var EXPORTED_SYMBOLS = ["getRNPAPI"]; + +const { RNP } = ChromeUtils.import("chrome://openpgp/content/modules/RNP.jsm"); + +Services.scriptloader.loadSubScript( + "chrome://openpgp/content/modules/cryptoAPI/interface.js", + null, + "UTF-8" +); /* global CryptoAPI */ + +const { EnigmailLog } = ChromeUtils.import( + "chrome://openpgp/content/modules/log.jsm" +); +const { EnigmailConstants } = ChromeUtils.import( + "chrome://openpgp/content/modules/constants.jsm" +); + +/** + * RNP implementation of CryptoAPI + */ +class RNPCryptoAPI extends CryptoAPI { + constructor() { + super(); + this.api_name = "RNP"; + } + + /** + * Get the list of all knwn keys (including their secret keys) + * + * @param {Array of String} onlyKeys: [optional] only load data for specified key IDs + * + * @returns {Promise<Array of Object>} + */ + async getKeys(onlyKeys = null) { + return RNP.getKeys(onlyKeys); + } + + /** + * Obtain signatures for a given set of key IDs. + * + * @param {string} keyId: space-separated list of key IDs + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeySignatures(keyId, ignoreUnknownUid = false) { + return RNP.getKeySignatures(keyId, ignoreUnknownUid); + } + + /** + * Obtain signatures for a given key. + * + * @param {KeyObj} keyObj: the signatures of this key will be returned + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeyObjSignatures(keyId, ignoreUnknownUid = false) { + return RNP.getKeyObjSignatures(keyId, ignoreUnknownUid); + } + + /** + * Export the minimum key for the public key object: + * public key, primary user ID, newest encryption subkey + * + * @param {string} fpr: - a single FPR + * @param {string} email: - [optional] the email address of the desired user ID. + * If the desired user ID cannot be found or is not valid, use the primary UID instead + * @param {Array<number>} subkeyDates: [optional] remove subkeys with specific creation Dates + * + * @returns {Promise<object>}: + * - exitCode (0 = success) + * - errorMsg (if exitCode != 0) + * - keyData: BASE64-encded string of key data + */ + async getMinimalPubKey(fpr, email, subkeyDates) { + throw new Error("Not implemented"); + } + + async importPubkeyBlockAutoAcceptAPI( + win, + keyBlock, + acceptance, + permissive, + limitedFPRs = [] + ) { + let res = await RNP.importPubkeyBlockAutoAcceptImpl( + win, + keyBlock, + acceptance, + permissive, + limitedFPRs + ); + return res; + } + + async importRevBlockAPI(data) { + return RNP.importRevImpl(data); + } + + /** + * Export secret key(s) to a file + * + * @param {string} keyId Specification by fingerprint or keyID + * @param {boolean} minimalKey - if true, reduce key to minimum required + * + * @returns {object}: + * - {Number} exitCode: result code (0: OK) + * - {String} keyData: ASCII armored key data material + * - {String} errorMsg: error message in case exitCode !== 0 + */ + + async extractSecretKey(keyId, minimalKey) { + throw new Error("extractSecretKey not implemented"); + } + + /** + * + * @param {byte} byteData - The encrypted data + * + * @returns {String or null} - the name of the attached file + */ + + async getFileName(byteData) { + throw new Error("getFileName not implemented"); + } + + /** + * + * @param {Path} filePath - The signed file + * @param {Path} sigPath - The signature to verify + * + * @returns {Promise<string>} - A message from the verification. + * + * Use Promise.catch to handle failed verifications. + * The message will be an error message in this case. + */ + + async verifyAttachment(filePath, sigPath) { + throw new Error("verifyAttachment not implemented"); + } + + /** + * + * @param {Bytes} encrypted The encrypted data + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptAttachment(encrypted) { + let options = {}; + options.fromAddr = ""; + options.msgDate = null; + return RNP.decrypt(encrypted, options); + } + + /** + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + * XXX: it's not... ^^^ This should be changed to always reject + * by throwing an Error (subclass?) for failures to decrypt. + */ + + async decrypt(encrypted, options) { + EnigmailLog.DEBUG(`rnp-cryptoAPI.js: decrypt()\n`); + + return RNP.decrypt(encrypted, options); + } + + /** + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptMime(encrypted, options) { + EnigmailLog.DEBUG(`rnp-cryptoAPI.js: decryptMime()\n`); + + // write something to gpg such that the process doesn't get stuck + if (encrypted.length === 0) { + encrypted = "NO DATA\n"; + } + + options.noOutput = false; + options.verifyOnly = false; + options.uiFlags = EnigmailConstants.UI_PGP_MIME; + + return this.decrypt(encrypted, options); + } + + /** + * + * @param {string} signed - The signed data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async verifyMime(signed, options) { + EnigmailLog.DEBUG(`rnp-cryptoAPI.js: verifyMime()\n`); + + //options.noOutput = true; + //options.verifyOnly = true; + //options.uiFlags = EnigmailConstants.UI_PGP_MIME; + + if (!options.mimeSignatureData) { + throw new Error("inline verify not yet implemented"); + } + return RNP.verifyDetached(signed, options); + } + + async getKeyListFromKeyBlockAPI( + keyBlockStr, + pubkey, + seckey, + permissive, + withPubKey + ) { + return RNP.getKeyListFromKeyBlockImpl( + keyBlockStr, + pubkey, + seckey, + permissive, + withPubKey + ); + } + + async genKey(userId, keyType, keySize, expiryTime, passphrase) { + let id = RNP.genKey(userId, keyType, keySize, expiryTime, passphrase); + await RNP.saveKeyRings(); + return id; + } + + async deleteKey(keyFingerprint, deleteSecret) { + return RNP.deleteKey(keyFingerprint, deleteSecret); + } + + async encryptAndOrSign(plaintext, args, resultStatus) { + return RNP.encryptAndOrSign(plaintext, args, resultStatus); + } + + async unlockAndGetNewRevocation(id, pass) { + return RNP.unlockAndGetNewRevocation(id, pass); + } + + async getPublicKey(id) { + return RNP.getPublicKey(id); + } +} + +function getRNPAPI() { + return new RNPCryptoAPI(); +} diff --git a/comm/mail/extensions/openpgp/content/modules/cryptoAPI/interface.js b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/interface.js new file mode 100644 index 0000000000..eb2419a2e1 --- /dev/null +++ b/comm/mail/extensions/openpgp/content/modules/cryptoAPI/interface.js @@ -0,0 +1,288 @@ +/* + * 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"; + +/** + * CryptoAPI - abstract interface + */ + +var inspector; + +class CryptoAPI { + constructor() { + this.api_name = "null"; + } + + get apiName() { + return this.api_name; + } + + /** + * Synchronize a promise: wait synchonously until a promise has completed and return + * the value that the promise returned. + * + * @param {Promise} promise: the promise to wait for + * + * @returns {Variant} whatever the promise returns + */ + sync(promise) { + if (!inspector) { + inspector = Cc["@mozilla.org/jsinspector;1"].createInstance( + Ci.nsIJSInspector + ); + } + + let res = null; + promise + .then(gotResult => { + res = gotResult; + inspector.exitNestedEventLoop(); + }) + .catch(gotResult => { + console.log("CryptoAPI.sync() failed result: %o", gotResult); + if (gotResult instanceof Error) { + inspector.exitNestedEventLoop(); + throw gotResult; + } + + res = gotResult; + inspector.exitNestedEventLoop(); + }); + + inspector.enterNestedEventLoop(0); + return res; + } + + /** + * Obtain signatures for a given set of key IDs. + * + * @param {string} keyId: space-separated list of key IDs + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeySignatures(keyId, ignoreUnknownUid = false) { + return null; + } + + /** + * Obtain signatures for a given key. + * + * @param {KeyObj} keyObj: the signatures of this key will be returned + * @param {boolean} ignoreUnknownUid: if true, filter out unknown signer's UIDs + * + * @returns {Promise<Array of Object>} - see extractSignatures() + */ + async getKeyObjSignatures(keyObj, ignoreUnknownUid = false) { + return null; + } + + /** + * Export the minimum key for the public key object: + * public key, user ID, newest encryption subkey + * + * @param {string} fpr - : a single FPR + * @param {string} email: [optional] the email address of the desired user ID. + * If the desired user ID cannot be found or is not valid, use the primary UID instead + * + * @returns {Promise<object>}: + * - exitCode (0 = success) + * - errorMsg (if exitCode != 0) + * - keyData: BASE64-encded string of key data + */ + async getMinimalPubKey(fpr, email) { + return { + exitCode: -1, + errorMsg: "", + keyData: "", + }; + } + + /** + * Get the list of all known keys (including their secret keys) + * + * @param {Array of String} onlyKeys: [optional] only load data for specified key IDs + * + * @returns {Promise<Array of Object>} + */ + async getKeys(onlyKeys = null) { + return []; + } + + async importPubkeyBlockAutoAccept(keyBlock) { + return null; + } + + // return bool success + async importRevBlockAPI(data) { + return null; + } + + /** + * Export secret key(s) to a file + * + * @param {string} keyId Specification by fingerprint or keyID + * @param {boolean} minimalKey - if true, reduce key to minimum required + * + * @returns {object}: + * - {Number} exitCode: result code (0: OK) + * - {String} keyData: ASCII armored key data material + * - {String} errorMsg: error message in case exitCode !== 0 + */ + + async extractSecretKey(keyId, minimalKey) { + return null; + } + + /** + * Determine the file name from OpenPGP data. + * + * @param {byte} byteData - The encrypted data + * + * @returns {string} - the name of the attached file + */ + + async getFileName(byteData) { + return null; + } + + /** + * Verify the detached signature of an attachment (or in other words, + * check the signature of a file, given the file and the signature). + * + * @param {Path} filePath - The signed file + * @param {Path} sigPath - The signature to verify + * + * @returns {Promise<string>} - A message from the verification. + * + * Use Promise.catch to handle failed verifications. + * The message will be an error message in this case. + */ + + async verifyAttachment(filePath, sigPath) { + return null; + } + + /** + * Decrypt an attachment. + * + * @param {Bytes} encrypted The encrypted data + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptAttachment(encrypted) { + return null; + } + + /** + * Generic function to decrypt and/or verify an OpenPGP message. + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decrypt(encrypted, options) { + return null; + } + + /** + * Decrypt a PGP/MIME-encrypted message + * + * @param {string} encrypted - The encrypted data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async decryptMime(encrypted, options) { + return null; + } + + /** + * Verify a PGP/MIME-signed message + * + * @param {string} signed - The signed data + * @param {object} options - Decryption options + * + * @returns {Promise<object>} - Return object with decryptedData and + * status information + * + * Use Promise.catch to handle failed decryption. + * retObj.errorMsg will be an error message in this case. + */ + + async verifyMime(signed, options) { + return null; + } + + /** + * Get details (key ID, UID) of the data contained in a OpenPGP key block + * + * @param {string} keyBlockStr - String: the contents of one or more public keys + * + * @returns {Promise<Array>}: array of objects with the following structure: + * - id (key ID) + * - fpr + * - name (the UID of the key) + */ + + async getKeyListFromKeyBlockAPI(keyBlockStr) { + return null; + } + + /** + * Create a new private key pair, including appropriate sub key pair, + * and store the new keys in the default keyrings. + * + * @param {string} userId - User ID string, with name and email. + * @param {string} keyType - "RSA" or "ECC". + * ECC uses EDDSA and ECDH/Curve25519. + * @param {number} keySize - RSA key size. Ignored for ECC. + * @param {number} expiryTime The number of days the key will remain valid + * (after the creation date). + * Set to zero for no expiration. + * @param {string} passphrase The passphrase to protect the new key. + * Set to null to use an empty passphrase. + * + * @returns {Promise<string>} - The new KeyID + */ + + async genKey(userId, keyType, keySize, expiryTime, passphrase) { + return null; + } + + async deleteKey(keyFingerprint, deleteSecret) { + return null; + } + + async encryptAndOrSign(plaintext, args, resultStatus) { + return null; + } + + async unlockAndGetNewRevocation(id, pass) { + return null; + } + + async getPublicKey(id) { + return null; + } +} |