Subject: [dmarc-ietf] ARC cv=invalid

From: Gene Shuman <[email-masked]>
Date: Mon, 19 Jun 2017 15:51:57 -0700

Starting a new thread, as this is probably *the* major blocker wrt OpenARC.
The last thread basicaly was questioining the need for the cv=invalid
status entirely.  The major question being, with an invalid/mangled chain,
how are we supossed to compute a b= value for the ARC-Seal?  If we do in
fact maintain the cv=invalid state, we can create a local AMS, but we can
no longer enforce a mandatory b= in the AS.  The other alternative is just
to stamp arc=invalid in the the AR & be done with it.  It is very much
important to figure this out.  In the former case we would need to say that
AS b= is undefined when cv=invalid, which wouldn't be that big of a deal
afaik.  In the later case, we could simply abort processing of messages,
and put the status in AR.  It's unclear to me which is preferable.

Another question, which is related, but independent to the former, is what
*precisely* constitutes an invalid chain vs a failing one.  I had
previously been working on the assumption that invalid was a property
strictly relate to the i= tag & the chain itself.  ie. duplicate i= tags,
missing i= tags, missing AMS, AS, AAR headers, etc.  But there are a large
class of errors that I had previously been considering failures which could
possibly be considered invalid results.  For instance, the s= tag is
strictly required.  When verifying an inbound message with a missing s=
tag, is cv=fail, or invalid?  dkimpy & the test suite(and google's arc
implementation?) all consider this a fail, while OpenARC currently
considers this to be invalid.  What is correct here?  I suggest failure,
this way we can limit invalid *strictly* to mangled sets/i= tags etc.
Basically circumstances in which it is strictly impossible to generate an
AS b= value consistiently.

=Gene

---

From: "Kurt Andersen (b)" <[email-masked]>
Date: Tue, 20 Jun 2017 11:35:18 -0700

On Mon, Jun 19, 2017 at 3:51 PM, Gene Shuman <[email-masked]> wrote:

> Starting a new thread, as this is probably *the* major blocker wrt
> OpenARC. . .
>

Taking your two questions in reversed order:

. . .what *precisely* constitutes an invalid chain vs a failing one?  I had
> missing i= tags, missing AMS, AS, AAR headers, etc.

This is what we intended when writing the spec and with some of the initial
implementations. "invalid" is a description of a chain which does not have
all of the right pieces ("structural integrity" is the term used in
5.1.1.5). "fail" is what happens when something else is broken (can't or
doesn't validate - no "s" tag for instance).

> with an invalid/mangled chain, how are we suposed to compute a b= value
> for the ARC-Seal?
>

Thinking back to the conversations when the spec was being initially
developed, I don't know that we touched on this specific scenario, but I
think that the most consistent approach with the rest of the spec would be
to have the spec call out a specific "implicit h=" handling for this
situation. I'd suggest the following approach for creating an ARC set in an
invalid situation: set i = one more than the highest i value found in the
(mangled) ARC fragments or 51 (based on the "Maximum 'i' Tag Value). Use
only the ARC headers for this set in the implicit 'h' since those will be
entirely under the control of the signing system. For the AMS, nothing
special should be required.

How does that sound?

--Kurt

---

From: Brandon Long <[email-masked]>
Date: Tue, 20 Jun 2017 13:18:24 -0700

On Mon, Jun 19, 2017 at 3:51 PM, Gene Shuman <[email-masked]> wrote:

> OpenARC. The last thread basicaly was questioining the need for the
> cv=invalid status entirely.  The major question being, with an
> invalid/mangled chain, how are we supossed to compute a b= value for the
> ARC-Seal?  If we do in fact maintain the cv=invalid state, we can create a
> local AMS, but we can no longer enforce a mandatory b= in the AS.  The
> other alternative is just to stamp arc=invalid in the the AR & be done with
> it.  It is very much important to figure this out.  In the former case we
> would need to say that AS b= is undefined when cv=invalid, which wouldn't
> be that big of a deal afaik.  In the later case, we could simply abort
> processing of messages, and put the status in AR.  It's unclear to me which
> is preferable.
>

The google implementation pre-dates cv=invalid, and when I went to
implement it, I couldn't find a good reason to do so, nor a great
bright-line rule for how to differentiate the two.

I don't see the point of trying to continue the chain after a cv=fail, so
having a mechanism to do so, and the possibly complicated rules associated
with it, seem pointless.

The alternative would be to strip the arc-set entirely and start fresh.
That seems to have minor benefit, so I didn't implement that, either, but I
could imagine doing that if some useful case came up.  This is also
strictly more useful than trying to persist an invalid chain.  I could see
a cv=restart as an equivalent to cv=none for this type of case, I guess.

Brandon

---

From: Seth Blank <[email-masked]>
Date: Tue, 20 Jun 2017 13:44:27 -0700

> having a mechanism to do so, and the possibly complicated rules associated

Are you suggesting that we remove cv=invalid and leave everything under
cv=fail, because that's all that matters to transmit downstream via the AS?

And then, if someone wants to really make it clear what happened, that
could be stamped in an A-R header like "arc=fail (invalid ARC set at i=3:
too many headers)"? Or do you think at this juncture, in the A-R
"arc=invalid" makes sense like "arc=invalid (missing AS for i=2)" to
differentiate ARC set failures from all other failures?

> a cv=restart as an equivalent to cv=none for this type of case, I guess.

I think "restarting" an ARC chain makes no sense. If the chain breaks, it's
broken. Custody's been lost and you don't get to show up with a new message.

---

From: Gene Shuman <[email-masked]>
Date: Tue, 20 Jun 2017 14:17:05 -0700

Yeah, we certainly shouldn't be restarting the chain, and I (& I think most
everyone else) concur that when it's invalid, the end. However I also don't
think we should be keeping everything as fail, as invalid is pretty
sematically different.  And there is a clear line.  cv=invalid if and only
if you can't reliably produce an AS b= value, given the current rules.  I
think I very much agree with Kurt on wrt this line.

Also, I don't think we should be relying on the contents of AR header
fields to make determinations about ARC chains.  It seems off to me to have
to parse all AR headers to look for an arc=invalid or whatever to decide
how to handle your ARC messages.  But I possibly could be convinced
otherwise.

This leaves us with the option of sticking cv=invalid in the AS, and still
the open question of if and how to generate the AS b= tag.  Kurt's
suggestion seems totally fine, although slightly awkward.  Not sure I have
any better ideas though.  What is the value of creating this signature, as
opposed to just not & relying solely on our AMS?  I guess we are signing
our new AAR then, which is worth something?

=Gene

On Tue, Jun 20, 2017 at 1:44 PM, Seth Blank <[email-masked]> wrote:

> I think "restarting" an ARC chain makes no sense. If the chain breaks,
> it's broken. Custody's been lost and you don't get to show up with a new
> message.
>
>
> _______________________________________________
> dmarc mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/dmarc
>
>

---

From: Seth Blank <[email-masked]>
Date: Tue, 20 Jun 2017 14:37:45 -0700

On Tue, Jun 20, 2017 at 2:17 PM, Gene Shuman <[email-masked]> wrote:

> Yeah, we certainly shouldn't be restarting the chain, and I (& I think
> most everyone else) concur that when it's invalid, the end. However I also
> don't think we should be keeping everything as fail, as invalid is pretty

I guess my question is, if the AS state is cv=fail vs cv=invalid, does the
difference between these two statuses make any meaningful difference for a
receiver to make a final delivery decision around a dmarc
reject|quarantine? Brandon?

Or is it useful later, when processing logs, to determine ARC signers who
are signing improperly?

If yes, then they should absolutely stay distinct states.

Otherwise, maybe it's just trace information? And if so, that was the
reason for the AAR, so it seems to me that's where the distinction is best
catalogued.

To be very clear: I'm thinking out loud here, I do not have a strong
opinion one way or the other, and am very curious what the group thinks.

> how to handle your ARC messages.  But I possibly could be convinced

Oh, I agree. That's my point. From my vantage point (which could be wrong),
if an invalid state does not offer any additional help to a receiver than a
fail, then an AAR would never need to be parsed in-flight.

However, this is a very good point and I'm sympathetic. If pulling ARC
signatories who produce an invalid result end up being crucial, it's most
likely way easier to do this from the AS cv= than from the AARs.

> our new AAR then, which is worth something?

I also don't have any better ideas.

>>> I don't see the point of trying to continue the chain after a cv=fail,
>>> so having a mechanism to do so, and the possibly complicated rules
>>> associated with it, seem pointless.
>>>
>>

-- 

Bringing Trust to Email

Seth Blank | Head of Product for Open Source and Protocols
[email-masked]
+1-415-894-2724 <415-894-2724>

---

From: "Kurt Andersen (b)" <[email-masked]>
Date: Tue, 20 Jun 2017 19:08:00 -0700

On Tue, Jun 20, 2017 at 2:17 PM, Gene Shuman <[email-masked]> replied:

> how to handle your ARC messages.
>

I agree with Seth that putting this info into the AAR headers is not the
right approach.

> our new AAR then, which is worth something?

Yes, you are signing your AAR and AMS (much like the i=1 ARC signer is
doing) attesting to the state of the message when you handled it. You can't
really say anything about previous handlers except that any traces of their
work has been thoroughly trashed.

--Kurt

---

From: Gene Shuman <[email-masked]>
Date: Wed, 21 Jun 2017 13:53:14 -0700

OK, so we've spoken with Brandon a bit about this in person, and we're
still a bit unclear about the resolution of this issue.

It seems we have two choices available to us upon receipt of an invalid
chain(which is defined as AS b= unable to be computed).

1. Simply stop adding further ARC headers.  Put arc=fail(or invalid) in the
AR.  Further recipients will detect that the chain is broken as well, for
the same reasons.  This is clearly the easiest solution.

2. Add one further ARC-Set with an explicit cv=invalid in order to 'close'
the chain, using the rule that Kurt has suggested.  This seems to have some
benefit to me, but it's minimal.  It seems to wrap things up nicely, and it
means that all ARC chains have a well defined cv value, which makes testing
a little easier.  However the cost is clearly added complexity, both in the
spec and implementations.  Is there any other tangible value to adding this
final ARC-Set?  Does it help identify the failure point in the chain?  Is
there any other benefit?  Kurt, can you speak to this?

=Gene

On Tue, Jun 20, 2017 at 7:08 PM, Kurt Andersen (b) <[email-masked]> wrote:

>> This leaves us with the option of sticking cv=invalid in the AS, and
>> still the open question of if and how to generate the AS b= tag.  Kurt's

---

From: "Kurt Andersen (b)" <[email-masked]>
Date: Wed, 21 Jun 2017 14:05:11 -0700

On Wed, Jun 21, 2017 at 1:53 PM, Gene Shuman <[email-masked]> wrote:

> 1. Simply stop adding further ARC headers.  Put arc=fail(or invalid) in
> the AR.  Further recipients will detect that the chain is broken as well,
> for the same reasons.  This is clearly the easiest solution.
>

If you put arc=fail in an AR and then the next hop ignores and strips the
AR (per spec), what good is it?

> there any other benefit?  Kurt, can you speak to this?

A terminal ARC-set with cv=invalid is the only way to "close" a chain and
avoid reprocessing by each and every subsequent hop as far as I can see.

--Kurt

---

From: Brandon Long <[email-masked]>
Date: Wed, 21 Jun 2017 16:18:00 -0700

> AR (per spec), what good is it?

None, but what good is the broken chain?  If all you're doing is avoiding
reprocessing, that seems pretty minimal.

> avoid reprocessing by each and every subsequent hop as far as I can see.

Note that we don't have a temp fail, so cv=fail could just be due to DNS
being unavailable, so the next hop may actually be able to validate the
chain, assuming the failing hop was a non-modifying hop.

Would you expect the next hop to also had a cv=fail arc header that only
signs itself?

I'm just fundamentally unclear what the utility of passing the fail state
forward is.

I understand the conceptual difference between cv=invalid and cv=fail, but
I feel that's going to be heavily implementation specific unless we have
very explicit rules to look for that are in the spec.  Ie, our arc impl has
on the order of 20 failure codes which are used to populate different error
messages in the comment of the authres header, similar to our dkim impl.  I
can certainly go through the list and decide which ones are invalid vs
fail, but someone else could make a different list.  Our signer also has a
handful of "these things must be right to sign this", but it generally
assumes a valid chain, having a comprehensive view of of possibly invalid
chains seems challenging.

That said, there are plenty of cv=fail which have nothing to do with the
chain structure, and could be dns or ams signature failures or whatever.

That said, part of me goes back to the dkim mantra, a broken signature
tells you nothing.  A broken chain tells you nothing.

Brandon

---

From: Seth Blank <[email-masked]>
Date: Wed, 21 Jun 2017 18:19:27 -0700

> reprocessing, that seems pretty minimal.

A final evaluation status has merit, but it's not avoiding reprocessing,
it's transmitting and signing your name to a definitive position that the
chain is dead as you saw it.

An ARC chain is a chain of custody, and if custody is lost, that status
shouldn't be a hot potato - it should be committed to the chain. And then
per the logic in the spec, no one else touches the chain after the chain is
declared dead.

> chain, assuming the failing hop was a non-modifying hop.

This doesn't scan for several reasons:
1) if you stamp cv=fail, the next hop cannot validate the chain, as per
spec it would see cv=fail and stop
2) even if it were within spec, if I stamp fail but modify the message, the
chain is now unrecoverable
3) if cv=fail is NOT stamped, and I go about my business, then the next hop
will try to recover the chain (and maybe it will recover from a tempfail),
but the chain will likely still not validate because the AMS will not
validate because I've most likely modified the message in a breaking manner

I think Kurt's original point stands. cv=invalid is the only way to
terminate a chain with a broken arc set.

Seth