mirror of
https://github.com/chatmail/core.git
synced 2026-04-27 02:16:29 +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::contact::addr_cmp;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
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::peerstate::Peerstate;
|
||||||
use crate::pgp;
|
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();
|
let mut public_keyring_for_validate = Vec::new();
|
||||||
if let Some(peerstate) = peerstate {
|
if let Some(peerstate) = peerstate {
|
||||||
if let Some(key) = &peerstate.public_key {
|
if let Some(key) = &peerstate.public_key {
|
||||||
public_keyring_for_validate.push(key.clone());
|
public_keyring_for_validate.push(key.clone());
|
||||||
} else if let Some(key) = &peerstate.gossip_key {
|
} else if let Some(key) = &peerstate.gossip_key {
|
||||||
public_keyring_for_validate.push(key.clone());
|
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.
|
/// 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,
|
message_time: i64,
|
||||||
allow_change: bool,
|
allow_change: bool,
|
||||||
) -> Result<Option<Peerstate>> {
|
) -> Result<Option<Peerstate>> {
|
||||||
|
let allow_change = allow_change && !context.is_self_addr(from).await?;
|
||||||
let mut peerstate;
|
let mut peerstate;
|
||||||
|
|
||||||
// Apply Autocrypt header
|
// 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> {
|
pub(crate) async fn load_self_secret_key(context: &Context) -> Result<SignedSecretKey> {
|
||||||
let private_key = context
|
let private_key = context
|
||||||
.sql
|
.sql
|
||||||
|
|||||||
@@ -304,7 +304,8 @@ impl MimeMessage {
|
|||||||
hop_info += "\n\n";
|
hop_info += "\n\n";
|
||||||
hop_info += &decryption_info.dkim_results.to_string();
|
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(|| {
|
let (mail, mut signatures, encrypted) = match tokio::task::block_in_place(|| {
|
||||||
try_decrypt(&mail, &private_keyring, &public_keyring)
|
try_decrypt(&mail, &private_keyring, &public_keyring)
|
||||||
}) {
|
}) {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ use crate::message::Message;
|
|||||||
use crate::mimeparser::SystemMessage;
|
use crate::mimeparser::SystemMessage;
|
||||||
use crate::sql::Sql;
|
use crate::sql::Sql;
|
||||||
use crate::stock_str;
|
use crate::stock_str;
|
||||||
|
use crate::tools;
|
||||||
|
|
||||||
/// Type of the public key stored inside the peerstate.
|
/// Type of the public key stored inside the peerstate.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -165,6 +166,9 @@ impl Peerstate {
|
|||||||
|
|
||||||
/// Loads peerstate corresponding to the given address from the database.
|
/// Loads peerstate corresponding to the given address from the database.
|
||||||
pub async fn from_addr(context: &Context, addr: &str) -> Result<Option<Peerstate>> {
|
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, \
|
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||||
verified_key, verified_key_fingerprint, \
|
verified_key, verified_key_fingerprint, \
|
||||||
@@ -182,6 +186,7 @@ impl Peerstate {
|
|||||||
context: &Context,
|
context: &Context,
|
||||||
fingerprint: &Fingerprint,
|
fingerprint: &Fingerprint,
|
||||||
) -> Result<Option<Peerstate>> {
|
) -> 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, \
|
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||||
verified_key, verified_key_fingerprint, \
|
verified_key, verified_key_fingerprint, \
|
||||||
@@ -206,6 +211,9 @@ impl Peerstate {
|
|||||||
fingerprint: &Fingerprint,
|
fingerprint: &Fingerprint,
|
||||||
addr: &str,
|
addr: &str,
|
||||||
) -> Result<Option<Peerstate>> {
|
) -> 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, \
|
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, \
|
||||||
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, \
|
||||||
verified_key, verified_key_fingerprint, \
|
verified_key, verified_key_fingerprint, \
|
||||||
@@ -221,6 +229,34 @@ impl Peerstate {
|
|||||||
Self::from_stmt(context, query, (&fp, &addr, &fp)).await
|
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(
|
async fn from_stmt(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
query: &str,
|
query: &str,
|
||||||
|
|||||||
Reference in New Issue
Block a user