Kategorie: Validierung & Vertrauen
Komplexität: ⭐⭐⭐ (Mittel)
Voraussetzungen: Zertifikat mit CDP/OCSP
Geschätzte Zeit: 10-15 Minuten
Dieses Szenario beschreibt die Prüfung des Widerrufsstatus eines Zertifikats mittels CRL (Certificate Revocation List) oder OCSP (Online Certificate Status Protocol).
Methoden:
| Methode | Vorteile | Nachteile |
|---|---|---|
| CRL | Offline-fähig, Batch | Große Dateien, Verzögerung |
| OCSP | Echtzeit, kleine Antworten | Online-Abhängigkeit |
| OCSP Stapling | Datenschutz, Performance | Server-Konfiguration |
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Zertifikat laden var cert = ctx.LoadCertificate("server.crt.pem"); var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem"); // OCSP URL aus Zertifikat extrahieren var ocspUrl = ctx.GetOcspUrl(cert); if (!string.IsNullOrEmpty(ocspUrl)) { // OCSP-Request erstellen var ocspRequest = ctx.CreateOcspRequest(cert, issuer); // OCSP-Anfrage senden using var http = new HttpClient(); http.DefaultRequestHeaders.Add("Content-Type", "application/ocsp-request"); var response = await http.PostAsync(ocspUrl, new ByteArrayContent(ocspRequest)); var ocspResponseBytes = await response.Content.ReadAsByteArrayAsync(); // OCSP-Response parsen var status = ctx.ParseOcspResponse(ocspResponseBytes, cert, issuer); Console.WriteLine($"OCSP-Status: {status.Status}"); Console.WriteLine($" Produziert: {status.ProducedAt}"); Console.WriteLine($" Gültig bis: {status.NextUpdate}"); if (status.Status == OcspStatus.Revoked) { Console.WriteLine($" Widerrufen: {status.RevocationTime}"); Console.WriteLine($" Grund: {status.RevocationReason}"); } }
public class CrlChecker { private readonly Dictionary<string, CrlCache> _crlCache = new(); public async Task<RevocationStatus> CheckCrl(X509Certificate2 cert, X509Certificate2 issuer) { using var ctx = PqCryptoContext.Initialize(); // CDP URL aus Zertifikat extrahieren var cdpUrl = ctx.GetCrlDistributionPoint(cert); if (string.IsNullOrEmpty(cdpUrl)) { return new RevocationStatus { Status = RevocationStatusCode.Unknown }; } // CRL aus Cache oder herunterladen var crl = await GetOrDownloadCrl(cdpUrl, issuer); // Serial Number in CRL suchen var serialNumber = cert.SerialNumber; var entry = crl.Entries.FirstOrDefault(e => e.SerialNumber.Equals(serialNumber, StringComparison.OrdinalIgnoreCase)); if (entry != null) { return new RevocationStatus { Status = RevocationStatusCode.Revoked, RevocationTime = entry.RevocationDate, Reason = entry.Reason }; } return new RevocationStatus { Status = RevocationStatusCode.Good, NextUpdate = crl.NextUpdate }; } private async Task<ParsedCrl> GetOrDownloadCrl(string cdpUrl, X509Certificate2 issuer) { // Cache prüfen if (_crlCache.TryGetValue(cdpUrl, out var cached)) { if (cached.NextUpdate > DateTime.UtcNow) { return cached.Crl; } } // CRL herunterladen using var http = new HttpClient(); var crlBytes = await http.GetByteArrayAsync(cdpUrl); // CRL parsen und verifizieren using var ctx = PqCryptoContext.Initialize(); var crl = ctx.ParseCrl(crlBytes); // Signatur prüfen if (!ctx.VerifyCrlSignature(crl, issuer)) { throw new CryptographicException("CRL-Signatur ungültig"); } // Cache aktualisieren _crlCache[cdpUrl] = new CrlCache { Crl = crl, NextUpdate = crl.NextUpdate }; return crl; } }
public class OcspStapling { // Server-seitig: OCSP-Response vorab holen public async Task<byte[]> GetStapledOcspResponse( X509Certificate2 serverCert, X509Certificate2 issuer) { using var ctx = PqCryptoContext.Initialize(); var ocspUrl = ctx.GetOcspUrl(serverCert); var request = ctx.CreateOcspRequest(serverCert, issuer); using var http = new HttpClient(); var response = await http.PostAsync(ocspUrl, new ByteArrayContent(request)); return await response.Content.ReadAsByteArrayAsync(); } // Client-seitig: Gestapelte Response prüfen public OcspStatus ValidateStapledResponse( byte[] stapledResponse, X509Certificate2 serverCert, X509Certificate2 issuer) { using var ctx = PqCryptoContext.Initialize(); var status = ctx.ParseOcspResponse(stapledResponse, serverCert, issuer); // Freshness prüfen if (status.ProducedAt < DateTime.UtcNow.AddHours(-24)) { throw new CryptographicException("OCSP-Response zu alt"); } return status; } }
// Einfachste Methode: X509Chain nutzen var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15); // Optional: Nur CRL oder nur OCSP // chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; // Nur cached CRLs bool isValid = chain.Build(cert); // Revocation-Status aus Chain extrahieren var revocationErrors = chain.ChainElements .SelectMany(e => e.ChainElementStatus) .Where(s => s.Status.HasFlag(X509ChainStatusFlags.Revoked) || s.Status.HasFlag(X509ChainStatusFlags.RevocationStatusUnknown)) .ToList(); if (revocationErrors.Any()) { foreach (var error in revocationErrors) { Console.WriteLine($"Revocation-Problem: {error.StatusInformation}"); } }
| Branche | Methode | Max. Verzögerung | Fallback |
|---|---|---|---|
| WebPKI | OCSP Must-Staple | Echtzeit | Soft-Fail |
| Finanzsektor | OCSP + CRL | 4 Stunden | Hard-Fail |
| Healthcare | CRL | 24 Stunden | Soft-Fail |
| Energie/SCADA | CRL (Offline) | 7 Tage | Hard-Fail |
Soft-Fail vs Hard-Fail:
| Beziehung | Szenario | Beschreibung |
|---|---|---|
| Voraussetzung | 5.2 Chain Validation | Chain aufbauen |
| Verwandt | 6.1 CRL erstellen | CRL generieren |
| Verwandt | 6.2 OCSP Responder | OCSP betreiben |
« ← 5.2 Chain Validation | ↑ Validierung-Übersicht | 5.4 Policy Validation → »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional