Scenarij 6.4: Opoziv certifikata

Kategorija: Opoziv (Revocation)
Složenost: ⭐⭐⭐ (Srednja)
Preduvjeti: Certifikat i pristup CA
Procijenjeno vrijeme: 10-15 minuta


Opis

Ovaj scenarij opisuje potpuni proces opoziva certifikata. Opoziv je potreban kod:

  • Kompromitacije ključa - Ključ ukraden/izgubljen
  • Zamjene - Izdan novi certifikat
  • Ukidanja rada - Usluga više nije aktivna
  • Promjene pripadnosti - Zaposlenik napušta organizaciju
  • Kršenja politike - Certifikat više ne odgovara pravilima

Tijek rada

flowchart TD REQUEST[Zahtjev za opoziv] --> VERIFY[Provjera ovlaštenja] VERIFY --> REASON[Dokumentiranje razloga] REASON --> DB[Unos u Revocation-DB] DB --> CRL[Ažuriranje CRL-a] DB --> OCSP[Ažuriranje OCSP-a] CRL --> PUBLISH[Objavljivanje] OCSP --> PUBLISH PUBLISH --> NOTIFY[Obavještavanje dionika] NOTIFY --> ARCHIVE[Arhiviranje dokumentacije] style REQUEST fill:#ffebee style PUBLISH fill:#e8f5e9


Primjer koda (C#)

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
 
using var ctx = PqCryptoContext.Initialize();
 
// Učitavanje certifikata za opoziv
var certToRevoke = ctx.LoadCertificate("server.crt.pem");
 
// Pristup CA
var caCert = ctx.LoadCertificate("intermediate-ca.crt.pem");
var caKey = ctx.LoadPrivateKey("intermediate-ca.key.pem", "CaPassword!");
 
// Dokumentiranje opoziva
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 = "Privatni ključ možda izložen u Git repozitoriju"
};
 
// Spremanje u bazu podataka
var revocationDb = new RevocationDatabase("revocations.db");
revocationDb.AddRevocation(revocationRecord);
 
Console.WriteLine($"Certifikat opozvan:");
Console.WriteLine($"  Serial: {revocationRecord.SerialNumber}");
Console.WriteLine($"  Subject: {revocationRecord.Subject}");
Console.WriteLine($"  Razlog: {revocationRecord.Reason}");
Console.WriteLine($"  Vrijeme: {revocationRecord.RevocationTime:yyyy-MM-dd HH:mm:ss} UTC");

Ažuriranje CRL-a i OCSP-a

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. Unos u bazu podataka
        var record = new RevocationRecord
        {
            SerialNumber = certificate.SerialNumber,
            Subject = certificate.Subject,
            RevocationTime = DateTimeOffset.UtcNow,
            Reason = reason,
            RequestedBy = requestedBy
        };
        _db.AddRevocation(record);
 
        // 2. Generiranje novog CRL-a
        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. Objavljivanje CRL-a
        await PublishCrl(crlBytes);
 
        // 4. Invalidacija OCSP predmemorije (ako je Stapling)
        InvalidateOcspCache(certificate.SerialNumber);
 
        // 5. Slanje obavijesti
        await NotifyStakeholders(record);
    }
 
    private async Task PublishCrl(byte[] crlBytes)
    {
        // Lokalno spremanje
        File.WriteAllBytes("current.crl", crlBytes);
 
        // Upload 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-mail vlasniku certifikata
        // E-mail sigurnosnom timu
        // Kreiranje tiketa
        Console.WriteLine($"Obavijesti poslane za {record.SerialNumber}");
    }
}

Razlozi opoziva i korištenje

Kod Razlog Kada koristiti Hitnost
0 unspecified Bez specifičnog razloga Normalna
1 keyCompromise Ključ kompromitiran/ukraden KRITIČNO
2 cACompromise CA kompromitiran KRITIČNO
3 affiliationChanged Organizacija promijenjena Normalna
4 superseded Izdan novi certifikat Normalna
5 cessationOfOperation Usluga ukinuta Normalna
6 certificateHold Privremeno blokiran Niska
9 privilegeWithdrawn Ovlaštenje povučeno Normalna

keyCompromise (1): Potrebne hitne mjere!

  • Odmah ažurirati CRL
  • Obavijestiti sve pogođene sustave
  • Izdati novi certifikat
  • Pokrenuti forenzičku analizu

Certificate Hold i ukidanje

public class CertificateHoldManager
{
    // Privremeno blokiranje 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();
    }
 
    // Ukidanje Hold stanja
    public void RemoveFromHold(string serialNumber, string reason)
    {
        var record = _db.GetRevocation(serialNumber);
        if (record?.Reason != X509RevocationReason.CertificateHold)
        {
            throw new InvalidOperationException("Samo Hold certifikati mogu biti oslobođeni");
        }
 
        // Označavanje u Delta-CRL-u s RemoveFromCrl
        _db.MarkAsRemovedFromHold(serialNumber);
 
        // Ili uklanjanje iz baznog CRL-a
        _db.DeleteRevocation(serialNumber);
 
        RegenerateCrl();
    }
}

Revizijski trag

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()
        };
 
        // Zapisivanje u audit log
        var json = JsonSerializer.Serialize(auditEntry);
        File.AppendAllText("audit.log", json + Environment.NewLine);
 
        // Obavještavanje SIEM-a
        SendToSiem(auditEntry);
    }
}

Zahtjevi za opoziv po industrijama

Industrija Maks. vrijeme propagacije Četveroočni princip Revizija
WebPKI 24 sata Opcionalno Obvezno
Financijski sektor 4 sata Obvezno Obvezno
Zdravstvo 24 sata Obvezno 10 godina
Energetika/SCADA 7 dana Obvezno Obvezno
Vlada 24 sata Obvezno 30 godina

Povezani scenariji

Odnos Scenarij Opis
Sljedeći korak 6.1 Kreiranje CRL-a Ažuriranje CRL-a
Sljedeći korak 6.2 OCSP Responder Pružanje statusa
Povezano 4.2 Re-Key Novi certifikat

« ← 6.3 Delta-CRL | ↑ Pregled opoziva | → Svi scenariji »


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

Zuletzt geändert: 30.01.2026. u 07:31