Scenarij 5.3: Preverjanje preklica

Kategorija: Validacija in zaupanje
Kompleksnost: ⭐⭐⭐ (Srednja)
Predpogoji: Certifikat s CDP/OCSP
Predviden čas: 10-15 minut


Opis

Ta scenarij opisuje preverjanje statusa preklica certifikata s pomočjo CRL (Certificate Revocation List) ali OCSP (Online Certificate Status Protocol).

Metode:

Metoda Prednosti Slabosti
CRL Možno brez povezave, paketno Velike datoteke, zakasnitev
OCSP V realnem času, majhni odgovori Odvisnost od povezave
OCSP Stapling Zasebnost, zmogljivost Konfiguracija strežnika

Potek dela

flowchart TD CERT[Preverjanje certifikata] --> HAS_OCSP{OCSP URL?} HAS_OCSP -->|Da| OCSP[OCSP zahteva] HAS_OCSP -->|Ne| CRL[Prenos CRL] OCSP --> OCSP_CHECK{Status?} CRL --> CRL_CHECK{V CRL?} OCSP_CHECK -->|good| OK[Ni preklican] OCSP_CHECK -->|revoked| REVOKED[Preklican] OCSP_CHECK -->|unknown| CRL CRL_CHECK -->|Ne| OK CRL_CHECK -->|Da| REVOKED style OK fill:#e8f5e9 style REVOKED fill:#ffebee


Primer kode: OCSP preverjanje

using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography.X509Certificates;
 
using var ctx = PqCryptoContext.Initialize();
 
// Nalaganje certifikata
var cert = ctx.LoadCertificate("server.crt.pem");
var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem");
 
// Ekstrakcija OCSP URL iz certifikata
var ocspUrl = ctx.GetOcspUrl(cert);
 
if (!string.IsNullOrEmpty(ocspUrl))
{
    // Ustvarjanje OCSP zahteve
    var ocspRequest = ctx.CreateOcspRequest(cert, issuer);
 
    // Pošiljanje OCSP zahteve
    using var http = new HttpClient();
    http.DefaultRequestHeaders.Add("Content-Type", "application/ocsp-request");
 
    var response = await http.PostAsync(ocspUrl,
        new ByteArrayContent(ocspRequest));
 
    var ocspResponseBytes = await response.Content.ReadAsByteArrayAsync();
 
    // Razčlenjevanje OCSP odgovora
    var status = ctx.ParseOcspResponse(ocspResponseBytes, cert, issuer);
 
    Console.WriteLine($"OCSP status: {status.Status}");
    Console.WriteLine($"  Ustvarjeno: {status.ProducedAt}");
    Console.WriteLine($"  Veljavno do: {status.NextUpdate}");
 
    if (status.Status == OcspStatus.Revoked)
    {
        Console.WriteLine($"  Preklicano: {status.RevocationTime}");
        Console.WriteLine($"  Razlog: {status.RevocationReason}");
    }
}

Primer kode: CRL preverjanje

public class CrlChecker
{
    private readonly Dictionary<string, CrlCache> _crlCache = new();
 
    public async Task<RevocationStatus> CheckCrl(X509Certificate2 cert, X509Certificate2 issuer)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        // Ekstrakcija CDP URL iz certifikata
        var cdpUrl = ctx.GetCrlDistributionPoint(cert);
        if (string.IsNullOrEmpty(cdpUrl))
        {
            return new RevocationStatus { Status = RevocationStatusCode.Unknown };
        }
 
        // CRL iz predpomnilnika ali prenos
        var crl = await GetOrDownloadCrl(cdpUrl, issuer);
 
        // Iskanje serijske številke v CRL
        var serialNumber = cert.SerialNumber;
        var entry = crl.Entries.FirstOrDefault(e =>
            e.SerialNumber.Equals(serialNumber, StringComparison.OrdinalIgnoreCase));
 
        if (entry != null)
        {
            return new RevocationStatus
            {
                Status = RevocationStatusCode.Revoked,
                RevocationTime = entry.RevocationDate,
                Reason = entry.Reason
            };
        }
 
        return new RevocationStatus
        {
            Status = RevocationStatusCode.Good,
            NextUpdate = crl.NextUpdate
        };
    }
 
    private async Task<ParsedCrl> GetOrDownloadCrl(string cdpUrl, X509Certificate2 issuer)
    {
        // Preverjanje predpomnilnika
        if (_crlCache.TryGetValue(cdpUrl, out var cached))
        {
            if (cached.NextUpdate > DateTime.UtcNow)
            {
                return cached.Crl;
            }
        }
 
        // Prenos CRL
        using var http = new HttpClient();
        var crlBytes = await http.GetByteArrayAsync(cdpUrl);
 
        // Razčlenjevanje in verifikacija CRL
        using var ctx = PqCryptoContext.Initialize();
        var crl = ctx.ParseCrl(crlBytes);
 
        // Preverjanje podpisa
        if (!ctx.VerifyCrlSignature(crl, issuer))
        {
            throw new CryptographicException("CRL podpis neveljaven");
        }
 
        // Posodobitev predpomnilnika
        _crlCache[cdpUrl] = new CrlCache
        {
            Crl = crl,
            NextUpdate = crl.NextUpdate
        };
 
        return crl;
    }
}

OCSP Stapling

public class OcspStapling
{
    // Strežniška stran: Vnaprejšnje pridobivanje OCSP odgovora
    public async Task<byte[]> GetStapledOcspResponse(
        X509Certificate2 serverCert,
        X509Certificate2 issuer)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        var ocspUrl = ctx.GetOcspUrl(serverCert);
        var request = ctx.CreateOcspRequest(serverCert, issuer);
 
        using var http = new HttpClient();
        var response = await http.PostAsync(ocspUrl,
            new ByteArrayContent(request));
 
        return await response.Content.ReadAsByteArrayAsync();
    }
 
    // Odjemalčeva stran: Preverjanje pripetega odgovora
    public OcspStatus ValidateStapledResponse(
        byte[] stapledResponse,
        X509Certificate2 serverCert,
        X509Certificate2 issuer)
    {
        using var ctx = PqCryptoContext.Initialize();
 
        var status = ctx.ParseOcspResponse(stapledResponse, serverCert, issuer);
 
        // Preverjanje svežine
        if (status.ProducedAt < DateTime.UtcNow.AddHours(-24))
        {
            throw new CryptographicException("OCSP odgovor prestar");
        }
 
        return status;
    }
}

Preverjanje preklica na podlagi .NET verige

// Najenostavnejša metoda: Uporaba X509Chain
var chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15);
 
// Opcijsko: Samo CRL ali samo OCSP
// chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline;  // Samo predpomnjeni CRL-ji
 
bool isValid = chain.Build(cert);
 
// Ekstrakcija statusa preklica iz verige
var revocationErrors = chain.ChainElements
    .SelectMany(e => e.ChainElementStatus)
    .Where(s => s.Status.HasFlag(X509ChainStatusFlags.Revoked) ||
                s.Status.HasFlag(X509ChainStatusFlags.RevocationStatusUnknown))
    .ToList();
 
if (revocationErrors.Any())
{
    foreach (var error in revocationErrors)
    {
        Console.WriteLine($"Težava s preklicom: {error.StatusInformation}");
    }
}

Panožne zahteve

Panoga Metoda Največja zakasnitev Nadomestek
WebPKI OCSP Must-Staple V realnem času Soft-Fail
Finančni sektor OCSP + CRL 4 ure Hard-Fail
Zdravstvo CRL 24 ur Soft-Fail
Energetika/SCADA CRL (brez povezave) 7 dni Hard-Fail

Soft-Fail proti Hard-Fail:

  • Soft-Fail: Pri nedosegljivosti → sprejem certifikata
  • Hard-Fail: Pri nedosegljivosti → zavrnitev certifikata

Povezani scenariji

Povezava Scenarij Opis
Predpogoj 5.2 Validacija verige Gradnja verige
Povezano 6.1 Ustvarjanje CRL Generiranje CRL
Povezano 6.2 OCSP Responder Upravljanje OCSP

« ← 5.2 Validacija verige | ↑ Pregled validacije | 5.4 Validacija politik → »


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

Zuletzt geändert: dne 30.01.2026 ob 06:50