Let's Encrypt and IPv6

On one of my domains I had the following error message when trying to renew the Let’s Encrypt (LE) Certificate:

root@vm:~/dehydrated# bash dehydrated -f config -c
# INFO: Using main config file config
Processing domain.tld
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Jan 10 08:04:02 2021 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting new certificate order from CA...
 + Received 1 authorizations URLs from the CA
 + Handling authorization for domain.tld
 + 1 pending challenge(s)
 + Deploying challenge tokens...
 + Responding to challenge for domain.tld authorization...
 + Cleaning challenge tokens...
 + Challenge validation has failed :(
ERROR: Challenge is invalid! (returned: invalid) (result: ["type"]      "http-01"
["status"]      "invalid"
["error","type"]        "urn:ietf:params:acme:error:connection"
["error","detail"]      "Fetching http://domain.tld/...: Error getting validation data"
["error","status"]      400
["error"]       {"type":"urn:ietf:params:acme:error:connection",
 "detail":"Fetching http://domain.tld/...: Error getting validation data","status":400}
["url"] "https://acme-v02.api.letsencrypt.org/acme/chall-v3/..."
["token"]       "..."
["validationRecord",0,"url"]    "http://domain.tld/..."
["validationRecord",0,"hostname"]       "domain.tld"
["validationRecord",0,"port"]   "80"
["validationRecord",0,"addressesResolved",0]    "95.217.XXX.XXX"
["validationRecord",0,"addressesResolved",1]    "2a01:4f9:XXXX:XXXX::1"
["validationRecord",0,"addressesResolved"]      ["95.217.XXX.XXX","2a01:4f9:XXXX:XXXX::1"]
["validationRecord",0,"addressUsed"]    "2a01:4f9:XXXX:XXXX::1"
["validationRecord",0]  {"url":"http://domain.tld/...",
"hostname":"domain.tld","port":"80","addressesResolved":["95.217.XXX.XXX","2a01:4f9:XXXX:XXXX::1"],
"addressUsed":"2a01:4f9:XXXX:XXXX::1"}
["validationRecord"]    [{"url":"http://domain.tld/...","hostname":"domain.tld","port":"80",
"addressesResolved":["95.217.181.151","2a01:4f9:XXXX:XXXX::1"],"addressUsed":"2a01:4f9:XXXX:XXXX::1"}])

So, what went wrong? It took some time to figure it out and after some searching I learned that Let’s Encrypt prefers IPv6 now.[0] However, the server was listing only on IPv4 socket for HTTP connections. HTTPS connection had the keyword to listen on IPv6 enabled. Hence the fix was quite simple, just adding the listen [::]:80 to virtual host.

root@vm:~/dehydrated# bash dehydrated -f config -c
# INFO: Using main config file config
Processing domain.tld
 + Checking domain name(s) of existing cert... unchanged.
 + Checking expire date of existing cert...
 + Valid till Jan 12 18:34:42 2021 GMT (Less than 30 days). Renewing!
 + Signing domains...
 + Generating private key...
 + Generating signing request...
 + Requesting new certificate order from CA...
 + Received 1 authorizations URLs from the CA
 + Handling authorization for domain.tld
 + 1 pending challenge(s)
 + Deploying challenge tokens...
 + Responding to challenge for domain.tld authorization...
 + Challenge is valid!
 + Cleaning challenge tokens...
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!                                                                                                                                           
root@vm:~/dehydrated# /etc/init.d/nginx restart

Once the certificate was place and nginx was restarted everything seemed fine, expect for this error in Firefox:

Error code: SSL_ERROR_NO_CYPHER_OVERLAP

What the hell? The problem here is that LE uses ECDSA[1] nowadays. That’s a change that I’m not quite feeling comfortable with, because I’ve hardened the encryption chipers some time ago and it includes the following lines:

    ...
    ssl_protocols             TLSv1.2 TLSv1.3;
    ssl_ciphers '...:+SSLv3:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!P
SK:!DSS:!RC4:!SEED:!IDEA:!ECDSA:kEDH:CAMELLIA128-SHA:AES128-SHA';   
  ssl_prefer_server_ciphers on;
    ...

The important keyword is ‘!ECDSA’ that tell nginx to not allow ECDSA as a valid chiper for connections. For the moment, I’ve remove this entry to make it work, but I’m going to renew it with something else later. I also have to updated my knowledge about ECDSA, because it is rather briefly then details enough. Yet there were quite some good reasons not use it, I just can’t remember it.

so far,
akendo

[0] https://community.letsencrypt.org/t/error-getting-validation-data-status-400/50287
[1] https://letsencrypt.org/2020/09/17/new-root-and-intermediates.html