I agree! I've had a play at converting my generator and parser for
Message-Instance headers (see the interop repo here dkim2wg/interop: DKIM2
interoperability testing <https://github.com/dkim2wg/interop/tree/master/brong>
- I worked from the code I wrote at the last hackathon in Montreal)
Another nice thing about JSON is that it removes the "wart" of 'z' and the 'b'
and 'c' prefixes. You can just do this:
*[number-number]* - a range of items
*"string"* - a single line or header field value
*null *- an expression that this can't be recreated
So you could have the following fields in a Message-Instance:
{*
* "rb" : [ [1, 50], [57, 60] ],
"rh" : {
"SecretValue": null,
"From": "Bron Gondwana <[email protected]>",
"List-Id": []
}
}
Which says:
• strip out the signature that was added in lines 51-56
• there may have been `SecretValue` headers, which I'm not giving you
instructions to recreate
• Change the `From` address back to Bron's real address; and
• Remove any `List-Id` headers
Here's some actual examples written by my code. Note that I include a 'h' key
naming the list of headers which were included in the `h1` hash calculation.
This is just an aid to debugging, and is not used by the validator. The actual
header selection logic is this function in my library:
sub should_skip {
my $hname = lc(shift);
# Stuff we handle ourselves
return 1 if $hname eq 'message-instance';
return 1 if $hname eq 'dkim2-signature';
# Trace Headers
return 1 if $hname eq 'received';
return 1 if $hname eq 'return-path';
# X headers
return 1 if $hname =~ m/^x-/;
# stuff we don't sign
return 1 if $hname eq 'dkim-signature';
return 1 if $hname eq 'arc-authentication-results';
return 1 if $hname eq 'arc-message-signature';
return 1 if $hname eq 'arc-seal';
}
Message-Instance: v=4; j=eyJhMSI6InNoYTI1NiIsImIxIjoiNG9sVWtNVWkyYkNDZlZ
yQU9nNHJTTnBQTUJXbldvS2Q3MSs5NHpwaVVxbz0iLCJoIjpbImFyY2hpdmVkLWF
0IiwiYXV0aGVudGljYXRpb24tcmVzdWx0cyIsImNvbnRlbnQtdHlwZSIsImRhdGU
iLCJmZWVkYmFjay1pZCIsImZyb20iLCJsaXN0LWFyY2hpdmUiLCJsaXN0LWhlbHA
iLCJsaXN0LWlkIiwibGlzdC1vd25lciIsImxpc3QtcG9zdCIsImxpc3Qtc3Vic2N
yaWJlIiwibGlzdC11bnN1YnNjcmliZSIsIm1lc3NhZ2UtaWQiLCJtZXNzYWdlLWl
kLWhhc2giLCJtaW1lLXZlcnNpb24iLCJwcmVjZWRlbmNlIiwic3ViamVjdCIsInR
vIl0sImgxIjoickQ2SjlFcUh3QVZ2YmFmc2lRdzRDQ25lQ2RUZTROQ2JQejBVRFB
1L05vQT0iLCJyYiI6W1sxLDE1XSwiSGVyZSdzIHNvbWUgZXh0cmEgdGV4dC4iLCI
iLFsxNiw2M11dLCJyaCI6eyJleHRyYS1oZWFkZXIiOlsieWVzIl19fQ==
brong@elg:~/src/interop/brong$ head -n 100 example.eml
Message-Instance: v=4; j=eyJhMSI6InNoYTI1NiIsImIxIjoiNG9sVWtNVWkyYkNDZlZ
yQU9nNHJTTnBQTUJXbldvS2Q3MSs5NHpwaVVxbz0iLCJoIjpbImFyY2hpdmVkLWF
0IiwiYXV0aGVudGljYXRpb24tcmVzdWx0cyIsImNvbnRlbnQtdHlwZSIsImRhdGU
iLCJmZWVkYmFjay1pZCIsImZyb20iLCJsaXN0LWFyY2hpdmUiLCJsaXN0LWhlbHA
iLCJsaXN0LWlkIiwibGlzdC1vd25lciIsImxpc3QtcG9zdCIsImxpc3Qtc3Vic2N
yaWJlIiwibGlzdC11bnN1YnNjcmliZSIsIm1lc3NhZ2UtaWQiLCJtZXNzYWdlLWl
kLWhhc2giLCJtaW1lLXZlcnNpb24iLCJwcmVjZWRlbmNlIiwic3ViamVjdCIsInR
vIl0sImgxIjoickQ2SjlFcUh3QVZ2YmFmc2lRdzRDQ25lQ2RUZTROQ2JQejBVRFB
1L05vQT0iLCJyYiI6W1sxLDE1XSwiSGVyZSdzIHNvbWUgZXh0cmEgdGV4dC4iLCI
iLFsxNiw2M11dLCJyaCI6eyJleHRyYS1oZWFkZXIiOlsieWVzIl19fQ==
Message-Instance: v=3; j=eyJhMSI6InNoYTI1NiIsImIxIjoiQVUyZWhBbHZRMmcrWm5
KZjNrVEhzQ3ljREZFN3NDbjZBaHBiVEdnU1lGTT0iLCJoIjpbImFyY2hpdmVkLWF
0IiwiYXV0aGVudGljYXRpb24tcmVzdWx0cyIsImNvbnRlbnQtdHlwZSIsImRhdGU
iLCJleHRyYS1oZWFkZXIiLCJmZWVkYmFjay1pZCIsImZyb20iLCJsaXN0LWFyY2h
pdmUiLCJsaXN0LWhlbHAiLCJsaXN0LWlkIiwibGlzdC1vd25lciIsImxpc3QtcG9
zdCIsImxpc3Qtc3Vic2NyaWJlIiwibGlzdC11bnN1YnNjcmliZSIsIm1lc3NhZ2U
taWQiLCJtZXNzYWdlLWlkLWhhc2giLCJtaW1lLXZlcnNpb24iLCJwcmVjZWRlbmN
lIiwic3ViamVjdCIsInRvIl0sImgxIjoiQlFXWVlFRVpUWmJWL1VjTjU3VmFCMWp
5SHB2VUJNbHhFazFZMHhrNWRRcz0iLCJyYiI6W1sxLDE1XSxbMTgsNjVdXSwicmg
iOnsiZXh0cmEtaGVhZGVyIjpbXX19
Message-Instance: v=2; j=eyJhMSI6InNoYTI1NiIsImIxIjoiNG9sVWtNVWkyYkNDZlZ
yQU9nNHJTTnBQTUJXbldvS2Q3MSs5NHpwaVVxbz0iLCJoIjpbImFyY2hpdmVkLWF
0IiwiYXV0aGVudGljYXRpb24tcmVzdWx0cyIsImNvbnRlbnQtdHlwZSIsImRhdGU
iLCJmZWVkYmFjay1pZCIsImZyb20iLCJsaXN0LWFyY2hpdmUiLCJsaXN0LWhlbHA
iLCJsaXN0LWlkIiwibGlzdC1vd25lciIsImxpc3QtcG9zdCIsImxpc3Qtc3Vic2N
yaWJlIiwibGlzdC11bnN1YnNjcmliZSIsIm1lc3NhZ2UtaWQiLCJtZXNzYWdlLWl
kLWhhc2giLCJtaW1lLXZlcnNpb24iLCJwcmVjZWRlbmNlIiwic3ViamVjdCIsInR
vIl0sImgxIjoickQ2SjlFcUh3QVZ2YmFmc2lRdzRDQ25lQ2RUZTROQ2JQejBVRFB
1L05vQT0iLCJyYiI6WyItLTEyYjUzZGM4MjlkMjQ1MTFiZmEwNGY3ZDVlMzY3NWY
4IixbNSw1XSxbNyw5XSwiVGhpcyBlbWFpbCBzdGFydHMgYSB3b3JraW5nIGdyb3V
wIGxhc3QgY2FsbCBmb3IgaHR0cHM6Ly9kYXRhdHJhY2tlci5pZXRmLm9yZy9kb2M
vZHJhZnQtaWV0Zi1qbWFwLXdlYnB1c2gtdmFwaWQvIGFzIGRpc2N1c3NlZCBpbiB
0aGUgSUVURjExOSBzZXNzaW9uLiIsWzExLDExXSwiUGxlYXNlIHBvc3QgYW55IGN
vbW1lbnRzIG9yIHJlc3BvbnNlcyBieSAqVGh1cnNkYXksIEFwcmlsIDR0aCwgMjA
yNCouIixbMTMsMTNdLFsxNiwyNV0sIi0tMTJiNTNkYzgyOWQyNDUxMWJmYTA0Zjd
kNWUzNjc1ZjgiLFsyNywzMV0sImFtaWx5OkFyaWFsO1wiPkhpIEFsbCw8YnI+PC9
kaXY+PGRpdiBzdHlsZT0zRFwiZm9udC1mYW1pbHk6QXJpYWw7XCI+PGRpdj48Yj0
iLCJyPjwvZGl2PjxkaXY+VGhpcyBlbWFpbCBzdGFydHMgYSB3b3JraW5nIGdyb3V
wIGxhc3QgY2FsbCBmb3IgPGEgaHJlZj0zRFwiPSIsImh0dHBzOi8vZGF0YXRyYWN
rZXIuaWV0Zi5vcmcvZG9jL2RyYWZ0LWlldGYtam1hcC13ZWJwdXNoLXZhcGlkL1w
iPmh0dHBzOi89IiwiL2RhdGF0cmFja2VyLmlldGYub3JnL2RvYy9kcmFmdC1pZXR
mLWptYXAtd2VicHVzaC12YXBpZC88L2E+IGFzIGRpc2N1c3NlPSIsImQgaW4gdGh
lIElFVEYxMTkgc2Vzc2lvbi48YnI+PC9kaXY+PGRpdiBzdHlsZT0zRFwiZm9udC1
mYW1pbHk6QXJpYWw7XCI+PGJyPSIsIj48L2Rpdj48ZGl2IHN0eWxlPTNEXCJmb25
0LWZhbWlseTpBcmlhbDtcIj5QbGVhc2UgcG9zdCBhbnkgY29tbWVudHMgb3IgcmV
zPSIsInBvbnNlcyBieSA8Yj5UaHVyc2RheSwgQXByaWwgNHRoLCAyMDI0PC9iPi4
8YnI+PC9kaXY+PGRpdiBzdHlsZT0zRFwiZm9udC09IiwiZmFtaWx5OkFyaWFsO1w
iPjxicj48L2Rpdj48ZGl2IHN0eWxlPTNEXCJmb250LWZhbWlseTpBcmlhbDtcIj5
UaGFua3MsPGJyPjwvPSIsImRpdj48ZGl2IHN0eWxlPTNEXCJmb250LWZhbWlseTp
BcmlhbDtcIj48YnI+PC9kaXY+PGRpdiBzdHlsZT0zRFwiZm9udC1mYW1pbD0iLCJ
5OkFyaWFsO1wiPkJyb24uPGJyPjwvZGl2PjxkaXY+PGJyPjwvZGl2PjxkaXY+PGJ
yPjwvZGl2PjwvZGl2PjxkaXYgaWQ9M0RcIj0iLCJzaWc1NjYyOTQxN1wiPjxkaXY
gY2xhc3M9M0RcInNpZ25hdHVyZVwiPi0tPGJyPjwvZGl2PjxkaXYgY2xhc3M9M0R
cInNpZ25hdHVyPSIsImVcIj4mbmJzcDsgQnJvbiBHb25kd2FuYSwgQ0VPLCBGYXN
0bWFpbCBQdHkgTHRkPGJyPjwvZGl2PjxkaXYgY2xhc3M9M0RcInNpPSIsImduYXR
1cmVcIj4mbmJzcDsgYnJvbmdAZmFzdG1haWx0ZWFtLmNvbTxicj48L2Rpdj48ZGl
2IGNsYXNzPTNEXCJzaWduYXR1cmVcIj0iLCI+PGJyPjwvZGl2PjwvZGl2PjxkaXY
gc3R5bGU9M0RcImZvbnQtZmFtaWx5OkFyaWFsO1wiPjxicj48L2Rpdj48L2JvZHk
+PC9odD0iLCJtbD4iLCItLTEyYjUzZGM4MjlkMjQ1MTFiZmEwNGY3ZDVlMzY3NWY
4LS0iXSwicmgiOnsiYXJjaGl2ZWQtYXQiOltdLCJhdXRoZW50aWNhdGlvbi1yZXN
1bHRzIjpbXSwiY29udGVudC10eXBlIjpbIm11bHRpcGFydC9hbHRlcm5hdGl2ZTs
gYm91bmRhcnk9MTJiNTNkYzgyOWQyNDUxMWJmYTA0ZjdkNWUzNjc1ZjgiXSwiZGF
0ZSI6WyJUaHUsIDIxIE1hciAyMDI0IDEyOjA5OjM3ICsxMDAwIl0sImZlZWRiYWN
rLWlkIjpbXSwiZnJvbSI6WyJcIkJyb24gR29uZHdhbmFcIiA8YnJvbmdAZmFzdG1
haWx0ZWFtLmNvbT4iXSwibGlzdC1hcmNoaXZlIjpbXSwibGlzdC1oZWxwIjpbXSw
ibGlzdC1pZCI6W10sImxpc3Qtb3duZXIiOltdLCJsaXN0LXBvc3QiOltdLCJsaXN
0LXN1YnNjcmliZSI6W10sImxpc3QtdW5zdWJzY3JpYmUiOltdLCJtZXNzYWdlLWl
kIjpbIjxmYjFiMTBhZS1lYTM2LTRlZTQtYjg0Zi1iNjJmMDM2Y2ZhZjVAYXBwLmZ
hc3RtYWlsLmNvbT4iXSwibWVzc2FnZS1pZC1oYXNoIjpbXSwicHJlY2VkZW5jZSI
6W10sInN1YmplY3QiOlsiV29ya2luZyBncm91cCBsYXN0IGNhbGwgZHJhZnQtaWV
0Zi1qbWFwLXdlYnB1c2gtdmFwaWQiXX19
Message-Instance: v=1; j=eyJhMSI6InNoYTI1NiIsImIxIjoiWEkyMjhWLzcyMFhOZWx
tNzZERktRZjkzNGlPRVFRQ3Q2d1ozdUtDSXI5UT0iLCJoIjpbImNvbnRlbnQtdHl
wZSIsImRhdGUiLCJmcm9tIiwibWVzc2FnZS1pZCIsIm1pbWUtdmVyc2lvbiIsInN
1YmplY3QiLCJ0byJdLCJoMSI6InRCOHV3UFFiY0NITzZ6dlUwRW56RUZXVUtLQnR
3eXptcnhlYXZ5NEpuMWc9In0=
I don't see any particular reason why the value needs all that syntax even, it
could just be:
Message-Instance: 1; yJhMSI6InNoYTI1NiIsImIxIjoiWEkyMjhWLzcyMFhOZWx
tNzZERktRZjkzNGlPRVFRQ3Q2d1ozdUtDSXI5UT0iLCJoIjpbImNvbnRlbnQtdHl
wZSIsImRhdGUiLCJmcm9tIiwibWVzc2FnZS1pZCIsIm1pbWUtdmVyc2lvbiIsInN
1YmplY3QiLCJ0byJdLCJoMSI6InRCOHV3UFFiY0NITzZ6dlUwRW56RUZXVUtLQnR
3eXptcnhlYXZ5NEpuMWc9In0=
I do like that whiespace is entirely non-significant in these fields, so you
can wrap them however you like.
ALSO DO NOTE: I still base-64 encode the `b1` and `h1` fields in this example.
That's really necessary because otherwise they would be binary, and JSON isn't
binary-safe.
Here's the JSON data for the i=2 header, which is a complex one because I
actually substitute one message for another at that point! This was a bug in
my test-case, but it exposes how Message-Instance algebra allows you to see
that such a change was done:
{
"a1": "sha256",
"b1": "4olUkMUi2bCCfVrAOg4rSNpPMBWnWoKd71+94zpiUqo=",
"h": [
"archived-at",
"authentication-results",
"content-type",
"date",
"feedback-id",
"from",
"list-archive",
"list-help",
"list-id",
"list-owner",
"list-post",
"list-subscribe",
"list-unsubscribe",
"message-id",
"message-id-hash",
"mime-version",
"precedence",
"subject",
"to"
],
"h1": "rD6J9EqHwAVvbafsiQw4CCneCdTe4NCbPz0UDPu/NoA=",
"rb": [
"--12b53dc829d24511bfa04f7d5e3675f8",
[5,5],
[7,9],
"This email starts a working group last call for
https://datatracker.ietf.org/doc/draft-ietf-jmap-webpush-vapid/ as discussed in
the IETF119 session.",
[11,11],
"Please post any comments or responses by *Thursday, April 4th, 2024*.",
[13,13],
[16,25],
"--12b53dc829d24511bfa04f7d5e3675f8",
[27,31],
"amily:Arial;\">Hi All,<br></div><div
style=3D\"font-family:Arial;\"><div><b=",
"r></div><div>This email starts a working group last call for <a
href=3D\"=",
"https://datatracker.ietf.org/doc/draft-ietf-jmap-webpush-vapid/\">https:/=",
"/datatracker.ietf.org/doc/draft-ietf-jmap-webpush-vapid/</a> as discusse=",
"d in the IETF119 session.<br></div><div
style=3D\"font-family:Arial;\"><br=",
"></div><div style=3D\"font-family:Arial;\">Please post any comments or
res=",
"ponses by <b>Thursday, April 4th, 2024</b>.<br></div><div
style=3D\"font-=",
"family:Arial;\"><br></div><div
style=3D\"font-family:Arial;\">Thanks,<br></=",
"div><div style=3D\"font-family:Arial;\"><br></div><div
style=3D\"font-famil=",
"y:Arial;\">Bron.<br></div><div><br></div><div><br></div></div><div
id=3D\"=",
"sig56629417\"><div class=3D\"signature\">--<br></div><div
class=3D\"signatur=",
"e\"> Bron Gondwana, CEO, Fastmail Pty Ltd<br></div><div
class=3D\"si=",
"gnature\"> [email protected]<br></div><div
class=3D\"signature\"=",
"><br></div></div><div
style=3D\"font-family:Arial;\"><br></div></body></ht=",
"ml>",
"--12b53dc829d24511bfa04f7d5e3675f8--"
],
"rh": {
"archived-at": [],
"authentication-results": [],
"content-type": ["multipart/alternative;
boundary=12b53dc829d24511bfa04f7d5e3675f8"],
"date": ["Thu, 21 Mar 2024 12:09:37 +1000"],
"feedback-id": [],
"from": ["\"Bron Gondwana\" <[email protected]>"],
"list-archive": [],
"list-help": [],
"list-id": [],
"list-owner": [],
"list-post": [],
"list-subscribe": [],
"list-unsubscribe": [],
"message-id": ["<[email protected]>"],
"message-id-hash": [],
"precedence": [],
"subject": ["Working group last call draft-ietf-jmap-webpush-vapid"]
}
}
Bron.
On Thu, Jan 22, 2026, at 12:35, Tobias Herkula wrote:
> Hi all,
>
> having reviewed the current DKIM2 drafts, I would like to propose a
> simplification of the wire
> representation.
>
> Relative to DKIM1, DKIM2 elevates “hop semantics” to first-class, signed
> assertions (e.g., mf/rt,
> chain intent, and potentially large recipient sets). My concern is that
> encoding these
> semantics primarily as an expanding set of tag=value parameters will (a)
> increase syntactic
> surface area, (b) incentivize ad-hoc list grammars, and (c) ultimately
> produce fragile parsers
> and interoperability friction.
>
> Proposal: represent the majority of DKIM2 hop metadata as a single
> base64-encoded JSON
> object, while constraining the DKIM2 header tag list to the minimal set
> required for signature
> mechanics.
>
> I am explicitly suggesting JSON (rather than a binary encoding), because even
> when base64-
> encoded it remains operationally transparent: it is trivially decodable and
> therefore
> inspectable by operators with standard tooling. In practice, that level of
> human readability is
> close to a requirement for deployment, troubleshooting, and incident response.
>
> Benefits:
>
> * Recipient-scale: large and/or structured rt sets can be represented
> without introducing
> additional list recipes or delimiter rules, while preserving a clean
> extension model.
>
> * EAI / SMTPUTF8 downgrade hops: a JSON container can carry the original
> recipient
> identities (including SMTPUTF8 forms) and any downgrade mapping artifacts
> in a
> structured and unambiguous way.
>
> * MIME granularity: JSON can naturally encode a MIME tree and carry per-part
> hashes. This
> enables an MUA (notably in IMAP-based retrieval scenarios) to validate the
> DKIM2
> signature once, then selectively validate only the MIME part(s) actually
> rendered to the
> user. This is particularly relevant for mobile clients and
> bandwidth-constrained
> environments.
>
> Considerations:
>
> This approach requires a well-defined JSON schema (including constraints on
> size and schema
> evolution) to ensure consistent interpretation across implementations. I can
> provide a small
> strawman JSON schema that maps cleanly to current DKIM2 concepts.
>
> Tobias Herkula
>
> --
>
> Senior Product Owner Mail Security
> Product Management Mail Transfer & Mail Security
>
> 1&1 Mail & Media GmbH
> E-Mail: [email protected]
> Web: www.mail-and-media.com
>
> Hauptsitz Montabaur, Amtsgericht Montabaur, HRB 7666
>
> Geschäftsführer: Alexander Charles, Dr. Michael Hagenau, Thomas Ludwig, Dr.
> Verena Patzelt
>
> Member of United Internet
>
> This e-mail may contain confidential and/or privileged information. If you
> are not the intended recipient of this e-mail, you are hereby notified that
> saving, distribution or use of the content of this e-mail in any way is
> prohibited. If you have received this e-mail in error, please notify the
> sender and delete the e-mail.
> _______________________________________________
> Ietf-dkim mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
>
--
Bron Gondwana, CEO, Fastmail Pty Ltd / Fastmail US LLC
[email protected]
_______________________________________________
Ietf-dkim mailing list -- [email protected]
To unsubscribe send an email to [email protected]