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 to ietf-dkim-le...@ietf.org