Subject: Re: [Acme] Rolling keys and pending validations

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Wed, 5 Jul 2017 15:03:00 -0700

On 06/30/2017 09:54 AM, Dunning, John wrote:
> Based on your description below, I think door A makes more sense to
> me.  My paraphrase of it is that key authorizations get bound at
> creation time, and thus get “grandfathered” in after a credential
> rotation.
This is a good paraphrase. What do other folks on this list think about
binding key authorization objects at creation time? I can't immediately
see a security issue with it, but as a reminder, an earlier version of
the protocol was subject to a vulnerability
(https://www.ietf.org/mail-archive/web/acme/current/msg00484.html)
related to changing the account key after creating an authorization
object, so I think tweaks in this area deserve extra scrutiny.

---

From: Richard Barnes <[email-masked]>
Date: Fri, 7 Jul 2017 09:42:49 -0400

On Wed, Jul 5, 2017 at 6:03 PM, Jacob Hoffman-Andrews <[email-masked]> wrote:

> Based on your description below, I think door A makes more sense to me.
> My paraphrase of it is that key authorizations get bound at creation time,
> and thus get “grandfathered” in after a credential rotation.
>
> binding key authorization objects at creation time? I can't immediately see
> a security issue with it, but as a reminder, an earlier version of the
> protocol was subject to a vulnerability (https://www.ietf.org/mail-
> archive/web/acme/current/msg00484.html) related to changing the account
> key after creating an authorization object, so I think tweaks in this area
> deserve extra scrutiny.
>

Note that the solution I implemented in -07 was to bind not at challenge
creation time, but at the time that a client responds to a challenge.  I
think I probably agree that it's simpler to bind at creation time, in the
sense that it avoids more race conditions.  It does move us more in the
direction of the server just providing an opaque value to the client, but
at least the client can still validate that the value makes sense.

I'm tempted to propose an option (C), but I'm not sure it's actually a good
idea:

C) Instead of using *key* authorizations, use *account* authorizations.
Instead of the object being of "token.H(key)", make it
"token.H(account-url)".

This would remove any question of roll-over interactions, and kind of match
the pattern we established when we moved from using "jwk" in JWS to using
"kid" with the account URL.  In fact, I think that would remove the last
reference we have to account keys outside of account management.  However,
I have the usual worries about the indirection caused by using account
URLs, and the potential ambiguity of treating a URL as an octet string.

--Richard

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Fri, 7 Jul 2017 11:06:14 -0700

On 07/07/2017 06:42 AM, Richard Barnes wrote:
> C) Instead of using *key* authorizations, use *account*
> authorizations.  Instead of the object being of "token.H(key)", make
> it "token.H(account-url)".
I like this in principle, and wish we'd adopted it several months ago.
At this point, I think it's too big a change for too little benefit. The
"bind keyAuthorization at challenge creation" approach has the benefit
that most clients will not even notice the change. It only makes a
different when key rollover and long-term pending challenges are in
play, which is pretty uncommon.

---

From: Richard Barnes <[email-masked]>
Date: Fri, 7 Jul 2017 15:35:42 -0400

> play, which is pretty uncommon.

Whether clients will notice depends on how we change the syntax to express
the "binding".  You seem to be assuming that we'll keep the syntax the
same.  That would mean that the server would note the keyAuthorization to
be used with the challenge at creation time, in a way that's invisible to
the client, and the client would still compute and send back a
keyAuthorization.  So you'll break clients in the following scenario:

1. Server creates challenge bound to keyAuthorization_oldkey, sends to
client
2. Client rolls keys
3. Client computes keyAuthorization_newkey
4. Client provisions the validation response with keyAuthorization_newkey
5. Client sends keyAuthorization_newkey in a response to the challenge,
signed with newkey

... since now the client's keyAuthorization doesn't match the one the
server bound.  You only avoid the race condition if you express the
keyAuthorization in the challenge.  And that entails changing the "token"
field to a "key-authorization" field, which will break clients.

If clients are going to have to change either way, then option (C) seems
like a marginally smaller change:

Option (A): Pull the keyAuthorization from the challenge; delete
keyAuthorization computation code
Option (B): Put the account URL in the keyAuthorization instead of the
account key; delete JWK thumbprint code

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Fri, 7 Jul 2017 15:09:41 -0700

On 07/07/2017 12:35 PM, Richard Barnes wrote:
> Whether clients will notice depends on how we change the syntax to
> express the "binding".  You seem to be assuming that we'll keep the
> syntax the same.  That would mean that the server would note the
> keyAuthorization to be used with the challenge at creation time, in a
> way that's invisible to the client
Yep, I am assuming we'll keep the syntax the same. I don't see a reason
to change.
> So you'll break clients in the following scenario:
>
> 5. Client sends keyAuthorization_newkey in a response to the
> challenge, signed with newkey
Yep, this was the scenario I was describing when I said:

> It only makes a different when key rollover and long-term pending
challenges are in

Thanks for spelling it out in more detail, that makes it clearer.
Essentially, I am saying that it is very rare for clients to hold onto
pending authorizations while rolling keys. The most common clients
(Cerbot, dehydrated, lego, etc) treat "get authorization; provision
validation response; request validation" as a single automated steps,
taking seconds or minutes. Those clients generally don't keep
authorizations around between runs, and would be rotating keys between
runs. So no problem.

The only clients that would have to change are those that (a) cannot be
fully automated, and therefore hold onto pending authorizations for
days, and (b) rotate their keys regularly. As far as I'm aware, Akamai
is the only client doing that, and they are the ones asking for "bind at
creation time." I believe that most other clients would not notice a
difference.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Fri, 28 Jul 2017 10:01:26 -0700

Any further thoughts on whether keyAuthorizations should be bound at
challenge creation time vs challenge submission time?

On 07/07/2017 03:09 PM, Jacob Hoffman-Andrews wrote:
> Yep, I am assuming we'll keep the syntax the same. I don't see a
> reason to change.
>> 1. Server creates challenge bound to keyAuthorization_oldkey, sends
>> to client
>> 2. Client rolls keys
> The only clients that would have to change are those that (a) cannot
> be fully automated, and therefore hold onto pending authorizations for
> is the only client doing that, and they are the ones asking for "bind
> at creation time." I believe that most other clients would not notice
> a difference.
>
>
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme