IT-Blog von Sebastian van de Meer

Kategorie: E-Mail & Mailserver (Seite 1 von 8)

Mailserver-Praxis mit Postfix und Dovecot — SPF, DKIM, DMARC, DANE, MTA-STS und Spam-Abwehr mit Rspamd.

Post-Quantum TLS für E-Mail — Postfix und Dovecot mit X25519MLKEM768 auf FreeBSD 15

Visualisierung hybrider Post-Quantum-TLS-Verschlüsselung für E-Mail mit X25519MLKEM768 (ML-KEM-768 + X25519) auf Postfix und Dovecot unter FreeBSD 15

Nachdem ich im letzten Beitrag OpenSSH mit hybriden Post-Quantum-Algorithmen abgesichert habe, lag die Frage nahe: Was ist eigentlich mit E-Mail? Mein FreeBSD 15 liefert Postfix 3.10.6, Dovecot 2.3.21.1 und OpenSSL 3.5.4 – und genau diese Kombination bringt alles mit, was man für quantensichere Verschlüsselung im Mailverkehr braucht. Ohne zusätzliche Pakete, ohne Patches, ohne Gefrickel.

Warum überhaupt PQC für E-Mail?

Das „Store now, decrypt later„-Szenario, das ich beim SSH-Beitrag angesprochen habe, trifft auf E-Mail mindestens genauso zu. E-Mails werden über SMTP zwischen Servern transportiert – und dieser Transport ist grundsätzlich abfangbar. Wer heute TLS-verschlüsselten Mailverkehr mitschneidet und archiviert, könnte diesen in einigen Jahren mit einem ausreichend leistungsfähigen Quantencomputer entschlüsseln. Zumindest theoretisch.

Heißt das, morgen liest jemand eure Mails? Nein. Aber wenn ihr vertrauliche Kommunikation betreibt und die heute eingesetzte Kryptografie in zehn Jahren noch standhalten soll, ist jetzt der richtige Zeitpunkt zum Handeln. Zumal der Aufwand (wie ihr gleich seht) überschaubar ist.

Was steckt hinter X25519MLKEM768?

Kurz zur Einordnung: ML-KEM (ehemals CRYSTALS-Kyber) ist der vom NIST im August 2024 standardisierte Post-Quantum-Algorithmus für den Schlüsselaustausch (FIPS 203). X25519MLKEM768 ist ein sogenannter Hybrid-Algorithmus – er kombiniert das klassische X25519 (Curve25519 ECDH) mit ML-KEM-768 zu einem gemeinsamen Schlüssel.

Der Clou dabei: Selbst wenn ML-KEM irgendwann gebrochen werden sollte, bleibt die klassische X25519-Komponente intakt. Und umgekehrt. Man muss also nicht darauf vertrauen, dass der neue Algorithmus auch wirklich hält – man bekommt das Beste aus beiden Welten.

Wer Firefox nutzt, hat das übrigens vermutlich schon in Aktion gesehen: Seit Firefox 124 wird bei TLS 1.3 standardmäßig X25519MLKEM768 für den Schlüsselaustausch verwendet. Schaut mal in die Verbindungsdetails einer HTTPS-Seite – die Chancen stehen gut, dass dort bereits ein hybrider PQC-Schlüsselaustausch stattfindet. Also, wenn der Server das anbietet, wie dieser hier *zwinker*.

Voraussetzungen prüfen

Bevor ihr konfiguriert, solltet ihr sicherstellen, dass euer OpenSSL ML-KEM überhaupt kann. Auf meinem FreeBSD 15:

$ openssl version
OpenSSL 3.5.4 30 Sep 2025 (Library: OpenSSL 3.5.4 30 Sep 2025)

Und dann die entscheidende Frage – kennt OpenSSL die benötigten KEM-Algorithmen?

$ openssl list -kem-algorithms | grep -i mlkem
  ML-KEM-512
  ML-KEM-768
  ML-KEM-1024
  X25519MLKEM768
  SecP256r1MLKEM768

Wenn X25519MLKEM768 in der Liste auftaucht, seid ihr startklar. Das ist bei OpenSSL ab Version 3.5 der Fall – der ML-KEM-Support ist im Default-Provider enthalten, es wird kein zusätzlicher OQS-Provider und kein liboqs benötigt.

Noch ein Check – sind die Algorithmen auch als TLS-Gruppen verfügbar?

$ openssl list -tls-groups | grep -i mlkem
  X25519MLKEM768
  SecP256r1MLKEM768
  SecP384r1MLKEM1024

Perfekt. Weiter geht’s.

Postfix konfigurieren

Postfix steuert die verwendeten TLS-Gruppen für den Schlüsselaustausch über den Parameter tls_eecdh_auto_curves. Dieser gilt sowohl für eingehende (smtpd) als auch für ausgehende (smtp) Verbindungen.

Vorher:

tls_eecdh_auto_curves = X25519, prime256v1, secp384r1

Nachher:

tls_eecdh_auto_curves = X25519MLKEM768, X25519, prime256v1, secp384r1

Das war’s. Eine Zeile. X25519MLKEM768 wird als bevorzugte Gruppe an den Anfang gestellt, die klassischen Kurven bleiben als Fallback erhalten. Clients die kein ML-KEM beherrschen, verhandeln einfach X25519 oder prime256v1 – die Abwärtskompatibilität bleibt also vollständig gewahrt.

Die Änderung setzt ihr entweder direkt in /usr/local/etc/postfix/main.cf oder über:

# postconf "tls_eecdh_auto_curves = X25519MLKEM768, X25519, prime256v1, secp384r1"
# postfix reload

Wichtig: Dieser Parameter beeinflusst alle Postfix-Dienste – SMTP (Port 25), Submission (Port 587) und SMTPS (Port 465). Ihr müsst also nicht jeden Port einzeln konfigurieren.

Dovecot konfigurieren

Dovecot verwendet den Parameter ssl_curve_list um die TLS-Gruppen für IMAP-Verbindungen festzulegen. Standardmäßig ist dieser leer, was bedeutet, dass OpenSSL seine eigenen Defaults verwendet. Das kann funktionieren, muss aber nicht.

In /usr/local/etc/dovecot/conf.d/10-ssl.conf:

ssl_curve_list = X25519MLKEM768:X25519:prime256v1:secp384r1

Achtung: Dovecot verwendet Doppelpunkte als Trennzeichen (OpenSSL-Syntax), Postfix verwendet Kommas. Nicht verwechseln. Ja, passiert mir oft 😀

Danach:

# doveadm reload

Überprüfen

Jetzt wird’s spannend. Funktioniert es tatsächlich? Zum Testen verwende ich openssl s_client direkt auf dem Server; denn euer lokales Linux oder macOS hat möglicherweise noch kein OpenSSL 3.5 mit ML-KEM-Support. Mein Linux Mint 22.3 hat es leider noch nicht *schnief*

SMTP (Port 25, STARTTLS):

$ openssl s_client -connect smtp.kernel-error.de:25 -starttls smtp \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

SMTPS (Port 465):

$ openssl s_client -connect smtp.kernel-error.de:465 \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

Submission (Port 587, STARTTLS):

$ openssl s_client -connect smtp.kernel-error.de:587 -starttls smtp \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

IMAPS (Port 993):

$ openssl s_client -connect imap.kernel-error.de:993 \
    -groups X25519MLKEM768 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519MLKEM768

Alle vier Ports verhandeln TLSv1.3 mit X25519MLKEM768. Die hybride Post-Quantum-Verschlüsselung ist aktiv.

Wenn ihr testen wollt, was passiert wenn ein Client kein ML-KEM unterstützt:

$ openssl s_client -connect imap.kernel-error.de:465 \
    -groups X25519 -brief </dev/null 2>&1 | grep -E 'Protocol|group'
Protocol version: TLSv1.3
Negotiated TLS1.3 group: X25519

Fallback auf X25519 – funktioniert sauber.

Was das nicht leistet

Wie schon beim SSH-Beitrag muss ich auch hier einschränken: Wir sichern damit den Schlüsselaustausch ab, nicht die Authentifizierung. Die TLS-Zertifikate verwenden weiterhin klassische Algorithmen (RSA, ECDSA). Für Post-Quantum-Signaturen in Zertifikaten bräuchte man ML-DSA (ehemals CRYSTALS-Dilithium) – und obwohl OpenSSL 3.5 das theoretisch unterstützt, gibt es Stand heute keine öffentliche Zertifizierungsstelle, die ML-DSA-Zertifikate ausstellt. Das wird kommen, ist aber noch Zukunftsmusik. Hey, wie ECDSA bei S/MIME (oder ist das schon anders?).

Für die Praxis bedeutet das: Ein Angreifer mit einem Quantencomputer könnte theoretisch die Serverauthentifizierung angreifen (ECDSA/RSA brechen), müsste das aber in Echtzeit tun – hier greift „store now, decrypt later“ nicht, weil eine gefälschte Authentifizierung nur im Moment der Verbindung nützt. Der Schlüsselaustausch hingegen – und damit die eigentliche Vertraulichkeit der transportierten E-Mails – ist durch X25519MLKEM768 auch gegen zukünftige Quantenangriffe geschützt.

Zwei Zeilen Konfiguration, ein Reload pro Dienst – und euer Mailserver verhandelt quantensichere Verschlüsselung. Vollständig abwärtskompatibel, ohne Einschränkungen für bestehende Clients. Es gibt eigentlich keinen Grund, das nicht zu tun. Oder fällt euch etwas ein?

Viel Spaß beim Nachbauen – und wie immer: bei Fragen, fragen.

GPT in Rspamd aktivieren: so nutze ich das LLM-Signal im Score

Seit einiger Zeit nutze ich das GPT-Modul von Rspamd, um bei der Spam-Erkennung ein zusätzliches Signal zu bekommen. Es ersetzt nichts — kein Bayes, kein DKIM, kein RBL — sondern ist ein weiterer Sensor im Gesamtbild. Wer sich fragt, wie das in der Praxis aussieht und worauf man achten muss: hier mein aktuelles Setup.

Update 2026-02-13: Dieser Beitrag wurde komplett überarbeitet. Die ursprüngliche Version nutzte json=false, was zu Parse-Problemen führte. Außerdem fehlte ein Custom Prompt — und genau das ist der entscheidende Punkt, wie sich herausgestellt hat.

Voraussetzungen

  • Rspamd >= 3.12 mit GPT-Plugin (bei mir aktuell 3.14.0 auf FreeBSD 15.0)
  • Ein OpenAI API-Key (oder kompatibler Endpoint)
  • Grundverständnis von Rspamd Metrics und Actions

OpenAI API-Key anlegen

Wer noch keinen Key hat: Auf platform.openai.com einloggen, unter API Keys einen neuen Service-Account-Key erzeugen. Der Key wird nur einmal angezeigt — sicher ablegen. Den Verbrauch sieht man im Dashboard. Bei gpt-4o-mini und Mailfiltering sind die Kosten minimal.

Die Konfiguration: gpt.conf

Hier meine aktuelle /usr/local/etc/rspamd/local.d/gpt.conf:

enabled = true;
type = "openai";
model = "gpt-4o-mini";
api_key = "GEHEIMER-KEY";

model_parameters {
  gpt-4o-mini {
    max_tokens = 160;
    temperature = 0.0;
  }
}

timeout = 10s;
allow_ham = true;
allow_passthrough = false;
json = true;

prompt = "You are an email spam detector. Analyze the email and respond with ONLY a JSON object, no other text. The JSON must have these fields: "probability" (number 0.00-1.00 where 1.0=spam, 0.0=ham), "reason" (one sentence citing the strongest indicator). Example: {"probability": 0.85, "reason": "Unsolicited offer with urgent language and suspicious links."}  LEGITIMATE patterns: verification emails with codes, transactional emails (receipts, confirmations), newsletter unsubscribe links. Flag as spam only with MULTIPLE red flags: urgent threats, domain impersonation, requests for credentials, mismatched URLs.";


symbols_to_except {
  RCVD_IN_DNSWL_MED   = -0.1;
  RCVD_IN_DNSWL_HI    = -0.1;
  DWL_DNSWL_MED        = -0.1;
  WHITELIST_RECP_ADDR = -0.1;
  BAYES_HAM           = -0.1;
  SPAMTRAP            = 0;
  RCPT_IN_SPAMTRAP    = 0;
  SPAMTRAP_ADDR       = 0;
  RCVD_VIA_SMTP_AUTH  = 0;
  LOCAL_CLIENT        = 0;
  FROM_LOCAL          = 0;
}

Was hat sich gegenüber der alten Version geändert?

json = true und der Custom Prompt

Das ist die wichtigste Änderung. In meiner ursprünglichen Konfiguration stand json = false. Das funktionierte, hatte aber einen Haken: die Antwort des Modells wurde als Freitext geparst, was unzuverlässig war.

Mit json = true aktiviert Rspamd den JSON-Modus. Das Modell wird angewiesen, strukturiertes JSON zurückzuliefern, und der Parser erwartet ein Feld probability in der Antwort.

Und hier kommt der Fallstrick: Der Default-Prompt von Rspamd passt nicht zum JSON-Modus. Er fordert das Modell auf, nummerierte Textzeilen zurückzugeben:

Output ONLY 2 lines:
1. Numeric score: 0.00-1.00
2. One-sentence reason...

Der JSON-Parser erwartet aber:

{"probability": 0.85, "reason": "..."}

Das Ergebnis: cannot convert spam score im Log und GPT_UNCERTAIN(0.00) bei jeder Mail. Das GPT-Modul lief, lieferte aber nie ein verwertbares Ergebnis.

Lösung: ein Custom Prompt, der explizit JSON mit dem probability-Feld verlangt. Damit funktioniert die Kette:

  1. Rspamd sendet Mail + Prompt an OpenAI
  2. OpenAI antwortet mit {"probability": 0.9, "reason": "..."}
  3. Rspamd parst das JSON, findet probability, mappt auf GPT_SPAM/GPT_HAM/GPT_SUSPICIOUS

reason_header entfernt

In der alten Version hatte ich reason_header = "X-GPT-Reason" gesetzt. Das schrieb die GPT-Begründung als eigenen Header in die Mail. Mit json = true ist das nicht mehr nötig — die Reason steckt im JSON und taucht im Rspamd-Log auf. Außerdem entferne ich ohnehin GPT-Header per Milter-Config, damit keine internen Analyse-Details an den Empfänger durchsickern.

symbols_to_except angepasst

Änderungen gegenüber der alten Version:

  • GREYLIST entfernt: Greylisting ist kein Vertrauens-Signal. Eine Mail die Greylisting besteht, kann trotzdem Spam sein. GPT soll diese Mails weiterhin bewerten.
  • BAYES_HAM hinzugefügt: Wenn Bayes die Mail bereits sicher als Ham einstuft, spart man sich den GPT-Call. Sinnvoll für Newsletter und regelmäßige Korrespondenz.
  • SPAMTRAP-Symbole hinzugefügt: Mails an Spamtrap-Adressen brauchen keine GPT-Analyse, die sind per Definition Spam.

Scoring: Gewichte und Thresholds

Die GPT-Symbole und ihre Gewichte in der metrics.conf (bzw. local.d/groups.conf):

symbols {
  GPT_SPAM       { weight = 9.0;  description = "GPT: classified as SPAM"; }
  GPT_SUSPICIOUS { weight = 4.5;  description = "GPT: classified as SUSPICIOUS"; }
  GPT_HAM        { weight = -0.5; one_shot = true; description = "GPT: classified as HAM"; }
}

Warum diese Gewichte?

  • GPT_SPAM (9.0): Kräftig, aber alleine nicht genug zum Rejecten. Erst in Kombination mit anderen Signalen (Bayes, RBL, fehlende Auth) wird der Reject-Threshold erreicht.
  • GPT_SUSPICIOUS (4.5): Schiebt Grenzfälle in Richtung Greylist oder Add-Header. Genau dafür ist GPT am nützlichsten.
  • GPT_HAM (-0.5): Bewusst niedrig und one_shot. GPT soll Spam erkennen, nicht Ham retten.

Dazu die Action-Thresholds:

actions {
  greylist   = 4;
  add_header = 6;
  reject     = 12;
}

Reject-Threshold bei mir: 12 statt Default 15. Das geht, weil die traditionellen Checks (SPF, DKIM, DMARC, RBL, Bayes, DNSBL) bereits solide arbeiten. GPT kommt als zusätzliches Signal obendrauf.

Praxis-Beispiel

Hier eine echte Spam-Mail aus dem Log, bei der GPT korrekt angeschlagen hat:

rspamd_task_write_log: (default: T (reject): [13.83/12.00]
  [BAYES_SPAM(5.10){100.00%;},
   ABUSE_SURBL(5.00){next.schnapper-empfehlung.de:url;...},
   GPT_SPAM(2.40){0.9;},
   FROM_NEQ_ENVFROM(0.50){...},
   FORGED_SENDER(0.30){...},
   ...]

Was man hier sieht:

  • GPT_SPAM(2.40){0.9;} — GPT hat Probability 0.9 (90% Spam) zurückgeliefert. Rspamd mappt den Probability-Wert nicht 1:1 auf das konfigurierte Gewicht, sondern skaliert intern — hier ergeben sich 2.40 von maximal 9.0 Punkten.
  • Zusammen mit BAYES_SPAM (5.10) und ABUSE_SURBL (5.00) kommt die Mail auf 13.83 — deutlich über dem Reject-Threshold von 12.
  • GPT war hier nicht das ausschlaggebende Signal, hat aber zur Gesamtbewertung beigetragen.

Das ist genau das Verhalten, das ich will: GPT als ein Baustein unter vielen, der bei Grenzfällen den Ausschlag geben kann.

Datenschutz

Das muss gesagt werden: Mit diesem Setup fließen Mailinhalte an OpenAI. Wer personenbezogene Daten verarbeitet oder in einem regulierten Umfeld arbeitet, muss prüfen ob das zulässig ist. Alternative: selbst gehostete Modelle über Ollama oder kompatible lokale Endpoints. Rspamd unterstützt das über den type-Parameter.

Für meinen privaten Mailserver ist das Risiko vertretbar — und die Ergebnisse sprechen für sich.

Zusammenfassung

ParameterWertWarum
jsontrueStrukturiertes Parsing, zuverlässiger als Freitext
promptCustomPflicht bei json=true! Default-Prompt liefert Textformat, Parser erwartet JSON
temperature0.0Deterministische Antworten, kein Kreativitäts-Bonus beim Spamfiltern
allow_hamtrueKleines positives Signal für legitime Mails
symbols_to_exceptBAYES_HAM, DNSWL, Whitelists, SMTP_AUTH, SpamtrapsUnnötige API-Calls vermeiden
reason_headernicht gesetztNicht nötig mit json=true, interne Details gehören nicht in den Header

Die wichtigste Erkenntnis: json = true ohne Custom Prompt ist kaputt. Der Default-Prompt und der JSON-Parser sprechen unterschiedliche Sprachen. Wer json = true setzt, muss einen Prompt mitliefern, der JSON mit einem probability-Feld verlangt. Sonst steht im Log cannot convert spam score und GPT liefert nur GPT_UNCERTAIN(0.00).

Volksverschlüsselung wird eingestellt

An mir flog gerade die Information vorbei, dass die Volksverschlüsselung zum 31.01.2026 eingestellt wird. Ich habe mir dort vor ein paar Jahren mal ein S/MIME-Zertifikat für meine E-Mails geholt. Mir hat der Ansatz gefallen, dass man sich mit seinem neuen Personalausweis und dessen Online-Funktion dort legitimieren kann und im Anschluss sein Zertifikat bekommt. Für mich hat diese Abhängigkeit absolut Sinn ergeben. Wir haben ja schon alle einen Perso mit Online-Funktion und PIN und was weiß ich alles. Also warum nicht auch einfach und schnell Zertifikate darüber erstellen?

Screenshot der Meldung zur Einstellung des Dienstes Volksverschlüsselung.

Funktioniert hat das alles wirklich gut – leider mit dem gleichen Problemchen wie auch bei cacert.org: Die Root-Zertifikate sind nicht in den Trust Stores der Betriebssysteme, Browser, Mailclients usw. Signiert man also etwas damit, wird es beim Empfänger als ungültig und unsicher angezeigt, es sei denn, dieser installiert manuell die Root-Zertifikate. Das macht natürlich niemand. Damit war die Volksverschlüsselung für mich genauso raus wie leider auch cacert.org.

Nun hing hinter der Volksverschlüsselung ebenfalls das Fraunhofer-Institut. Meine Hoffnung war, dass über diesen Weg am Ende doch mal die Root-Zertifikate in die Trust Stores kommen. Aber leider nicht.

Die Diskussion, ob man Trust Stores wirklich braucht, ob man sie vor allem vorgefüllt braucht, mache ich genauso wenig auf wie DNSSEC und TLSA, ok? Denn uns allen ist ja inzwischen klar, dass wir es „sicher“ haben könnten – wenn man nur nicht so scheiß viel Geld mit den CAs verdienen könnte. Denn die ganzen CAs zahlen ja schon ein paar Euro, um in die Trust Stores zu kommen 😉

Soviel dann also zur Volksverschlüsselung.

S/MIME-Zertifikat per DNS veröffentlichen – SMIMEA

smimea S/MIME Blog Image

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
   311C301A06035504030C1343657274756D20534D494D4520525341204341301E
   170D3235303331333133343135355A170D3237303331333133343135345A3078
   3114301206035504040C0B76616E206465204D65657231123010060355042A0C
   0953656261737469616E311E301C06035504030C1553656261737469616E2076
   616E206465204D656572312C302A06092A864886F70D010901161D6B65726E65
   6C2D6572726F72406B65726E656C2D6572726F722E636F6D30820222300D0609
   2A864886F70D01010105000382020F003082020A0282020100D0A90BC53ABA04
   08543FE600F0F71C17BE7EB4A8996A8EF5E9122AAC8E7F39D627186617C4D6CA
   734E1A9E6302F8076065EA93D762542D2C12BFF32D5D4942B9A8AA84E2E63CE9
   B843C1665C014A6572A42E376ED0629694FCC942FE53D76052A40CDAB1257A1D
   501D9C65DE18F27C5490A24181498A202E56F4DC0FDCBFE94766F96EBF47C872
   3744ABD69DC684417106DF3D4F12FD52A13B786490366DBF6CB5A843621CD686
   B06D072FD7D486BD0AC706021D137A365718DCD8709D55B64428F8DB56B268BD
   BED463A25231B40566C041A48958BE1767E27E21881D2109935C02F27EA306B6
   4997683EEFDF8685F4F090AB09692F232CD34AC7FF2296768CED62C68C37B4C3
   DD9F04EC9F5C9BB9F712A5032AC2F83D68DA756E4F2886A6F65889CFAEA0C15E
   3624EA3D9E3EFF91D68606F7B7B1B7120035AD4F71369E6D79977B4B2CC3575A
   C51CAF419E795B78822DD36B6D0B0E4622BCE55F7B27FCB52FDCD6A4FBD33EF0
   9F897CADA2E793D1509DE54773B3FBE9091CEA2E27A41CBA38A08BBBE1B15BF5
   6EB35B21D66F5B1B1CC6FDD6362AA88A4010F3D2732F071A841BC765D6F74C3B
   430D036A327918D08156BA2882D78113DD15633599319F4BD5D4F12E1F0102BA
   33766ADF09DC58323246D20BAC815BE5B8822C260EFBB07ADBAB98FA42F31650
   FEFAE5D679D4AD29992F199D59F38D54988D77B61E740CBF470203010001A382
   01C2308201BE300C0603551D130101FF0402300030410603551D1F043A303830
   36A034A0328630687474703A2F2F63736D696D6572736163612E63726C2E6365
   7274756D2E706C2F63736D696D6572736163612E63726C30818306082B060105
   0507010104773075302E06082B060105050730018622687474703A2F2F63736D
   696D6572736163612E6F6373702D63657274756D2E636F6D304306082B060105
   050730028637687474703A2F2F63736D696D6572736163612E7265706F736974
   6F72792E63657274756D2E706C2F63736D696D6572736163612E636572301F06
   03551D2304183016801466FBC30FBEF4BFE09CC9AB4DDE4719BDC0CAA668301D
   0603551D0E041604148D8C102E11D87004F7DDB4E04FF01781888A32A0304C06
   03551D20044530433009060767810C010504023036060B2A84680186F6770264
   01013027302506082B06010505070201161968747470733A2F2F7777772E6365
   7274756D2E706C2F435053301D0603551D250416301406082B06010505070304
   06082B06010505070302300E0603551D0F0101FF0404030204F030280603551D
   110421301F811D6B65726E656C2D6572726F72406B65726E656C2D6572726F72
   2E636F6D300D06092A864886F70D01010B0500038202010070724799F05CF4C8
   21854F43BD950BB608B989046349214F9D0EEC79F73A59DBF4063608FE5A7A7F
   A50CD46A15486018EB9C334418084D8F97FE32EA21CCBAFE902BF6472DB6CA60
   D79EBE09919AFA0652D92CB13B506400BAF4774F3263967A49548A6F723ADCBB
   715AF79705099E5EC84E283DAFA3465908F4148C2B153C41D051C94295D4F042
   54217D1C8E48DF59D92ECBCB4A872EC728A954DAF7B661DE8037F7F103393612
   14163901ACFE98F3D597A67DBE87A8EE1FEC33DB71712F4907E0F3B1171E9176
   158189AC8229B26B369C0FE2BBD5964CA2ABFC7D955485056102844E84E8F79E
   0F30BF41D5F42B3C4F4CCA9BF9334D5728518473A0E61A3AFC88F59034F27154
   6B5D806D86F1E8BC6B54B4E05F80C44835DCC2C534E419F63BBFDB305C1733B4
   2DD2CC5795876F004F18C2E4D64B2C9FC6939590BE32501B6A6CEDB19B5FBF47
   887C76E14C99A36D46E99B5C76782E4E345ECB37E8886303C84849ADC8BDE1AF
   4E3A8096AEE407A40699D5C000ADCD16A4805DDF8FB208FFB902EF14031CFFBE
   3C0DC03588EBF15557B3B1029B2CD196064BC0DEE1F11D12391825B86CB34A6F
   BEBBAD43B0FE0EA43301F93D0B26ACED182B1E27063AE578C003D4D4498132B8
   D980532754CFFBD9E6D8917615B62AE08295FC46391AA0FD9815FDD822D95E9B
   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)
        Serial Number:
            73:c1:3c:47:8d:a7:b1:14:b8:71:f0:07:37:f1:b0:fb
        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)
                Modulus:
                    00:d0:a9:0b:c5:3a:ba:04:08:54:3f:e6:00:f0:f7:
                    1c:17:be:7e:b4:a8:99:6a:8e:f5:e9:12:2a:ac:8e:
                    7f:39:d6:27:18:66:17:c4:d6:ca:73:4e:1a:9e:63:
                    02:f8:07:60:65:ea:93:d7:62:54:2d:2c:12:bf:f3:
                    2d:5d:49:42:b9:a8:aa:84:e2:e6:3c:e9:b8:43:c1:
                    66:5c:01:4a:65:72:a4:2e:37:6e:d0:62:96:94:fc:
                    c9:42:fe:53:d7:60:52:a4:0c:da:b1:25:7a:1d:50:
                    1d:9c:65:de:18:f2:7c:54:90:a2:41:81:49:8a:20:
                    2e:56:f4:dc:0f:dc:bf:e9:47:66:f9:6e:bf:47:c8:
                    72:37:44:ab:d6:9d:c6:84:41:71:06:df:3d:4f:12:
                    fd:52:a1:3b:78:64:90:36:6d:bf:6c:b5:a8:43:62:
                    1c:d6:86:b0:6d:07:2f:d7:d4:86:bd:0a:c7:06:02:
                    1d:13:7a:36:57:18:dc:d8:70:9d:55:b6:44:28:f8:
                    db:56:b2:68:bd:be:d4:63:a2:52:31:b4:05:66:c0:
                    41:a4:89:58:be:17:67:e2:7e:21:88:1d:21:09:93:
                    5c:02:f2:7e:a3:06:b6:49:97:68:3e:ef:df:86:85:
                    f4:f0:90:ab:09:69:2f:23:2c:d3:4a:c7:ff:22:96:
                    76:8c:ed:62:c6:8c:37:b4:c3:dd:9f:04:ec:9f:5c:
                    9b:b9:f7:12:a5:03:2a:c2:f8:3d:68:da:75:6e:4f:
                    28:86:a6:f6:58:89:cf:ae:a0:c1:5e:36:24:ea:3d:
                    9e:3e:ff:91:d6:86:06:f7:b7:b1:b7:12:00:35:ad:
                    4f:71:36:9e:6d:79:97:7b:4b:2c:c3:57:5a:c5:1c:
                    af:41:9e:79:5b:78:82:2d:d3:6b:6d:0b:0e:46:22:
                    bc:e5:5f:7b:27:fc:b5:2f:dc:d6:a4:fb:d3:3e:f0:
                    9f:89:7c:ad:a2:e7:93:d1:50:9d:e5:47:73:b3:fb:
                    e9:09:1c:ea:2e:27:a4:1c:ba:38:a0:8b:bb:e1:b1:
                    5b:f5:6e:b3:5b:21:d6:6f:5b:1b:1c:c6:fd:d6:36:
                    2a:a8:8a:40:10:f3:d2:73:2f:07:1a:84:1b:c7:65:
                    d6:f7:4c:3b:43:0d:03:6a:32:79:18:d0:81:56:ba:
                    28:82:d7:81:13:dd:15:63:35:99:31:9f:4b:d5:d4:
                    f1:2e:1f:01:02:ba:33:76:6a:df:09:dc:58:32:32:
                    46:d2:0b:ac:81:5b:e5:b8:82:2c:26:0e:fb:b0:7a:
                    db:ab:98:fa:42:f3:16:50:fe:fa:e5:d6:79:d4:ad:
                    29:99:2f:19:9d:59:f3:8d:54:98:8d:77:b6:1e:74:
                    0c:bf:47
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://csmimersaca.crl.certum.pl/csmimersaca.crl
            Authority Information Access: 
                OCSP - URI:http://csmimersaca.ocsp-certum.com
                CA Issuers - URI:http://csmimersaca.repository.certum.pl/csmimersaca.cer
            X509v3 Authority Key Identifier: 
                66:FB:C3:0F:BE:F4:BF:E0:9C:C9:AB:4D:DE:47:19:BD:C0:CA:A6:68
            X509v3 Subject Key Identifier: 
                8D:8C:10:2E:11:D8:70:04:F7:DD:B4:E0:4F:F0:17:81:88:8A:32:A0
            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.5.4.2
                Policy: 1.2.616.1.113527.2.100.1.1
                  CPS: https://www.certum.pl/CPS
            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
    Signature Algorithm: sha256WithRSAEncryption
    Signature Value:
        70:72:47:99:f0:5c:f4:c8:21:85:4f:43:bd:95:0b:b6:08:b9:
        89:04:63:49:21:4f:9d:0e:ec:79:f7:3a:59:db:f4:06:36:08:
        fe:5a:7a:7f:a5:0c:d4:6a:15:48:60:18:eb:9c:33:44:18:08:
        4d:8f:97:fe:32:ea:21:cc:ba:fe:90:2b:f6:47:2d:b6:ca:60:
        d7:9e:be:09:91:9a:fa:06:52:d9:2c:b1:3b:50:64:00:ba:f4:
        77:4f:32:63:96:7a:49:54:8a:6f:72:3a:dc:bb:71:5a:f7:97:
        05:09:9e:5e:c8:4e:28:3d:af:a3:46:59:08:f4:14:8c:2b:15:
        3c:41:d0:51:c9:42:95:d4:f0:42:54:21:7d:1c:8e:48:df:59:
        d9:2e:cb:cb:4a:87:2e:c7:28:a9:54:da:f7:b6:61:de:80:37:
        f7:f1:03:39:36:12:14:16:39:01:ac:fe:98:f3:d5:97:a6:7d:
        be:87:a8:ee:1f:ec:33:db:71:71:2f:49:07:e0:f3:b1:17:1e:
        91:76:15:81:89:ac:82:29:b2:6b:36:9c:0f:e2:bb:d5:96:4c:
        a2:ab:fc:7d:95:54:85:05:61:02:84:4e:84:e8:f7:9e:0f:30:
        bf:41:d5:f4:2b:3c:4f:4c:ca:9b:f9:33:4d:57:28:51:84:73:
        a0:e6:1a:3a:fc:88:f5:90:34:f2:71:54:6b:5d:80:6d:86:f1:
        e8:bc:6b:54:b4:e0:5f:80:c4:48:35:dc:c2:c5:34:e4:19:f6:
        3b:bf:db:30:5c:17:33:b4:2d:d2:cc:57:95:87:6f:00:4f:18:
        c2:e4:d6:4b:2c:9f:c6:93:95:90:be:32:50:1b:6a:6c:ed:b1:
        9b:5f:bf:47:88:7c:76:e1:4c:99:a3:6d:46:e9:9b:5c:76:78:
        2e:4e:34:5e:cb:37:e8:88:63:03:c8:48:49:ad:c8:bd:e1:af:
        4e:3a:80:96:ae:e4:07:a4:06:99:d5:c0:00:ad:cd:16:a4:80:
        5d:df:8f:b2:08:ff:b9:02:ef:14:03:1c:ff:be:3c:0d:c0:35:
        88:eb:f1:55:57:b3:b1:02:9b:2c:d1:96:06:4b:c0:de:e1:f1:
        1d:12:39:18:25:b8:6c:b3:4a:6f:be:bb:ad:43:b0:fe:0e:a4:
        33:01:f9:3d:0b:26:ac:ed:18:2b:1e:27:06:3a:e5:78:c0:03:
        d4:d4:49:81:32:b8:d9:80:53:27:54:cf:fb:d9:e6:d8:91:76:
        15:b6:2a:e0:82:95:fc:46:39:1a:a0:fd:98:15:fd:d8:22:d9:
        5e:9b:75:73:ca:35:47:7d:59:b9:8d:e4:85:20:65:f5:8f:b6:
        0e:0e:62:0d:3e:2f:5c:ad

Beide Skripte findet ihr auf GitHub, damit ihr sie nutzen oder verbessern könnt.

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.

Warum ist der SMIMEA-DNS-Record so aufgebaut? Ganz einfach:

Der erste Teil, also , 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 stattdessen nur der SHA256-Hash des Local-Parts (also der Teil vor dem @) genutzt. Das bedeutet: Wer die genaue E-Mail-Adresse kennt, kann den passenden DNS-Eintrag finden – aber jemand, der einfach nur blind durch die Zone scannt, sieht nur Hashes und kann damit nichts anfangen.

Der _smimecert-Prefix zeigt an, dass es sich um einen SMIMEA-Record handelt, ähnlich wie es bei ._tcp. für SRV-Records oder _acme-challenge. für Let’s Encrypt-Zertifikate der Fall ist.

Und schließlich kommt die Domain, zu der die E-Mail-Adresse gehört.

Zusammen ergibt das einen sicheren, einfach abfragbaren und nicht direkt durchsuchbaren DNS-Eintrag für dein S/MIME-Zertifikat.

Möchte man die Abfrage manuell mit dig für die E-Mail-Adresse „kernel-error@kernel-error.com“ durchführen, muss man zuerst den Local-Part der E-Mail-Adresse (kernel-error) mit SHA256 hashen. Laut RFC 8162, Abschnitt 3.1 wird der SHA-256-Hash auf die ersten 28 Bytes (56 Hex-Zeichen) gekürzt, um die DNS-Label-Längenbeschränkung von 63 Zeichen pro Label (RFC 1035, Abschnitt 2.3.4) einzuhalten.

echo -n "kernel-error" | sha256sum | awk '{print $1}' | cut -c1-56
70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0

Anschließend kann man die dig-Abfrage korrekt zusammensetzen:

dig +dnssec +short 70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com. SMIMEA
3 0 0 30820714308204FCA003020102021073C13C478DA7B114B871F00737 F1B0FB300D06092A864886F70D01010B0500304E310B300906035504 061302504C3121301F060355040A0C1841737365636F204461746120 53797374656D7320532E412E311C301A06035504030C134365727475 6D20534D494D4520525341204341301E170D32353033313331333431 35355A170D3237303331333133343135345A30783114301206035504 040C0B76616E206465204D65657231123010060355042A0C09536562 61737469616E311E301C06035504030C1553656261737469616E2076 616E206465204D656572312C302A06092A864886F70D010901161D6B 65726E656C2D6572726F72406B65726E656C2D6572726F722E636F6D 30820222300D06092A864886F70D01010105000382020F003082020A 0282020100D0A90BC53ABA0408543FE600F0F71C17BE7EB4A8996A8E F5E9122AAC8E7F39D627186617C4D6CA734E1A9E6302F8076065EA93 D762542D2C12BFF32D5D4942B9A8AA84E2E63CE9B843C1665C014A65 72A42E376ED0629694FCC942FE53D76052A40CDAB1257A1D501D9C65 DE18F27C5490A24181498A202E56F4DC0FDCBFE94766F96EBF47C872 3744ABD69DC684417106DF3D4F12FD52A13B786490366DBF6CB5A843 621CD686B06D072FD7D486BD0AC706021D137A365718DCD8709D55B6 4428F8DB56B268BDBED463A25231B40566C041A48958BE1767E27E21 881D2109935C02F27EA306B64997683EEFDF8685F4F090AB09692F23 2CD34AC7FF2296768CED62C68C37B4C3DD9F04EC9F5C9BB9F712A503 2AC2F83D68DA756E4F2886A6F65889CFAEA0C15E3624EA3D9E3EFF91 D68606F7B7B1B7120035AD4F71369E6D79977B4B2CC3575AC51CAF41 9E795B78822DD36B6D0B0E4622BCE55F7B27FCB52FDCD6A4FBD33EF0 9F897CADA2E793D1509DE54773B3FBE9091CEA2E27A41CBA38A08BBB E1B15BF56EB35B21D66F5B1B1CC6FDD6362AA88A4010F3D2732F071A 841BC765D6F74C3B430D036A327918D08156BA2882D78113DD156335 99319F4BD5D4F12E1F0102BA33766ADF09DC58323246D20BAC815BE5 B8822C260EFBB07ADBAB98FA42F31650FEFAE5D679D4AD29992F199D 59F38D54988D77B61E740CBF470203010001A38201C2308201BE300C 0603551D130101FF0402300030410603551D1F043A30383036A034A0 328630687474703A2F2F63736D696D6572736163612E63726C2E6365 7274756D2E706C2F63736D696D6572736163612E63726C3081830608 2B0601050507010104773075302E06082B0601050507300186226874 74703A2F2F63736D696D6572736163612E6F6373702D63657274756D 2E636F6D304306082B060105050730028637687474703A2F2F63736D 696D6572736163612E7265706F7369746F72792E63657274756D2E70 6C2F63736D696D6572736163612E636572301F0603551D2304183016 801466FBC30FBEF4BFE09CC9AB4DDE4719BDC0CAA668301D0603551D 0E041604148D8C102E11D87004F7DDB4E04FF01781888A32A0304C06 03551D20044530433009060767810C010504023036060B2A84680186 F677026401013027302506082B06010505070201161968747470733A 2F2F7777772E63657274756D2E706C2F435053301D0603551D250416 301406082B0601050507030406082B06010505070302300E0603551D 0F0101FF0404030204F030280603551D110421301F811D6B65726E65 6C2D6572726F72406B65726E656C2D6572726F722E636F6D300D0609 2A864886F70D01010B0500038202010070724799F05CF4C821854F43 BD950BB608B989046349214F9D0EEC79F73A59DBF4063608FE5A7A7F A50CD46A15486018EB9C334418084D8F97FE32EA21CCBAFE902BF647 2DB6CA60D79EBE09919AFA0652D92CB13B506400BAF4774F3263967A 49548A6F723ADCBB715AF79705099E5EC84E283DAFA3465908F4148C 2B153C41D051C94295D4F04254217D1C8E48DF59D92ECBCB4A872EC7 28A954DAF7B661DE8037F7F10339361214163901ACFE98F3D597A67D BE87A8EE1FEC33DB71712F4907E0F3B1171E9176158189AC8229B26B 369C0FE2BBD5964CA2ABFC7D955485056102844E84E8F79E0F30BF41 D5F42B3C4F4CCA9BF9334D5728518473A0E61A3AFC88F59034F27154 6B5D806D86F1E8BC6B54B4E05F80C44835DCC2C534E419F63BBFDB30 5C1733B42DD2CC5795876F004F18C2E4D64B2C9FC6939590BE32501B 6A6CEDB19B5FBF47887C76E14C99A36D46E99B5C76782E4E345ECB37 E8886303C84849ADC8BDE1AF4E3A8096AEE407A40699D5C000ADCD16 A4805DDF8FB208FFB902EF14031CFFBE3C0DC03588EBF15557B3B102 9B2CD196064BC0DEE1F11D12391825B86CB34A6FBEBBAD43B0FE0EA4 3301F93D0B26ACED182B1E27063AE578C003D4D4498132B8D9805327 54CFFBD9E6D8917615B62AE08295FC46391AA0FD9815FDD822D95E9B 7573CA35477D59B98DE4852065F58FB60E0E620D3E2F5CAD

Was bedeutet das?
3 → Gibt an, dass es sich um einen S/MIMEA-Record handelt. Die Zahl steht für den sogenannten „Usage“-Wert, also wie das Zertifikat genutzt wird. In diesem Fall bedeutet 3, dass es für eine End-Entity-Zertifizierung gedacht ist, also für die tatsächliche E-Mail-Verschlüsselung und Signatur.

0 → Der „Selector“-Wert. Hier steht 0, was bedeutet, dass der gesamte Public Key aus dem Zertifikat gespeichert wird. Alternativ könnte 1 stehen, dann wäre nur der „Subject Public Key Info“-Teil enthalten.

0 → Gibt an, welche Hash-Funktion verwendet wird. Ist es 1, steht es für SHA-256 steht. Alternativ könnte 2 für SHA-512 verwendet werden oder, wie in unserem Fall 0, was für das komplette Zertifikat steht.

Hexwerte → Das ist der eigentliche Zertifikatsinhalt, also der öffentliche Schlüssel in hexadezimaler Darstellung.

Möchte man den kompletten DNS-Record einmal manuell auf der Konsole prüfen, geht das wie folgt:

dig +short 70e1c7d87e825b3aba45e2a478025ea0d91d298038436abde5a4c2d0._smimecert.kernel-error.com SMIMEA | sed 's/^3 0 0 //' | tr -d '[:space:]' > dns_cert.hex

Damit holen wir uns den SMIMEA-Eintrag, entfernen die vorderen 3 0 0, da diese nur die Nutzungsparameter angeben, und speichern den reinen HEX-Wert in eine Datei.

xxd -r -p dns_cert.hex dns_cert.der

Hier wandeln wir den HEX-String in eine binäre DER-Datei um.

openssl x509 -inform DER -in dns_cert.der -text -noout

So kann man sich das Zertifikat im lesbaren Format anzeigen lassen.

Und nun?

SMIMEA ist leider noch immer nicht besonders weit verbreitet. Das liegt sicherlich daran, dass das RFC noch immer experimental ist, aber auch daran, dass es auf weiteren Techniken aufbaut, die ebenfalls eher selten genutzt werden. So braucht man SMIMEA nur, wenn man überhaupt selbst ein S/MIME-Zertifikat zur Signatur und Verschlüsselung von E-Mails verwendet. Zusätzlich muss die Domain per DNSSEC geschützt sein – was noch weniger verbreitet ist – 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.

Ihr kennt das doch mit der Sicherheit im Internet: Sie ist nur relevant, wenn man damit Geld verdienen kann oder wenn man Opfer geworden ist. Die Implementierung von SMIMEA ist also 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.

Pffff… 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 der E-Mail-Adresse 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.

Naja, jetzt könnt ihr die Skripte nutzen und euch den ganzen Fummel selbst auf der CLI anschauen, testen und vor allem auch verstehen.

Viel Spaß! 😃


B.t.w.: Das einzig korrekt funktionierende online Tool, was ich finden konnte ist: https://www.co.tt/smimea.cgi

Alle anderen sind nicht erreichbar, halten sich nicht ans RFC oder ich war zu blöde, sie zu bedienen.

Arduino und die jammernde Pflanze: Technik trifft Humor

Auf irgendeinem CCC Event bin ich über eine lustige Projektidee einer jammernde Pflanze gestoßen. Diese hat mir und auch meiner größeren Tochter so gut gefallen, dass wir es zusammen nachbauen wollten.

Geöffnetes Gehäuse mit der gesamten Technik für das Arduino-Projekt: Die jammernde Pflanze – Technik trifft Humor

Ziel ist ein kleines „Gerät“, welches den Feuchtigkeitsgehalt der Blumenerde einer Pflanze misst. Ist der Wert zu „trocken“, soll mittels eines kleinen MP3 Players eine Audiodatei abgespielt werden. So bekommt man als Pflanzeneigentümer mit, wenn die Pflanze gegossen werden muss. Damit die Pflanze sich nur beschwert, wenn auch jemand da ist (sonst hört es ja keiner) gibt es noch einen kleinen Bewegungsmelder. Ist also die Blumenerde zu trocken und es wird eine Bewegung erkannt, jammert die Pflanze und schon weiß man, dass die Pflanze Wasser braucht.

Da es das erste Projekt dieser Art für meine Tochter ist, sollte es so übersichtlich und einfach wie möglich sein. Daher wird es auch nicht bis ins letzte Detail ausgeklügelt sein.

Beim Arduino haben wir uns für den Nano entschieden, denn er hat fast die gleichen Möglichkeiten, wie der große UNO, ist aber halt deutlich kleiner. Der MP3 Player ist ein kleines DFPlayer Modul, als Bewegungsmelder arbeitet der HC-SR312 und der normale Feuchtigkeitssensor.

Gestartet haben wir mit einem einfachen Breadboard um die Verschaltung, Modul für Modul, zu setzen und die Ansteuerung mit dem Arduino anhand der Beispiele zu testen. So ist es einfacher nachzuvollziehen und man konnte jedes Modul einfach testen.

Beim DFPlayer haben wir per TTS Texte in verschiedene MP3s umgewandelt und auf der SD Karte im Ordner mp3 gespeichert. Diese MP3s werden random abgespielt, wenn die Erde zu trocken ist und eine Bewegung erkannt wurde.

Nachdem die elektronische Verschaltung klar war und zusammen mit dem Code funktionierte.

Screenshot der Arduino IDE mit dem Code für das Arduino-Projekt: Die jammernde Pflanze – Technik trifft Humor

Haben wir mit KiCad eine kleine Platine designt um diese „drucken“ zu lassen, damit am Ende alle Bauteile auf dieser verlötet werden können. So hat man weniger Kabelsalat und alles ist platzsparend aufgehoben.

Elektrischer Schaltplan für das Arduino-Projekt: Die jammernde Pflanze – Technik trifft Humor

Im Anschluss haben wir noch mittels FreeCAD ein Gehäuse für die Elektronik designt und es mit dem 3D Drucker gedruckt. Die einzelnen Teile haben wir, um es einfach zu halten, jeweils mit einem Tropfen Sekundenkleber fixiert.

Screenshot von FreeCAD 0.19 beim Design des Gehäuses für das Arduino-Projekt: Die jammernde Pflanze – Technik trifft Humor

Inzwischen steckt das Teil in der Blume und meldet sich erfolgreich wenn es Zeit ist, die Blume zu wässern. Da es abhängig von den MP3s auf dem Player ist, was die Pflanze „sagt“… Sind damit lustige Reaktionen fast schon garantiert. Die Pflanze kann dich im Vorbeigehen voll jammern, um Wasser betteln oder beginnen zu schimpfen.

Natürlich wird meine Tochter nach dem Projekt nicht in der Lage sein, dieses vollständig ohne Hilfe zu wiederholen aber die einzelnen Schritte sind klar. Wie so ein Gerät entsteht, was für Punkte im groben nötig sind… All diese Dinge sind nun deutlich transparenter. Schnell findet man Dinge, welche man verbessern könnte. Feuchtigkeitssensor und die restliche Elektronik trennen oder mit einem NodeMCU ESP8266 mit WIFI Statusdaten auf einem Webserver oder so etwas senden. Oder einfach alles mittels Li-Ion Polymer Akkus und einem kleinen BMS unabhängig vom Stromnetz werden. Usw usw usw….

Wenn jemand dieses kleine Projekt selbst nachbauen möchte, kommen ab hier die nötigen Dinge.

Arduino Quellcode für die Jammernde Pflanze:

#include <Arduino.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>

/* --- Pins ---------------------------------------------------- */
const uint8_t PIN_DF_RX   = 10;
const uint8_t PIN_DF_TX   = 11;
const uint8_t PIN_PIR     = 7;
const uint8_t PIN_SENSOR = A0;

/* --- Parameter ----------------------------------------------- */
const int schwellwert = 380;
const unsigned long PLAY_COOLDOWN_MS = 15000;
const uint8_t TRACK_JAMMERN = 1;

/* --- Objekte ------------------------------------------------- */
SoftwareSerial dfSerial(PIN_DF_RX, PIN_DF_TX);
DFRobotDFPlayerMini dfPlayer;

/* --- Laufzeitstatus ------------------------------------------ */
unsigned long lastPlay = 0;

/* ------------------------------------------------------------- */

void setup() {
  pinMode(PIN_PIR, INPUT);

  Serial.begin(115200);
  dfSerial.begin(9600);

  Serial.println(F("Initializing DFPlayer ..."));

  if (!dfPlayer.begin(dfSerial)) {
    Serial.println(F("DFPlayer init failed"));
    while (true);
  }

  dfPlayer.volume(20);
  dfPlayer.outputDevice(DFPLAYER_DEVICE_SD);
  dfPlayer.EQ(DFPLAYER_EQ_NORMAL);
  dfPlayer.setTimeOut(500);

  Serial.println(F("DFPlayer Mini online"));
}

/* ------------------------------------------------------------- */

void loop() {
  /* DFPlayer Events immer zuerst abholen */
  if (dfPlayer.available()) {
    handleDFPlayerEvent(dfPlayer.readType(), dfPlayer.read());
  }

  int messwert = analogRead(PIN_SENSOR);
  bool bewegung = digitalRead(PIN_PIR) == HIGH;
  bool trocken = messwert > schwellwert;

  unsigned long now = millis();

  if (trocken && bewegung) {
    if (now - lastPlay >= PLAY_COOLDOWN_MS) {
      Serial.println(F("Bewegung + Erde trocken -> spiele Sound"));
      dfPlayer.play(TRACK_JAMMERN);
      lastPlay = now;
    }
  } else {
    logStatus(trocken, bewegung, messwert);
  }

  delay(100);  // leichte Entlastung – kein Logik-Delay
}

/* ------------------------------------------------------------- */

void logStatus(bool trocken, bool bewegung, int messwert) {
  if (!bewegung && trocken) {
    Serial.print(F("Keine Bewegung, Erde trocken: "));
  } else if (bewegung && !trocken) {
    Serial.print(F("Bewegung, Erde ok: "));
  } else if (!bewegung && !trocken) {
    Serial.print(F("Keine Bewegung, Erde ok: "));
  }
  Serial.println(messwert);
}

/* ------------------------------------------------------------- */

void handleDFPlayerEvent(uint8_t type, int value) {
  if (type == DFPlayerPlayFinished) {
    Serial.print(F("Track "));
    Serial.print(value);
    Serial.println(F(" beendet"));
  }
}

Für den DFPlayer benötigt man noch die nötige library, diese gibt es zum Beispiel bei GitHub und wird einfach lokal unter /home/USERNAME/Arduino/libraries abgelegt.

Die STL Dateien für den 3D Drucker gibt es hier:

STL File Gehäuse / STL File Deckel

Eine Amazon Einkaufsliste haben wir hier:

Optional oder zum Test:

Dann fehlen nur noch die >>Gerber Dateien<< zum bestellen der Platine.

Windows Server 2012 R2 mit Exchange 2016: SSL Labs A-Rating erreichen

Qualis A+ Icon.

Ich habe hier einen Windows Server 2012 R2 mit einem Exchange 2016. Out of the Box spricht das Ding TLS 1.0, SSLv3 und RC4. Da gehen einem schnell die Haare hoch, oder?

Kann man so ein System auf ein A+ im Qualys Rating bekommen und es arbeitet dann noch? Kleiner Spoiler, ja geht!

Ich muss zugeben, Microsoft Produkte strengen mich in dieser Hinsicht immer sehr an. Auch wenn sie ganz sicher ihre Daseinsberechtigung haben.

Nun gut… Für ein A+ benötigen wir neben brauchbaren ciphern, sauberen Protokollen usw. noch HTTP Strict Transport Security (https://de.wikipedia.org/wiki/HTTP_Strict_Transport_Security). Dieses ist im Grunde nur ein http response header und dieses konfigurieren wir im IIS Manager. Das besagte Testsystem kümmert sich nur um den Exchangeserver, daher konfiguriere ich es ganz oben (so wird es überall hin vererbt).

IIS-Manager ==> HTTP-Antwortheader ==> Hinzufügen

Screenshot der Internetinformationsdienste (IIS)-Manager.

Name: strict-transport-security
Wert: max-age=31536000; includeSubdomains

Wie auch im Bild zu sehen.

Qualis A+ Wertung.

Jetzt der spannende Teil. Man muss einige Änderungen in der Registrierung vornehmen um MD5, RC4 usw. zu deaktivieren. Ich habe da etwas vorbereitet um dieses zu tun. Ebenfalls wird SSLv3, TLS 1.0, TLS 1.1 deaktiviert. TLS 1.2 und TLS 1.3  wird aktiviert (TLS 1.3 dabei nur für die Zukunft). Ebenfalls werden super schwache Cipher deaktiviert. Die bestmöglichen dafür aktiviert und es wird auch eine Cipherorder vorgegeben. Das File einfach herunterladen, ausführen und im Anschluss den Server durchstarten (Microsoft halt…).

Aber dann sollte man sein A+ haben. Auch wenn ich gerne noch schönere Cipher hätte :-/ aber mehr ging nicht, bzw. habe ich nicht hin bekommen!

Qualis Wertung mit Blick auf Cipher Suites und Protocols.

Oh natürlich… Das Registry Snippet zum Download:

Fragen? Dann fragen…

Bash-Skript: Automatisiertes Erstellen von Abuse-E-Mails

Wenn man ein System mit öffentlicher IP Adresse hat, klopfen irgendwelche Bots oder ein Script Kiddie direkt nach dem Einschalten die Dienste auf mögliche Schwachstellen, schwache Zugangsdaten oder default logins ab. Kennt wohl jeder…

Davor schützt gepatchte Software, Dienste möglichst unerreichbar machen oder ein IDS (Intrusion detaction system). Im einfachsten Fall ist dieses Fail2Ban.

Screenshot der Konsolenausgabe vom Abuse Scipt.

Was tun, wenn Fail2Ban Brute Force Angriffe auf SSH oder Postfix (Mailserver) feststellt? Tjo, die Adresse an weiteren Versuchen hindern natürlich. OK, darum kümmert sich Fail2Ban… Am besten noch so, das Fail2Ban dieses seinen anderen Kisten ebenfalls mitteilt, dann wird diese IP es dort schon nicht mehr probieren können. Ebenfalls könnte es eine gute Idee sein, dieses Verhalten der IP Adresse irgendwo zu melden. Dienste wie AbuseIPDB lassen sich gut mit Fail2Ban verbinden. So können andere Admins auf der Welt direkt davon profitieren.

Könnte man nicht zusätzlich noch den ISP oder Hoster hinter der „bösen“ IP Adresse informieren? Meist ist es ja ein Root-Server oder VPS oder, oder… Vielleicht weiß der Admin ja noch nichts von seinem kompromittierten Glück?!? Ja kann man. Dazu sollte es im whois zur IP Adresse immer eine „abuse-mailbox“ also einen „abuse-contact“ geben.

Als kleines Beispiel:

➜  ~ whois 8.8.8.8|grep -i abuse
Comment:        All abuse reports MUST include: 
OrgAbuseHandle: IPADD5-ARIN
OrgAbuseName:   ipaddressing
OrgAbusePhone:  +1-877-453-8353 
OrgAbuseEmail:  ipaddressing@level3.com
OrgAbuseRef:    https://rdap.arin.net/registry/entity/IPADD5-ARIN
Comment:        Please note that the recommended way to file abuse complaints are located in the following links. 
Comment:        To report abuse and illegal activity: https://www.google.com/contact/
OrgAbuseHandle: ABUSE5250-ARIN
OrgAbuseName:   Abuse
OrgAbusePhone:  +1-650-253-0000 
OrgAbuseEmail:  network-abuse@google.com
OrgAbuseRef:    https://rdap.arin.net/registry/entity/ABUSE5250-ARIN

An diese Adresse kann man sich nun mit seinem Anliegen wenden. Damit der angeschriebene ~Admin~ etwas mit der Meldung anfangen kann sollte sie die folgenden Informationen enthalten:

– die IP Adresse des eigenen Systems.
– die IP Adresse von welcher die Störungen kommen/gekommen sind.
– Ein paar Zeilen aus dem Logfile um das Problem verständlich zu machen.
– Die Zeitzone des eigenen Systems, damit die Datums und Zeitangaben im Logfile sinnvoll nutzbar sind.
– Eine kurze Beschreibung, warum man dieses als Problem empfindet.

Da ein Hoster diesen Abuse natürlich an seinen Kunden weitergeben wird und dieser möglicherweise noch Fragen dazu haben könnte, hilft es, wenn man direkt erlaubt die Kontaktdaten weiter zu geben.

Leider findet sich die AbuseMailbox im whois nicht immer und vor allem nicht einheitlich. Gibt man sich nun die Mühe und sammelt alle nötigen Informationen zusammen, wird man nach dem Absender der eigentlichen AbuseMail oft enttäuscht. Denn der überwiegende Teil dieser E-Mails landet einfach beim Empfänger in /dev/null. Rückmeldungen bekommt man fast nie und oft hat es einfach überhaupt keinen Effekt. Klar hin und wieder hilft es jemandem… Hier und da schiebe ich selbst so einen Abuse an. Dabei möchte ich selbstredend so wenig wie möglich Arbeit in das Thema stecken.

Da mich Systeme wie Fail2Ban direkt mit dem jeweiligen whois zur IP Adresse informieren, brauche ich nur noch etwas, was mir die anderen Informationen einsammelt und am besten direkt abschickt. Dafür habe ich folgendes bash script geschrieben.

An dieses kann ich direkt beim Aufruf durch andere scripte oder durch mich die „böse“ IP Adresse und die E-Mail-Adresse der AbuseMailbox übergeben. Das script prüft dann ob es sich um eine brauchbare E-Mail-Adresse und IP handelt, sammel zum Beispiel für SSH Brute Force die nötigen Informationen aus dem auth.log, generiert mir dann meine AbuseMail und sendet diese nach einer Sichtkontrolle ab. Ich selbst bekomme diese E-Mail dann noch als BCC. Das script ist alt, stumpf und sehr einfach. Weil die Frage nach dem script kam, hier das script:

#!/usr/local/bin/bash

if [ "$1" == "-h" ] ; then
    printf "You can add abuse ip and mail on start or interactive by request."
    printf "Usage 1: abusemail.sh 1.2.3.4 example@example.org"
    printf "Usage 2: abusemail.sh"
    exit 0
fi

myip="1.2.3.4"
bcc="my@mail.com"


function validateMail()
 {
         local mail=$1
         local stat=1
         if [[ "$mail" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]]; then
                stat=0
        fi
        return $stat
}

function validateIP()
 {
         local ip=$1
         local stat=1
         if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
                OIFS=$IFS
                IFS='.'
                ip=($ip)
                IFS=$OIFS
                [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
                && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
                stat=$?
        fi
        return $stat
}
clear
printf "\x1b[31;1;4mCreate und send abuse e-mail!\x1b[0m\n\n"
printf "Enter IP Address"

if [ "$1" == "" ] ; then
    read ip
else
    ip=$1
fi

validateIP $ip

if [[ $? -ne 0 ]];then
  printf "Invalid IP Address ($ip)"
  exit 1
else
  printf "$ip ==> \x1b[32;1;4mOK\x1b[0m\n\n"
fi
printf "\n"
printf "Enter Abuse E-Mail Address"

if [ "$1" == "" ] ; then
    read mail
else
    mail=$2
fi

validateMail $mail

if [[ $? -ne 0 ]];then
  printf "Invalid Abuse E-Mail Address ($mail)"
  exit 1
else
  printf "$mail  ==> \x1b[32;1;4mOK\x1b[0m"
fi

printf "Dear abuse team,\n\nI got some SSH connections from one of your IPv4 addresses. It seems to\nbe a bot or something....\n\nYes, you can forward this E-Mail with contact informations to your \ncustomer to solve this case, if necessary.\n\nMy timezone: Europe/Berlin\nMy IPv4: $myip\nYour IPv4: $ip\n\nSome log snippets:\n" > /tmp/abusemail
grep $ip /var/log/auth.log >> /tmp/abusemail
printf "\nBest regards\nSebastian van de Meer\n" >> /tmp/abusemail


printf "\n\n\n\x1b[31;1;4mCheck e-mail before sending!\x1b[0m\n\n"
printf "\x1b[32;1;4mRecipient:\x1b[0m $mail\n\n"
printf "\x1b[32;1;4mSubject:\x1b[0m Abuse against: $ip - Brute Force\n\n"
cat /tmp/abusemail
printf "\n\n"

while true
do
 printf "\x1b[33;1;4mSend Abuse Mail? [Y/n]\x1b[0m\n"
 read -r input
 
 case $input in
     [yY][eE][sS]|[yY])
 cat /tmp/abusemail | /usr/local/bin/mailx -s "Abuse against: $ip - Brute Force" -r "My Name <myfrom@address.com>" -b $bcc $mail
 printf "Abuse Mail is on it´s way..."
 break
 ;;
     [nN][oO]|[nN])
 printf "Abuse Mail aborted"
 break
        ;;
     *)
 printf "Invalid input..."
 ;;
 esac
done

Noch Fragen? Dann fragen!

Rspamd: Automatisches Spam/Ham-Lernen mit Dovecot und IMAPSieve

Bei jedem Spamfilter kann es vorkommen, dass Spam durchrutscht oder eine echte Nachricht fälschlicherweise als Spam eingestuft wird. Rspamd bietet über das Webinterface die Möglichkeit, trainiert zu werden. Hier kann man einfach den Quellcode jeder E-Mail kopieren und Rspamd mitteilen, ob es sich dabei um Spam (SPAM) oder um eine legitime Nachricht (HAM) handelt. Dieses Vorgehen ist jedoch ungeeignet, um den Spamfilter effektiv zu trainieren.

Dovecot and RSPAMD Logo

Wünschenswert wäre folgende Lösung: Immer wenn ein Benutzer eine E-Mail in den Ordner „Junk“ verschiebt, sollte diese E-Mail automatisch von Rspamd als Spam gelernt werden. Zusätzlich sollte jede E-Mail, die der Benutzer aus dem „Junk“-Ordner herausholt, als Ham gelernt werden.

Genau dieses Szenario möchte ich hier kurz beschreiben. Das Hostsystem ist ein FreeBSD; Linux-User müssen daher bei den Pfaden wie /usr/local aufpassen! Ebenfalls lauscht mein Rspamd-Worker nicht auf einem Unix-Socket, sondern auf der IP 127.0.0.3, da er in einer Jail-Umgebung läuft.

Beginnen wir mit der Konfiguration für Dovecot.

20-imap.conf:

protocol imap {
  mail_plugins = $mail_plugins sieve
}

90-plugin.conf:

plugin {
  sieve_plugins = sieve_imapsieve sieve_extprograms

  # From elsewhere to Spam folder or flag changed in Spam folder
  imapsieve_mailbox1_name = Junk
  imapsieve_mailbox1_causes = COPY FLAG
  imapsieve_mailbox1_before = file:/usr/local/etc/dovecot/sieve/report-spam.sieve

  # From Spam folder to elsewhere
  imapsieve_mailbox2_name = *
  imapsieve_mailbox2_from = Junk
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_before = file:/usr/local/etc/dovecot/sieve/report-ham.sieve

  sieve_pipe_bin_dir = /usr/local/libexec/dovecot

  sieve_global_extensions = +vnd.dovecot.pipe
}

/usr/local/etc/dovecot/sieve/report-spam.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "imap4flags"];

if environment :is "imap.cause" "COPY" {
    pipe :copy "sa-learn-spam.sh";
}

# Catch replied or forwarded spam
elsif anyof (allof (hasflag "\\Answered",
                    environment :contains "imap.changedflags" "\\Answered"),
             allof (hasflag "$Forwarded",
                    environment :contains "imap.changedflags" "$Forwarded")) {
    pipe :copy "sa-learn-spam.sh";
}

/usr/local/etc/dovecot/sieve/report-ham.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

if environment :matches "imap.mailbox" "*" {
  set "mailbox" "${1}";
}

if string "${mailbox}" [ "Trash", "train_ham", "train_prob", "train_spam" ] {
  stop;
}

pipe :copy "sa-learn-ham.sh";

Natürlich nicht vergessen, die beiden neuen Sieve-Skripte für Sieve zu kompilieren:

# sievec /usr/local/etc/dovecot/sieve/report-spam.sieve
# sievec /usr/local/etc/dovecot/sieve/report-ham.sieve

Es fehlen nur noch die beiden Shell-Skripte, um die Mails an Rspamd weiterleiten zu können.

/usr/local/libexec/dovecot/sa-learn-spam.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_spam

/usr/local/libexec/dovecot/sa-learn-ham.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_ham

Beide müssen ausführbar sein:

# chmod +x /usr/local/libexec/dovecot/sa-learn-spam.sh /usr/local/libexec/dovecot/sa-learn-ham.sh

Wenn ich nun eine E-Mail in den Ordner „Junk“ verschiebe, lernt Rspamd diese automatisch als Spam:

2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as spam: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Verschiebe ich eine E-Mail aus dem Ordner „Junk“ heraus, wird sie, wie gewünscht, als Ham gelernt:

2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as ham: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Fragen? Einfach fragen!

Ach, und was man nicht mehr verwenden sollte: das Antispam-Plugin – das ist „tot“.

E-Mail-Test: Niederländische Standards ziehen an

E-Mail Test der Niederlande für die E-Mail Domain kernel-error.de
Die Domain kernel-error.de ist in der Hall of Fame der niederländischen IT Security Tests.

Der niederländische Staat bietet ein Tool an um Webseiten sowie Mailserver auf ihre Transportsicherheit zu überprüfen. Heute sind die neuen guidelines gestartet. Dieses zieht die geforderte „Sicherheit“ schon ein deutliches Stück an.

So gibt es nun eine Warnung für TLS 1.0 sowie TLS 1.1. Wie wir alle wissen wollte man es ab Q1 2020 nicht mehr nutzen, hier wird es ebenfalls bald von Qualys SSL eine Abwertung geben. Zusätzlich wird besonderer Wert auf einen guten Diffie-Hellman key exchange gelegt und ebenfalls sind weitere Cipher herausgeflogen. Alles um TLS 1.3 möglichst gut den Weg zu ebnen!

https://en.internet.nl/mail/kernel-error.com/

Ebenfalls gibt es in der Hall of Fame nun noch die Sektion der Champions, also die Domains welche es sowohl beim Webserver als auch beim Mailserver die 100% zu erreichen.

Fragen? Dann fragen 🙂

Automatische E-Mail-Archivierung mit Dovecot IMAP einrichten

Um etwas mehr Ordnung in meinem IMAP Postfach zu halten nutzen ich ein kleines Python Skript cleanup-maildir https://www.freshports.org/mail/cleanup-maildir/. Dieses Skript läuft jede Nacht und sortiert automatisch alle E-Mails die älter sind als 365 Tage aus meinem Posteingang (inbox) sowie meinen Gesendeten E-Mails ins Archive. Dabei sortiert es die Mails automatisch in Unterordner mit dem Jahres und Monatsnamen, damit ich die E-Mails schneller finden kann.

Zum Beginn lief es nur als cronjob auf meinem Postfach, inzwischen sammelt es sich die Benutzer, den MailBox Pfad sowie die Option ob es laufen soll oder nicht (autoarchive=0|1) aus dem LDAP Server.

Den grundlegenden Aufruf des Skriptes möchte ich kurz mit euch teilen!

sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Inbox' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive ''
sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Sent' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive 'Sent/'

sudo -u vmboxuser lässt den Befehl als der Nutzer laufen, welcher bei mir übergreifen Zugriff auf die Postfächer hat.
–age=365 sagt, dass nur E-Mails älter 365 Tage angefasst werden sollen.
–archive-folder=’Archive.Inbox/Sent‘ gibt die Zielordner im Postfach an.
–maildir-root='[…]‘ das Postfach (Domain und Postfachname kommen normalerweise als Variable aus dem LDAP).
archive sagt dem Skript, dass archiviert werden soll. Man könnte auch löschen oder ähnliches.
ist der Default also die Inbox
‚Sent/‘ sind die gesendeten E-Mail.

 Die entstehende Ordnerstruktur im Postfach ist dann:

Screenshot der IMAP Archive Ordnerstruktur.

Tjo… Läuft seit Jahren sehr gut und räumt die Postfächer automatisch auf.

« Ältere Beiträge

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑