Repository: certbot/certbot

Issue:
Certbot sends GET request to the order URL
## My operating system is (include version):
Windows 10

## I installed Certbot with (snap, OS package manager, pip, certbot-auto, etc):
with OS installer

## I ran this command and it produced this output:
certbot.exe certonly --manual -d example.com
##other options are in config file
It sends GET request to order URL

## Certbot's behavior differed from what I expected because:
According to https://datatracker.ietf.org/doc/html/rfc8555#section-6.3 GET requests should only be
sent to NewNonce and Directory

## Here is a Certbot log showing the issue (if available):
###### Logs are stored in `/var/log/letsencrypt` by default. Feel free to redact domains, e-mail and IP addresses as you see fit.
2022-07-15 01:40:16,196:DEBUG:urllib3.connectionpool:https://server:443 "GET /acme/accounts/17845651851233067750/orders/14507744743890048869 HTTP/1.1" 405 77
2022-07-15 01:40:16,196:DEBUG:acme.client:Received response:
HTTP 405
Content-Type: application/problem+json
Content-Length: 77
Connection: keep-alive
Cache-Control: no-store
Replay-Nonce: MTMxMjc2NTU1MzEzNTc2MzA2MTc1MDQ0NTIxMDY1MDc2NTYyNzQ2MjUxNA

{"type":"urn:ietf:params:acme:error:malformed","detail":"method not allowed"}
## Here is the relevant nginx server block or Apache virtualhost for the domain I am configuring:



Discussion:
I think we will need more detail (like the full log file) to identify what's happening here.
Ah, I think I get it. Somehow certbot gets incorrect response - redirect 302 to thee order url after submitting CSR and then curl? just follows it:

```
2022-07-15 01:40:15,138:DEBUG:urllib3.connectionpool:https://server:443 "POST /acme/accounts/17845651851233067750/orders/14507744743890048869/csr HTTP/1.1" 302 713
2022-07-15 01:40:15,143:DEBUG:urllib3.connectionpool:Resetting dropped connection: pki.techcorpapps.com
2022-07-15 01:40:16,196:DEBUG:urllib3.connectionpool:https://server:443 "GET /acme/accounts/17845651851233067750/orders/14507744743890048869 HTTP/1.1" 405 77 
```

I suppose it has something to do with the fact that RFC8555 lists Location header in 200 response for csr request and somehow status gets changed to 302:

```
[RFC 8555](https://datatracker.ietf.org/doc/html/rfc8555)                          ACME                        March 2019

   HTTP/1.1 200 OK
   Replay-Nonce: CGf81JWBsq8QyIgPCi9Q9X
   Link: <https://example.com/acme/directory>;rel="index"
   Location: https://example.com/acme/order/TOlocE8rfgo

   {
     "status": "valid",
     "expires": "2016-01-20T14:09:07.99Z",
     "notBefore": "2016-01-01T00:00:00Z",
     "notAfter": "2016-01-08T00:00:00Z",
     "identifiers": [
       { "type": "dns", "value": "www.example.org" },
       { "type": "dns", "value": "example.org" }
     ],
     "authorizations": [
       "https://example.com/acme/authz/PAniVnsZcis",
       "https://example.com/acme/authz/r4HqLzrSrpI"
     ],
     "finalize": "https://example.com/acme/order/TOlocE8rfgo/finalize",
     "certificate": "https://example.com/acme/cert/mAt3xBGaobw"
   }
```

Unrelated issue is non-empty payload in POST-AS-GET to challenge url:

```
2022-07-15 23:16:00,842:DEBUG:acme.client:Sending POST request to https://server/acme/accounts/17845651851233067750/orders/11072510413633624695/authorizations/6301682414922894554/challenges/12698641033028031789:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAia2lkIjogImh0dHBzOi8vcGtpLnRlY2hjb3JwYXBwcy5jb20vYWNtZS9hY2NvdW50cy8xNzg0NTY1MTg1MTIzMzA2Nzc1MCIsICJub25jZSI6ICJNamN3TWpVek5qWTFOekl4TkRFd01qUXpNRE0yTURJeU5UTXhOalUzTlRBMk16SXdOREF3TWpjeCIsICJ1cmwiOiAiaHR0cHM6Ly9wa2kudGVjaGNvcnBhcHBzLmNvbS9hY21lL2FjY291bnRzLzE3ODQ1NjUxODUxMjMzMDY3NzUwL29yZGVycy8xMTA3MjUxMDQxMzYzMzYyNDY5NS9hdXRob3JpemF0aW9ucy82MzAxNjgyNDE0OTIyODk0NTU0L2NoYWxsZW5nZXMvMTI2OTg2NDEwMzMwMjgwMzE3ODkifQ",
  "signature": "FXtJLoX6qiJ5KxWLknP1G1oVMCWnlPaaqLykrJCDS6upocOYCPv49V4uNKWwlluOnaz-IW_vCQmA1DbAwHV_b8xlfNQY1SkMOjzZzInV22g_yrV9MTpJMb_1cjkF9WvqvLNfpN4hf-H1VhVs_F48OpMtHXp9T76fzUzoEUJ3NcmD7fXRxulXRjz9id1utq-QGGo_EMzxoV18zF9EIe18gm7uyKdpmP3xeJmoq8z2O4fPLxivmCYFQKoDo8Oyf6H1P0E2xHoxGNMOKIYNE0my0Z7c3ZljITneFJ2U9p0mBJB5VD5CVDS7IgSxma8cVukv0pD7HGD5DU1e_CXjQ4Od5g",
  "payload": "e30"
}
```
>Unrelated issue is non-empty payload in POST-AS-GET to challenge url:

Are you sure that this is a POST-as-GET? It looks like the challenge response to me: https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1.

>and somehow status gets changed to 302

This doesn't sound likely to me. If the Certbot log says that it received an HTTP 302 from your ACME server, then it probably did. 
> This doesn't sound likely to me. If the Certbot log says that it received an HTTP 302 from your ACME server, then it probably did.

If I read the log correctly, it's the ACME server sending a HTTP 302 to the initial POST which results in a [Post/Redirect/Get](https://en.wikipedia.org/wiki/Post/Redirect/Get). Sounds like a buggy ACME server to me.
Sorry if I wasn't clear. I don't think I've ever said that certbot changed the server's response. Of course, it was the server that sent 302. And I even tried to identify possible reasons for why it did it (RFC8555 lists it in its example with status code 200. Obviously, it is meaningless with 200. I think it might have been that the server's code was not explicit on the status code and later either php-fpm or nginx seeing the Location header, set 302. Anyway, this is no longer the issuer. I appoligise for creating this unnecessary issue and thanks for you help to understand what actually happened.

As the non-empty payload in POST-AS-GET concerns, I may not fully understand what challenge response means. But the log is clear, it is certbot's payload:
```
2022-07-19 14:43:33,175:DEBUG:acme.client:Sending POST request to https://pki.techcorpapps.com/acme/accounts/14336688870470774508/orders/7080861310268238649/authorizations/9240296490710005702/challenges/9636213494679776807:
{
  "protected": "eyJhbGciOiAiUlMyNTYiLCAia2lkIjogImh0dHBzOi8vcGtpLnRlY2hjb3JwYXBwcy5jb20vYWNtZS9hY2NvdW50cy8xNDMzNjY4ODg3MDQ3MDc3NDUwOCIsICJub25jZSI6ICJNekV6TnpReU1qYzBNRFl4TlRVeU56UTNOVFUyTnpReE1EYzNNelEyTXpFMk1EQTJNalEwTXpZeU5BIiwgInVybCI6ICJodHRwczovL3BraS50ZWNoY29ycGFwcHMuY29tL2FjbWUvYWNjb3VudHMvMTQzMzY2ODg4NzA0NzA3NzQ1MDgvb3JkZXJzLzcwODA4NjEzMTAyNjgyMzg2NDkvYXV0aG9yaXphdGlvbnMvOTI0MDI5NjQ5MDcxMDAwNTcwMi9jaGFsbGVuZ2VzLzk2MzYyMTM0OTQ2Nzk3NzY4MDcifQ",
  "signature": "m417cjrUktpgqWtcLlMFt6Qv-IqsaZLMtHQba7peJHAWDKuH4GjISpfvdAYe23wu61C-CCNbXOn5WcNXEzpqLMH4fjtGr8KB6j0pZmOSd9xB-3S3qjWE0WjpSOqwqipDoa50xitatkCYEcGeH8vnfn_wzFv-Qv9H739hMd5TsIM1v-UMQi7XZUtUSQdAlgOk6q1a-JWCGBZda8SMk8cMCKSDLJAwtqFw1nDHU-60OSjaXPFo44DdpXZ3MWrAVnJLRPYMcPL4zx4zfFqbGXXba3AoxRsD8VDQvcWmgHElO73gyJF1l-IoCRULiNW1PMEo-5D20wYC9V7bz7oOZw_e-A",
  "payload": "e30"
}
```
My understanding RFC8555 is that after I fulfiled the manual challenge (save the file in /.well-known/acme-challenge/, the certbot sends the POST-AS-GET request to that challenge url, indicating to the server that the challenge is complete and ready for verification.

Here is the reference - https://datatracker.ietf.org/doc/html/rfc8555#section-7.5.1

```
The client indicates to the server that it is ready for the challenge
   validation by sending an empty JSON body ("{}") carried in a POST
   request to the challenge URL (not the authorization URL).
```

Ah, sorry, I got it again. It's just the confusing language of empty body, when it actually says empty json body, so "e30" are actually "{}". Poor me ) Many thanks for leading me in the right direction!
This issue can be closed. I'd would really like if someone updates the certbot documentation in terms of explaining use of REQUESTS_CA_BUNDLE or CURL_CA_BUNDLE envvars to provide trusted root certs and that -eab-hmac-key is base64url encoding of raw key bytes. This would have made my experience with certbot ideal. In any case, it is the best ACME client I have tested so far.

Resolving patch:
diff --git a/certbot/certbot/configuration.py b/certbot/certbot/configuration.py
--- a/certbot/certbot/configuration.py
+++ b/certbot/certbot/configuration.py
@@ -170,7 +170,11 @@ def temp_checkpoint_dir(self) -> str:
 
     @property
     def no_verify_ssl(self) -> bool:
-        """Disable verification of the ACME server's certificate."""
+        """Disable verification of the ACME server's certificate.
+
+        The root certificates trusted by Certbot can be overriden by setting the
+        REQUESTS_CA_BUNDLE environment variable.
+        """
         return self.namespace.no_verify_ssl
 
     @property


Test patch: