~~NOTOC~~
====== Scenarij 6.2: OCSP strežnik ======
**Kategorija:** [[.:start|Preklic (Revocation)]] \\
**Kompleksnost:** Visoka \\
**Predpogoji:** PKI infrastruktura, certifikat za podpisovanje OCSP \\
**Ocenjeni čas:** 30-45 minut
----
===== Opis =====
Ta scenarij opisuje **implementacijo OCSP strežnika** (Online Certificate Status Protocol, RFC 6960). OCSP omogoča preverjanje statusa certifikata v realnem času.
**Prednosti pred CRL:**
* Status v realnem času
* Manjši odgovori
* Brez popolnega prenosa
* Zasebnost (preverjen samo en certifikat)
----
===== Potek dela =====
flowchart LR
CLIENT[Odjemalec] -->|OCSP zahteva| RESPONDER[OCSP strežnik]
RESPONDER --> DB[(Baza preklicov)]
RESPONDER -->|OCSP odgovor| CLIENT
subgraph Response
GOOD[good]
REVOKED[revoked]
UNKNOWN[unknown]
end
style RESPONDER fill:#e8f5e9
----
===== Primer kode: Ustvarjanje OCSP zahteve =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
using var ctx = PqCryptoContext.Initialize();
// Nalaganje certifikata za preverjanje in izdajatelja
var cert = ctx.LoadCertificate("server.crt.pem");
var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem");
// Ustvarjanje OCSP zahteve
var ocspRequest = ctx.CreateOcspRequest(
certificate: cert,
issuer: issuer,
hashAlgorithm: HashAlgorithmName.SHA256,
nonce: true // Zaščita pred ponovitvijo
);
// Zahteva kot DER
byte[] requestBytes = ocspRequest.Encode();
// Pošiljanje zahteve
using var http = new HttpClient();
var content = new ByteArrayContent(requestBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/ocsp-request");
var ocspUrl = ctx.GetOcspUrl(cert); // Branje AIA Extension
var response = await http.PostAsync(ocspUrl, content);
var responseBytes = await response.Content.ReadAsByteArrayAsync();
// Razčlenjevanje odgovora
var status = ctx.ParseOcspResponse(responseBytes, cert, issuer);
Console.WriteLine($"OCSP Status: {status.Status}");
Console.WriteLine($" Ustvarjeno: {status.ProducedAt}");
Console.WriteLine($" This Update: {status.ThisUpdate}");
Console.WriteLine($" Next Update: {status.NextUpdate}");
----
===== Primer kode: Implementacija OCSP strežnika =====
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
{
// Razčlenjevanje zahteve
var request = _ctx.ParseOcspRequest(requestBytes);
// Response Builder
var responseBuilder = new OcspResponseBuilder();
foreach (var certId in request.CertificateIds)
{
// Iskanje statusa v bazi podatkov
var revocationInfo = _revocationDb.GetRevocationStatus(
certId.IssuerNameHash,
certId.IssuerKeyHash,
certId.SerialNumber
);
if (revocationInfo == null)
{
// Neznan certifikat
responseBuilder.AddStatus(certId, OcspCertStatus.Unknown);
}
else if (revocationInfo.IsRevoked)
{
// Preklican
responseBuilder.AddStatus(
certId,
OcspCertStatus.Revoked,
revocationInfo.RevocationTime,
revocationInfo.RevocationReason
);
}
else
{
// Veljaven
responseBuilder.AddStatus(certId, OcspCertStatus.Good);
}
}
// Podpisovanje 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);
}
}
----
===== Ustvarjanje certifikata za OCSP strežnik =====
// OCSP strežnik potrebuje poseben 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 veljavnost za OCSP strežnik
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 (brez preverjanja preklica za strežnik)
.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");
}
}
----
===== Status OCSP odgovora =====
^ Status ^ HTTP ^ Pomen ^
| **successful** | 200 | Zahteva obdelana |
| **malformedRequest** | 200 | Neveljavna zahteva |
| **internalError** | 200 | Napaka strežnika |
| **tryLater** | 200 | Začasno nedostopno |
| **sigRequired** | 200 | Potreben podpis |
| **unauthorized** | 200 | Ni pooblastil |
**Pomembno:** OCSP vedno vrne HTTP 200! Status je kodiran v odgovoru.
----
===== Panožne zahteve za OCSP =====
^ Panoga ^ Predpomnjenje odgovorov ^ Stapling ^ Visoka razpoložljivost ^
| **WebPKI** | Maks. 10 min | Obvezno | 99.9% |
| **Enterprise** | Maks. 1 ura | Priporočeno | Odvisno od SLA |
| **Finančni sektor** | Maks. 5 min | Obvezno | 99.99% |
| **Zdravstvo** | Maks. 1 ura | Opcijsko | 99.9% |
----
===== Povezani scenariji =====
^ Povezava ^ Scenarij ^ Opis ^
| **Alternativa** | [[.:crl_erstellen|6.1 Ustvarjanje CRL]] | Preverjanje brez povezave |
| **Povezano** | [[sl:int:pqcrypt:szenarien:validierung:revocation_check|5.3 Preverjanje preklica]] | Preverjanje na strani odjemalca |
| **Predpogoj** | [[.:zertifikat_widerrufen|6.4 Preklic certifikata]] | Postopek preklica |
----
<< [[.:crl_erstellen|← 6.1 Ustvarjanje CRL]] | [[.:start|↑ Pregled preklica]] | [[.:delta_crl|6.3 Delta-CRL →]] >>
{{tag>szenario widerruf ocsp responder echtzeit}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//