4.1. Main Use Case
This section applies to the main use case, where the sending and receiving side (fully) support Header Protection as specified herein (cf. Section 3.1.1).¶
Note: The sending side specification of the main use case is also applicable to the cases where the sending side (fully) supports Header Protection as specified herein, while the receiving side does not, but is MIME-conformant according to [RFC2045], ff. (cf. Section 3.1.2 and Section 3.1.2.1).¶
Further backward compatibility cases are defined in Section 4.2.¶
4.1.1. MIME Format
4.1.1.1. Introduction
As per S/MIME version 3.1 and later (cf. [RFC8551]), the sending client MAY wrap a full MIME message in a message/RFC822 wrapper in order to apply S/MIME security services to these header fields.¶
To help the receiving side to distinguish between a forwarded and a wrapped message, the Content-Type header field parameter "forwarded" is added as defined in [I-D.melnikov-iana-reg-forwarded].¶
The simplified (cryptographic overhead not shown) MIME structure of such an Email Message looks as follows:¶
<Outer Message Header Section (unprotected)> <Outer Message Body (protected)> <MIME Header Section (wrapper)> <Inner Message Header Section> <Inner Message Body>¶
The following example demonstrates how an Original Message might be protected, i.e., the Original Message is contained as Inner Message in the Protected Body of an Outer Message. It illustrates the first Body part (of the Outer Message) as a "multipart/signed" (application/pkcs7-signature) media type:¶
Lines are prepended as follows:¶
- "O: " Outer Message Header Section¶
- "I: " Message Header Section¶
- "W: " Wrapper (MIME Header Section)¶
O: Date: Mon, 25 Sep 2017 17:31:42 +0100 (GMT Daylight Time) O: Message-ID: <e4a483cb-1dfb-481d-903b-298c92c21f5e@m.example.net> O: Subject: Meeting at my place O: From: "Alexey Melnikov" <alexey.melnikov@example.net> O: To: somebody@example.net O: MIME-Version: 1.0 O: Content-Type: multipart/signed; charset=us-ascii; micalg=sha1; O: protocol="application/pkcs7-signature"; O: boundary=boundary-AM This is a multipart message in MIME format. --boundary-AM W: Content-Type: message/RFC822; forwarded=no W: I: Date: Mon, 25 Sep 2017 17:31:42 +0100 (GMT Daylight Time) I: From: "Alexey Melnikov" <alexey.melnikov@example.net> I: Message-ID: <e4a483cb-1dfb-481d-903b-298c92c21f5e@m.example.net> I: MIME-Version: 1.0 I: MMHS-Primary-Precedence: 3 I: Subject: Meeting at my place I: To: somebody@example.net I: X-Mailer: Isode Harrier Web Server I: Content-Type: text/plain; charset=us-ascii This is an important message that I don't want to be modified. --boundary-AM Content-Transfer-Encoding: base64 Content-Type: application/pkcs7-signature [[base-64 encoded signature]] --boundary-AM--¶
The Outer Message Header Section is unprotected, while the remainder (Outer Message Body) is protected. The Outer Message Body consists of the wrapper (MIME Header Section) and the Inner Message (Header Section and Body).¶
The wrapper is a simple MIME Header Section with media type "message/rfc822" containing a Content-Type header field parameter "forwarded=no" followed by an empty line.¶
If the source is an Original (message/rfc822) Message, the Inner Message Header Section is typically the same as (or a subset of) the Original Message Header Section, and the Inner Message Body is typically the same as the Original Message Body.¶
The Inner Message itself may contain any MIME structure.¶
Note: It is still to be decided by the LAMPS WG whether or not to recommend an alternative MIME format as described in Appendix C.1.1.1 (instead of the currently standardized and above defined format).¶
4.1.2. Sending Side
This section describes the process an MUA should use to apply cryptographic protection to an e-mail message with header protection. We start by describing the legacy message composition process as a baseline.¶
4.1.2.1. Composing a Cryptographically-Protected Message Without Header Protection
[I-D.dkg-lamps-e2e-mail-guidance] describes the typical process for a legacy crypto MUA to apply cryptographic protections to an e-mail message. That guidance and terminology is replicated here for reference:¶
-
origbody
: the traditional unprotected message body as a well-formed MIME tree (possibly just a single MIME leaf part). As a well-formed MIME tree,origbody
already has structural headers (Content-*
) present.¶ -
origheaders
: the intended non-structural headers for the message, represented here as a list of(h,v)
pairs, whereh
is a header field name andv
is the associated value. Note that these are header fields that the MUA intends to be visible to the recipient of the message. In particular, if the MUA uses theBcc
header during composition, but plans to omit it from the message (see section 3.6.3 of [RFC5322]), it will not be inorigheaders
.¶ -
crypto
: The series of cryptographic protections to apply (for example, "sign with the secret key corresponding to X.509 certificate X, then encrypt to X.509 certificates X and Y"). This is a routine that accepts a MIME tree as input (the Cryptographic Payload), wraps the input in the appropriate Cryptographic Envelope, and returns the resultant MIME tree as output.¶
The algorithm returns a MIME object that is ready to be injected into the mail system:¶
4.1.2.2. Header Confidentiality Policy
When composing an encrypted message with protected headers, the composing MUA needs a Header Confidentialiy Policy.
In this document, we represent that Header Confidentiality Policy as a function hcp
:¶
-
hcp(name, val_in) --> val_out
: this function takes a header field namename
and initial valueval_in
as arguments, and returns a replacement header valueval_out
. Ifval_out
is the special valuenull
, it mean that the header in question should be omitted from the set of headers visible outside the Cryptographic Envelope.¶
For example, an MUA that only obscures the Subject
header field by replacing it with the literal string [...]
and does not offer confidentiality to any other header fields would be represented as (in pseudocode):¶
hcp(name, val_in) --> val_out:
if name is 'Subject':
return '[...]'
else:
return val_in
¶
Note that such a policy is only needed when the end-to-end protections include encryption (confidentiality). No comparable policy is needed for other end-to-end cryptographic protections (integrity and authenticity), as they are simply uniformly applied so that all header fields known by the sender have these protections.¶
This asymmetry is an unfortunate consequence of complexities in message delivery systems, some of which may reject, drop, or delay messages where all headers are removed from the top-level MIME object.¶
This document does not mandate any particular Header Confidentiality Policy, though it offers guidance for MUA implementers in selecting one in Section 4.1.3. Future documents may recommend or mandate such a policy for an MUA with specific needs. Such a recommendation might be motivated by descriptions of metadata-derived attacks, or stem from research about message deliverability, or describe new signalling mechanisms, but these topics are out of scope for this document.¶
4.1.2.3. Composing with "Wrapped Message" Header Protection
To compose a message using "Wrapped Message" header protection, we use those inputs described in Section 4.1.2.1 plus the Header Confidentiality Policy hcp
defined in Section 4.1.2.2.
The new algorithm is:¶
-
For header name and value
(h,v)
inorigheaders
:¶- Add header
h
oforigbody
with valuev
¶
- Add header
-
If any of the header fields in
origbody
, including headers in the nested internal MIME structure, contain any 8-bit UTF-8 characters (see section section 3.7 of [RFC6532]):¶- Let
payload
be a new MIME part with one header:Content-Type: message/global; forwarded=no
, and whose body isorigbody
.¶
- Let
-
Else:¶
- Let
payload
be a new MIME part with one header:Content-Type: message/rfc822; forwarded=no
, and whose body isorigbody
.¶
- Let
- Apply
crypto
topayload
, yielding MIME treeoutput
¶ -
If
crypto
contains encryption:¶ -
For header name and value
(h,v)
inorigheaders
:¶- Add header
h
ofoutput
with valuev
¶
- Add header
- Return
output
¶
Note that the Header Confidentiality Policy hcp
is ignored if crypto
does not contain encryption.
This is by design.¶
4.1.2.4. Composing with "Injected Headers" Header Protection
To compose a message using "Injected Headers" header protection, the composing MUA needs one additional input in addition to the Header Confidentiality Policy hcp
defined in Section 4.1.2.2.¶
-
legacy
: a boolean value, indicating whether any recipient of the message is believed to have a legacy client. If all recipients are known to implement this draft,legacy
should be set tofalse
. (How a MUA determines the value oflegacy
is out of scope for this document; an initial implementation can simply set it totrue
)¶
The revised algorithm for applying cryptographic protection to a message is as follows:¶
- Create a new MIME leaf part
legacydisplay
with headerContent-Type: text/plain; protected-headers="v1"
and an empty body.¶ -
if
crypto
contains encryption, andlegacy
istrue
:¶-
For each header name and value
(h,v)
inorigheaders
:¶-
If
h
is user-facing (see [I-D.autocrypt-lamps-protected-headers]):¶
-
-
-
If the body of
legacydisplay
is empty:¶- Let
payload
be MIME partorigbody
, discardinglegacydisplay
¶
- Let
-
Else: (body of
legacydisplay
is not empty)¶ -
For each header name and value
(h,v)
inorigheaders
:¶- Add header
h
of MIME partpayload
with valuev
¶
- Add header
- Set the
protected-headers
parameter on theContent-Type
ofpayload
tov1
¶ - Apply
crypto
topayload
, producing MIME treeoutput
¶ -
If
crypto
contains encryption:¶ -
For each header name and value
(h,v)
inorigheaders
:¶- Add header
h
ofoutput
with valuev
¶
- Add header
- Return
output
¶
Note that both new parameters (hcp
and legacy
) are effectively ignored if crypto
does not contain encryption.
This is by design, because they are irrelevant for signed-only cryptographic protections.¶
4.1.2.5. Choosing Between Wrapped Message and Injected Headers
When composing a message with end-to-end cryptographic protections, an MUA SHOULD protect the headers of that message as well as the body.¶
An MUA MAY protect the headers of any outbound message using either the "Wrapped Message" or the "Injected Headers" style of protection. See Section 4.2 for more discussion about reasons to choose one mechanism or another.¶
[[ TODO: this document should recommend generation of one particular scheme by default for new implementers ]]¶
4.1.3. Default Header Confidentiality Policy
An MUA SHOULD have a sensible default Header Confidentiality Policy, and SHOULD NOT require the user to select one.¶
The default Header Confidentiality Policy SHOULD provide confidentiality for the Subject
header field by replacing it with the literal string [...]
.
Most users treat the Subject of a message the same way that they treat the body, and they are surprised to find that the Subject of an encrypted message is visible.¶
[[ TODO: select one of the two policies below the recommended default ]]¶
4.1.3.1. Minimalist Header Confidentiality Policy
Accordingly, the most conservative recommended Header Confidentiality Policy only protects the Subject
:¶
hcp_minimal(name, val_in) --> val_out:
if name is 'Subject':
return '[...]'
else:
return val_in
¶
4.1.3.2. Strong Header Confidentiality Policy
Alternately, a more aggressive (and therefore more privacy-preserving) Header Confidentiality Policy only leaks a handful of fields whose absence is known to increase rates of delivery failure, and simultaneously obscures the Message-ID
behind a random new one:¶
hcp_strong(name, val_in) --> val_out:
if name in ['From', 'To', 'Cc', 'Date']:
return val_in
else if name is 'Subject':
return '[...]'
else if name is 'Message-ID':
return generate_new_message_id()
else:
return null
¶
The function generate_new_message_id()
represents whatever process the MUA typically uses to generate a Message-ID
for a new outbound message.¶
4.1.3.3. Offering Stronger Header Confidentiality
A MUA MAY offer even stronger confidentiality for headers of an encrypted message than described in Section 4.1.3.2.
For example, it might implement an HCP that obfuscates the From
field, or omits the Cc
field, or ensures Date
is represented in UTC
(obscuring the local timezone).¶
The authors of this document hope that implementers with deployment experience will document their chosen Header Confidentiality Policy and the rationale behind their choice.¶
4.1.4. Receiving Side
An MUA that receives a cryptographically-protected e-mail will render it for the user.¶
The receiving MUA will render the message body, a selected subset of header fields, and (as described in [I-D.dkg-lamps-e2e-mail-guidance]) provide a summary of the cryptographic properties of the message.¶
Most MUAs only render a subset of header fields by default.
For example, few MUAs typically render Message-Id
or Received
header fields for the user, but most do render From
, To
, Cc
, Date
, and Subject
.¶
A MUA that knows how to handle a message with protected headers makes the following two changes to its behavior when rendering a message:¶
- If it detects that an incoming message had protected headers, it renders header fields for the message from the protected headers, ignoring the external (unprotected) headers.¶
- It includes information in the message's cryptographic summary to indicate the types of protection that applied to each rendered header field (if any).¶
A MUA that handles protected headers does not need to render any new header fields that it did not render before.¶
4.1.4.1. Identifying that a Message has Protected Headers
An incoming message can be identified as having protected headers based on one of two signals:¶
- The Cryptographic Payload has
Content-Type: message/rfc822
orContent-Type: message/global
and the parameterforwarded
has a value ofno
. See Section 4.1.4.3 for rendering guidance.¶ - The Cryptographic Payload has some other
Content-Type
and it has parameterprotected-headers
set tov1
. See Section 4.1.4.4 for rendering guidance.¶
Messages of both types exist in the wild, and a sensible MUA should be able to handle them both. They provide the same semantics and the same meaning.¶
4.1.4.2. Updating the Cryptographic Summary
Regardless of whether a cryptographically-protected message has protected headers, the cryptographic summary of the message should be modified to indicate what protections the headers have.¶
Each header individually has exactly one the following protections:¶
-
unprotected
(this is the case for all headers in messages that have no protected headers)¶ -
signed-only
(bound into the same validated signature as the enclosing message, but also visible in transit)¶ -
encrypted-only
(only appears within the cryptographic payload; the corresponding external header was either omitted or obfuscated)¶ -
encrypted-and-signed
(same as encrypted, but additionally is under a validatd signature)¶
Note that while the message itself may be encrypted-and-signed
, some headers may be replicated on the outside of the message (e.g. Date
)
Those headers would be signed-only
, despite the message itself being encrypted-and-signed
.¶
Rendering this information is likely to be complex and messy --- users may not understand it. It is beyond the scope of this document to suggest any specific graphical affordances or user experience. Future work should include examples of successful rendering of this information.¶
4.1.4.3. Rendering a Wrapped Message
When the Cryptographic Payload has Content-Type
of message/rfc822
or message/global
, and the parameter forwarded
is set to no
, the values of the protected headers are drawn from the headers of the Cryptographic Payload, and the body that is rendered is the body of the Cryptographic Payload.¶
4.1.4.3.1. Example Signed-Only Wrapped Message
Consider a message with this structure, where the MUA is able to validate the cryptographic signature:¶
A └─╴application/pkcs7-mime; smime-type="signed-data" ⇩ (unwraps to) B └┬╴message/rfc822 [Cryptographic Payload] C └┬╴multipart/alternative [Rendered Body] D ├─╴text/plain E └─╴text/html¶
The message body should be rendered the same way as this message:¶
C └┬╴multipart/alternative D ├─╴text/plain E └─╴text/html¶
It should render header fields taken from part C
.¶
Its cryptographic summary should indicates that the message was signed and all rendered header fields were included in the signature.¶
The MUA SHOULD ignore header fields from part A
for the purposes of rendering.¶
4.1.4.3.2. Example Encrypted-and-Signed Wrapped Message
Consider a message with this structure, where the MUA is able to validate the cryptographic signature:¶
F └─╴application/pkcs7-mime; smime-type="enveloped-data" ↧ (decrypts to) G └─╴application/pkcs7-mime; smime-type="signed-data" ⇩ (unwraps to) H └┬╴message/rfc822 [Cryptographic Payload] I └┬╴multipart/alternative [Rendered Body] J ├─╴text/plain K └─╴text/html¶
The message body should be rendered the same way as this message:¶
I └┬╴multipart/alternative J ├─╴text/plain K └─╴text/html¶
It should render headers taken from part I
.¶
Its cryptographic summary should indicates that the message was signed and encrypted.
Each rendered header field found in I
should be compared against the header field of the same name from F
.
If the value found in F
matches the value found in I
, the header field should be marked as signed-only
.
If no matching header field was found in F
, or the value found did not match the value from I
, the header field should be marked as signed-and-encrypted
.¶
4.1.4.4. Rendering a Message with Injected Headers
When the Cryptographic Payload does not have a Content-Type
of message/rfc822
or message/global
, and the parameter protected-headers
is set to v1
, the values of the protected headers are drawn from the headers of the Cryptographic Payload, and the body that is rendered is the Cryptographic Payload itself.¶
4.1.4.4.1. Example Signed-only Message with Injected Headers
L └─╴application/pkcs7-mime; smime-type="signed-data" ⇩ (unwraps to) M └┬╴multipart/alternative [Cryptographic Payload + Rendered Body] N ├─╴text/plain O └─╴text/html¶
The message body should be rendered the same way as this message:¶
M └┬╴multipart/alternative N ├─╴text/plain O └─╴text/html¶
It should render header fieldss taken from part M
.¶
Its cryptographic summary should indicates that the message was signed and all rendered header fields were included in the signature.¶
The MUA SHOULD ignore header fields from part L
for the purposes of rendering.¶
4.1.4.4.2. Example Signed-and-Encrypted Message with Injected Headers
Consider a message with this structure, where the MUA is able to validate the cryptographic signature:¶
P └─╴application/pkcs7-mime; smime-type="enveloped-data" ↧ (decrypts to) Q └─╴application/pkcs7-mime; smime-type="signed-data" ⇩ (unwraps to) R └┬╴multipart/alternative [Cryptographic Payload + Rendered Body] S ├─╴text/plain T └─╴text/html¶
The message body should be rendered the same way as this message:¶
R └┬╴multipart/alternative S ├─╴text/plain T └─╴text/html¶
It should render headers taken from part R
.¶
Its cryptographic summary should indicates that the message was signed and encrypted.
As in Section 4.1.4.3.2, each rendered header field found in R
should be compared against the header field of the same name from P
.
If the value found in P
matches the value found in R
, the header field should be marked as signed-only
.
If no matching header field was found in P
, or the value found did not match the value from R
, the header field should be marked as signed-and-encrypted
.¶
4.1.4.4.3. Do Not Render Legacy Display Part
As described [I-D.autocrypt-lamps-protected-headers], a message with cryptographic confidentiality protection MAY include a "Legacy Display" part for backward-compatibility with legacy MUAs¶
The receiving MUA SHOULD avoid rendering the Legacy Display part to the user at all, since it is aware of and can render the actual Protected Headers.¶
If a Legacy Display part is detected, it and its enclosing multipart/mixed
wrapper should be discarded before rendering.¶
4.1.4.4.3.1. Legacy Display Detection Algorithm
A receiving MUA acting on a message SHOULD detect the presence of a Legacy Display part and the corresponding "original body" with the following simple algorithm:¶
- Check that all of the following are true for the message:¶
- The Cryptographic Envelope must contain an encrypting Cryptographic Layer¶
- The Cryptographic Payload must have a
Content-Type
ofmultipart/mixed
¶ - The Cryptographic Payload must have exactly two subparts¶
- The first subpart of the Cryptographic Payload must have a
Content-Type
oftext/plain
ortext/rfc822-headers
¶ - The first subpart of the Cryptographic Payload's
Content-Type
must contain a property ofprotected-headers
, and its value must bev1
.¶ - If all of the above are true, then the first subpart is the Legacy Display part, and the second subpart is the "original body". Otherwise, the message does not have a Legacy Display part.¶
4.1.4.4.3.2. Legacy Display Example
Consider a message with this structure, where the MUA is able to validate the cryptographic signature:¶
U └─╴application/pkcs7-mime; smime-type="enveloped-data" ↧ (decrypts to) V └─╴application/pkcs7-mime; smime-type="signed-data" ⇩ (unwraps to) W └┬╴multipart/mixed [Cryptographic Payload] X ├─╴text/plain [Legacy Display] Y └┬╴multipart/alternative [Rendered Body] Z ├─╴text/plain A' └─╴text/html¶
The message body should be rendered the same way as this message, effectively hiding the Legacy Display part (X
) and its wrapper:¶
Y └┬╴multipart/alternative Z ├─╴text/plain A' └─╴text/html¶
It should render headers taken from part W
, following the same guidance as in Section 4.1.4.4.2 and Section 4.1.4.3.2 about the cryptographic status of each rendered header field.¶
4.1.4.5. Affordances for Debugging and Troubleshooting
Note that advanced users of an MUA may need access to the original message, for example to troubleshoot problems with the MUA itself, or problems with the SMTP transport path taken by the message.¶
A MUA that applies these rendering guidelines SHOULD ensure that the full original source of the message as it was received remains available to such a user for debugging and troubleshooting.¶
4.1.4.6. Composing a Reply to an Encrypted Message with Protected Headers
When composing a reply to an encrypted message with protected headers, the MUA is acting both as a receiving MUA and as a sending MUA. Special guidance applies here, as things can go wrong in at least two ways: leaking previously-confidential information, and replying to the wrong party.¶
4.1.4.6.1. Avoid Leaking Encrypted Headers in Reply
As noted in [I-D.dkg-lamps-e2e-mail-guidance], an MUA in this position MUST NOT leak previously-encrypted content in the clear in a followup message. The same is true for protected headers.¶
Values from any header field that was identified as either encrypted
or signed-and-encrypted
based on the steps outlined above MUST NOT be placed in cleartext output when generating a message.¶
In particular, if Subject
was encrypted, and it is copied into the draft encrypted reply, the replying MUA MUST obfuscate the Subject
field in the cleartext header as described above.¶
[[ TODO: formally describe how a replying MUA should generate a message-specific Header Protection policy based on the cryptographic status of the headers of the incoming message ]]¶
4.1.4.6.2. Avoid Misdirected Replies to Encrypted Messages with Protected Headers
When replying to a message, the Composing MUA typically decides who to send the reply to based on:¶
- the
Reply-To
,Mail-Followup-To
, orFrom
headers¶ - optionally, the other
To
orCc
headers (if the user chose to "reply all")¶
When a message has protected headers, the replying MUA MUST populate the destination fields of the draft message using the protected headers, and ignore any unprotected headers.¶
This mitigates against an attack where Mallory gets a copy of an encrypted message from Alice to Bob, and then replays the message to Bob with an additional Cc
to Mallory's own e-mail address in the message's outer header.¶
If Bob knows Mallory's certificate already, and he replies to such a message without following the guidance in this section, it's likely that his MUA will encrypt the cleartext of the message directly to Mallory.¶
4.1.4.7. Implicitly-rendered Header Fields
While From
and To
and Cc
and Subject
and Date
are often explicitly rendered to the user, some header fields do affect message display, without being explicitly rendered.¶
For example, Message-Id
, References
, and In-Reply-To
header fields may collectively be used to place a message in a "thread" or series of messages.¶
In another example, Section 4.1.4.6.2 observes that the value of the Reply-To
field can influence the draft reply message.
So while the user may never see the Reply-To
header directly, it is implicitly "rendered" when the user interacts with the message by replying to it.¶
An MUA that depends on any implicitly-rendered header field in a message with protected headers SHOULD use the value from the protected header, and SHOULD NOT use any value found outside the cryptographic protection.¶
4.1.4.8. Unprotected Headers Added in Transit
Some headers are legitimately added in transit, and could not have been known to the sender at message composition time.¶
The most common of these headers are Received
and DKIM-Signature
, neither of which are typically rendered, either explicitly or implicitly.¶
If a receiving MUA has specific knowledge about a given header field, including that:¶
- the header field would not have been known to the original sender, and¶
- the header field might be rendered explicitly or implicitly,¶
then the MUA MAY decide to operate on the value of that header field from the unprotected header section, even though the message has protected headers.¶
The MUA MAY prefer to verify that the headers in question have additional transit-derived cryptographic protections (e.g., to test whether they are covered by a valid DKIM-Signature
) before rendering or acting on them.¶
Specific examples appear below.¶
4.1.4.8.1. Mailing list headers: List-* and Archived-At
If the message arrives through a mailing list, the list manager itself may inject headers (most of which start with List-
) in the message:¶
For some MUAs, these headers are implicitly rendered, by providing buttons for actions like "Subscribe", "View Archived Version", "Reply List", "List Info", etc.¶
An MUA that receives a message with protected headers that contains these header fields in the unprotected section, and that has reason to believe the message is coming through a mailing list MAY decide to render them to the user (explicitly or implicitly) even though they are not protected.¶
FIXME: other examples of unprotected transit headers?¶