Subject: Re: [Acme] Simplifying key rollover

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Thu, 9 Jun 2016 15:59:15 -0700

On 03/31/2016 02:27 PM, Jacob Hoffman-Andrews wrote:
> I'd like to propose some changes to how we do account key roll-over. I
> think the current approach is too complex. The current version is
> included below for reference.
>
> Instead I'd like to propose:
>
> To update the key on a registration object, POST a double-signed JOSE
> object to the registration URL, with the field "key" containing the new
> key, in JWK format.
>
> The double-signed object should have two signatures: one from the old
> key, and one from the new key. This ensures that the key rollover is
> authorized by the existing account holder, and also proves that the
> requester possesses the private key corresponding to the new key.
>
> What do you all think?
>
> Relatedly, since we are introduce a self-signature to prove possession
> of the new key, we probably want to introduce the same guarantee on
> initial account creation. One easy way to achieve this would be to
> require that the "jwk" field be provided in the protected header, rather
> than in the protected or unprotected header as is allowed today.
I've posted a PR for this change, tweaked slightly to use a separate
resource: https://github.com/ietf-wg-acme/acme/pull/139.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Wed, 22 Jun 2016 11:26:07 -0700

Any objections to the below? We'd like to start implementing in Boulder
soon.

On 06/09/2016 03:59 PM, Jacob Hoffman-Andrews wrote:
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme
>

---

From: Roland Shoemaker <[email-masked]>
Date: Mon, 27 Jun 2016 12:03:07 -0700

The proposed simplification looks good to me and would make the Boulder
implementation much cleaner overall.

I also agree the ambiguity about which header the 'jwk' field is
provided in should be cleared up, it seems like there is no reason not
to require it in the protected header.

---

From: Karthikeyan Bhargavan <[email-masked]>
Date: Tue, 28 Jun 2016 04:21:54 +0200

> object to the registration URL, with the field "key" containing the new

In principle, this suggestion would work, but could you clarify the
structure of the JSON object? Does it still contain the oldKey?

The safest design would be to have the JSON object include
the thumbprints of both the old and new keys and then sign it
with both the new and old keys. This way, both keys explicitly
acknowledge the rollover. (If we don’t do this, there are some
subtle albeit not-so-practical attacks, say if the old key is compromised 
but the new one is not.)

> Thanks,
> Jacob
> Current spec:
> ### Account Key Roll-over
> 
> A client may wish to change the public key that is associated with a
> registration, e.g., in order to mitigate the risk of key compromise.  To do
> this, the client first constructs a JSON object representing a request to
> update the registration:
> 
> resource (required, string):
> : The string "reg", indicating an update to the registration.
> 
> oldKey (required, string):
> : The JWK thumbprint of the old key {{RFC7638}}, base64url-encoded
> 
> ~~~~~~~~~~
> {
>  "resource": "reg",
>  "oldKey": "D7J9RL1f-RWUl68JP-gW1KSl2TkIrJB7hK6rLFFeYMU"
> }
> ~~~~~~~~~~
> 
> The client signs this object with the new key pair and encodes the
> object and
> signature as a JWS.  The client then sends this JWS to the server in the
> "newKey" field of a request to update the registration.
> 
> ~~~~~~~~~~
> POST /acme/reg/asdf HTTP/1.1
> Host: example.com
> 
> {
>  "resource": "reg",
>  "newKey": /* JSON object signed as JWS with new key */
> }
> /* Signed as JWS with original key */
> ~~~~~~~~~~
> 
> On receiving a request to the registration URL with the "newKey"
> attribute set,
> the server MUST perform the following steps:
> 
> 1. Check that the contents of the "newKey" attribute are a valid JWS
> 2. Check that the "newKey" JWS verifies using the key in the "jwk" header
>   parameter of the JWS
> 3. Check that the payload of the JWS is a valid JSON object
> 4. Check that the "resource" field of the object has the value "reg"
> 5. Check that the "oldKey" field of the object contains the JWK
> thumbprint of
>   the account key for this registration
> 
> If all of these checks pass, then the server updates the registration by
> replacing the old account key with the public key carried in the "jwk"
> header
> parameter of the "newKey" JWS object.
> 
> If the update was successful, then the server sends a response with
> status code
> 200 (OK) and the updated registration object as its body.  If the update
> was not
> successful, then the server responds with an error status code and a problem
> document describing the error.
> 
>