mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Treat attached PGP keys as peer keys with mutual encryption preference (#3778)
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
### Fixes
|
||||
- Set read/write timeouts for IMAP over SOCKS5 #3833
|
||||
- Treat attached PGP keys as peer keys with mutual encryption preference #3832
|
||||
|
||||
|
||||
## 1.103.0
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::str;
|
||||
|
||||
use anyhow::{bail, Context as _, Result};
|
||||
use deltachat_derive::{FromSql, ToSql};
|
||||
@@ -10,17 +11,17 @@ use lettre_email::mime::{self, Mime};
|
||||
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::aheader::Aheader;
|
||||
use crate::aheader::{Aheader, EncryptPreference};
|
||||
use crate::blob::BlobObject;
|
||||
use crate::constants::{DC_DESIRED_TEXT_LINES, DC_DESIRED_TEXT_LINE_LEN};
|
||||
use crate::contact::{addr_cmp, addr_normalize, ContactId};
|
||||
use crate::context::Context;
|
||||
use crate::decrypt::{prepare_decryption, try_decrypt};
|
||||
use crate::decrypt::{prepare_decryption, try_decrypt, DecryptionInfo};
|
||||
use crate::dehtml::dehtml;
|
||||
use crate::events::EventType;
|
||||
use crate::format_flowed::unformat_flowed;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::key::Fingerprint;
|
||||
use crate::key::{DcKey, Fingerprint, SignedPublicKey};
|
||||
use crate::message::{self, Viewtype};
|
||||
use crate::param::{Param, Params};
|
||||
use crate::peerstate::Peerstate;
|
||||
@@ -52,6 +53,7 @@ pub struct MimeMessage {
|
||||
pub from_is_signed: bool,
|
||||
pub list_post: Option<String>,
|
||||
pub chat_disposition_notification_to: Option<SingleInfo>,
|
||||
pub decryption_info: DecryptionInfo,
|
||||
pub decrypting_failed: bool,
|
||||
|
||||
/// Set of valid signature fingerprints if a message is an
|
||||
@@ -322,6 +324,7 @@ impl MimeMessage {
|
||||
from,
|
||||
from_is_signed,
|
||||
chat_disposition_notification_to,
|
||||
decryption_info,
|
||||
decrypting_failed: mail.is_err(),
|
||||
|
||||
// only non-empty if it was a valid autocrypt message
|
||||
@@ -390,8 +393,8 @@ impl MimeMessage {
|
||||
parser.decoded_data = mail_raw;
|
||||
}
|
||||
|
||||
crate::peerstate::maybe_do_aeap_transition(context, &mut decryption_info, &parser).await?;
|
||||
if let Some(peerstate) = decryption_info.peerstate {
|
||||
crate::peerstate::maybe_do_aeap_transition(context, &mut parser).await?;
|
||||
if let Some(peerstate) = &parser.decryption_info.peerstate {
|
||||
peerstate
|
||||
.handle_fingerprint_change(context, message_time)
|
||||
.await?;
|
||||
@@ -950,7 +953,7 @@ impl MimeMessage {
|
||||
&filename,
|
||||
is_related,
|
||||
)
|
||||
.await;
|
||||
.await?;
|
||||
}
|
||||
None => {
|
||||
match mime_type.type_() {
|
||||
@@ -1093,9 +1096,18 @@ impl MimeMessage {
|
||||
decoded_data: &[u8],
|
||||
filename: &str,
|
||||
is_related: bool,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
if decoded_data.is_empty() {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
if let Some(peerstate) = &mut self.decryption_info.peerstate {
|
||||
if peerstate.prefer_encrypt != EncryptPreference::Mutual
|
||||
&& mime_type.type_() == mime::APPLICATION
|
||||
&& mime_type.subtype().as_str() == "pgp-keys"
|
||||
&& Self::try_set_peer_key_from_file_part(context, peerstate, decoded_data).await?
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
let msg_type = if context
|
||||
.is_webxdc_file(filename, decoded_data)
|
||||
@@ -1117,7 +1129,7 @@ impl MimeMessage {
|
||||
} else {
|
||||
self.message_kml = parsed;
|
||||
}
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
msg_type
|
||||
} else if filename == "multi-device-sync.json" {
|
||||
@@ -1130,13 +1142,13 @@ impl MimeMessage {
|
||||
warn!(context, "failed to parse sync data: {}", err);
|
||||
})
|
||||
.ok();
|
||||
return;
|
||||
return Ok(());
|
||||
} else if filename == "status-update.json" {
|
||||
let serialized = String::from_utf8_lossy(decoded_data)
|
||||
.parse()
|
||||
.unwrap_or_default();
|
||||
self.webxdc_status_update = Some(serialized);
|
||||
return;
|
||||
return Ok(());
|
||||
} else {
|
||||
msg_type
|
||||
};
|
||||
@@ -1151,7 +1163,7 @@ impl MimeMessage {
|
||||
context,
|
||||
"Could not add blob for mime part {}, error {}", filename, err
|
||||
);
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
info!(context, "added blobfile: {:?}", blob.as_name());
|
||||
@@ -1174,6 +1186,66 @@ impl MimeMessage {
|
||||
part.is_related = is_related;
|
||||
|
||||
self.do_add_single_part(part);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns whether a key from the attachment was set as peer's pubkey.
|
||||
async fn try_set_peer_key_from_file_part(
|
||||
context: &Context,
|
||||
peerstate: &mut Peerstate,
|
||||
decoded_data: &[u8],
|
||||
) -> Result<bool> {
|
||||
let key = match str::from_utf8(decoded_data) {
|
||||
Err(err) => {
|
||||
warn!(context, "PGP key attachment is not a UTF-8 file: {}", err);
|
||||
return Ok(false);
|
||||
}
|
||||
Ok(key) => key,
|
||||
};
|
||||
let key = match SignedPublicKey::from_asc(key) {
|
||||
Err(err) => {
|
||||
warn!(
|
||||
context,
|
||||
"PGP key attachment is not an ASCII-armored file: {}", err,
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
Ok((key, _)) => key,
|
||||
};
|
||||
if let Err(err) = key.verify() {
|
||||
warn!(context, "attached PGP key verification failed: {}", err);
|
||||
return Ok(false);
|
||||
}
|
||||
if !key.details.users.iter().any(|user| {
|
||||
user.id
|
||||
.id()
|
||||
.ends_with(&(String::from("<") + &peerstate.addr + ">"))
|
||||
}) {
|
||||
return Ok(false);
|
||||
}
|
||||
if let Some(curr_key) = &peerstate.public_key {
|
||||
if key != *curr_key && peerstate.prefer_encrypt != EncryptPreference::Reset {
|
||||
// We don't want to break the existing Autocrypt setup. Yes, it's unlikely that a
|
||||
// user have an Autocrypt-capable MUA and also attaches a key, but if that's the
|
||||
// case, let 'em first disable Autocrypt and then change the key by attaching it.
|
||||
warn!(
|
||||
context,
|
||||
"not using attached PGP key for peer '{}' because another one is already set \
|
||||
with prefer-encrypt={}",
|
||||
peerstate.addr,
|
||||
peerstate.prefer_encrypt,
|
||||
);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
info!(
|
||||
context,
|
||||
"will use attached PGP key for peer '{}' with mutual encryption", peerstate.addr,
|
||||
);
|
||||
peerstate.public_key = Some(key);
|
||||
peerstate.prefer_encrypt = EncryptPreference::Mutual;
|
||||
peerstate.save_to_db(&context.sql).await?;
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
fn do_add_single_part(&mut self, mut part: Part) {
|
||||
|
||||
@@ -9,7 +9,6 @@ use crate::chatlist::Chatlist;
|
||||
use crate::constants::Chattype;
|
||||
use crate::contact::{addr_cmp, Contact, Origin};
|
||||
use crate::context::Context;
|
||||
use crate::decrypt::DecryptionInfo;
|
||||
use crate::events::EventType;
|
||||
use crate::key::{DcKey, Fingerprint, SignedPublicKey};
|
||||
use crate::message::Message;
|
||||
@@ -565,10 +564,10 @@ impl Peerstate {
|
||||
/// In `drafts/aeap_mvp.md` there is a "big picture" overview over AEAP.
|
||||
pub async fn maybe_do_aeap_transition(
|
||||
context: &Context,
|
||||
info: &mut DecryptionInfo,
|
||||
mime_parser: &crate::mimeparser::MimeMessage,
|
||||
mime_parser: &mut crate::mimeparser::MimeMessage,
|
||||
) -> Result<()> {
|
||||
if let Some(peerstate) = &mut info.peerstate {
|
||||
let info = &mime_parser.decryption_info;
|
||||
if let Some(peerstate) = &info.peerstate {
|
||||
// If the from addr is different from the peerstate address we know,
|
||||
// we may want to do an AEAP transition.
|
||||
if !addr_cmp(&peerstate.addr, &mime_parser.from.addr)
|
||||
@@ -588,6 +587,8 @@ pub async fn maybe_do_aeap_transition(
|
||||
&& mime_parser.from_is_signed
|
||||
&& info.message_time > peerstate.last_seen
|
||||
{
|
||||
let info = &mut mime_parser.decryption_info;
|
||||
let peerstate = info.peerstate.as_mut().context("no peerstate??")?;
|
||||
// Add info messages to chats with this (verified) contact
|
||||
//
|
||||
peerstate
|
||||
|
||||
@@ -5350,6 +5350,22 @@ Reply from different address
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_thunderbird_autocrypt_unencrypted() -> Result<()> {
|
||||
let t = TestContext::new_bob().await;
|
||||
t.set_config(Config::ShowEmails, Some("2")).await?;
|
||||
|
||||
let raw = include_bytes!("../test-data/message/thunderbird_with_autocrypt_unencrypted.eml");
|
||||
receive_imf(&t, raw, false).await?;
|
||||
|
||||
let peerstate = Peerstate::from_addr(&t, "alice@example.org")
|
||||
.await?
|
||||
.unwrap();
|
||||
assert_eq!(peerstate.prefer_encrypt, EncryptPreference::Mutual);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||
async fn test_mua_user_adds_member() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
142
test-data/message/thunderbird_with_autocrypt_unencrypted.eml
Normal file
142
test-data/message/thunderbird_with_autocrypt_unencrypted.eml
Normal file
@@ -0,0 +1,142 @@
|
||||
From - Fri, 09 Dec 2022 13:16:11 GMT
|
||||
X-Mozilla-Status: 0801
|
||||
X-Mozilla-Status2: 00000000
|
||||
Message-ID: <0c8e3ffc-99ae-eb68-15b5-15c4d85a5c12@example.org>
|
||||
Date: Fri, 9 Dec 2022 10:16:11 -0300
|
||||
MIME-Version: 1.0
|
||||
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101
|
||||
Thunderbird/102.5.1
|
||||
Content-Language: en-US
|
||||
To: bob@example.net
|
||||
From: Alice <alice@example.org>
|
||||
Subject: test message 10:15
|
||||
Autocrypt: addr=alice@example.org; keydata=
|
||||
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
|
||||
rhEBN10sGyg93A==
|
||||
X-Mozilla-Draft-Info: internal/draft; vcard=0; receipt=0; DSN=0; uuencode=0;
|
||||
attachmentreminder=0; deliveryformat=0
|
||||
X-Identity-Key: id3
|
||||
Fcc: imap://alice%40example.org@in.example.org/Sent
|
||||
Content-Type: multipart/signed; micalg=pgp-sha256;
|
||||
protocol="application/pgp-signature";
|
||||
boundary="------------FFBOG29BVxcOkoFV1hnc0RaY"
|
||||
|
||||
This is an OpenPGP/MIME signed message (RFC 4880 and 3156)
|
||||
--------------FFBOG29BVxcOkoFV1hnc0RaY
|
||||
Content-Type: multipart/mixed; boundary="------------4cwiD0i5NnTXNSfPNpFwrv6V";
|
||||
protected-headers="v1"
|
||||
From: Alice <alice@example.org>
|
||||
To: bob@example.net
|
||||
Message-ID: <0c8e3ffc-99ae-eb68-15b5-15c4d85a5c12@example.org>
|
||||
Subject: test message 10:15
|
||||
|
||||
--------------4cwiD0i5NnTXNSfPNpFwrv6V
|
||||
Content-Type: multipart/mixed; boundary="------------fbNEFvfS22YOKnkTd1oAl0ak"
|
||||
|
||||
--------------fbNEFvfS22YOKnkTd1oAl0ak
|
||||
Content-Type: text/plain; charset=UTF-8; format=flowed
|
||||
Content-Transfer-Encoding: base64
|
||||
|
||||
MTIzDQoNCg==
|
||||
--------------fbNEFvfS22YOKnkTd1oAl0ak
|
||||
Content-Type: application/pgp-keys; name="OpenPGP_0xE0D506661947F47C.asc"
|
||||
Content-Disposition: attachment; filename="OpenPGP_0xE0D506661947F47C.asc"
|
||||
Content-Description: OpenPGP public key
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
rhEBN10sGyg93A=3D=3D
|
||||
=3DDPMe
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
--------------fbNEFvfS22YOKnkTd1oAl0ak--
|
||||
|
||||
--------------4cwiD0i5NnTXNSfPNpFwrv6V--
|
||||
|
||||
--------------FFBOG29BVxcOkoFV1hnc0RaY
|
||||
Content-Type: application/pgp-signature; name="OpenPGP_signature.asc"
|
||||
Content-Description: OpenPGP digital signature
|
||||
Content-Disposition: attachment; filename="OpenPGP_signature"
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
|
||||
wsD5BAABCAAjFiEEvtjufiR1TFlamixB4NUGZhlH9HwFAmOTNRsFAwAAAAAACgkQ4NUGZhlH9Hzw
|
||||
Iwv/dNC7LDvRGmZ71IaivkUkSTbpGgg0gnCNOuf+B8OxUBQlWPkBmLxyrXbkxsTghFogDsVQeZQQ
|
||||
DJ182KMgeC//rUN5DPJNrh95YZnav0nUpzW1mkFZjK+PdhbfdXKoXhJIqcw/7lpy/povRYZ20Igg
|
||||
tIHLa1NlqPPhSx/o2dsEqWeAtXF4e8T/jQSA5+ZQtVrdcTCNQG6zbqlHZuJ7bF1bwuHPgLgDhJ5k
|
||||
+T2ny80ZtkfLXJl5tQdblAomhBPfEOj+AeLCKsrJFO3WFZOvsuoKMPZpwW1wEh7+QYLABX/lRvqx
|
||||
IxjH1Tc26vttlOrVH13FKGSeWJELun+b2dP1LPiBQ7DOsrrFNs3fp56Nb7Y+exH5ld0jz0kJZTUD
|
||||
yPqZpJXTsWkFPE7x1tbH/7goiH8f9DbQrvmqQ2fnCjzf3UJR3ZhG/13YAUEdLVkVzwMItEd6yisg
|
||||
MP8mlbwm4aDeCiGXO/xhOoBVl6bn1HVSxo7mb0chHVyD1NOfd7qsxem0L/A2
|
||||
=MOQB
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
--------------FFBOG29BVxcOkoFV1hnc0RaY--
|
||||
Reference in New Issue
Block a user