Bug 1603782 - Implement OpenPGP message creation that uses separate MIME layers for signature and encryption. r=PatrickBrunschwig DONTBUILD
Differential Revision: https://phabricator.services.mozilla.com/D83698 --HG-- extra : amend_source : 3bdec5bb91f5ba3add4a7d20d80dbfb943f2d44c
This commit is contained in:
Родитель
11ea2ce6c2
Коммит
1f516189db
|
@ -32,6 +32,8 @@ pref("mail.openpgp.allow_external_gnupg", false);
|
|||
pref("mail.openpgp.alternative_gpg_path", "");
|
||||
// The hexadecimal OpenPGP key ID used for an identity.
|
||||
pref("mail.identity.default.openpgp_key_id", "");
|
||||
// If true, then openpgp_key_id is managed externally by GnuPG
|
||||
pref("mail.identity.default.is_gnupg_key_id", false);
|
||||
|
||||
// When sending, encrypt to this additional key. Not available in release channel builds.
|
||||
pref("mail.openpgp.debug.extra_encryption_key", "");
|
||||
|
|
|
@ -8,6 +8,9 @@ var { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
|
|||
var { GPGMELibLoader } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/GPGMELib.jsm"
|
||||
);
|
||||
var { EnigmailConstants } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/constants.jsm"
|
||||
);
|
||||
|
||||
var GPGMELib;
|
||||
|
||||
|
@ -110,4 +113,73 @@ var GPGME = {
|
|||
|
||||
return result;
|
||||
},
|
||||
|
||||
async signDetached(plaintext, args, resultStatus) {
|
||||
resultStatus.exitCode = -1;
|
||||
resultStatus.statusFlags = 0;
|
||||
resultStatus.statusMsg = "";
|
||||
resultStatus.errorMsg = "";
|
||||
|
||||
if (args.encrypt || !args.sign || !args.sigTypeDetached) {
|
||||
throw new Error("invalid parameters, neither encrypt nor sign");
|
||||
}
|
||||
|
||||
let result = null;
|
||||
//args.sender must be keyId
|
||||
let keyId = args.sender.replace(/^0x/, "").toUpperCase();
|
||||
|
||||
let ctx = new GPGMELib.gpgme_ctx_t();
|
||||
if (GPGMELib.gpgme_new(ctx.address())) {
|
||||
throw new Error("gpgme_new failed");
|
||||
}
|
||||
GPGMELib.gpgme_set_armor(ctx, 1);
|
||||
GPGMELib.gpgme_set_textmode(ctx, 1);
|
||||
let keyHandle = new GPGMELib.gpgme_key_t();
|
||||
if (!GPGMELib.gpgme_get_key(ctx, keyId, keyHandle.address(), 1)) {
|
||||
if (!GPGMELib.gpgme_signers_add(ctx, keyHandle)) {
|
||||
var tmp_array = ctypes.char.array()(plaintext);
|
||||
let data_plaintext = new GPGMELib.gpgme_data_t();
|
||||
if (
|
||||
!GPGMELib.gpgme_data_new_from_mem(
|
||||
data_plaintext.address(),
|
||||
tmp_array,
|
||||
tmp_array.length,
|
||||
0
|
||||
)
|
||||
) {
|
||||
let data_signed = new GPGMELib.gpgme_data_t();
|
||||
if (!GPGMELib.gpgme_data_new(data_signed.address())) {
|
||||
let exitCode = GPGMELib.gpgme_op_sign(
|
||||
ctx,
|
||||
data_plaintext,
|
||||
data_signed,
|
||||
GPGMELib.GPGME_SIG_MODE_DETACH
|
||||
);
|
||||
if (exitCode != GPGMELib.GPG_ERR_NO_ERROR) {
|
||||
GPGMELib.gpgme_data_release(data_signed);
|
||||
} else {
|
||||
let result_len = new ctypes.size_t();
|
||||
let result_buf = GPGMELib.gpgme_data_release_and_get_mem(
|
||||
data_signed,
|
||||
result_len.address()
|
||||
);
|
||||
if (!result_buf.isNull()) {
|
||||
let unwrapped = ctypes.cast(
|
||||
result_buf,
|
||||
ctypes.char.array(result_len.value).ptr
|
||||
).contents;
|
||||
result = unwrapped.readString();
|
||||
resultStatus.exitCode = 0;
|
||||
resultStatus.statusFlags |= EnigmailConstants.SIG_CREATED;
|
||||
GPGMELib.gpgme_free(result_buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GPGMELib.gpgme_key_release(keyHandle);
|
||||
}
|
||||
GPGMELib.gpgme_release(ctx);
|
||||
return result;
|
||||
},
|
||||
};
|
||||
|
|
|
@ -6,6 +6,7 @@ const EXPORTED_SYMBOLS = ["GPGMELibLoader"];
|
|||
|
||||
var { ctypes } = ChromeUtils.import("resource://gre/modules/ctypes.jsm");
|
||||
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
var systemOS = Services.appinfo.OS.toLowerCase();
|
||||
var { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
|
||||
var abi = ctypes.default_abi;
|
||||
|
||||
|
@ -38,7 +39,7 @@ function tryLoadGPGME(name, suffix) {
|
|||
} catch (e) {}
|
||||
}
|
||||
|
||||
if (!libgpgme && Services.appinfo.OS !== "WINNT") {
|
||||
if (!libgpgme && systemOS !== "winnt") {
|
||||
// try specific additional directories
|
||||
|
||||
for (let tryPath of ADDITIONAL_LIB_PATHS) {
|
||||
|
@ -56,7 +57,7 @@ function tryLoadGPGME(name, suffix) {
|
|||
|
||||
if (libgpgme) {
|
||||
console.debug(
|
||||
"Successfully loaded OpenPGP library " +
|
||||
"Successfully loaded optional OpenPGP library " +
|
||||
filename +
|
||||
" from " +
|
||||
loadFromInfo
|
||||
|
@ -66,14 +67,25 @@ function tryLoadGPGME(name, suffix) {
|
|||
|
||||
function loadExternalGPGMELib() {
|
||||
if (!libgpgme) {
|
||||
// Try loading libgpgme.so, libgpgme.dylib, or gpgme.dll first
|
||||
if (systemOS === "winnt") {
|
||||
tryLoadGPGME("libgpgme-11", "");
|
||||
|
||||
let gpgmeLibName = "gpgme";
|
||||
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
gpgmeLibName = "libgpgme-11";
|
||||
if (!libgpgme) {
|
||||
tryLoadGPGME("gpgme-11", "");
|
||||
}
|
||||
}
|
||||
|
||||
if (!libgpgme) {
|
||||
tryLoadGPGME("gpgme", "");
|
||||
}
|
||||
|
||||
if (!libgpgme) {
|
||||
tryLoadGPGME("gpgme", ".11");
|
||||
}
|
||||
|
||||
if (!libgpgme) {
|
||||
tryLoadGPGME("gpgme.11");
|
||||
}
|
||||
tryLoadGPGME(gpgmeLibName, "");
|
||||
}
|
||||
|
||||
return !!libgpgme;
|
||||
|
@ -102,8 +114,7 @@ const gpgme_sig_notation_flags_t = ctypes.unsigned_int;
|
|||
const gpgme_export_mode_t = ctypes.unsigned_int;
|
||||
const gpgme_decrypt_flags_t = ctypes.unsigned_int;
|
||||
const gpgme_data_encoding_t = ctypes.unsigned_int;
|
||||
|
||||
gpgme_data_t;
|
||||
const gpgme_sig_mode_t = ctypes.int; // it's an enum, risk of wrong type.
|
||||
|
||||
let _gpgme_subkey = ctypes.StructType("_gpgme_subkey");
|
||||
_gpgme_subkey.define([
|
||||
|
@ -474,6 +485,42 @@ function enableGPGMELibJS() {
|
|||
gpgme_data_encoding_t
|
||||
),
|
||||
|
||||
gpgme_op_sign: libgpgme.declare(
|
||||
"gpgme_op_sign",
|
||||
abi,
|
||||
gpgme_error_t,
|
||||
gpgme_ctx_t,
|
||||
gpgme_data_t,
|
||||
gpgme_data_t,
|
||||
gpgme_sig_mode_t
|
||||
),
|
||||
|
||||
gpgme_signers_add: libgpgme.declare(
|
||||
"gpgme_signers_add",
|
||||
abi,
|
||||
gpgme_error_t,
|
||||
gpgme_ctx_t,
|
||||
gpgme_key_t
|
||||
),
|
||||
|
||||
gpgme_get_key: libgpgme.declare(
|
||||
"gpgme_get_key",
|
||||
abi,
|
||||
gpgme_error_t,
|
||||
gpgme_ctx_t,
|
||||
ctypes.char.ptr,
|
||||
gpgme_key_t.ptr,
|
||||
ctypes.int
|
||||
),
|
||||
|
||||
gpgme_set_textmode: libgpgme.declare(
|
||||
"gpgme_set_textmode",
|
||||
abi,
|
||||
ctypes.void_t,
|
||||
gpgme_ctx_t,
|
||||
ctypes.int
|
||||
),
|
||||
|
||||
gpgme_error_t,
|
||||
gpgme_ctx_t,
|
||||
gpgme_data_t,
|
||||
|
@ -499,5 +546,6 @@ function enableGPGMELibJS() {
|
|||
GPGME_EXPORT_MODE_SECRET: 16,
|
||||
GPGME_DECRYPT_UNWRAP: 128,
|
||||
GPGME_DATA_ENCODING_ARMOR: 3,
|
||||
GPGME_SIG_MODE_DETACH: 1,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1822,6 +1822,25 @@ var RNP = {
|
|||
},
|
||||
|
||||
async encryptAndOrSign(plaintext, args, resultStatus) {
|
||||
if (args.sign && args.senderKeyIsExternal) {
|
||||
if (!GPGME.allDependenciesLoaded()) {
|
||||
throw new Error(
|
||||
"invalid configuration, request to use external GnuPG key, but GPGME isn't working"
|
||||
);
|
||||
}
|
||||
if (args.encrypt) {
|
||||
throw new Error(
|
||||
"internal error, unexpected request to sign and encrypt in a single step with external GnuPG key configuration"
|
||||
);
|
||||
}
|
||||
if (!args.sigTypeDetached || args.sigTypeClear) {
|
||||
throw new Error(
|
||||
"unexpected signing request with external GnuPG key configuration"
|
||||
);
|
||||
}
|
||||
return GPGME.signDetached(plaintext, args, resultStatus);
|
||||
}
|
||||
|
||||
resultStatus.exitCode = -1;
|
||||
resultStatus.statusFlags = 0;
|
||||
resultStatus.statusMsg = "";
|
||||
|
@ -1895,21 +1914,26 @@ var RNP = {
|
|||
if (!senderKey || senderKey.isNull()) {
|
||||
return null;
|
||||
}
|
||||
let isPersonal = false;
|
||||
let senderKeySecretAvailable = this.getSecretAvailableFromHandle(
|
||||
senderKey
|
||||
);
|
||||
if (senderKeySecretAvailable) {
|
||||
let senderFpr = this.getFingerprintFromHandle(senderKey);
|
||||
isPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(senderFpr);
|
||||
}
|
||||
if (!isPersonal) {
|
||||
throw new Error(
|
||||
"configured sender key " +
|
||||
args.sender +
|
||||
" isn't accepted as a personal key"
|
||||
// Manually configured external key overrides the check for
|
||||
// a valid personal key.
|
||||
if (!args.senderKeyIsExternal) {
|
||||
let isPersonal = false;
|
||||
let senderKeySecretAvailable = this.getSecretAvailableFromHandle(
|
||||
senderKey
|
||||
);
|
||||
if (senderKeySecretAvailable) {
|
||||
let senderFpr = this.getFingerprintFromHandle(senderKey);
|
||||
isPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(senderFpr);
|
||||
}
|
||||
if (!isPersonal) {
|
||||
throw new Error(
|
||||
"configured sender key " +
|
||||
args.sender +
|
||||
" isn't accepted as a personal key"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.encryptToSender) {
|
||||
this.addSuitableEncryptKey(senderKey, op);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ var EnigmailConstants = {
|
|||
SEND_ATTACHMENT: 0x0800, // 2048
|
||||
ENCRYPT_HEADERS: 0x1000, // 4096
|
||||
SEND_VERBATIM: 0x2000, // 8192
|
||||
SEND_TWO_MIME_LAYERS: 0x4000, // 16384
|
||||
SEND_SENDER_KEY_EXTERNAL: 0x8000, // 32768
|
||||
|
||||
/* Status flags */
|
||||
GOOD_SIGNATURE: 0x00000001,
|
||||
|
|
|
@ -20,21 +20,12 @@ const { EnigmailLog } = ChromeUtils.import(
|
|||
const { EnigmailPrefs } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/prefs.jsm"
|
||||
);
|
||||
const { EnigmailApp } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/app.jsm"
|
||||
);
|
||||
const { EnigmailDialog } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/dialog.jsm"
|
||||
);
|
||||
const { EnigmailGpg } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/gpg.jsm"
|
||||
);
|
||||
const { EnigmailErrorHandling } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/errorHandling.jsm"
|
||||
);
|
||||
const { EnigmailFiles } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/files.jsm"
|
||||
);
|
||||
const { EnigmailFuncs } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/funcs.jsm"
|
||||
);
|
||||
|
@ -65,160 +56,8 @@ const gMimeHashAlgorithms = [
|
|||
|
||||
const ENC_TYPE_MSG = 0;
|
||||
const ENC_TYPE_ATTACH_BINARY = 1;
|
||||
const ENC_TYPE_ATTACH_ASCII = 2;
|
||||
|
||||
const GPG_COMMENT_OPT =
|
||||
"Using GnuPG with %s - https://doesnotexist-openpgp-integration.thunderbird/";
|
||||
|
||||
var EnigmailEncryption = {
|
||||
getEncryptCommand(
|
||||
fromMailAddr,
|
||||
toMailAddr,
|
||||
bccMailAddr,
|
||||
hashAlgorithm,
|
||||
sendFlags,
|
||||
isAscii,
|
||||
errorMsgObj,
|
||||
logFileObj
|
||||
) {
|
||||
EnigmailLog.DEBUG(
|
||||
"encryption.jsm: getEncryptCommand: hashAlgorithm=" + hashAlgorithm + "\n"
|
||||
);
|
||||
|
||||
try {
|
||||
fromMailAddr = EnigmailFuncs.stripEmail(fromMailAddr);
|
||||
toMailAddr = EnigmailFuncs.stripEmail(toMailAddr);
|
||||
bccMailAddr = EnigmailFuncs.stripEmail(bccMailAddr);
|
||||
} catch (ex) {
|
||||
errorMsgObj.value = l10n.formatValueSync("invalid-email");
|
||||
return null;
|
||||
}
|
||||
|
||||
var signMsg = sendFlags & EnigmailConstants.SEND_SIGNED;
|
||||
var encryptMsg = sendFlags & EnigmailConstants.SEND_ENCRYPTED;
|
||||
var usePgpMime = sendFlags & EnigmailConstants.SEND_PGP_MIME;
|
||||
|
||||
var useDefaultComment = false;
|
||||
try {
|
||||
useDefaultComment = EnigmailPrefs.getPref("useDefaultComment");
|
||||
} catch (ex) {}
|
||||
|
||||
var hushMailSupport = false;
|
||||
try {
|
||||
hushMailSupport = EnigmailPrefs.getPref("hushMailSupport");
|
||||
} catch (ex) {}
|
||||
|
||||
var detachedSig =
|
||||
(usePgpMime || sendFlags & EnigmailConstants.SEND_ATTACHMENT) &&
|
||||
signMsg &&
|
||||
!encryptMsg;
|
||||
|
||||
var toAddrList = toMailAddr.split(/\s*,\s*/);
|
||||
var bccAddrList = bccMailAddr.split(/\s*,\s*/);
|
||||
var k;
|
||||
|
||||
var encryptArgs = EnigmailGpg.getStandardArgs(true);
|
||||
|
||||
if (!useDefaultComment) {
|
||||
encryptArgs = encryptArgs.concat([
|
||||
"--comment",
|
||||
GPG_COMMENT_OPT.replace(/%s/, EnigmailApp.getName()),
|
||||
]);
|
||||
}
|
||||
|
||||
var angledFromMailAddr =
|
||||
fromMailAddr.search(/^0x/) === 0 || hushMailSupport
|
||||
? fromMailAddr
|
||||
: "<" + fromMailAddr + ">";
|
||||
angledFromMailAddr = angledFromMailAddr.replace(/(["'`])/g, "\\$1");
|
||||
|
||||
if (signMsg && hashAlgorithm) {
|
||||
encryptArgs = encryptArgs.concat(["--digest-algo", hashAlgorithm]);
|
||||
}
|
||||
|
||||
if (logFileObj) {
|
||||
logFileObj.value = EnigmailErrorHandling.getTempLogFile();
|
||||
encryptArgs.push("--log-file");
|
||||
encryptArgs.push(
|
||||
EnigmailFiles.getEscapedFilename(
|
||||
EnigmailFiles.getFilePath(logFileObj.value)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (encryptMsg) {
|
||||
switch (isAscii) {
|
||||
case ENC_TYPE_MSG:
|
||||
encryptArgs.push("-a");
|
||||
encryptArgs.push("-t");
|
||||
break;
|
||||
case ENC_TYPE_ATTACH_ASCII:
|
||||
encryptArgs.push("-a");
|
||||
}
|
||||
|
||||
encryptArgs.push("--encrypt");
|
||||
|
||||
if (signMsg) {
|
||||
encryptArgs.push("--sign");
|
||||
}
|
||||
|
||||
if (sendFlags & EnigmailConstants.SEND_ALWAYS_TRUST) {
|
||||
encryptArgs.push("--trust-model");
|
||||
encryptArgs.push("always");
|
||||
}
|
||||
if (sendFlags & EnigmailConstants.SEND_ENCRYPT_TO_SELF && fromMailAddr) {
|
||||
encryptArgs = encryptArgs.concat(["--encrypt-to", angledFromMailAddr]);
|
||||
}
|
||||
|
||||
for (k = 0; k < toAddrList.length; k++) {
|
||||
toAddrList[k] = toAddrList[k].replace(/'/g, "\\'");
|
||||
if (toAddrList[k].length > 0) {
|
||||
encryptArgs.push("-r");
|
||||
if (toAddrList[k].search(/^GROUP:/) === 0) {
|
||||
// groups from gpg.conf file
|
||||
encryptArgs.push(toAddrList[k].substr(6));
|
||||
} else {
|
||||
encryptArgs.push(
|
||||
hushMailSupport || toAddrList[k].search(/^0x/) === 0
|
||||
? toAddrList[k]
|
||||
: "<" + toAddrList[k] + ">"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < bccAddrList.length; k++) {
|
||||
bccAddrList[k] = bccAddrList[k].replace(/'/g, "\\'");
|
||||
if (bccAddrList[k].length > 0) {
|
||||
encryptArgs.push("--hidden-recipient");
|
||||
encryptArgs.push(
|
||||
hushMailSupport || bccAddrList[k].search(/^0x/) === 0
|
||||
? bccAddrList[k]
|
||||
: "<" + bccAddrList[k] + ">"
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (detachedSig) {
|
||||
encryptArgs = encryptArgs.concat(["-s", "-b"]);
|
||||
|
||||
switch (isAscii) {
|
||||
case ENC_TYPE_MSG:
|
||||
encryptArgs = encryptArgs.concat(["-a", "-t"]);
|
||||
break;
|
||||
case ENC_TYPE_ATTACH_ASCII:
|
||||
encryptArgs.push("-a");
|
||||
}
|
||||
} else if (signMsg) {
|
||||
encryptArgs = encryptArgs.concat(["-t", "--clearsign"]);
|
||||
}
|
||||
|
||||
if (fromMailAddr) {
|
||||
encryptArgs = encryptArgs.concat(["-u", angledFromMailAddr]);
|
||||
}
|
||||
|
||||
return encryptArgs;
|
||||
},
|
||||
|
||||
getCryptParams(
|
||||
fromMailAddr,
|
||||
toMailAddr,
|
||||
|
@ -238,6 +77,7 @@ var EnigmailEncryption = {
|
|||
result.encrypt = false;
|
||||
result.encryptToSender = false;
|
||||
result.armor = false;
|
||||
result.senderKeyIsExternal = false;
|
||||
|
||||
EnigmailLog.DEBUG(
|
||||
"encryption.jsm: getCryptParams: hashAlgorithm=" + hashAlgorithm + "\n"
|
||||
|
@ -262,6 +102,10 @@ var EnigmailEncryption = {
|
|||
var encryptMsg = sendFlags & EnigmailConstants.SEND_ENCRYPTED;
|
||||
var usePgpMime = sendFlags & EnigmailConstants.SEND_PGP_MIME;
|
||||
|
||||
if (sendFlags & EnigmailConstants.SEND_SENDER_KEY_EXTERNAL) {
|
||||
result.senderKeyIsExternal = true;
|
||||
}
|
||||
|
||||
var detachedSig =
|
||||
(usePgpMime || sendFlags & EnigmailConstants.SEND_ATTACHMENT) &&
|
||||
signMsg &&
|
||||
|
@ -346,7 +190,7 @@ var EnigmailEncryption = {
|
|||
* - keyId: String - the found key ID, or null if fromMailAddr is not valid
|
||||
* - errorMsg: String - the erorr message if key not valid, or null if key is valid
|
||||
*/
|
||||
async determineOwnKeyUsability(sendFlags, fromKeyId) {
|
||||
async determineOwnKeyUsability(sendFlags, fromKeyId, isExternalGnuPG) {
|
||||
EnigmailLog.DEBUG(
|
||||
"encryption.jsm: determineOwnKeyUsability: sendFlags=" +
|
||||
sendFlags +
|
||||
|
@ -372,12 +216,13 @@ var EnigmailEncryption = {
|
|||
foundKey = EnigmailKeyRing.getKeyById(fromKeyId);
|
||||
}
|
||||
|
||||
// even for isExternalGnuPG we require that the public key is available
|
||||
if (!foundKey) {
|
||||
ret.errorMsg = EnigmailErrorHandling.determineInvSignReason(fromKeyId);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (foundKey.secretAvailable) {
|
||||
if (!isExternalGnuPG && foundKey.secretAvailable) {
|
||||
let isPersonal = await PgpSqliteDb2.isAcceptedAsPersonalKey(foundKey.fpr);
|
||||
if (!isPersonal) {
|
||||
ret.errorMsg = l10n.formatValueSync(
|
||||
|
@ -392,7 +237,10 @@ var EnigmailEncryption = {
|
|||
|
||||
let canSign = false;
|
||||
let canEncrypt = false;
|
||||
if (sign) {
|
||||
|
||||
if (isExternalGnuPG) {
|
||||
canSign = true;
|
||||
} else if (sign) {
|
||||
if (foundKey && foundKey.getSigningValidity().keyValid) {
|
||||
canSign = true;
|
||||
}
|
||||
|
@ -458,7 +306,7 @@ var EnigmailEncryption = {
|
|||
"encryption.jsm: encryptMessageStart: NO ENCRYPTION!\n"
|
||||
);
|
||||
errorMsgObj.value = l10n.formatValueSync("not-required");
|
||||
return null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!EnigmailCore.getService(win)) {
|
||||
|
@ -469,8 +317,6 @@ var EnigmailEncryption = {
|
|||
|
||||
let logFileObj = {};
|
||||
|
||||
// GnuPG
|
||||
// let encryptArgs = EnigmailEncryption.getEncryptCommand(fromMailAddr, toMailAddr, bccMailAddr, hashAlgo, sendFlags, ENC_TYPE_MSG, errorMsgObj, logFileObj);
|
||||
let encryptArgs = EnigmailEncryption.getCryptParams(
|
||||
fromMailAddr,
|
||||
toMailAddr,
|
||||
|
@ -483,29 +329,18 @@ var EnigmailEncryption = {
|
|||
);
|
||||
|
||||
if (!encryptArgs) {
|
||||
return null;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!listener) {
|
||||
listener = {};
|
||||
throw new Error("unexpected no listener");
|
||||
}
|
||||
if ("done" in listener) {
|
||||
listener.outerDone = listener.done;
|
||||
}
|
||||
|
||||
listener.done = function(exitCode) {
|
||||
EnigmailErrorHandling.appendLogFileToDebug(logFileObj.value);
|
||||
if (this.outerDone) {
|
||||
this.outerDone(exitCode);
|
||||
}
|
||||
};
|
||||
|
||||
let resultStatus = {};
|
||||
const cApi = EnigmailCryptoAPI();
|
||||
console.debug("listener: %o", listener);
|
||||
let encrypted = cApi.sync(
|
||||
cApi.encryptAndOrSign(
|
||||
listener.getInputForEncryption(),
|
||||
listener.getInputForCrypto(),
|
||||
encryptArgs,
|
||||
resultStatus
|
||||
)
|
||||
|
@ -516,107 +351,18 @@ var EnigmailEncryption = {
|
|||
EnigmailDialog.alert(win, resultStatus.errorMsg);
|
||||
}
|
||||
} else if (encrypted) {
|
||||
listener.addEncryptedOutput(encrypted);
|
||||
listener.addCryptoOutput(encrypted);
|
||||
}
|
||||
|
||||
listener.done(resultStatus.exitCode);
|
||||
return null;
|
||||
},
|
||||
|
||||
encryptMessageEnd(
|
||||
fromMailAddr,
|
||||
stderrStr,
|
||||
exitCode,
|
||||
uiFlags,
|
||||
sendFlags,
|
||||
outputLen,
|
||||
retStatusObj
|
||||
) {
|
||||
EnigmailLog.DEBUG(
|
||||
"encryption.jsm: encryptMessageEnd: uiFlags=" +
|
||||
uiFlags +
|
||||
", sendFlags=" +
|
||||
EnigmailData.bytesToHex(EnigmailData.pack(sendFlags, 4)) +
|
||||
", outputLen=" +
|
||||
outputLen +
|
||||
"\n"
|
||||
EnigmailErrorHandling.appendLogFileToDebug(logFileObj.value);
|
||||
console.debug(
|
||||
"sendFlags=" + EnigmailData.bytesToHex(EnigmailData.pack(sendFlags, 4))
|
||||
);
|
||||
|
||||
var signMsg = sendFlags & EnigmailConstants.SEND_SIGNED;
|
||||
var encryptMsg = sendFlags & EnigmailConstants.SEND_ENCRYPTED;
|
||||
|
||||
retStatusObj.statusFlags = 0;
|
||||
retStatusObj.errorMsg = "";
|
||||
retStatusObj.blockSeparation = "";
|
||||
|
||||
if (!EnigmailCore.getService().initialized) {
|
||||
throw new Error("encryption.jsm: encryptMessageEnd: not yet initialized");
|
||||
if (resultStatus.exitCode === 0 && !listener.getCryptoOutputLength()) {
|
||||
resultStatus.exitCode = -1;
|
||||
}
|
||||
|
||||
//EnigmailErrorHandling.parseErrorOutput(stderrStr, retStatusObj);
|
||||
|
||||
//exitCode = EnigmailExecution.fixExitCode(exitCode, retStatusObj);
|
||||
if (exitCode === 0 && !outputLen) {
|
||||
exitCode = -1;
|
||||
}
|
||||
|
||||
if (exitCode !== 0 && (signMsg || encryptMsg)) {
|
||||
// GnuPG might return a non-zero exit code, even though the message was correctly
|
||||
// signed or encryped -> try to fix the exit code
|
||||
|
||||
var correctedExitCode = 0;
|
||||
if (signMsg) {
|
||||
if (!(retStatusObj.statusFlags & EnigmailConstants.SIG_CREATED)) {
|
||||
correctedExitCode = exitCode;
|
||||
}
|
||||
}
|
||||
if (encryptMsg) {
|
||||
if (!(retStatusObj.statusFlags & EnigmailConstants.END_ENCRYPTION)) {
|
||||
correctedExitCode = exitCode;
|
||||
}
|
||||
}
|
||||
exitCode = correctedExitCode;
|
||||
}
|
||||
|
||||
EnigmailLog.DEBUG(
|
||||
"encryption.jsm: encryptMessageEnd: command execution exit code: " +
|
||||
exitCode +
|
||||
"\n"
|
||||
);
|
||||
|
||||
/*
|
||||
if (retStatusObj.statusFlags & EnigmailConstants.DISPLAY_MESSAGE) {
|
||||
if (retStatusObj.extendedStatus.search(/\bdisp:/) >= 0) {
|
||||
retStatusObj.errorMsg = retStatusObj.statusMsg;
|
||||
} else {
|
||||
if (fromMailAddr.search(/^0x/) === 0) {
|
||||
fromMailAddr = fromMailAddr.substr(2);
|
||||
}
|
||||
if (fromMailAddr.search(/^[A-F0-9]{8,40}$/i) === 0) {
|
||||
fromMailAddr = "[A-F0-9]+" + fromMailAddr;
|
||||
}
|
||||
|
||||
let s = new RegExp(
|
||||
"^(\\[GNUPG:\\] )?INV_(RECP|SGNR) [0-9]+ (\\<|0x)?" +
|
||||
fromMailAddr +
|
||||
"\\>?",
|
||||
"m"
|
||||
);
|
||||
if (retStatusObj.statusMsg.search(s) >= 0) {
|
||||
retStatusObj.errorMsg +=
|
||||
"\n\n" + EnigmailLocale.getString("keyError.resolutionAction");
|
||||
} else if (retStatusObj.statusMsg.length > 0) {
|
||||
retStatusObj.errorMsg = retStatusObj.statusMsg;
|
||||
}
|
||||
}
|
||||
} else if (retStatusObj.statusFlags & EnigmailConstants.INVALID_RECIPIENT) {
|
||||
retStatusObj.errorMsg = retStatusObj.statusMsg;
|
||||
} else if (exitCode !== 0) {
|
||||
retStatusObj.errorMsg = EnigmailLocale.getString("badCommand");
|
||||
}
|
||||
*/
|
||||
|
||||
return exitCode;
|
||||
return resultStatus.exitCode;
|
||||
},
|
||||
|
||||
encryptMessage(
|
||||
|
|
|
@ -20,9 +20,6 @@ const { EnigmailCompat } = ChromeUtils.import(
|
|||
const { EnigmailFuncs } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/funcs.jsm"
|
||||
);
|
||||
const { EnigmailDialog } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/dialog.jsm"
|
||||
);
|
||||
const { EnigmailLog } = ChromeUtils.import(
|
||||
"chrome://openpgp/content/modules/log.jsm"
|
||||
);
|
||||
|
@ -49,8 +46,9 @@ const PGPMIME_ENCRYPT_CID = Components.ID(
|
|||
const PGPMIME_ENCRYPT_CONTRACTID = "@enigmail.net/compose/mimeencrypt;1";
|
||||
|
||||
const maxBufferLen = 102400;
|
||||
const MIME_SIGNED = 1;
|
||||
const MIME_ENCRYPTED = 2;
|
||||
const MIME_SIGNED = 1; // only one MIME layer
|
||||
const MIME_ENCRYPTED = 2; // only one MIME layer, combined enc/sig data
|
||||
const MIME_OUTER_ENC_INNER_SIG = 3; // use two MIME layers
|
||||
|
||||
var gDebugLogLevel = 1;
|
||||
|
||||
|
@ -105,21 +103,19 @@ PgpMimeEncrypt.prototype = {
|
|||
// 1: processing body
|
||||
// 2: skipping header
|
||||
inputMode: 0,
|
||||
dataLength: 0,
|
||||
headerData: "",
|
||||
encapsulate: null,
|
||||
encHeader: null,
|
||||
cryptoBoundary: null,
|
||||
outerBoundary: null,
|
||||
innerBoundary: null,
|
||||
win: null,
|
||||
pipe: null,
|
||||
proc: null,
|
||||
statusStr: "",
|
||||
encryptedData: "",
|
||||
hashAlgorithm: null,
|
||||
pipeQueue: "",
|
||||
outQueue: "",
|
||||
closePipe: false,
|
||||
cryptoMode: 0,
|
||||
//statusStr: "",
|
||||
cryptoOutputLength: 0,
|
||||
cryptoOutput: "",
|
||||
hashAlgorithm: "SHA256", // TODO: coordinate with RNP.jsm
|
||||
cryptoInputBuffer: "",
|
||||
outgoingMessageBuffer: "",
|
||||
mimeStructure: 0,
|
||||
exitCode: -1,
|
||||
inspector: null,
|
||||
checkSMime: true,
|
||||
|
@ -222,16 +218,20 @@ PgpMimeEncrypt.prototype = {
|
|||
if (this.sendFlags & EnigmailConstants.SEND_PGP_MIME) {
|
||||
if (this.sendFlags & EnigmailConstants.SEND_ENCRYPTED) {
|
||||
// applies to encrypted and signed & encrypted
|
||||
this.cryptoMode = MIME_ENCRYPTED;
|
||||
if (this.sendFlags & EnigmailConstants.SEND_TWO_MIME_LAYERS) {
|
||||
this.mimeStructure = MIME_OUTER_ENC_INNER_SIG;
|
||||
this.innerBoundary = EnigmailMime.createBoundary();
|
||||
} else {
|
||||
this.mimeStructure = MIME_ENCRYPTED;
|
||||
}
|
||||
} else if (this.sendFlags & EnigmailConstants.SEND_SIGNED) {
|
||||
this.cryptoMode = MIME_SIGNED;
|
||||
this.hashAlgorithm = "SHA256"; // TODO: coordinate with RNP.jsm
|
||||
this.mimeStructure = MIME_SIGNED;
|
||||
}
|
||||
} else {
|
||||
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
this.cryptoBoundary = EnigmailMime.createBoundary();
|
||||
this.outerBoundary = EnigmailMime.createBoundary();
|
||||
this.startCryptoHeaders();
|
||||
} catch (ex) {
|
||||
console.debug(ex);
|
||||
|
@ -245,11 +245,14 @@ PgpMimeEncrypt.prototype = {
|
|||
startCryptoHeaders() {
|
||||
EnigmailLog.DEBUG("mimeEncrypt.js: startCryptoHeaders\n");
|
||||
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
this.signedHeaders1(false);
|
||||
}
|
||||
if (this.cryptoMode == MIME_ENCRYPTED) {
|
||||
this.encryptedHeaders();
|
||||
switch (this.mimeStructure) {
|
||||
case MIME_SIGNED:
|
||||
this.signedHeaders1(false);
|
||||
break;
|
||||
case MIME_ENCRYPTED:
|
||||
case MIME_OUTER_ENC_INNER_SIG:
|
||||
this.encryptedHeaders();
|
||||
break;
|
||||
}
|
||||
|
||||
this.writeSecureHeaders();
|
||||
|
@ -315,7 +318,8 @@ PgpMimeEncrypt.prototype = {
|
|||
}
|
||||
|
||||
if (
|
||||
this.cryptoMode == MIME_ENCRYPTED &&
|
||||
(this.mimeStructure == MIME_ENCRYPTED ||
|
||||
this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) &&
|
||||
this.originalSubject &&
|
||||
this.originalSubject.length > 0
|
||||
) {
|
||||
|
@ -355,17 +359,18 @@ PgpMimeEncrypt.prototype = {
|
|||
}
|
||||
|
||||
w += this.getAutocryptGossip() + `\r\n--${this.encHeader}\r\n`;
|
||||
this.writeToPipe(w);
|
||||
this.appendToCryptoInput(w);
|
||||
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
this.writeOut(w);
|
||||
if (this.mimeStructure == MIME_SIGNED) {
|
||||
this.appendToMessage(w);
|
||||
}
|
||||
},
|
||||
|
||||
getAutocryptGossip() {
|
||||
let gossip = "";
|
||||
if (
|
||||
this.cryptoMode == MIME_ENCRYPTED &&
|
||||
(this.mimeStructure == MIME_ENCRYPTED ||
|
||||
this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) &&
|
||||
this.msgCompFields.hasHeader("autocrypt") &&
|
||||
this.keyMap &&
|
||||
EnigmailFuncs.getNumberOfRecipients(this.msgCompFields) > 1
|
||||
|
@ -392,7 +397,7 @@ PgpMimeEncrypt.prototype = {
|
|||
return gossip;
|
||||
},
|
||||
|
||||
encryptedHeaders(isEightBit) {
|
||||
encryptedHeaders(isEightBit = false) {
|
||||
EnigmailLog.DEBUG("mimeEncrypt.js: encryptedHeaders\n");
|
||||
let subj = "";
|
||||
|
||||
|
@ -403,18 +408,17 @@ PgpMimeEncrypt.prototype = {
|
|||
{}
|
||||
);
|
||||
}
|
||||
|
||||
this.writeOut(
|
||||
this.appendToMessage(
|
||||
subj +
|
||||
"Content-Type: multipart/encrypted;\r\n" +
|
||||
' protocol="application/pgp-encrypted";\r\n' +
|
||||
' boundary="' +
|
||||
this.cryptoBoundary +
|
||||
this.outerBoundary +
|
||||
'"\r\n' +
|
||||
"\r\n" +
|
||||
"This is an OpenPGP/MIME encrypted message (RFC 4880 and 3156)\r\n" +
|
||||
"--" +
|
||||
this.cryptoBoundary +
|
||||
this.outerBoundary +
|
||||
"\r\n" +
|
||||
"Content-Type: application/pgp-encrypted\r\n" +
|
||||
"Content-Description: PGP/MIME version identification\r\n" +
|
||||
|
@ -422,7 +426,7 @@ PgpMimeEncrypt.prototype = {
|
|||
"Version: 1\r\n" +
|
||||
"\r\n" +
|
||||
"--" +
|
||||
this.cryptoBoundary +
|
||||
this.outerBoundary +
|
||||
"\r\n" +
|
||||
'Content-Type: application/octet-stream; name="encrypted.asc"\r\n' +
|
||||
"Content-Description: OpenPGP encrypted message\r\n" +
|
||||
|
@ -431,41 +435,60 @@ PgpMimeEncrypt.prototype = {
|
|||
);
|
||||
},
|
||||
|
||||
signedHeaders1(isEightBit) {
|
||||
signedHeaders1(isEightBit = false) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: signedHeaders1\n");
|
||||
this.writeOut(
|
||||
let boundary;
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
boundary = this.innerBoundary;
|
||||
} else {
|
||||
boundary = this.outerBoundary;
|
||||
}
|
||||
let sigHeader =
|
||||
"Content-Type: multipart/signed; micalg=pgp-" +
|
||||
this.hashAlgorithm.toLowerCase() +
|
||||
";\r\n" +
|
||||
' protocol="application/pgp-signature";\r\n' +
|
||||
' boundary="' +
|
||||
this.cryptoBoundary +
|
||||
'"\r\n' +
|
||||
(isEightBit ? "Content-Transfer-Encoding: 8bit\r\n\r\n" : "\r\n") +
|
||||
"This is an OpenPGP/MIME signed message (RFC 4880 and 3156)\r\n" +
|
||||
"--" +
|
||||
this.cryptoBoundary +
|
||||
"\r\n"
|
||||
);
|
||||
this.hashAlgorithm.toLowerCase() +
|
||||
";\r\n" +
|
||||
' protocol="application/pgp-signature";\r\n' +
|
||||
' boundary="' +
|
||||
boundary +
|
||||
'"\r\n' +
|
||||
(isEightBit ? "Content-Transfer-Encoding: 8bit\r\n\r\n" : "\r\n") +
|
||||
"This is an OpenPGP/MIME signed message (RFC 4880 and 3156)\r\n" +
|
||||
"--" +
|
||||
boundary +
|
||||
"\r\n";
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
this.appendToCryptoInput(sigHeader);
|
||||
} else {
|
||||
this.appendToMessage(sigHeader);
|
||||
}
|
||||
},
|
||||
|
||||
signedHeaders2() {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: signedHeaders2\n");
|
||||
|
||||
this.writeOut(
|
||||
let boundary;
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
boundary = this.innerBoundary;
|
||||
} else {
|
||||
boundary = this.outerBoundary;
|
||||
}
|
||||
let sigHeader =
|
||||
"\r\n--" +
|
||||
this.cryptoBoundary +
|
||||
"\r\n" +
|
||||
'Content-Type: application/pgp-signature; name="OpenPGP_signature.asc"\r\n' +
|
||||
"Content-Description: OpenPGP digital signature\r\n" +
|
||||
'Content-Disposition: attachment; filename="OpenPGP_signature"\r\n\r\n'
|
||||
);
|
||||
boundary +
|
||||
"\r\n" +
|
||||
'Content-Type: application/pgp-signature; name="OpenPGP_signature.asc"\r\n' +
|
||||
"Content-Description: OpenPGP digital signature\r\n" +
|
||||
'Content-Disposition: attachment; filename="OpenPGP_signature"\r\n\r\n';
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
this.appendToCryptoInput(sigHeader);
|
||||
} else {
|
||||
this.appendToMessage(sigHeader);
|
||||
}
|
||||
},
|
||||
|
||||
finishCryptoHeaders() {
|
||||
EnigmailLog.DEBUG("mimeEncrypt.js: finishCryptoHeaders\n");
|
||||
|
||||
this.writeOut("\r\n--" + this.cryptoBoundary + "--\r\n");
|
||||
this.appendToMessage("\r\n--" + this.outerBoundary + "--\r\n");
|
||||
},
|
||||
|
||||
finishCryptoEncapsulation(abort, sendReport) {
|
||||
|
@ -486,48 +509,76 @@ PgpMimeEncrypt.prototype = {
|
|||
}
|
||||
|
||||
if (this.encapsulate) {
|
||||
this.writeToPipe("--" + this.encapsulate + "--\r\n");
|
||||
this.appendToCryptoInput("--" + this.encapsulate + "--\r\n");
|
||||
}
|
||||
|
||||
if (this.encHeader) {
|
||||
this.writeToPipe("\r\n--" + this.encHeader + "--\r\n");
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
this.writeOut("\r\n--" + this.encHeader + "--\r\n");
|
||||
this.appendToCryptoInput("\r\n--" + this.encHeader + "--\r\n");
|
||||
if (this.mimeStructure == MIME_SIGNED) {
|
||||
this.appendToMessage("\r\n--" + this.encHeader + "--\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
let statusFlagsObj = {};
|
||||
let errorMsgObj = {};
|
||||
EnigmailEncryption.encryptMessageStart(
|
||||
this.win,
|
||||
this.UIFlags,
|
||||
this.senderEmailAddr,
|
||||
this.recipients,
|
||||
this.bccRecipients,
|
||||
this.hashAlgorithm,
|
||||
this.sendFlags,
|
||||
this,
|
||||
statusFlagsObj,
|
||||
errorMsgObj
|
||||
);
|
||||
this.exitCode = 0;
|
||||
|
||||
//if (!proc) throw Cr.NS_ERROR_FAILURE;
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
// prepare the inner crypto layer (the signature)
|
||||
let sendFlagsWithoutEncrypt =
|
||||
this.sendFlags & ~EnigmailConstants.SEND_ENCRYPTED;
|
||||
|
||||
this.exitCode = EnigmailEncryption.encryptMessageStart(
|
||||
this.win,
|
||||
this.UIFlags,
|
||||
this.senderEmailAddr,
|
||||
this.recipients,
|
||||
this.bccRecipients,
|
||||
this.hashAlgorithm,
|
||||
sendFlagsWithoutEncrypt,
|
||||
this,
|
||||
statusFlagsObj,
|
||||
errorMsgObj
|
||||
);
|
||||
if (!this.exitCode) {
|
||||
// success
|
||||
let innerSignedMessage = this.cryptoInputBuffer;
|
||||
this.cryptoInputBuffer = "";
|
||||
|
||||
this.signedHeaders1(false);
|
||||
this.appendToCryptoInput(innerSignedMessage);
|
||||
this.signedHeaders2();
|
||||
this.cryptoOutput = this.cryptoOutput
|
||||
.replace(/\r/g, "")
|
||||
.replace(/\n/g, "\r\n"); // force CRLF
|
||||
this.appendToCryptoInput(this.cryptoOutput);
|
||||
this.appendToCryptoInput("\r\n--" + this.innerBoundary + "--\r\n");
|
||||
this.cryptoOutput = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.exitCode) {
|
||||
// no failure yet
|
||||
let encryptionFlags = this.sendFlags;
|
||||
if (this.mimeStructure == MIME_OUTER_ENC_INNER_SIG) {
|
||||
// remove signature flag, because we already signed
|
||||
encryptionFlags = encryptionFlags & ~EnigmailConstants.SEND_SIGNED;
|
||||
}
|
||||
this.exitCode = EnigmailEncryption.encryptMessageStart(
|
||||
this.win,
|
||||
this.UIFlags,
|
||||
this.senderEmailAddr,
|
||||
this.recipients,
|
||||
this.bccRecipients,
|
||||
this.hashAlgorithm,
|
||||
encryptionFlags,
|
||||
this,
|
||||
statusFlagsObj,
|
||||
errorMsgObj
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
this.flushInput();
|
||||
|
||||
/*
|
||||
if (!this.pipe) {
|
||||
this.closePipe = true;
|
||||
}
|
||||
else {
|
||||
this.pipe.close();
|
||||
}
|
||||
*/
|
||||
|
||||
// wait here for proc to terminate
|
||||
//proc.wait();
|
||||
|
||||
LOCAL_DEBUG(
|
||||
"mimeEncrypt.js: finishCryptoEncapsulation: exitCode = " +
|
||||
this.exitCode +
|
||||
|
@ -537,14 +588,15 @@ PgpMimeEncrypt.prototype = {
|
|||
throw new Error("failure in finishCryptoEncapsulation");
|
||||
}
|
||||
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
if (this.mimeStructure == MIME_SIGNED) {
|
||||
this.signedHeaders2();
|
||||
}
|
||||
|
||||
this.encryptedData = this.encryptedData
|
||||
this.cryptoOutput = this.cryptoOutput
|
||||
.replace(/\r/g, "")
|
||||
.replace(/\n/g, "\r\n"); // force CRLF
|
||||
this.writeOut(this.encryptedData);
|
||||
|
||||
this.appendToMessage(this.cryptoOutput);
|
||||
this.finishCryptoHeaders();
|
||||
this.flushOutput();
|
||||
} catch (ex) {
|
||||
|
@ -586,7 +638,10 @@ PgpMimeEncrypt.prototype = {
|
|||
if (line.replace(/[\r\n]/g, "").length === 0) {
|
||||
this.inputMode = 1;
|
||||
|
||||
if (this.cryptoMode == MIME_ENCRYPTED) {
|
||||
if (
|
||||
this.mimeStructure == MIME_ENCRYPTED ||
|
||||
this.mimeStructure == MIME_OUTER_ENC_INNER_SIG
|
||||
) {
|
||||
if (!this.encHeader) {
|
||||
let ct = this.getHeader("content-type", false);
|
||||
if (
|
||||
|
@ -594,43 +649,43 @@ PgpMimeEncrypt.prototype = {
|
|||
ct.search(/text\/html/i) === 0
|
||||
) {
|
||||
this.encapsulate = EnigmailMime.createBoundary();
|
||||
this.writeToPipe(
|
||||
this.appendToCryptoInput(
|
||||
'Content-Type: multipart/mixed; boundary="' +
|
||||
this.encapsulate +
|
||||
'"\r\n\r\n'
|
||||
);
|
||||
this.writeToPipe("--" + this.encapsulate + "\r\n");
|
||||
this.appendToCryptoInput("--" + this.encapsulate + "\r\n");
|
||||
}
|
||||
}
|
||||
} else if (this.cryptoMode == MIME_SIGNED) {
|
||||
} else if (this.mimeStructure == MIME_SIGNED) {
|
||||
let ct = this.getHeader("content-type", true);
|
||||
let hdr = EnigmailFuncs.getHeaderData(ct);
|
||||
hdr.boundary = hdr.boundary || "";
|
||||
hdr.boundary = hdr.boundary.replace(/['"]/g, "");
|
||||
}
|
||||
|
||||
this.writeToPipe(this.headerData);
|
||||
this.appendToCryptoInput(this.headerData);
|
||||
if (
|
||||
this.cryptoMode == MIME_SIGNED ||
|
||||
this.mimeStructure == MIME_SIGNED ||
|
||||
(this.sendFlags & EnigmailConstants.SEND_VERBATIM) !== 0
|
||||
) {
|
||||
this.writeOut(this.headerData);
|
||||
this.appendToMessage(this.headerData);
|
||||
}
|
||||
}
|
||||
} else if (this.inputMode == 1) {
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
if (this.mimeStructure == MIME_SIGNED) {
|
||||
// special treatments for various special cases with PGP/MIME signed messages
|
||||
if (line.substr(0, 5) == "From ") {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: added >From\n");
|
||||
this.writeToPipe(">");
|
||||
this.appendToCryptoInput(">");
|
||||
}
|
||||
}
|
||||
|
||||
this.writeToPipe(line);
|
||||
if (this.cryptoMode == MIME_SIGNED) {
|
||||
this.writeOut(line);
|
||||
this.appendToCryptoInput(line);
|
||||
if (this.mimeStructure == MIME_SIGNED) {
|
||||
this.appendToMessage(line);
|
||||
} else if ((this.sendFlags & EnigmailConstants.SEND_VERBATIM) !== 0) {
|
||||
this.writeOut(
|
||||
this.appendToMessage(
|
||||
EnigmailData.decodeQuotedPrintable(line.replace("=\r\n", ""))
|
||||
);
|
||||
}
|
||||
|
@ -648,60 +703,49 @@ PgpMimeEncrypt.prototype = {
|
|||
return null;
|
||||
},
|
||||
|
||||
writeOut(str) {
|
||||
appendToMessage(str) {
|
||||
if (gDebugLogLevel > 4) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: writeOut: " + str.length + "\n");
|
||||
LOCAL_DEBUG("mimeEncrypt.js: appendToMessage: " + str.length + "\n");
|
||||
}
|
||||
|
||||
this.outQueue += str;
|
||||
this.outgoingMessageBuffer += str;
|
||||
|
||||
if (this.outQueue.length > maxBufferLen) {
|
||||
if (this.outgoingMessageBuffer.length > maxBufferLen) {
|
||||
this.flushOutput();
|
||||
}
|
||||
},
|
||||
|
||||
flushOutput() {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: flushOutput: " + this.outQueue.length + "\n");
|
||||
LOCAL_DEBUG(
|
||||
"mimeEncrypt.js: flushOutput: " + this.outgoingMessageBuffer.length + "\n"
|
||||
);
|
||||
|
||||
this.outStringStream.setData(this.outQueue, this.outQueue.length);
|
||||
this.outStringStream.setData(
|
||||
this.outgoingMessageBuffer,
|
||||
this.outgoingMessageBuffer.length
|
||||
);
|
||||
var writeCount = this.outStream.writeFrom(
|
||||
this.outStringStream,
|
||||
this.outQueue.length
|
||||
this.outgoingMessageBuffer.length
|
||||
);
|
||||
if (writeCount < this.outQueue.length) {
|
||||
if (writeCount < this.outgoingMessageBuffer.length) {
|
||||
LOCAL_DEBUG(
|
||||
"mimeEncrypt.js: flushOutput: wrote " +
|
||||
writeCount +
|
||||
" instead of " +
|
||||
this.outQueue.length +
|
||||
this.outgoingMessageBuffer.length +
|
||||
" bytes\n"
|
||||
);
|
||||
}
|
||||
this.outQueue = "";
|
||||
this.outgoingMessageBuffer = "";
|
||||
},
|
||||
|
||||
writeToPipe(str) {
|
||||
appendToCryptoInput(str) {
|
||||
if (gDebugLogLevel > 4) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: writeToPipe: " + str.length + "\n");
|
||||
LOCAL_DEBUG("mimeEncrypt.js: appendToCryptoInput: " + str.length + "\n");
|
||||
}
|
||||
|
||||
if (this.pipe) {
|
||||
this.pipeQueue += str;
|
||||
if (this.pipeQueue.length > maxBufferLen) {
|
||||
this.flushInput();
|
||||
}
|
||||
} else {
|
||||
this.pipeQueue += str;
|
||||
}
|
||||
},
|
||||
|
||||
flushInput() {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: flushInput\n");
|
||||
if (!this.pipe) {
|
||||
return;
|
||||
}
|
||||
this.pipe.write(this.pipeQueue);
|
||||
this.pipeQueue = "";
|
||||
this.cryptoInputBuffer += str;
|
||||
},
|
||||
|
||||
getHeader(hdrStr, fullHeader) {
|
||||
|
@ -735,59 +779,28 @@ PgpMimeEncrypt.prototype = {
|
|||
return res;
|
||||
},
|
||||
|
||||
getInputForEncryption() {
|
||||
return this.pipeQueue;
|
||||
getInputForCrypto() {
|
||||
return this.cryptoInputBuffer;
|
||||
},
|
||||
|
||||
addEncryptedOutput(s) {
|
||||
this.stdout(s);
|
||||
addCryptoOutput(s) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: addCryptoOutput:" + s.length + "\n");
|
||||
this.cryptoOutput += s;
|
||||
this.cryptoOutputLength += s.length;
|
||||
},
|
||||
|
||||
getCryptoOutputLength() {
|
||||
return this.cryptoOutputLength;
|
||||
},
|
||||
|
||||
// API for decryptMessage Listener
|
||||
stdin(pipe) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: stdin\n");
|
||||
if (this.pipeQueue.length > 0) {
|
||||
pipe.write(this.pipeQueue);
|
||||
this.pipeQueue = "";
|
||||
}
|
||||
if (this.closePipe) {
|
||||
pipe.close();
|
||||
} else {
|
||||
this.pipe = pipe;
|
||||
}
|
||||
},
|
||||
|
||||
stdout(s) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: stdout:" + s.length + "\n");
|
||||
this.encryptedData += s;
|
||||
this.dataLength += s.length;
|
||||
throw new Error("unexpected");
|
||||
},
|
||||
|
||||
stderr(s) {
|
||||
LOCAL_DEBUG("mimeEncrypt.js: stderr\n");
|
||||
this.statusStr += s;
|
||||
},
|
||||
|
||||
done(exitCode) {
|
||||
EnigmailLog.DEBUG("mimeEncrypt.js: done: " + exitCode + "\n");
|
||||
|
||||
let retStatusObj = {};
|
||||
|
||||
this.exitCode = EnigmailEncryption.encryptMessageEnd(
|
||||
this.senderEmailAddr,
|
||||
this.statusStr,
|
||||
exitCode,
|
||||
this.UIFlags,
|
||||
this.sendFlags,
|
||||
this.dataLength,
|
||||
retStatusObj
|
||||
);
|
||||
|
||||
if (this.exitCode !== 0) {
|
||||
if (retStatusObj.errorMsg.length) {
|
||||
EnigmailDialog.alert(this.win, retStatusObj.errorMsg);
|
||||
}
|
||||
}
|
||||
throw new Error("unexpected");
|
||||
//this.statusStr += s;
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -1866,6 +1866,10 @@ Enigmail.msg = {
|
|||
f &= ~EnigmailConstants.SEND_SIGNED;
|
||||
}
|
||||
|
||||
if (gSendEncrypted && gSendSigned) {
|
||||
f |= EnigmailConstants.SEND_TWO_MIME_LAYERS;
|
||||
}
|
||||
|
||||
return f;
|
||||
},
|
||||
|
||||
|
@ -2200,10 +2204,18 @@ Enigmail.msg = {
|
|||
return false;
|
||||
}
|
||||
|
||||
let senderKeyIsGnuPG =
|
||||
Services.prefs.getBoolPref("mail.openpgp.allow_external_gnupg") &&
|
||||
this.identity.getBoolAttribute("is_gnupg_key_id");
|
||||
if (senderKeyIsGnuPG) {
|
||||
sendFlags |= EnigmailConstants.SEND_SENDER_KEY_EXTERNAL;
|
||||
}
|
||||
|
||||
if ((gSendEncrypted || gSendSigned) && senderKeyId) {
|
||||
let senderKeyUsable = await EnigmailEncryption.determineOwnKeyUsability(
|
||||
sendFlags,
|
||||
senderKeyId
|
||||
senderKeyId,
|
||||
senderKeyIsGnuPG
|
||||
);
|
||||
if (senderKeyUsable.errorMsg) {
|
||||
let fullAlert = await document.l10n.formatValue(
|
||||
|
|
Загрузка…
Ссылка в новой задаче