Subject: [Acme] Economize on nonces

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Fri, 8 Jul 2016 13:55:43 -0700

https://github.com/ietf-wg-acme/acme/pull/156

Previously the server was required to provide a nonce on all successful
responses, including GETs. This makes certain nonce-storage techniques
like an
in-memory list impractical, because the size of the list would have to scale
with GET requests rather than just authenticated POSTs.

This change reduces the scope of requests where nonces are required.

It also tweaks the example section for Replay-Nonce to not define the
base64url
character set.

---

From: James Kasten <[email-masked]>
Date: Fri, 8 Jul 2016 16:02:36 -0700

I agree that there are a large number of wasted nonce values which creates
a burden for the ACME server.  This PR would certainly reduce the number of
unused nonces.

It seems unfortunate that with this PR, the only guaranteed way to begin
the ACME process is by posting a failed registration request.

Additionally, I have seen some clients which fetch the directory before
each submission for a fresh nonce, yielding at least twice as many nonces
as they need. (Example:
https://github.com/diafygi/letsencrypt-nosudo/blob/master/sign_csr.py#L26 )
With this PR, clients may be inclined to simply perform all of their
transactions twice to get the same "nonce_req" result.

On Fri, Jul 8, 2016 at 1:55 PM, Jacob Hoffman-Andrews <[email-masked]> wrote:

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

---

From: Roland Shoemaker <[email-masked]>
Date: Fri, 8 Jul 2016 16:36:35 -0700

(Playing devils advocate) Why not just remove the nonce system entirely?

The main use of the nonce system is to protect against TLS termination
at a CDN (or MITM middleboxes) which could, if malicious, replay
requests. Why not instead just recommend local termination of TLS and
that implementing clients should pin the relevant API TLS keys?

This would greatly simplify a number of things, including the rather
annoying need to always start any API flow with a failed request/HEAD to
a random endpoint.

---

From: Ron <[email-masked]>
Date: Sun, 10 Jul 2016 02:27:38 +0930

> the ACME process is by posting a failed registration request.

Yes, I think if we are going to do this we'd want some trivial way to
explicitly request a fresh nonce.

In the code I have I always cache the most recently received nonce, and
use that if it's available, but if I don't have one that hasn't already
been used, I just fall back to doing a HEAD request on the directory URI
to obtain one.

It would be nice to have some similarly simple operation to replace that
with.

---

From: Niklas Keller <[email-masked]>
Date: Sat, 9 Jul 2016 23:29:08 +0200

> It would be nice to have some similarly simple operation to replace that

Same implementation here for kelunik/acme-client.

I'm fine with removing it as long as there's still an explicit endpoint to
obtain one, e.g. a HEAD to the directory or simply make the directory
always return one, as HEAD should be the same as GET without a body.

Regards, Niklas

---

From: James Kasten <[email-masked]>
Date: Sat, 9 Jul 2016 15:25:31 -0700

One other way that the nonce storage problem may be solved on the ACME
server is by using "authenticated nonces".  The server could devise a
system that included a timestamp and MAC.  The idea being that the server
would only accept a nonce if its timestamp was within a window and the MAC
was verified.

This switches the problem around.  Instead of storing a list of valid
nonces, now the server would be storing a list of used nonces.

Eventually, the server would make a pass cleaning up its list of "expired"
used nonces.

I believe this achieves the same end-goal as the PR (only valid POST
requests generate entries within the nonce table), while still allowing the
server to return valid nonces on all requests.

---

From: Richard Barnes <[email-masked]>
Date: Sat, 9 Jul 2016 18:39:43 -0400

On Saturday, July 9, 2016, Niklas Keller <[email-masked]> wrote:

> 2016-07-09 18:57 GMT+02:00 Ron <[email-masked]
> <javascript:_e(%7B%7D,'cvml',[email-masked]');>>:
>

This sounds like an OK solution to me.  Coherent with the idea that the
directory is the entry point for the whole thing.

--Richard

---

From: Richard Barnes <[email-masked]>
Date: Tue, 12 Jul 2016 12:14:37 -0400

Looking at this further, I don't really see what the benefit is.

On the one hand, it's trivial to implement a nonce scheme where it's free
to issue as many nonces as you want, and you only have to store nonces that
actually get used [1].  The thing that's costly is using nonces, which this
proposal doesn't help at all.

On the other hand, you're basically trading off a valid HEAD for a
malformed POST.  That seems like a bad deal for clients (who have to do a
signature operation to get a nonce) and servers (who now can't just fail a
malformed POST).  And building functionality on malformed requests just
seems like bad protocol engineering.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 12 Jul 2016 15:42:06 -0700

> that implementing clients should pin the relevant API TLS keys?
I agree that this would be the best solution. Right now Let's Encrypt
relies on CDN termination for DDoS resistance and faster mitigation of
some front-end vulnerabilities. I'd be interested to hear from other CAs
(currently I think only SSLMate is participating on list): Do you have a
CDN in front of your API or not?

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Tue, 12 Jul 2016 15:46:15 -0700

On 07/08/2016 04:02 PM, James Kasten wrote:
> It seems unfortunate that with this PR, the only guaranteed way to
> begin the ACME process is by posting a failed registration request.

The feedback about sending a failed POST to get your first nonce, and
400's not being recoverable, makes a lot of sense. I'll add a separate
POST endpoint that just gets a nonce.

I think having GET /directory return the first nonce isn't great,
because (a) /directory is actually one of the most commonly fetched
URLs, and doesn't necessarily imply an intention to proceed with
issuance, and (b) it violates the norm that GETs should be idempotent,
and makes caching of the otherwise cacheable /directory impossible.

> Additionally, I have seen some clients which fetch the directory
before each submission for a fresh nonce, yielding at least twice as
many nonces as they need. (Example:
https://github.com/diafygi/letsencrypt-nosudo/blob/master/sign_csr.py#L26 )
With this PR, clients may be inclined to simply perform all of their
transactions twice to get the same "nonce_req" result.

This is a good point. I waffled on whether successful POSTs should be
required to return a nonce, or only allowed, but I agree that making it
optional would encourage the double-POSTing client design, which is
relatively wasteful.

---

From: Andrew Ayer <[email-masked]>
Date: Sun, 17 Jul 2016 19:15:56 -0700

On Fri, 8 Jul 2016 16:36:35 -0700

> (Playing devils advocate) Why not just remove the nonce system

That's an interesting question.  How important is it to prevent
replays?  I believe that ACME messages can be divided into three classes:

1. Idempotent operations: completing challenges, revoking certificates,
and deleting resources (assuming resource IDs aren't reused).  No need
for replay protection here.

2. Operations that create resources on the server (registrations,
applications, certificates).  It seems that the only risk from
replays is resource exhaustion on the server, which is something the
server already needs to be concerned about.

3. Operations that modify resources (registrations).  This is sensitive,
as a replay would allow a malicious CDN to roll back a resource to an
earlier state.  The only attack I see with the current protocol would
be rolling back the registration contact to an email address that is
now controlled by the attacker instead of the account owner.

Could this be solved by adding an integer version field to every
resource that starts at zero, and requiring that all modifications
include a version that's greater than the existing version?  As a side
benefit, this makes the protocol safe against concurrent modifications
by different clients, since only one update would succeed.

Have I overlooked anything?  Would we be painting the protocol into a
corner if we removed nonces and instead required individual messages to
be safe to replay?

Regards,
Andrew

---

From: Andrew Ayer <[email-masked]>
Date: Sun, 17 Jul 2016 19:39:23 -0700

On Tue, 12 Jul 2016 15:42:06 -0700
Jacob Hoffman-Andrews <[email-masked]> wrote:

> > The main use of the nonce system is to protect against TLS
> > termination at a CDN (or MITM middleboxes) which could, if
> > malicious, replay requests. Why not instead just recommend local
> > termination of TLS and that implementing clients should pin the
> > relevant API TLS keys?
> some front-end vulnerabilities. I'd be interested to hear from other
> CAs (currently I think only SSLMate is participating on list): Do you
> have a CDN in front of your API or not?

SSLMate does not.  If we did, it would probably only be on the endpoint
to download a certificate, since the amount of traffic to that endpoint
dwarfs everything else and it's trivially cacheable.  That endpoint
isn't security sensitive, so I'd want to move it to a different origin
so the sensitive API operations could bypass the CDN.

(Note that we're not a CA, but we have an ACME-like API that abstracts
over several different CAs and adds some extra management functionality.)

Regards,
Andrew