~~NOTOC~~ ====== Scenario 6.4: Revoke Certificate ====== **Category:** [[.:start|Revocation]] \\ **Complexity:** ⭐⭐⭐ (Medium) \\ **Prerequisites:** Certificate and CA access \\ **Estimated Time:** 10-15 Minutes ---- ===== Description ===== This scenario describes the **complete process for revoking a certificate**. Revocation is necessary for: * **Key compromise** - Key stolen/lost * **Supersession** - New certificate issued * **Cessation of operation** - Service no longer active * **Affiliation change** - Employee leaves organization * **Policy violation** - Certificate no longer complies with policies ---- ===== Workflow ===== flowchart TD REQUEST[Revocation Request] --> VERIFY[Verify Authorization] VERIFY --> REASON[Document Reason] REASON --> DB[Add to Revocation DB] DB --> CRL[Update CRL] DB --> OCSP[Update OCSP] CRL --> PUBLISH[Publish] OCSP --> PUBLISH PUBLISH --> NOTIFY[Notify Stakeholders] NOTIFY --> ARCHIVE[Archive Documentation] style REQUEST fill:#ffebee style PUBLISH fill:#e8f5e9 ---- ===== Code Example (C#) ===== using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using var ctx = PqCryptoContext.Initialize(); // Load certificate to revoke var certToRevoke = ctx.LoadCertificate("server.crt.pem"); // CA access var caCert = ctx.LoadCertificate("intermediate-ca.crt.pem"); var caKey = ctx.LoadPrivateKey("intermediate-ca.key.pem", "CaPassword!"); // Document revocation 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 possibly exposed in Git repository" }; // Save to database var revocationDb = new RevocationDatabase("revocations.db"); revocationDb.AddRevocation(revocationRecord); Console.WriteLine($"Certificate revoked:"); Console.WriteLine($" Serial: {revocationRecord.SerialNumber}"); Console.WriteLine($" Subject: {revocationRecord.Subject}"); Console.WriteLine($" Reason: {revocationRecord.Reason}"); Console.WriteLine($" Time: {revocationRecord.RevocationTime:yyyy-MM-dd HH:mm:ss} UTC"); ---- ===== Update CRL and OCSP ===== 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. Add to database var record = new RevocationRecord { SerialNumber = certificate.SerialNumber, Subject = certificate.Subject, RevocationTime = DateTimeOffset.UtcNow, Reason = reason, RequestedBy = requestedBy }; _db.AddRevocation(record); // 2. Generate new CRL 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. Publish CRL await PublishCrl(crlBytes); // 4. Invalidate OCSP cache (if stapling) InvalidateOcspCache(certificate.SerialNumber); // 5. Send notification await NotifyStakeholders(record); } private async Task PublishCrl(byte[] crlBytes) { // Save locally File.WriteAllBytes("current.crl", crlBytes); // Upload to CDP using var http = new HttpClient(); var content = new ByteArrayContent(crlBytes); await http.PutAsync("https://crl.example.com/intermediate.crl", content); Console.WriteLine("CRL published"); } private async Task NotifyStakeholders(RevocationRecord record) { // Email to certificate holder // Email to security team // Create ticket Console.WriteLine($"Notifications sent for {record.SerialNumber}"); } } ---- ===== Revocation Reasons and Usage ===== ^ Code ^ Reason ^ When to Use ^ Urgency ^ | 0 | unspecified | No specific reason | Normal | | 1 | keyCompromise | Key compromised/stolen | **CRITICAL** | | 2 | cACompromise | CA compromised | **CRITICAL** | | 3 | affiliationChanged | Organization changed | Normal | | 4 | superseded | New certificate issued | Normal | | 5 | cessationOfOperation | Service discontinued | Normal | | 6 | certificateHold | Temporarily suspended | Low | | 9 | privilegeWithdrawn | Privilege withdrawn | Normal | **keyCompromise (1):** Immediate action required! * Update CRL immediately * Inform all affected systems * Issue new certificate * Start forensic analysis ---- ===== Certificate Hold and Release ===== public class CertificateHoldManager { // Temporarily suspend certificate public void PlaceOnHold(string serialNumber, string reason) { _db.AddRevocation(new RevocationRecord { SerialNumber = serialNumber, RevocationTime = DateTimeOffset.UtcNow, Reason = X509RevocationReason.CertificateHold, Notes = reason, IsOnHold = true }); RegenerateCrl(); } // Release hold public void RemoveFromHold(string serialNumber, string reason) { var record = _db.GetRevocation(serialNumber); if (record?.Reason != X509RevocationReason.CertificateHold) { throw new InvalidOperationException("Only hold certificates can be released"); } // Mark as removed from hold in Delta CRL _db.MarkAsRemovedFromHold(serialNumber); // Or remove from base CRL _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() }; // Write to audit log var json = JsonSerializer.Serialize(auditEntry); File.AppendAllText("audit.log", json + Environment.NewLine); // Notify SIEM SendToSiem(auditEntry); } } ---- ===== Industry-Specific Revocation Requirements ===== ^ Industry ^ Maximum Propagation Time ^ Four-Eyes ^ Audit ^ | **WebPKI** | 24 hours | Optional | Mandatory | | **Financial Sector** | 4 hours | Mandatory | Mandatory | | **Healthcare** | 24 hours | Mandatory | 10 years | | **Energy/SCADA** | 7 days | Mandatory | Mandatory | | **Government** | 24 hours | Mandatory | 30 years | ---- ===== Related Scenarios ===== ^ Relationship ^ Scenario ^ Description ^ | **Next Step** | [[.:crl_erstellen|6.1 Create CRL]] | Update CRL | | **Next Step** | [[.:ocsp_responder|6.2 OCSP Responder]] | Provide status | | **Related** | [[en:int:pqcrypt:szenarien:verwaltung:rekey|4.2 Rekey]] | New certificate | ---- << [[.:delta_crl|← 6.3 Delta CRL]] | [[.:start|↑ Revocation Overview]] | [[en:int:pqcrypt:szenarien:start|→ All Scenarios]] >> {{tag>scenario revocation process audit}} ---- //Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//