Challenge is not checked by acme-staging-v02


#1

New account has been successfully created via v02 But the validation is where I’m stuck and looking for help.

Here is what I’m doing:

  1. GET https://acme-staging-v02.api.letsencrypt.org/directory -> OK
    answer: nonce

  2. POST https://acme-staging-v02.api.letsencrypt.org/acme/new-order -> OK
    body: protected + payload(‘domain’) + signature
    answer: nonce, authorization url, finalize url

  3. GET https://acme-staging-v02.api.letsencrypt.org/acme/authz/ xxxx -> OK
    “type”: “http-01”,
    “status”: “pending”,
    “url”: “/acme/challenge/xxxx”,
    “token”: “yyy”
    After creating file .well-known/acme-challenge on my end with $token.$thumb I I send

  4. GET https://acme-staging-v02.api.letsencrypt.org/acme/challenge/xxxx -> OK
    But my server is never accessed and I don’t understand why.

If I send POST-as-GET with empty payload on 3rd step I get following answer from acme server
“type”: “urn:ietf:params:acme:error:malformed”,
“detail”: “Invalid status value”,
“status”: 400

What I’m missing here?
Thanks


#2

Hi @serghey_rodin,

Your client needs to send a POST request with the trivial JSON JWS Body {} in this step to initiate the challenge. Note, this is different from a POST-as-GET request that would send a null JWS body.

The relevant draft specification section is https://tools.ietf.org/html/draft-ietf-acme-acme-16#section-7.5.1

The client indicates to the server it is ready for the challenge validation by sending an empty JSON body ("{}"), carried in a POST request to the challenge URL (not authorization URL).

Hope that helps!


#3

Thanks! It worked… almost

  1. GET https://acme-staging-v02.api.letsencrypt.org/directory -> OK
    nonce1 received

  2. POST https://acme-staging-v02.api.letsencrypt.org/acme/new-order -> OK
    nonce2 received

  3. GET https://acme-staging-v02.api.letsencrypt.org/acme/authz/xxxx -> OK
    There is no nonce3 in reply so for my next post request Im gonna reuse nonce2
    Creating file .well-known/acme-challenge on the server

  4. POST https://acme-staging-v02.api.letsencrypt.org/acme/challenge/xxxx -> Bad Request / 400
    {
    “type”: “urn:ietf:params:acme:error:badNonce”,
    “detail”: "JWS has an invalid anti-replay nonce: “nonce1"”,
    “status”: 400
    }
    Hmm but why? I used trivial JWS body like you suggested and I used second nonce since there was no third one. And why first nonce displayed in error detail. I tried to send first nonce instead second but it didn’t help either. IETF draft says that in this case I can use nonce from this reply and resend my request. That’s what I did and ta-da it worked

  5. POST https://acme-staging-v02.api.letsencrypt.org/acme/challenge/xxxx -> OK

    “type”: “http-01”,
    “status”: “valid”,
    “url”: “https://acme-staging-v02.api.letsencrypt.org/acme/challenge/CromOAeKJDlQLjAe9-zLMIeNgEnBfIZye3g1jzVLCkg/205381125”,
    “token”: "hXxSWTzpBTgGg0He1tcv8

But to me it looks like a problem that I can’t form a valid request and have to request new nonce. I’m attaching full debug output from my client just in case you want to take a look at headers
Thanks
acme-chat.txt (10.6 KB)


#4

Hi @serghey_rodin

you can use one nonce only one time. So if you want to reuse a nonce, this is an error.

Fetch a new nonce.


#5

Sorry I wasn’t very clear there. I didn’t use nonce twice I meant that I used second nonce to form 4th request because there was no reply-nonce after 3rd. Here simplified step by step process

.
Step 1

  • first nonce after requesting GET-> /directory

Step 2

  • first nonce used to place new order “/acme/new-order”
  • second nonce received as answer to POST -> " /acme/new-order"

Step 3

  • didn’t use second nonce to make GET acme/authz/xxxx
  • didn’t receive third nonce either

Step 4

  • using second nonce to make POST to acme/challenge/xxxx
  • receiving error with a new nonce a third one

Step 5

  • using third nonce to resend POST to acme/challenge/xxxx
  • all is good except that I wasn’t able to form a valid request on step 4 and had to rely on fallback procedure

#6

Your error says that you have used an invalid nonce. Did you wait too long?

Nonces have only a short TTL.

So if your program waits 5 minutes (DNS propagation etc.), then fetch a new nonce.


#7

This communication takes less than 5 seconds. To be precise it takes 3.398s so pretty quick.

My current implementations looks ugly to me because I have to resend post request twice but I don’t understand what’s wrong and why there is always content of the first nonce in the answer:

GET /directory -> OK -> receiving nonce1
POST /acme/new-order -> sending nonce1 -> OK -> receiving nonce2
GET /acme/authz/xxxx -> OK -> didn’t receive a nonce
POST /acme/challenge/xxxx -> sending nonce2 -> Bad Request -> receiving nonce3

{
  "type": "urn:ietf:params:acme:error:badNonce",
  "detail": "JWS has an invalid anti-replay nonce: \"content of the nonce1\"",
  "status": 400
}

POST /acme/challenge/xxxx -> sending nonce3 -> OK -> receiving nonce4

I also tried to make GET and use reply-nonce from it but it didn’t help and again I see a weird relation to first nonce in the answer.
GET /directory -> OK -> receiving nonce1
POST /acme/new-order -> sending nonce1 -> OK -> receiving nonce2
GET /acme/authz/xxxx -> OK -> didn’t receive a nonce
GET /acme/challenge/xxxx -> OK -> receiving nonce3
POST /acme/challenge/xxxx -> sending nonce3 -> Bad Request -> receiving nonce4

{
  "type": "urn:ietf:params:acme:error:badNonce",
  "detail": "JWS has an invalid anti-replay nonce: \"content of the nonce1\"",
  "status": 400
}

POST /acme/challenge/xxxx -> sending nonce4 -> OK -> receiving nonce5


#8

HI @serghey_rodin,

This was very useful, thanks for sharing.

Nonce’s aren’t sent for GET requests to URLs, only POST and HEAD requests. You can also use the explicit newNonce endpoint.

Looking at your log I think your code is saying its using nonce2 (VWE68SLTym-Ap0d5QcBDRj3iipfe5UuWBNrvGjO5QKI) but when I decode the protected field of the JWS used in the subsequent curl -s -i -d command I see "nonce": "Z13l3uFpQOhNIPt6CAJF8XGIfx4VgOs2wEp3Czs82Ck" which is nonce1 and the nonce included in the error message.

The errors seem correct to me given the logs and I think you have a bug somewhere.


#9

Oh that makes sense. Thank you very much!


#10

I noticed you’re using GET for a lot of endpoints (authz, challenge, etc) that are now deprecated for use with GET requests. If you’re actively working on new client code, you should definitely migrate to using POST-as-GET for those endpoints. The GETs will continue to work only until November 2019.

See the original announcement here:

And some additional discussion here:

In short, the only endpoints that will support GET after November 2019 are directory and newNonce (and newNonce should ideally use HEAD instead).