Scenario 6.4: Revoke Certificate

Category: 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:


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

Relationship Scenario Description
Next Step 6.1 Create CRL Update CRL
Next Step 6.2 OCSP Responder Provide status
Related 4.2 Rekey New certificate

« ← 6.3 Delta CRL | ↑ Revocation Overview | → All Scenarios »


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