Check that the character right before dkim= is a space or a tab

This commit is contained in:
Hocuri
2022-10-26 15:03:21 +02:00
parent 6e528d6349
commit 8b64a39542

View File

@@ -4,7 +4,6 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::BTreeSet; use std::collections::BTreeSet;
use std::fmt; use std::fmt;
use std::time::SystemTime;
use anyhow::Result; use anyhow::Result;
use mailparse::MailHeaderMap; use mailparse::MailHeaderMap;
@@ -132,23 +131,27 @@ fn remove_comments(header: &str) -> Cow<'_, str> {
/// Authentication-Results: gmx.net; dkim=pass header.i=@slack.com /// Authentication-Results: gmx.net; dkim=pass header.i=@slack.com
/// ``` /// ```
fn parse_one_authres_header(header_value: &str, from_domain: &str) -> DkimResult { fn parse_one_authres_header(header_value: &str, from_domain: &str) -> DkimResult {
if let Some((_start, dkim_to_end)) = header_value.split_once("dkim=") { if let Some((before_dkim_part, dkim_to_end)) = header_value.split_once("dkim=") {
let dkim_part = dkim_to_end.split(';').next().unwrap_or_default(); // Check that the character right before `dkim=` is a space or a tab
let dkim_parts: Vec<_> = dkim_part.split_whitespace().collect(); // so that we wouldn't e.g. mistake `notdkim=pass` for `dkim=pass`
if let Some(&"pass") = dkim_parts.first() { if before_dkim_part.ends_with(' ') || before_dkim_part.ends_with('\t') {
// DKIM headers contain a header.d or header.i field let dkim_part = dkim_to_end.split(';').next().unwrap_or_default();
// that says which domain signed. We have to check ourselves let dkim_parts: Vec<_> = dkim_part.split_whitespace().collect();
// that this is the same domain as in the From header. if let Some(&"pass") = dkim_parts.first() {
let header_d: &str = &format!("header.d={}", &from_domain); // DKIM headers contain a header.d or header.i field
let header_i: &str = &format!("header.i=@{}", &from_domain); // that says which domain signed. We have to check ourselves
// that this is the same domain as in the From header.
let header_d: &str = &format!("header.d={}", &from_domain);
let header_i: &str = &format!("header.i=@{}", &from_domain);
if dkim_parts.contains(&header_d) || dkim_parts.contains(&header_i) { if dkim_parts.contains(&header_d) || dkim_parts.contains(&header_i) {
// We have found a `dkim=pass` header! // We have found a `dkim=pass` header!
return DkimResult::Passed; return DkimResult::Passed;
}
} else {
// dkim=fail, dkim=none, ...
return DkimResult::Failed;
} }
} else {
// dkim=fail, dkim=none, ...
return DkimResult::Failed;
} }
} }
@@ -391,6 +394,18 @@ Authentication-Results: gmx.net; dkim=pass header.i=@amazonses.com";
] ]
); );
let bytes = b"Authentication-Results: gmx.net; notdkim=pass header.i=@slack.com
Authentication-Results: gmx.net; notdkim=pass header.i=@amazonses.com";
let mail = mailparse::parse_mail(bytes)?;
let actual = parse_authres_headers(&mail.get_headers(), "slack.com");
assert_eq!(
actual,
vec![
("gmx.net".to_string(), DkimResult::Nothing),
("gmx.net".to_string(), DkimResult::Nothing)
]
);
let bytes = b"Authentication-Results: gmx.net; dkim=pass header.i=@amazonses.com"; let bytes = b"Authentication-Results: gmx.net; dkim=pass header.i=@amazonses.com";
let mail = mailparse::parse_mail(bytes)?; let mail = mailparse::parse_mail(bytes)?;
let actual = parse_authres_headers(&mail.get_headers(), "slack.com"); let actual = parse_authres_headers(&mail.get_headers(), "slack.com");