Subject: Re: [Acme] Bypassing the intended purpose of requiring 128 bits of entropy for the http-01 token

From: Richard Barnes <[email-masked]>
Date: Tue, 13 Jun 2017 11:59:21 -0400

Hey Zach,

Thanks for submitting a PR on this.  I just filed a review with some
specific comments:

https://github.com/ietf-wg-acme/acme/pull/312#pullrequestreview-43769669

This change seems fine to me, especially if we make the change I propose in
there to digest the whole key authorization instead of just the token.  I
don't think there's a security problem here, but I also don't think
stateless clients are tremendously valuable to the ecosystem, and it seems
conservative to require more knowledge on the part of the verification host.

Looking at the thread, I'm not seeing strong objections.   Unless I hear
something here before Zach updates the PR, I'll go ahead and merge once
that's done.

--Richard

On Mon, May 8, 2017 at 6:21 PM, Zach Shepherd <[email-masked]> wrote:

> The following feedback is based on cd7c5e9 (current HEAD of master).
>
> Section 8.3 states that the token value for HTTP validation "MUST have at
> least 128 bits of entropy."
>
> Section 11.3 explains that one goal of this is that "the entropy
> requirement prevents ACME clients from implementing a “naive” validation
> server that automatically replies to challenges without participating in
> the creation of the intial authorization request."
>
> However, because of the way the token is used in the validation process,
> as a part of the request, this goal is not met. It is possible to configure
> a webserver to respond to all requests under .well-known/acme-challenge
> with the ASCII representation of the key authorization. (See, e.g.,
> https://github.com/Neilpang/acme.sh/wiki/Stateless-Mode.)
>
> Essentially, the server informs the client of the token during the
> validation process, removing any need for the client to have known it.
>
> If this is acceptable, the entropy requirement should be removed. If this
> is unacceptable, the challenge and validation should be revised.
>
> Regards,
> Zach Shepherd
>
>
> _______________________________________________
> Acme mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/acme
>
>

---

From: Ilari Liusvaara <[email-masked]>
Date: Tue, 13 Jun 2017 20:23:47 +0300

> something here before Zach updates the PR, I'll go ahead and merge once

I think that if one wanted to be consistent among different validation
methods, then challenges would be based on hash of one thing, and the
responses would be (hash of) another.

However, I do not think it is sufficient for security to take just the
random token for request, and random token + accout JWT for response.

The problems with do not manifest in HTTP nor DNS, since HTTP and DNS
requests are also bound to the validatio name (via virtual host
and QNAME respectively) as fundamential part of request process.

However, TLS-SNI is another matter. There is nothing binding validation
to domain name, not even if preimages are disclosed. And this in my view
causes TLS-SNI to fail to validate the domain itself, instead validating
the underlying IP address.

Now, the lack of this binding does not manifest when the server is
dedicated and the webmaster has full control of the entiere server,
however it does manifest if the server is shared between multiple
tenants. The server has no way of determining if the challenge-
response pairs are legimate or not.

To fix this, I think that the identifier being validated should be
included in requests (and possibly responses).

One scheme I considered earlier (but didn't actually send a mail about,
due to writing the mail to a wrong place):

Request form would be (before hashing):

TR.<random>.<method>.<identifierbase64url>

And response form would be (possibly before hashing):

KA.<random>.<method>.<identifierbase64url>.<accountjwt>

(I included message tags and methods to follow good practice of
separating different messages, altough in this case, there is no
way to confuse the two, since number of periods is different.)

Now, disclosing the preimages allows verifying that the challenge-
response pair is a validation of legimate domain.

-Ilari

---

From: Richard Barnes <[email-masked]>
Date: Wed, 14 Jun 2017 09:23:59 -0400

Hey Ilari,

Thanks for this analysis.  I agree that a tighter and clearer binding of
the challenge/response pair to the validation transaction would be
desireable, as would more uniformity across challenges.  I would like to
propose a slightly different structure, though.

===

The essential elements of a challenge are (1) the content of the challenge,
(2) the content of the response, (3) the content of the validation query,
and (4) the content of the validation response  (where in 3 and 4, we mean
the part that is specific to the validation, vs. .well-known or
_acme-challenge).  Right now, (1) and (2) are the same for all challenges,
but (3) and (4) differ.

http: (1) token (2) keyAuthorization (3) token (4) keyAuthorization
tls: (1) token (2) keyAuthorization (3) H(token) (4) H(keyAuthorization)
dns: (1) token (2) keyAuthorization (3) (nil) (4) H(keyAuthorization)

I think we could meet the requirements above with the following steps:

1. Update the keyAuthorization structure to be a JSON object binding the
validation to a bunch of stuff, e.g.:

{
  "identifier": {"type": "dns", "value": "example.com"},
  "method": "dns-01",
  "key": { ... },
  "nonce: "evaGxfADs6pSRb2LAv9IZf17Dt3juxGJ-PCt92wr-oA"
}

2. Have the client provide the serialized keyAuthorization in its response
to the challenge (in ACME) and have the server verify that it decodes
properly, has only the identified fields, and the fields have the proper
values.

3. Derive the validation query and response values from the serialized
keyAuthorization value provided in the response, using a "reveal the
preimage" pattern, either:
3.a. query = H(kA), response=kA, or
3.b. query = H(H(kA)), response=H(kA)

I kind of like the latter better, because it meets all the transport
requirements for DNS and TLS (since the hashes are small).  It also enables
the server to verify that a challenge/response pair is valid without
necessarily revealing to the server the details of the validation; if the
server really wants to know, it can demand the raw key authorization.

That would give us a uniform structure across challenges:

all: (1) token (2) keyAuthorization (3) H(H(keyAuthorization)) (4)
H(keyAuthorization)

What would folks think of that?  It's a large-ish change for this stage of
the process, but it seems like the regularity it provides will help
simplify analysis and make implementation easier, so I'm inclined to do it.

Thanks,
--Richard

---

From: Ilari Liusvaara <[email-masked]>
Date: Wed, 14 Jun 2017 18:22:04 +0300

> properly, has only the identified fields, and the fields have the proper

This has the raw key, which means one has to compare raw keys. IIRC,
that is somewhat frowned on.

> server really wants to know, it can demand the raw key authorization.

I expect the most common check is check for identifier.

But being able to calculate where the response goes from the key
authorization (e.g.
'http://somehost3.example.net/.well-known/acme-challenge/yeag2...',
'_acme-validation.somehost3.example.net' or 
'gesc3<...>.token.acme.invalid') is sure nice to have.

> all: (1) token (2) keyAuthorization (3) H(H(keyAuthorization)) (4)

I don't think there is any extra space in DNS for the query. IIRC,
there is 255 byte total length restriction for DNS QNAMEs in addition
to the 63 byte per-component limit.

-Ilari

---

From: Logan Widick <[email-masked]>
Date: Sat, 17 Jun 2017 08:47:23 -0500

Would it be possible to add a section for how to follow this pattern in the
presence of space constraints?

One possible way would be to divide H(H(kA)) and H(kA) into N pieces as
needed to get through the system. Each request would include the "piece
number" in some way so that the system can work even in the (probably rare)
event that pieces of either H(H(kA)) or H(kA) are identical. The ACME
server would make N requests (one for each of the N pieces). If N=1, the
piece number would be omitted and only 1 request would be made. In the
event of failure, the problem document could indicate the failing pieces in
an array.

That way, the same pattern works regardless of space constraints.

As for key comparison, here are some ideas:
1. Put the key thumbprint (produced using the same hash function H
specified in the challenge) in the revised key authorization structure in
lieu of the key. Include the key ID as another field in the key
authorization structure.
2. Require that only a given subset of JWK fields appears (like the fields
required for thumbprints). Include the key ID as another field in the key
authorization structure.

Sincerely,

Logan Widick

On Jun 14, 2017 10:22, "Ilari Liusvaara" <[email-masked]> wrote:

-Ilari

---

From: Ilari Liusvaara <[email-masked]>
Date: Sat, 17 Jun 2017 17:55:42 +0300

> event of failure, the problem document could indicate the failing pieces in

The even you call "probably rare" is in fact extremely unlikely. Even
under deliberate manipulation trying to make it happen.

In fact, if |kA| != |H(x)|, finding any such kA breaks the hash function
outright.

There are two places which have space constraints:

- DNS QNAME: Eating challenge space in addition to what already needs
  to be there is pretty harsh. Additionally, adding challenge there
  would break delegated setups.
- TLS certificate SAN names: The DNS 63 byte limit for name component
  may be relevant. Can be worked around by inserting a period in the
  middle of the challenge / response. The DNS name limit is not
  relevant: The postfixes are fixed, limiting the name to 85 bytes or
  so.

The primary reason for having challenge is for the target to find the
response(s) to return. In case of HTTP or TLS-SNI, returning multiple
responses at once is highly problematic (demultiplexing requests
problem). Not so with DNS: It can easily return multiple responses at
once (up to around 18 without fallback, around 1000 with fallback to
TCP).

And the reason for having the challenge and response be (statistically)
different is prevent careless servers from just copying the challlenge
to response and passing validation. TLS-SNI-01 has that problem (HTTP-01
does not, due to the account thumbprint being added).

> required for thumbprints). Include the key ID as another field in the key

Doesn't that put the same information in two places (which is legendary
source of all sorts of problems)?

Computing thumbprints and comparing those does not detect keys that are
different as the same, but can detect the same keys as different (due to
noncanonical representations. However, those are either illegal JWKs, or
just crazy, like RSA key with e > n).

-Ilari

---

From: Richard Barnes <[email-masked]>
Date: Wed, 21 Jun 2017 12:39:41 -0400

I'm going to retract my earlier proposal that we address this issue.
While the idea of better aligning the challenges is aesthetically
appealing, there seems to be agreement that there's not a major security
issue here.  And the spec has already passed WGLC with the existing set of
challenges.

So I would propose that we close this issue and PR #312 (
https://github.com/ietf-wg-acme/acme/pull/312), which implements one
solution.  If there is a continued desire to do work here, a follow-on spec
could define a harmonized set of challenges.

Chairs: What say ye?

--Richard

---

From: "Salz, Rich" <[email-masked]>
Date: Wed, 21 Jun 2017 16:48:01 +0000

>I'm going to retract my earlier proposal that we address this issue.   While the idea of better aligning the challenges is aesthetically appealing, there seems to be agreement that there's not a major security issue here.  And the spec has already passed WGLC with the existing set of challenges.

> So I would propose that we close this issue and PR #312 ... If there is a continued desire to do work here, a follow-on spec could define a harmonized set of challenges.

> Chairs: What say ye?

Agree to defer this to a possible future version.

Or, more simply, new challenges could be defined -- "now with more entropy" -- if there is a concern.