Rust邮件认证库mail-auth的使用,支持SMTP、DKIM和SPF等邮件安全协议验证

Rust邮件认证库mail-auth的使用,支持SMTP、DKIM和SPF等邮件安全协议验证

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

功能特性

  • DomainKeys Identified Mail (DKIM):

    • ED25519-SHA256 (Edwards-Curve Digital Signature Algorithm), RSA-SHA256和RSA-SHA1签名和验证
    • DKIM授权第三方签名
    • 使用Abuse Reporting Format进行DKIM失败报告
    • 为RSA和Ed25519生成密钥对(通过generate功能启用)
  • Authenticated Received Chain (ARC):

    • ED25519-SHA256 (Edwards-Curve Digital Signature Algorithm), RSA-SHA256和RSA-SHA1链验证
    • ARC密封
  • Sender Policy Framework (SPF):

    • 策略评估
    • 使用Abuse Reporting Format进行SPF失败报告
  • Domain-based Message Authentication, Reporting and Conformance (DMARC):

    • 策略评估
    • DMARC聚合报告解析和生成
  • Abuse Reporting Format (ARF):

    • 滥用和认证失败报告
    • 反馈报告解析和生成
  • SMTP TLS Reporting:

    • 报告解析和生成

使用示例

DKIM签名验证

// 创建一个使用Cloudflare DNS的认证器
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap();

// 解析消息
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MESSAGE.as_bytes()).unwrap();

// 验证签名
let result = authenticator.verify_dkim(&authenticated_message).await;

// 确保所有签名都通过了验证
assert!(result.iter().all(|s| s.result() == &DkimResult::Pass));

DKIM签名

// 使用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();

// 使用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();    

// 打印包含两个签名的消息到stdout
println!(
    "{}{}{}",
    signature_rsa.to_header(),
    signature_ed.to_header(),
    RFC5322_MESSAGE
);

ARC链验证

// 创建一个使用Cloudflare DNS的认证器
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap();

// 解析消息
let authenticated_message = AuthenticatedMessage::parse(RFC5322_MERENCE.as_bytes()).unwrap();

// 验证ARC链
let result = authenticator.verify_arc(&authenticated_message).await;

// 确保ARC通过了验证
assert_eq!(result.result(), &DkimResult::Pass);

SPF策略评估

// 创建一个使用Cloudflare DNS的认证器
let authenticator = MessageAuthenticator::new_cloudflare_tls().unwrap();

// 验证HELO身份
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);

// 验证MAIL-FROM身份
let result = authenticator
    .verify_spf(SpfParameters::verify_mail_from(
        "::1".parse().unwrap(),
        "gmail.com",
        "my-local-domain.org",
        "sender@gmail.com",
    ))
    .await;
assert_eq!(result.result(), SpfResult::Fail);

完整示例代码

以下是一个完整的示例,展示了如何使用mail-auth库进行DKIM签名和验证:

use mail_auth::{
    AuthenticatedMessage, DkimResult, DkimSigner, MessageAuthenticator,
    dkim::RsaKey,
};
use sha2::Sha256;
use std::error::Error;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
    // 示例邮件内容
    const RFC5322_MESSAGE: &str = "From: sender@example.com\r\n\
                                 To: recipient@example.com\r\n\
                                 Subject: Test message\r\n\
                                 \r\n\
                                 This is a test message.";

    // 创建签名器
    let private_key = "-----BEGIN RSA PRIVATE KEY-----\n..."; // 替换为实际的RSA私钥
    let pk_rsa = RsaKey::<Sha256>::from_pkcs1_pem(private_key)?;
    
    // 签名邮件
    let signature = DkimSigner::from_key(pk_rsa)
        .domain("example.com")
        .selector("default")
        .headers(["From", "To", "Subject"])
        .sign(RFC5322_MESSAGE.as_bytes())?;

    // 创建带签名的完整邮件
    let signed_message = format!("{}{}", signature.to_header(), RFC5322_MESSAGE);

    // 创建验证器
    let authenticator = MessageAuthenticator::new_cloudflare_tls()?;
    
    // 解析消息
    let authenticated_message = AuthenticatedMessage::parse(signed_message.as_bytes())?;
    
    // 验证签名
    let result = authenticator.verify_dkim(&authenticated_message).await;
    
    // 检查验证结果
    assert!(result.iter().all(|s| s.result() == &DkimResult::Pass));
    println!("DKIM验证成功!");
    
    Ok(())
}

测试和模糊测试

运行测试套件:

$ cargo test

使用cargo-fuzz进行模糊测试:

$ cargo +nightly fuzz run mail_auth

许可证

可以选择以下任一许可证:

  • Apache License, Version 2.0
  • MIT license

版权

版权所有 © 2020, Stalwart Labs LLC


1 回复

Rust邮件认证库mail-auth使用指南

mail-auth是一个Rust库,用于处理邮件认证相关的协议验证,包括SMTP、DKIM和SPF等邮件安全协议。它可以帮助开发者构建安全的邮件发送和接收系统。

主要功能

  • DKIM (DomainKeys Identified Mail) 签名和验证
  • SPF (Sender Policy Framework) 验证
  • SMTP协议相关认证
  • 邮件头验证

安装

Cargo.toml中添加依赖:

[dependencies]
mail-auth = "0.2"

完整示例代码

1. DKIM签名完整示例

use mail_auth::{Authenticator, DkimSigner, common::headers::HeaderWriter};
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取私钥文件
    let private_key = fs::read_to_string("private_key.pem")?;
    
    // 创建DKIM签名器
    let signer = DkimSigner::from_pem(&private_key)
        .expect("Failed to parse private key")
        .domain("example.com")
        .selector("default")
        .headers(&["From", "To", "Subject", "Date"]);

    // 构建邮件头
    let date = chrono::Local::now().to_rfc2822();
    let mut headers = Vec::new();
    headers.push(("From", "sender@example.com"));
    headers.push(("To", "recipient@example.com"));
    headers.push(("Subject", "Test email with DKIM"));
    headers.push(("Date", &date));

    // 邮件正文
    let body = "Hello,\n\nThis is a test email with DKIM signature.\n\nBest regards,\nSender";

    // 签名邮件
    let signature = signer.sign(&headers, body)?;
    
    // 输出带签名的完整邮件
    println!("From: sender@example.com");
    println!("To: recipient@example.com");
    println!("Subject: Test email with DKIM");
    println!("Date: {}", date);
    println!("DKIM-Signature: {}", signature);
    println!("\n{}", body);

    Ok(())
}

2. DKIM验证完整示例

use mail_auth::{Authenticator, DkimVerifier};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 示例邮件内容(实际应用中从文件或网络读取)
    let email = r#"From: sender@example.com
To: recipient@example.com
Subject: Test email
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=default;
 c=relaxed/relaxed; q=dns/txt; t=1234567890; h=from:to:subject;
 bh=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOP;
 b=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCD

Hello, this is a test email!"#;

    // 验证DKIM签名
    let verifier = DkimVerifier::from_email(email)?;
    let result = verifier.verify()?;
    
    if result.is_passed() {
        println!("✅ DKIM验证成功");
        println!("签名域名: {}", result.domain().unwrap_or("未知"));
    } else {
        println!("❌ DKIM验证失败: {:?}", result.error());
    }

    Ok(())
}

3. SPF验证完整示例

use mail_auth::spf::SpfVerifier;
use std::net::{IpAddr, Ipv4Addr};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 客户端IP地址
    let ip = IpAddr::V4(Ipv4Addr::new(192, 0, 2, 1));
    
    // 发件人地址
    let sender = "sender@example.com";
    
    // HELO/EHLO域名
    let helo_domain = "mail.example.com";
    
    // 执行SPF验证
    let result = SpfVerifier::new(ip, sender, helo_domain)
        .verify()
        .await?;
    
    match result.result() {
        mail_auth::spf::SpfResult::Pass => println!("✅ SPF验证通过"),
        mail_auth::spf::SpfResult::Fail => println!("❌ SPF验证失败"),
        mail_auth::spf::SpfResult::SoftFail => println!("⚠️ SPF软失败"),
        mail_auth::spf::SpfResult::Neutral => println!("➖ SPF中立"),
        mail_auth::spf::SpfResult::None => println!("❓ 无SPF记录"),
        mail_auth::spf::SpfResult::TempError => println!("⚠️ 临时错误"),
        mail_auth::spf::SpfResult::PermError => println!("❌ 永久错误"),
    }
    
    println!("验证结果详情: {:?}", result);

    Ok(())
}

4. 综合验证完整示例

use mail_auth::{verify::verify_email, Authenticator};
use std::net::{IpAddr, Ipv4Addr};
use tokio::fs;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 读取测试邮件文件
    let email = fs::read_to_string("test_email.eml").await?;
    
    // 客户端IP地址
    let client_ip = IpAddr::V4(Ipv4Addr::new(192, 0, 2, 100));
    
    // 综合验证邮件
    let result = verify_email(&email, client_ip).await?;
    
    println!("=== 邮件验证结果 ===");
    println!("DKIM: {:?}", result.dkim());
    println!("SPF: {:?}", result.spf());
    
    if result.is_passed() {
        println!("✅ 邮件通过所有验证");
    } else {
        println!("❌ 邮件验证失败");
    }
    
    Ok(())
}

项目结构

mail_auth_demo/
├── Cargo.toml
├── src/
│   ├── main.rs          # 主程序入口
│   ├── dkim.rs          # DKIM相关功能
│   ├── spf.rs           # SPF相关功能
│   └── verification.rs  # 综合验证功能
├── private_key.pem      # DKIM私钥
├── test_email.eml       # 测试用邮件
└── README.md            # 项目说明

注意事项

  1. DKIM签名需要有效的RSA私钥,格式为PEM
  2. SPF验证需要正确的DNS记录配置
  3. 生产环境建议使用异步API以提高性能
  4. 所有验证操作都应包含错误处理
  5. 邮件内容应符合RFC标准格式
回到顶部