BATV

From Halon, SMTP software for hosting providers
Jump to: navigation, search
The implementation code is available in our code repository.

The Halon SMTP software can implement BATV (Bounce Tag Address Validation) via HSL. It provides a cryptographic mechanisms to verify the integrity of a bounced message in order to prevent backscatter. BATV works by rewriting the sender (MAIL FROM) address to a unique (yet valid for X days) address while allowing bounced in a time window. If a bounce (empty envelope sender) is received to an address with a BATV tag, it is possible to validate that the tag was created by you less than X days ago. If a bounce is received to an address without a/invalid/expired BATV tag it should be rejected.

Verify BATV

Add the following to your RCPT flow.

include "file:1"// BATV
if (($sender == "" or $sender =~ "/^mailer-daemon@/i") and batv_verify($recipient, [=> "secret key"]) != "pass")
    
Reject("Invalid Bounce"); 

You should strip the BATV tag before calling your lookup function using the batv_strip() function. If simple block are used, copy the lookup code and replace $recipient with batv_strip($recipient) in appropriate places.

Add the following to your DATA flow.

include "file:1"// BATV
SetRecipient(batv_strip($recipient)); 

Add BATV

Add the following to your outgoing DATA flow.

include "file:1"// BATV
if ($sender != "" and $sender[0:5] != "prvs=")
    
SetSender(batv_sign($sender"secret key")); 

Key rotation

BATV keys should be rotated when needed or every 1000th day for good security. When "needed" might be considered as when you start to receive bounces that actually goes through the verification process. It could mean that someone know the key, and sends forged messages with that key in use, but that is very unlikely to happen.

→ First key

DATA flow → Signing batv_sign($sender, "myfirstkey");
RCPT TO flow → Verifying batv_verify($recipient, [0 => "myfirstkey"]);

→ Second key

DATA flow → Signing batv_sign($sender, "mysecondkey", ["keyid" => 1]);
RCPT TO flow → Verifying batv_verify($recipient, [0 => "myfirstkey", 1 => "mysecondkey"]);

→ Second key (but seven days later, the old first key can be removed)

RCPT TO flow → Verifying batv_verify($recipient, [1 => "mysecondkey"]);

Implementation

batv_sign($sender, $key, $options)

→ String

Signs the $sender address parameter with the specified $key. As options the following parameters can be specified.

Name Default Parameter
keyid 0 Key id (0-9)
days 7 Days the tag should be valid
if ($sender != "")
    
SetSender(batv_sign($sender"my secret key", ["keyid" => 1]); 

batv_verify($sender, $keys, $options)

→ String

Verifies the $sender address parameter with any of the available $keys. As options the following parameters can be specified.

Name Default Parameter
days 7 Days the tag is valid

The following return values may be returned

Value Type Reason
"pass" Good The BATV tag is valid! Message should be batv_stripped and delivered.
"missing" Neutral No BATV tag
"invalid" Bad BATV tag is invalid
"checksum" Bad BATV tag is bad (invalid key)
"expired" Bad BATV tag has expired
// Verify BATV signature in Recipient Flow
if ($sender == "" and batv_verify($recipient, [=> "my secret key"]) != "pass")
    
Reject("Invalid Bounce"); 

batv_strip($sender)

→ String

Removes the BATV tag from the e-mail address. If not tagged, $sender will be returned.

echo batv_strip("prvs=1212af4dsa=test@example.com"); // echo test@example.com
echo batv_strip("test@example.com"); // echo test@example.com

SetRecipient(batv_strip($recipient)); // Strip BATV signature in Content Flow before delivery