diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 1036cbb06..474ecd354 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -427,7 +427,7 @@ impl MimeMessage { None }; - let public_keyring = if incoming { + let mut public_keyring = if incoming { if let Some(autocrypt_header) = autocrypt_header { vec![autocrypt_header.public_key] } else { @@ -437,6 +437,44 @@ impl MimeMessage { key::load_self_public_keyring(context).await? }; + if let Some(signature) = match &decrypted_msg { + Some(pgp::composed::Message::Literal { .. }) => None, + Some(pgp::composed::Message::Compressed { .. }) => { + // One layer of compression should already be handled by now. + // We don't decompress messages compressed multiple times. + None + } + Some(pgp::composed::Message::SignedOnePass { reader, .. }) => reader.signature(), + Some(pgp::composed::Message::Signed { reader, .. }) => Some(reader.signature()), + Some(pgp::composed::Message::Encrypted { .. }) => { + // The message is already decrypted once. + None + } + None => None, + } { + for issuer_fingerprint in signature.issuer_fingerprint() { + let issuer_fingerprint = + crate::key::Fingerprint::from(issuer_fingerprint.clone()).hex(); + if let Some(public_key_bytes) = context + .sql + .query_row_optional( + "SELECT public_key + FROM public_keys + WHERE fingerprint=?", + (&issuer_fingerprint,), + |row| { + let bytes: Vec = row.get(0)?; + Ok(bytes) + }, + ) + .await? + { + let public_key = SignedPublicKey::from_slice(&public_key_bytes)?; + public_keyring.push(public_key) + } + } + } + let mut signatures = if let Some(ref decrypted_msg) = decrypted_msg { crate::pgp::valid_signature_fingerprints(decrypted_msg, &public_keyring)? } else { diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index d6ffc48f0..7f777742a 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -3316,6 +3316,31 @@ async fn test_thunderbird_autocrypt() -> Result<()> { Ok(()) } +/// Tests that a message without an Autocrypt header is assigned to the key-contact +/// by using the signature Issuer Fingerprint. +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_issuer_fingerprint() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + + let alice_contact_id = bob.add_or_lookup_contact_id(alice).await; + + let raw = include_bytes!("../../test-data/message/encrypted-signed.eml"); + let received_msg = receive_imf(bob, raw, false).await?.unwrap(); + + assert_eq!(received_msg.msg_ids.len(), 1); + let msg_id = received_msg.msg_ids[0]; + + let message = Message::load_from_db(bob, msg_id).await?; + assert!(message.get_showpadlock()); + + let from_id = message.from_id; + assert_eq!(from_id, alice_contact_id); + + Ok(()) +} + /// Tests reception of a message from Thunderbird with attached key. #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_prefer_encrypt_mutual_if_encrypted() -> Result<()> { diff --git a/test-data/message/encrypted-signed.eml b/test-data/message/encrypted-signed.eml new file mode 100644 index 000000000..a399b9957 --- /dev/null +++ b/test-data/message/encrypted-signed.eml @@ -0,0 +1,52 @@ +Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; + boundary="18566fe03178296e_f40510c3b59ace3_ecf843ae3ccd2b17" +MIME-Version: 1.0 +From: alice@example.org +To: bob@example.net +Subject: [...] +Date: Mon, 28 Jul 2025 14:15:14 +0000 +Message-ID: <48b9e9cc-2bae-4d41-89b4-a409e2c60c28@localhost> +References: <48b9e9cc-2bae-4d41-89b4-a409e2c60c28@localhost> +Chat-Version: 1.0 + + +--18566fe03178296e_f40510c3b59ace3_ecf843ae3ccd2b17 +Content-Type: application/pgp-encrypted; charset="utf-8" +Content-Description: PGP/MIME version identification +Content-Transfer-Encoding: 7bit + +Version: 1 + +--18566fe03178296e_f40510c3b59ace3_ecf843ae3ccd2b17 +Content-Type: application/octet-stream; name="encrypted.asc"; + charset="utf-8" +Content-Description: OpenPGP encrypted message +Content-Disposition: inline; filename="encrypted.asc"; +Content-Transfer-Encoding: 7bit + +-----BEGIN PGP MESSAGE----- + +wV4D5tq63hTeebASAQdAaI0Cw7tTd10Oz0I1C1Ds5NpF/m6zXlx73Pxzib6Q2Qow +36Fc9KiSZx+vXlw9mZ9zYpumIY/svkYcTRdZwohPWe4TL7iRC8gTZ43/VGZvb+1k +wcBMA+PY3JvEjuMiAQf+MCZLm1vgocYO0xRz2J9Z9QGqScfxBMhYToZbFTx4DAha +hejVmW9AGnNqm8yky2DJpqT3oy//D261HX+xzLfkfWFgHzKud7NtMN6II/d1jyqO +A+K0LjSLPcR3aWl8g30+6bGhHCwc2spP3gIk1aE8S/1c/yQPxD7mqNSkYrY6BgHP ++5Z7ocrud4RKVQayZsWpiiY962w1GJii1h4zE+xhkqFERr1OqepQB7CDf4FBsGr0 +qarJtcWCGqd9ksr/wn8Ew9MPHz+8ooCSlXzJ7Uac4VshUm9dXzO3NSS6MgTME0av +WRlRiKuGCmrS4dyf/Tdj1yMB3jJ52SxdEq0yYYLKvdLBWAF9JU7sQp3x4oivpr5U +wv5OP/tbfRVA2zqkOHlMhBAXaLOsiJrHYh3ieJLwfWSmEQARLE7sBgD5fqre1v+D +Xpof8R42j9MQ3St/+nPDsLpbZ2a2RKBl16C8IYnmK1CYwh5lEK533HMHeSLka/ng +soK2HqJxrhkxYpm5OPWN8liSdKlQ8mZXISGNPo8KEWFlPqONqj88UudpQiPCh2qw +aeFC2Y1EkQQGpiTq1GuTQfG8zO4wa3FTW1wOELsvYozszS1Oc1exH767pS+ozNWa +xk8J7ekEFvR5b3TUK2a/ucmRgXuuowCxxV6EiNeRqGa3SfQnQWnMkqsVIeIiARDt +QMbRCrrAjJ+dQEekviq/hqq9+DRLuX0hOybe8aYjJttg7NLgaM04V4QuvWeVQa2g +2IBR2Nw1pcvbyDRkTLsQ2AlR/ig5VPf+4oqN2nBuXgPzply9LU5JyhW9GNIhH+N1 +K6w8o5o4ebUx0ldaTjBnrFMUqih4nE9qrrb0UYMcQO3HVAueQii0CZqhJy/n/6U6 +cAhnh/fTI1wMoYuYR7cLdf+9P7dHcQPdt3FQA/NrRpv31tyzzKNeBr0VdvoT0uwX +sv0nh+ACjnum7H8yCyoe1tIqUPW0byslROuHAfMwp7rsnBEGJ4AqFYNIdpfSFuia +LsZmODaUG1n6XkamfKPin+Z5Mo8/bK0KwE317Zc/aQD/okvGv4SWsQmW +=hj9/ +-----END PGP MESSAGE----- + + +--18566fe03178296e_f40510c3b59ace3_ecf843ae3ccd2b17--