Scenarij 5.3: Provjera opoziva
Kategorija: Validacija i povjerenje
Složenost: ⭐⭐⭐ (Srednja)
Preduvjeti: Certifikat s CDP/OCSP
Procijenjeno vrijeme: 10-15 minuta
Opis
Ovaj scenarij opisuje provjeru statusa opoziva certifikata putem CRL (Certificate Revocation List) ili OCSP (Online Certificate Status Protocol).
Metode:
| Metoda | Prednosti | Nedostaci |
|---|---|---|
| CRL | Moguće offline, grupno | Velike datoteke, kašnjenje |
| OCSP | Realtime, mali odgovori | Ovisnost o mreži |
| OCSP Stapling | Privatnost, performanse | Konfiguracija poslužitelja |
Tijek rada
flowchart TD
CERT[Provjera certifikata] --> HAS_OCSP{OCSP URL?}
HAS_OCSP -->|Da| OCSP[OCSP upit]
HAS_OCSP -->|Ne| CRL[Preuzimanje CRL-a]
OCSP --> OCSP_CHECK{Status?}
CRL --> CRL_CHECK{Na CRL-u?}
OCSP_CHECK -->|good| OK[Nije opozvan]
OCSP_CHECK -->|revoked| REVOKED[Opozvan]
OCSP_CHECK -->|unknown| CRL
CRL_CHECK -->|Ne| OK
CRL_CHECK -->|Da| REVOKED
style OK fill:#e8f5e9
style REVOKED fill:#ffebee
Primjer koda: OCSP provjera
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ; using System.Security.Cryptography.X509Certificates; using var ctx = PqCryptoContext.Initialize(); // Učitavanje certifikata var cert = ctx.LoadCertificate("server.crt.pem"); var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem"); // Ekstrakcija OCSP URL-a iz certifikata var ocspUrl = ctx.GetOcspUrl(cert); if (!string.IsNullOrEmpty(ocspUrl)) { // Kreiranje OCSP zahtjeva var ocspRequest = ctx.CreateOcspRequest(cert, issuer); // Slanje OCSP upita 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(); // Parsiranje OCSP odgovora var status = ctx.ParseOcspResponse(ocspResponseBytes, cert, issuer); Console.WriteLine($"OCSP status: {status.Status}"); Console.WriteLine($" Proizvedeno: {status.ProducedAt}"); Console.WriteLine($" Vrijedi do: {status.NextUpdate}"); if (status.Status == OcspStatus.Revoked) { Console.WriteLine($" Opozvan: {status.RevocationTime}"); Console.WriteLine($" Razlog: {status.RevocationReason}"); } }
Primjer koda: CRL provjera
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-a iz certifikata var cdpUrl = ctx.GetCrlDistributionPoint(cert); if (string.IsNullOrEmpty(cdpUrl)) { return new RevocationStatus { Status = RevocationStatusCode.Unknown }; } // CRL iz predmemorije ili preuzimanje var crl = await GetOrDownloadCrl(cdpUrl, issuer); // Pretraživanje serijskog broja na CRL-u 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) { // Provjera predmemorije if (_crlCache.TryGetValue(cdpUrl, out var cached)) { if (cached.NextUpdate > DateTime.UtcNow) { return cached.Crl; } } // Preuzimanje CRL-a using var http = new HttpClient(); var crlBytes = await http.GetByteArrayAsync(cdpUrl); // Parsiranje i verifikacija CRL-a using var ctx = PqCryptoContext.Initialize(); var crl = ctx.ParseCrl(crlBytes); // Provjera potpisa if (!ctx.VerifyCrlSignature(crl, issuer)) { throw new CryptographicException("Nevaljani CRL potpis"); } // Ažuriranje predmemorije _crlCache[cdpUrl] = new CrlCache { Crl = crl, NextUpdate = crl.NextUpdate }; return crl; } }
OCSP Stapling
public class OcspStapling { // Na strani poslužitelja: unaprijed dohvaćanje 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(); } // Na strani klijenta: provjera pripojenog odgovora public OcspStatus ValidateStapledResponse( byte[] stapledResponse, X509Certificate2 serverCert, X509Certificate2 issuer) { using var ctx = PqCryptoContext.Initialize(); var status = ctx.ParseOcspResponse(stapledResponse, serverCert, issuer); // Provjera svježine if (status.ProducedAt < DateTime.UtcNow.AddHours(-24)) { throw new CryptographicException("OCSP odgovor prestari"); } return status; } }
.NET provjera opoziva temeljena na lancu
// Najjednostavnija metoda: korištenje X509Chain var chain = new X509Chain(); chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15); // Opcionalno: samo CRL ili samo OCSP // chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; // Samo spremljeni CRL-ovi bool isValid = chain.Build(cert); // Ekstrakcija statusa opoziva iz lanca 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($"Problem s opozivom: {error.StatusInformation}"); } }
Specifični zahtjevi po industrijama
| Industrija | Metoda | Maks. kašnjenje | Fallback |
|---|---|---|---|
| WebPKI | OCSP Must-Staple | Realtime | Soft-Fail |
| Financijski sektor | OCSP + CRL | 4 sata | Hard-Fail |
| Zdravstvo | CRL | 24 sata | Soft-Fail |
| Energetika/SCADA | CRL (Offline) | 7 dana | Hard-Fail |
Soft-Fail vs Hard-Fail:
- Soft-Fail: Kod nedostupnosti → Prihvatiti certifikat
- Hard-Fail: Kod nedostupnosti → Odbiti certifikat
Povezani scenariji
| Odnos | Scenarij | Opis |
|---|---|---|
| Preduvjet | 5.2 Validacija lanca | Izgraditi lanac |
| Povezano | 6.1 Kreiranje CRL-a | Generiranje CRL-a |
| Povezano | 6.2 OCSP Responder | Rad OCSP-a |
« ← 5.2 Validacija lanca | ↑ Pregled validacije | 5.4 Validacija politika → »
Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional
Zuletzt geändert: 30.01.2026. u 07:20