17 个不稳定版本 (3 个重大更改)

0.5.0 2024年8月11日
0.4.3 2024年6月19日
0.4.2 2024年5月29日
0.3.10 2024年3月28日
0.1.0 2022年12月1日

#8电子邮件

Download history 921/week @ 2024-05-03 1088/week @ 2024-05-10 1530/week @ 2024-05-17 1356/week @ 2024-05-24 1451/week @ 2024-05-31 1004/week @ 2024-06-07 1478/week @ 2024-06-14 1476/week @ 2024-06-21 1529/week @ 2024-06-28 1058/week @ 2024-07-05 905/week @ 2024-07-12 750/week @ 2024-07-19 1698/week @ 2024-07-26 1153/week @ 2024-08-02 1398/week @ 2024-08-09 1008/week @ 2024-08-16

5,433 每月下载量
2 crates 中使用

Apache-2.0 OR MIT

540KB
14K SLoC

mail-auth

crates.io build docs.rs crates.io

mail-auth 是一个用 Rust 编写的电子邮件身份验证和报告库,支持 DKIMARCSPFDMARC 协议。该库旨在快速、安全、正确,同时支持所有主要的 消息身份验证和报告 RFC

特性

  • DomainKeys Identified Mail (DKIM):
    • ED25519-SHA256(爱德华曲线数字签名算法)、RSA-SHA256 和 RSA-SHA1 签名和验证。
    • DKIM 授权第三方签名。
    • 使用滥用报告格式进行 DKIM 失败报告。
    • 为 RSA 和 Ed25519(通过 generate 功能启用)生成密钥对。
  • Authenticated Received Chain (ARC):
    • ED25519-SHA256(爱德华曲线数字签名算法)、RSA-SHA256 和 RSA-SHA1 链验证。
    • ARC 封印。
  • Sender Policy Framework (SPF):
    • 策略评估。
    • 使用滥用报告格式进行 SPF 失败报告。
  • 基于域的消息身份验证、报告和一致性 (DMARC):
    • 策略评估。
    • DMARC 聚合报告解析和生成。
  • 滥用报告格式 (ARF):
    • 滥用和身份验证失败报告。
    • 反馈报告解析和生成。
  • SMTP TLS 报告:
    • 报告解析和生成。

使用示例

DKIM 签名验证

    // Create a resolver using Cloudflare DNS
    let resolver = Resolver::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;

    // Make sure all signatures passed verification
    assert!(result.iter().all(|s| s.result() == &DkimResult::Pass));

DKIM 签名

    // Sign an e-mail message using RSA-SHA256
    let pk_rsa =  RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
    let signature_rsa = DkimSigner::from_key(pk_rsa)
        .domain("example.com")
        .selector("default")
        .headers(["From", "To", "Subject"])
        .sign(RFC5322_MESSAGE.as_bytes())
        .unwrap();

    // Sign an e-mail message using ED25519-SHA256
    let pk_ed = Ed25519Key::from_bytes(
        &base64_decode(ED25519_PUBLIC_KEY.as_bytes()).unwrap(),
        &base64_decode(ED25519_PRIVATE_KEY.as_bytes()).unwrap(),
    )
    .unwrap();
    let signature_ed = DkimSigner::from_key(pk_ed)
        .domain("example.com")
        .selector("default-ed")
        .headers(["From", "To", "Subject"])
        .sign(RFC5322_MESSAGE.as_bytes())
        .unwrap();    

    // Print the message including both signatures to stdout
    println!(
        "{}{}{}",
        signature_rsa.to_header(),
        signature_ed.to_header(),
        RFC5322_MESSAGE
    );

ARC 链验证

    // Create a resolver using Cloudflare DNS
    let resolver = Resolver::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;

    // Make sure ARC passed verification
    assert_eq!(result.result(), &DkimResult::Pass);

ARC 链封印

    // Create a resolver using Cloudflare DNS
    let resolver = Resolver::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;

    // Build Authenticated-Results header
    let auth_results = AuthenticationResults::new("mx.mydomain.org")
        .with_dkim_result(&dkim_result, "[email protected]")
        .with_arc_result(&arc_result, "127.0.0.1".parse().unwrap());

    // Seal message
    if arc_result.can_be_sealed() {
        // Seal the e-mail message using RSA-SHA256
        let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
        let arc_set = ArcSealer::from_key(pk_rsa)
            .domain("example.org")
            .selector("default")
            .headers(["From", "To", "Subject", "DKIM-Signature"])
            .seal(&authenticated_message, &auth_results, &arc_result)
            .unwrap();

        // Print the sealed message to stdout
        println!("{}{}", arc_set.to_header(), RFC5322_MESSAGE)
    } else {
        eprintln!("The message could not be sealed, probably an ARC chain with cv=fail was found.")
    }

SPF 策略评估

    // Create a resolver using Cloudflare DNS
    let resolver = Resolver::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")
        .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]")
        .await;
    assert_eq!(result.result(), SpfResult::Fail);

DMARC 策略评估

    // Create a resolver using Cloudflare DNS
    let resolver = Resolver::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;

    // Verify SPF MAIL-FROM identity
    let spf_result = resolver
        .verify_spf_sender("::1".parse().unwrap(), "example.org", "my-local-domain.org", "[email protected]")
        .await;

    // Verify DMARC
    let dmarc_result = resolver
        .verify_dmarc(
            &authenticated_message,
            &dkim_result,
            "example.org",
            &spf_result,
            |domain| psl::domain_str(domain).unwrap_or(domain),
        )
        .await;
    assert_eq!(dmarc_result.dkim_result(), &DmarcResult::Pass);
    assert_eq!(dmarc_result.spf_result(), &DmarcResult::Pass);

更多示例请参阅 examples 目录。

测试与模糊测试

运行测试套件

 $ cargo test

使用 cargo-fuzz 对库进行模糊测试

 $ cargo +nightly fuzz run mail_auth

符合 RFC

DKIM

SPF

DMARC

ARF

SMTP TLS 报告

许可证

根据以下任一许可证授权:

根据您的选择。

版权 (C) 2020-2023,Stalwart Labs Ltd.

依赖项

~23–36MB
~665K SLoC