1 | /*
|
2 | * Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
3 | *
|
4 | * Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
5 | * https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
6 | * <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
|
7 | * option. This file may not be copied, modified, or distributed
|
8 | * except according to those terms.
|
9 | */
|
10 |
|
11 | use mail_auth::{
|
12 | arc::ArcSealer,
|
13 | common::{
|
14 | crypto::{RsaKey, Sha256},
|
15 | headers::HeaderWriter,
|
16 | },
|
17 | AuthenticatedMessage, AuthenticationResults, Resolver,
|
18 | };
|
19 |
|
20 | const TEST_MESSAGE: &str = include_str!("../resources/arc/001.txt");
|
21 |
|
22 | const RSA_PRIVATE_KEY: &str = r#"-----BEGIN RSA PRIVATE KEY-----
|
23 | MIICXwIBAAKBgQDwIRP/UC3SBsEmGqZ9ZJW3/DkMoGeLnQg1fWn7/zYtIxN2SnFC
|
24 | jxOCKG9v3b4jYfcTNh5ijSsq631uBItLa7od+v/RtdC2UzJ1lWT947qR+Rcac2gb
|
25 | to/NMqJ0fzfVjH4OuKhitdY9tf6mcwGjaNBcWToIMmPSPDdQPNUYckcQ2QIDAQAB
|
26 | AoGBALmn+XwWk7akvkUlqb+dOxyLB9i5VBVfje89Teolwc9YJT36BGN/l4e0l6QX
|
27 | /1//6DWUTB3KI6wFcm7TWJcxbS0tcKZX7FsJvUz1SbQnkS54DJck1EZO/BLa5ckJ
|
28 | gAYIaqlA9C0ZwM6i58lLlPadX/rtHb7pWzeNcZHjKrjM461ZAkEA+itss2nRlmyO
|
29 | n1/5yDyCluST4dQfO8kAB3toSEVc7DeFeDhnC1mZdjASZNvdHS4gbLIA1hUGEF9m
|
30 | 3hKsGUMMPwJBAPW5v/U+AWTADFCS22t72NUurgzeAbzb1HWMqO4y4+9Hpjk5wvL/
|
31 | eVYizyuce3/fGke7aRYw/ADKygMJdW8H/OcCQQDz5OQb4j2QDpPZc0Nc4QlbvMsj
|
32 | 7p7otWRO5xRa6SzXqqV3+F0VpqvDmshEBkoCydaYwc2o6WQ5EBmExeV8124XAkEA
|
33 | qZzGsIxVP+sEVRWZmW6KNFSdVUpk3qzK0Tz/WjQMe5z0UunY9Ax9/4PVhp/j61bf
|
34 | eAYXunajbBSOLlx4D+TunwJBANkPI5S9iylsbLs6NkaMHV6k5ioHBBmgCak95JGX
|
35 | GMot/L2x0IYyMLAz6oLWh2hm7zwtb0CgOrPo1ke44hFYnfc=
|
36 | -----END RSA PRIVATE KEY-----"#;
|
37 |
|
38 | #[tokio::main]
|
39 | async fn main() {
|
40 | // Create a resolver using Cloudflare DNS
|
41 | let resolver = Resolver::new_cloudflare_tls().unwrap();
|
42 |
|
43 | // Parse message to be sealed
|
44 | let authenticated_message = AuthenticatedMessage::parse(TEST_MESSAGE.as_bytes()).unwrap();
|
45 |
|
46 | // Verify ARC and DKIM signatures
|
47 | let arc_result = resolver.verify_arc(&authenticated_message).await;
|
48 | let dkim_result = resolver.verify_dkim(&authenticated_message).await;
|
49 |
|
50 | // Build Authenticated-Results header
|
51 | let auth_results = AuthenticationResults::new("mx.mydomain.org")
|
52 | .with_dkim_results(&dkim_result, "sender@example.org")
|
53 | .with_arc_result(&arc_result, "127.0.0.1".parse().unwrap());
|
54 |
|
55 | // Seal message
|
56 | if arc_result.can_be_sealed() {
|
57 | // Seal the e-mail message using RSA-SHA256
|
58 | let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
|
59 | let arc_set = ArcSealer::from_key(pk_rsa)
|
60 | .domain("example.org")
|
61 | .selector("default")
|
62 | .headers(["From", "To", "Subject", "DKIM-Signature"])
|
63 | .seal(&authenticated_message, &auth_results, &arc_result)
|
64 | .unwrap();
|
65 |
|
66 | // Print the sealed message to stdout
|
67 | println!("{}{}", arc_set.to_header(), TEST_MESSAGE)
|
68 | } else {
|
69 | eprintln!("The message could not be sealed, probably an ARC chain with cv=fail was found.")
|
70 | }
|
71 | }
|