-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
1,276 additions
and
627 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
[package] | ||
name = "mail-auth" | ||
description = "DKIM, ARC, SPF and DMARC library for Rust" | ||
version = "0.5.1" | ||
version = "0.6.0" | ||
edition = "2021" | ||
authors = [ "Stalwart Labs <[email protected]>"] | ||
license = "Apache-2.0 OR MIT" | ||
|
@@ -26,10 +26,8 @@ test = [] | |
ahash = "0.8.0" | ||
ed25519-dalek = { version = "2.0", optional = true } | ||
flate2 = "1.0.25" | ||
lru-cache = "0.1.2" | ||
mail-parser = { version = "0.9", features = ["ludicrous_mode", "full_encoding"] } | ||
mail-builder = { version = "0.3", features = ["ludicrous_mode"] } | ||
parking_lot = "0.12.0" | ||
quick-xml = { version = "0.37", optional = true } | ||
ring = { version = "0.17", optional = true } | ||
rsa = { version = "0.9.6", optional = true } | ||
|
@@ -41,6 +39,7 @@ sha2 = { version = "0.10.6", features = ["oid"], optional = true } | |
hickory-resolver = { version = "0.24", features = ["dns-over-rustls", "dnssec-ring"] } | ||
zip = "2.1.1" | ||
rand = { version = "0.8.5", optional = true } | ||
quick_cache = "0.6.9" | ||
|
||
[dev-dependencies] | ||
tokio = { version = "1.16", features = ["net", "io-util", "time", "rt-multi-thread", "macros"] } | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,14 +35,14 @@ Features: | |
### DKIM Signature Verification | ||
|
||
```rust | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Parse message | ||
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap(); | ||
|
||
// Validate signature | ||
let result = resolver.verify_dkim(&authenticated_message).await; | ||
let result = authenticator.verify_dkim(&authenticated_message).await; | ||
|
||
// Make sure all signatures passed verification | ||
assert!(result.iter().all(|s| s.result() == &DkimResult::Pass)); | ||
|
@@ -85,14 +85,14 @@ Features: | |
### ARC Chain Verification | ||
|
||
```rust | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Parse message | ||
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap(); | ||
|
||
// Validate ARC chain | ||
let result = resolver.verify_arc(&authenticated_message).await; | ||
let result = authenticator.verify_arc(&authenticated_message).await; | ||
|
||
// Make sure ARC passed verification | ||
assert_eq!(result.result(), &DkimResult::Pass); | ||
|
@@ -101,15 +101,15 @@ Features: | |
### ARC Chain Sealing | ||
|
||
```rust | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Parse message to be sealed | ||
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap(); | ||
|
||
// Verify ARC and DKIM signatures | ||
let arc_result = resolver.verify_arc(&authenticated_message).await; | ||
let dkim_result = resolver.verify_dkim(&authenticated_message).await; | ||
let arc_result = authenticator.verify_arc(&authenticated_message).await; | ||
let dkim_result = authenticator.verify_dkim(&authenticated_message).await; | ||
|
||
// Build Authenticated-Results header | ||
let auth_results = AuthenticationResults::new("mx.mydomain.org") | ||
|
@@ -137,45 +137,61 @@ Features: | |
### SPF Policy Evaluation | ||
|
||
```rust | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Verify HELO identity | ||
let result = resolver | ||
.verify_spf_helo("127.0.0.1".parse().unwrap(), "gmail.com", "my-local-domain.org") | ||
let result = authenticator | ||
.verify_spf(SpfParameters::verify_ehlo( | ||
"127.0.0.1".parse().unwrap(), | ||
"gmail.com", | ||
"my-local-domain.org", | ||
)) | ||
.await; | ||
assert_eq!(result.result(), SpfResult::Fail); | ||
|
||
// Verify MAIL-FROM identity | ||
let result = resolver | ||
.verify_spf_sender("::1".parse().unwrap(), "gmail.com", "my-local-domain.org", "[email protected]") | ||
let result = authenticator | ||
.verify_spf(SpfParameters::verify_mail_from( | ||
"::1".parse().unwrap(), | ||
"gmail.com", | ||
"my-local-domain.org", | ||
"[email protected]", | ||
)) | ||
.await; | ||
assert_eq!(result.result(), SpfResult::Fail); | ||
``` | ||
|
||
### DMARC Policy Evaluation | ||
|
||
```rust | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Verify DKIM signatures | ||
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap(); | ||
let dkim_result = resolver.verify_dkim(&authenticated_message).await; | ||
let dkim_result = authenticator.verify_dkim(&authenticated_message).await; | ||
|
||
// Verify SPF MAIL-FROM identity | ||
let spf_result = resolver | ||
.verify_spf_sender("::1".parse().unwrap(), "example.org", "my-local-domain.org", "[email protected]") | ||
let spf_result = authenticator | ||
.verify_spf(SpfParameters::verify_mail_from( | ||
"::1".parse().unwrap(), | ||
"example.org", | ||
"my-host-domain.org", | ||
"[email protected]", | ||
)) | ||
.await; | ||
|
||
// Verify DMARC | ||
let dmarc_result = resolver | ||
let dmarc_result = authenticator | ||
.verify_dmarc( | ||
&authenticated_message, | ||
&dkim_result, | ||
"example.org", | ||
&spf_result, | ||
|domain| psl::domain_str(domain).unwrap_or(domain), | ||
DmarcParameters::new( | ||
&authenticated_message, | ||
&dkim_result, | ||
"example.org", | ||
&spf_result, | ||
) | ||
.with_domain_suffix_fn(|domain| psl::domain_str(domain).unwrap_or(domain)), | ||
) | ||
.await; | ||
assert_eq!(dmarc_result.dkim_result(), &DmarcResult::Pass); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,7 @@ | |
* except according to those terms. | ||
*/ | ||
|
||
use mail_auth::{AuthenticatedMessage, DkimResult, Resolver}; | ||
use mail_auth::{AuthenticatedMessage, DkimResult, MessageAuthenticator}; | ||
|
||
const TEST_MESSAGE: &str = r#"DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; | ||
d=football.example.com; [email protected]; | ||
|
@@ -39,14 +39,14 @@ Joe."#; | |
|
||
#[tokio::main] | ||
async fn main() { | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Parse message | ||
let authenticated_message = AuthenticatedMessage::parse(TEST_MESSAGE.as_bytes()).unwrap(); | ||
|
||
// Validate signature | ||
let result = resolver.verify_dkim(&authenticated_message).await; | ||
let result = authenticator.verify_dkim(&authenticated_message).await; | ||
|
||
// Make sure all signatures passed verification | ||
assert!(result.iter().all(|s| s.result() == &DkimResult::Pass)); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,10 @@ | |
* except according to those terms. | ||
*/ | ||
|
||
use mail_auth::{AuthenticatedMessage, DmarcResult, Resolver}; | ||
use mail_auth::{ | ||
dmarc::verify::DmarcParameters, spf::verify::SpfParameters, AuthenticatedMessage, DmarcResult, | ||
MessageAuthenticator, | ||
}; | ||
|
||
const TEST_MESSAGE: &str = r#"DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; | ||
d=football.example.com; [email protected]; | ||
|
@@ -39,31 +42,33 @@ Joe."#; | |
|
||
#[tokio::main] | ||
async fn main() { | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Verify DKIM signatures | ||
let authenticated_message = AuthenticatedMessage::parse(TEST_MESSAGE.as_bytes()).unwrap(); | ||
let dkim_result = resolver.verify_dkim(&authenticated_message).await; | ||
let dkim_result = authenticator.verify_dkim(&authenticated_message).await; | ||
|
||
// Verify SPF MAIL-FROM identity | ||
let spf_result = resolver | ||
.verify_spf_sender( | ||
let spf_result = authenticator | ||
.verify_spf(SpfParameters::verify_mail_from( | ||
"::1".parse().unwrap(), | ||
"example.org", | ||
"my-host-domain.org", | ||
"[email protected]", | ||
) | ||
)) | ||
.await; | ||
|
||
// Verify DMARC | ||
let dmarc_result = resolver | ||
let dmarc_result = authenticator | ||
.verify_dmarc( | ||
&authenticated_message, | ||
&dkim_result, | ||
"example.org", | ||
&spf_result, | ||
|domain| psl::domain_str(domain).unwrap_or(domain), | ||
DmarcParameters::new( | ||
&authenticated_message, | ||
&dkim_result, | ||
"example.org", | ||
&spf_result, | ||
) | ||
.with_domain_suffix_fn(|domain| psl::domain_str(domain).unwrap_or(domain)), | ||
) | ||
.await; | ||
assert_eq!(dmarc_result.dkim_result(), &DmarcResult::Pass); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,31 +8,31 @@ | |
* except according to those terms. | ||
*/ | ||
|
||
use mail_auth::{Resolver, SpfResult}; | ||
use mail_auth::{spf::verify::SpfParameters, MessageAuthenticator, SpfResult}; | ||
|
||
#[tokio::main] | ||
async fn main() { | ||
// Create a resolver using Cloudflare DNS | ||
let resolver = Resolver::new_cloudflare_tls().unwrap(); | ||
// Create an authenticator using Cloudflare DNS | ||
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap(); | ||
|
||
// Verify HELO identity | ||
let result = resolver | ||
.verify_spf_helo( | ||
let result = authenticator | ||
.verify_spf(SpfParameters::verify_ehlo( | ||
"127.0.0.1".parse().unwrap(), | ||
"gmail.com", | ||
"my-host-domain.org", | ||
) | ||
"my-local-domain.org", | ||
)) | ||
.await; | ||
assert_eq!(result.result(), SpfResult::Fail); | ||
|
||
// Verify MAIL-FROM identity | ||
let result = resolver | ||
.verify_spf_sender( | ||
let result = authenticator | ||
.verify_spf(SpfParameters::verify_mail_from( | ||
"::1".parse().unwrap(), | ||
"gmail.com", | ||
"my-host-domain.org", | ||
"my-local-domain.org", | ||
"[email protected]", | ||
) | ||
)) | ||
.await; | ||
assert_eq!(result.result(), SpfResult::Fail); | ||
} |
Oops, something went wrong.