feat: Ignore unprotected headers if Content-Type has "hp" parameter (#7130)

This is a part of implementation of https://www.rfc-editor.org/rfc/rfc9788 "Header Protection for
Cryptographically Protected Email".
This commit is contained in:
iequidoo
2025-10-26 16:33:21 -03:00
committed by iequidoo
parent 6611a9fa02
commit 966ea28f83

View File

@@ -271,7 +271,7 @@ impl MimeMessage {
&mut from,
&mut list_post,
&mut chat_disposition_notification_to,
&mail.headers,
&mail,
);
headers.retain(|k, _| {
!is_hidden(k) || {
@@ -299,7 +299,7 @@ impl MimeMessage {
&mut from,
&mut list_post,
&mut chat_disposition_notification_to,
&part.headers,
part,
);
(part, part.ctype.mimetype.parse::<Mime>()?)
} else {
@@ -536,7 +536,7 @@ impl MimeMessage {
&mut inner_from,
&mut list_post,
&mut chat_disposition_notification_to,
&mail.headers,
mail,
);
if !signatures.is_empty() {
@@ -1632,6 +1632,11 @@ impl MimeMessage {
}
}
/// Merges headers from the email `part` into `headers` respecting header protection.
/// Should only be called with nonempty `headers` if `part` is a root of the Cryptographic
/// Payload as defined in <https://www.rfc-editor.org/rfc/rfc9788.html> "Header Protection for
/// Cryptographically Protected Email", otherwise this may unnecessarily discard headers from
/// outer parts.
#[allow(clippy::too_many_arguments)]
fn merge_headers(
context: &Context,
@@ -1642,10 +1647,14 @@ impl MimeMessage {
from: &mut Option<SingleInfo>,
list_post: &mut Option<String>,
chat_disposition_notification_to: &mut Option<SingleInfo>,
fields: &[mailparse::MailHeader<'_>],
part: &mailparse::ParsedMail,
) {
let fields = &part.headers;
// See <https://www.rfc-editor.org/rfc/rfc9788.html>.
let has_header_protection = part.ctype.params.contains_key("hp");
headers.retain(|k, _| {
!is_protected(k) || {
!(has_header_protection || is_protected(k)) || {
headers_removed.insert(k.to_string());
false
}
@@ -2096,7 +2105,8 @@ pub(crate) fn parse_message_id(ids: &str) -> Result<String> {
}
/// Returns whether the outer header value must be ignored if the message contains a signed (and
/// optionally encrypted) part.
/// optionally encrypted) part. This is independent from the modern Header Protection defined in
/// <https://www.rfc-editor.org/rfc/rfc9788.html>.
///
/// NB: There are known cases when Subject and List-ID only appear in the outer headers of
/// signed-only messages. Such messages are shown as unencrypted anyway.