Subject: [dmarc-ietf] WGLC ARC-16 concern on Section 5.1.2 - cv=fail should sign greedily

From: Seth Blank <[email-masked]>
Date: Wed, 25 Jul 2018 14:34:03 -0700

https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-5.1.2

Originally, even in the event of a chain validation failure, the Sealer's
ARC-Seal would sign all ARC header fields on the message.

When we introduced the concept of cv=invalid last year, the advice was to
only sign your own ARC Set, because there was no deterministic way to know
which header fields to sign when those ARC header fields were not properly
intact (the definition of invalid). We then decided to abandon the
cv=invalid path and only have cv=fail.

Somehow, in the current doc this advice for invalid chains now applies to
all chain failures. Section 5.1.2's title even mentions it is for the
invalid case, but the text as written applies to all failed chains.

Without the ARC Seal covering the ARC header fields in the failing chain,
all the data in the failed chain can be modified as it is not covered under
the latest signature.

The proper guidance should be that the ARC-Seal MUST sign the ARC Chain in
its entirety, unless that is structurally impossible, in which case it
should only sign itself.

I believe the proper text for this section (replacing the first paragraph
for 5.1.2 in its entirety) should be:

   In the event that it is not possible to generate a deterministic list of
previous
   ARC Sets to sign (such as when the chain undergoing validation
   is structurally invalid), the signature scope of the AS header field b=
   value MUST only include the latest ARC Set headers as if this newest ARC
   Set was the only set present.

---

From: "Luis Muñoz" <[email-masked]>
Date: Wed, 25 Jul 2018 14:46:24 -0700

> its entirety, unless that is structurally impossible, in which case it

There should be clear indication in the ARC-Seal about which of the 
branches above were taken.

-lem

---

From: Seth Blank <[email-masked]>
Date: Wed, 25 Jul 2018 14:49:42 -0700

> branches above were taken.

Agreed, and that was the intent of cv=invalid. However the working group
had strong consensus not to go down that path.

This could be another valuable output of the experiment, if the invalid
case does require a separate chain validation status.

---

From: "Murray S. Kucherawy" <[email-masked]>
Date: Fri, 27 Jul 2018 08:24:53 -0700

On Wed, Jul 25, 2018 at 2:34 PM, Seth Blank <[email-masked]> wrote:

>    In the event that it is not possible to generate a deterministic list
> of previous

I think it's weird that the body of content that gets hashed by the sealer
in this case varies from what would normally happen.  A verifier might have
to try two different verification algorithms if, for example, it doesn't
determine that the chain is structurally invalid.

If I receive a chain that was apparently valid at the last sealer and
determine that it is no longer so, could we simply decline to re-seal it at
all?

-MSK

---

From: Seth Blank <[email-masked]>
Date: Fri, 27 Jul 2018 08:35:11 -0700

On Fri, Jul 27, 2018 at 08:24 Murray S. Kucherawy <[email-masked]>
wrote:

>  covering the ARC header fields in the failing chain, all the data in the
>> failed chain can be modified as it is not covered under the latest
>> signature.
>>
>
The verification algorithm is straightforward. If you receive a chain that
ends with cv=fail stop your evaluation, you’re done. There’s no separate
validation path here.

Additionally, I worry about the security implications of passing along a
known bad chain without terminating it. Right now, worst case, one
intermediary needs to evaluate and terminate a maliciously formed chain. If
it’s simply not Sealed, then everyone in the path must perform the
evaluation. I don’t know what new vectors this opens up, but I could
foresee some cascading issues.

---

From: "Murray S. Kucherawy" <[email-masked]>
Date: Fri, 27 Jul 2018 10:21:04 -0700

> ends with cv=fail stop your evaluation, you’re done. There’s no separate

Then why bother signing anything when you affix "cv=fail"?

-MSK

---

From: Seth Blank <[email-masked]>
Date: Fri, 27 Jul 2018 10:29:26 -0700

On Fri, Jul 27, 2018 at 10:21 AM, Murray S. Kucherawy <[email-masked]>
wrote:

>> The verification algorithm is straightforward. If you receive a chain
>> that ends with cv=fail stop your evaluation, you’re done. There’s no
>> separate validation path here.
>>
>

Because adding your ARC Seal over the chain guarantees that the receiver
has a complete list of everyone who modified the message up until the
failure. Without this signature any failures cannot be localized, and any
ARC data in a failed chain could not be trusted. This data is crucial for
analysis, understanding the experiment, and reporting back accurate and
untampered information.

---

From: "Murray S. Kucherawy" <[email-masked]>
Date: Fri, 27 Jul 2018 10:39:21 -0700

On Fri, Jul 27, 2018 at 10:29 AM, Seth Blank <[email-masked]> wrote:

> On Fri, Jul 27, 2018 at 10:21 AM, Murray S. Kucherawy <[email-masked]
> > wrote:
>

But (and I think this proves my point) I don't know if "cv=fail" refers to
an invalid chain or a failed chain.  I have to run the verification to
figure that out.  But you're saying you just stop when you see "cv=fail".

I remain confused.

-MSK

---

From: Seth Blank <[email-masked]>
Date: Fri, 27 Jul 2018 10:54:05 -0700

> figure that out.  But you're saying you just stop when you see "cv=fail".

I don't understand what you're exploring. The algorithm in
https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-5.2 is
clear and the separate paths you're describing don't factor it.

On validation, you grab the highest instanced ARC set (step 1), and then
start a process to set the chain validation status of the inbound ARC Chain.

If the highest instanced ARC Set has cv=fail in it, you're done (step 2).
No cryptographic checks have even been performed at this point, because in
either scenario the chain is dead. If the AS validates and you have
cv=fail, then the chain state is fail. If the AS does not validate, then
the chain state is fail.

Crypto isn't checked until step 3, and we never get there. If you're doing
analysis and want to understand what caused the chain to fail, you're now
outside of validation and outside of matters that affect interoperability.

Or am I still misunderstanding what you're getting at?

---

From: "Murray S. Kucherawy" <[email-masked]>
Date: Fri, 27 Jul 2018 14:25:29 -0700

On Fri, Jul 27, 2018 at 10:54 AM, Seth Blank <[email-masked]> wrote:

> On Fri, Jul 27, 2018 at 10:39 AM, Murray S. Kucherawy <[email-masked]
> > wrote:
>>
>> But (and I think this proves my point) I don't know if "cv=fail" refers
>> to an invalid chain or a failed chain.  I have to run the verification to
>> I remain confused..
> https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-5.2
> is clear and the separate paths you're describing don't factor it.
>

And therefore, if I'm a sealer and I've decided I'm going to mark the chain
failed, why wouldn't I just do "cv=fail" with a bogus or empty signature?
The verifier isn't going to use whatever signature I've put there anyway;
as you point out, the verifier sees "cv=fail" and stops.

And if that's all correct, then I don't understand why we're talking about
what exactly you seal if you're the one attaching "cv=fail", because it's
moot.

-MSK

---

From: Bron Gondwana <[email-masked]>
Date: Sat, 28 Jul 2018 12:39:11 +1000

On Sat, Jul 28, 2018, at 03:29, Seth Blank wrote:
> On Fri, Jul 27, 2018 at 10:21 AM, Murray S. Kucherawy
> <[email-masked]> wrote:>> On Fri, Jul 27, 2018 at 8:35 AM, Seth Blank
>> <[email-masked]> wrote:>> 
>>> The verification algorithm is straightforward. If you receive a
>>> chain that ends with cv=fail stop your evaluation, you’re done.
>>> There’s no separate validation path here.>> 
>> 
> Because adding your ARC Seal over the chain guarantees that the
> receiver has a complete list of everyone who modified the message up
> until the failure.
No, this is wrong.  I have detailed why this is wrong many times.  A
single cv=fail means that there's no proof that the entire previous
chain isn't just a valid set of ARC headers picked up from somewhere
else with the serial numbers filed off and the entire message replaced
with something else.
The only thing your ARC Seal will validate is your own ARC-Authentication-
Results header - which isn't nothing (it could contain the IP address
that you received this message from) - but if SPF / DKIM and ARC are
all fails in your Authentication-Results, any earlier ARC and DKIM
headers have no provable causal relationship with the rest of the
message you received.
Bron.

--
  Bron Gondwana, CEO, FastMail Pty Ltd
  [email-masked]

---

From: Seth Blank <[email-masked]>
Date: Sat, 28 Jul 2018 18:12:23 -0700

On Fri, Jul 27, 2018 at 7:39 PM, Bron Gondwana <[email-masked]>
wrote:

> The only thing your ARC Seal will validate is your own
> ARC-Authentication-Results header - which isn't nothing (it could contain
> the IP address that you received this message from) - but if SPF / DKIM and
> ARC are all fails in your Authentication-Results, any earlier ARC and DKIM
> headers have no provable causal relationship with the rest of the message
> you received.
>

A structurally valid ARC Chain (all ARC Sets have one each of the ARC
header fields, the ARC Sets instance numbers are 1..N inclusive, and each
AS covers all ARC Set header fields on the message 1..its own instance
number) where all AS's validate says a very specific thing about that ARC
Chain: that no one has modified *THE ARC HEADER FIELDS* that are part of
the Chain.

This also means that from the first ARC Set at i=1 through the last passing
ARC Set, you have a guaranteed list of all domains who have modified the
message (yes, some may have Sealed without modifying) and the corresponding
ARC-Authentication-Results each saw, which you know have not been modified
by someone other than the ADMD which added them.

This does not stop someone from taking an intact and passing ARC Chain and
adding their own garbage on top. Fundamentally, this is how mail work; mail
is spooled and replayed all the time by design. This is an issue with DKIM,
and covered in 6376 sections 5.4.1 and 8.6. Since ARC inherits heavily from
DKIM, it also inherits these specific replay issues. It was determined that
fixing the replay issue was out of scope, except for providing guidance on
how to contain impact. Sections 9.4 and 9.5 talk directly to these issues:

https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-9.4

https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-9.5

Frankly, your concern speaks directly to the issue I raised initially. If
cv=fail only signs itself, then there is absolutely no way to localize the
issue and determine which Sealer decided to run amok with the Chain. If you
see a cv=fail, you have to throw out all the data. At least when Sealing
cv=fail, if you Seal greedily, there is in intact chain of Seals which can
be used to make important determinations as to the veracity of the header
field data and may be able to use that to determine where things may have
fallen apart or been replayed.

---

From: Bron Gondwana <[email-masked]>
Date: Mon, 30 Jul 2018 08:59:49 +1000

On Sun, Jul 29, 2018, at 11:12, Seth Blank wrote:
> On Fri, Jul 27, 2018 at 7:39 PM, Bron Gondwana
> <[email-masked]> wrote:>> __
>> 
>> message you received.>> 
> header fields, the ARC Sets instance numbers are 1..N inclusive, and
> each AS covers all ARC Set header fields on the message 1..its own
> instance number) where all AS's validate says a very specific thing
> about that ARC Chain: that no one has modified *THE ARC HEADER FIELDS*
> that are part of the Chain.> 
> This also means that from the first ARC Set at i=1 through the last
> passing ARC Set, you have a guaranteed list of all domains who have
> modified the message (yes, some may have Sealed without modifying)
> and the corresponding ARC-Authentication-Results each saw, which you
> know have not been modified by someone other than the ADMD which
> added them.
Modified "a message", sure.  You have proof that a message
followed that path
> This does not stop someone from taking an intact and passing ARC Chain
> and adding their own garbage on top. Fundamentally, this is how mail
> work; mail is spooled and replayed all the time by design. This is an
> issue with DKIM, and covered in 6376 sections 5.4.1 and 8.6. Since ARC
> inherits heavily from DKIM, it also inherits these specific replay
> issues. It was determined that fixing the replay issue was out of
> scope, except for providing guidance on how to contain impact.
> Sections 9.4 and 9.5 talk directly to these issues:> 
> https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-9.4> 
> https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-9..5[1]> 
> Frankly, your concern speaks directly to the issue I raised initially.
> If cv=fail only signs itself, then there is absolutely no way to
> localize the issue and determine which Sealer decided to run amok with
> the Chain. If you see a cv=fail, you have to throw out all the data.
> At least when Sealing cv=fail, if you Seal greedily, there is in
> intact chain of Seals which can be used to make important
> determinations as to the veracity of the header field data and may be
> able to use that to determine where things may have fallen apart or
> been replayed.
I'm not sure what you mean by "the veracity of the header field data".
Can you give an example of a cv=fail where there's useful information
still trustworthy in the message, because I don't see it.  To use the
"chain of custody" analogy, if you have a bag of evidence and it's been
unsupervised in the hands of an unknown party, the contents have no
evidentiary value any more.
There's two types of fail - fail on AMS, which could just be a
modification by somebody, and a fail on an AS, which means there's
definitely either buggy software or somebody screwing with the chain.
But even a single AMS fail means that an unknown intermediary could have
changed every single header that's covered by the AMS.  There's no way
to know what they changed.  Ditto the body.  It could be a totally
different message and there's no way to know because the chain of
evidence is broken.
So again - all that you can know when you see a broken AMS is that
somebody got their hands on a message which had followed the
existing chain.
Bron.

Links:

  1. https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-16#section-9.5

---

From: Seth Blank <[email-masked]>
Date: Mon, 30 Jul 2018 11:10:14 -0700

On Sun, Jul 29, 2018 at 3:59 PM, Bron Gondwana <[email-masked]>
wrote:
> Can you give an example of a cv=fail where there's useful information still
> trustworthy in the message, because I don't see it.  To use the "chain of
> custody" analogy, if you have a bag of evidence and it's been unsupervised
> in the hands of an unknown party, the contents have no evidentiary value
> any more.
>
> changed every single header that's covered by the AMS.  There's no way to
> know what they changed.  Ditto the body.  It could be a totally different
> message and there's no way to know because the chain of evidence is broken.
>
> somebody got their hands on a message which had followed the existing chain.
>

There are two premises to keep in mind:

1) For the first chunk of ARC's life, there will be a significant amount of
ARC breakage due to intermediaries who do not properly or yet implement
ARC. Some of the data ARC collects may in isolating these intermediaries
and helping them properly adopt ARC.

2) we don't know what data is valuable yet, and would rather collect extra
data than throw out potentially useful data (Section 11.3.3)

Given these, it is worthwhile to capture the chain information even in
failing states (i.e. cv=fail should sign greedily), especially when you
consider the three major failure scenarios:

1) A good actor improperly Sealing

ALL the data in the Chain is valuable, including the breakage, because it
isolates the issue and allows that improper Sealer to get feedback and fix
their systems. Realistically, there will be a lot of work done here, as
intermediaries deploying ARC for the first time may get it wrong.

2) A good actor not Sealing

Again, ALL the data in the Chain is valuable, as it would isolate where the
breaking intermediary is and allow outreach. This will probably be the most
prevalent ARC failure we see in the wild in the near term - mailing lists
that do not yet Seal.

3) A bad actor modifying the chain

Sure, the Chain is garbage. But if all the AS's validate, then the bad
actor's been forced down two paths: either a) they are forced to extend or
replay a valid chain, or b) they must create a garbage chain using only
domains they have DNS control over. If the AS's don't need to validate,
then there are numerous malicious paths an attacker can take to modify the
chain in subtle ways.

---

From: Seth Blank <[email-masked]>
Date: Mon, 30 Jul 2018 13:47:53 -0700

I've been thinking about this and discussing offline, so to put it
differently:

5.1.2 says when a chain fails, to put cv=fail in the AS and only Seal the
ARC Set being added.

Per the original message and suggested text, I believe 5.1.2 should only
provide the above guidance when it is not otherwise possible to sign the
entire ARC Chain (i.e. when the Chain is structurally invalid and a
deterministic set of headers cannot be enumerated).

Regardless of this behavior, the Chain is still equally dead. But in one
scenario (initial ARC Chain not Sealed) you get no data from that dead
chain, and in the other (failing Set Seals initial Chain) you can.

Might it be clearer to make my recommended change and also put something in
5.1.2 saying that the cv=fail Seal is just for trace purposes since the
chain can never validate per 5.2?

---

From: "John Levine" <[email-masked]>
Date: 30 Jul 2018 18:17:25 -0400

>deterministic set of headers cannot be enumerated).

I still have a question: if you have the right set of older headers,
you could sign them even if they're corrupted and the signatures are
invalid.  But if the old sets have extra or missing headers, you can
only sign your own set.

I think it's fine to sign and hope for the best, but how is a
validator supposed to tell the difference?  Perhaps we need something
like cv=restart.

R's,
John

---

From: Seth Blank <[email-masked]>
Date: Mon, 30 Jul 2018 17:20:11 -0700

> validator supposed to tell the difference?  Perhaps we need something

So that's where this specific thread started if you roll back to the very
first message.

The working group considered cv=invalid last year, but there was strong
consensus was against it. The guidance for Sealing cv=invalid Chains
somehow made it into this draft applied to all cv=fail Chains. All Chains
should be Sealed in the same fashion (your AS covers the ARC Set you've
added and all previous ARC Sets), unless the Chain is invalid in which case
you only Seal your own ARC Set.

We could add a comment about cv=invalid into Experimental Considerations.
If not being able to tell the cases apart creates issues, it can absolutely
be added once we are considering the standardization of ARC.

---

From: "John R Levine" <[email-masked]>
Date: 30 Jul 2018 20:41:54 -0400

> you only Seal your own ARC Set.

Ah.  Perhaps reword 5.1.1 like this:

The signature of an AS header field signs a specific canonicalized
form of the ARC Set header values, when all of the previous ARC sets
are valid. In that case, the ARC set header values are supplied to the
hash function in increasing instance order, starting at 1, and include
the ARC Set being added at the time of Sealing the message.  If any of
the existing sets are invalid, the AS header field only signs its own
ARC Set.

Within an ARC Set, header fields are supplied to the hash function in the following order:

1. ARC-Authentication-Results
2. ARC-Message-Signature
3. ARC-Seal

The ARC-Seal is generated in a manner similar to when DKIM-Signatures
are added to messages ([RFC6376], section 3.7).

In 5.1.2:

In the case of a failed Authenticated Received Chain, the header
fields included in the signature scope of the AS header field b= value
MUST only include the ARC Set headers in the newly created set, as if
this newest ARC Set was the only set present.

In 5.2, oldest pass is confusing, since it doesn't tell you whether
the validation succeeds or not.  I would take out steps 5-7 and add
something to the INFORMATIONAL at the end like "A validator can check
the AMS headers to estimate when in a chain of forwards the message
was modified."

Regards,
John Levine, [email-masked], Taughannock Networks, Trumansburg NY
Please consider the environment before reading this e-mail. https://jl.ly