Scenarij 6.4: Preklic certifikata

Kategorija: Preklic (Revocation)
Kompleksnost: Srednja
Predpogoji: Certifikat in dostop do CA
Ocenjeni čas: 10-15 minut


Opis

Ta scenarij opisuje popoln postopek preklica certifikata. Preklic je potreben pri:

  • Ogroženost ključa - Ključ ukraden/izgubljen
  • Zamenjava - Izdan nov certifikat
  • Ukinitev delovanja - Storitev ni več aktivna
  • Sprememba pripadnosti - Sodelavec zapusti organizacijo
  • Kršitev politike - Certifikat ne ustreza več smernicam

Potek dela

flowchart TD REQUEST[Zahteva za preklic] --> VERIFY[Preverjanje pooblastila] VERIFY --> REASON[Dokumentiranje razloga] REASON --> DB[Vnos v bazo preklicov] DB --> CRL[Posodobitev CRL] DB --> OCSP[Posodobitev OCSP] CRL --> PUBLISH[Objava] OCSP --> PUBLISH PUBLISH --> NOTIFY[Obveščanje deležnikov] NOTIFY --> ARCHIVE[Arhiviranje dokumentacije] style REQUEST fill:#ffebee style PUBLISH fill:#e8f5e9


Primer kode (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Nalaganje certifikata za preklic
var certToRevoke = ctx.LoadCertificate("server.crt.pem");
 
// Dostop do CA
var caCert = ctx.LoadCertificate("intermediate-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("intermediate-ca.key.pem", "CaPassword!");
 
// Dokumentiranje preklica
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 = "Zasebni ključ morda izpostavljen v Git repozitoriju"
};
 
// Shranjevanje v bazo podatkov
var revocationDb = new RevocationDatabase("revocations.db");
revocationDb.AddRevocation(revocationRecord);
 
Console.WriteLine($"Certifikat preklican:");
Console.WriteLine($"  Serijska: {revocationRecord.SerialNumber}");
Console.WriteLine($"  Subject: {revocationRecord.Subject}");
Console.WriteLine($"  Razlog: {revocationRecord.Reason}");
Console.WriteLine($"  Čas: {revocationRecord.RevocationTime:yyyy-MM-dd HH:mm:ss} UTC");

Posodabljanje CRL in 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. Vnos v bazo podatkov
        var record = new RevocationRecord
        {
            SerialNumber = certificate.SerialNumber,
            Subject = certificate.Subject,
            RevocationTime = DateTimeOffset.UtcNow,
            Reason = reason,
            RequestedBy = requestedBy
        };
        _db.AddRevocation(record);
 
        // 2. Generiranje novega 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. Objava CRL
        await PublishCrl(crlBytes);
 
        // 4. Razveljavitev OCSP predpomnilnika (če je Stapling)
        InvalidateOcspCache(certificate.SerialNumber);
 
        // 5. Pošiljanje obvestil
        await NotifyStakeholders(record);
    }
 
    private async Task PublishCrl(byte[] crlBytes)
    {
        // Lokalno shranjevanje
        File.WriteAllBytes("current.crl", crlBytes);
 
        // Nalaganje na CDP
        using var http = new HttpClient();
        var content = new ByteArrayContent(crlBytes);
        await http.PutAsync("https://crl.example.com/intermediate.crl", content);
 
        Console.WriteLine("CRL objavljen");
    }
 
    private async Task NotifyStakeholders(RevocationRecord record)
    {
        // E-pošta imetniku certifikata
        // E-pošta varnostni ekipi
        // Ustvarjanje zahtevka
        Console.WriteLine($"Obvestila poslana za {record.SerialNumber}");
    }
}

Razlogi za preklic in uporaba

Koda Razlog Kdaj uporabiti Nujnost
0 unspecified Brez specifičnega razloga Normalna
1 keyCompromise Ključ ogrožen/ukraden KRITIČNA
2 cACompromise CA ogrožena KRITIČNA
3 affiliationChanged Zamenjava organizacije Normalna
4 superseded Izdan nov certifikat Normalna
5 cessationOfOperation Storitev ukinjena Normalna
6 certificateHold Začasno blokirano Nizka
9 privilegeWithdrawn Pooblastilo odvzeto Normalna

keyCompromise (1): Potrebni takojšnji ukrepi!

  • Takojšnja posodobitev CRL
  • Obveščanje vseh prizadetih sistemov
  • Izdaja novega certifikata
  • Začetek forenzične analize

Certificate Hold in odprava

public class CertificateHoldManager
{
    // Začasna blokada certifikata
    public void PlaceOnHold(string serialNumber, string reason)
    {
        _db.AddRevocation(new RevocationRecord
        {
            SerialNumber = serialNumber,
            RevocationTime = DateTimeOffset.UtcNow,
            Reason = X509RevocationReason.CertificateHold,
            Notes = reason,
            IsOnHold = true
        });
 
        RegenerateCrl();
    }
 
    // Odprava blokade
    public void RemoveFromHold(string serialNumber, string reason)
    {
        var record = _db.GetRevocation(serialNumber);
        if (record?.Reason != X509RevocationReason.CertificateHold)
        {
            throw new InvalidOperationException("Samo blokirani certifikati se lahko sprostijo");
        }
 
        // V Delta-CRL označiti z RemoveFromCrl
        _db.MarkAsRemovedFromHold(serialNumber);
 
        // Ali odstranitev iz baznega CRL
        _db.DeleteRevocation(serialNumber);
 
        RegenerateCrl();
    }
}

Revizijska sled

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()
        };
 
        // Pisanje v revizijski dnevnik
        var json = JsonSerializer.Serialize(auditEntry);
        File.AppendAllText("audit.log", json + Environment.NewLine);
 
        // Obveščanje SIEM
        SendToSiem(auditEntry);
    }
}

Panožne zahteve za preklic

Panoga Maks. čas širjenja Štiri-oči Revizija
WebPKI 24 ur Opcijsko Obvezno
Finančni sektor 4 ure Obvezno Obvezno
Zdravstvo 24 ur Obvezno 10 let
Energetika/SCADA 7 dni Obvezno Obvezno
Javni sektor 24 ur Obvezno 30 let

Povezani scenariji

Povezava Scenarij Opis
Naslednji korak 6.1 Ustvarjanje CRL Posodobitev CRL
Naslednji korak 6.2 OCSP strežnik Zagotavljanje statusa
Povezano 4.2 Ponovna izdaja ključa Nov certifikat

« ← 6.3 Delta-CRL | ↑ Pregled preklica | → Vsi scenariji »


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

Zuletzt geändert: dne 30.01.2026 ob 07:50