Internet-Draft | Email Modification Algebra | November 2024 |
Gondwana | Expires 24 May 2025 | [Page] |
This memo describes a method for describing the changes made to an email during common email modifications, for example those caused by mailing lists and forwarders.¶
While this is general enough to be used for any changes, it is anticipated that this method will normally be used for removing added data rather than large complex changes.¶
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 24 May 2025.¶
Copyright (c) 2024 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
Currently, when an email is sent with a DKIM signature, the message can go through multiple forwarders and still be authenticated, however if a single change is made to a header which is covered by the signature, or to the body, then the signature no longer validates - and it's impossible for the receiver to know what was changed, or even if the entire message was replaced.¶
By producing a way to describe changes, the recipient can examine the sections which were changed and determine whether the change was malicious. Because each step signs its own changes in DKIM2, this also allows the recipient to identify exactly which intermediary introduced each change, and adjust their reputation accordingly.¶
For headers, the format is to completely replace all headers with a particular name. For example if you replace the subject and from address in an email, then you need to include the complete old headers for each of those:¶
Header: "DKIM2-Delta-Header:"¶
Command | Input |
---|---|
i | DKIM2 matching header number |
b | replace headers with base64 octet value |
t | replace headers with raw text characters value |
Example for a message which has had Subject and From replaced, and Reply-To added.¶
From: [email protected] To: [email protected] Reply-To: [email protected] DKIM2-Delta-Header: i=3; t=Subject:A replacement for DKIM; b=From:YnJvbmdAZmFzdG1haWx0ZWFtLmNvbQo=; t=Reply-To¶
Notice that "Reply-To" has no colon, and hence is an instruction to remove any "Reply-To" headers. All headers are case insignificant for removal, and SHOULD be inserted with the case given in the header when being added back.¶
This difference format for the body is inspired by [RFC3284] (The VCDIFF Generic Differencing and Compression Data Format).¶
Since the transport for the delta is a 7-bit mime header, this format has been made simple and human readable. It is a simple program describing ranges of data to copy from the output to recreate the input.¶
Header: "DKIM2-Delta-Body:"¶
Command | Input |
---|---|
i | DKIM2 matching header number |
b | insert octets from base64 encoded value |
c | copy raw octets from range offset-length in new-message body |
d | copy base64 encoded octets from range offset-length in new-message body |
t | insert raw octets from value (only usable for some text characters) |
z | y (if set, MUST be only source) - unspecified change made |
Example:¶
DKIM2-Delta-Body: i=2; c=0-19452; c=20312-150¶
Example - appended to some base64 content; so we need to add back the last few characters (and the mime trailer)¶
DKIM2-Delta-Body: i=2; c=0-19452; t=aX==; c=20312-150¶
Example - a URL was substituted in the content of the body (complex, but still easily doable!)¶
DKIM2-Delta-Body: i=3; c=0-3542; b=PGEgaHJlZj0iaHR0cHM6Ly93d3cuZXhhbXBsZS5jb20iPkV4YW1wbGU8L2E+Cg==; c=3623-84743¶
The decision whether to use 'b' or 't' is up to the system creating the diff, however 't' has a limited set of characters that are safe to use in headers.¶
Likewise, it is expected that 'c' will normally be used to copy octets directly from the new message, however in cases where a message needs to transit 7 bits systems cleanly, the email modifier may need to re-encode the octets of the original message, and this allows for doing so.¶
In the most extreme case, it is possible to place content in the [RFC2046] preamble or epilogue, either as base64-encoded or raw MIME structures, which represents the original message.¶
For example an email which removes an attachment could have:¶
Content-Type: multipart/mixed; boundary="oldboundary" This is a multipart message in MIME format. --oldboundary Content-Type: text/plain The message --oldboundary Content-Type: application/pdf A big attachment in base64... --oldboundary--¶
And the new message:¶
DKIM2: i=1; ... DKIM2-Delta-Body: i=1; c=0-45; c=337-13; c=58-39; c=337-13; c=275-78 DKIM2-Delta-Header: i=1; b=Content-Type,bXVsdGlwYXJ0L21peGVkOyBib3VuZGFyeT0ib2xkYm91bmRhcnki Content-Type: multipart/mixed; boundary="newboundary" This is a multipart message in MIME format. --newboundary Content-Type: text/plain The message --newboundary-- The following is content which was removed by example.com forwarding service and is present to allow reconstructing the original message for DKIM2 verification. Content-Type: application/pdf A big attachment in base64... --oldboundary--¶
In this case, the delta format is using the old boundary string at the very end as the source three times to recreate each of the old MIME boundaries. A much simpler though slightly more space hungry version of the same thing can be done like this:¶
DKIM2: i=1; n=hi DKIM2-Delta-Body: i=1; c=0-45; c=276-144 DKIM2-Delta-Header: i=1; b=Content-Type,bXVsdGlwYXJ0L21peGVkOyBib3VuZGFyeT0ib2xkYm91bmRhcnki Content-Type: multipart/mixed; boundary="newboundary" This is a multipart message in MIME format. --newboundary Content-Type: text/plain The message --newboundary-- The following is content which was removed by example.com forwarding service and is present to allow reconstructing the original message for DKIM2 verification. --oldboundary Content-Type: text/plain The message --oldboundary Content-Type: application/pdf A big attachment in base64... --oldboundary--¶
Or you can reuse the boundaries from the original message:¶
DKIM2: i=1; ... DKIM2-Delta-Body: i=1; c=0-110; c=269-62; c=97-16 Content-Type: multipart/mixed; boundary="oldboundary" This is a multipart message in MIME format. --oldboundary Content-Type: text/plain The message --oldboundary-- The following attachment was removed by example.com forwarding service and is present to allow reconstructing the original message for DKIM2 verification. Content-Type: application/pdf A big attachment in base64...¶
This also reverses back to the original message.¶
Each DKIM2 signature implicitly covers all DKIM2-Delta-Body and DKIM2-Delta-Header headers
with an i=N
value for the same and lower N values as the i=
on the DKIM2 header.¶
To get back to the original message and confirm that it was unchanged, it is necessary to apply this algorith iteratively.¶
For example if you receive a message at i=7
for which there is a modification to the
headers at i=5
and a modification to both headers and body at i=3
, to recreate the
original message you would first apply the header changes from i=5
, then apply the
header and body changes for i=3
. If this doesn't create a message which validates
with the initial i=1 signature, then some hop has corrupted the message, and you can
check every single DKIM signature in reverse to find the first one where the message
no longer validates.¶
original version¶
[[This section to be removed by RFC Editor]]¶