Automatische Veröffentlichung von Zertifikatsperrlisten nach einem Zertifikat-Widerruf

Oft bekomme ich mit, dass PKI-Betreiber gerne wünschen, dass für widerrufene Zertifikate umgehend eine neue Zertifikatsperrliste ausgestellt werden soll.

Nachfolgend möchte ich einige Überlegungen dazu loswerden, warum dieses Vorgehen nicht optimal ist und einen eleganteren Lösungsvorschlag machen.

Welches Problem wollen wir eigentlich lösen?

Der eigentliche Wunsch, der hinter der sofortigen Sperrlistenveröffentlichung steht ist, dass man sich einen "Live-Widerruf" wünscht, sprich dass der Widerruf sofort, oder zumindest so schnell wie möglich wirksam wird.

Wirksam heißt in diesem Fall, dass Relying Parties die Zertifikatsperrung umgehend erkennen und die widerrufenen Zertifikate entsprechend nicht mehr akzeptieren.

Die Grenzen der Sinnhaftigkeit

Bevor wir über Lösungen sprechen sollten wir uns bewusst machen, dass unser Ansatz schon im Vorfeld zum scheitern verurteilt ist.

Zertifikat-Sperrinformationen sind nicht "live": (Windows-)Clients speichern CRLs zwischen und rufen entsprechend nicht bei jeder Zertifikatprüfung neue Sperrlisten ab. Im schlechtesten Fall rufen Clients gar erst eine neue Zertifikatsperrliste ab, wenn die zwischengespeicherte Sperrliste abgelaufen ist. Auch die Verwendung der Onlineresponder (OCSP) Rolle wird hieran nichts ändern.

Und selbst wenn wir eine super robuste Sperrstatusinfrastuktur haben, stehen wir vor dem Problem, dass nicht alle Relying Parties denn auch den Sperrstatus von Zertifikaten überhaupt überprüfen.

Wir können somit festhalten, dass wir nicht garantieren können, dass Clients von neu ausgestellten Zertifikatsperrlisten tatsächlich Gebrauch machen, was wiederum bedeutet, dass wir von einer häufigeren Ausstellung (außer in Ausnahmefällen) keinen nennenswerten Vorteil haben werden.

Der naheliegendste Weg wäre, bei jeder Zertifikatsperrung direkt die Ausstellung einer Zertifikatsperrliste auszulösen.

Manche erstellen sich hierfür beispielsweise einen geplanten Task auf der Zertifizierungsstelle, der das Ereignis mit ID 25 der Quelle Microsoft-Windows-CertificationAuthority oder das Ereignis mit ID 4870 der Quelle Microsoft-Windows-Security-Auditing abfängt und dann eine Sperrlistenveröffentlichung auslöst.

Auch soll es schon Feature-Anfragen für mir bekannte Certificate Lifecycle Management (CLM)-Produkte gegeben haben, entsprechende Befehle an die Zertifizierungsstelle zu senden.

Dieser Ansatz hat jedoch mehrere gravierende Nachteile:

Die Erstellung einer Zertifikatsperrliste ist ressourcenintensiv – insbesondere wenn viele Zertifikate widerrufen wurden oder widerrufen werden sollen. Die Erstellung einer Zertifikatsperrliste kann mehrere Minuten dauern und entsprechend Speicherplatz/Systemressourcen verbrauchen. Als Faustregel kann man von 1 MB pro 20.000 widerrufenen Zertifikaten ausgehen.

Jede ausgestellte Zertifikatsperrliste, die noch zeitlich gültig ist, wird in der Zertifizierungsstellen-Datenbank gespeichert. Wenn wir zu oft Zertifikatsperrlisten erzeugen (und diese im schlechtesten Fall auch entsprechend groß sind), wächst unsere Zertifizierungsstellen-Datenbank enorm an. Als einen Extremfall aus der Praxis habe ich einmal eine Zertifizierungsstelle erlebt, deren Datenbank über 65 GB (!) an gültigen Zertifikatsperrlisten beinhaltete. Verursacht wurde dies durch den massenhaften Widerruf von Zertifikaten via Script. Jeder einzelne Widerruf hat die Erstellung einer neuen CRL ausgelöst, was zu einer Kettenreaktion geführt hat.

Darüber hinaus wird das Prinzip der Rollentrennung verletzt, wenn ein CLM-System das Recht hat, die Zertifizierungsstelle zur Ausstellung von Zertifikatsperrlisten anzuweisen.

Was wir eigentlich wollen und was realistisch machbar ist

Nachdem wir nun zur Erkenntnis gekommen sind, dass die Ausstellung einer Zertifikatsperrliste bei jedem Zertifikatwiderruf keine besonders gute Idee ist, könnten wir zu dem Schluss kommen, dass stattdessen eine regelmäßige Veröffentlichung durch die Zertifizierungsstelle eine sinnvolle Lösung sein könnte. Und das ist schließlich genau das, was die Zertifizierungsstelle in ihrer Standardkonfiguration schon macht.

Vielleicht ist uns dieses Intervall jedoch zu lange und wir möchten gerne vorher schon eine Veröffentlichung auslösen.

Wir könnten beispielsweise in regelmäßigen Abständen, ohne Interaktion eines Zertifizierungsstellen-Administrators, und auch nur dann, wenn es seit der letzten Veröffentlichung zu einem Widerruf von Zertifikaten gekommen ist, eine neue Sperrliste ausstellen, ohne unnötige Last auf der Zertifizierungsstelle zu generieren.

Unser Ansatz könnte wie folgt aussehen:

  • Zunächst ermitteln wir, wann zuletzt eine Zertifikatsperrliste ausgestellt wurde (durch Auswertung des NotBefore-Datums der aktuellen Zertifikatsperrliste).
  • Danach ermitteln wir, ob seitdem Zertifikate widerrufen wurden (durch Abfrage des Windows-Ereignisprotokolls für den Zeitraum zwischen "jetzt" und dem Veröffentlichungsdatum der letzten CRL)
  • Wenn das der Fall sein sollte, stellen wir eine neue Zertifikatsperrliste aus. Wenn nicht, dann nicht.

Wir bedienen uns hierfür des Ereignisses mit ID 25 der Quelle Microsoft-Windows-CertificationAuthority.

Alternativ ginge auch das Ereignis mit ID 4870 der Quelle Microsoft-Windows-Security-Auditing, das aber erst aktiviert werden muss), da wir hier eine effiziente Abfrage gestalten können.

Wir könnten diese Informationen auch über die Zertifizierungsstellen-Datenbank beziehen, was aber deutlich weniger effizient ist und mit zunehmender Anzahl Zertifikate immer langsamer werden wird.

Nachfolgend ein Beispiel-Powershell-Script:

#requires -RunAsAdministrator

[cmdletbinding()]
param()

$RegistryRoot = "HKLM:\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration"

If (-not (Test-Path -Path $RegistryRoot)) {
Write-Error -Message "No CA found!" -ErrorAction Stop
}

# Query the CA registry for the relevant information
$CaName = (Get-ItemPropertyValue -Path $RegistryRoot -Name "Active")
$CaServerName = (Get-ItemPropertyValue -Path "$RegistryRoot\$CaName" -Name 'CAServerName')
$ClockSkewMinutes = (Get-ItemPropertyValue -Path "$RegistryRoot\$CaName" -Name 'ClockSkewMinutes')

# Parse the current CRL for it's creation time
$CRLFile = "$env:SystemRoot\System32\CertSrv\CertEnroll\$CaName.crl"
$CRL = New-Object -ComObject X509Enrollment.CX509CertificateRevocationList
$CRL.InitializeDecode([System.Convert]::ToBase64String((Get-Content -Path $CRLFile -Encoding Byte)), 1)
$ThisUpdateUtc = [DateTime]::SpecifyKind($CRL.ThisUpdate, [DateTimeKind]::Utc)

# Query the audit log for any revocations that happened since the last $Events = Get-WinEvent -FilterHashtable @{
Logname='Application'
ProviderName='Microsoft-Windows-CertificationAuthority'
Id='25'
StartTime=($ThisUpdateUtc.AddMinutes($ClockSkewMinutes).ToLocalTime())
} -ErrorAction SilentlyContinue

# Only publish a new CRL if there were any revocations since the last CRL publication
If ($Events) {
Write-Host "Publishing CRL"
$CertAdmin = New-Object -ComObject CertificateAuthority.Admin
$CertAdmin.PublishCRL("$CaServerName\$CaName", 0)
}

Dieses Script führen wir in regelmäßigen Abständen per geplantem Task auf der Zertifizierungsstelle aus, beispielsweise einmal in der Stunde.

Wird zwischenzeitlich eine Zertifikatsperrung vorgenommen, erkennt unser Script dies und veröffentlicht beim nächsten Lauf eine neue Zertifikatsperrliste.

Fallstricke

Auf Zertifizierungsstellen mit hohem Volumen wird das Ereignisprotokoll schneller beschrieben und erreicht entsprechend früher seine maximale Größe, was zur Löschung der ältesten Ereignisse führen wird. Damit das Script zuverlässig arbeitet, muss für das Ereignisprotokoll der Zertifizierungsstelle also eine entsprechend ausreichende Maximalgröße eingestellt sein.

Schlussworte

Meiner Ansicht nach wird der Mechanismus für Zertifikatwiderruf überbewertet.

  • Wir haben als PKI-Betreiber keine Kontrolle darüber, dass Relying Parties überhaupt den Sperrstatus überprüfen.
  • Wir haben als PKI-Betreiber keine Kontrolle darüber, dass Relying Parties eine neue Zertifikatsperrliste oder OCSP-Antwort anfordern, solange noch eine vorherige Zertifikatsperrliste zeitgültig ist.
  • Wir haben als PKI-Betreiber keine Kontrolle darüber, dass uns die Information, dass Zertifikate widerrufen werden müssen, überhaupt erreicht.

Ich halte es hier wie Peter Gutmann: CRLs don’t work.

Der robusteste Weg ist meiner Meinung nach, nicht auf die Sperrstatusinfrastruktur zu vertrauen und stattdessen mit kürzestmöglichen Zertifikatgültigkeiten zu arbeiten – was eine entsprechend häufige Rezertifizierung zur Folge hat.

Weiterführende Links:

Externe Quellen

de_DEDeutsch