Hi Steve (and all),

I was thinking that we could move the interoperability test suite currently at 
https://github.com/stalwartlabs/mail-auth/blob/main/src/dkim2/interop_test.rs 
to https://github.com/dkim2wg, so other implementers can contribute their code 
directly rather than going through the mail-auth repo.
The suite uses testcontainers to build a Docker image covering all four 
implementations I'm aware of (Rust, Go, Python, and PhoenixDKIM in C).

I'm also happy to leave the interop code in mail-auth and continue adding new 
implementations there as they come up.


Best,
Mauro


> On 7 Jul 2026, at 12:16, Steve Atkins <[email protected]> wrote:
> 
> 
> 
>> On 4 Jul 2026, at 08:25, Mauro De Gennaro <[email protected]> 
>> wrote:
>> 
>> Hi all,
>> 
>> I wanted to share some news from implementing DKIM2, along with a few 
>> findings that came out of interop testing. Incidentally, this message is 
>> itself DKIM2 signed, so if your tooling supports it, feel free to use it as 
>> a small real-world sample.
>> 
>> I have added DKIM2 support (draft-ietf-dkim-dkim2-spec-03) to mail-auth, the 
>> Rust library for email authentication, which lives at 
>> https://github.com/stalwartlabs/mail-auth. One thing worth mentioning is 
>> that mail-auth also compiles to WebAssembly, so it can be used from 
>> JavaScript applications and other WASM environments. To make it easy to try, 
>> I put together a playground at https://mail-auth.stalw.art/ that signs and 
>> validates DKIM2, as well as DMARC, entirely from the browser, resolving the 
>> records using DNS-over-HTTP.
>> 
>> DKIM2 is now also supported in Stalwart mail server 
>> (https://github.com/stalwartlabs/stalwart/), which uses mail-auth 
>> internally. Beyond signing and verification, I have implemented inbound DSN 
>> validation for DKIM2 as described in the draft, so that delivery status 
>> notifications coming back along the chain can themselves be authenticated.
>> 
>> On interoperability, I tested mail-auth against Bron's Python implementation 
>> (https://github.com/dkim2wg/interop.git) and Steve's Go implementation 
>> (https://forge.turscar.ie/turscar/dkim2.git). The integration tests are at 
>> https://github.com/stalwartlabs/mail-auth/blob/main/src/dkim2/interop_test.rs
>>  and they exercise signing, verification and recipe generation across all 
>> three implementations, in both directions, including multi-hop chains. The 
>> good news is that with header folding disabled, every combination passes: 
>> signing, verifying and recipe based reconstruction all agree across the 
>> three implementations.
> 
> Nice work! 
> 
>> 
>> I did hit one issue, when mail-auth folds the DKIM2-Signature and 
>> Message-Instance header fields, which is expected behaviour for long fields 
>> such as the base64 signature, both the Python and the Go implementations 
>> fail to parse them. The draft describes in section 2.12 that folding 
>> whitespace is allowed inside base64 strings and must be ignored when the 
>> value is used, so I believe mail-auth's output is conformant here, and it 
>> round-trips cleanly through my own parser. In Steve's Go library the mf= and 
>> rt= values are base64 decoded in strict mode without first removing the 
>> folding whitespace, which trips on the embedded space or tab. In Bron's 
>> Python library the s= value is split on the colon without unfolding first, 
>> so the algorithm token ends up carrying the leading CRLF and tab, and the 
>> algorithm comparison then fails. Neither looks hard to fix, and as noted, 
>> disabling folding on my side makes all tests pass.
> 
> We should add some test vectors to check folding and otehr FWS in all the 
> places things can be folded, I guess.
> 
>> Finally, a couple of small notes on the spec itself. Overall I found it 
>> clear, but a few of the sections that describe algorithms in prose would 
>> benefit from some accompanying pseudocode, in particular the parts covering 
>> recipe application and the chain walk during verification. It would remove a 
>> little ambiguity for implementers. The other point concerns header field 
>> names in recipes. It is not entirely clear from the text whether the JSON 
>> keys must be lowercased or may retain their original case. Steve's 
>> implementation expects lowercase and rejects mixed case, whereas I initially 
>> generated recipes preserving the original header case, which the current 
>> wording about matching without regard to case seemed to permit. A sentence 
>> stating the expected behaviour would avoid this divergence.
> 
> The current spec says they’re case-sensitive. There was discussion about 
> requiring lower case around the time I implemented that bit, and I apparently 
> got ahead of the spec.
> 
> Cheers,
>  Steve
> _______________________________________________
> Ietf-dkim mailing list -- [email protected]
> To unsubscribe send an email to [email protected]

_______________________________________________
Ietf-dkim mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to