Szenario 6.4: Zertifikat widerrufen

Kategorie: Widerruf (Revocation)
Komplexität: ⭐⭐⭐ (Mittel)
Voraussetzungen: Zertifikat und CA-Zugriff
Geschätzte Zeit: 10-15 Minuten


Beschreibung

Dieses Szenario beschreibt den vollständigen Prozess zum Widerruf eines Zertifikats. Ein Widerruf ist notwendig bei:

  • Schlüsselkompromittierung - Schlüssel gestohlen/verloren
  • Ablösung - Neues Zertifikat ausgestellt
  • Betriebseinstellung - Dienst nicht mehr aktiv
  • Zugehörigkeitsänderung - Mitarbeiter verlässt Organisation
  • Policy-Verletzung - Zertifikat entspricht nicht mehr Richtlinien

Workflow

flowchart TD REQUEST[Widerrufsantrag] --> VERIFY[Berechtigung prüfen] VERIFY --> REASON[Grund dokumentieren] REASON --> DB[In Revocation-DB eintragen] DB --> CRL[CRL aktualisieren] DB --> OCSP[OCSP aktualisieren] CRL --> PUBLISH[Veröffentlichen] OCSP --> PUBLISH PUBLISH --> NOTIFY[Stakeholder benachrichtigen] NOTIFY --> ARCHIVE[Dokumentation archivieren] style REQUEST fill:#ffebee style PUBLISH fill:#e8f5e9


Code-Beispiel (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Zu widerrufendes Zertifikat laden
var certToRevoke = ctx.LoadCertificate("server.crt.pem");
 
// CA-Zugriff
var caCert = ctx.LoadCertificate("intermediate-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("intermediate-ca.key.pem", "CaPassword!");
 
// Widerruf dokumentieren
var revocationRecord = new RevocationRecord
{
    SerialNumber = certToRevoke.SerialNumber,
    Subject = certToRevoke.Subject,
    RevocationTime = DateTimeOffset.UtcNow,
    Reason = X509RevocationReason.KeyCompromise,
    RequestedBy = "admin@example.com",
    RequestedAt = DateTimeOffset.UtcNow,
    ApprovedBy = "security@example.com",
    Notes = "Private Key möglicherweise in Git Repository exponiert"
};
 
// In Datenbank speichern
var revocationDb = new RevocationDatabase("revocations.db");
revocationDb.AddRevocation(revocationRecord);
 
Console.WriteLine($"Zertifikat widerrufen:");
Console.WriteLine($"  Serial: {revocationRecord.SerialNumber}");
Console.WriteLine($"  Subject: {revocationRecord.Subject}");
Console.WriteLine($"  Grund: {revocationRecord.Reason}");
Console.WriteLine($"  Zeit: {revocationRecord.RevocationTime:yyyy-MM-dd HH:mm:ss} UTC");

CRL und OCSP aktualisieren

public class RevocationManager
{
    private readonly RevocationDatabase _db;
    private readonly X509Certificate2 _caCert;
    private readonly AsymmetricAlgorithm _caKey;
 
    public async Task RevokeAndPublish(
        X509Certificate2 certificate,
        X509RevocationReason reason,
        string requestedBy)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // 1. In Datenbank eintragen
        var record = new RevocationRecord
        {
            SerialNumber = certificate.SerialNumber,
            Subject = certificate.Subject,
            RevocationTime = DateTimeOffset.UtcNow,
            Reason = reason,
            RequestedBy = requestedBy
        };
        _db.AddRevocation(record);
 
        // 2. Neue CRL generieren
        var crlBuilder = new CertificateRevocationListBuilder();
        foreach (var rev in _db.GetAllRevocations())
        {
            crlBuilder.AddEntry(
                HexToBytes(rev.SerialNumber),
                rev.RevocationTime,
                rev.Reason
            );
        }
 
        var nextCrlNumber = _db.GetNextCrlNumber();
        var crlBytes = crlBuilder.Build(
            _caCert,
            nextCrlNumber,
            DateTimeOffset.UtcNow.AddDays(7),
            HashAlgorithmName.SHA256,
            mode: CryptoMode.Hybrid
        );
 
        // 3. CRL veröffentlichen
        await PublishCrl(crlBytes);
 
        // 4. OCSP Cache invalidieren (falls Stapling)
        InvalidateOcspCache(certificate.SerialNumber);
 
        // 5. Benachrichtigung senden
        await NotifyStakeholders(record);
    }
 
    private async Task PublishCrl(byte[] crlBytes)
    {
        // Lokal speichern
        File.WriteAllBytes("current.crl", crlBytes);
 
        // Auf CDP hochladen
        using var http = new HttpClient();
        var content = new ByteArrayContent(crlBytes);
        await http.PutAsync("https://crl.example.com/intermediate.crl", content);
 
        Console.WriteLine("CRL veröffentlicht");
    }
 
    private async Task NotifyStakeholders(RevocationRecord record)
    {
        // E-Mail an Zertifikatsinhaber
        // E-Mail an Security-Team
        // Ticket erstellen
        Console.WriteLine($"Benachrichtigungen gesendet für {record.SerialNumber}");
    }
}

Widerrufsgründe und Verwendung

Code Reason Wann verwenden Urgenz
0 unspecified Kein spezifischer Grund Normal
1 keyCompromise Schlüssel kompromittiert/gestohlen KRITISCH
2 cACompromise CA kompromittiert KRITISCH
3 affiliationChanged Organisation gewechselt Normal
4 superseded Neues Zertifikat ausgestellt Normal
5 cessationOfOperation Dienst eingestellt Normal
6 certificateHold Temporär gesperrt Niedrig
9 privilegeWithdrawn Berechtigung entzogen Normal

keyCompromise (1): Sofortige Maßnahmen erforderlich!

  • CRL sofort aktualisieren
  • Alle betroffenen Systeme informieren
  • Neues Zertifikat ausstellen
  • Forensische Analyse starten

Certificate Hold und Aufhebung

public class CertificateHoldManager
{
    // Zertifikat temporär sperren
    public void PlaceOnHold(string serialNumber, string reason)
    {
        _db.AddRevocation(new RevocationRecord
        {
            SerialNumber = serialNumber,
            RevocationTime = DateTimeOffset.UtcNow,
            Reason = X509RevocationReason.CertificateHold,
            Notes = reason,
            IsOnHold = true
        });
 
        RegenerateCrl();
    }
 
    // Hold aufheben
    public void RemoveFromHold(string serialNumber, string reason)
    {
        var record = _db.GetRevocation(serialNumber);
        if (record?.Reason != X509RevocationReason.CertificateHold)
        {
            throw new InvalidOperationException("Nur Hold-Zertifikate können freigegeben werden");
        }
 
        // In Delta-CRL mit RemoveFromCrl markieren
        _db.MarkAsRemovedFromHold(serialNumber);
 
        // Oder aus Basis-CRL entfernen
        _db.DeleteRevocation(serialNumber);
 
        RegenerateCrl();
    }
}

Audit-Trail

public class RevocationAudit
{
    public void LogRevocation(RevocationRecord record)
    {
        var auditEntry = new
        {
            Timestamp = DateTimeOffset.UtcNow,
            Action = "CERTIFICATE_REVOKED",
            SerialNumber = record.SerialNumber,
            Subject = record.Subject,
            Reason = record.Reason.ToString(),
            RequestedBy = record.RequestedBy,
            ApprovedBy = record.ApprovedBy,
            Notes = record.Notes,
            ClientIp = GetClientIp(),
            UserAgent = GetUserAgent()
        };
 
        // In Audit-Log schreiben
        var json = JsonSerializer.Serialize(auditEntry);
        File.AppendAllText("audit.log", json + Environment.NewLine);
 
        // SIEM benachrichtigen
        SendToSiem(auditEntry);
    }
}

Branchenspezifische Widerrufsanforderungen

Branche Max. Propagationszeit Vier-Augen Audit
WebPKI 24 Stunden Optional Pflicht
Finanzsektor 4 Stunden Pflicht Pflicht
Healthcare 24 Stunden Pflicht 10 Jahre
Energie/SCADA 7 Tage Pflicht Pflicht
Government 24 Stunden Pflicht 30 Jahre

Verwandte Szenarien

Beziehung Szenario Beschreibung
Nächster Schritt 6.1 CRL erstellen CRL aktualisieren
Nächster Schritt 6.2 OCSP Responder Status bereitstellen
Verwandt 4.2 Rekey Neues Zertifikat

« ← 6.3 Delta-CRL | ↑ Widerruf-Übersicht | → Alle Szenarien »


Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional

Zuletzt geändert: den 29.01.2026 um 15:13