April 8, 2025 permalink
(Rust) an SMTP server which creates a 'DKIM-Signature' header for incoming emails, then relays the email to another SMTP server. Includes handy dkim-gen-keys app
https://github.com/arduent/dkim-relay
This program runs as an SMTP server which creates a DKIM-Signature header for incoming emails, then relays the email to another SMTP server as configured. The user may use the included program dkim-gen-keys to create the RSA private key and BIND zone file entry for the corresponding public key. Keys are RSA (up to 2048 bits, though 1024-bit keys may be more practical on some systems due to DNS fragmentation issues).
When a client connects and sends SMTP commands to deliver an email, the server parses the header and body into separate structures. The email is not altered except for the insertion of the DKIM-Signature header.
The server uses relaxed/relaxed canonicalization. It compresses whitespace and converts header field names to lowercase. Blank or missing headers can be included to "lock in" their absence, which prevents a third party from later inserting unauthorized headers without breaking the signature.
A 32-byte SHA-256 hash is computed on the canonicalized body. The canonicalized header data (which now includes a temporary DKIM-Signature header with an empty b= tag and a proper bh= value) is hashed. The header hash is then combined with a fixed DER prefix (19 bytes for SHA-256) to form a 51-byte DigestInfo. This DigestInfo is signed using the RSA private key with PKCS#1 v1.5 padding (using the OpenSSL crate to mimic the legacy RSA_sign/RSA_verify functions). The resulting signature is base64‑encoded and inserted into the b= tag of the final DKIM-Signature header.
The generated DKIM-Signature header (with the now–populated b= field) is added at the top of the header block. In cases where multiple DKIM-Signature headers exist, the topmost one is used for verification.