When does Let's Encrypt return "invalid" on challenge validation?

When submitting a challenge response, Let’s Encrypt responds with a validation status of “valid”, “invalid”, or “pending”[1].

Let’s Encrypt determines this status by hitting the preagreed endpoint and looking for proof of domain ownership.

If that endpoint returns X, Let’s Encrypt will give validation status Y. (shown as X: Y)

Status code 200, correct body: "valid"
Status code 200, wrong body: “pending”?
Status code 404: “pending”? “invalid”?
Status code 502: “pending”?

Can anybody clarify the 404 case specifically? I’m pretty unsure about most of the cases so if somebody has deeper knowledge or could point me to the specific code paths in the server that would be appreciated.

[1] I think it’s “pending” but it might be a different word. In any case my experience has been that this state allows Let’s Encrypt to poll for the endpoint until it becomes available (potentially with some short timeout).

1 Like

section 6.4 of the ACME spec covers this https://ietf-wg-acme.github.io/acme/

source code for boulder: https://github.com/letsencrypt/boulder :smiley:

1 Like

Thanks for your reply.

6.4 doesn’t appear to specifically cover my question. To be clear my question is under what circumstances does the server validate the challenge response, invalidate the challenge response, or decide to continue polling for the challenge response.

I will take a look at the boulder codebase but I haven’t dug into it before so I was hoping somebody could point me to the right package.

From reading the latest ACME docs it looks like I’m going to have to dig into the code to figure this out. The docs don’t specify what the polling behavior of the server is when validating a challenge response.

I'm not certain exactly what you want;

“invalid”: The certificate will not be issued. Consider this order process abandoned.
“pending”: The server does not believe that the client has fulfilled the requirements. Check the “authorizations” array for entries that are still pending.
“processing”: The server agrees that the requirements have been fulfilled, and is in the process of generating the certificate. Retry after the time given in the “Retry-After” header field of the response, if any.
“valid”: The server has issued the certificate and provisioned its URL to the “certificate” field of the order. Download the certificate.

My understanding is, when a client asks for a token to velidate a domain with, and it hasn't yet been tested - it's "pending"
If the client places a token on a server, then asks ACME to check it - and it gets an incorrect response - this is "invalid"
If it asks ACME to check the token, and it gets a correct response, then it's "valid"

1 Like

Hi @voutasaurus, thanks for the great question.

The answer from @serverco is accurate when it describes each status at a high level. Thanks @serverco!

If you're curious & want to go deeper I can provide some pointers! For conventions sake when I give a filepath it will be relative to the Boulder repo's top level directory. Most of the "action" happens in the Boulder validation authority (VA) component: va/va.go.

Each of the statuses in question are defined in core/objects.go as core.StatusInvalid, core.StatusValid, core.StatusPending and core.StatusProcessing.

  • core.StatusProcessing isn't used anywhere at present and can be ignored.
  • core.StatusPending is the default status of a new challenge once it has been created server side. You can see that in the newChallenge constructor function from core/challenges.go. If a challenge is in this state the Boulder VA hasn't attempted to perform a validation of the challenge.
  • core.StatusInvalid is the status used when the VA attempts to validate the challenge and fails. You can see where this happens in the PeformValidation function of the VA when there is a non-nil probs.ProblemDetails returned by the validateChalengeAndCAAA function.
  • core.StatusValid is the status used when the VA succeeds in validating a challenge. This happens immediately after the core.StatusInvalid case we discussed above.

Hopefully this helps!


Thanks for the details.

Briefly looking at the code it looks like the ACME server does not poll the challenge response endpoint at all, even if there is a network error. It dials out once and then that challenge is either valid or invalid from then on. This is a little surprising to me, but I’m glad I learned something here.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.