/* 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/. */ /** * Remote content must stay hard-blocked for S/MIME encrypted messages, which do * not enforce integrity protection (bug 1994709, invariant #5) -- unlike * integrity-protected OpenPGP mail, an S/MIME encrypted message never gets the * remote-content override. * * The test message (data/alice.remoteimage.env.eml) is an S/MIME enveloped HTML * message with a remote inside the encrypted body; it is generated by * NSS's tests/smime/smime.sh and copied here by * mailnews/test/data/smime/local-gen.sh. * * The message is viewed in a real folder (not opened from file) so it is * registered with the encrypted-URI service exactly as in normal use. */ "use strict"; const { assert_selected_and_displayed, be_in_folder, create_folder, get_about_message, select_click_row, } = ChromeUtils.importESModule( "resource://testing-common/mail/FolderDisplayHelpers.sys.mjs" ); const { get_notification, wait_for_notification_to_show } = ChromeUtils.importESModule( "resource://testing-common/mail/NotificationBoxHelpers.sys.mjs" ); const { SmimeUtils } = ChromeUtils.importESModule( "resource://testing-common/mailnews/SmimeUtils.sys.mjs" ); const NOTIFICATION_BOX = "mail-notification-top"; const NOTIFICATION_VALUE = "remoteContent"; const DISABLE_PREF = "mailnews.message_display.disable_remote_image"; let folder; let gMsgNo = 0; add_setup(async function () { SmimeUtils.ensureNSS(); SmimeUtils.loadPEMCertificate( new FileUtils.File(getTestFilePath("data/TestCA.pem")), Ci.nsIX509Cert.CA_CERT ); SmimeUtils.loadCertificateAndKey( new FileUtils.File(getTestFilePath("data/Bob.p12")), "nss" ); folder = await create_folder("SMIMERemoteContent"); registerCleanupFunction(async () => { // A later test loading the same certificates would block on a // confirmation prompt. await SmimeUtils.removeCertificates(["NSS Test CA (RSA)", "Bob"]); }); }); async function addAndSelect(eml) { const source = await IOUtils.readUTF8(getTestFilePath(`data/${eml}`)); folder.QueryInterface(Ci.nsIMsgLocalMailFolder); folder.gettingNewMessages = true; folder.addMessage( "X-Mozilla-Status: 0001\r\nX-Mozilla-Status2: 00000000\r\n" + source ); folder.gettingNewMessages = false; gMsgNo++; await be_in_folder(folder); await select_click_row(gMsgNo - 1); await assert_selected_and_displayed(gMsgNo - 1); } function messagePaneDoc() { return get_about_message().getMessagePaneBrowser().contentDocument; } // Assert an S/MIME encrypted message decrypts and renders, but its remote image // stays blocked (with remote content globally enabled) and no override is // offered (with remote content blocked). async function assertSmimeBlocked(eml) { await SpecialPowers.pushPrefEnv({ set: [[DISABLE_PREF, false]], }); await addAndSelect(eml); const doc = messagePaneDoc(); Assert.ok( doc.documentElement.textContent.includes( "This is a test message from Alice to Bob." ), `${eml}: S/MIME message was decrypted and rendered` ); // A blocked image never loads, so once layout has ticked naturalWidth stays 0. await new Promise(resolve => window.requestAnimationFrame(resolve)); const img = doc.getElementById("testelement"); Assert.ok(img, `${eml}: remote image element present in decrypted body`); Assert.equal( img.naturalWidth, 0, `${eml}: S/MIME remote image stays blocked even with remote content enabled` ); await SpecialPowers.pushPrefEnv({ set: [[DISABLE_PREF, true]], }); await addAndSelect(eml); const aboutMessage = get_about_message(); await wait_for_notification_to_show( aboutMessage, NOTIFICATION_BOX, NOTIFICATION_VALUE ); const notification = get_notification( aboutMessage, NOTIFICATION_BOX, NOTIFICATION_VALUE ); const buttons = notification.buttonContainer.querySelectorAll( "button, toolbarbutton" ); Assert.equal(buttons.length, 0, `${eml}: no remote-content override offered`); } add_task(async function test_smime_encrypted_blocked() { // A plain S/MIME enveloped message with remote content stays blocked, with no // override (invariant #5). await assertSmimeBlocked("alice.remoteimage.env.eml"); }); add_task(async function test_pgp_sig_wrapping_smime_blocked() { // A top-level OpenPGP signature wrapping an inner S/MIME encrypted part must // stay blocked: S/MIME is never integrity protected, so the signature-wrapper // exception must not relax it (bug 1994709 invariants #4/#5). Thunderbird does // not surface this exotic nesting at the top level, so the inner content is // not even rendered -- also a safe outcome. Either way, no remote content may // load, even with remote content globally enabled. await SpecialPowers.pushPrefEnv({ set: [[DISABLE_PREF, false]], }); await addAndSelect("pgp-sig-wrapping-smime-enc.eml"); await new Promise(resolve => window.requestAnimationFrame(resolve)); const img = messagePaneDoc().getElementById("testelement"); Assert.ok( !img || !img.complete || img.naturalWidth === 0, "outer-PGP-sig / inner-S/MIME: remote image does not load" ); await SpecialPowers.pushPrefEnv({ set: [[DISABLE_PREF, true]], }); });