mirror of
https://github.com/chatmail/core.git
synced 2026-04-06 15:42:10 +03:00
fix: Don't treat forged outgoing messages as Autocrypt-encrypted
This commit is contained in:
@@ -12,7 +12,7 @@ use crate::authres::{self, DkimResults};
|
||||
use crate::contact::addr_cmp;
|
||||
use crate::context::Context;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey};
|
||||
use crate::key::{self, DcKey, Fingerprint, SignedPublicKey, SignedSecretKey};
|
||||
use crate::peerstate::Peerstate;
|
||||
use crate::pgp;
|
||||
|
||||
@@ -264,16 +264,22 @@ pub(crate) fn validate_detached_signature<'a, 'b>(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn keyring_from_peerstate(peerstate: Option<&Peerstate>) -> Vec<SignedPublicKey> {
|
||||
/// Returns public keyring for `peerstate`.
|
||||
pub(crate) async fn keyring_from_peerstate(
|
||||
context: &Context,
|
||||
peerstate: Option<&Peerstate>,
|
||||
) -> Result<Vec<SignedPublicKey>> {
|
||||
let mut public_keyring_for_validate = Vec::new();
|
||||
if let Some(peerstate) = peerstate {
|
||||
if let Some(key) = &peerstate.public_key {
|
||||
public_keyring_for_validate.push(key.clone());
|
||||
} else if let Some(key) = &peerstate.gossip_key {
|
||||
public_keyring_for_validate.push(key.clone());
|
||||
} else if context.is_self_addr(&peerstate.addr).await? {
|
||||
public_keyring_for_validate = key::load_self_public_keyring(context).await?;
|
||||
}
|
||||
}
|
||||
public_keyring_for_validate
|
||||
Ok(public_keyring_for_validate)
|
||||
}
|
||||
|
||||
/// Applies Autocrypt header to Autocrypt peer state and saves it into the database.
|
||||
@@ -292,6 +298,7 @@ pub(crate) async fn get_autocrypt_peerstate(
|
||||
message_time: i64,
|
||||
allow_change: bool,
|
||||
) -> Result<Option<Peerstate>> {
|
||||
let allow_change = allow_change && !context.is_self_addr(from).await?;
|
||||
let mut peerstate;
|
||||
|
||||
// Apply Autocrypt header
|
||||
|
||||
19
src/key.rs
19
src/key.rs
@@ -101,6 +101,25 @@ pub(crate) async fn load_self_public_key(context: &Context) -> Result<SignedPubl
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns our own public keyring.
|
||||
pub(crate) async fn load_self_public_keyring(context: &Context) -> Result<Vec<SignedPublicKey>> {
|
||||
let keys = context
|
||||
.sql
|
||||
.query_map(
|
||||
r#"SELECT public_key
|
||||
FROM keypairs
|
||||
ORDER BY id=(SELECT value FROM config WHERE keyname='key_id') DESC"#,
|
||||
(),
|
||||
|row| row.get::<_, Vec<u8>>(0),
|
||||
|keys| keys.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|bytes| SignedPublicKey::from_slice(&bytes).log_err(context).ok())
|
||||
.collect();
|
||||
Ok(keys)
|
||||
}
|
||||
|
||||
pub(crate) async fn load_self_secret_key(context: &Context) -> Result<SignedSecretKey> {
|
||||
let private_key = context
|
||||
.sql
|
||||
|
||||
@@ -304,7 +304,8 @@ impl MimeMessage {
|
||||
hop_info += "\n\n";
|
||||
hop_info += &decryption_info.dkim_results.to_string();
|
||||
|
||||
let public_keyring = keyring_from_peerstate(decryption_info.peerstate.as_ref());
|
||||
let public_keyring =
|
||||
keyring_from_peerstate(context, decryption_info.peerstate.as_ref()).await?;
|
||||
let (mail, mut signatures, encrypted) = match tokio::task::block_in_place(|| {
|
||||
try_decrypt(&mail, &private_keyring, &public_keyring)
|
||||
}) {
|
||||
|
||||
@@ -16,6 +16,7 @@ use crate::message::Message;
|
||||
use crate::mimeparser::SystemMessage;
|
||||
use crate::sql::Sql;
|
||||
use crate::stock_str;
|
||||
use crate::tools;
|
||||
|
||||
/// Type of the public key stored inside the peerstate.
|
||||
#[derive(Debug)]
|
||||
@@ -165,6 +166,9 @@ impl Peerstate {
|
||||
|
||||
/// Loads peerstate corresponding to the given address from the database.
|
||||
pub async fn from_addr(context: &Context, addr: &str) -> Result<Option<Peerstate>> {
|
||||
if context.is_self_addr(addr).await? {
|
||||
return Ok(Some(Peerstate::get_self_stub(addr)));
|
||||
}
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||
verified_key, verified_key_fingerprint, \
|
||||
@@ -182,6 +186,7 @@ impl Peerstate {
|
||||
context: &Context,
|
||||
fingerprint: &Fingerprint,
|
||||
) -> Result<Option<Peerstate>> {
|
||||
// NOTE: If it's our key fingerprint, this returns None currently.
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||
verified_key, verified_key_fingerprint, \
|
||||
@@ -206,6 +211,9 @@ impl Peerstate {
|
||||
fingerprint: &Fingerprint,
|
||||
addr: &str,
|
||||
) -> Result<Option<Peerstate>> {
|
||||
if context.is_self_addr(addr).await? {
|
||||
return Ok(Some(Peerstate::get_self_stub(addr)));
|
||||
}
|
||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||
verified_key, verified_key_fingerprint, \
|
||||
@@ -221,6 +229,34 @@ impl Peerstate {
|
||||
Self::from_stmt(context, query, (&fp, &addr, &fp)).await
|
||||
}
|
||||
|
||||
/// Returns peerstate stub for self `addr`.
|
||||
///
|
||||
/// Needed for [`crate::decrypt::keyring_from_peerstate()`] which returns a keyring of all our
|
||||
/// pubkeys for such a stub so that we can check if a message is signed by us.
|
||||
fn get_self_stub(addr: &str) -> Self {
|
||||
let now = tools::time();
|
||||
// We can have multiple pubkeys, just make the corresponding fields None.
|
||||
Self {
|
||||
addr: addr.to_string(),
|
||||
last_seen: now,
|
||||
last_seen_autocrypt: now,
|
||||
prefer_encrypt: EncryptPreference::Mutual,
|
||||
public_key: None,
|
||||
public_key_fingerprint: None,
|
||||
gossip_key: None,
|
||||
gossip_key_fingerprint: None,
|
||||
gossip_timestamp: 0,
|
||||
verified_key: None,
|
||||
verified_key_fingerprint: None,
|
||||
verifier: None,
|
||||
secondary_verified_key: None,
|
||||
secondary_verified_key_fingerprint: None,
|
||||
secondary_verifier: None,
|
||||
backward_verified_key_id: None,
|
||||
fingerprint_changed: false,
|
||||
}
|
||||
}
|
||||
|
||||
async fn from_stmt(
|
||||
context: &Context,
|
||||
query: &str,
|
||||
|
||||
Reference in New Issue
Block a user