Subject: [Uta] draft-ietf-uta-mta-sts-07 STS policy removal.

From: Viktor Dukhovni <[email-masked]>
Date: Mon, 7 Aug 2017 21:55:20 +0000

I've tried to explain a number of times that policy in STS is
problematic.  This is another attempt.  First what I believe
to be the requirements:

1.  We need to provide a means for a domain to transition
    from having an STS policy to not having an STS policy.

2.  The transition process should not look like failure to
    obtain the policy, generating warnings in the logs that
    don't look different from an active attack.

3.  It should be possible to remove policy in a timely manner.

We have two signalling methods understood by STS-capable clients:

A.  The DNS TXT record which triggers a policy refresh when
    different from the previously observed value.

B.  The STS policy obtained via WebPKI-authenticated HTTPS.

Based on the requirements, it should be possible to construct a
combination of the TXT record and STS policy that have the
following semantics:

I.  The STS policy causes clients to flush the existing cached
    entry, thereby enabling "clean" timely policy removal.  Clients
    that do policy refresh in the background may still send a few
    messages based on previously cached policy, but should have
    current policy by the time any deferred messages are retried.

II. The requisite TXT record will cause a refresh of existing
    cached policies, but will avoid new policy requests if the
    client does not yet have a cached policy for the destination
    domain.  This avoids a state in which clients constantly look
    for a new policy after removing the current policy.

To this end I propose the following design refinement.

a.  In the STS policy a value of 0 for max_age signals policy
    removal.

b.  In the STS DNS TXT record, an empty "id" value implies that no
    new policy is expected.  Just as with other changes in the id
    value an empty id must also trigger refresh of cached policies,
    but must not trigger attempts to load new policies.

The process for clean policy removal is then:

    i.   Publish a new policy with max_age=0, check that all HTTPS
	 servers have the new policy.
    ii.  Publish an empty value for the id in the TXT record.
    iii. After the expiration of all previous policies (time
	 of publication + non-zero "max_age"), delete the
	 empty id TXT record.

The client state is then one of the following:

    1.  No policy in the cache

	When seeing empty id TXT do nothing, just as with NXDOMAIN
	or NODATA

    2.  A policy in the cache with max_age=0 and an expiration
        time derived from the DNS TTL of the non-empty id TXT
	record that was observed at the time of policy refresh.

	Such policies do not enforce TLS or send reports.

	When seeing empty id TXT, NXDOMAIN or NODATA, flush such
	a cached policy.

	If instead (before an empty or non-existent TXT record is
	seen) a new policy appears with max_age > 0, cache that.

    3.  A policy in the cache with max_age > 0 and non-empty TXT id.

	Enforce TLS and/or send reports.

	If a new policy with max_age=0 is seen along with a non
	empty id in the TXT, cache that for the DNS TTL of the TXT
	record.

	When an empty TXT id is seen fetch the new policy, it will
	typically have max_age=0, but otherwise is treated just as
	any other policy.

    4.  A policy in the cache with max_age > 0, and an empty TXT id.

	Treat as any other policy until a refresh results in max_age=0.
	At that time, if the TXT is empty or missing flush the policy
	without further caching.

The basic idea is that an empty TXT tells existing caches to update,
but does not elicit fresh cache entries.  While a cache entry with
"max_age=0", waits for the TXT record to become empty or deleted,
so as to avoid policy refresh on every delivery while the TXT id
remains non-empty.  The expiration time of the "max_age=0" cache
entry is based on the DNS TTL of the observed non-empty TXT id.

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Tue, 8 Aug 2017 08:58:03 -0400

Hi, Viktor,

Thanks for the thorough writeup. A question about the "requirements" stated:

> 3.  It should be possible to remove policy in a timely manner.

What do you mean by "remove" and "not having" a policy? What specific
behavior do you want from senders?

E.g. senders will stop

a) performing any kind of certificate validation checks per the policy?
b) making reports based on those checks?
c) any change in delivery behavior based on those checks?
d) maintaining a policy cache entry for the recipient domain?

The reason I ask is that some of these are achievable today, and some of
them are achievable with more minimal modifications than the flow you
describe.

Thanks.

On Mon, Aug 7, 2017 at 5:55 PM, Viktor Dukhovni <[email-masked]>
wrote:

> _______________________________________________
> Uta mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/uta
>

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 8 Aug 2017 17:30:18 +0300

> d) maintaining a policy cache entry for the recipient domain?

The way I understand the request, it is full clear of policy, that is:

- The existing policy is (immediately) invalidated.
- The policy cache entry for the recipient is deleted.

And since there is no policy anymore:

- All certificate validation per the policy ceases.
- All reporting per the policy ceases.
- There is no difference in delivery behavior (for future deliveries)
  from STS policy having never existed.

This is similar behavior with what happens with HSTS if valid HSTS
header with max-age=0 is ever received: The HSTS policy is instantly
deleted and the name reverts to non-HSTS operation (http:// connections
work and certificate errors can be clicked through).

-Ilari

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 8 Aug 2017 18:11:54 +0300

> On Tue, Aug 08, 2017 at 08:58:03AM -0400, Daniel Margolis wrote:

Also, reading the specification, there looks to be some issues with
the use of PKIX:

1) CN-IDs have long been deprecated. RFC 6125 is pretty clear that:

- If SAN contains any recoginized identifier type (which here does
  include DNS-ID), then CN-ID MUST be ignored. So union is just wrong.
- CN-ID is for backward compatiblity only, which does not apply here,
  since the specification is new -> CN-ID is not to be used at all.

2) Does mx pattern '.example.net' match host 'example.net'? The text
is not explicitly say if it does or does not (the example code in
appendix does not seem to consider those two to match).

3) The wildcards in PKIX are not recursive. Thus, certificate with only
SAN '*.example.net' can not match 'foo.bar.example.net'. Yet, tracing
the code in appendix, it appears that the code considers this to match.

-Ilari

---

From: Viktor Dukhovni <[email-masked]>
Date: Tue, 8 Aug 2017 17:20:02 +0000

> work and certificate errors can be clicked through).

Correct.  Full removal of any prior evidence of SMTP STS Policy, but
because SMTP STS has both a DNS TXT record and a policy obtained via
HTTPS, the process of policy removal involves more steps on both sides.

For example, policy removal should not result in an intermediate
state where the client is constantly refetching the max_age=0 STS
policy (because the TXT record is still visible, but the cache
has been flushed).

I had considered using NXDOMAIN/NODATA, instead of an empty id, to
signal policy removal (provided the other end returns max_age =
0), but this leads to a problem, because some DNS libraries (e.g.
libresolv) make it difficult to obtain the TTL of a negative reply.
With no TTL for NXDOMAIN/NODATA it is not clear how often one should
attempt to poll for "max_age = 0", and with TXT record removed, it
can no longer trigger early refresh. 

-- 
	Viktor.

[ It is unfortunate that DNS NXDOMAIN/NODATA is often considered a
  lookup error, whereas it is actually a lookup success, that yields
  an empty result.  DNS APIs should expose negative TTLs, but not
  all do. ]

---

From: Daniel Margolis <[email-masked]>
Date: Tue, 8 Aug 2017 11:47:01 -0700

Thanks for the comments. Inline:

>   since the specification is new -> CN-ID is not to be used at all.

I had thought I had specified to use only SAN if present, but apparently I
didn't. Nonetheless, I thought it made sense to allow matching by CN-ID if
no SAN is present. While this is a new specification, the certificates may
be pre-existing.

So you're definitely right on ignoring CN-ID if SAN is present, but I would
err on the side of falling back to CN-ID. Does it make sense?

> appendix does not seem to consider those two to match).

Thanks. I filed issues on the github for this and the below.

---

From: Daniel Margolis <[email-masked]>
Date: Tue, 8 Aug 2017 12:08:05 -0700

The reason I asked this question is, as I said, we can achieve some of the
desired properties with less complexity. I'd like to break down the various
implementation options and which of the "removal" properties they retain so
we can make sure we choose the simplest option that satisfies the
requirements (or understand what the extra complexity buys us).

So forgive me for fleshing out slightly more, but I believe "removal" is
comprised of roughly the following behaviors:

A. MX/certificate changes don't affect mail delivery
B. MX/certificate changes don't affect TLSRPT reporting (since a domain may
wish to continue to use TLSRPT but stop using MTA-STS)
C. Any resource impact on *senders to this domain* from doing MTA-STS
validation is eliminated
D. It is safe to remove the policy and TXT record

(D), I believe, is invariant in all implementations: any hypothetical
"removal" flow *will* involve serving the "removal" signal (whatever it
is--a max_age=0 policy or anything else) until the last point in time the
*old* policy was served + that policy's max_age. So (D) does not
distinguish between different "removal" options.

*Currently: *By setting "mode=report", you can achieve (A), but not (B).

*Under the "max_age=0" proposal: *You can achieve (A), (B), and (C).

*Alternatively: *If we had a "mode=none", you would achieve (A) and (B) but
*not* (C), since senders would cache the "mode=none" policy until max_age
has passed).

I believe "mode=none" is simpler to implement and reason about, since it
doesn't change the policy caching logic; it *only* changes the actual
reporting and enforcing behavior. (Conversely, the "max_age=0" proposal may
be simpler when viewed as changes only to the process that fetches and
caches policies, since it does not involve any changes to policy use; that
process simply purges the cached policy and calls it a day.)

I also believe property (C) is unimportant, since senders who implement
MTA-STS must be resilient (in the resource usage sense) to recipients who
have live policies; they can't in any way depend on the recipient revoking
a policy to keep the cost of policy validation or caching down.

*Questions:*

Is  the "mode=none" proposal simpler or more complex than "max_age=0"?

Is property (C) important?

*tl;dr:*

I'm good with policy removal, but "mode=none" seems a bit simpler to me
(both in implementation and reasoning about its properties). Thoughts?

---

From: Viktor Dukhovni <[email-masked]>
Date: Tue, 8 Aug 2017 21:06:32 +0000

> distinguish between different "removal" options.

It must be possible to phase out the STS policy and decommission
the associated HTTPS service.

So, it I think that it is D that I'm trying describe, and specifically
looking for D to happen "cleanly", that is, removal happens without
policy refresh failures that look like an active attack.

> *Currently: *By setting "mode=report", you can achieve (A), but not (B).

Not the subject of this thread.

> *Under the "max_age=0" proposal: *You can achieve (A), (B), and (C).

The *combination* of max_age=0 *and* empty TXT id, makes it possible
to cleanly transition from STS to no STS with no DNS TXT record
and no HTTPS policy object.

> *not* (C), since senders would cache the "mode=none" policy until max_age

mode=none still requires period refresh via HTTPS.  So it fails the
requirement to be able to erase all trace of STS.

> a policy to keep the cost of policy validation or caching down.

Once again the goal is to give the domain that publishes the policy a
clean way out.

> Is  the "mode=none" proposal simpler or more complex than "max_age=0"?

It fails to address how to actually *remove* all STS policy.
The domain owner should be able to discontinue the underlying
HTTPS service, and periodic policy updates from senders.

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Tue, 8 Aug 2017 15:24:45 -0700

Just for the sake of below discussion, I'm going to pretend there are three
options on the table:

1. mode=report (as I said, this achieves A but not B)
2. mode=none (this doesn't exist, but you can imagine what it would look
like)
3. max_age=0 (this is my shorthand for the previous proposal Viktor
described, i.e. max_age=0 and an empty TXT ID)

With that said, comments inline:

> policy refresh failures that look like an active attack.

Sorry, I might have been unclear here, but I agree that you want to achieve
(D). My point was that all three options have the exact same properties
with respect to (D).

In all three cases, you have to serve some "I'm opting out policy"--in
option 1, this is a policy with "mode=report", in option 2 this is a policy
with "mode=none", in option 3 this is a policy with "max_age=0"--for the
same amount of time (i.e. preceding policies' last-serve-time + their
max_age).

So, you want (D), but the behavior with respect to (D) is unchanged in all
three options, thus it doesn't help us distinguish between options.

> requirement to be able to erase all trace of STS.

How do you mean? You have to continue to serve this policy until all other
previously served policies have expired; past that point you can turn it
down at will.

> HTTPS service, and periodic policy updates from senders.

Let me explain the process to remove all STS policy under a "mode=none"
scenario:

Suppose at time *t0* I have a normal (e.g. mode=enforce) policy with a
max_age of *m*.

Step 1: publish a policy with mode=none, and change the TXT record -- this
happens at *t1*
Step 2: wait until time *t1 + m*
Step 3: remove the mode=none policy and TXT record

In comparison, the process with the "max_age=0" scenario, as I understand
it:

Step 1: publish a policy with max_age=0, and change the TXT record
Step 2: wait until *t1 + m*
Step 3: remove the max_age=0 policy and TXT record

So in fact property (D) is the same in both cases, is it not?

---

From: Peter Gutmann <[email-masked]>
Date: Wed, 9 Aug 2017 05:11:35 +0000

Ilari Liusvaara <[email-masked]> writes:

>1) CN-IDs have long been deprecated. 

Right, but everyone uses the CN for the primary ID anyway, that's pretty much
the universal usage for it.  Deprecating this universal usage is an example of
what someone on the PKIX list once called "workgroup posturing" (it wasn't me,
even if it sounds like the sort of thing I'd say :-).

>Thus, certificate with only SAN '*.example.net' can not match
>'foo.bar.example.net'. Yet, tracing the code in appendix, it appears that the
>code considers this to match.

The pseudocode and long-form descriptions don't match up in a number of
locations.  In fact the 2459 pseudocode, the 3280 pseudocode, and the text all
disagree with each other (I haven't checked whether it's changed again in
5280), so depending on which you use as your reference you can get different
results for path validation.  Or think of it as a great deal of flexibility in
what you can call a compliant implementation.

I've always taken the text as being definitive.  Or at least I produced my own
pseudocode, leading to the inevitable reference to https://xkcd.com/927.

Peter.

---

From: Viktor Dukhovni <[email-masked]>
Date: Wed, 9 Aug 2017 01:20:54 -0400

> On Aug 8, 2017, at 6:24 PM, Daniel Margolis <[email-masked]> wrote:
> 
> How do you mean? You have to continue to serve this policy until all other previously served policies have expired; past that point you can turn it down at will.

No.  That's the point, you can't generally just turn it out at
will without some care, or else risk creating refresh failures
during a transition period.

When a "none" policy is cached, it is still a policy and still
subject to periodic refresh, perhaps you're suggesting to use
"none" as a synonym for "max_age=0" that still leaves us with
a usable cache time, in which case are free to use NODATA/NXDOMAIN
as that TTL is no longer requires.

So the new process would be:

* Publish a "none" policy with a comparatively short "max_age".
* Remove the TXT record.
* After some time (all previous policies expire) remove the
  "none" policy.

Now the clients can:

   * Cache policies with empty id (not otherwise valid)
     when TXT lookup returns NXDOMAIN/NODATA.  Except
     when policy mode is "none" in which case the cache
     is immediately flushed, and stays that way unless
     the TXT reappears at some point.  Refresh per max_age
     and proactive update attempt cycle.

   * When "none" is seen with a "TXT" id, cache that as
     indicated, but if TXT disappears at any time, flush
     the policy then.

This seems to work better than "max_age = 0".  However, the
same cannot be said of "report", which has no clean transition
to policy removal, as dropping the TXT record still leads to
policy refresh with no end in sight, while a suddenly missing
policy (404 and the like) is not defined (deliberately IIRC
and likely correctly) to mean policy removal.
 
-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Wed, 9 Aug 2017 08:52:48 -0700

On Tue, Aug 8, 2017 at 10:20 PM, Viktor Dukhovni <[email-masked]>
wrote:

> > How do you mean? You have to continue to serve this policy until all
> other previously served policies have expired; past that point you can turn
> it down at will.
>

> distinguish between different "removal" options.

The time period during which a domain who opts out of STS must publish the
"opt out" signal--regardless of how it is expressed--is the same in all
possible implementations of any opt-out signal.

> as that TTL is no longer requires.

I'm not entirely sure I understand you. To be clear, my point was that
"mode=none" can be an indicator of "don't check anything against this
policy." The rest--policy caching--still applies as normal.

> * Publish a "none" policy with a comparatively short "max_age".

Call the above time "t0".

> * Remove the TXT record.

Call this time "t1."

Note that this step (removal of the TXT record) can only safely be done
once any *previously published* policies are expired. Normally this would
require that  "t1 > t0 + previous_max_age" (though of course it's possible
for *previous-previous policies* to have been published with overlapping
max_ages).

> * After some time (all previous policies expire) remove the

This can also happen at "t1", if the above is observed.

> and likely correctly) to mean policy removal.

I don't understand this statement. If you have a cached policy which has
expired and there is no TXT record, why would you be refreshing the policy
at all?

---

From: Viktor Dukhovni <[email-masked]>
Date: Wed, 9 Aug 2017 17:48:27 +0000

> possible implementations of any opt-out signal.

Yes, but "report" is NOT an opt-out signal.  It is a policy that
is subject to further cache refresh.  Please describe how you
think one correctly phases out a "report" policy without causing
apparent policy refresh failures at a sending domain?

> policy." The rest--policy caching--still applies as normal.

No, with "none" the policy refresh can stop (and cache flushed) as
soon as NXDOMAIN/NODATA is seen for the TXT lookup.  The same is
not true for "report", to avoid downgrade attacks.

> expired and there is no TXT record, why would you be refreshing the policy

Because the TXT record presence/absense is *insecure* (no DNSSEC
or else we'd be doing DANE!).  Therefore the TXT record must ONLY
be used:

    1.  To signal initial policy presence when none is cached.
    2.  To signal expedited policy refresh when the id changes.
    3.  [New] To signal policy removal when the policy is "none"
	and the TXT record "disappears".
    4.  [New] Conversely to signal policy removal when the policy
	transitions to "none" and was cached in the absence of a
	TXT record (still absent).

It seems that safe policy removal and cache refresh downgrade
resistance needs more discussion to avoid implementation errors.

Mere removal of the TXT record is *not* sufficient to stop policy
refresh.  Recall that policy refresh will typically happen 
before the policy is expired (more robust continuity) and must
not at that time be subject to DNS downgrade.  When a policy
is refreshed.  It will be stored for the advertised max_age
even if the TXT record is missing.

If a policy just vanishes without a secure signal that it is
being removed, that looks like an attack, unless you want to
use 404 as a secure policy removal signal (last I asked that
was not the case).

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Wed, 9 Aug 2017 11:14:16 -0700

> apparent policy refresh failures at a sending domain?

"Report" is not an opt-out signal, but not for the reason you say: a
"report" policy still generates TLSRPT reports on failure, and thus is not
a true opt-out.

It does not, however, result in any change to refresh behavior. Whether a
sender has a cached policy has no impact on their behavior with respect to
refreshes, does it?

> not true for "report", to avoid downgrade attacks.

That's not true; once a policy expires, it can be flushed from the cache
(as it can no longer safely be used).

>         TXT record (still absent).

Can you point to what language in the current draft suggests that the
behavior with respect to policy refreshing differs if you have a cached
policy versus if you do not? I am still not understanding what difference
you see here.

> not at that time be subject to DNS downgrade.

I believe this is your mistake. While I agree that one should try to
refresh a policy prior to expiration, "refresh a policy" means checking the
TXT record.

Your first sentence ("mere removal of the TXT record...") does not follow
from your second sentence.

There's zero security advantage in ignoring the TXT record and going
straight to HTTPS, since HTTPS also relies upon the (insecure) DNS
resolution. As a result, it makes no real sense to refresh the policy if
the TXT does not say to do it. A sender who implements this will appear to
be compliant with the draft--there's no real harm from doing this, aside
from maybe excessive HTTPS requests--but there's no great reason to do this
unless you think attackers can only attack the TXT record and not the
CNAME/A for the policy host.

> When a policy

---

From: Viktor Dukhovni <[email-masked]>
Date: Wed, 9 Aug 2017 18:33:11 +0000

> (as it can no longer safely be used).

You're missing the point, a robust STS implementation will rarely
encounter an expired policy because it will periodically refresh
policies (for domains to which email is still being sent) *before*
they are due to expire.

When an unexpired policy is being refreshed, there should not be
mysterious refresh failures.  So if the policy is not yet deleted,
its lifetime will be again extended by the published "max_age".

What signal *securely* indicates actual deletion of an unexpired
policy?  (Not the DNS TXT record, which just expedites refresh).
 
> policy versus if you do not? I am still not understanding what difference

The draft under-specifies the requirements for getting refresh
right.  Let's forget the draft and think logically, then fix
the draft.

When a policy is cached, it should be easily downgraded to no
policy.  Therefore a signal forged DNS response MUST NOT flush
the cache.  STS is subject to downgrade at first contact, but
is supposed to be resilient there-after, so long as mail flow
to the domain happens often enough.

Therefore, already cached policies are refreshed periodically (for
domains that receive some mail) regardless of the TXT record, and
the TXT record is only there to *expedite* refresh and signal
cold-start policy presence.

> refresh a policy prior to expiration, "refresh a policy" means checking the

Sorry that means STS is trivial to downgrade to cold-start.
If that's the spec, I'm not implementing it.

> resolution.

No it does not.  That's the whole point of HTTPS.

> As a result, it makes no real sense to refresh the policy if
> the TXT does not say to do it.

I'm afraid you're missing the consequent attack, and that's why
we've failed to reach closure on this issue.

> A sender who implements this will appear to

Forged CNAME/A do not downgrade the policy.  They just cause a
(noisy in the mail logs) failure to do the policy refresh, which
will be retried, and hence the attack must stay on path for a good
fraction of the policy lifetime (some time back I proposed refreshing
the policy at 0.5 max_age, 0.75 max_age, ... but no less than the
larger of 0.5 max_age and say 1 hour; search the list archive).

STS policy refresh must not be suppressed by forged DNS replies.
Only first contact is inevitably subject to DNS downgrade.

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Wed, 9 Aug 2017 17:05:51 -0700

For everyone else, Viktor and I were able to talk face-to-face for a half
hour and sort this out. Much easier. :)

To skip the reasoning (unless people have questions), our conclusions in
terms of changes:

1. Implement a "none" mode (along side "enforce" and "report"), which does
exactly what it sounds like (i.e. don't report, don't enforce)
2. We suggest in the Security Considerations that MTAs proactively refresh
policies long before expiration; we should additionally suggest that when
proactive refreshes fail (for any reason--i.e. DNS records not found, HTTPS
connect fails), MTAs should also be noisy about this (i.e. log it to their
owner and, if possible, send a TLSRPT report), *except* if the existing
cached policy has a "none" mode.
3. Finally, and unrelated to this discussion but arising from it, if the
TXT record does not exist (or does not parse), senders who are doing a
proactive refresh should probably bail on the policy retrieval (i.e., they
should not go straight to policy.example.com just because they have a
cached policy); this seems like unexpected behavior (at least to me).

With the above, the guidance to "downgrade" from STS is as follows:

1. Publish a new policy (as with any new policy, updating the TXT record's
ID) with mode=none.
2. After all pre-existing policies have expired (e.g. the time of step 1
plus the existing policy's max_age), safely remove the TXT record and
current policy.

I will incorporate this into draft 08.

Thanks for the discussion.

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 10 Aug 2017 00:05:24 -0400

> On Aug 9, 2017, at 8:05 PM, Daniel Margolis <[email-masked]> wrote:
> 
> 1. Publish a new policy (as with any new policy, updating the TXT record's ID) with mode=none. 
> 2. After all pre-existing policies have expired (e.g. the time of step 1 plus the existing policy's max_age), safely remove the TXT record and current policy.

One corner of the problem space we did not consider:

  * I'd like to be able to delete the "none" policy promptly, by noticing
    a removed TXT record.

  * So it would be nice to be able to remove the TXT record promptly.

  * However, you're suggesting that policy refresh should not happen
    when the TXT record is absent.

  * This implies that the TXT record removal must wait until everyone's
    max_age has expired.

  * Consequently "none" policies will linger in caches needlessly long.

If instead NXDOMAIN/NODATA triggers a policy refresh (new logically
empty id) then senders can flush "none" policies as soon as they
also see the TXT record deleted, and that deletion can reduce the
number of required DNS changes.  Instead of modifying the TXT to
trigger refresh and later deleting it, it can be deleted right
away.

The only complication is that deleted TXT is then, for senders with
a cached policy other than none, just another TXT value (NULL if
using a SQL database or similar) that triggers refresh and cached
policies can then have a NULL id, but a "none" policy with a NULL
id can be deleted right away.

Please think it over...

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Thu, 10 Aug 2017 10:02:41 -0700

It's certainly doable. As you might have guessed, I'm vaguely attached to
the idea that "not having a TXT means you don't have a policy." I don't
really know _why_ I'm attached to this--functionally, your suggested
behavior is about the same in terms of implementation--but it feels a bit
funny to me to treat _not_ having a TXT record as significant _if_ you
previously had one. (Of course, if people don't know you previously had
one, they don't need to know the absence is "significant", so this may be
silly to worry about.)

Also, note that this slightly oddifies the _DNS_ caching story; the
NXDOMAIN TTL is derived from the SOA record, so unlike a "real" TXT record,
the TTL on the "null" record comes (obviously) from a different place,
which is a little bit (but only a little bit) weird in terms of usability
of the configuration parameters, so to speak.

If anyone else has read this far on the thread, I'm happy to get feedback
on this proposal from others on the list.

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 10 Aug 2017 17:46:56 +0000

> of the configuration parameters, so to speak.

Yes, the negative TTL is from the SOA, but the TXT record TTL is
not something the sending MTA has to concern itself with, the TTLs
are handled transparently by the resolver.  The difference might
plausibly matter to the administrator of the receiving domain, who
might want to adjust the negative TTL, but he might do that regardless
of whether we refresh cached (!= "none") policies even when the
TXT is not present.  That is, if you want a shorter or longer
negative TTL, you would do tune it regardless of how we decide this
question.

> on this proposal from others on the list.

Yes, please!

-- 
	Viktor.

---

From: Daniel Margolis <[email-masked]>
Date: Thu, 10 Aug 2017 11:28:51 -0700

Your point about the administrator of the Policy Domain was exactly my
point, yes. And if an NXDOMAIN result is never "significant"--i.e. if it
only exists for people not actually using STS--then we don't have to
imagine implementors are ever concerned with SOA TTL. So adding
significance in this sense means people have to be aware of NXDOMAIN TTLs
(which to be honest I had to lookup just now to confirm my recollection
that it comes from SOA!).

Again, not a big deal; it's an extra knob, which I generally have been
trying to avoid, but it's not a very complicated extra knob, so it's hardly
a big deal. *shrug*

Feedback from others is welcome. I am very much without a strong opinion on
this one.

---

From: Jim Fenton <[email-masked]>
Date: Thu, 10 Aug 2017 15:56:29 -0700

>> on this proposal from others on the list.
I have been following the discussion, although not in as much detail as
the two of you.

One small adjustment: When removing the policy, after removing the TXT
record, you should probably wait the former record's TTL before removing
the "none" policy because the TXT record could be cached elsewhere, even
if it looks like it's gone when you ask for it.

At a higher level: I agree that including a procedure policy removal is
an essential part of the specification. But we also have to make sure
that that procedure doesn't present an opportunity for an attacker to
downgrade the policy associated with a recipient domain. I *think* this
satisfies this requirement but I'm not completely sure.

-Jim

---

From: Viktor Dukhovni <[email-masked]>
Date: Thu, 10 Aug 2017 23:07:38 +0000

> if it looks like it's gone when you ask for it.

Actually, not so much the DNS record's TTL, but the max_age of any
previous "!= none" policy.  All other policies need to expire will
all caches having "none" (or be cleared) before the "none" policy
is removed.

Under that condition, there's no need to wait to remove the TXT
record, removal of the record (being a change in the record) will
in this variant of the design trigger a refresh, and the sending
MTA will see a "none" policy and proceed to promptly flush it.

However, since refresh will often only happen in the background
when delivering mail to the domain in question, not all domains
will do the refresh in a timely manner, hence the "max_age" delay
to remove the policy.

> satisfies this requirement but I'm not completely sure.

Agreed.  My goal was to make sure that deliberate removal "by the
book" can be distinguished from an attack.  And thus that MTAs
would be able to noisily log "abnormal" policy refresh failure,
while not generating any warnings for the proper policy removal
procedure.

-- 
	Viktor.

---

From: Jim Fenton <[email-masked]>
Date: Thu, 10 Aug 2017 16:36:16 -0700

> MTA will see a "none" policy and proceed to promptly flush it.
That's the part I didn't get: that an NXDOMAIN or NODATA response was
also considered to be a record change that triggers a refresh. Thanks.
That isn't immediately obvious because the lack of a TXT record when you
don't already have a policy cached inhibits fetch of the policy.

-Jim

---

From: Daniel Margolis <[email-masked]>
Date: Thu, 10 Aug 2017 19:14:09 -0700

Right. It has no real impact on the state machine (so to speak) but makes
it possible for the recipient to remove the TXT record immediately, should
they desire.

I'm open to feedback from other people. This still seems weird to
me--mostly aesthetically--in the sense that a "none" policy is still a
policy but a non-existent TXT record is not a TXT record, so it sort of
violates my assumption that if you have a valid policy you have a TXT
record. But this is mostly aesthetics, so feedback is welcome.