fix: receive_imf: Don't break 1:1 chat protection if received the verified Autocrypt key (#4597)

For example, broadcast list messages are sent unencrypted, but their Autocrypt header still contains
the verified key. Thus we're sure that we still can encrypt to the peer and there's no need to break
the existing protection.
This commit is contained in:
iequidoo
2023-08-25 23:21:12 -03:00
parent 25a78aceb9
commit 83fa355291
4 changed files with 90 additions and 3 deletions

View File

@@ -23,6 +23,7 @@ use crate::ephemeral::{stock_ephemeral_timer_changed, Timer as EphemeralTimer};
use crate::events::EventType;
use crate::headerdef::{HeaderDef, HeaderDefMap};
use crate::imap::{markseen_on_imap_table, GENERATED_PREFIX};
use crate::key::DcKey;
use crate::location;
use crate::log::LogExt;
use crate::message::{
@@ -766,7 +767,18 @@ async fn add_parts(
// That's why the config is checked here, and not above.
&& context.get_config_bool(Config::VerifiedOneOnOneChats).await?
{
new_protection = ProtectionStatus::ProtectionBroken;
let decryption_info = &mime_parser.decryption_info;
new_protection =
match decryption_info.autocrypt_header.as_ref().filter(|ah| {
Some(&ah.public_key.fingerprint())
== decryption_info
.peerstate
.as_ref()
.and_then(|p| p.verified_key_fingerprint.as_ref())
}) {
Some(_) => chat.protected,
None => ProtectionStatus::ProtectionBroken,
};
}
if chat.protected != new_protection {
// The message itself will be sorted under the device message since the device

View File

@@ -136,6 +136,22 @@ impl TestContextManager {
received_msg
}
/// - Let one TestContext send a message.
/// - Let the other TestContext receive it.
/// - Assert that the message text is the formatted `err`.
/// - Assert that the message info contains the original text.
pub async fn send_recv_with_err(
&self,
from: &TestContext,
to: &TestContext,
err: &str,
msg: &str,
) -> Message {
let received_msg = self.try_send_recv(from, to, msg).await;
check_msg_with_err(to, &received_msg, err, msg).await;
received_msg
}
/// - Let one TestContext send a message
/// - Let the other TestContext receive it
pub async fn try_send_recv(&self, from: &TestContext, to: &TestContext, msg: &str) -> Message {
@@ -1198,6 +1214,18 @@ async fn write_msg(context: &Context, prefix: &str, msg: &Message, buf: &mut Str
.unwrap();
}
/// - Assert that the message text is the formatted error `err`.
/// - Assert that the message info contains the original text.
pub async fn check_msg_with_err(ctx: &TestContext, msg: &Message, err: &str, text: &str) {
assert_eq!(msg.text, format!("[{err}]"));
assert!(msg
.id
.get_info(ctx)
.await
.unwrap()
.contains(&format!("\n\n{text}\n\n")));
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -1,7 +1,7 @@
use anyhow::Result;
use pretty_assertions::assert_eq;
use crate::chat::{Chat, ProtectionStatus};
use crate::chat::{add_contact_to_chat, create_broadcast_list, Chat, ProtectionStatus};
use crate::chatlist::Chatlist;
use crate::config::Config;
use crate::constants::DC_GCL_FOR_FORWARDING;
@@ -12,7 +12,9 @@ use crate::mimefactory::MimeFactory;
use crate::mimeparser::SystemMessage;
use crate::receive_imf::receive_imf;
use crate::stock_str;
use crate::test_utils::{get_chat_msg, mark_as_verified, TestContext, TestContextManager};
use crate::test_utils::{
check_msg_with_err, get_chat_msg, mark_as_verified, TestContext, TestContextManager,
};
use crate::{e2ee, message};
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@@ -742,6 +744,45 @@ async fn test_create_oneonone_chat_with_former_verified_contact() -> Result<()>
Ok(())
}
/// Some messages are sent unencrypted, but they mustn't break a verified chat protection.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_unencrypted() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;
enable_verified_oneonone_chats(&[&alice]).await;
mark_as_verified(&alice, &bob).await;
let err_str = "This message is not encrypted. See 'Info' for more details";
let msg = tcm.send_recv_with_err(&bob, &alice, err_str, "hi").await;
assert!(!msg.get_showpadlock());
let alice_chat = Chat::load_from_db(&alice, msg.chat_id).await?;
assert!(alice_chat.is_protected());
assert!(!alice_chat.is_protection_broken());
let broadcast_id = create_broadcast_list(&bob).await?;
add_contact_to_chat(
&bob,
broadcast_id,
bob.add_or_lookup_contact(&alice).await.id,
)
.await?;
let sent_msg = bob.send_text(broadcast_id, "hi all").await;
let msg = alice.recv_msg(&sent_msg).await;
check_msg_with_err(&alice, &msg, err_str, "hi all").await;
assert!(!msg.get_showpadlock());
assert_eq!(msg.chat_id, alice_chat.id);
let alice_chat = Chat::load_from_db(&alice, msg.chat_id).await?;
assert!(alice_chat.is_protected());
assert!(!alice_chat.is_protection_broken());
alice
.golden_test_chat(alice_chat.id, "verified_chats_test_unencrypted")
.await;
Ok(())
}
// ============== Helper Functions ==============
async fn assert_verified(this: &TestContext, other: &TestContext, protected: ProtectionStatus) {

View File

@@ -0,0 +1,6 @@
Single#Chat#10: bob@example.net [bob@example.net] 🛡️
--------------------------------------------------------------------------------
Msg#10: info (Contact#Contact#Info): Messages are guaranteed to be end-to-end encrypted from now on. [NOTICED][INFO 🛡️]
Msg#11: (Contact#Contact#10): [This message is not encrypted. See 'Info' for more details] [FRESH]
Msg#12: (Contact#Contact#10): [This message is not encrypted. See 'Info' for more details] [FRESH]
--------------------------------------------------------------------------------