Scenario 6.1: Create CRL

Category: Revocation
Complexity: ⭐⭐⭐ (Medium)
Prerequisites: CA certificate and key
Estimated Time: 15-20 Minutes


Description

This scenario describes the creation of a Certificate Revocation List (CRL) according to RFC 5280. CRLs are signed lists of revoked certificates published by CAs.

CRL Fields:

  • issuer - DN of the issuing CA
  • thisUpdate - Issuance time
  • nextUpdate - Next planned update
  • revokedCertificates - List of revoked serial numbers
  • signature - CA signature

Workflow

flowchart LR REV[Revoked Certificates] --> BUILD[CRL Builder] BUILD --> SIGN[Sign with CA] SIGN --> PUBLISH[Publish] PUBLISH --> CDP[Update CDP URL] style SIGN fill:#e8f5e9


Code Example (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography.X509Certificates;
 
using var ctx = PqCryptoContext.Initialize();
 
// Load CA
var caCert = ctx.LoadCertificate("intermediate-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("intermediate-ca.key.pem", "CaPassword!");
 
// Create CRL builder
var crlBuilder = new CertificateRevocationListBuilder();
 
// Add revoked certificates
crlBuilder.AddEntry(
    serialNumber: new byte[] { 0x01, 0x02, 0x03 },
    revocationTime: new DateTimeOffset(2024, 6, 15, 10, 30, 0, TimeSpan.Zero),
    reason: X509RevocationReason.KeyCompromise
);
 
crlBuilder.AddEntry(
    serialNumber: new byte[] { 0x01, 0x02, 0x04 },
    revocationTime: DateTimeOffset.UtcNow.AddDays(-7),
    reason: X509RevocationReason.CessationOfOperation
);
 
// Generate CRL
byte[] crlBytes = crlBuilder.Build(
    issuerCertificate: caCert,
    crlNumber: BigInteger.Parse("1000"),
    nextUpdate: DateTimeOffset.UtcNow.AddDays(7),
    hashAlgorithm: HashAlgorithmName.SHA256,
    rsaSignaturePadding: null,  // Not relevant for PQ
    mode: CryptoMode.Hybrid
);
 
// Save CRL
File.WriteAllBytes("intermediate-ca.crl", crlBytes);
 
// Convert CRL to PEM
var crlPem = ctx.ToPem(crlBytes, "X509 CRL");
File.WriteAllText("intermediate-ca.crl.pem", crlPem);
 
Console.WriteLine("CRL created:");
Console.WriteLine($"  Entries: {crlBuilder.Entries.Count}");
Console.WriteLine($"  CRL Number: 1000");
Console.WriteLine($"  Next Update: {DateTimeOffset.UtcNow.AddDays(7):yyyy-MM-dd}");

Update CRL from Existing CRL

public class CrlUpdater
{
    public byte[] UpdateCrl(
        byte[] existingCrl,
        X509Certificate2 caCert,
        AsymmetricAlgorithm caKey,
        IEnumerable<CrlEntry>? newEntries = null)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Parse existing CRL
        var parsedCrl = ctx.ParseCrl(existingCrl);
 
        // New builder with existing entries
        var builder = new CertificateRevocationListBuilder();
 
        foreach (var entry in parsedCrl.Entries)
        {
            builder.AddEntry(entry.SerialNumber, entry.RevocationTime, entry.Reason);
        }
 
        // Add new entries
        if (newEntries != null)
        {
            foreach (var entry in newEntries)
            {
                builder.AddEntry(entry.SerialNumber, entry.RevocationTime, entry.Reason);
            }
        }
 
        // New CRL number (incremented)
        var newCrlNumber = parsedCrl.CrlNumber + 1;
 
        // Create new CRL
        return builder.Build(
            issuerCertificate: caCert,
            crlNumber: newCrlNumber,
            nextUpdate: DateTimeOffset.UtcNow.AddDays(7),
            hashAlgorithm: HashAlgorithmName.SHA256,
            mode: CryptoMode.Hybrid
        );
    }
}

CRL Extensions

// CRL with extensions
var crlBuilder = new CertificateRevocationListBuilder();
 
// CRL Extensions
crlBuilder.AddExtension(
    oid: "2.5.29.20",  // CRL Number
    critical: false,
    value: BuildCrlNumberExtension(1001)
);
 
crlBuilder.AddExtension(
    oid: "2.5.29.35",  // Authority Key Identifier
    critical: false,
    value: BuildAkiExtension(caCert)
);
 
crlBuilder.AddExtension(
    oid: "2.5.29.28",  // Issuing Distribution Point
    critical: true,
    value: BuildIdpExtension(
        distributionPoint: "http://crl.example.com/intermediate.crl",
        onlyContainUserCerts: true
    )
);
 
// Entry Extensions (per revoked certificate)
crlBuilder.AddEntry(
    serialNumber: revokedSerial,
    revocationTime: DateTimeOffset.UtcNow,
    reason: X509RevocationReason.KeyCompromise,
    extensions: new X509ExtensionCollection
    {
        // Invalidity Date (when actually compromised)
        BuildInvalidityDateExtension(compromiseDate),
        // Certificate Issuer (if Indirect CRL)
        BuildCertificateIssuerExtension(certIssuerDn)
    }
);

Revocation Reasons (RFC 5280)

Code Reason Description
0 unspecified No specific reason
1 keyCompromise Key compromised
2 cACompromise CA compromised
3 affiliationChanged Affiliation changed
4 superseded Replaced by new certificate
5 cessationOfOperation Operations ceased
6 certificateHold Temporarily suspended
8 removeFromCRL Remove from CRL (release hold)
9 privilegeWithdrawn Privilege withdrawn
10 aACompromise Attribute authority compromised

Configure CRL Distribution Point

// Issue certificate with CDP
var cert = ctx.IssueCertificate(
    csr,
    issuerCert: caCert,
    issuerKey: caKey,
    extensions: new ExtBuilder()
        .CrlDistributionPoint(
            uri: "http://crl.example.com/intermediate.crl",
            ldapUri: "ldap://ldap.example.com/cn=Intermediate-CA,o=Example,c=DE?certificateRevocationList"
        )
        .Build()
);

Industry-Specific CRL Requirements

Industry Maximum nextUpdate Format Distribution
WebPKI 7 days DER HTTP
Enterprise 24 hours DER/PEM HTTP, LDAP
Energy/SCADA 30 days DER Offline
Healthcare 24 hours DER HTTP

Best Practice: Update CRL before nextUpdate (50-75% of validity period).


Relationship Scenario Description
Alternative 6.2 OCSP Responder Online verification
Extension 6.3 Delta CRL Incremental updates
Prerequisite 6.4 Revoke Certificate Revocation process

« ← Revocation Overview | ↑ Scenarios | 6.2 OCSP Responder → »


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

Zuletzt geändert: on 2026/01/30 at 06:56 AM