Skip to content

Commit

Permalink
fix: receive_imf: Don't break 1:1 chat protection if received the ver…
Browse files Browse the repository at this point in the history
…ified 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.
  • Loading branch information
iequidoo committed Aug 27, 2023
1 parent a520f02 commit 3d80a2b
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
14 changes: 13 additions & 1 deletion src/receive_imf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -758,7 +759,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
Expand Down
28 changes: 28 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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::*;
Expand Down
45 changes: 43 additions & 2 deletions src/tests/verified_chats.rs
Original file line number Diff line number Diff line change
@@ -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::config::Config;
use crate::contact::VerifiedStatus;
use crate::contact::{Contact, Origin};
Expand All @@ -10,7 +10,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)]
Expand Down Expand Up @@ -736,6 +738,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) {
Expand Down
6 changes: 6 additions & 0 deletions test-data/golden/verified_chats_test_unencrypted
Original file line number Diff line number Diff line change
@@ -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]
--------------------------------------------------------------------------------

0 comments on commit 3d80a2b

Please sign in to comment.