~~NOTOC~~
====== Scenarij 6.2: OCSP Responder ======
**Kategorija:** [[.:start|Opoziv (Revocation)]] \\
**Složenost:** ⭐⭐⭐⭐ (Visoka) \\
**Preduvjeti:** CA infrastruktura, OCSP-Signing certifikat \\
**Procijenjeno vrijeme:** 30-45 minuta
----
===== Opis =====
Ovaj scenarij opisuje **implementaciju OCSP Respondera** (Online Certificate Status Protocol, RFC 6960). OCSP omogućuje provjeru statusa certifikata u stvarnom vremenu.
**Prednosti nad CRL-om:**
* Status u stvarnom vremenu
* Manji odgovori
* Bez potpunog preuzimanja
* Privatnost (samo jedan certifikat provjeren)
----
===== Tijek rada =====
flowchart LR
CLIENT[Klijent] -->|OCSP Request| RESPONDER[OCSP Responder]
RESPONDER --> DB[(Revocation DB)]
RESPONDER -->|OCSP Response| CLIENT
subgraph Response
GOOD[good]
REVOKED[revoked]
UNKNOWN[unknown]
end
style RESPONDER fill:#e8f5e9
----
===== Primjer koda: Kreiranje OCSP zahtjeva =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
using var ctx = PqCryptoContext.Initialize();
// Učitavanje certifikata za provjeru i Issuera
var cert = ctx.LoadCertificate("server.crt.pem");
var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem");
// Kreiranje OCSP zahtjeva
var ocspRequest = ctx.CreateOcspRequest(
certificate: cert,
issuer: issuer,
hashAlgorithm: HashAlgorithmName.SHA256,
nonce: true // Zaštita od ponavljanja
);
// Request kao DER
byte[] requestBytes = ocspRequest.Encode();
// Slanje zahtjeva
using var http = new HttpClient();
var content = new ByteArrayContent(requestBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/ocsp-request");
var ocspUrl = ctx.GetOcspUrl(cert); // Čitanje AIA ekstenzije
var response = await http.PostAsync(ocspUrl, content);
var responseBytes = await response.Content.ReadAsByteArrayAsync();
// Parsiranje odgovora
var status = ctx.ParseOcspResponse(responseBytes, cert, issuer);
Console.WriteLine($"OCSP status: {status.Status}");
Console.WriteLine($" Proizvedeno: {status.ProducedAt}");
Console.WriteLine($" This Update: {status.ThisUpdate}");
Console.WriteLine($" Next Update: {status.NextUpdate}");
----
===== Primjer koda: Implementacija OCSP Respondera =====
public class OcspResponder
{
private readonly X509Certificate2 _responderCert;
private readonly AsymmetricAlgorithm _responderKey;
private readonly IRevocationDatabase _revocationDb;
private readonly PqCryptoContext _ctx;
public OcspResponder(
X509Certificate2 responderCert,
AsymmetricAlgorithm responderKey,
IRevocationDatabase revocationDb)
{
_responderCert = responderCert;
_responderKey = responderKey;
_revocationDb = revocationDb;
_ctx = PqCryptoContext.Initialize();
}
public byte[] ProcessRequest(byte[] requestBytes)
{
try
{
// Parsiranje zahtjeva
var request = _ctx.ParseOcspRequest(requestBytes);
// Response Builder
var responseBuilder = new OcspResponseBuilder();
foreach (var certId in request.CertificateIds)
{
// Traženje statusa u bazi podataka
var revocationInfo = _revocationDb.GetRevocationStatus(
certId.IssuerNameHash,
certId.IssuerKeyHash,
certId.SerialNumber
);
if (revocationInfo == null)
{
// Nepoznat certifikat
responseBuilder.AddStatus(certId, OcspCertStatus.Unknown);
}
else if (revocationInfo.IsRevoked)
{
// Opozvan
responseBuilder.AddStatus(
certId,
OcspCertStatus.Revoked,
revocationInfo.RevocationTime,
revocationInfo.RevocationReason
);
}
else
{
// Valjan
responseBuilder.AddStatus(certId, OcspCertStatus.Good);
}
}
// Potpisivanje odgovora
return responseBuilder.Build(
responderCert: _responderCert,
responderKey: _responderKey,
producedAt: DateTimeOffset.UtcNow,
nextUpdate: DateTimeOffset.UtcNow.AddMinutes(5),
nonce: request.Nonce,
mode: CryptoMode.Hybrid
);
}
catch (Exception ex)
{
// Internal Error Response
return BuildErrorResponse(OcspResponseStatus.InternalError);
}
}
private byte[] BuildErrorResponse(OcspResponseStatus status)
{
return _ctx.BuildOcspErrorResponse(status);
}
}
----
===== Kreiranje certifikata za OCSP Responder =====
// OCSP Responder treba poseban certifikat
using var ocspKey = ctx.GenerateKeyPair(PqAlgorithm.MlDsa65);
var dn = new DnBuilder()
.AddCN("OCSP Responder - Example CA")
.AddO("Example GmbH")
.AddC("DE")
.Build();
var csr = ctx.CreateCertificateRequest(ocspKey, dn);
var ocspCert = ctx.IssueCertificate(
csr,
issuerCert: caCert,
issuerKey: caKey,
validDays: 30, // Kratka valjanost za OCSP Responder
extensions: new ExtBuilder()
.BasicConstraints(ca: false, critical: true)
// OCSP Signing Key Usage
.KeyUsage(KeyUsageFlags.DigitalSignature, critical: true)
// OCSP Signing EKU
.ExtendedKeyUsage(ExtKeyUsage.OcspSigning)
// id-pkix-ocsp-nocheck Extension (bez provjere opoziva za Responder)
.OcspNoCheck()
.SubjectKeyIdentifier(ocspKey.PublicKey)
.AuthorityKeyIdentifier(caCert)
.Build()
);
ocspCert.ToPemFile("ocsp-responder.crt.pem");
ocspKey.ToEncryptedPemFile("ocsp-responder.key.pem", "OcspPassword!");
----
===== ASP.NET Core OCSP Endpoint =====
[ApiController]
[Route("ocsp")]
public class OcspController : ControllerBase
{
private readonly OcspResponder _responder;
public OcspController(OcspResponder responder)
{
_responder = responder;
}
// POST /ocsp
[HttpPost]
[Consumes("application/ocsp-request")]
[Produces("application/ocsp-response")]
public IActionResult Post()
{
using var ms = new MemoryStream();
Request.Body.CopyTo(ms);
var requestBytes = ms.ToArray();
var responseBytes = _responder.ProcessRequest(requestBytes);
return File(responseBytes, "application/ocsp-response");
}
// GET /ocsp/{base64-request} (za OCSP GET)
[HttpGet("{encodedRequest}")]
[Produces("application/ocsp-response")]
public IActionResult Get(string encodedRequest)
{
var requestBytes = Convert.FromBase64String(
Uri.UnescapeDataString(encodedRequest)
);
var responseBytes = _responder.ProcessRequest(requestBytes);
return File(responseBytes, "application/ocsp-response");
}
}
----
===== OCSP Response Status =====
^ Status ^ HTTP ^ Značenje ^
| **successful** | 200 | Zahtjev obrađen |
| **malformedRequest** | 200 | Nevaljani zahtjev |
| **internalError** | 200 | Greška poslužitelja |
| **tryLater** | 200 | Privremeno nedostupno |
| **sigRequired** | 200 | Potreban potpis |
| **unauthorized** | 200 | Neovlašteno |
**Važno:** OCSP uvijek vraća HTTP 200! Status je kodiran u odgovoru.
----
===== Zahtjevi za OCSP po industrijama =====
^ Industrija ^ Response Caching ^ Stapling ^ Visoka dostupnost ^
| **WebPKI** | Maks. 10 min | Obvezno | 99.9% |
| **Enterprise** | Maks. 1 sat | Preporučeno | Ovisno o SLA |
| **Financijski sektor** | Maks. 5 min | Obvezno | 99.99% |
| **Zdravstvo** | Maks. 1 sat | Opcionalno | 99.9% |
----
===== Povezani scenariji =====
^ Odnos ^ Scenarij ^ Opis ^
| **Alternativa** | [[.:crl_erstellen|6.1 Kreiranje CRL-a]] | Offline provjera |
| **Povezano** | [[hr:int:pqcrypt:szenarien:validierung:revocation_check|5.3 Provjera opoziva]] | Provjera na strani klijenta |
| **Preduvjet** | [[.:zertifikat_widerrufen|6.4 Opoziv certifikata]] | Proces opoziva |
----
<< [[.:crl_erstellen|← 6.1 Kreiranje CRL-a]] | [[.:start|↑ Pregled opoziva]] | [[.:delta_crl|6.3 Delta-CRL →]] >>
{{tag>scenarij opoziv ocsp responder realtime}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//