Florian Fischer

After Action Report: Delta-Sperrlisten

Freitag, kurz nach sechs Uhr morgens: Unser Dokumentenmanagementsystem lässt niemanden mehr ans Archiv. Die Fehlermeldung ist so hilfreich wie ein Achselzucken: „Eine unbehandelte Ausnahme ist aufgetreten. Genauere Informationen können dem Log entnommen werden.“

Am Ende des Tages wusste ich mehr über Zertifikate und Sperrlisten als in den Jahren davor zusammen. Diesen Text schreibe ich vor allem für mich, um das Gelernte festzuhalten. Vielleicht hilft er aber auch jemandem, der irgendwann vor derselben Meldung sitzt.

Was passiert ist

Im Log stand schnell der eigentliche Fehler: CERT_REV_FAILED – failed to check revocation status. Der Server konnte also nicht prüfen, ob ein Zertifikat gesperrt ist. Das Zertifikat selbst war gültig, nur sein Sperrstatus war unbekannt. Wieso das wichtig ist? Dazu später mehr.

Die Ursache lag nicht bei uns: Die Sperrliste der ausstellenden Zertifizierungsstelle (Certificate Authority - CA) war um 03:59 Uhr abgelaufen. Die neue Liste war am Vortag pünktlich erzeugt, aber nie verteilt worden. Ab da scheiterte jede Anmeldung.

Der Ablauf in Kurzform:

Zeit Was passierte
Vortag, 15:49 Neue Sperrliste wird erzeugt, aber nicht verteilt
03:59 Alte Sperrliste läuft ab, das DMS steht
06:15 Erste Meldung eines Kollegen
ca. 06:40 Ursache mit curl und certutil belegt, Ticket beim Betreiber der CA
ca. 08:44 Neue Liste liegt auf dem Webserver, aber noch nicht im Active Directory
bis 11:26 DMS mal erreichbar, mal nicht, je nach Prozess
11:26 Liste auch im AD, letzte Fehler im Log

Erst mal: Wozu gibt es Zertifikate?

Ich hatte in meiner Laufbahn bisher nie etwas mit Zertifikaten, oder Kryptographie allgemein, zu tun. Von daher musste ich hier wirklich im Urschleim anfangen um erstmal Grundlagen aufzubauen.

Asymmetrische Kryptografie arbeitet mit einem Schlüsselpaar. Den öffentlichen Schlüssel darf jeder kennen, den privaten nur der Besitzer (deswegen auch die Namen). Wir können also zwischen zwei Anwendungsfällen unterscheiden:

Bleibt ein Problem: Woher weiß ich, dass ein öffentlicher Schlüssel wirklich zu dem gehört, der das behauptet? Genau dafür gibt es Zertifikate. Ein Zertifikat sagt: „Dieser Schlüssel gehört zu diesem Namen“, und eine Zertifizierungsstelle bestätigt das mit ihrer Signatur. Das ist wie beim Personalausweis: Ich kenne dich nicht, aber ich vertraue der Behörde, die ihn ausgestellt hat.

In der Praxis ist das eine Kette:

Root-CA                (selbstsigniert, steht im Vertrauensspeicher)
 └─ Issuing-CA         (von der Root signiert)
     └─ Serverzertifikat (von der Issuing-CA signiert)

Der Client prüft jedes Glied: Signatur, Gültigkeitsdatum, Name, Verwendungszweck – und ob das Zertifikat gesperrt ist. Am letzten Punkt wurde es für unser DMS hier ein wenig unangenehm.

Nebenbei hat mir die Kette eine Sache erklärt auf die ich schon vorher mal gestoßen bin: Eine CA stellt keine Zertifikate aus, die länger laufen als sie selbst. Ein Zertifikat ist schließlich nur so lange gültig wie sein Aussteller. Deshalb endeten bei uns alle Zertifikate 2027 (bspw. selbsterstellte für interne PDF-Signaturen), auch wenn wir fünf Jahre ausgewählt hatten: die ausstellende CA selbst läuft dann ab.

Sperrlisten: Basis und Delta

Zertifikate können vor ihrem Ablauf ungültig werden, zum Beispiel wenn ein privater Schlüssel kompromittiert wurde oder ein Server stillgelegt wird. Damit Clients das erfahren, veröffentlicht die CA eine Sperrliste

Eine Sperrliste führt nur die gesperrten Zertifikate auf. Wer auf einer aktuellen Liste nicht steht, gilt als nicht gesperrt. Entscheidend ist das Wort aktuell: Jede Liste hat ein Feld „Nächste Aktualisierung“ (NextUpdate). Danach ist sie ungültig. Ab hier kann man sich vermutlich vorstellen wo das Problem lag.

Windows-CAs arbeiten oft mit zwei Listen:

Der Client braucht beide. Bei uns war die Basis-CRL noch Wochen gültig, aber die Delta-CRL abgelaufen. Damit war der Sperrstatus unbekannt, nicht „gesperrt“. Im Log hieß das entsprechend REVOCATION_STATUS_UNKNOWN.

Ironischerweise stand in der abgelaufenen Delta-CRL kein einziger Eintrag. Inhaltlich fehlte also nichts. Das System konnte es nur nicht wissen. Für Systeme, welche dann die Rolle des Prüfers annehmen, gibt es an diesem Punkt effektiv zwei Möglichkeiten.

Fail-Closed und Soft-Fail

Denn "unbekannt" kann zweierlei Konsequenzen haben:

Beides ist eine Abwägung zwischen Sicherheit und Verfügbarkeit. Fail-Closed ist sicherer, macht das System aber abhängig davon, dass die Sperrlisten immer erreichbar und gültig sind. Das ist gut für die Sicherheit, schlecht wenn man die Nutzer schnell wieder arbeitsfähig machen will.

Diese Sperrliste betrifft dabei jedes Zertifikat, das die CA ausgestellt hat. Die für mich in diesem Moment ziemlich abstrakte Folge war: Wer weiß was noch betroffen ist. Also: extra melden und höhere Prio.

Die Fehlersuche

Das meiste ließ sich mit zwei Bordmitteln von Windows klären.

curl prüft unter Windows die Sperrung genau wie der Server. Der Vergleich mit und ohne Sperrprüfung war der erste Beweis:

curl.exe -v https://<server>/      → CRYPT_E_REVOCATION_OFFLINE
curl.exe -v --ssl-no-revoke https://<server>/  → 200 OK

Das gleiche Ergebnis auf einem der DMS-Server und an meinem regulären Arbeitsplatz hieß: kein lokales Netzproblem, sondern die PKI selbst.

certutil zeigt die ganze Kette mit allen Abrufwegen und ihrem Ergebnis:

certutil -verify -urlfetch server.cer

Darin steht pro Sperrliste, wo sie abgerufen wurde, ob sie gültig ist (Überprüft, OK, Abgelaufen) und ihr Hash. Mit certutil -dump sieht man in einer CRL-Datei ThisUpdate, NextUpdate und den geplanten nächsten Veröffentlichungstermin.

Dann wurde es kniffliger. Die Sperrliste wird an zwei Orten verteilt: per HTTP auf einem Webserver und per LDAP im Active Directory. Am Vormittag lag die neue Liste nur auf dem Webserver, im AD noch die alte. Erkennbar war das am Pfad (ldap:///… heißt AD, http://… Webserver) und am Hash. Um das schnell zu entdecken lief ein kleines Powershell-Skript welches aller zwei Minuten checkt ob ein neues Delta drin war. Hat super funktioniert, aber leider nur den http-Pfad abgedeckt.

Als die neue Liste dann endlich auftauchte, gab es noch ein kleines Detail: Der Last-Modified-Header der Datei zeigte exakt den geplanten Veröffentlichungstermin vom Vortag, auf die Sekunde. Die CA hatte ihren Job also pünktlich gemacht. Liegen geblieben ist die Liste erst beim Verteilen.

Mein curl-Test als Admin lief danach durch, die Dienste unter ihrem Dienstkonto aber nicht. Jeder Prozess prüft selbst, mit eigenem Cache und eigenem Timing beim Rückfall von LDAP auf HTTP. Das Ergebnis: Mal ging das Repository, mal die Suche, mal gar nichts1. Gelöst hat es erst die Veröffentlichung ins AD.

Was ich (schmerzlicherweise) über Caches gelernt habe:

Was ich mitnehme

Und ganz persönlich: Vor diesem Freitag habe ich von vielen der Sachen hier nie gehört. Jetzt habe ich einen soliden Einstieg in diese Themen gefunden, auch wenn ich hoffe das Wissen nicht so schnell erneut unter solchen Umständen einsetzen zu müssen.

  1. Das hat es besonders spaßig gemacht. Auf den ersten Versuch ging es, die Nutzer waren froh. Kurz danach die Ernüchterung als es wieder kaputt ging.↩