~~NOTOC~~
====== Scenario 6.1: Create CRL ======
**Category:** [[.:start|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? 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).
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Alternative** | [[.:ocsp_responder|6.2 OCSP Responder]] | Online verification |
| **Extension** | [[.:delta_crl|6.3 Delta CRL]] | Incremental updates |
| **Prerequisite** | [[.:zertifikat_widerrufen|6.4 Revoke Certificate]] | Revocation process |
----
<< [[.:start|← Revocation Overview]] | [[en:int:pqcrypt:szenarien:start|↑ Scenarios]] | [[.:ocsp_responder|6.2 OCSP Responder →]] >>
{{tag>scenario revocation crl pki}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//