---
title: "How to create or renew a TLSA record for DANE with certificates from Let's Encrypt"
slug: create-or-renew-tlsa-records
description: >
  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.
date: 2024-10-03T09:26:58Z
draft: false
ShowLastmod: true
toc: true
scrolltotop: true
tags:
  - 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)][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:

```text
$ 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:

```text
$ 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`:

```plain
$ 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`:

```plain
$ 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][isi], 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.

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

Following the advice by _viktor_ on [ISI.edu][isi], 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][dane].

## Verify the validity of the TLSA record

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

- <https://www.mailhardener.com/tools/dane-validator?domain=bovender.de>
- <https://dane.sys4.de/smtp/bovender.de>

Query TLSA records:

- <https://www.nslookup.io/domains/_25._tcp.bovender.de/dns-records/tlsa/>

## "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][isi] 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.

---

# Addendum 2026-04-22

## How to produce the certificate-associated data for the TLSA record?

The certificate associated data is a SHA-256 or SHA-512 checksum, depending
on the third number.

```plain
2 1 1 cbbc559b44d524d6a132bdac672744da3407f12aae5d5f722c5f6c7913871c75 # E7
#     ^^^ this is the certificate-associated data in the TLSA record
```

```bash
openssl x509 -in E7.der -pubkey -noout | openssl ec -pubin -outform der | openssl sha256
```

### Obtain the hash for the certificate itself (DANE-EE)

Given a ECDSA key in `cert.pem`:

```bash
openssl x509 -in cert.pem -pubkey -noout | openssl ec -pubin -outform der | openssl sha256
```

Use the resulting hash in

```plain
3 1 1 HASH
```

[dane]: https://en.wikipedia.org/wiki/DNS-based_Authentication_of_Named_Entities
[isi]: https://dnssec-stats.ant.isi.edu/~viktor/x3hosts.html
