~~NOTOC~~
====== Scenarij 5.3: Provjera opoziva ======
**Kategorija:** [[.:start|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 _crlCache = new();
public async Task 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 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 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** | [[.:chain_validation|5.2 Validacija lanca]] | Izgraditi lanac |
| **Povezano** | [[hr:int:pqcrypt:szenarien:widerruf:crl_erstellen|6.1 Kreiranje CRL-a]] | Generiranje CRL-a |
| **Povezano** | [[hr:int:pqcrypt:szenarien:widerruf:ocsp_responder|6.2 OCSP Responder]] | Rad OCSP-a |
----
<< [[.:chain_validation|← 5.2 Validacija lanca]] | [[.:start|↑ Pregled validacije]] | [[.:policy_validation|5.4 Validacija politika →]] >>
{{tag>scenarij validacija opoziv crl ocsp}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//