Subject: [Acme] various issues with the spec

From: Stefan Bühler <[email-masked]>
Date: Tue, 9 Jun 2015 22:13:25 +0200

Hi all,

I've been working on a my own acme client (written in Go).

There are some issues I came across, and I thought I'd list them here.
They are too many to write separate mails for each one :)

* Updating registrations: sending empty "contact" and "agreement" should
  actually reset them (if allowed) compared to not sending them, which
  should just keep them as they are (and this should be documented, not
  just happen to be an implementation detail).

  This also means a user can officially query the registration by
  POSTing an empty (signed) JSON object to the registration URI.

* A registration update response should include the rel="next" link and
  the rel="terms-of-service" link, if it would have been sent for a new
  registration.

* The "success" status code for updates should be documented. Right now
  it seems to be "202 Accepted"

* There should be a way to list all authorizations for a registration,
  and also a way to list all certificates authorized by an
  authorization.

* simpleHttps cannot require the https certificate to use the public
  key of either registration or the "future" key; the registration
  private key should never be available to the web server, and the
  "future" key is not given at that stage.

  Whether https or http is used doesn't matter much here; although I
  see no reason not to require https - it makes MITM harder, because an
  attacker risks getting caught.

* The simpleHttps path should be more restricted to prevent path
  traversals. (https://github.com/letsencrypt/boulder/issues/335)

* dvsni should not require the target domain to be part of the
  certificate; some TLS implementations have quite nice SNI support by
  automatically selecting a matching certificate.

  During the process of authorization you don't want to break your
  normal setup by accidentally using the dvsni certificate.

* 5.5 `If the final state is "valid", ... or add a "recoveryToken"
  field.`

  There is currently no way for a client to see "private" information
  about a authorization, as it doesn't support a (signed) POST request.

  I think it would be a good idea to define "private" (and completely
  hidden, see below) fields in an authorization request which can only
  be seen by the currect signed request - for example the "key" field
  (which isn't listed by a GET request) and such "recoveryToken" field.

* 6.3. Recovery Contact: `using contact information provided by the
  client in a prior authorizationRequest message.` - I don't see any
  way to provide such contact information - the contact information is
  only provided in the registration, not in the authorization.

  5.5 mentions a "recoveryToken", which would be provided by the
  server, not the client!

* 6.4. Recovery Token: the server must never show the token used to
  satisfy the challenge.

  That way an authorization can be passed on to a different user, i.e.
  someone else tells me the URL to post my registration recovery token
  to, enabling them to takeover the domain without me having to give
  them my recovery token.

* What happens to an expired authorization? Do users create new
  authorizations or reuse the old one?

  The same user should get redirected to an existing authorization when
  trying to create a new one for the same identifier (of course you
  shouldn't redirect to an authorization by a different user).

* Updates should use (or at least allow) "PUT" instead of "POST", as
  they should be idempotent.

* Please document the various "status" more detailed (possible values
  and their interpretations)

* Please document the generic fields a challenge has ("type", "status",
  "url", "validated").

I didn't start working on certificates yet, so there might be more; I
also only had a closer look at simpleHttps and dvsni so far, not at the
other challenge types.

Best regards,
Stefan

---

From: Stefan Bühler <[email-masked]>
Date: Sat, 13 Jun 2015 23:21:21 +0200

Hi again,

now that I realized the link to the "Latest Version" doesn't
actually point to the latest version I'm updating my issue list.

As it doesn't look like there is anyone interested in them on this
mailing list I'll keep them to myself, or post them to github when I
find the time.

On Tue, 9 Jun 2015 22:13:25 +0200
Stefan Bühler <[email-masked]> wrote:

> * Updating registrations: sending empty "contact" and "agreement"
> should actually reset them (if allowed) compared to not sending them,
> which should just keep them as they are (and this should be
> documented, not just happen to be an implementation detail).
> 
> * A registration update response should include the rel="next" link
> and the rel="terms-of-service" link, if it would have been sent for a
> new registration.
> 
> * The "success" status code for updates should be documented. Right
> now it seems to be "202 Accepted"
> 
>   see no reason not to require https - it makes MITM harder, because
> an attacker risks getting caught.
> 
>   The same user should get redirected to an existing authorization
> when trying to create a new one for the same identifier (of course you
> * Please document the generic fields a challenge has ("type",
> "status", "url", "validated").
> 
> also only had a closer look at simpleHttps and dvsni so far, not at
> the other challenge types.
> 
> Best regards,
> Stefan
> 
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme

---

From: "Salz, Rich" <[email-masked]>
Date: Sat, 13 Jun 2015 21:24:41 +0000

> As it doesn't look like there is anyone interested in them on this mailing list I'll
> keep them to myself, or post them to github when I find the time.

No, please post here.

It's just that the WG is in transition right now, moving from a BoF to a formal WG...

---

From: Stefan Bühler <[email-masked]>
Date: Sun, 14 Jun 2015 00:24:32 +0200

On Sat, 13 Jun 2015 21:24:41 +0000
"Salz, Rich" <[email-masked]> wrote:
> > mailing list I'll keep them to myself, or post them to github when
> > I find the time.
> 
> No, please post here.

Ok, here we go:

* I don't see how a client would determine the /acme/revoke-cert URI,
  it isn't part of any Link header as far as I could see. Perhaps it
  should be part of the Link headers of the registration?

* Updates should use "PUT" instead of "POST", as they should be
  idempotent

* When updating a registration sending empty "contact"/"agreement"
  should actually reset them (if allowed) compared to not sending them,
  which just retrieves the currently set values.

  I.e. posting {"contact":[]} should delete all contact information.

* All responses to successful updates should contain the same "Link"
  headers as the creating request did.

* The "success" status code for updates should be documented. Right now
  boulder always returns "202 Accepted".

  For challenges the spec says `The server provides a 200 response
  including the updated challenge.`; boulder returns 202 anyway.

* simpleHttps: `The content type of the resource MUST be "text/plain"`
  versus `4. Verify that the Content-Type header of the response is
  either absent, or has the value "text/plain"`

  Is an absent Content-Type header ok or not?

* dvsni: Please don't require the domain name which is being validated
  to be part of subjectAltName; configuring such certificate might
  break a working setup in production, when it "wins" over an already
  present and valid certificate for the domain.

* dvsni: Don't require it to be a self-signed certificate - what does it
  matter who signed it?

* dvsni: `The public key is the public key for the key pair being
  authorized`. I hope this was just an accident, this would be *really*
  wrong to require.

I guess that the "dns" challenge type is probably not ready yet; but I
suggest adding a "nodns" challenge which should be required in all
combinations which don't include "dns": no any _acme-challenge TXT
must be present.

Maybe another type "nodnssec" could also be added, to require DNSSEC in
all combinations not including "dns" - so DNSSEC domains always have to
be authorized by "dns" challenge.

Also I'd like to suggest making "dns" more powerful; for example making
it possible to authorize accounts by public key and to authorize sub
domains. Example:

_acme-challenge.example.com TXT "inherit:1 key-sha256:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU="
_acme-challenge.example.com TXT "token:17817c66b60ce2e4012dfad92657527a"

---

From: [email-masked]
Date: Sat, 13 Jun 2015 19:04:02 -0400

Updates should be idempotent????

They are not by definition. 

In general, just use http features as little as possible. Caching is not at all helpful. Uri encoding is inferior to JSON structures.

Sent from my iPhone

> On Jun 13, 2015, at 6:24 PM, Stefan Bühler <[email-masked]> wrote:
>

---

From: Fraser Tweedale <[email-masked]>
Date: Sun, 14 Jun 2015 11:17:38 +1000

>   present and valid certificate for the domain.
No, this certificate is only presented for the host
`<nonce>.acme.invalid'.

> * dvsni: Don't require it to be a self-signed certificate - what does it
It must be signed by the account key as evidence that the entity
performing the authorization controls the account key.

>   authorized`. I hope this was just an accident, this would be *really*
Why would this be wrong?  Remember that this certificate is
generated as part of, and intented for use only as part of the
authorization workflow.  It has no bearing on certificates
eventually issued for the domain name being authorized.

Cheers,
Fraser

---

From: Stefan Bühler <[email-masked]>
Date: Sun, 14 Jun 2015 08:19:04 +0200

On Sat, 13 Jun 2015 19:04:02 -0400
[email-masked] wrote:

> In general, just use http features as little as possible. Caching is
> not at all helpful. Uri encoding is inferior to JSON structures.

Well, given there is a replay token, every action is actually
idempotent - repeating the request will not change the state further in
any way (after a request actually reached the server).

My argument is more about the underlying HTTP protocol. When you are in
the middle of a keep-alive connection, and send a POST, but the server
decided in just this moment to close the connection (yes, all fixed
with HTTP/2, at least they got this one right), the client does not know
whether the server actually received and processed the request.

With an idempotent request the client can just repeat it on a new
connection without asking for user feedback.

I think some proxies (and perhaps client implementations too) will
actually open a new connection for each POST request (although I just
found mails claiming squid does it for POST/PUT/DELETE).

regards,
Stefan

---

From: Fraser Tweedale <[email-masked]>
Date: Sun, 14 Jun 2015 17:01:37 +1000

On Sun, Jun 14, 2015 at 08:06:46AM +0200, Stefan Bühler wrote:
> On Sun, 14 Jun 2015 11:17:38 +1000
> Fraser Tweedale <[email-masked]> wrote:
> 
> > > * dvsni: Please don't require the domain name which is being
> > > validated to be part of subjectAltName; configuring such
> > > certificate might break a working setup in production, when it
> > > "wins" over an already present and valid certificate for the domain.
> > > 
> You are thinking of a setup where you configure explicitly which
> certificate is used for which SNI value. But gnutls for example has a
> nice feature where you can just give it all your certificates, and it
> will pick the matching one automatically.
> 
Do you propose that the certificate *not* bear the domain name being
validated in *either* the Subject DN or subjectAltName extension?

This probably does not affect the protocol, but I think is nice to
include it anyway for the sake of being explicit.  Can you identify
any existing server software which would is incompatible with ACME
dvsni due to the validation certificate bearing the name being
validated?

> > >   authorized`. I hope this was just an accident, this would be
> > > *really* wrong to require.
> > > 
> I don't want my webserver to see my account private key, ever. Am I
> really the first guy to have a problem with that?
> 
> > > * dvsni: Don't require it to be a self-signed certificate - what
> > > does it matter who signed it?
> > > 
> What exactly is the attack scenario here if this is not checked?
> Person A playing MITM to give control over domain B to account C, and
> account C started the authorization but didn't actually want it to
> succeed?
> 
> If you really require such evidence, perhaps it could be required to
> have the certificate signed by the account key instead of being
> self-signed.
> 
> regards,
> Stefan

You've convinced me on these latter points - the certificate should
be signed by the account key but the key could be a different key
(i.e. not a self-signed cert) - and this means that the web server
need not have access to the account private key.

Cheers,
Fraser

---

From: Stefan Bühler <[email-masked]>
Date: Sun, 14 Jun 2015 12:31:21 +0200

On Sun, 14 Jun 2015 17:01:37 +1000
Fraser Tweedale <[email-masked]> wrote:

> > certificate is used for which SNI value. But gnutls for example has
> > a nice feature where you can just give it all your certificates,
> > and it will pick the matching one automatically.
> > 

Yes, neither set in the common name nor in subjectAltName; I think
gnutls would find both.

Just for the record, I'd be fine with adding a subjectAltName like
`DNS:<dnsname>.acme.invalid', so the domain name is at least present in
some form (although I don't know what to gain from it).

> dvsni due to the validation certificate bearing the name being

I happen to know such webserver: lighttpd 2 (not released yet); see
http://doc.lighttpd.net/lighttpd2/mod_gnutls.html

> > > > * dvsni: `The public key is the public key for the key pair
> > > > being authorized`. I hope this was just an accident, this would
> > > > be *really* wrong to require.
> > > > 
> > Person A playing MITM to give control over domain B to account C,
> > and account C started the authorization but didn't actually want it
> > to succeed?
> > 

Ok.

regards,
Stefan

---

From: Phillip Hallam-Baker <[email-masked]>
Date: Sun, 14 Jun 2015 07:09:28 -0400

As a meta point, this discussion is incomprehensible. The objective is to
produce a comprehensible spec.

We should agree terms of art for the actors, certs etc. and use them
consistently.