DNSSEC and Postfix DANE Security

DNS is a core Internet technology invented in RFC 882/883 during late 1983 with the first implementation in 1984. In a nutshell it is a hierarchical distributed database that allows information to be stored and retrieved using both a domain name and record type as keys to the value to be retrieved. The domain name is often called the record owner and often does not correspond to a routable IP address (when there are no A or AAAA type records for it).

There are two core types of nameservers, authoritative resolvers and recursive resolvers. Some recursive resolvers are a special type of recursive resolver called a caching resolver, they simply ask another recursive resolver for the answer if they do not have it already cached, and cached but make no attempt to query authoritative nameservers themselves. These are common in home network routers and sometimes are used on servers too.

Authoritative resolvers only have answers for ‘zones’ they are authoritative for, they will not attempt to find answers for zones they are not authoritative for. Recursive resolvers on the other hand are not authoritative for any zones. They try to find the nameserver that is authoritative and ask that nameserver for the answer to the query.

When software you are using needs an answer to DNS question, it will ask the name resolution facilities of your operating system. Your operating system may already have the answer cached. When your operating system does not have it cached, your operating system will ask the recursive resolver it is configured to use.

Assuming your caching resolver does not already have the answer cached, the caching resolver will ask one of the thirteen authoritative root nameservers. Usually the answer is not in the root zone, but the root zone will respond with the authoritative nameservers for the Top Level Domain (e.g. .com or .nl or .video etc.) zone the query falls within.

The recursive resolver then asks one of the authoritative nameservers for the TLD zone which also usually does not have the answer itself, but responds with the authoritative nameservers for the vanity domain name zone the answer likely falls within. One of those nameservers generally is able to either give the answer or respond that there is no answer.

The recursive resolver can then respond to the query by your operating system, and it usually will cache the answer so that it can answer right away when other query for the same domain name and record type is requested before the life of the answer has expired.

It is a beautiful system and the core of the Internet as we know it, but as originally implemented, it had one major design flaw. There was no mechanism by which the authenticity of the answer could be validated. The recursive resolvers trusted that the answers they were getting were not modified in transit from the authoritative nameservers, and your operating system trusted that the answer it received was not modified in transit from the recursive resolver it queried. DNSSEC fixes that flaw by providing a mechanism for validating the response.

How DNSSEC Works

DNSSEC uses public/private key cryptography to provide signatures for DNS responses that can be used to verify the response has not been modified in transit. Each zone that is protected by DNSSEC has a Key Signing key pair and a Zone Signing key pair.

The private Zone Signing Key is used to create the signatures for the records in your zone file. The public key is also in your zone file. That public key can be used to verify the that the other records have not been modified.

The public Zone Signing Key is in turned signed by your private Key Signing Key, and the public Key Signing Key needed to verify the authenticity of the Zone Signing Key is also in your zone file. To authenticate the Key Signing Key, a fingerprint (called a DS record) of your public Key Signing Key is in your parent zone, typically your Top Level Domain zone, where it is signed by their Zone Signing Key.

The Zone Signing Key for a TLD is authenticated by their Key Signing Key, which in turn is authenticated by a DS record in the root zone, which is authenticated by the Zone Signing Key for the root zone, which is authenticated by the Key Signing Key for the root zone.

The public Key Signing Key for the root zone has to be implicitly trusted by your DNSSEC validating software.

Like the PKI system, DNSSEC is built on a chain of trust that your private key and the private keys of those above you have not been compromised. Similar to Certificate Transparency, DNSSEC could be improved if there were transparency logs every time the Key Signing Key for a zone is updated.

Zone Signing Keys are generally rotated with some frequency. It is recommended to rotate them once a month. I rotate mine once a week. Key Signing Keys are rotated with less frequency, rarely more often than once a year and generally far less often.

If you use static zone files, like many of us do, there is no need for your private signing keys to even be on your authoritative nameserver. Rather, you upload a signed zone file. On the other hand if your authoritative nameserver creates dynamic responses, it needs to have the private Zone Signing Key so it can sign those dynamic responses. You authoritative nameserver does not however need to have the private Key Signing Key, that is only needed to sign the static record with your public Zone Signing Key.

Deploying DNSSEC

Unless the topic of DNSSEC is something you really dig (pun intended) for the cryptographic beauty of it, like I do, I do not recommend deploying DNSSEC on your zone yourself. The risk of bricking your zone is just too high if you screw up, and it has happened and will continue to happen as system administrators take it on themselves. The list at https://ianix.com/pub/dnssec-outages.html should scare you.

But please do not let that list deter you. Rather, let it motivate you to get things right. Do your research before attempting to deploy it yourself. It is better to outsource DNS services to someone you can sue when they fuck things up majorly. Those companies tend to have a financial motive to do things right, fix them quickly when they do not do things right, and have knowledgeable people they can contact 24/7 to fix things when they break.

I can not recommend one, I have been running my own for years so I do not have experience with the services.

For me personally, the only issue I ever experienced, a DS record of mine mysteriously disappeared from the .org Top Level Domain. That resulted in e-mail delivery problems for mail servers using a dane-only policy because they could no longer validate the TLSA record.

The ease in which DNS records that are not protected can be actively modified by an attacker, including the government and malicious black hats, that should be what scares you into deploying DNSSEC. It is a serious problem that costs billions of dollars. If the DNS results for your zone can not be validated then they can not be trusted and your business is open for attack.

DANE — What Is It?

When a zone is signed with DNSSEC, we have cryptographic confidence in the results of a query. We can demonstrate with very high confidence the results of the query have not been modified. In fact with the exception of EV certificates, we can have higher confidence than we have when using the PKI system to validate the x.509 certificates we trust for encrypted communications on the web.

DANE stands for DNSSEC Authenticated Named Entities. It leverages the confidence we can have in DNSSEC signed zones to give verification to the identities tied to cryptography public keys.

In the context of public keys in an x.509 certificate used with an Internet service, this is done with a TLSA record, as defined in RFC 6698 (updated by RFC 7218 and RFC 7671.

There are two components to utilizing a TLSA record, the Domain Name to query and the Record Data (RDATA) returned from the query.

TLSA Domain Name

While it is possible to use an x.509 certificate associated with an IP address with client/server Transport Layer Security, that is neither the norm nor can it be validated with a TLSA record. A TLSA record is used to validate an x.509 certificate for use with a specific port (such as 25 for MX SMTP or 443 for HTTPS), Internet Protocol (almost always TCP but hypothetically could also be UDP), and hostname.

The domain name (sometimes called owner) of a usable TLSA record starts with an underscore followed by the integer port number and a period. This is followed by a second underscore and the Internet Protocol and another period, followed by the full domain name of the service the x.509 is to secure.

The Domain Name for a TLSA record securing this website, for example, would be _443._tcp.librelamp.com. (note the ending dot).

If a client wants to use DANE to validate the x.509 certificate used with this website, it would request the TLSA record associated with that domain name:

[alice@localhost ~]$ dig TLSA +short _443._tcp.librelamp.com.
3 0 1 F311DBE35A529E381C06B6A5FBC7E1C381FB9ED11218F6E16A3359A2 040C4887

The record returned is the Record Data that can be used to validate the x.509 certificate.

NOTE: F311DBE35A529E381C06B6A5FBC7E1C381FB9ED11218F6E16A3359A2 040C4887 should not have a space in it, that is a bug with the output of the dig utility, it inserts spaces into long RDATA fields.

TLSA Record Data

There are four components to a TLSA Record Data field:

  1. The Certificate Usage Field
  2. The Selector Field
  3. The Matching Type Field
  4. The Certificate Association Data Field

The first three should be seen as meta-data about the fourth, how a TLSA validator should interpret the fourth.

The Certificate Usage Field

This will be an integer value between 0 and 3 inclusive.

A value of 0 indicates the Association Data Field is not for the certificate the server sends itself, but for a Trust Anchor that has signed the certificate the server sends. It also indicates the TLSA validator should validate the certificate through the PKI system.

There are not any circumstances I can think of as to why a value of 0 would be beneficial to use. In the context of DANE for SMTP it is not legal to use a value of 0 in this field.

A value of 1 indicates the Association Data Field is for the certificate itself (End Entity). It also indicates the TLSA validator should validate the certificate through the PKI system.

There are not any circumstances I can think of as to why a value of 1 would be beneficial to use. In the context of DANE for SMTP it is not legal to use a value of 1 in this field.

A value of 2 indicates the Association Data Field is not for the certificate the server sends itself, but for a Trust Anchor that has signed the certificate the server sends. It also indicates the TLSA validator should NOT attempt to validate the certificate through the PKI system.

Generally this value should not be used. Where it is beneficial are scenarios where you frequently change the private key and get a new certificate issued but signed by the same Trust Anchor.

A value of 3 indicates the Association Data Field is for the certificate itself (End Entity). It also indicates the TLSA validator should NOT attempt to validate the certificate through the PKI system.

This is almost always what you want to use.

The Selector Field

This will be an integer value of either 0 or 1.

A value of 0 indicates the Association Data Field is in the context of the full binary structure of the x.509 certificate as defined in RFC 5280.

It is common for DANE related tutorials on the Internet to instruct the user to use a 0 here. I personally do not like to because it requires changing the Association Data Field every time the certificate is re-issued even if the Private Key did not change. With short-lived certificates that is really inconvenient.

A value of 1 indicates the Association Data Field is in the context of the SubjectPublicKeyInfo DER-encoded binary structure as defined in RFC 5280.

This is my preferred option. It only requires updating the Association Data field when the private key changes, and it can be generated from the private key itself before you have been issued an x.509 certificate.

The Matching Type Field

This will be an integer value between 0 and 2 inclusive.

A value of 0 indicates the Association Data Field contains either the entire certificate data or the SubjectPublicKeyInfo (depending upon the Selector field). Please do not do this. The data is already sent to the client as part of the TLS handshake, including it in a DNS is both redundant and it really bloats the size of the record.

A value of 1 indicates the Association Data Field contains an SHA-256 hash of the data. This is almost always what you want to use.

A value of 2 indicates the Association Data Field contains an SHA-512 hash of the data. This bloats the size of the record and should only be done if and when a collision is found in SHA-512.

The RFC suggests using the same algorithm used for the certificate in order to reduce the number of hash algorithms required by the client. Usually that will be SHA-256 anyway, but even if your certificate uses SHA-512 it is very unlikely any client will support SHA-512 that does not also support SHA-256 so just use SHA-256.

The Certificate Association Data Field

This is the actual data that is used to validate the x.509 certificate. Usually it will be a hex-encoded SHA-256 hash, I have personally never seen the full data or a SHA-512 hash used in the wild, though I suppose someone somewhere is.

If I have convinced you to create what I call a ‘3 1 1’ record (an SHA-256 hash of the SubjectPublicKeyInfo from the certificate you will be serving), you can generate it either from the private key or from the certificate if you already have the certificate.

To generate it from the private key:

[root@host ~]# /usr/bin/libressl pkey -outform DER -in /path/to/private.key \
  |/usr/bin/libressl dgst -sha256 -binary \
  |/usr/bin/hexdump -ve '/1 "%02x"'

If you would like to generate it from the certificate instead:

[user@host ~]$ /usr/bin/libressl x509 -in /path/to/certificate.crt -noout -pubkey \
  |/usr/bin/libressl pkey -pubin -outform DER \
  |/usr/bin/libressl dgst -sha256 -binary \
  |/usr/bin/hexdump -ve '/1 "%02x"'

Either method will generate a SHA-256 fingerprint that only needs to be changed when you change the actual private key. Either method works for either RSA or ECDSA key pairs.

BIND / NSD Compatible Zone File Entry

This is what e-mail related TLSA records might look like in your zone file (Association Data Field hash value shortened with for horizontal display space reasons):

_25._tcp.mx1.example.net.     IN    TLSA   ( 3 1 1 e692975369bb…ceac84c213af )
_25._tcp.mx2.example.net.     IN    TLSA   ( 3 1 1 9e2d190313ff…0768ffd311a3 )
_25._tcp.mx3.example.net.     IN    TLSA   ( 3 1 1 047dd4f2822e…9c01f1d6a49c )
_465._tcp.smtp.example.net.   IN    TLSA   ( 3 1 1 32cac031ce77…cc657e33f882 )
_993._tcp.imap.example.net.   IN    TLSA   ( 3 1 1 0a446661c1b4…1f31afe94c38 )

Note the () around the record data. That's important, it tells the name server software it all belongs together despite the spaces.

Note that at this time, I am not aware of any Mail User Agents that DANE validate, so the records that correspond with Port 465 (SMTPS Submission) and Port 993 (IMAPS) are likely not actually currently beneficial, but they also do not hurt.

TLSA records are definitely beneficial on Port 25 for your MX servers, many client MTAs sending mail to your mailbox domain will use a secure channel that is simply not vulnerable to fraudulently signed CA certificates when Port 25 TLSA records exist.

TLSA Record Rotation

It is a good idea to generate new private keys for TLS on a yearly basis. A new private key will result in a public key that has a different fingerprint than the old public key.

Due to caching issues, changes to DNS often take three or four hours to properly propagate, sometimes even longer with caching resolvers that cache answers longer than they should.

First, create your new private key. Optionally you can get the new x.509 certificate at the same time but do not put it into service yet.

Second, update your DNS zone file to include a new TLSA record that reflects the new private key. Leave the old TLSA record in the zone file, it is still needed.

Third, about twenty-four hours after the new TLSA record has been added to your DNS zone, you can get an x.509 certificate based on that private key if you do not already have one, and put it into service.

Fourth, once Postfix has been restarted using your new certificate based on the new key, you can remove the old TLSA record.


Personally I generate new private keys in January, and I do it every January.

If you use Let’s Encrypt, the certificates are only good for 90 days so you need to get new certificates every other month. However if you use the shell scripts I provide to generate them, they only result in new private keys the first time they are run in the calendar year, so as long as you create what I call a ‘3 1 1’ records, you still only have to rotate the TLSA record once a year.

All of the shell scripts I provide will create a file in /etc/pki/tls/tlsa/ with the same name as the corresponding private key except ending in .tlsa instead of .pvt that has the necessary TLSA data for a ‘3 1 1’ record.