Subject: [Acme] Challenge retry ambiguities

From: Hugo Landau <[email-masked]>
Date: Thu, 15 Mar 2018 17:03:48 +0000

The specification as it stands seems to be a bit vague on the subject of

challenge retries.

It suggests that a challenge should be retried automatically by the server, and

that the challenge should remain in the "processing" state for this time. It

also states that the "invalid" state should be used after the server has given

up. It also states that the client should be explicitly able to request

retries.

This doesn't make sense. The implication is that "invalid" is a final state,

and the challenge cannot move back to "processing" after becoming "invalid". If

a server doesn't wish to make automatic retries, it has "given up" and the

specification thus dictates that the challenge move to "invalid", but this

makes it impossible to retry the challenge. This precludes an implementation

where the server e.g. only makes retries at the request of the client. For a

server which does make retries automatically, it also means the client's

ability to request retries ends when the server ceases to make retries

automatically, even though this is largely an internal detail of the server and

not really an exposed aspect of the API.

The language around how processing/invalid challenges interact with

authorizations is also unclear to me. The specification doesn't say anything

about whether a challenge becoming permanently "invalid" precludes attempting

another challenge in the same authorization.

Retries were added in the first place because the aggregation of multiple

authorizations into orders means quite a lot of progress in the issuance

process may be lost by a single challenge failure. But there still seem to be

issues with the specification as currently written: an authorization which

becomes "invalid" does so permanently and thus scuppers the entire order, which

may have a hundred authorizations.

IMO, challenges and authorizations should be evergreen, barring exceptional

events like administrative intervention. It would make more sense for

challenges to revert to "pending" when the server has given up. The attempts

are still recorded as challenge errors. The "invalid" state would only be used

administratively or if it is determined (for some reason) that completion of

the challenge is permanently impossible (no such cases arise in the current

HTTP/DNS challenges).

Separately, it's unclear what happens to an authorization when a challenge

becomes "invalid":

>If there is an error while the authorization is still pending, then the

>authorization transitions to the "invalid" state.

The meaning of "an error" here is unclear. Is the intention here that a

challenge becoming "invalid" precludes attempting any other challenge in that

authorization? This seems like a bad idea and will result in the creation of

excessive duplicate orders/authorizations. I'd argue an authorization should

become invalid iff all of its challenges become invalid.

---

From: Jacob Hoffman-Andrews <[email-masked]>
Date: Wed, 21 Mar 2018 16:11:59 -0700

> up. It also states that the client should be explicitly able to request

I think the idea here is that there's a window of time during which the
challenge is in "processing" state. During that time, the server can
choose to retry on some interval, and also the client can ask for early
retries (so a client who is trying different things. So long as the
server is willing to keep trying, it wouldn't transition into "invalid"
state.

This is discussed a bit more in the recently added "Status Changes"
section:
https://ietf-wg-acme.github.io/acme/draft-ietf-acme-acme.html#rfc.section.7.1.6.

"Note that within the “processing” state, the server may attempt to
validate the challenge multiple times (see Section 8.2). Likewise,
client requests for retries do not cause a state change."

> not really an exposed aspect of the API.

I understand this reading, although that's not the intent. A server that
wanted to offer retries only upon client initiation would simply leave
the challenge in "processing" state until the challenge's authorization
expired. Essentially, the server would never "give up" until expiration
time.

> The specification doesn't say anything

I think the intent of the spec is for this to be "server's choice."
Let's Encrypt treats failing any challenge as failing the whole
authorization, but in theory a different CA could do it differently.

> process may be lost by a single challenge failure.

I have to admit, even though I asked for retries to be added because I
was worried about this scenario, we have not actually implemented
retries at Let's Encrypt. Partly we reduced the resource consumption of
orders by moving CSR submission to the last step, and partly we realized
we can mitigate this problem by reusing authorizations (both pending and
valid) for subsequent orders.

Basically, I see that there's some possible refinement here, but I don't
think it will be resolved without someone implementing retries, and I
don't think we should delay finalization of the RFC to try and nail it
down. There will definitely be some corners that will be worked out as
deployment widens, and if necessary we can address those with errata and
a follow-on spec.