fix: Take the last valid Autocrypt header (#7167)

DKIM-Signatures apply to the last headers, so start from the last header and take a valid one,
i.e. skip headers having unknown critical attributes, etc. Though this means that Autocrypt header
must be "oversigned" to guarantee that a not DKIM-signed header isn't taken, still start from the
last header for consistency with processing other headers. This isn't a security issue anyway.
This commit is contained in:
iequidoo
2025-09-21 13:42:36 -03:00
committed by iequidoo
parent 738dc5ce19
commit 7477ebbdd7
3 changed files with 180 additions and 24 deletions

View File

@@ -351,7 +351,7 @@ impl MimeMessage {
let incoming = !context.is_self_addr(&from.addr).await?;
let mut aheader_value: Option<String> = mail.headers.get_header_value(HeaderDef::Autocrypt);
let mut aheader_values = mail.headers.get_all_values(HeaderDef::Autocrypt.into());
let mail_raw; // Memory location for a possible decrypted message.
let decrypted_msg; // Decrypted signed OpenPGP message.
@@ -378,11 +378,11 @@ impl MimeMessage {
timestamp_rcvd,
);
if let Some(protected_aheader_value) = decrypted_mail
let protected_aheader_values = decrypted_mail
.headers
.get_header_value(HeaderDef::Autocrypt)
{
aheader_value = Some(protected_aheader_value);
.get_all_values(HeaderDef::Autocrypt.into());
if !protected_aheader_values.is_empty() {
aheader_values = protected_aheader_values;
}
(Ok(decrypted_mail), true)
@@ -400,26 +400,27 @@ impl MimeMessage {
}
};
let autocrypt_header = if !incoming {
None
} else if let Some(aheader_value) = aheader_value {
match Aheader::from_str(&aheader_value) {
Ok(header) if addr_cmp(&header.addr, &from.addr) => Some(header),
Ok(header) => {
warn!(
context,
"Autocrypt header address {:?} is not {:?}.", header.addr, from.addr
);
None
}
Err(err) => {
warn!(context, "Failed to parse Autocrypt header: {:#}.", err);
None
}
let mut autocrypt_header = None;
if incoming {
// See `get_all_addresses_from_header()` for why we take the last valid header.
for val in aheader_values.iter().rev() {
autocrypt_header = match Aheader::from_str(val) {
Ok(header) if addr_cmp(&header.addr, &from.addr) => Some(header),
Ok(header) => {
warn!(
context,
"Autocrypt header address {:?} is not {:?}.", header.addr, from.addr
);
continue;
}
Err(err) => {
warn!(context, "Failed to parse Autocrypt header: {:#}.", err);
continue;
}
};
break;
}
} else {
None
};
}
let autocrypt_fingerprint = if let Some(autocrypt_header) = &autocrypt_header {
let fingerprint = autocrypt_header.public_key.dc_fingerprint().hex();