Because nobody has this documented it seems:

If you want to generate TLSA records in Python (possibly because you use Python-based tooling like fabric or ansible) and want to do that using the well-known modern cryptography library, the internet doesn’t tell you how to. It actually is not that difficult, as show below.

This code expects a certificate in pem format, and will then print two records you can put into DNS. The examples given are tailored to DANE for SMTP which you should be using for mail.

The first line gives a digest of the public-key, the second one a digest of the whole certificate. If you are able to reuse the keypair when rotating certificates, the first variant will stay the same, meaning you won’t have to update DNS on every key rotation.

import hashlib

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat

with file('cert.pem', 'r') as f:
    mx_pem_cert = f.read()
mx_cert = x509.load_pem_x509_certificate(mx_pem_cert, default_backend())

mx_pubkey = mx_cert.public_key()
mx_pubkey_bytes = mx_pubkey.public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
digest = hashlib.sha256(mx_pubkey_bytes).hexdigest()
print(f'_25._tcp.example.com TLSA 3 0 1 {digest}')

mx_der_certbytes = mx_cert.public_bytes(Encoding.DER)
digest2 = hashlib.sha256(mx_der_certbytes).hexdigest()
print(f'_25._tcp.example.com TLSA 3 1 1 {digest2}')

Next step then is to use something like dns-lexicon to actually provision your DNS provider.

Good luck automating all the things.

Version history

2022-01-30: updated to use more modern python idioms


Published

Category

tricks

Tags