Check DKIM Authentication-Results (#3583)

Fix #3507

Note that this is not intended for a release at this point! We first have to test whether it runs stable enough. If we want to make a release while we are not confident enough in authres-checking, then we have to disable it.

BTW, most of the 3000 new lines are in `test_data/messages/dkimchecks...`, not the actual code

da3a4b94 adds the results to the Message info. It currently does this by adding them to `hop_info`. Maybe we should rename `hop_info` to `extra_info` or something; this has the disadvantage that we can't rename the sql column name though.

Follow-ups for this could be:
- In `update_authservid_candidates()`: Implement the rest of the algorithm @hpk42 and me thought about. What's missing is remembering how sure we are that these are the right authserv-ids. Esp., when receiving a message sent from another account at the same domain, we can be quite sure that the authserv-ids in there are the ones of our email server. This will make authres-checking work with buzon.uy, disroot.org, yandex.ru, mailo.com, and riseup.net.
- Think about how we present this to the user - e.g. currently the only change is that we don't accept key changes, which will mean that the small lock on the message is not shown.
- And it will mean that we can fully enable AEAP, after revisiting the security implications of this, and assuming everyone (esp. @link2xt who pointed out the problems in the first place) feels comfortable with it.
This commit is contained in:
Hocuri
2022-10-28 12:15:37 +02:00
committed by GitHub
parent d8bc3769a5
commit b1c6c40fa7
326 changed files with 3304 additions and 42 deletions

View File

@@ -66,6 +66,9 @@
### Changes
- Look at Authentication-Results. Don't accept Autocrypt key changes
if they come with negative authentiation results while this contact
sent emails with positive authentication results in the past. #3583
- jsonrpc in cffi also sends events now #3662
- jsonrpc: new format for events and better typescript autocompletion
- Join all "[migration] vXX" log messages into one

744
src/authres.rs Normal file
View File

@@ -0,0 +1,744 @@
//! Parsing and handling of the Authentication-Results header.
//! See the comment on [`handle_authres`] for more.
use std::borrow::Cow;
use std::collections::BTreeSet;
use std::fmt;
use anyhow::Result;
use mailparse::MailHeaderMap;
use mailparse::ParsedMail;
use once_cell::sync::Lazy;
use crate::config::Config;
use crate::context::Context;
use crate::headerdef::HeaderDef;
use crate::tools::time;
use crate::tools::EmailAddress;
/// `authres` is short for the Authentication-Results header, defined in
/// <https://datatracker.ietf.org/doc/html/rfc8601>, which contains info
/// about whether DKIM and SPF passed.
///
/// To mitigate From forgery, we remember for each sending domain whether it is known
/// to have valid DKIM. If an email from such a domain comes with invalid DKIM,
/// we don't allow changing the autocrypt key.
///
/// See <https://github.com/deltachat/deltachat-core-rust/issues/3507>.
pub(crate) async fn handle_authres(
context: &Context,
mail: &ParsedMail<'_>,
from: &str,
message_time: i64,
) -> Result<DkimResults> {
let from_domain = match EmailAddress::new(from) {
Ok(email) => email.domain,
Err(e) => {
warn!(context, "invalid email {:#}", e);
// This email is invalid, but don't return an error, we still want to
// add a stub to the database so that it's not downloaded again
return Ok(DkimResults::default());
}
};
let authres = parse_authres_headers(&mail.get_headers(), &from_domain);
update_authservid_candidates(context, &authres).await?;
compute_dkim_results(context, authres, &from_domain, message_time).await
}
#[derive(Default, Debug)]
pub(crate) struct DkimResults {
/// Whether DKIM passed for this particular e-mail.
pub dkim_passed: bool,
/// Whether DKIM is known to work for e-mails coming from the sender's domain,
/// i.e. whether we expect DKIM to work.
pub dkim_should_work: bool,
/// Whether changing the public Autocrypt key should be allowed.
/// This is false if we expected DKIM to work (dkim_works=true),
/// but it failed now (dkim_passed=false).
pub allow_keychange: bool,
}
impl fmt::Display for DkimResults {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"DKIM Results: Passed={}, Works={}, Allow_Keychange={}",
self.dkim_passed, self.dkim_should_work, self.allow_keychange
)?;
if !self.allow_keychange {
write!(fmt, " KEYCHANGES NOT ALLOWED!!!!")?;
}
Ok(())
}
}
type AuthservId = String;
#[derive(Debug, PartialEq)]
enum DkimResult {
/// The header explicitly said that DKIM passed
Passed,
/// The header explicitly said that DKIM failed
Failed,
/// The header didn't say anything about DKIM; this might mean that it wasn't
/// checked, but it might also mean that it failed. This is because some providers
/// (e.g. ik.me, mail.ru, posteo.de) don't add `dkim=none` to their
/// Authentication-Results if there was no DKIM.
Nothing,
}
type ParsedAuthresHeaders = Vec<(AuthservId, DkimResult)>;
fn parse_authres_headers(
headers: &mailparse::headers::Headers<'_>,
from_domain: &str,
) -> ParsedAuthresHeaders {
let mut res = Vec::new();
for header_value in headers.get_all_values(HeaderDef::AuthenticationResults.into()) {
let header_value = remove_comments(&header_value);
if let Some(mut authserv_id) = header_value.split(';').next() {
if authserv_id.contains(char::is_whitespace) || authserv_id.is_empty() {
// Outlook violates the RFC by not adding an authserv-id at all, which we notice
// because there is whitespace in the first identifier before the ';'.
// Authentication-Results-parsing still works securely because they remove incoming
// Authentication-Results headers.
// We just use an arbitrary authserv-id, it will work for Outlook, and in general,
// with providers not implementing the RFC correctly, someone can trick us
// into thinking that an incoming email is DKIM-correct, anyway.
// The most important thing here is that we have some valid `authserv_id`.
authserv_id = "invalidAuthservId";
}
let dkim_passed = parse_one_authres_header(&header_value, from_domain);
res.push((authserv_id.to_string(), dkim_passed));
}
}
res
}
/// The headers can contain comments that look like this:
/// ```text
/// Authentication-Results: (this is a comment) gmx.net; (another; comment) dkim=pass;
/// ```
fn remove_comments(header: &str) -> Cow<'_, str> {
// In Pomsky, this is:
// "(" Codepoint* lazy ")"
// See https://playground.pomsky-lang.org/?text=%22(%22%20Codepoint*%20lazy%20%22)%22
static RE: Lazy<regex::Regex> = Lazy::new(|| regex::Regex::new(r"\([\s\S]*?\)").unwrap());
RE.replace_all(header, " ")
}
/// Parses a single Authentication-Results header, like:
///
/// ```text
/// Authentication-Results: gmx.net; dkim=pass header.i=@slack.com
/// ```
fn parse_one_authres_header(header_value: &str, from_domain: &str) -> DkimResult {
if let Some((before_dkim_part, dkim_to_end)) = header_value.split_once("dkim=") {
// Check that the character right before `dkim=` is a space or a tab
// so that we wouldn't e.g. mistake `notdkim=pass` for `dkim=pass`
if before_dkim_part.ends_with(' ') || before_dkim_part.ends_with('\t') {
let dkim_part = dkim_to_end.split(';').next().unwrap_or_default();
let dkim_parts: Vec<_> = dkim_part.split_whitespace().collect();
if let Some(&"pass") = dkim_parts.first() {
// DKIM headers contain a header.d or header.i field
// 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) {
// We have found a `dkim=pass` header!
return DkimResult::Passed;
}
} else {
// dkim=fail, dkim=none, ...
return DkimResult::Failed;
}
}
}
DkimResult::Nothing
}
/// ## About authserv-ids
///
/// After having checked DKIM, our email server adds an Authentication-Results header.
///
/// Now, an attacker could just add an Authentication-Results header that says dkim=pass
/// in order to make us think that DKIM was correct in their From-forged email.
///
/// In order to prevent this, each email server adds its authserv-id to the
/// Authentication-Results header, e.g. Testrun's authserv-id is `testrun.org`, Gmail's
/// is `mx.google.com`. When Testrun gets a mail delivered from outside, it will then
/// remove any Authentication-Results headers whose authserv-id is also `testrun.org`.
///
/// We need to somehow find out the authserv-id(s) of our email server, so that
/// we can use the Authentication-Results with the right authserv-id.
///
/// ## What this function does
///
/// When receiving an email, this function is called and updates the candidates for
/// our server's authserv-id, i.e. what we think our server's authserv-id is.
///
/// Usually, every incoming email has Authentication-Results with our server's
/// authserv-id, so, the intersection of the existing authserv-ids and the incoming
/// authserv-ids for our server's authserv-id is a good guess for our server's
/// authserv-id. When this intersection is empty, we assume that the authserv-id has
/// changed and start over with the new authserv-ids.
///
/// See [`handle_authres`].
async fn update_authservid_candidates(
context: &Context,
authres: &ParsedAuthresHeaders,
) -> Result<()> {
let mut new_ids: BTreeSet<&str> = authres
.iter()
.map(|(authserv_id, _dkim_passed)| authserv_id.as_str())
.collect();
if new_ids.is_empty() {
// The incoming message doesn't contain any authentication results, maybe it's a
// self-sent or a mailer-daemon message
return Ok(());
}
let old_config = context.get_config(Config::AuthservIdCandidates).await?;
let old_ids = parse_authservid_candidates_config(&old_config);
let intersection: BTreeSet<&str> = old_ids.intersection(&new_ids).copied().collect();
if !intersection.is_empty() {
new_ids = intersection;
}
// If there were no AuthservIdCandidates previously, just start with
// the ones from the incoming email
if old_ids != new_ids {
let new_config = new_ids.into_iter().collect::<Vec<_>>().join(" ");
context
.set_config(Config::AuthservIdCandidates, Some(&new_config))
.await?;
// Updating the authservid candidates may mean that we now consider
// emails as "failed" which "passed" previously, so we need to
// reset our expectation which DKIMs work.
clear_dkim_works(context).await?
}
Ok(())
}
/// Use the parsed authres and the authservid candidates to compute whether DKIM passed
/// and whether a keychange should be allowed.
///
/// We track in the `sending_domains` table whether we get positive Authentication-Results
/// for mails from a contact (meaning that their provider properly authenticates against
/// our provider).
///
/// Once a contact is known to come with positive Authentication-Resutls (dkim: pass),
/// we don't accept Autocrypt key changes if they come with negative Authentication-Results.
async fn compute_dkim_results(
context: &Context,
mut authres: ParsedAuthresHeaders,
from_domain: &str,
message_time: i64,
) -> Result<DkimResults> {
let mut dkim_passed = false;
let ids_config = context.get_config(Config::AuthservIdCandidates).await?;
let ids = parse_authservid_candidates_config(&ids_config);
// Remove all foreign authentication results
authres.retain(|(authserv_id, _dkim_passed)| ids.contains(authserv_id.as_str()));
if authres.is_empty() {
// If the authentication results are empty, then our provider doesn't add them
// and an attacker could just add their own Authentication-Results, making us
// think that DKIM passed. So, in this case, we can as well assume that DKIM passed.
dkim_passed = true;
} else {
for (_authserv_id, current_dkim_passed) in authres {
match current_dkim_passed {
DkimResult::Passed => {
dkim_passed = true;
break;
}
DkimResult::Failed => {
dkim_passed = false;
break;
}
DkimResult::Nothing => {
// Continue looking for an Authentication-Results header
}
}
}
}
let last_working_timestamp = dkim_works_timestamp(context, from_domain).await?;
let mut dkim_should_work = dkim_should_work(last_working_timestamp)?;
if message_time > last_working_timestamp && dkim_passed {
set_dkim_works_timestamp(context, from_domain, message_time).await?;
dkim_should_work = true;
}
Ok(DkimResults {
dkim_passed,
dkim_should_work,
allow_keychange: dkim_passed || !dkim_should_work,
})
}
/// Whether DKIM in emails from this domain should be considered to work.
fn dkim_should_work(last_working_timestamp: i64) -> Result<bool> {
// When we get an email with valid DKIM-Authentication-Results,
// then we assume that DKIM works for 30 days from this time on.
let should_work_until = last_working_timestamp + 3600 * 24 * 30;
let dkim_ever_worked = last_working_timestamp > 0;
// We're using time() here and not the time when the message
// claims to have been sent (passed around as `message_time`)
// because otherwise an attacker could just put a time way
// in the future into the `Date` header and then we would
// assume that DKIM doesn't have to be valid anymore.
let dkim_should_work_now = should_work_until > time();
Ok(dkim_ever_worked && dkim_should_work_now)
}
async fn dkim_works_timestamp(context: &Context, from_domain: &str) -> Result<i64, anyhow::Error> {
let last_working_timestamp: i64 = context
.sql
.query_get_value(
"SELECT dkim_works FROM sending_domains WHERE domain=?",
paramsv![from_domain],
)
.await?
.unwrap_or(0);
Ok(last_working_timestamp)
}
async fn set_dkim_works_timestamp(
context: &Context,
from_domain: &str,
timestamp: i64,
) -> Result<()> {
context
.sql
.execute(
"INSERT INTO sending_domains (domain, dkim_works) VALUES (?,?)
ON CONFLICT(domain) DO UPDATE SET dkim_works=excluded.dkim_works",
paramsv![from_domain, timestamp],
)
.await?;
Ok(())
}
async fn clear_dkim_works(context: &Context) -> Result<()> {
context
.sql
.execute("DELETE FROM sending_domains", paramsv![])
.await?;
Ok(())
}
fn parse_authservid_candidates_config(config: &Option<String>) -> BTreeSet<&str> {
config
.as_deref()
.map(|c| c.split_whitespace().collect())
.unwrap_or_default()
}
#[cfg(test)]
mod tests {
#![allow(clippy::indexing_slicing)]
use std::time::Duration;
use tokio::fs;
use tokio::io::AsyncReadExt;
use super::*;
use crate::e2ee;
use crate::mimeparser;
use crate::peerstate::Peerstate;
use crate::securejoin::get_securejoin_qr;
use crate::securejoin::join_securejoin;
use crate::test_utils;
use crate::test_utils::TestContext;
use crate::test_utils::TestContextManager;
use crate::tools;
#[test]
fn test_remove_comments() {
let header = "Authentication-Results: mx3.messagingengine.com;
dkim=pass (1024-bit rsa key sha256) header.d=riseup.net;"
.to_string();
assert_eq!(
remove_comments(&header),
"Authentication-Results: mx3.messagingengine.com;
dkim=pass header.d=riseup.net;"
);
let header = ") aaa (".to_string();
assert_eq!(remove_comments(&header), ") aaa (");
let header = "((something weird) no comment".to_string();
assert_eq!(remove_comments(&header), " no comment");
let header = "🎉(🎉(🎉))🎉(".to_string();
assert_eq!(remove_comments(&header), "🎉 )🎉(");
// Comments are allowed to include whitespace
let header = "(com\n\t\r\nment) no comment (comment)".to_string();
assert_eq!(remove_comments(&header), " no comment ");
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_parse_authentication_results() -> Result<()> {
let t = TestContext::new().await;
t.configure_addr("alice@gmx.net").await;
let bytes = b"Authentication-Results: gmx.net; dkim=pass header.i=@slack.com
Authentication-Results: gmx.net; dkim=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::Passed),
("gmx.net".to_string(), DkimResult::Nothing)
]
);
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 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)],);
// Weird Authentication-Results from Outlook without an authserv-id
let bytes = b"Authentication-Results: spf=pass (sender IP is 40.92.73.85)
smtp.mailfrom=hotmail.com; dkim=pass (signature was verified)
header.d=hotmail.com;dmarc=pass action=none
header.from=hotmail.com;compauth=pass reason=100";
let mail = mailparse::parse_mail(bytes)?;
let actual = parse_authres_headers(&mail.get_headers(), "hotmail.com");
// At this point, the most important thing to test is that there are no
// authserv-ids with whitespace in them.
assert_eq!(
actual,
vec![("invalidAuthservId".to_string(), DkimResult::Passed)]
);
let bytes = b"Authentication-Results: gmx.net; dkim=none header.i=@slack.com
Authentication-Results: gmx.net; dkim=pass header.i=@slack.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::Failed),
("gmx.net".to_string(), DkimResult::Passed)
]
);
// ';' in comments
let bytes = b"Authentication-Results: mx1.riseup.net;
dkim=pass (1024-bit key; unprotected) header.d=yandex.ru header.i=@yandex.ru header.a=rsa-sha256 header.s=mail header.b=avNJu6sw;
dkim-atps=neutral";
let mail = mailparse::parse_mail(bytes)?;
let actual = parse_authres_headers(&mail.get_headers(), "yandex.ru");
assert_eq!(
actual,
vec![("mx1.riseup.net".to_string(), DkimResult::Passed)]
);
let bytes = br#"Authentication-Results: box.hispanilandia.net;
dkim=fail reason="signature verification failed" (2048-bit key; secure) header.d=disroot.org header.i=@disroot.org header.b="kqh3WUKq";
dkim-atps=neutral
Authentication-Results: box.hispanilandia.net; dmarc=pass (p=quarantine dis=none) header.from=disroot.org
Authentication-Results: box.hispanilandia.net; spf=pass smtp.mailfrom=adbenitez@disroot.org"#;
let mail = mailparse::parse_mail(bytes)?;
let actual = parse_authres_headers(&mail.get_headers(), "disroot.org");
assert_eq!(
actual,
vec![
("box.hispanilandia.net".to_string(), DkimResult::Failed),
("box.hispanilandia.net".to_string(), DkimResult::Nothing),
("box.hispanilandia.net".to_string(), DkimResult::Nothing),
]
);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_update_authservid_candidates() -> Result<()> {
let t = TestContext::new_alice().await;
update_authservid_candidates_test(&t, &["mx3.messagingengine.com"]).await;
let candidates = t.get_config(Config::AuthservIdCandidates).await?.unwrap();
assert_eq!(candidates, "mx3.messagingengine.com");
// "mx4.messagingengine.com" seems to be the new authserv-id, DC should accept it
update_authservid_candidates_test(&t, &["mx4.messagingengine.com"]).await;
let candidates = t.get_config(Config::AuthservIdCandidates).await?.unwrap();
assert_eq!(candidates, "mx4.messagingengine.com");
// A message without any Authentication-Results headers shouldn't remove all
// candidates since it could be a mailer-daemon message or so
update_authservid_candidates_test(&t, &[]).await;
let candidates = t.get_config(Config::AuthservIdCandidates).await?.unwrap();
assert_eq!(candidates, "mx4.messagingengine.com");
update_authservid_candidates_test(&t, &["mx4.messagingengine.com", "someotherdomain.com"])
.await;
let candidates = t.get_config(Config::AuthservIdCandidates).await?.unwrap();
assert_eq!(candidates, "mx4.messagingengine.com");
Ok(())
}
/// Calls update_authservid_candidates(), meant for using in a test.
///
/// update_authservid_candidates() only looks at the keys of its
/// `authentication_results` parameter. So, this function takes `incoming_ids`
/// and adds some AuthenticationResults to get the HashMap we need.
async fn update_authservid_candidates_test(context: &Context, incoming_ids: &[&str]) {
let v = incoming_ids
.iter()
.map(|id| (id.to_string(), DkimResult::Passed))
.collect();
update_authservid_candidates(context, &v).await.unwrap()
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_realworld_authentication_results() -> Result<()> {
let mut test_failed = false;
let dir = tools::read_dir("test-data/message/dkimchecks-2022-09-28/".as_ref())
.await
.unwrap();
let mut bytes = Vec::new();
for entry in dir {
if !entry.file_type().await.unwrap().is_dir() {
continue;
}
let self_addr = entry.file_name().into_string().unwrap();
let self_domain = EmailAddress::new(&self_addr).unwrap().domain;
let authres_parsing_works = [
"ik.me",
"web.de",
"posteo.de",
"gmail.com",
"hotmail.com",
"mail.ru",
"aol.com",
"yahoo.com",
"icloud.com",
"fastmail.com",
"mail.de",
"outlook.com",
"gmx.de",
"testrun.org",
]
.contains(&self_domain.as_str());
let t = TestContext::new().await;
t.configure_addr(&self_addr).await;
if !authres_parsing_works {
println!("========= Receiving as {} =========", &self_addr);
}
// Simulate receiving all emails once, so that we have the correct authserv-ids
let mut dir = tools::read_dir(&entry.path()).await.unwrap();
// The ordering in which the emails are received can matter;
// the test _should_ pass for every ordering.
dir.sort_by_key(|d| d.file_name());
//rand::seq::SliceRandom::shuffle(&mut dir[..], &mut rand::thread_rng());
for entry in &dir {
let mut file = fs::File::open(entry.path()).await?;
bytes.clear();
file.read_to_end(&mut bytes).await.unwrap();
let mail = mailparse::parse_mail(&bytes)?;
let from = &mimeparser::get_from(&mail.headers)[0].addr;
let res = handle_authres(&t, &mail, from, time()).await?;
assert!(res.allow_keychange);
}
for entry in &dir {
let mut file = fs::File::open(entry.path()).await?;
bytes.clear();
file.read_to_end(&mut bytes).await.unwrap();
let mail = mailparse::parse_mail(&bytes)?;
let from = &mimeparser::get_from(&mail.headers)[0].addr;
let res = handle_authres(&t, &mail, from, time()).await?;
if !res.allow_keychange {
println!(
"!!!!!! FAILURE Receiving {:?}, keychange is not allowed !!!!!!",
entry.path()
);
test_failed = true;
}
let from_domain = EmailAddress::new(from).unwrap().domain;
assert_eq!(
res.dkim_should_work,
dkim_should_work(dkim_works_timestamp(&t, &from_domain).await?)?
);
assert_eq!(res.dkim_passed, res.dkim_should_work);
// delta.blinzeln.de and gmx.de have invalid DKIM, so the DKIM check should fail
let expected_result = (from_domain != "delta.blinzeln.de") && (from_domain != "gmx.de")
// These are (fictional) forged emails where the attacker added a fake
// Authentication-Results before sending the email
&& from != "forged-authres-added@example.com"
// Other forged emails
&& !from.starts_with("forged");
if res.dkim_passed != expected_result {
if authres_parsing_works {
println!(
"!!!!!! FAILURE Receiving {:?}, order {:#?} wrong result: !!!!!!",
entry.path(),
dir.iter().map(|e| e.file_name()).collect::<Vec<_>>()
);
test_failed = true;
}
println!("From {}: {}", from_domain, res.dkim_passed);
}
}
}
assert!(!test_failed);
Ok(())
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_handle_authres() {
let t = TestContext::new().await;
// Even if the format is wrong and parsing fails, handle_authres() shouldn't
// return an Err because this would prevent the message from being added
// to the database and downloaded again and again
let bytes = b"Authentication-Results: dkim=";
let mail = mailparse::parse_mail(bytes).unwrap();
handle_authres(&t, &mail, "invalidfrom.com", time())
.await
.unwrap();
}
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_handle_authres_fails() -> Result<()> {
let mut tcm = TestContextManager::new();
let alice = tcm.alice().await;
let bob = tcm.bob().await;
// Bob sends Alice a message, so she gets his key
tcm.send_recv_accept(&bob, &alice, "Hi").await;
// We don't need bob anymore, let's make sure it's not accidentally used
drop(bob);
// Assume Alice receives an email from bob@example.net with
// correct DKIM -> `set_dkim_works()` was called
set_dkim_works_timestamp(&alice, "example.net", time()).await?;
// And Alice knows her server's authserv-id
alice
.set_config(Config::AuthservIdCandidates, Some("example.org"))
.await?;
tcm.section("An attacker, bob2, sends a from-forged email to Alice!");
let bob2 = tcm.unconfigured().await;
bob2.configure_addr("bob@example.net").await;
e2ee::ensure_secret_key_exists(&bob2).await?;
let chat = bob2.create_chat(&alice).await;
let mut sent = bob2
.send_text(chat.id, "Please send me lots of money")
.await;
sent.payload
.insert_str(0, "Authentication-Results: example.org; dkim=fail");
let received = alice.recv_msg(&sent).await;
// Assert that the error tells the user about the problem
assert!(received.error.unwrap().contains("DKIM failed"));
let bob_state = Peerstate::from_addr(&alice, "bob@example.net")
.await?
.unwrap();
// Also check that the keypair was not changed
assert_eq!(
bob_state.public_key.unwrap(),
test_utils::bob_keypair().public
);
// Since Alice didn't change the key, Bob can't read her message
let received = tcm
.try_send_recv(&alice, &bob2, "My credit card number is 1234")
.await;
assert!(!received.text.as_ref().unwrap().contains("1234"));
assert!(received.error.is_some());
tcm.section("Turns out bob2 wasn't an attacker at all, Bob just has a new phone and DKIM just stopped working.");
tcm.section("To fix the key problems, Bob scans Alice's QR code.");
let qr = get_securejoin_qr(&alice.ctx, None).await.unwrap();
join_securejoin(&bob2.ctx, &qr).await.unwrap();
loop {
if let Some(mut sent) = bob2.pop_sent_msg_opt(Duration::ZERO).await {
sent.payload
.insert_str(0, "Authentication-Results: example.org; dkim=fail");
alice.recv_msg(&sent).await;
} else if let Some(sent) = alice.pop_sent_msg_opt(Duration::ZERO).await {
bob2.recv_msg(&sent).await;
} else {
break;
}
}
// Unfortunately, securejoin currently doesn't work with authres-checking,
// so these checks would fail:
// let contact_bob = alice.add_or_lookup_contact(&bob2).await;
// assert_eq!(
// contact_bob.is_verified(&alice.ctx).await.unwrap(),
// VerifiedStatus::BidirectVerified
// );
// let contact_alice = bob2.add_or_lookup_contact(&alice).await;
// assert_eq!(
// contact_alice.is_verified(&bob2.ctx).await.unwrap(),
// VerifiedStatus::BidirectVerified
// );
// // Bob can read Alice's messages again
// let received = tcm
// .try_send_recv(&alice, &bob2, "Can you read this again?")
// .await;
// assert_eq!(received.text.as_ref().unwrap(), "Can you read this again?");
// assert!(received.error.is_none());
Ok(())
}
}

View File

@@ -3702,11 +3702,11 @@ mod tests {
// create group and sync it to the second device
let a1_chat_id = create_group_chat(&a1, ProtectionStatus::Unprotected, "foo").await?;
a1.send_text(a1_chat_id, "ho!").await;
let sent = a1.send_text(a1_chat_id, "ho!").await;
let a1_msg = a1.get_last_msg().await;
let a1_chat = Chat::load_from_db(&a1, a1_chat_id).await?;
let a2_msg = a2.recv_msg(&a1.pop_sent_msg().await).await;
let a2_msg = a2.recv_msg(&sent).await;
let a2_chat_id = a2_msg.chat_id;
let a2_chat = Chat::load_from_db(&a2, a2_chat_id).await?;

View File

@@ -184,6 +184,12 @@ pub enum Config {
/// In a future versions, this switch may be removed.
#[strum(props(default = "0"))]
SendSyncMsgs,
/// Space-separated list of all the authserv-ids which we believe
/// may be the one of our email server.
///
/// See `crate::authres::update_authservid_candidates`.
AuthservIdCandidates,
}
impl Context {

View File

@@ -544,6 +544,12 @@ impl Context {
.await?
.to_string(),
);
res.insert(
"authserv_id_candidates",
self.get_config(Config::AuthservIdCandidates)
.await?
.unwrap_or_default(),
);
let elapsed = self.creation_time.elapsed();
res.insert("uptime", duration_to_str(elapsed.unwrap_or_default()));

View File

@@ -4,12 +4,13 @@ use std::collections::HashSet;
use anyhow::{Context as _, Result};
use mailparse::ParsedMail;
use mailparse::SingleInfo;
use crate::aheader::Aheader;
use crate::authres;
use crate::authres::handle_authres;
use crate::contact::addr_cmp;
use crate::context::Context;
use crate::headerdef::HeaderDef;
use crate::headerdef::HeaderDefMap;
use crate::key::{DcKey, Fingerprint, SignedPublicKey, SignedSecretKey};
use crate::keyring::Keyring;
use crate::log::LogExt;
@@ -55,35 +56,43 @@ pub async fn try_decrypt(
.await
}
pub async fn create_decryption_info(
pub async fn prepare_decryption(
context: &Context,
mail: &ParsedMail<'_>,
from: &[SingleInfo],
message_time: i64,
) -> Result<DecryptionInfo> {
let from = mail
.headers
.get_header(HeaderDef::From_)
.and_then(|from_addr| mailparse::addrparse_header(from_addr).ok())
.and_then(|from| from.extract_single_info())
.map(|from| from.addr)
.unwrap_or_default();
let from = if let Some(f) = from.first() {
&f.addr
} else {
return Ok(DecryptionInfo::default());
};
let autocrypt_header = Aheader::from_headers(&from, &mail.headers)
let autocrypt_header = Aheader::from_headers(from, &mail.headers)
.ok_or_log_msg(context, "Failed to parse Autocrypt header")
.flatten();
let peerstate =
get_autocrypt_peerstate(context, &from, autocrypt_header.as_ref(), message_time).await?;
let dkim_results = handle_authres(context, mail, from, message_time).await?;
let peerstate = get_autocrypt_peerstate(
context,
from,
autocrypt_header.as_ref(),
message_time,
dkim_results.allow_keychange,
)
.await?;
Ok(DecryptionInfo {
from,
from: from.to_string(),
autocrypt_header,
peerstate,
message_time,
dkim_results,
})
}
#[derive(Debug)]
#[derive(Default, Debug)]
pub struct DecryptionInfo {
/// The From address. This is the address from the unnencrypted, outer
/// From header.
@@ -96,6 +105,7 @@ pub struct DecryptionInfo {
/// means out-of-order message arrival, We don't modify the
/// peerstate in this case.
pub message_time: i64,
pub(crate) dkim_results: authres::DkimResults,
}
/// Returns a reference to the encrypted payload of a ["Mixed
@@ -263,12 +273,16 @@ fn keyring_from_peerstate(peerstate: &Option<Peerstate>) -> Keyring<SignedPublic
/// If we already know this fingerprint from another contact's peerstate, return that
/// peerstate in order to make AEAP work, but don't save it into the db yet.
///
/// The param `allow_change` is used to prevent the autocrypt key from being changed
/// if we suspect that the message may be forged and have a spoofed sender identity.
///
/// Returns updated peerstate.
pub(crate) async fn get_autocrypt_peerstate(
context: &Context,
from: &str,
autocrypt_header: Option<&Aheader>,
message_time: i64,
allow_change: bool,
) -> Result<Option<Peerstate>> {
let mut peerstate;
@@ -289,8 +303,15 @@ pub(crate) async fn get_autocrypt_peerstate(
if let Some(ref mut peerstate) = peerstate {
if addr_cmp(&peerstate.addr, from) {
peerstate.apply_header(header, message_time);
peerstate.save_to_db(&context.sql, false).await?;
if allow_change {
peerstate.apply_header(header, message_time);
peerstate.save_to_db(&context.sql, false).await?;
} else {
info!(
context,
"Refusing to update existing peerstate of {}", &peerstate.addr
);
}
}
// If `peerstate.addr` and `from` differ, this means that
// someone is using the same key but a different addr, probably

View File

@@ -63,6 +63,11 @@ pub enum HeaderDef {
Sender,
EphemeralTimer,
Received,
/// A header that includes the results of the DKIM, SPF and DMARC checks.
/// See <https://datatracker.ietf.org/doc/html/rfc8601>
AuthenticationResults,
_TestHeader,
}

View File

@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
use ::pgp::types::KeyTrait;
use anyhow::{bail, ensure, format_err, Context as _, Result};
use futures::{StreamExt, TryStreamExt};
use futures::StreamExt;
use futures_lite::FutureExt;
use rand::{thread_rng, Rng};
use tokio::fs::{self, File};
@@ -17,7 +17,6 @@ use crate::chat::{self, delete_and_reset_all_device_msgs, ChatId};
use crate::config::Config;
use crate::contact::ContactId;
use crate::context::Context;
use crate::e2ee;
use crate::events::EventType;
use crate::key::{self, DcKey, DcSecretKey, SignedPublicKey, SignedSecretKey};
use crate::log::LogExt;
@@ -31,6 +30,7 @@ use crate::tools::{
create_folder, delete_file, get_filesuffix_lc, open_file_std, read_file, time, write_file,
EmailAddress,
};
use crate::{e2ee, tools};
// Name of the database file in the backup.
const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite";
@@ -576,10 +576,7 @@ async fn export_backup_inner(
.append_path_with_name(temp_db_path, DBFILE_BACKUP_NAME)
.await?;
let read_dir: Vec<_> =
tokio_stream::wrappers::ReadDirStream::new(fs::read_dir(context.get_blobdir()).await?)
.try_collect()
.await?;
let read_dir = tools::read_dir(context.get_blobdir()).await?;
let count = read_dir.len();
let mut written_files = 0;

View File

@@ -93,6 +93,7 @@ mod update_helper;
pub mod webxdc;
#[macro_use]
mod dehtml;
mod authres;
mod color;
pub mod html;
pub mod plaintext;

View File

@@ -15,7 +15,7 @@ use crate::blob::BlobObject;
use crate::constants::{DC_DESIRED_TEXT_LINES, DC_DESIRED_TEXT_LINE_LEN};
use crate::contact::{addr_cmp, addr_normalize, ContactId};
use crate::context::Context;
use crate::decrypt::{create_decryption_info, try_decrypt};
use crate::decrypt::{prepare_decryption, try_decrypt};
use crate::dehtml::dehtml;
use crate::events::EventType;
use crate::format_flowed::unformat_flowed;
@@ -178,7 +178,7 @@ impl MimeMessage {
.get_header_value(HeaderDef::Date)
.and_then(|v| mailparse::dateparse(&v).ok())
.unwrap_or_default();
let hop_info = parse_receive_headers(&mail.get_headers());
let mut hop_info = parse_receive_headers(&mail.get_headers());
let mut headers = Default::default();
let mut recipients = Default::default();
@@ -220,7 +220,9 @@ impl MimeMessage {
let mut mail_raw = Vec::new();
let mut gossiped_addr = Default::default();
let mut from_is_signed = false;
let mut decryption_info = create_decryption_info(context, &mail, message_time).await?;
let mut decryption_info = prepare_decryption(context, &mail, &from, message_time).await?;
hop_info += "\n\n";
hop_info += &decryption_info.dkim_results.to_string();
// `signatures` is non-empty exactly if the message was encrypted and correctly signed.
let (mail, signatures, warn_empty_signature) =
@@ -369,6 +371,11 @@ impl MimeMessage {
parser.heuristically_parse_ndn(context).await;
parser.parse_headers(context).await?;
if !decryption_info.dkim_results.allow_keychange {
for part in parser.parts.iter_mut() {
part.error = Some("Seems like DKIM failed, this either is an attack or (more likely) a bug in Authentication-Results checking. Please tell us about this at https://support.delta.chat.".to_string());
}
}
if warn_empty_signature && parser.signatures.is_empty() {
for part in parser.parts.iter_mut() {
part.error = Some("No valid signature".to_string());

View File

@@ -609,6 +609,13 @@ CREATE INDEX smtp_messageid ON imap(rfc724_mid);
92
).await?;
}
if dbversion < 93 {
sql.execute_migration(
"CREATE TABLE sending_domains(domain TEXT PRIMARY KEY, dkim_works INTEGER DEFAULT 0);",
93,
)
.await?;
}
let new_version = sql
.get_raw_config_int(VERSION_CFG)

View File

@@ -74,6 +74,14 @@ impl TestContextManager {
.await
}
/// Creates a new unconfigured test account.
pub async fn unconfigured(&mut self) -> TestContext {
TestContext::builder()
.with_log_sink(self.log_tx.clone())
.build()
.await
}
/// Writes info events to the log that mark a section, e.g.:
///
/// ========== `msg` goes here ==========
@@ -89,19 +97,23 @@ impl TestContextManager {
/// - Let the other TestContext receive it and accept the chat
/// - Assert that the message arrived
pub async fn send_recv_accept(&self, from: &TestContext, to: &TestContext, msg: &str) {
let received_msg = self.try_send_recv(from, to, msg).await;
assert_eq!(received_msg.text.as_ref().unwrap(), msg);
received_msg.chat_id.accept(to).await.unwrap();
}
/// - Let one TestContext send a message
/// - Let the other TestContext receive it
pub async fn try_send_recv(&self, from: &TestContext, to: &TestContext, msg: &str) -> Message {
self.section(&format!(
"{} sends a message '{}' to {}",
from.name(),
msg,
to.name()
));
let chat = from.create_chat(to).await;
let sent = from.send_text(chat.id, msg).await;
let received_msg = to.recv_msg(&sent).await;
received_msg.chat_id.accept(to).await.unwrap();
assert_eq!(received_msg.text.unwrap(), msg);
to.recv_msg(&sent).await
}
pub async fn change_addr(&self, test_context: &TestContext, new_addr: &str) {
@@ -369,6 +381,12 @@ impl TestContext {
///
/// Panics if there is no message or on any error.
pub async fn pop_sent_msg(&self) -> SentMessage {
self.pop_sent_msg_opt(Duration::from_secs(3))
.await
.expect("no sent message found in jobs table")
}
pub async fn pop_sent_msg_opt(&self, timeout: Duration) -> Option<SentMessage> {
let start = Instant::now();
let (rowid, msg_id, payload, recipients) = loop {
let row = self
@@ -393,25 +411,25 @@ impl TestContext {
if let Some(row) = row {
break row;
}
if start.elapsed() < Duration::from_secs(3) {
if start.elapsed() < timeout {
tokio::time::sleep(Duration::from_millis(100)).await;
} else {
panic!("no sent message found in jobs table");
return None;
}
};
self.ctx
.sql
.execute("DELETE FROM jobs WHERE id=?;", paramsv![rowid])
.execute("DELETE FROM smtp WHERE id=?;", paramsv![rowid])
.await
.expect("failed to remove job");
update_msg_state(&self.ctx, msg_id, MessageState::OutDelivered)
.await
.expect("failed to update message state");
SentMessage {
Some(SentMessage {
payload,
sender_msg_id: msg_id,
recipients,
}
})
}
/// Parses a message.
@@ -725,7 +743,7 @@ impl Drop for LogSink {
/// passed through a SMTP-IMAP pipeline.
#[derive(Debug, Clone)]
pub struct SentMessage {
payload: String,
pub payload: String,
recipients: String,
pub sender_msg_id: MsgId,
}

View File

@@ -12,7 +12,7 @@ use std::time::{Duration, SystemTime};
use anyhow::{bail, Error, Result};
use chrono::{Local, TimeZone};
use futures::StreamExt;
use futures::{StreamExt, TryStreamExt};
use mailparse::dateparse;
use mailparse::headers::Headers;
use mailparse::MailHeaderMap;
@@ -495,6 +495,13 @@ pub fn open_file_std<P: AsRef<std::path::Path>>(
}
}
pub async fn read_dir(path: &Path) -> Result<Vec<fs::DirEntry>> {
let res = tokio_stream::wrappers::ReadDirStream::new(fs::read_dir(path).await?)
.try_collect()
.await?;
Ok(res)
}
pub(crate) fn time() -> i64 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
@@ -715,7 +722,9 @@ hi
Message-ID: 2dfdbde7@example.org
Hop: From: localhost; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:22 +0000
Hop: From: hq5.merlinux.eu; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:25 +0000";
Hop: From: hq5.merlinux.eu; By: hq5.merlinux.eu; Date: Sat, 14 Sep 2019 17:00:25 +0000
DKIM Results: Passed=true, Works=true, Allow_Keychange=true";
check_parse_receive_headers_integration(raw, expected).await;
let raw = include_bytes!("../test-data/message/encrypted_with_received_headers.eml");
@@ -732,7 +741,9 @@ Message-ID: Mr.adQpEwndXLH.LPDdlFVJ7wG@example.net
Hop: From: [127.0.0.1]; By: mail.example.org; Date: Mon, 27 Dec 2021 11:21:21 +0000
Hop: From: mout.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 +0000
Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 +0000";
Hop: From: hq5.example.org; By: hq5.example.org; Date: Mon, 27 Dec 2021 11:21:22 +0000
DKIM Results: Passed=true, Works=true, Allow_Keychange=true";
check_parse_receive_headers_integration(raw, expected).await;
}

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas106.aol.mail.ne1.yahoo.com;
dkim=pass header.i=@buzon.uy header.s=2019;
spf=pass smtp.mailfrom=buzon.uy;
dmarc=pass(p=REJECT) header.from=buzon.uy;
From: <alice@buzon.uy>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas206.aol.mail.ne1.yahoo.com;
dkim=unknown;
spf=none smtp.mailfrom=delta.blinzeln.de;
dmarc=unknown header.from=delta.blinzeln.de;
From: <alice@delta.blinzeln.de>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas210.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@disroot.org header.s=mail;
spf=pass smtp.mailfrom=disroot.org;
dmarc=pass(p=QUARANTINE) header.from=disroot.org;
From: <alice@disroot.org>
To: <alice@aol.com>

View File

@@ -0,0 +1,7 @@
Authentication-Results: atlas105.aol.mail.ne1.yahoo.com;
dkim=pass header.i=@fastmail.com header.s=fm2;
dkim=pass header.i=@messagingengine.com header.s=fm2;
spf=pass smtp.mailfrom=fastmail.com;
dmarc=pass(p=NONE,sp=NONE) header.from=fastmail.com;
From: <alice@fastmail.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas-baseline-production.v2-mail-prod1-gq1.omega.yahoo.com;
dkim=pass header.i=@gmail.com header.s=20210112;
spf=pass smtp.mailfrom=gmail.com;
dmarc=pass(p=NONE,sp=QUARANTINE) header.from=gmail.com;
From: <alice@gmail.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,8 @@
Authentication-Results: atlas112.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@hotmail.com header.s=selector1;
spf=pass smtp.mailfrom=hotmail.com;
dmarc=pass(p=NONE) header.from=hotmail.com;
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas101.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@icloud.com header.s=1a1hai;
spf=pass smtp.mailfrom=icloud.com;
dmarc=pass(p=QUARANTINE,sp=QUARANTINE) header.from=icloud.com;
From: <alice@icloud.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas-production.v2-mail-prod1-gq1.omega.yahoo.com;
dkim=pass header.i=@ik.me header.s=20200325;
spf=pass smtp.mailfrom=ik.me;
dmarc=pass(p=REJECT) header.from=ik.me;
From: <alice@ik.me>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas104.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@mail.ru header.s=mail4;
spf=pass smtp.mailfrom=mail.ru;
dmarc=pass(p=REJECT) header.from=mail.ru;
From: <alice@mail.ru>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas211.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@mailo.com header.s=mailo;
spf=pass smtp.mailfrom=mailo.com;
dmarc=pass(p=NONE) header.from=mailo.com;
From: <alice@mailo.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,8 @@
Authentication-Results: atlas-production.v2-mail-prod1-gq1.omega.yahoo.com;
dkim=pass header.i=@outlook.com header.s=selector1;
spf=pass smtp.mailfrom=outlook.com;
dmarc=pass(p=NONE,sp=QUARANTINE) header.from=outlook.com;
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@outlook.com>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas-production.v2-mail-prod1-gq1.omega.yahoo.com;
dkim=pass header.i=@posteo.de header.s=2017;
spf=pass smtp.mailfrom=posteo.de;
dmarc=pass(p=NONE) header.from=posteo.de;
From: <alice@posteo.de>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas114.aol.mail.bf1.yahoo.com;
dkim=pass header.i=@yandex.ru header.s=mail;
spf=pass smtp.mailfrom=yandex.ru;
dmarc=pass(p=NONE) header.from=yandex.ru;
From: <alice@yandex.ru>
To: <alice@aol.com>

View File

@@ -0,0 +1,6 @@
Authentication-Results: atlas206.aol.mail.ne1.yahoo.com;
dkim=unknown;
spf=none smtp.mailfrom=delta.blinzeln.de;
dmarc=unknown header.from=delta.blinzeln.de;
From: forged-authres-added@example.com
Authentication-Results: aaa.com; dkim=pass header.i=@example.com

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=aol.com header.i=@aol.com header.b="sjmqxpKe";
dkim-atps=neutral
From: <alice@aol.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,3 @@
From: <alice@delta.blinzeln.de>
To: <alice@buzon.uy>
Authentication-Results: secure-mailgate.com; auth=pass smtp.auth=91.203.111.88@webbox222.server-home.org

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; secure) header.d=disroot.org header.i=@disroot.org header.b="L9SmOHOj";
dkim-atps=neutral
From: <alice@disroot.org>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,6 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=fastmail.com header.i=@fastmail.com header.b="kLB05is1";
dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="B8mfR89g";
dkim-atps=neutral
From: <alice@fastmail.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="Ngf1X5eN";
dkim-atps=neutral
From: <alice@gmail.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,7 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=hotmail.com header.i=@hotmail.com header.b="dEHn9Szj";
dkim-atps=neutral
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=icloud.com header.i=@icloud.com header.b="rAXD4xVN";
dkim-atps=neutral
From: <alice@icloud.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (1024-bit key; secure) header.d=ik.me header.i=@ik.me header.b="EWWQpVZX";
dkim-atps=neutral
From: <alice@ik.me>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; secure) header.d=mail.de header.i=@mail.de header.b="18cRkjHf";
dkim-atps=neutral
From: <alice@mail.de>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,6 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=mail.ru header.i=@mail.ru header.b="uXBGAnnn";
dkim-atps=neutral
From: <alice@mail.ru>
To: <alice@buzon.uy>
Authentication-Results: smtpng1.m.smailru.net; auth=pass smtp.auth=alice@mail.ru smtp.mailfrom=alice@mail.ru

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (1024-bit key; unprotected) header.d=mailo.com header.i=@mailo.com header.b="awx9eOw9";
dkim-atps=neutral
From: <alice@mailo.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,7 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=outlook.com header.i=@outlook.com header.b="Uq5LH/n/";
dkim-atps=neutral
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@outlook.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; secure) header.d=posteo.de header.i=@posteo.de header.b="AyOucyBM";
dkim-atps=neutral
From: <alice@posteo.de>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (1024-bit key; secure) header.d=riseup.net header.i=@riseup.net header.b="eQhRD1BM";
dkim-atps=neutral
From: <alice@riseup.net>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,5 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (2048-bit key; unprotected) header.d=yahoo.com header.i=@yahoo.com header.b="a1T2PpDI";
dkim-atps=neutral
From: <alice@yahoo.com>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,6 @@
Authentication-Results: mail.buzon.uy;
dkim=pass (1024-bit key; unprotected) header.d=yandex.ru header.i=@yandex.ru header.b="oGBtMMzR";
dkim-atps=neutral
Authentication-Results: iva4-143b1447cf50.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru
From: <alice@yandex.ru>
To: <alice@buzon.uy>

View File

@@ -0,0 +1,3 @@
From: forged-authres-added@example.com
Authentication-Results: aaa.com; dkim=pass header.i=@example.com
Authentication-Results: aaa.com; dkim=pass header.i=@example.com

View File

@@ -0,0 +1,2 @@
From: <alice@aol.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@buzon.uy>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@disroot.org>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@fastmail.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@gmail.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,4 @@
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@icloud.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@ik.me>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@mail.de>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,3 @@
From: <alice@mail.ru>
To: <alice@delta.blinzeln.de>
Authentication-Results: smtpng1.m.smailru.net; auth=pass smtp.auth=alice@mail.ru smtp.mailfrom=alice@mail.ru

View File

@@ -0,0 +1,2 @@
From: <alice@mailo.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,4 @@
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@outlook.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@posteo.de>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@riseup.net>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,2 @@
From: <alice@yahoo.com>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,3 @@
Authentication-Results: iva4-143b1447cf50.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru
From: <alice@yandex.ru>
To: <alice@delta.blinzeln.de>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=aol.com header.i=@aol.com header.b="DBDqUGR2";
dkim-atps=neutral
From: <alice@aol.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=buzon.uy header.i=@buzon.uy header.b="VVA3HpHe";
dkim-atps=neutral
From: <alice@buzon.uy>
To: <alice@disroot.org>

View File

@@ -0,0 +1,3 @@
From: <alice@delta.blinzeln.de>
To: <alice@disroot.org>
Authentication-Results: secure-mailgate.com; auth=pass smtp.auth=91.203.111.88@webbox222.server-home.org

View File

@@ -0,0 +1,6 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=fastmail.com header.i=@fastmail.com header.b="OFgq9UWZ";
dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="B52d7C0G";
dkim-atps=neutral
From: <alice@fastmail.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="lxlrOeGY";
dkim-atps=neutral
From: <alice@gmail.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,7 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=hotmail.com header.i=@hotmail.com header.b="VdDCDs55";
dkim-atps=neutral
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=icloud.com header.i=@icloud.com header.b="kD59vbQH";
dkim-atps=neutral
From: <alice@icloud.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (1024-bit key; unprotected) header.d=ik.me header.i=@ik.me header.b="YBLXQ2kp";
dkim-atps=neutral
From: <alice@ik.me>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=mail.de header.i=@mail.de header.b="3ha9obSK";
dkim-atps=neutral
From: <alice@mail.de>
To: <alice@disroot.org>

View File

@@ -0,0 +1,6 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=mail.ru header.i=@mail.ru header.b="IrDU+LTI";
dkim-atps=neutral
From: <alice@mail.ru>
To: <alice@disroot.org>
Authentication-Results: smtpng1.m.smailru.net; auth=pass smtp.auth=alice@mail.ru smtp.mailfrom=alice@mail.ru

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=mailo.com header.i=@mailo.com header.b="WgsA5pwT";
dkim-atps=neutral
From: <alice@mailo.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,7 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=outlook.com header.i=@outlook.com header.b="UtZoPK7Z";
dkim-atps=neutral
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@outlook.com>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (2048-bit key; unprotected) header.d=posteo.de header.i=@posteo.de header.b="R67Ab9Vj";
dkim-atps=neutral
From: <alice@posteo.de>
To: <alice@disroot.org>

View File

@@ -0,0 +1,5 @@
Authentication-Results: disroot.org;
dkim=pass (1024-bit key; unprotected) header.d=riseup.net header.i=@riseup.net header.b="fFYxwl1W";
dkim-atps=neutral
From: <alice@riseup.net>
To: <alice@disroot.org>

View File

@@ -0,0 +1,6 @@
Authentication-Results: disroot.org;
dkim=pass (1024-bit key; unprotected) header.d=yandex.ru header.i=@yandex.ru header.b="CvyR5Vj/";
dkim-atps=neutral
Authentication-Results: iva4-143b1447cf50.qloud-c.yandex.net; dkim=pass header.i=@yandex.ru
From: <alice@yandex.ru>
To: <alice@disroot.org>

View File

@@ -0,0 +1,3 @@
From: forged-authres-added@example.com
Authentication-Results: aaa.com; dkim=pass header.i=@example.com
Authentication-Results: aaa.com; dkim=pass header.i=@example.com

View File

@@ -0,0 +1,6 @@
From: <alice@aol.com>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=aol.com header.s=a2048 header.b=HlBq3Lmt;
dmarc=pass (policy=reject) header.from=aol.com;
spf=pass (mail3.ecloud.global: domain of alice@aol.com designates 77.238.178.146 as permitted sender) smtp.mailfrom=alice@aol.com

View File

@@ -0,0 +1,6 @@
From: <alice@buzon.uy>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=buzon.uy header.s=2019 header.b=XfN4sE6M;
dmarc=pass (policy=reject) header.from=buzon.uy;
spf=pass (mail3.ecloud.global: domain of alice@buzon.uy designates 185.101.93.79 as permitted sender) smtp.mailfrom=alice@buzon.uy

View File

@@ -0,0 +1,6 @@
From: <alice@delta.blinzeln.de>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=none;
dmarc=none;
spf=none (mail2.ecloud.global: domain of alice@delta.blinzeln.de has no SPF policy when checking 192.162.87.117) smtp.mailfrom=alice@delta.blinzeln.de

View File

@@ -0,0 +1,6 @@
From: <alice@disroot.org>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=disroot.org header.s=mail header.b=Vf7JxMcu;
dmarc=pass (policy=quarantine) header.from=disroot.org;
spf=pass (mail2.ecloud.global: domain of alice@disroot.org designates 178.21.23.139 as permitted sender) smtp.mailfrom=alice@disroot.org

View File

@@ -0,0 +1,7 @@
From: <alice@fastmail.com>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=fastmail.com header.s=fm2 header.b=bQ080jJU;
dkim=pass header.d=messagingengine.com header.s=fm2 header.b=FVyMuSGb;
dmarc=pass (policy=none) header.from=fastmail.com;
spf=pass (mail2.ecloud.global: domain of alice@fastmail.com designates 66.111.4.28 as permitted sender) smtp.mailfrom=alice@fastmail.com

View File

@@ -0,0 +1,6 @@
From: <alice@gmail.com>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=gmail.com header.s=20210112 header.b=f2AxVaaA;
dmarc=pass (policy=none) header.from=gmail.com;
spf=pass (mail2.ecloud.global: domain of alice@gmail.com designates 2a00:1450:4864:20::443 as permitted sender) smtp.mailfrom=alice@gmail.com

View File

@@ -0,0 +1,9 @@
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=hotmail.com header.s=selector1 header.b="ECc21y/J";
arc=pass ("microsoft.com:s=arcselector9901:i=1");
dmarc=pass (policy=none) header.from=hotmail.com;
spf=pass (mail3.ecloud.global: domain of alice@hotmail.com designates 40.92.68.54 as permitted sender) smtp.mailfrom=alice@hotmail.com

View File

@@ -0,0 +1,6 @@
From: <alice@icloud.com>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=icloud.com header.s=1a1hai header.b=enuQcpfH;
dmarc=pass (policy=quarantine) header.from=icloud.com;
spf=pass (mail3.ecloud.global: domain of alice@icloud.com designates 17.57.155.16 as permitted sender) smtp.mailfrom=alice@icloud.com

View File

@@ -0,0 +1,6 @@
From: <alice@ik.me>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=ik.me header.s=20200325 header.b=E5lGMzkQ;
dmarc=pass (policy=reject) header.from=ik.me;
spf=pass (mail2.ecloud.global: domain of alice@ik.me designates 83.166.143.168 as permitted sender) smtp.mailfrom=alice@ik.me

View File

@@ -0,0 +1,6 @@
From: <alice@mail.de>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=mail.de header.s=mailde202009 header.b=vVqLo0H5;
dmarc=pass (policy=none) header.from=mail.de;
spf=pass (mail3.ecloud.global: domain of alice@mail.de designates 2001:868:100:600::216 as permitted sender) smtp.mailfrom=alice@mail.de

View File

@@ -0,0 +1,6 @@
From: <alice@mail.ru>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=mail.ru header.s=mail4 header.b=heZ1ZiKV;
dmarc=pass (policy=reject) header.from=mail.ru;
spf=pass (mail2.ecloud.global: domain of alice@mail.ru designates 94.100.181.251 as permitted sender) smtp.mailfrom=alice@mail.ru

View File

@@ -0,0 +1,6 @@
From: <alice@mailo.com>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=mailo.com header.s=mailo header.b=HnhKNKUg;
dmarc=pass (policy=none) header.from=mailo.com;
spf=pass (mail2.ecloud.global: domain of alice@mailo.com designates 213.182.54.15 as permitted sender) smtp.mailfrom=alice@mailo.com

View File

@@ -0,0 +1,9 @@
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@outlook.com>
To: <alice@e.email>
Authentication-Results: mail3.ecloud.global;
dkim=pass header.d=outlook.com header.s=selector1 header.b=MqNsAJKf;
arc=pass ("microsoft.com:s=arcselector9901:i=1");
dmarc=pass (policy=none) header.from=outlook.com;
spf=pass (mail3.ecloud.global: domain of alice@outlook.com designates 40.92.66.84 as permitted sender) smtp.mailfrom=alice@outlook.com

View File

@@ -0,0 +1,6 @@
From: <alice@posteo.de>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=posteo.de header.s=2017 header.b=bMopHaXo;
dmarc=pass (policy=none) header.from=posteo.de;
spf=pass (mail2.ecloud.global: domain of alice@posteo.de designates 185.67.36.66 as permitted sender) smtp.mailfrom=alice@posteo.de

View File

@@ -0,0 +1,6 @@
From: <alice@riseup.net>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=riseup.net header.s=squak header.b="GUmo/IlI";
dmarc=pass (policy=none) header.from=riseup.net;
spf=pass (mail2.ecloud.global: domain of alice@riseup.net designates 198.252.153.129 as permitted sender) smtp.mailfrom=alice@riseup.net

View File

@@ -0,0 +1,6 @@
From: <alice@yahoo.com>
To: <alice@e.email>
Authentication-Results: mail2.ecloud.global;
dkim=pass header.d=yahoo.com header.s=s2048 header.b=mRSwanl2;
dmarc=pass (policy=reject) header.from=yahoo.com;
spf=pass (mail2.ecloud.global: domain of alice@yahoo.com designates 77.238.178.146 as permitted sender) smtp.mailfrom=alice@yahoo.com

View File

@@ -0,0 +1,3 @@
From: forged-authres-added@example.com
Authentication-Results: mail2.ecloud.global;
Authentication-Results: aaa.com; dkim=pass header.i=@example.com

View File

@@ -0,0 +1,39 @@
ARC-Authentication-Results: i=1; mx1.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=sonic314-20.consmr.mail.ir2.yahoo.com
policy.ptr=sonic314-20.consmr.mail.ir2.yahoo.com;
bimi=none (No BIMI records found);
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=aol.com header.i=@aol.com
header.b=Y+EgdIPN header.a=rsa-sha256 header.s=a2048 x-bits=2048;
dmarc=pass policy.published-domain-policy=reject
policy.applied-disposition=none policy.evaluated-disposition=none
(p=reject,d=none,d.eval=none) policy.policy-from=p
header.from=aol.com;
iprev=pass smtp.remote-ip=77.238.177.146
(sonic314-20.consmr.mail.ir2.yahoo.com);
spf=pass smtp.mailfrom=alice@aol.com
smtp.helo=sonic314-20.consmr.mail.ir2.yahoo.com
Authentication-Results: mx1.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=sonic314-20.consmr.mail.ir2.yahoo.com
policy.ptr=sonic314-20.consmr.mail.ir2.yahoo.com
Authentication-Results: mx1.messagingengine.com;
bimi=none (No BIMI records found)
Authentication-Results: mx1.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx1.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=aol.com header.i=@aol.com
header.b=Y+EgdIPN header.a=rsa-sha256 header.s=a2048 x-bits=2048;
dmarc=pass policy.published-domain-policy=reject
policy.applied-disposition=none policy.evaluated-disposition=none
(p=reject,d=none,d.eval=none) policy.policy-from=p
header.from=aol.com;
iprev=pass smtp.remote-ip=77.238.177.146
(sonic314-20.consmr.mail.ir2.yahoo.com);
spf=pass smtp.mailfrom=alice@aol.com
smtp.helo=sonic314-20.consmr.mail.ir2.yahoo.com
From: <alice@aol.com>
To: <alice@fastmail.com>

View File

@@ -0,0 +1,33 @@
ARC-Authentication-Results: i=1; mx4.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=mail.buzon.uy policy.ptr=mail.buzon.uy;
bimi=none (No BIMI records found);
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=buzon.uy header.i=@buzon.uy
header.b=ibjKHetx header.a=rsa-sha256 header.s=2019 x-bits=2048;
dmarc=pass policy.published-domain-policy=reject
policy.applied-disposition=none policy.evaluated-disposition=none
(p=reject,d=none,d.eval=none) policy.policy-from=p
header.from=buzon.uy;
iprev=pass smtp.remote-ip=185.101.93.79 (mail.buzon.uy);
spf=pass smtp.mailfrom=alice@buzon.uy smtp.helo=mail.buzon.uy
Authentication-Results: mx4.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=mail.buzon.uy policy.ptr=mail.buzon.uy
Authentication-Results: mx4.messagingengine.com;
bimi=none (No BIMI records found)
Authentication-Results: mx4.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx4.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=buzon.uy header.i=@buzon.uy
header.b=ibjKHetx header.a=rsa-sha256 header.s=2019 x-bits=2048;
dmarc=pass policy.published-domain-policy=reject
policy.applied-disposition=none policy.evaluated-disposition=none
(p=reject,d=none,d.eval=none) policy.policy-from=p
header.from=buzon.uy;
iprev=pass smtp.remote-ip=185.101.93.79 (mail.buzon.uy);
spf=pass smtp.mailfrom=alice@buzon.uy smtp.helo=mail.buzon.uy
From: <alice@buzon.uy>
To: <alice@fastmail.com>

View File

@@ -0,0 +1,38 @@
ARC-Authentication-Results: i=1; mx1.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=nx184.node01.secure-mailgate.com
policy.ptr=nx184.node01.secure-mailgate.com;
bimi=skipped (DMARC did not pass);
arc=none (no signatures found);
dkim=none (no signatures found);
dmarc=none policy.published-domain-policy=none
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,d=none,d.eval=none) policy.policy-from=p
header.from=delta.blinzeln.de;
iprev=pass smtp.remote-ip=89.22.108.184
(nx184.node01.secure-mailgate.com);
spf=none smtp.mailfrom=alice@delta.blinzeln.de
smtp.helo=nx184.node01.secure-mailgate.com
Authentication-Results: mx1.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=nx184.node01.secure-mailgate.com
policy.ptr=nx184.node01.secure-mailgate.com
Authentication-Results: mx1.messagingengine.com;
bimi=skipped (DMARC did not pass)
Authentication-Results: mx1.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx1.messagingengine.com;
dkim=none (no signatures found);
dmarc=none policy.published-domain-policy=none
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,d=none,d.eval=none) policy.policy-from=p
header.from=delta.blinzeln.de;
iprev=pass smtp.remote-ip=89.22.108.184
(nx184.node01.secure-mailgate.com);
spf=none smtp.mailfrom=alice@delta.blinzeln.de
smtp.helo=nx184.node01.secure-mailgate.com
From: <alice@delta.blinzeln.de>
To: <alice@fastmail.com>
Authentication-Results: secure-mailgate.com; auth=pass smtp.auth=91.203.111.88@webbox222.server-home.org

View File

@@ -0,0 +1,35 @@
ARC-Authentication-Results: i=1; mx5.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=knopi.disroot.org policy.ptr=knopi.disroot.org;
bimi=none (No BIMI records found);
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=disroot.org
header.i=@disroot.org header.b=OQYRknPj header.a=rsa-sha256
header.s=mail x-bits=2048;
dmarc=pass policy.published-domain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=disroot.org;
iprev=pass smtp.remote-ip=178.21.23.139 (knopi.disroot.org);
spf=pass smtp.mailfrom=alice@disroot.org smtp.helo=knopi.disroot.org
Authentication-Results: mx5.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=knopi.disroot.org policy.ptr=knopi.disroot.org
Authentication-Results: mx5.messagingengine.com;
bimi=none (No BIMI records found)
Authentication-Results: mx5.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx5.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=disroot.org
header.i=@disroot.org header.b=OQYRknPj header.a=rsa-sha256
header.s=mail x-bits=2048;
dmarc=pass policy.published-domain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=disroot.org;
iprev=pass smtp.remote-ip=178.21.23.139 (knopi.disroot.org);
spf=pass smtp.mailfrom=alice@disroot.org smtp.helo=knopi.disroot.org
From: <alice@disroot.org>
To: <alice@fastmail.com>

View File

@@ -0,0 +1,41 @@
ARC-Authentication-Results: i=1; mx6.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=mail-wm1-f67.google.com
policy.ptr=mail-wm1-f67.google.com;
bimi=skipped (DMARC Policy is not at enforcement);
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=gmail.com
header.i=@gmail.com header.b=hr44hXYS header.a=rsa-sha256
header.s=20210112 x-bits=2048;
dmarc=pass policy.published-domain-policy=none
policy.published-subdomain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,sp=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=gmail.com;
iprev=pass smtp.remote-ip=209.85.128.67 (mail-wm1-f67.google.com);
spf=pass smtp.mailfrom=alice@gmail.com
smtp.helo=mail-wm1-f67.google.com
Authentication-Results: mx6.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=mail-wm1-f67.google.com
policy.ptr=mail-wm1-f67.google.com
Authentication-Results: mx6.messagingengine.com;
bimi=skipped (DMARC Policy is not at enforcement)
Authentication-Results: mx6.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx6.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=gmail.com
header.i=@gmail.com header.b=hr44hXYS header.a=rsa-sha256
header.s=20210112 x-bits=2048;
dmarc=pass policy.published-domain-policy=none
policy.published-subdomain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,sp=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=gmail.com;
iprev=pass smtp.remote-ip=209.85.128.67 (mail-wm1-f67.google.com);
spf=pass smtp.mailfrom=alice@gmail.com
smtp.helo=mail-wm1-f67.google.com
From: <alice@gmail.com>
To: <alice@fastmail.com>

View File

@@ -0,0 +1,45 @@
ARC-Authentication-Results: i=2; mx2.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=fail smtp.helo=EUR05-DB8-obe.outbound.protection.outlook.com
policy.ptr=mail-db8eur05olkn2101.outbound.protection.outlook.com;
bimi=skipped (DMARC Policy is not at enforcement);
arc=pass (as.1.microsoft.com=pass, ams.1.microsoft.com=pass)
smtp.remote-ip=40.92.89.101;
dkim=pass (2048-bit rsa key sha256) header.d=hotmail.com
header.i=@hotmail.com header.b=FbLQTic7 header.a=rsa-sha256
header.s=selector1 x-bits=2048;
dmarc=pass policy.published-domain-policy=none
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,d=none,d.eval=none) policy.policy-from=p
header.from=hotmail.com;
iprev=pass smtp.remote-ip=40.92.89.101
(mail-db8eur05olkn2101.outbound.protection.outlook.com);
spf=pass smtp.mailfrom=alice@hotmail.com
smtp.helo=EUR05-DB8-obe.outbound.protection.outlook.com
Authentication-Results: mx2.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=fail smtp.helo=EUR05-DB8-obe.outbound.protection.outlook.com
policy.ptr=mail-db8eur05olkn2101.outbound.protection.outlook.com
Authentication-Results: mx2.messagingengine.com;
bimi=skipped (DMARC Policy is not at enforcement)
Authentication-Results: mx2.messagingengine.com;
arc=pass (as.1.microsoft.com=pass, ams.1.microsoft.com=pass)
smtp.remote-ip=40.92.89.101
Authentication-Results: mx2.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=hotmail.com
header.i=@hotmail.com header.b=FbLQTic7 header.a=rsa-sha256
header.s=selector1 x-bits=2048;
dmarc=pass policy.published-domain-policy=none
policy.applied-disposition=none policy.evaluated-disposition=none
(p=none,d=none,d.eval=none) policy.policy-from=p
header.from=hotmail.com;
iprev=pass smtp.remote-ip=40.92.89.101
(mail-db8eur05olkn2101.outbound.protection.outlook.com);
spf=pass smtp.mailfrom=alice@hotmail.com
smtp.helo=EUR05-DB8-obe.outbound.protection.outlook.com
ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none;
dkim=none; arc=none
From: <alice@hotmail.com>
To: <alice@fastmail.com>

View File

@@ -0,0 +1,41 @@
ARC-Authentication-Results: i=1; mx4.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=qs51p00im-qukt01072701.me.com
policy.ptr=qs51p00im-qukt01072701.me.com;
bimi=declined (Domain declined to participate);
arc=none (no signatures found);
dkim=pass (2048-bit rsa key sha256) header.d=icloud.com
header.i=@icloud.com header.b=QwCPOZZR header.a=rsa-sha256
header.s=1a1hai x-bits=2048;
dmarc=pass policy.published-domain-policy=quarantine
policy.published-subdomain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=quarantine,sp=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=icloud.com;
iprev=pass smtp.remote-ip=17.57.155.16 (qs51p00im-qukt01072701.me.com);
spf=pass smtp.mailfrom=alice@icloud.com
smtp.helo=qs51p00im-qukt01072701.me.com
Authentication-Results: mx4.messagingengine.com;
x-csa=none;
x-me-sender=none;
x-ptr=pass smtp.helo=qs51p00im-qukt01072701.me.com
policy.ptr=qs51p00im-qukt01072701.me.com
Authentication-Results: mx4.messagingengine.com;
bimi=declined (Domain declined to participate)
Authentication-Results: mx4.messagingengine.com;
arc=none (no signatures found)
Authentication-Results: mx4.messagingengine.com;
dkim=pass (2048-bit rsa key sha256) header.d=icloud.com
header.i=@icloud.com header.b=QwCPOZZR header.a=rsa-sha256
header.s=1a1hai x-bits=2048;
dmarc=pass policy.published-domain-policy=quarantine
policy.published-subdomain-policy=quarantine
policy.applied-disposition=none policy.evaluated-disposition=none
(p=quarantine,sp=quarantine,d=none,d.eval=none) policy.policy-from=p
header.from=icloud.com;
iprev=pass smtp.remote-ip=17.57.155.16 (qs51p00im-qukt01072701.me.com);
spf=pass smtp.mailfrom=alice@icloud.com
smtp.helo=qs51p00im-qukt01072701.me.com
From: <alice@icloud.com>
To: <alice@fastmail.com>

Some files were not shown because too many files have changed in this diff Show More