Skip to main content

3 posts tagged with "dkim"

View All Tags

· 3 min read
Mauro D.

Email security is a critical aspect of digital communication, especially given the rising sophistication of cyber threats. DomainKeys Identified Mail (DKIM) and Authenticated Received Chain (ARC) are standards designed to ensure the authenticity and integrity of emails. However, as discovered by analysts at Zone.eu, vulnerabilities in the DKIM standard could undermine these protections, affecting billions of users worldwide.

Introduction to DKIM and ARC

DKIM provides an email authentication method that allows an organization to take responsibility for a message in transit. The standard uses cryptographic signatures to verify that an email has not been altered since it was originally sent. ARC, on the other hand, is an email authentication system designed to provide a way to preserve email authentication results across subsequent intermediaries that might modify the message, thus extending the benefits of DKIM.

The Exploit Revealed

The vulnerability uncovered by Zone.eu revolves around the DKIM's "l=" parameter, which specifies the exact number of octets in the body of the email that are signed. This can be exploited by attackers who can append additional content to the message without affecting the validity of the DKIM signature. This oversight can lead emails with forged content to still appear as authenticated, deceiving both email systems and end-users, especially when visual trust indicators like BIMI are employed.

Stalwart’s Response to the Exploit

Recognizing the gravity of this exploit, Stalwart Mail Server has taken decisive steps to mitigate this risk and reinforce the security of email communications for its users. Initially, in Stalwart's implementation of DKIM and ARC, the option to set a signature length was disabled by default, which was a preventive measure against potential misuse. To further strengthen security in light of the new findings, Stalwart has now entirely removed the ability to specify signature lengths in both DKIM signatures and ARC seals. This change ensures that users cannot accidentally enable this feature, which could lead to vulnerabilities.

Furthermore, Stalwart has enhanced its validation processes. Both DKIM signatures and ARC seals are now verified in strict mode exclusively. Stalwart will not validate any signatures or seals that include a length parameter (the "l=" tag). Instead, these will receive a neutral result, meaning they neither pass nor fail the verification process but are flagged for potential risk. This approach aligns with best practices recommended in the wake of the exploit's discovery and is designed to prevent similar types of vulnerabilities from being exploited.

Conclusion

Stalwart Mail Server's response illustrates a proactive and security-conscious approach, ensuring that our users remain protected against emerging threats. By eliminating the option to specify signature lengths and enforcing strict validation standards, Stalwart continues to be at the forefront of safeguarding email communications against evolving cyber threats.

We extend our thanks to the researchers at Zone.eu for their diligence in uncovering this significant security concern, thereby contributing to the broader effort of enhancing email security across the globe.

· 3 min read
Mauro D.

Today the mail-auth library was released, which is an e-mail authentication and reporting library written in Rust that supports the DKIM, ARC, SPF and DMARC protocols. It is the Rust equivalent of OpenDKIM, OpenSPF, OpenARC and OpenDMARC combined in one library (as well as some extras such ARF support). mail-auth includes the following features:

  • DomainKeys Identified Mail (DKIM):
  • ED25519-SHA256 (Edwards-Curve Digital Signature Algorithm), RSA-SHA256 and RSA-SHA1 signing and verification.
  • DKIM Authorized Third-Party Signatures.
  • DKIM failure reporting using the Abuse Reporting Format.
  • Authenticated Received Chain (ARC):
  • ED25519-SHA256 (Edwards-Curve Digital Signature Algorithm), RSA-SHA256 and RSA-SHA1 chain verification.
  • ARC sealing.
  • Sender Policy Framework (SPF):
  • Policy evaluation.
  • SPF failure reporting using the Abuse Reporting Format.
  • Domain-based Message Authentication, Reporting, and Conformance (DMARC):
  • Policy evaluation.
  • DMARC aggregate report parsing and generation.
  • Abuse Reporting Format (ARF):
  • Abuse and Authentication failure reporting.
  • Feedback report parsing and generation.

DKIM Signature Verification

        // 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 Signing

        // Sign an e-mail message using RSA-SHA256
let pk_rsa = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
let signature_rsa = Signature::new()
.headers(["From", "To", "Subject"])
.domain("example.com")
.selector("default")
.sign(RFC5322_MESSAGE.as_bytes(), &pk_rsa)
.unwrap();

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

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

ARC Chain Verification

        // 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 Chain Sealing

        // 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 = PrivateKey::from_rsa_pkcs1_pem(RSA_PRIVATE_KEY).unwrap();
let arc_set = ARC::new(&auth_results)
.domain("example.org")
.selector("default")
.headers(["From", "To", "Subject", "DKIM-Signature"])
.seal(&authenticated_message, &arc_result, &pk_rsa)
.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 Policy Evaluation

        // 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")
.await;
assert_eq!(result.result(), SPFResult::Fail);

// Verify MAIL-FROM identity
let result = resolver
.verify_spf_sender("::1".parse().unwrap(), "gmail.com", "[email protected]")
.await;
assert_eq!(result.result(), SPFResult::Fail);

DMARC Policy Evaluation

        // 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", "[email protected]")
.await;

// Verify DMARC
let dmarc_result = resolver
.verify_dmarc(
&authenticated_message,
&dkim_result,
"example.org",
&spf_result,
)
.await;
assert_eq!(dmarc_result.dkim_result(), &DMARCResult::Pass);
assert_eq!(dmarc_result.spf_result(), &DMARCResult::Pass);

More examples available on Github under the examples directory.

· 2 min read
Mauro D.

Building and sending e-mails securely does not have to be complicated. Today the mail-send crate was released including the following features:

  • Generates e-mail messages conforming to the Internet Message Format standard (RFC 5322) with full MIME support (RFC 2045–2049) and automatic selection of the most optimal encoding for each message body part.
  • DomainKeys Identified Mail (DKIM) Signatures (RFC 6376).
  • SMTP support with TLS and multiple authentication mechanisms (XOAUTH2, CRAM-MD5, DIGEST-MD5, LOGIN and PLAIN).
  • Full async (requires Tokio).

Composing and sending an e-mail message via SMTP is as simple as:

        // Build a simple multipart message
let message = MessageBuilder::new()
.from(("John Doe", "[email protected]"))
.to(vec![
("Jane Doe", "[email protected]"),
("James Smith", "[email protected]"),
])
.subject("Hi!")
.html_body("<h1>Hello, world!</h1>")
.text_body("Hello world!");

// Connect to an SMTP relay server over TLS and
// authenticate using the provided credentials.
Transport::new("smtp.gmail.com")
.credentials("john", "p4ssw0rd")
.connect_tls()
.await
.unwrap()
.send(message)
.await
.unwrap();

And to sign a message with DKIM just do:

    // Build a simple text message with a single attachment
let message = MessageBuilder::new()
.from(("John Doe", "[email protected]"))
.to("[email protected]")
.subject("Howdy!")
.text_body("These pretzels are making me thirsty.")
.binary_attachment("image/png", "pretzels.png", [1, 2, 3, 4].as_ref());

// Set up DKIM signer
let dkim = DKIM::from_pkcs1_pem_file("./cert.pem")
.unwrap()
.domain("example.com")
.selector("2022")
.headers(["From", "To", "Subject"]) // Headers to sign
.expiration(60 * 60 * 7); // Number of seconds before this signature expires (optional)

// Connect to an SMTP relay server over TLS.
// Signs each message with the configured DKIM signer.
Transport::new("smtp.example.com")
.dkim(dkim)
.connect_tls()
.await
.unwrap()
.send(message)
.await
.unwrap();

More examples can be found on Github. Enjoy DKIM signing!