This would be better to capture in an I-D. Email to the list with this
sort of detail is way too transient.
Mike
On 3/30/25 5:09 PM, Wei Chuang wrote:
This email is a continuation of exploring how the hashing will work in
DKIM2. The prior email focussed on how the "h=" tag worked, while
this one will focus on hashing the prior DKIM2 signatures and whether
to disclose intermediate hash results to tolerate further changes.
This is that place holder in step 5) in the prior email. This
presumes that body hashing is largely understood. Bron and Richard
noted that that the body hash largely is the same as DKIM1 but only
supports relaxed canonicalization. Relaxed body canonicalization is
defined in RFC6376 section 3.4.4
<https://datatracker.ietf.org/doc/html/rfc6376#section-3.4.4>.
Regarding the DKIM2 header fields hashing, my understanding is that
this process should be very similar to ARC RFC8617 section 5.2
<https://datatracker.ietf.org/doc/html/rfc8617#section-5.2>. ARC
header fields use the instance tag "i=n" to identify and order the
fields as they are generated over forwardings. DKIM2 adopts this
practice. ARC has three header fields per given tag and value n, and
the baseline DKIM2 has only DKIM2-Signature. However Bron noted in in
draft-gondwana-dkim2-header section 4.1 that other optional DKIM2
header fields may carry "i=n" such as DKIM2-Delta-Header,
DKIM2-Delta-Body and DKIM2-Authentication-Result. Left perhaps
unsaid, potentially there may be other DKIM2- prefixed fields. This
attempts to clarify how this might work in part to determine its
feasibility.
To sign a message, the signer must find the maximum instance tag
"i=n", denoted as M. To add a new DKIM2-Signature, first verify that
there isn't any to be defined in the future indication that the
message "left" DKIM2. Preventing adding DKIM2 header fields is
mentioned in draft-gondwana-dkim2-header section 4
<https://datatracker.ietf.org/doc/html/draft-gondwana-dkim2-header-00#name-handling-of-messages-that-l>to
indicate that a message has left the DKIM2 ecosystem. (DKIM2/1
interop is an area of disagreement, and left for later discussion)
Assuming this not the case, then add optional DKIM2 headers are added
at i=M+1, then generate a DKIM2-Signature at i=M+1 using the hashing
procedures below.
To gather the DKIM-Signature hashes for a given N:
1) Collect all DKIM2 header fields in the message header
a) These will all be prefixed "DKIM2-" and have a instance tag "i=n"
immediately after the header field name
b) Group them into a group of header fields of instance tag "i=n" from
1 to N where each n is called a DKIM2 set. If not continuous, then
issue an error.
2. Hash successively by DKIM2 sets in order by "i=n" starting from i=1
to N. Within each set hash each field in alphabetical order.
This also calls for consideration of publishing the header hash as a
new tag "hh=" result in addition to the body hash as described in
RFC6376 as tag "bh=". While not discussed in RFC6376, presumably
publication of "bh=" could allow a receiver to ignore in some cases
changes in the body based on local policy. In the same vein,
publication of the header hash could allow a receiver to ignore some
header modifications as well as provide more insight into failing
signature validations.
Putting this all together, let's look at the detailed flow of
hashing. Recall that DKIM1 calls for:
D-SIG = is the canonicalized DKIM-Signature field itself without the
signature value portion of the parameter, that is, an empty parameter
value.
body-hash = hash-alg (canon-body, l-param)
data-hash = hash-alg (h-headers, D-SIG, body-hash)
signature = sig-alg (d-domain, selector, data-hash)
In order to tolerate changes to headers and body, this DKIM2 approach
could discloses the intermediate hashes so that data-hash can be
recomputed:
D2-SIG = hash-alg(the canonicalized DKIM2-Signature field itself
without the signature value portion of the parameter, that is, an
empty parameter value, concatenated other sorted DKIM2 headers at the
same instance number).
header-hash = hash-alg(h-headers as describe in the "Header Signing
Strawman" email)
dkim2-hash = hash-alg(all earlier DKIM2-signatures)
body-hash = hash-alg (canon-body, l-param)
data-hash = hash-alg(dkim2-hash, header-hash, D2-SIG, body-hash)
signature = sig-alg (d-domain, selector, data-hash)
For the overall hashing for verification procedure, follow the
following pseudo code.
1) Collect all DKIM2 header fields in the message header
2) Find the maximum instance tag value of M where there exists a
continuous sequence from 1 to M.
3) Start with an instance tag value of M and validate the
DKIM2-Signature.
4) Optionally validate the DKIM2-Signature with i=1 to M-1. (Whether
this is optional is an area of disagreement, to be discussed later)
Feedback is very much welcome.
-Wei
On Wed, Mar 26, 2025 at 1:23 AM Wei Chuang <wei...@google.com> wrote:
This is a strawman description for the DKIM2 header signing. I
know that Richard is writing a draft for this, but as draft
writing is heavyweight and before going too deep down a particular
path, I think there is benefit to put some sort of concept out
early for community feedback. In the IETF-122 discussion we heard
from Bron that there is an implicit list of headers that always
will be signed, and that the headers will be oversigned. There is
also a DKIM2-Signature "h=" to specify extra headers to be signed
not covered by the implicit list as mentioned in
draft-gondwana-dkim2-header. Bron also mentioned that subsequent
DKIM2-Signatures extra headers "h=" cover prior DKIM2-Signatures
"h=" headers i.e. must be a superset.
RFC6376 has a list of recommended headers to sign for in section
5.4.1
<https://datatracker.ietf.org/doc/html/rfc6376#section-5.4.1>.
This can be the start of that implicit always signed headers.
These are:
* From
* Reply-To
* Subject
* Date
* To, Cc
* Resent-Date, Resent-From, Resent-To, Resent-Cc
* In-Reply-To, References
* List-Id, List-Help, List-Unsubscribe, List-Subscribe, List-Post,
List-Owner, List-Archive
At a high level, the signing algorithm would be:
1) Find in the message which of the recommended headers are
present. Obtain the values in the order found in the recommended
headers list, and canonicalize using the Relaxed algorithm found
in RFC6376 section 3.4.2
<https://datatracker.ietf.org/doc/html/rfc6376#section-3.4.2>.
Then successively hash them. If multiple headers of a given name
are found, obtain these in a bottom to top order as described in
RFC6376 section 5.4.2
<https://datatracker.ietf.org/doc/html/rfc6376#section-5.4.2>.
2) Take the headers in the extra "h=" headers list, and obtain the
value in the order found. If multiple headers of a given name are
found in "h=", obtain them in a bottom to top order as described
in RFC6376 section 5.4.2
<https://datatracker.ietf.org/doc/html/rfc6376#section-5.4.2>.
Canonicalize using the Relaxed algorithm found in RFC6376 section
3.4.2
<https://datatracker.ietf.org/doc/html/rfc6376#section-3.4.2>then
successively hash them. If not found, treat the value as empty.
3) Oversign the entire list of recommended headers as described in
RFC6376 section 3.5
<https://datatracker.ietf.org/doc/html/rfc6376#section-3.5>thereby
preventing those from being added to the message. This hashes an
empty value for each header.
4) Oversign the extra "h=" headers, preventing them from being
added to the message. This hashes an empty value for each header
5) Hash the body and DKIM2-Signature headers (out of scope for
this description)
6) Sign the hash.
The validation algorithm is analogous. Hash as above, then
perform the signature validation with the hash.
The giant <implicit oversigning list> is:
from:reply-to:subject:date:to:cc:resent-date:resent-from:resent-to:resent-cc:in-reply-to:
references:list-id:list-help:list-unsubscribe:list-subscribe:list-post:list-owner:list-archive
EXAMPLE
ORIGINATION MESSAGE: with List-Unsubscribe-Post as the extra header
DKIM2-Signature: i=1; h=list-unsubscribe-post
To: list@mailinglist.example
From: user@origination.example
List-Unsubscribe-Post:
Effective h=from:to:list-unsubscribe-post:<implicit oversigning
list>:list-unsubscribe-post i.e. is order the headers are hashed.
FORWARDED MESSAGE: From header rewritten and Delivered-to added
DKIM2-Signature: i=2; h=list-unsubscribe-post:delivered-to
From: list@mailinglist.example
Delivered-to: list@mailinglist.example
DKIM2-Signature: i=1; h=list-unsubscribe-post
To: list@mailinglist.example
List-Unsubscribe-Post:
Effective h=from:to:list-unsubscribe-post:delivered-to:<implicit
oversigning list>:
list-unsubscribe-post:delivered-to i.e. is order the headers are
hashed.
So I think this implicit header signing could work and does save
some unnecessary legacy h= overhead in the message header.
-Wei
_______________________________________________
Ietf-dkim mailing list --ietf-dkim@ietf.org
To unsubscribe send an email toietf-dkim-le...@ietf.org
_______________________________________________
Ietf-dkim mailing list -- ietf-dkim@ietf.org
To unsubscribe send an email to ietf-dkim-le...@ietf.org