<?xml version="1.0" encoding="UTF-8"?>
  <?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
  <!-- generated by https://github.com/cabo/kramdown-rfc version  (Ruby 3.2.3) -->


<!DOCTYPE rfc  [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">

]>


<rfc ipr="trust200902" docName="draft-gondwana-dkim2-modification-alegbra-04" category="std" consensus="true" submissionType="IETF" obsoletes="4686" tocInclude="true" sortRefs="true" symRefs="true">
  <front>
    <title abbrev="Email Modification Versioning">A method for describing changes made to an email</title>

    <author initials="B." surname="Gondwana" fullname="Bron Gondwana">
      <organization>Fastmail Pty Ltd</organization>
      <address>
        <postal>
          <street>Level 2, 114 William Street</street>
          <code>3000</code>
          <country>Australia</country>
        </postal>
        <phone>+61 457 416 436</phone>
        <email>brong@fastmailteam.com</email>
      </address>
    </author>

    <date year="2025" month="October" day="17"/>

    
    
    <keyword>Internet-Draft</keyword>

    <abstract>


<t>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.</t>

<t>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.</t>



    </abstract>



  </front>

  <middle>


<section anchor="background-and-motivations"><name>Background and motivations</name>

<t>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.</t>

<t>By producing a way to describe changes, the recipient can examine the sections
which were changed and determine whether the change was malicious.  Along with
signatures which validate against previous versions, this can be used to
allow signing systems to take accountability for only the version of the
message which passed through their system.</t>

</section>
<section anchor="the-mailversion-header-field"><name>The MailVersion Header Field</name>

<t>This document describes an ordered set of header fields, each of
which describes the message at a specific version, along with
instructions on how to convert that version back to the previous
version.</t>

<section anchor="mailversion-header"><name>MailVersion Header</name>

<t>The format of the file is a tag-list.  TODO: we need to decide where we
pull tag-list from!</t>

<texttable>
      <ttcol align='left'>Tag</ttcol>
      <ttcol align='left'>Type</ttcol>
      <ttcol align='left'>Value</ttcol>
      <c>v</c>
      <c>position</c>
      <c>Revision number (range: 1 to 100)</c>
      <c>bh</c>
      <c>base64</c>
      <c>Body Hash value for this revision</c>
      <c>bin.n.m</c>
      <c>base64</c>
      <c>Hash for the binary representation of the numbered mime part</c>
      <c>b</c>
      <c>body-recipe</c>
      <c>Recipe to replicate the previous version of the message body</c>
      <c>h.header</c>
      <c>head-recipe</c>
      <c>Recipe to replicate the previous version of the named header field</c>
</texttable>

</section>
<section anchor="body-recipe"><name>body-recipe</name>

<t>The Body Recipe is a comma separated list of instructions.  Each instruction starts with a
prefix.  Commas can be followed by optional whitespace.</t>

<texttable>
      <ttcol align='left'>Prefix</ttcol>
      <ttcol align='left'>Value</ttcol>
      <ttcol align='left'>Action</ttcol>
      <c>c:</c>
      <c>start-end</c>
      <c>Copy the lines (inclusive) numbered from 1.</c>
      <c>b:</c>
      <c>base64</c>
      <c>Decode the base64 to get the value of a line to insert.</c>
      <c>t:</c>
      <c>text</c>
      <c>Copy the exact text to get the value of a line to insert.</c>
      <c>z</c>
      <c>none</c>
      <c>If present, says that changes have been made to the body which can not be described to get back to the earlier version, meaning the signing system takes accountability for the full content.</c>
</texttable>

</section>
<section anchor="header-recipe"><name>header-recipe</name>

<t>The Header Recipe is a comma separated list of instructions.  Each instruction starts with a
prefix.  Commas can be followed by optional whitespace.</t>

<t>While key names are case insensitive, implementations SHOULD create the header with the same
case as the key.</t>

<texttable>
      <ttcol align='left'>Prefix</ttcol>
      <ttcol align='left'>Value</ttcol>
      <ttcol align='left'>Action</ttcol>
      <ttcol align='left'>&#160;</ttcol>
      <c>d:</c>
      <c>integer</c>
      <c>'*'</c>
      <c>Delete the indexed (numbered from 1) copy of this header field, or all copies</c>
      <c>b:</c>
      <c>base64</c>
      <c>Decode the base64 to get the value of a header field to insert</c>
      <c>&#160;</c>
      <c>t:</c>
      <c>text</c>
      <c>Copy the exact text to get the value of a header field to insert</c>
      <c>&#160;</c>
      <c>z</c>
      <c>none</c>
      <c>If present, says that changes have been made to the named header field which can not be described to get back to the earlier version, meaning the signing system takes accountability for the full content of this message.</c>
      <c>&#160;</c>
</texttable>

</section>
<section anchor="examples"><name>Examples</name>

<t>Example for a message which has had Subject and From replaced,
and Reply-To added.</t>

<figure><artwork><![CDATA[
From: brong@fastmailteam.com.dmarc.fail
To: dkim2@lists.ietf.org
Reply-To: dkim2@lists.ietf.org
MailVersion: v=2;
 bh=[...];
 h.Subject=d:*,t:A replacement for DKIM;
 h.From=d:*,b:YnJvbmdAZmFzdG1haWx0ZWFtLmNvbQo=;
 h.Reply-To=d:*
]]></artwork></figure>

<t>Example:</t>

<figure><artwork><![CDATA[
MailVersion: v=2; bh=[...]; b=c:1-500,c:520-520
]]></artwork></figure>

<t>Example - a URL was substituted in the content of the body (complex, but still
easily doable!)</t>

<figure><artwork><![CDATA[
MailVersion: v=3;
 bh=[...];
 b=c:1-500,
   b:PGEgaHJlZj0iaHR0cHM6Ly93d3cuZXhhbXBsZS5jb20iPkV4YW1wbGU8L2E+Cg==,
   c:501-702
]]></artwork></figure>

<t>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 tag-values</t>

<t>Likewise, it is expected that 'c' will normally be used to copy lines 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, albeit at some expense in header bloat!</t>

</section>
</section>
<section anchor="iterative-application"><name>Iterative application</name>

<t>To get back to the original message and confirm that it was unchanged, it is necessary
to apply this algorith iteratively.</t>

<t>For example if you receive a message for which there is a modification to the
headers at <spanx style="verb">v=3</spanx> and a modification to both headers and body at <spanx style="verb">v=2</spanx>, to recreate the
original message you would first apply the header changes from <spanx style="verb">v=3</spanx>, then apply the
header and body changes for <spanx style="verb">v=2</spanx>.  If this doesn't create a message which validates
with the initial <spanx style="verb">v=1</spanx> hash, then some hop has corrupted the message.</t>

</section>
<section anchor="security"><name>Security</name>

<t>TBA</t>

</section>
<section anchor="iana-considerations"><name>IANA Considerations</name>

<t>TBA</t>

</section>


  </middle>

  <back>



    <references title='Informative References'>



<reference anchor='RFC3284'>
  <front>
    <title>The VCDIFF Generic Differencing and Compression Data Format</title>
    <author fullname='D. Korn' initials='D.' surname='Korn'/>
    <author fullname='J. MacDonald' initials='J.' surname='MacDonald'/>
    <author fullname='J. Mogul' initials='J.' surname='Mogul'/>
    <author fullname='K. Vo' initials='K.' surname='Vo'/>
    <date month='June' year='2002'/>
    <abstract>
      <t>This memo describes VCDIFF, a general, efficient and portable data format suitable for encoding compressed and/or differencing data so that they can be easily transported among computers. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name='RFC' value='3284'/>
  <seriesInfo name='DOI' value='10.17487/RFC3284'/>
</reference>

<reference anchor='RFC2046'>
  <front>
    <title>Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types</title>
    <author fullname='N. Freed' initials='N.' surname='Freed'/>
    <author fullname='N. Borenstein' initials='N.' surname='Borenstein'/>
    <date month='November' year='1996'/>
    <abstract>
      <t>This second document defines the general structure of the MIME media typing system and defines an initial set of media types. [STANDARDS-TRACK]</t>
    </abstract>
  </front>
  <seriesInfo name='RFC' value='2046'/>
  <seriesInfo name='DOI' value='10.17487/RFC2046'/>
</reference>




    </references>


<section anchor="changes-from-earlier-versions"><name>Changes from Earlier Versions</name>

<section anchor="draft-gondwana-dkim2-modification-algebra-03"><name>draft-gondwana-dkim2-modification-algebra-03</name>

<t><list style="symbols">
  <t>Rename header to 'MailVersion'</t>
  <t>Remove all requirements that it integrates with DKIM2.</t>
  <t>Add body hash and per-mime-part hashes (NOTE: this is a bunch of extra calculation, so
definitely to discuss)</t>
</list></t>

</section>
<section anchor="draft-gondwana-dkim2-modification-algebra-02"><name>draft-gondwana-dkim2-modification-algebra-02</name>

<t><list style="symbols">
  <t>change the header format to have unique keys, making it fit the ABNF for these types
of headers.</t>
  <t>allow easier editing of multi-value headers by always popping the first header and
always prepending newly added headers.</t>
  <t>change body to use d.0, d.1, etc with the program in the value, so that the program
ordering is reliable regardless of the parser used to read the header.</t>
</list></t>

</section>
<section anchor="draft-gondwana-dkim2-modification-algebra-02-1"><name>draft-gondwana-dkim2-modification-algebra-02</name>

<t><list style="symbols">
  <t>change to using line numbers rather than octet offsets</t>
  <t>remove d= base64 decoding capability</t>
  <t>for multiple lines; require a separate b= or t= for each line</t>
</list></t>

</section>
<section anchor="draft-gondwana-dkim2-modification-algebra-01"><name>draft-gondwana-dkim2-modification-algebra-01</name>

<t><list style="symbols">
  <t>rename 'DKIM2-Diff' headers to 'DKIM2-Delta'</t>
  <t>add 'z=y' option to DKIM2-Delta-Body for "complete replacement"</t>
  <t>add d= base64 decoding option to DKIM2-Delta-Body</t>
</list></t>

</section>
<section anchor="draft-gondwana-dkim2-modification-algebra-00"><name>draft-gondwana-dkim2-modification-algebra-00</name>

<t><list style="symbols">
  <t>original version</t>
</list></t>

<t>[[This section to be removed by RFC Editor]]</t>

</section>
</section>


  </back>

<!-- ##markdown-source:
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
QZMbAAA=

-->

</rfc>

