Mal wieder soweit: Mein aktuelles S/MIME-Zertifikat zum Signieren von E-Mails läuft aus. Also habe ich mir ein neues besorgt. Da GlobalSign keine Class-2-Zertifikate mehr für Privatpersonen anbietet, musste ich die CA wechseln. Durch Zufall bin ich auf SSLplus gestoßen – die haben echt gute Angebote für alle möglichen Zertifikate. Aber darum soll es in diesem Beitrag nicht gehen.
Wie immer will ich mein Zertifikat öffentlich zugänglich machen, sonst müsste jeder erst eine von mir signierte E-Mail erhalten, bevor er mein Zertifikat hat. Erst dann könnten Absender mir verschlüsselte E-Mails schicken.
Dafür gibt es ein experimentelles RFC 8162, das beschreibt, wie sich ein solches Zertifikat in einer DNSSEC-geschützten Zone veröffentlichen lässt. Natürlich gibt es im Internet wieder zig verschiedene Anleitungen und Wege, um das zu realisieren. Aber nichts wirklich Zuverlässiges, was ich finden konnte. Den DNS-Record für meine Bind9-Zone wieder manuell zu erstellen, hatte ich jedenfalls keine Lust.
Also habe ich zwei kleine Python3-Skripte geschrieben:
smimea_generate_record.py
Erstellt einen kopierbaren RR für die DNS-Zone. Kann interaktiv genutzt werden: Fragt nach E-Mail-Adresse und PEM-Zertifikat. Oder direkt mit Parametern aufgerufen werden. Prüft, ob E-Mail-Adresse und Zertifikat zusammenpassen, und gibt den fertigen Record aus.
./smimea_generate_record.py
Enter the email address: kernel-error@kernel-error.com
Enter the path to the PEM certificate: mail.pem
✅ Email 'kernel-error@kernel-error.com' matches the certificate!
🔹 **Generated BIND9 DNS Record:**
70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com. 3600 IN SMIMEA 3 0 0 (
30820714308204FCA003020102021073C13C478DA7B114B871F00737F1B0FB30
0D06092A864886F70D01010B0500304E310B300906035504061302504C312130
1F060355040A0C1841737365636F20446174612053797374656D7320532E412E
[... komplettes Zertifikat in Hex ...]
7573CA35477D59B98DE4852065F58FB60E0E620D3E2F5CAD
)
smimea_lookup.py
Fragt den SMIMEA-Record im DNS ab, lädt das Zertifikat herunter und prüft es mit OpenSSL auf Gültigkeit. Funktioniert interaktiv oder mit übergebenen Werten.
./smimea_lookup.py
Enter the email address: kernel-error@kernel-error.com
Querying DNS for SMIMEA record:
70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com
Certificate saved as smimea_cert.der
Certificate successfully retrieved and verified:
Certificate:
Data:
Version: 3 (0x2)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = PL, O = Asseco Data Systems S.A., CN = Certum SMIME RSA CA
Validity
Not Before: Mar 13 13:41:55 2025 GMT
Not After : Mar 13 13:41:54 2027 GMT
Subject: SN = van de Meer, GN = Sebastian, CN = Sebastian van de Meer,
emailAddress = kernel-error@kernel-error.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (4096 bit)
X509v3 Extended Key Usage:
E-mail Protection, TLS Web Client Authentication
X509v3 Key Usage: critical
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
X509v3 Subject Alternative Name:
email:kernel-error@kernel-error.com
Beide Skripte findet ihr auf GitHub, damit ihr sie nutzen oder verbessern könnt.
Warum viele Anleitungen falsch sind
Warum habe ich geschrieben, dass ich nichts Zuverlässiges finden konnte? Nun, oft stoße ich auf Anleitungen, die noch auf TYPE53 basieren. Das ist nötig, wenn Bind9 den eigentlichen RR-Type noch nicht kennt – also ein klares Zeichen dafür, dass es sich um eine sehr frühe Implementierung handelt.
Ein weiteres häufiges Problem: Der Hash des Local-Parts wird einfach weggelassen. Stattdessen erfolgen die Abfragen direkt auf _smimecert., was aber falsch ist. Ohne den SHA256-Hash des Local-Parts gibt es keine eindeutige Zuordnung zur jeweiligen E-Mail-Adresse.
Aufbau des SMIMEA-DNS-Records
Der erste Teil — der SHA256-Hash — sorgt dafür, dass nicht einfach jeder direkt aus der DNS-Zone die E-Mail-Adressen auslesen kann. Statt die E-Mail-Adresse im Klartext zu speichern, wird nur der SHA256-Hash des Local-Parts (also der Teil vor dem @) genutzt. Wer die genaue E-Mail-Adresse kennt, kann den passenden DNS-Eintrag finden — aber jemand, der blind durch die Zone scannt, sieht nur Hashes.
Der _smimecert-Prefix zeigt an, dass es sich um einen SMIMEA-Record handelt, ähnlich wie bei ._tcp. für SRV-Records oder _acme-challenge. für Let’s Encrypt. Und schließlich kommt die Domain, zu der die E-Mail-Adresse gehört.
Manuelle Abfrage mit dig
Möchte man die Abfrage manuell durchführen, muss man zuerst den Local-Part der E-Mail-Adresse mit SHA256 hashen. Laut RFC 8162, Abschnitt 3.1 wird der Hash auf die ersten 28 Bytes (56 Hex-Zeichen) gekürzt, um die DNS-Label-Längenbeschränkung von 63 Zeichen (RFC 1035, Abschnitt 2.3.4) einzuhalten:
echo -n "kernel-error" | sha256sum | awk '{print $1}' | cut -c1-56
70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0
Anschließend die dig-Abfrage:
dig +dnssec +short 70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com. SMIMEA
3 0 0 30820714308204FCA003020102021073C13C478DA7B114B871F00737
F1B0FB300D06092A864886F70D01010B0500304E310B30090603550406
[... Zertifikat in Hex ...]
Was bedeuten die Felder?
3 — Usage: End-Entity-Zertifikat (DANE-EE), also für die tatsächliche E-Mail-Verschlüsselung und Signatur
0 — Selector: Das komplette Zertifikat wird gespeichert (alternativ: 1 für nur den Public Key)
0 — Matching Type: Keine Hash-Funktion, das Zertifikat liegt im Klartext vor (alternativ: 1 für SHA-256, 2 für SHA-512)
- Hex-Werte — Der eigentliche Zertifikatsinhalt in hexadezimaler Darstellung
Manuelle Prüfung auf der Konsole
Den kompletten DNS-Record abrufen, die SMIMEA-Parameter (3 0 0) entfernen und als Hex-Datei speichern:
dig +short 70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com SMIMEA | sed 's/^3 0 0 //' | tr -d '[:space:]' > dns_cert.hex
Hex in eine binäre DER-Datei umwandeln und mit OpenSSL anzeigen:
# Hex → DER
xxd -r -p dns_cert.hex dns_cert.der
# Zertifikat anzeigen
openssl x509 -inform DER -in dns_cert.der -text -noout
Verbreitung und Ausblick
SMIMEA ist leider noch immer nicht besonders weit verbreitet. Das liegt daran, dass das RFC noch immer experimental ist, aber auch daran, dass es auf weiteren Techniken aufbaut, die ebenfalls eher selten genutzt werden. Man braucht SMIMEA nur, wenn man überhaupt ein S/MIME-Zertifikat zur Signatur und Verschlüsselung von E-Mails verwendet. Zusätzlich muss die Domain per DNSSEC geschützt sein — und dann muss auch noch der zusätzliche Mehrwert von SMIMEA verstanden werden.
Denn SMIMEA verteilt nicht nur die Zertifikate, sondern macht einen direkt initial verschlüsselt erreichbar. Wenn man der Empfänger einer solchen signierten Nachricht ist, kann man das Zertifikat zudem gegen eine vertrauenswürdige DNS-Zone halten und sich so vergewissern, dass es wirklich die Signatur des Absenders ist — ähnlich wie bei TLSA/DANE.
Die Implementierung ist aktuell sehr überschaubar. Es gibt Milter für beispielsweise Postfix oder Plugins für Thunderbird, aber vor allem im Enterprise-Umfeld ist mir momentan keine funktionierende Lösung bekannt.
Eigentlich wollte ich doch nur schnell schreiben, dass ich da zwei Python-Skripte zusammengebastelt habe — und am Ende ist es doch wieder so ein riesiges Ding geworden. Aber ich denke, vor allem der Teil mit dem gekürzten Hash des Local-Parts ist wichtig zu erklären. Das ist echt eine verrückte Konstruktion. Klar, das hat seinen Sinn, aber zumindest ich bin damals genau an diesem Punkt hängen geblieben.
Das einzig korrekt funktionierende Online-Tool, das ich finden konnte: co.tt/smimea.cgi. Alle anderen sind nicht erreichbar, halten sich nicht ans RFC oder ich war zu blöde, sie zu bedienen. Fragen? Einfach melden.