Atrox1449
Atrox1449

Reputation: 101

NGINX SSL handshake error - sslv3 alert certificate expired:SSL alert number 45

I'm using NGINX for a DNS over TLS server.

However Android "private DNS" suddenly stopped working on all devices.

Using kdig still works as expected

kdig -d @my.dns.server +tls-ca +tls-host=my.dns.server example.org

However Android requests instead fail and I get the following error in NGINX logs

SSL_do_handshake() failed (SSL: error:14094415:SSL routines:ssl3_read_bytes:sslv3 alert certificate expired:SSL alert number 45) while SSL handshaking, client: **.**.**.**, server: 0.0.0.0:853

The cert is still valid however and I'm not sure why it's throwing this error.

My NGINX SSL config is

ssl_certificate /etc/letsencrypt/live/my.dns.server/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/my.dns.server/privkey.pem; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;

ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA";
ssl_handshake_timeout    10s;
ssl_session_cache        shared:SSL:20m;
ssl_session_timeout      4h;

Upvotes: 3

Views: 9338

Answers (1)

LuckyTurtleDev
LuckyTurtleDev

Reputation: 131

The Problem:

The DST Root CA X3 certificate, which letsencrypt uses, has expired. They had already started to use the new ISRG Root X1 certificate additionally for multiple years, but some old devices (for example android < 7.1.1) does not know this new certificate. This means these devices cannot use the new certificate and also should not be able to use the old one anymore.

But letsencrypt has noticed that many old ssl implementations (including android) don't check if a certificate has expired. So they can still use the old DST Root CA X3 certificate for these devices. Newer ssl implementation can use the new ISRG Root X1 certificate instead.

see: https://letsencrypt.org/2020/12/21/extending-android-compatibility.html

Sadly, some newer ssl implementation (including the android dot client) notice the old expired certificate and abort the ssl-connection, because the certificate has expired. They don't check the new certificate at all. Because of this implementation dependent behaviour, some newer programs don't work, but others work just fine.

The Solution:

To keep all newer ssl implementation working, you need to use only the new ISRG Root X1 certificate. To do this, you must use the ISRG Root X1 chain. But this will break the compatible with older device, which don't know the new ISRG Root X1 certificate yet.

If you use certbot you can use the following flag --preferred-chain "ISRG Root X1"

If you use the caddy webserver you can add the following lines to the beginning of your Caddyfile:

{
    preferred_chains {
        root_common_name "ISRG Root X1"
    }
}

Upvotes: 1

Related Questions