blog/content/posts/2024/dane-tlsa-record-for-letsencrypt/index.md

8.0 KiB

title slug description date draft ShowLastmod toc scrolltotop tags
How to create or renew a TLSA record for DANE with certificates from Let's Encrypt create-or-renew-tlsa-records I had to renew my TLSA records for DNS-based Authentication of Named Entities (DANE) on my server that uses SSL certificates from Let's Encrypt. 2024-10-03T09:26:58Z false true true true
email
server
security

I have been operating my own mail server for some 10 years. Recently, some e-mails that others attempted to send to me any my family would not longer be delivered. This is a very unfortunate situation, because most senders will not make a second attempt (e.g., with a different recipient address), leave alone provide you with an error message. However, luckily, this morning (Reunification Day in Germany!), I received this screenshot:

{{< figure src="outlook-error.jpg" alt="(German) screenshot of an e-mail delivery error due to an invalid TLSA record" caption="(German) screenshot of an e-mail delivery error due to an invalid TLSA record">}}

And then it was all clear to me. The resource records (RR) in my domain-name system (DNS) configuration that configure DNS-based Authentication of Named Entities (DANE) were no longer valid. I use certificates issued by Let's Encrypt, and evidently their chain of trust had changed so that the trust anchors that I had written into my DNS records were no longer valid.

Correctly setting up TLSA records for DANE is everything but trivial. After some trial and error, I found the following resource most useful:

https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html

Key points from this and other pages to remember:

  • When using TLSA RR in the form 2 1 1 ..., i.e., declaring that the payload (...) of the record is the digest of a "trust anchor", be aware that this must be the SHA256 digest of the public key of your trust anchor.
  • Let's Encrypt's certbot tool places three files on your server: cert.pem, chain.pem and fullchain.pem, where cert.pem is the mail server's certificate, chain.pem is the trust chain excluding the root CA and fullchain.pem is cert.pem + chain.pem. The important bit here is that none of these certificate files contain the root CA!
  • As a consequence, do not use a digest of Let's Encrypt's root CAs in your TLSA record, unless you want to add that root CA to the certificate files on your server (don't).
  • Configure TLSA records for all intermediate CAs, e.g., R10-R14.

Interstingly and embarassingly, the Information Sciences Institute (ISI) on their page linked to above has a list of mail servers that still use a TLSA record with a retired CA from Let's Encrypt -- and that list contains `bovender.de' :-/ I guess it's about time to fix that!

Let's Encrypt's chains of trust

Let's Encrypt's chains of trust are described here:

https://letsencrypt.org/certificates/

For the reasons mentioned above, we are not interested in the root CAs (ISRG Root X1 and ISRG Root X2). Instead, we want to use the digests of the public keys of the subordinate (intermediate) CAs. At the time of writing (2024-10), Let's Encrypt lists four active intermediate CAs:

  • E5 and E6 for certificates with ECDSA public keys
  • R10 and R11 for certificates with RSA public keys

To find out which of the two algorithms (ECDSA and RSA) was used to generate your mail server's certificate, ssh into your server, navigate to /etc/letsencrypt/live/<mailserver-certificate-name> as root and issue:

$ openssl x509 -in cert.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            03:d3:73:ef:60:97:31:88:bc:e5:31:99:f3:00:d5:b0:c1:92
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = US, O = Let's Encrypt, CN = R11
        Validity
            Not Before: Sep 24 22:37:51 2024 GMT
            Not After : Dec 23 22:37:50 2024 GMT
        Subject: CN = bovender.de
        Subject Public Key Info:
# ...

Thus, my mail server's current (!) certificate was issued by R11.

This may be different in the future when the certificate is renewed.

Currently my web server's certificate uses the ECDSA algorithm:

$ cd ../bovender/
$ openssl x509 -in cert.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            04:22:00:17:8a:ed:51:09:56:15:62:2e:b5:85:49:70:05:ac
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = US, O = Let's Encrypt, CN = E6
        Validity
            Not Before: Aug 19 11:34:11 2024 GMT
            Not After : Nov 17 11:34:10 2024 GMT
        Subject: CN = bovender.de

This certificate was issued by the E6 intermediate CA.

An alternative way to find out more about a web server's SSL certificate is to use curl:

$ curl -I --write-out '%{certs}' https://bovender.de
HTTP/2 301
server: nginx/1.27.1
date: Thu, 03 Oct 2024 09:25:05 GMT
content-type: text/html
content-length: 169
location: https://www.bovender.de/
strict-transport-security: max-age=63072000; includeSubDomains; preload

# ...

Subject:C = US, O = Let's Encrypt, CN = E6
Issuer:C = US, O = Internet Security Research Group, CN = ISRG Root X1

# ...

-----END CERTIFICATE-----

E6 again (surprise!).

The key type that certbot uses to renew certificates is contained in /etc/letsencrypt/renewal/<mailserver-certificate-name>.conf:

$ cat mail.conf
# renew_before_expiry = 30 days
version = 2.11.0
archive_dir = /etc/letsencrypt/archive/mail
cert = /etc/letsencrypt/live/mail/cert.pem
privkey = /etc/letsencrypt/live/mail/privkey.pem
chain = /etc/letsencrypt/live/mail/chain.pem
fullchain = /etc/letsencrypt/live/mail/fullchain.pem

# Options used in the renewal process
[renewalparams]
account = [REDACTED]
authenticator = webroot
server = https://acme-v02.api.letsencrypt.org/directory
key_type = rsa
# ...

The line key_type declares that RSA be used for my mail server's certificate.

Setting up TLSA RRs in your DNS zone

As advised by ISI.edu, it is best practive to have TLSA records for all possible intermediate CAs as you will never know which intermediate CA will be the next to issue a renewed certificate. This is even more important if you have a cron job set up to automatically renew certificates that are about to expire.

For the record (pun intended), here are my _25._tcp entries. Everything after the pound sign (#) MUST NOT be included in the record, of course.

2 1 1 2bbad93ab5c79279ec121507f272cbe0c6647a3aae52e22f388afab426b4adba # R10
2 1 1 6ddac18698f7f1f7e1c69b9bce420d974ac6f94ca8b2c761701623f99c767dc7 # R11

Following the advice by viktor on ISI.edu, I have left only those two records in my DNS zone that represent currently used intermediate CAs (R10 and R11). I know that certbot will not issue ECDSA certificates for my mail server because the configuration file (see above) contains the line key_type=RSA. My web server has an ECDSA certificate, but I currently see no use for DANE for my web server as Chrome and Firefox do not support it.

Verify the validity of the TLSA record

To test that DANE works as expected, try one of these sites:

Query TLSA records:

"Die Moral von der Geschicht"

"The moral of the story":

  • Server administration was, is, and will always be complicated.
  • Always mistrust yourself.
  • Regularly verify that everything works as expected, especially security-related stuff.
  • If something does not work, spend more time researching on the world wide web. I came across the ISI.edu page only after several hours and is was far more useful for me than all the websites and blog and forum posts that I had previously read.