Subject: [Acme] Nonces for GETs

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Sat, 6 Aug 2016 11:55:26 -0700

At IETF 96 it was proposed to drop this issue:
https://www.ietf.org/proceedings/96/minutes/minutes-96-acme.

The rationale from the notes is that nonces are not a scarce resource.
However, cachability and idempotence of GETs were not addressed. I think
it's worth not requiring nonces on GETs purely for those reasons. In
practical terms, this difference has caused real bugs for Let's Encrypt.

Would someone like to present a specific defense of providing a unique
nonce with every GET?

---

From: Ron <[email-masked]>
Date: Sun, 7 Aug 2016 23:58:05 +0930

> Would someone like to present a specific defense of providing a unique

The example that I and others originally voiced on this list was that you
shouldn't have to do a POST that you know will fail (because you don't
yet have a valid nonce) to get a valid nonce.

But as long as there is some trivial way to GET a fresh nonce (similar
to what we are already doing now with a HEAD request to the directory)
I don't see a problem with not providing a nonce with _every_ GETable
resource.

IIRC you objected to using the directory for this, but a separate "get
me a new nonce" resource would probably be fine for that too.  modulo
needing a flag day for the client code to transition to that if Boulder
doesn't implement both for some period of time.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 8 Aug 2016 11:32:13 +1000

> practical terms, this difference has caused real bugs for Let's Encrypt.

The hazard here is that you generate a cacheable response that
contains a nonce.  That means that clients could see the same nonce
twice if they pull from cache.  But the downside there is that you
could end up with a rejection when the nonce is used the second time.
The upside is that the rejection will contain a new nonce.  (If you
aren't retrying requests when you get a 4xx, then you will have a bad
day anyway).

Not sure about your question regarding idempotence.  Maybe you are
concerned about GET being safe (in the RFC7231 sense) and the
side-effects of the request.  To that, I'd suggest that if generating
a nonce is not safe in your server implementation, you have bought
yourself a lot of pain for nought.  Generating a nonce safely (e.g.,
without committing state) is fairly trivial.

---

From: Richard Barnes <[email-masked]>
Date: Sun, 7 Aug 2016 18:55:15 -0700

> practical terms, this difference has caused real bugs for Let's Encrypt.

Could you comment a little more specifically on what issues this has caused
you?

> Would someone like to present a specific defense of providing a unique

As Ron notes, there's a need for some way to prime the nonce pump.  Because
POSTs require nonces, that means that we need either use a non-POST method
or modify POST behavior.  Let me propose a few options for people to opine
on...

Option 1: HEAD to some existing resource that admits a GET (e.g., directory)
Pro: Aligns with HTTP's requirement for GET == HEAD if you also send
Replay-Nonce for the GET
Con: ... but sending Replay-Nonce for the GET makes the affected resource
non-cacheable

Option 2: GET/HEAD to a new-nonce resource
Pro: Clean separation of the nonce-priming function
Con: One more resource to specify / provision / remember

Option 3: HEAD to the resource you would be POSTing to
Pro: Simple client logic; no need to use a separate resource
Con: Contrary to a SHOULD in RFC 7231, especially when the resource doesn't
respond to GET

Option 4: POST an empty body to the resource you would be POSTing to; get
nonce in error response
Pro: Client can use the same resource; priming POST can't be mistaken for a
real POST
Con: Client and server need a special case in their POST logic

I think my preference order would be 3 ~= 4 > 2 > 1, but I don't have
strong feelings here as long as we end up with something predictable for
the client to do.

--Richard

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

---

From: Andrew Ayer <[email-masked]>
Date: Tue, 9 Aug 2016 13:20:19 -0700

On Sun, 7 Aug 2016 18:55:15 -0700
Richard Barnes <[email-masked]> wrote:

> As Ron notes, there's a need for some way to prime the nonce pump.
> Because POSTs require nonces, that means that we need either use a
> non-POST method or modify POST behavior.  Let me propose a few
> options for people to opine on...
> 
> Option 1: HEAD to some existing resource that admits a GET (e.g.,
> directory) Pro: Aligns with HTTP's requirement for GET == HEAD if you
> also send Replay-Nonce for the GET
> Con: ... but sending Replay-Nonce for the GET makes the affected
> resource non-cacheable
> 
> Con: Contrary to a SHOULD in RFC 7231, especially when the resource
> doesn't respond to GET
> 
> Option 4: POST an empty body to the resource you would be POSTing to;
> get nonce in error response
> Pro: Client can use the same resource; priming POST can't be mistaken
> for a real POST

What about option 5: make the protocol resilient to replays and remove
nonces, as I suggested a few weeks ago:
https://www.ietf.org/mail-archive/web/acme/current/msg01158.html

Regards,
Andrew

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 9 Aug 2016 16:25:43 -0700

On 08/07/2016 06:55 PM, Richard Barnes wrote:
> Could you comment a little more specifically on what issues this has
> caused you?

We turned on caching at our CDN, which led to some clients getting
nonces that had already been used by other clients. A lot of clients
didn't implement retries on badNonce, because in normally operation it's
a relatively rare case.

> As Ron notes, there's a need for some way to prime the nonce pump. 

Yup, agreed.

rlb> Option 1: HEAD to some existing resource that admits a GET (e.g.,
directory)
rlb> Option 2: GET/HEAD to a new-nonce resource
rlb> Option 3: HEAD to the resource you would be POSTing to
rlb> Option 4: POST an empty body to the resource you would be POSTing to;
agwa> Option 5: make the protocol resilient to replays and remove
nonces
jsha> Option 6: POST an empty body to a new-nonce resource?
jsha> Option 7: Don't require nonces for new-reg.

Option 7 is not terribly appealing because it makes new-reg require
different analysis for replay resistance. However, implementers already
need different code to validate a new-reg request than to validate other
requests, because the key in a new-reg request doesn't already exist.

Similarly, option 5 allows getting rid of nonces, but at the cost of
making the protocol harder to analyze. Each new request type created
would have to be analyzed as to whether it was safe for replays. It's
nicer, in my mind, to have one solution that covers the whole protocol.

Right now I lean towards Option 6. Thoughts?