Internet-Draft DKIM Access Control and Differential Cha June 2026
Nurpmeso Expires 18 December 2026 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-nurpmeso-dkim-access-control-diff-changes-11
Updates:
6376 (if approved)
Published:
Intended Status:
Informational
Expires:
Author:
S. Nurpmeso, Ed.

DKIM Access Control and Differential Changes

Abstract

This document specifies a DKIM (RFC 6376) iteration that allows cryptographical verification of SMTP (RFC 5321) envelope data, and of any signature along the message path, even beyond IMF (RFC 5322) message content changes. It addresses existing security glitches, and introduces active mitigations to embrace collateral damage effects of email solutions of the younger past by a standardized solution, also by moving complexity away from lower network protocol layers, where problems cannot be solved. It updates DKIM in certain aspects that reality has proven to be superfluous, incomplete, or obsoleted.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 18 December 2026.

Table of Contents

1. Introduction

DKIM[RFC6376] was not designed to cover SMTP[RFC5321] envelope data, allowing replay of valid, verifiable messages to an infinite set of recipients by malicious third parties, undetectable by sender and recipients. (Rationale: to aid SMTP delivery to recipients in various conditions even the existing but optional "x=" expiration tag timestamp must be chosen so far in the future that malicious players have plenty of time to misuse messages.)

Whereas DKIM[RFC6376] standardized rudimentary, incomplete approaches to inspect at least header field modifications of IMF[RFC5322] message content that happen along the message path (the "z=" tag content; also to point to the "l=" tag), the overall design was agreed in not to survive them (compare, for example, [RFC6377]).

The resulting paradigm is "as long as one signature can be successfully verified, DKIM verification will succeed". It is a context-free "take it and accept it" approach.

This is problematic as message content changes may be falsely attributed to (the) address(es) in the IMF originator field(s). Later policy-enforcing standards effectively complicated the situation, in that false attribution may now technically be avoidable, but mitigations of practice like "user A via B" will still be attributed to "A" by a human for one, and, in short, anything is valid, if just one signature is. ([RFC9057] elaborates more context.)

Potentially many signatures may exist in a message. DKIM[RFC6376] gives hints on how verification can be performed, but in practice mitigations are applied in order to reduce excessive and useless verifications on hops down the message path: elder, especially broken signatures are removed, or renamed, as changes are performed on message content. Especially mailing-lists, or, in general, hops that cross the [RFC3461] definition of a "final delivery for the message" act like this. A standardized approach to avoid excessive network traffic, and, in parts, CPU work during message verification will mitigate careless configurations.

1.1. Conventions and Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

The term "FOSS" refers to Free and Open Source Software.

The term "privately encrypt" is used to denote that the software should take appropriate steps to ensure data encryption and key security.

2. DKIM Vivid Adjustments

This document obsoletes certain unused / incomplete aspects of DKIM[RFC6376], and adjusts certain vivid parts as follows. The full context of the changes will become clear as the remains of this document unfold.

Informative remark: The protocol changes apply only to signatures signalling compliance with the iterated variant presented in this document.

3. DKIM/ACDC

The DKIM[RFC6376] iteration Access Control and Differential Changes:

The DKIM[RFC6376] iteration Access Control and Differential Changes creates DKIX-Sig: signature header fields, which are identical to DKIM-Signature: header fields except for the new "acdc=" and "dch=" tags, the missing "v=" tag, and the changed semantics of the now optional "h=" tag.

The "dch=" tag holds the checksum of the canonicalized data of all existing DKIX-DC: header fields, each header field concluded with a CRLF, sorted in reverse header stack order as defined by DKIM[RFC6376] section 5.4.2, "Signatures Involving Multiple Instances of a Field" (which should be equal the reverse "sequence" order), with the DKIX-DC: header created for this signature, if any, last (at the top of the stack).

The "acdc=" tag consists of multiple subtags separated with colon (U+003A, :). For efficiency reasons it SHOULD be placed early, before tags like the new "dch=", but also "bh=", "b=", and "h=", or example.

4. The DKIX-Store header field

The DKIX-Store: header field has no meaning in the email system. The sole purpose of mentioning it is to announce that it MUST be removed when messages enter and leave the email system.

It could for example be temporarily created and used by non-integrated mail solutions that consist of otherwise unrelated software, to pass informational data in between the "ingress" and the "egress" processing side. To address possible software bugs and configuration errors this specification enforces removal of all occurrences.

Informative remark: In order to achieve locality it is suggested to "privately encrypt" data passed around in this temporary header field.

5. Access Control

SMTP[RFC5321] delivers messages to individual domains. With DKIM/ACDC, whenever a SMTP envelope is created or changed, all distinct domain-names found within the list of intended SMTP envelope RCPT TO addressees are collected, because messages need to be actively forged on this individual domain base: DKIM/ACDC will create and include DKIX-AC: header fields covering SMTP envelopes as messages are sent to individual domains.

The domains' _dkimacdc DNS entries, as below, are queried. Dependent upon the detected state the DKIX-AC: header fields will either contain exact envelope info (DKIM/ACDC supported), or only domain names.

In any case the completely prepared message, including the readily prepared signatures, is forged, (a) DKIX-AC: header field(s) is/are generated which cover(s) the logical recipient subset, and the resulting message is then sent.

Informative remark: MTA-integrated DKIM/ACDC implementations can create perfect fit DKIX-AC: header fields only for recipients truly accepted by the receiving MTA (not hindering even SMTP pipelining[RFC2920]), and use successive transmissions until all recipients have been worked.

DKIM/ACDC aware recipient domains are expected to manage a DKIX-AC: identity cache to mitigate replay attacks. (Hint: a verified DKIX-AC: signature seems like a natural cache key source, see below.)

Informative remark: The now mandatory and constrained "x=" tag allows for finite identity cache sizes.
Informative remark: Perfect fit DKIX-AC: header fields can create write-once cache entries.

A DKIM/ACDC aware hop that receives a message that contains at least one DKIM/ACDC enabled signature, and that does not contain a DKIX-AC: header field MUST reject it with SMTP reply code 550; if enhanced status codes[RFC3463] are used, 5.5.4 MUST be used.

It MUST reject messages which fail the signature check of a DKIX-AC: or signature header field, or the condition and flag check verification, with SMTP reply code 550; the enhanced status code MUST be 5.7.7 ("message integrity failure").

It MUST likewise fail if the DKIX-AC: header field does not correspond to the SMTP envelope data, with exceptions as documented for the "N" flag of the "acdc=" tag of DKIX-Sig:natures.

It MUST test for a superset of recipients, and only fail if an envelope recipient is not included in the DKIX-AC: header field. DKIX-AC: header fields with an "ec=" are treated specially.

Senders MAY use Delivery Status Notifications[RFC3461] to fine-tune the resulting behavior.

5.1. The DKIX-AC header field

The syntax of this header field is the usual semicolon separated list of DKIM-style tags of unspecified order; unknown tags MUST be ignored. It is used to cryptographically link the SMTP envelope to the sent IMF[RFC5322] mail message.

The "w=" tag is the linked DKIX-Sig: "sequence", best placed early. Multiple signatures with the same "sequence", but different algorithms, may exist, and so may DKIX-AC: header fields.

The selector of the linked signature is given by the "s=" tag, the used algorithm can be deduced from there.

The "o=" tag is the domain of the SMTP[RFC5321] MAIL FROM, the "f=" tag denotes the "local-part".

Informative remark: In conjunction with the "acdc=" "N" flag these do not correspond to the "local email system".

The "d=" tag value is the recipient domain, with one to multiple "t=" tag(s) for the "local-part"s of RCPT TOs.

Warning: The "d=" tag may have an empty value alongside "P"ostmaster mode!
Warning: SMTP[RFC5321] address "local-part"s permit "quoted-string"s!

In case the recipient domain for a particular message forge has not announced support for DKIM/ACDC, and to strengthen SMTP envelope anonymity in permanent IMF[RFC5322] message data, the tag "f=", as well as any "t=" tag MUST be omitted, and instead a "privately encrypted" "ec=" tag be placed: the content of this tag is BASE64[RFC4648] encoded, and MUST correlate to the hidden "f=" and "t=" tags.

Informative remark: The SMTP envelope domains are cryptographically fixated even in the minimal non-DKIM/ACDC variant of DKIX-AC:, protecting users of DKIM/ACDC aware hops against replay. The security enhancement was considered worth the resulting unfortunate leakage of this minimal DKIX-AC: header field to permanent storage.

Mirroring DKIM-Signature: the tag list is concluded with the "b=" tag that is the cryptographic signature data of the DKIX-AC: header field. To ensure proper linkage and uniqueness of the "b=" signature the reassembled (see DKIM[RFC6376] section 3.5) value of the linked DKIX-Sig: signature is "temporarily assigned" to "b=" before creating it; Thereafter the "b=" tag is assigned its own value.

All instances of DKIX-AC: header fields MUST be removed by DKIM/ACDC aware software as soon as possible: they MUST NOT be delivered by local delivery agents as part of the message. They MUST, however, exist in rejected messages.

However, if a domain is only an intermediate, which was neither directly addressed nor which originated the mail, and which does not modify the SMTP envelope either, then it MUST NOT remove the "current" DKIX-AC: header field(s), and it MUST NOT generate (a) new one(s).

5.2. The _dkimacdc.DOMAIN DNS TXT RR

The syntax of this DNS resource record is the usual semicolon separated list of DKIM-style tags of unspecified order; unknown tags MUST be ignored.

DNS CNAME chains MUST be followed when looking up this DNS RR.

The optional tag "c=" (%x64 "=") MUST have the value "n" (%x6E). It announces that the DKIM-Signature: legacy header field need not be generated for messages sent to this host. Senders MAY follow this advise if they can ensure that the message will not pass intermediate hops.

The optional tag "a=" (%x61 "=") represents a colon-separated list of supported algorithm names, interpreted case-insensitively. Unknown list entries MUST be ignored. The entries "ed25519-sha256" and "eda-sha256" are implied.

6. Differential Changes

Whenever a DKIM/ACDC enabled domain detects during signature creation that the canonicalized representation of a message, whether header fields and/or body data, was modified, a new DKIX-DC: header field has to be created.

6.1. The DKIX-DC header field

The syntax of this header field is the usual semicolon separated list of DKIM-style tags of unspecified order; unknown tags MUST be ignored.

The "w=" tag is the linked DKIX-Sig: ACDC "sequence", best placed early.

The "h=" tag is used to store differential data for header fields, "b=" that for body content. Both tags are optional, but at least one MUST exist in a valid DKIX-DC: header field, and a given one MUST NOT have an empty value.

The differential data is stored in the patch format as below, which is first compressed with ZLIB[RFC1950], and then BASE64[RFC4648] encoded.

6.2. Preparing patch creation

The differential changes are created with canonicalized header fields and body data, respectively, as seen on egress, alongside the equally canonicalized data present before modifications took place, that is, on ingress.

All header fields covered by the header field database Appendix A MUST be included. All header fields covered by former signatures of the DKIM/ACDC chain MUST be included. DKIM/ACDC enabled signatures, and any other "DKIX-" header field MUST NOT be included.

The header fields MUST be sorted byte-wise (by numeric ASCII byte value) by-name, the formed subgroups MUST remain in the (reverse) header stack order defined by DKIM[RFC6376] section 5.4.2, "Signatures Involving Multiple Instances of a Field".

Differential changes are then expressed with the patch content as below.

6.2.1. Patch content

The patch format is an adopted variant of the BSDiff algorithm patch format, as below. Overall it consists of a header, followed by control data. Thereafter the two byte (8-bit octet) streams of differential data (in reverse order) and extra data conclude the patch. Erroneous patch data MUST cause rejection.

The header and the control data consist of 32-bit signed integers, stored in network byte order (MSF; most significant byte first).

The header consists of four values denoting the length of the control data tuple block in bytes, the length of the differential data block in bytes, the length of the extra data block in bytes, concluded by the length of the original "data target" in bytes; The sum of the first three values must be one less than the maximum positive 32-bit signed integer. The number of control data tuples MUST NOT excess the length of the original "data source" (in bytes) plus one.

The control data is a stream of tuples of three values each. The first denotes the length of differential data to join in in bytes, or 0. Differential data is joined in by adding "the current" differential byte to "the current" byte of the "data source", then storing the addition result byte in the "data target". The read positions within the differential data and the "data source" move forward accordingly. The write position in the "data target" moves forward accordingly.

The second value denotes the length of extra data to copy in bytes, or 0. The read position within extra data move forward accordingly. The write position in the "data target" moves forward accordingly.

All tuples are worked in order, and within each tuple first the differential data, if any, then the extra data, if any, is worked.

The last value of control data tuples denotes the number of bytes to seek relatively in the "data source" before the next tuple is worked. Of all the values, only this one may be negative. The overall offset within the "data source" MUST NOT become negative after the seek.

Informative remark: Of all control data tuples only the first may only perform seek adjustments without also storing data in "data target". Even if it is otherwise ignored the seek value of the last control data tuple must result in a valid offset. (0 is always valid.) Other conditions MUST be treated as errors.

6.2.2. BSDiff patch content adaption

  • 32-bit integers are used for length and offset values. This almost halves memory usage, and produces smaller patch control data. It is deemed sufficient for email purposes.
  • Data is stored in big endian (network; MSF; most significant byte first) instead of little endian (LSF; least significant byte first) byte order.
  • In order to allow for memory usage reduction during patch generation the adaption uses a shared memory region for differential and extra data: the former is therefore stored in reversed order, top down. (Reduces memory usage by the size of the target data set.)
  • The entire, readily prepared patch is passed through a compressor. (The original uses three separate bzip2 streams to sequentially serialize control, differential and extra data separately.)
  • The original header did not contain the size of the extra data, which was stored last, with its size implicitly extending to the end of the patch. The adaption includes the extra data size in the header, allowing more verification tests to be applied with only the header being readily parsed. This also enables the I/O layer to allocate perfectly sized memory with only the header data being available.

6.2.3. An example algorithm

A very fast and simple algorithm that processes data linewise is presented here.

Informative remark: Like SMTP DKIM does not know about MIME, it treats the body (and the header fields, in that respect) as CRLF terminated lines of bytes, with certain byte-based ("relaxed") normalizations applied on top. MIME reencoding (may) happen along the message path: the MIME content-transfer-encoding type, its line length(s), as well as character sets, and more, can theoretically be in flux. With the advent of tracking of differential changes it is expected that software becomes smarter, by adapting more to what exists in messages, instead of performing "brute force modifications". For example, a service provider that rewrites URIs within messages can ensure that the line lengths of a base64 formatted input are preserved after the rewrite, as base64, and with the underlaying character set being unchanged, and that, where modifications took place, the lengths of only the modified lines are adjusted so to keep the differential changes as minimal as possible. In such a world a very fast linewise algorithm is sufficient.

Initialize a "list of lines" that can be iterated over uni-directionally to 0. While there is still input data from the target (egress) data set:

  • Search for LF line feed. If found, advance over it, otherwise use the entire remaining input.
  • Verify the resulting data length fits into 31-bit, minus 1.
  • Create a hash of the data that is proof against complexity attacks.
  • Put the data at the end of the "list of lines".

Initialize a "hashmap" to 0. If any, store all members of the "list of lines" therein, indexed by their hashes.

Initialize an "absolute position", a "current length of differences", and a "current length of extra data" to 0. Initialize a "former line" to 0. Also initialize an "overall length of differences", and an "overall length of extra data" to 0. While there is still input data from the source (ingress) data set:

  • Search for LF line feed. If found, advance over it, otherwise use the entire remaining input.
  • Verify the resulting data length fits into 31-bit, minus 1.
  • If the "hashmap" is not 0:

    • Create a hash of the data (with the same algorithm as above).
    • If the "former line" is not 0, check whether its next line (in the "list of lines"), if any, matches the current data. If so, make the next line the "former line", verify the resulting "overall length of differences" will fit in 31-bit, minus 1; Add that many bytes to the "absolute position", add that many bytes to the "current length of differences", add that many zero bytes to "differences".
    • Otherwise search "hashmap" for the hash (ensure an exact data match, as necessary). If a match is found, then if either the "current length of differences" is not 0, or the "current length of extra data" is not 0, or if no control tuple has yet been dumped, then dump a control tuple first, and set the "current length of extra data" to 0; Make it the "former line", verify the resulting "overall length of differences" will fit in 31-bit, minus 1; If the offset of the start of the "former line" (within the target (egress) data set) does not equal the "absolute position", ensure the relative seek of the formerly dumped control tuple is set to the subtraction of the start of the "former line" and the "absolute position"; Set the "current length of differences" to that many bytes, set the "absolute position" to the start of the "former line" plus that many bytes, add that many zero bytes to "differences". (Optimization: dumping an otherwise "empty" initial control tuple is not necessary if no relative seek is to be applied.)
  • Otherwise the line is extra data. Verify the resulting "overall length of extra data" will fit in 31-bit, minus 1; Add that many bytes to the "current length of extra data", copy that many bytes to "extra data".

After all the data has been worked, then if either the "current length of differences" is not 0, or the "current length of extra data" is not 0, then dump a control tuple.

Ensure the relative seek of the last control tuple, if any, is 0.

Here exemplary results of the FOSS [BSDIPA] plug-and-play ISO C99 and perl reference implementation that generates the above patch format with either (the string suffix sort based) BSDiff algorithm of Colin Percival, or the above textual variant:

# Email, sent to/received reencoded from ML (4621 vs 5309 bytes):
$ diff -e .S1 .S2 | wc -c
2326
#  BSDiff: data: ctrl=216 (18 entries) diff=3554 extra=1067
#          857 result bytes; Code 0:001 secs, ZLIB I/O 0:000 secs
#          (BZ2 950 / 0:001, XZ 884 / 0:126, ZSTD 875 / 0:107)
# Textual: data: ctrl=108 (9 entries) diff=3043 extra=1578
#          1089 result bytes; Code 0:000 secs, ZLIB I/O 0:000 secs
#          (BZ2 1260 / 0:001, XZ 1144 / 0:127, ZSTD 1116 / 0:126)

# Large roff manual (428420 vs rewritten 390770 bytes)
$ diff -e .B1 .B2 | wc -c
241233
#  BSDiff: data: ctrl=54816 (4568 entries) diff=304307 extra=124113
#          74830 result bytes; Code 0:198 secs, ZLIB I/O 0:122 secs
#          (BZ2 67368 / 0:022, XZ 65216 / 0:137, ZSTD 69444 / 0:144)
# Textual: data: ctrl=54456 (4538 entries) diff=202309 extra=226111
#          97355 result bytes; Code 0:004 secs, ZLIB I/O 0:098 secs
#          (BZ2 81943 / 0:053, XZ 82364 / 0:253, ZSTD 86767 / 0:213)

6.3. Rationale

Differences are included to allow DKIM verifiers to restore previous message content for the purpose of cryptographically verifying elder signatures. This for example allows for collecting trustworthy statistics of organizational trust ([RFC5863], section 2.5) in an automated fashion. Alternatively or in addition per-user decisions for certain message paths, involving certain modification per path hop, are made possible, and can be taken into account.

For example, user interfaces could use traffic light semantics that unfold on click to traffic light semantics of all message versions, which would (with precautions) visualize differences. This can empower users to make decisions on the trustworthiness of intermediates, and, for example, request display of the From: header field as created by the original message sender for a message path that crosses a mailing-list. (As in, "yes, i accept this hop changes From:, it is a mailing list".)
Informative remark: The data exists in the DKIM "relaxed" normalized variant: former states are not meant to be usable messages. This is deemed acceptable because of the purpose of including differential changes, and because their visualization of a successfully verified DKIM/ACDC chain should still be sufficient to allow users, and automated systems, making responsible decisions.

7. Mitigations for Future

At the time of this writing the email infrastructure is deeply penetrated by mitigation code that circumvents problems incurred by standards like DMARC and SPF, driven by the desire to keep existing infrastructures (configurations) in an usable state.

For example, SPF will not survive a single hop, which means that alias expansion, a widely used core feature of the email infrastructure, does no longer easily work. The IETF has no solution for this problem, but the software world has created a "Sender Rewriting Scheme", involving dedicated software to implement mitigations, so that aliases can be used regardless.

As another example, DMARC causes a lot of mailing-lists to apply mitigations of various form and style: old signatures are removed, or renamed, often the From: header field is rewritten in a "User A via List B" style, and the Reply-To: header field will announce the real sender, unless that was already set. The introduction of this requirement of blind trust into "A via B" displays seems like a devastating psychological failure.

7.1. Mitigations

This memo suggests to apply mitigations actively as part of DKIM processing, at minimum temporarily, until, at some future time, the email infrastructure has adapted to a new reality. Future engineers can then decide how to proceed further.

In any case it seems wise to move decisions on actual content changes away from the SMTP layer, to reduce failures to cryptographical signature failures, and let users and/or algorithms on a higher layer decide whether a certain content change or applied mitigation is "acceptable", or not.

  • Remove existing DKIM/ACDC announcing DKIM-Signature: header fields. In case no mitigations have yet been applied to "RFC5322.From", and no such mitigation will be applied, as below, the signature linked to "sequence" 1 is an exception. This mitigation MUST be applied. The mitigation MAY be applied to non DKIM/ACDC linked DKIM-Signatures: as well in as far as local policy allows. Before the flag day DKIM/ACDC will create a single DKIM-Signature: that will verify correctly.

  • Mitigate non-local MAIL FROM envelopes.

    Because a possible SPF check will fail on the next hop (in situations with a strict SPF policy that applies a policy), if a message that does not originate locally leaves the email system on egress, with a SMTP envelope MAIL FROM of a foreign domain, mitigate such addresses, so that the current hop becomes the, quoting [RFC3461], "final delivery for the [original] message". DKIM/ACDC software SHOULD offer options to exclude certain domains from these mitigations.

    To mitigate, synthesize for example an address of the local domain with a "local-part" starting with DKIX=, followed by at least 16 bytes of the BASE64[RFC4648] encoded HMAC[RFC2104] of a dedicated cryptographic private key and the original MAIL FROM.

    Alternatively, using a dedicated subdomain is an approach that avoids any possible "local-part" ambiguities. Then for example the IETF mailing-list From: header field DMARC mitigation approach could be used, which decomposes the original MAIL FROM by replacing the commercial at (U+0040, @) with its "hexadecimal value in quoted-printable notation" to end with "local-part=40domain", followed by the domains of the mitigating host: local-part=40domain@subdomain.domain.

    Informative remark: the SMTP size limit of "local-part" is 64 octets, however the overall "reverse-path" limit of RFC 821 and RFC 2821 was 256 octets.

    The synthesized address MUST be linkable to the original MAIL FROM for at least 864000 seconds (ten days: to reach into the next working week). It SHOULD be linkable only by Delivery Status Notifications[RFC3461] or (other) message bounces. If the bounce transports enough message data content this MAY be furtherly constrained to verifiable DKIM signatures of the local domain, even the exact message for which the address was synthesized. The optional bounce identifier "id" may be usable for this purpose.

    Informative remark: Except for linking purposes to the original envelope the synthesized address is otherwise "transparent", and should appear as if it does not exist: DKIM/ACDC software is expected to cause appropriate rejection on SMTP level at the earliest possible time.
  • Mitigate From: header fields, if necessary.

    When a message was changed in between ingress and egress, so that the DKIM signature (not only: related to the From: header field) will no longer verify. Then, if the From: header field was not already locally mitigated (by for example mailing-list software), actively mitigate the From: header field, so that the current hop becomes the, quoting [RFC3461], "final delivery for the [original] message" in respect to the IMF[RFC5322] message that is visible to recipients. DKIM/ACDC software SHOULD offer options to exclude certain domains from these mitigations.

    To mitigate, place the original "name-addr" in the Reply-To: header field, unless that already exists, set the Author: header field if it can be ensured that From: was, actually, the author, and replace From: with synthesized content. The examples of non-local MAIL FROM envelope mitigation apply also here in respect to "addr-spec"; yet, the dedicated subdomain approach results in visually more appealing header field content. For the "display-name" a "From: X via <Y>" notation MAY be used, where "X" denotes the original "display-name".

    For example, if the original content was "Forename Surname <for.sur@example1.net>" then the mitigation could be "Forename Surname via" <for.sur=40example1.net@dkim.example2.net>. Without dedicated subdomains a variant of the widely known construct "Forename Surname <for(DOT)sur(AT)example1(DOT)net>" via <dkix-dedicated@example2.net> may be used. Whether DKIM/ACDC dedicated subdomain or DKIM/ACDC dedicated address, the backing software implementation is expected to rewrite the address

8. Example

An example that shows the flow of a single message with multiple different recipients, including mailing-lists and aliases. It assumes all recipients announced DKIM/ACDC support. It provides full mitigations and support for SPF and DMARC.

Originator (yet forged for recipient domain f.g):

  MAIL FROM: <a@b.c>
  RCPT TO: <d@f.g>
  RCPT TO: <e@f.g>
  ...
  DKIX-AC: w=1; s=K1ed; o=b.c; f=a; d=f.g; t=d; t=e; b=..
    DKIM-Signature: w=1; s=K1; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  To: d@f.g, e@f.g, x@y.z, u@v.w, r@s.t, o@p.q
  ...

f.g, local delivery (to d@ and e@):

  ...
  DKIX-Sig: acdc=2:N0C:AIV; s=K2ed; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  ...

x@y.z -- a mailing-list!
It redistributes after RFC 2369 and RFC 2919 additions,
in-message unsubscribe footer, and From: mitigated
(in best RFC 3461 manner):

  MAIL FROM: <x@y.z>
  RCPT TO: <l@m.n>
  ...
  DKIX-AC: w=2; s=K2ed; o=y.z; f=x; d=m.n; t=l; b=..
  DKIX-DC: w=2; h=BASE64; b=BASE64
    DKIM-Signature: w=2; s=K2; ..
  DKIX-Sig: acdc=2:V0C0U3:ADEOVYy; s=K2ed; dch=..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a(AT)b(DOT)c via <x@y.z>
  Reply-To: a@b.c
  ...
  List-Unsubscribe: bla

u@v.w -- an expanded alias!
The hop honours RFC 3461, and changes MAIL FROM;
it keeps DKIM-Signature: w=1 for DMARC compatibility:

  MAIL FROM: <u@v.w>
  RCPT TO: <realu@realv.realw>
  ...
  DKIX-AC: w=2; s=K2ed; o=v.w; f=u; d=realv.realw; t=realu; b=..
    DKIM-Signature: w=2; s=K2; ..
  DKIX-Sig: acdc=2:N0C:EOVy; s=K2ed; ..
    DKIM-Signature: w=1; s=K1; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  ...

r@s.t -- an expanded alias!
Note: invalid DKIM/ACDC, because no MAIL FROM update,
will later fail SPF;
it keeps DKIM-Signature: w=1 for DMARC compatibility:

  MAIL FROM: <a@b.c>
  RCPT TO: <realr@reals.realt>
  ...
  DKIX-AC: w=2; s=K2ed; o=b.c; f=a; d=reals.realt; t=realr; b=..
    DKIM-Signature: w=2; s=K2; ..
  DKIX-Sig: acdc=2:N0C:EVy; s=K2ed; ..
    DKIM-Signature: w=1; s=K1; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  ...

... the same, but DKIM/ACDC compliant:

  MAIL FROM: <DKIX=a=40b.c@s.t>
  RCPT TO: <realr@reals.realt>
  ...
  DKIX-AC: w=2; s=K2ed; o=s.t; f=DKIX=a=40b.c; ..
    DKIM-Signature: w=2; s=K2; ..
  DKIX-Sig: acdc=2:N0C:EOVy; s=K2ed; ..
    DKIM-Signature: w=1; s=K1; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  ...

o@p.q -- a mailing-list!
Note: invalid DKIM/ACDC, because no From: mitigation,
c/would later fail DMARC;
it redistributes after RFC 2369 and RFC 2919 additions,
and in-message unsubscribe footer.

  MAIL FROM: <o@p.q>
  RCPT TO: <X@X.X>
  ...
  DKIX-AC: w=2; s=K2ed; o=p.q; f=o; d=X.X; t=X; b=..
  DKIX-DC: w=2; h=BASE64; b=BASE64
    DKIM-Signature: w=2; s=K2; ..
  DKIX-Sig: acdc=2:V0C0U3:DEOVYy; s=K2ed; dch=..
  DKIX-Sig: acdc=1:V0C0U3:O; s=K1ed; ..
  From: a@b.c
  ...
  List-Unsubscribe: bla

... the same, but DKIM/ACDC compliant
(using dedicated mitigation subdomain):

  MAIL FROM: <o@p.q>
  RCPT TO: <X@X.X>
  ...
  DKIX-AC: w=2; s=K2ed; o=p.q; f=o; d=X.X; t=X; b=..
  DKIX-DC: w=2; h=BASE64; b=BASE64
    DKIM-Signature: w=2; s=K2; d=dkim.p.q; ..
  DKIX-Sig: acdc=2:V0C0U3:DEOVYy; s=K2ed; d=dkim.p.q; dch=..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: "a@b.c" via <a=40b.c@dkim.p.q>
  Reply-To: a@b.c
  ...
  List-Unsubscribe: bla

l@m.n (recipient of x.y.z mailing-list), local delivery:

  ...
  DKIX-Sig: acdc=3:V0C0U3:IVYy; s=K3ed; ..
  DKIX-DC: w=2; h=BASE64; b=BASE64
  DKIX-Sig: acdc=2:V0C0U3:ADEOVYy; s=K2ed; dch=..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a(AT)b(DOT)c via <x@y.z>
  ...

realr@reals.realt -- expanded alias target, local delivery:

  ...
  DKIX-Sig: acdc=3:N0C:IVy; s=K3ed; ..
  DKIX-Sig: acdc=2:N0C:EOVy; s=K2ed; ..
  DKIX-Sig: acdc=1:N0C:O; s=K1ed; ..
  From: a@b.c
  ...

9. IANA Considerations

IANA is asked to add the header fields DKIX-Sig:, DKIX-AC:, DKIX-DC:, and DKIX-Store: to the "Permanent Message Header Field Names" registry. IANA is asked to add "eda" to the "DKIM Key Type" registry. IANA is asked to add the tag "w=" to the "DKIM-Signature Tag Specifications" registry.

10. Security Considerations

Public key cryptography is the safest approach to identification of counterparts and verification of data. This specification enables DKIM to cryptographically verify SMTP envelopes, and to cryptographically verify all message transitions back to the original message sender.

11. Normative References

[RFC4648]
Josefsson, S., "The Base16, Base32, and Base64 Data Encodings", RFC 4648, DOI 10.17487/RFC4648, , <https://www.rfc-editor.org/info/rfc4648>.
[RFC6376]
Crocker, D., Ed., Hansen, T., Ed., and M. Kucherawy, Ed., "DomainKeys Identified Mail (DKIM) Signatures", STD 76, RFC 6376, DOI 10.17487/RFC6376, , <https://www.rfc-editor.org/info/rfc6376>.
[RFC8463]
Levine, J., "A New Cryptographic Signature Method for DomainKeys Identified Mail (DKIM)", RFC 8463, DOI 10.17487/RFC8463, , <https://www.rfc-editor.org/info/rfc8463>.

12. Informative References

[RFC1123]
Braden, R., Ed., "Requirements for Internet Hosts - Application and Support", STD 3, RFC 1123, DOI 10.17487/RFC1123, , <https://www.rfc-editor.org/info/rfc1123>.
[RFC1950]
Deutsch, P. and J. Gailly, "ZLIB Compressed Data Format Specification version 3.3", RFC 1950, DOI 10.17487/RFC1950, , <https://www.rfc-editor.org/info/rfc1950>.
[RFC2045]
Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, DOI 10.17487/RFC2045, , <https://www.rfc-editor.org/info/rfc2045>.
[RFC2104]
Krawczyk, H., Bellare, M., and R. Canetti, "HMAC: Keyed-Hashing for Message Authentication", RFC 2104, DOI 10.17487/RFC2104, , <https://www.rfc-editor.org/info/rfc2104>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/info/rfc2119>.
[RFC2920]
Freed, N., "SMTP Service Extension for Command Pipelining", STD 60, RFC 2920, DOI 10.17487/RFC2920, , <https://www.rfc-editor.org/info/rfc2920>.
[RFC3207]
Hoffman, P., "SMTP Service Extension for Secure SMTP over Transport Layer Security", RFC 3207, DOI 10.17487/RFC3207, , <https://www.rfc-editor.org/info/rfc3207>.
[RFC3461]
Moore, K., "Simple Mail Transfer Protocol (SMTP) Service Extension for Delivery Status Notifications (DSNs)", RFC 3461, DOI 10.17487/RFC3461, , <https://www.rfc-editor.org/info/rfc3461>.
[RFC3463]
Vaudreuil, G., "Enhanced Mail System Status Codes", RFC 3463, DOI 10.17487/RFC3463, , <https://www.rfc-editor.org/info/rfc3463>.
[RFC5234]
Crocker, D., Ed. and P. Overell, "Augmented BNF for Syntax Specifications: ABNF", STD 68, RFC 5234, DOI 10.17487/RFC5234, , <https://www.rfc-editor.org/info/rfc5234>.
[RFC5321]
Klensin, J., "Simple Mail Transfer Protocol", RFC 5321, DOI 10.17487/RFC5321, , <https://www.rfc-editor.org/info/rfc5321>.
[RFC5322]
Resnick, P., Ed., "Internet Message Format", RFC 5322, DOI 10.17487/RFC5322, , <https://www.rfc-editor.org/info/rfc5322>.
[RFC5863]
Hansen, T., Siegel, E., Hallam-Baker, P., and D. Crocker, "DomainKeys Identified Mail (DKIM) Development, Deployment, and Operations", RFC 5863, DOI 10.17487/RFC5863, , <https://www.rfc-editor.org/info/rfc5863>.
[RFC6377]
Kucherawy, M., "DomainKeys Identified Mail (DKIM) and Mailing Lists", BCP 167, RFC 6377, DOI 10.17487/RFC6377, , <https://www.rfc-editor.org/info/rfc6377>.
[RFC7208]
Kitterman, S., "Sender Policy Framework (SPF) for Authorizing Use of Domains in Email, Version 1", RFC 7208, DOI 10.17487/RFC7208, , <https://www.rfc-editor.org/info/rfc7208>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/info/rfc8174>.
[RFC9057]
Crocker, D., "Email Author Header Field", RFC 9057, DOI 10.17487/RFC9057, , <https://www.rfc-editor.org/info/rfc9057>.
[RFC9562]
Davis, K., Peabody, B., and P. Leach, "Universally Unique IDentifiers (UUIDs)", RFC 9562, DOI 10.17487/RFC9562, , <https://www.rfc-editor.org/info/rfc9562>.
[RFC9787]
Gillmor, D. K., Ed., Melnikov, A., Ed., and B. Hoeneisen, Ed., "Guidance on End-to-End Email Security", RFC 9787, DOI 10.17487/RFC9787, , <https://www.rfc-editor.org/info/rfc9787>.
[RFC9788]
Gillmor, D. K., Hoeneisen, B., and A. Melnikov, "Header Protection for Cryptographically Protected Email", RFC 9788, DOI 10.17487/RFC9788, , <https://www.rfc-editor.org/info/rfc9788>.
[BSDIPA]
"BSDIPA, a mutation of BSDiff", <https://github.com/sdaoden/s-bsdipa>.

Appendix A. Header field database

The database of header fields, in an automatically extractable form. Lines starting with EQUALS SIGN U+003D form start and, with a following SOLIDUS U+002F, end tags. The tag "HFDB" encloses the entire database. The header fields are case-insensitive, followed by whitespace, followed by its assigned bit number. Lines starting with NUMBER SIGN U+0023 are comments.

=HFDB
# sorted for normal 4, list 6
# RFC 5322, 3.6 / 5322-bis, I.
from 0
sender 1
reply-to 2
date 3
to 4
cc 5
bcc 6
message-id 7
in-reply-to 8
references 9
subject 10
# RFC 9057
author 11
# RFC 2045
mime-version 12
content-type 13
content-transfer-encoding 14
# (rest usually not in main header)
content-id 15
content-description 16
# RFC 1806
content-disposition 17
# RFC 9788
hp-outer 18
# draft-ietf-drums-mail-followup-to
mail-followup-to 19
# draft-josefsson-openpgp-mailnews-header
openpgp 20
# RFC 2369
list-id 21
list-help 22
list-subscribe 23
list-unsubscribe 24
list-post 25
list-owner 26
list-archive 27
# RFC 5064
archived-at 28
# draft-ietf-sml-structured-email
content-purpose 29
# RFC 5322, 3.6 / 5322-bis, II.
resent-from 30
resent-sender 31
resent-to 32
resent-cc 33
resent-date 34
resent-message-id 35
resent-bcc 36
#comments
keywords 37
# RFCs 3282 / 4021
content-language 38

# RFC 5703
original-from 39
original-subject 40
# RFC 4021 / draft-ietf-mailmaint-expires
expires 41

# RFC 8058 (last)
list-unsubscribe-post 42
=/HFDB

A.1. Example code for managing "hfdb-bits"

Example C code to interpret and create the DKIM/ACDC "hfdb-bits" tag.

#include <string.h>
#include <strings.h>

/* 0-based */
#define HFDB_ENTRIES (42 +1)

#define HFDB_STORE_BITS ((HFDB_ENTRIES + (8 - 1)) & ~(8 - 1))
#define HFDB_STORE_SIZE (HFDB_STORE_BITS / 8)
#define HFDB_STORE_C2OFF(C) ((hfdb_u8)(C) / 8)
#define HFDB_STORE_C2BIT(C) ((hfdb_u8)(C) & (8 - 1))
#define HFDB_STORE_SET(SP,BIT) \
   ((SP)->s_dat[HFDB_STORE_C2OFF(BIT)] |= (1u << HFDB_STORE_C2BIT(BIT)))
#define HFDB_STORE_CLEAR(SP,BIT) \
   ((SP)->s_dat[HFDB_STORE_C2OFF(BIT)] &= ~(1u << HFDB_STORE_C2BIT(BIT)))
#define HFDB_STORE_TEST(SP,BIT) \
   ((SP)->s_dat[HFDB_STORE_C2OFF(BIT)] & (1u << HFDB_STORE_C2BIT(BIT)))

#define HFDB_STRING_SIZE (HFDB_STORE_BITS / 5)

typedef unsigned char hfdb_u8;
struct hfdb_store{
   hfdb_u8 s_max; /* Max bit set in .s_dat, +1 */
   hfdb_u8 s_dat[HFDB_STORE_SIZE];
};

/* Number of bits set/characters stored, -1 on error */
static int hfdb_from_cp(struct hfdb_store *sp, char const *cp);
static int hfdb_to_cp(struct hfdb_store *sp, char cp[HFDB_STRING_SIZE +1]);

static int
hfdb_from_cp(struct hfdb_store *sp, char const *cp){
   int rv, addbits;

   memset(sp, 0, sizeof(*sp));

   rv = 0;
   for(addbits = 0; *cp != '\0'; addbits += 5, ++cp){
      int bs;

      bs = (int)(unsigned)*cp;
      /* Support case-insensitivity */
      if(bs >= 'a')
         bs -= 'a' - 'A';
    /* 5 bits/char: 0b11111: 36#V: 0-9A-V */
      if(bs > 'V' || bs < '0')
         break;
      bs -= '0'; /* "atoi" */
      if(bs > 9){
         bs -= 7;
         /* ..but ASCII U+003A..U+0040 not allowed */
         if(bs <= 9)
            break;
      }

      for(; bs != 0; ++rv){
         int b;

         b = ffs(bs);
         --b;
         bs ^= 1 << b;
         b += addbits;
         if(b >= HFDB_ENTRIES)
            goto jleave;
         HFDB_STORE_SET(sp, b);
         sp->s_max = ++b;
      }
   }

jleave:
   return (*cp == '\0' ? rv : -1);
}

static int
hfdb_to_cp(struct hfdb_store *sp, char cp[HFDB_STRING_SIZE +1]){
   int xmax, addbits;
   char *cursor, *lx;

   lx = cursor = cp;
   xmax = (sp->s_max <= HFDB_ENTRIES) ? sp->s_max : HFDB_ENTRIES;

   for(addbits = 0; addbits < xmax; addbits += 5){
      int c, b;

      b = 5;
      c = xmax - addbits;
      if(b > c)
         b = c;
      for(c = 0; b > 0;){
         int bx;

         bx = addbits + --b;
         if(HFDB_STORE_TEST(sp, bx))
            c |= 1u << b;
      }
      *cursor++ = "0123456789ABCDEFGHIJKLMNOPQRSTUV"[c];
      if(c != 0)
         lx = cursor;
   }
   *lx = '\0';

   return (int)(lx - cp);
}

Appendix B. Further DKIM Updates

Appendix C. Acknowledgements

Thanks to, in the order of appearance, Jesse Thompson, Richard Clayton for arguments against reliance on header field stacks, and pro the numbering scheme, and especially for noticing the partial transaction replay attack problem, Douglas Foster, Michael Thomas for explicit man-in-the-middle replay addressing; Alessandro Vesely inspired the explicitness of the E flag, Bron Gondwana for the inspiration to split up binary differences of headers and body, as well as the IANA registry revision, Lasse Collin for LZMA2 (and clarification vs XZ), and Julian Seward for bzip2. A big fat acknowledgment is due to Murray S. Kucherawy. Special thanks to Klaus Schulze, Manuel Goettsching, both also as Ash Ra Tempel, Laeuten der Seele, Laurent Garnier, as well as the Sleeping Environmental Bot broadcast.

Author's Address

Steffen Nurpmeso (editor)