~~NOTOC~~
====== Scenario 6.2: OCSP Responder ======
**Categoria:** [[.:start|Revoca (Revocation)]] \\
**Complessità:** Alta \\
**Prerequisiti:** Infrastruttura CA, certificato OCSP Signing \\
**Tempo stimato:** 30-45 minuti
----
===== Descrizione =====
Questo scenario descrive l'**implementazione di un OCSP Responder** (Online Certificate Status Protocol, RFC 6960). OCSP consente la verifica in tempo reale dello stato del certificato.
**Vantaggi rispetto a CRL:**
* Stato in tempo reale
* Risposte più piccole
* Nessun download completo
* Privacy (solo un certificato verificato)
----
===== Workflow =====
flowchart LR
CLIENT[Client] -->|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
----
===== Esempio codice: Creare OCSP Request =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
using var ctx = PqCryptoContext.Initialize();
// Zu prüfendes Zertifikat und Issuer laden
var cert = ctx.LoadCertificate("server.crt.pem");
var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem");
// OCSP Request erstellen
var ocspRequest = ctx.CreateOcspRequest(
certificate: cert,
issuer: issuer,
hashAlgorithm: HashAlgorithmName.SHA256,
nonce: true // Replay-Schutz
);
// Request als DER
byte[] requestBytes = ocspRequest.Encode();
// Request senden
using var http = new HttpClient();
var content = new ByteArrayContent(requestBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/ocsp-request");
var ocspUrl = ctx.GetOcspUrl(cert); // AIA Extension auslesen
var response = await http.PostAsync(ocspUrl, content);
var responseBytes = await response.Content.ReadAsByteArrayAsync();
// Response parsen
var status = ctx.ParseOcspResponse(responseBytes, cert, issuer);
Console.WriteLine($"OCSP Status: {status.Status}");
Console.WriteLine($" Produziert: {status.ProducedAt}");
Console.WriteLine($" This Update: {status.ThisUpdate}");
Console.WriteLine($" Next Update: {status.NextUpdate}");
----
===== Esempio codice: Implementare OCSP Responder =====
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
{
// Request parsen
var request = _ctx.ParseOcspRequest(requestBytes);
// Response Builder
var responseBuilder = new OcspResponseBuilder();
foreach (var certId in request.CertificateIds)
{
// Status in Datenbank nachschlagen
var revocationInfo = _revocationDb.GetRevocationStatus(
certId.IssuerNameHash,
certId.IssuerKeyHash,
certId.SerialNumber
);
if (revocationInfo == null)
{
// Unbekanntes Zertifikat
responseBuilder.AddStatus(certId, OcspCertStatus.Unknown);
}
else if (revocationInfo.IsRevoked)
{
// Widerrufen
responseBuilder.AddStatus(
certId,
OcspCertStatus.Revoked,
revocationInfo.RevocationTime,
revocationInfo.RevocationReason
);
}
else
{
// Gültig
responseBuilder.AddStatus(certId, OcspCertStatus.Good);
}
}
// Response signieren
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);
}
}
----
===== Creare certificato OCSP Responder =====
// OCSP Responder braucht spezielles Zertifikat
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, // Kurze Gültigkeit für 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 (keine Revocation-Prüfung für 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} (für 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 =====
^ Stato ^ HTTP ^ Significato ^
| **successful** | 200 | Request elaborata |
| **malformedRequest** | 200 | Request non valida |
| **internalError** | 200 | Errore server |
| **tryLater** | 200 | Temporaneamente non disponibile |
| **sigRequired** | 200 | Firma richiesta |
| **unauthorized** | 200 | Non autorizzato |
**Importante:** OCSP restituisce sempre HTTP 200! Lo stato è codificato nella Response.
----
===== Requisiti OCSP specifici per settore =====
^ Settore ^ Response Caching ^ Stapling ^ Alta disponibilità ^
| **WebPKI** | Max 10 min | Obbligatorio | 99.9% |
| **Enterprise** | Max 1 ora | Raccomandato | Secondo SLA |
| **Settore finanziario** | Max 5 min | Obbligatorio | 99.99% |
| **Sanità** | Max 1 ora | Opzionale | 99.9% |
----
===== Scenari correlati =====
^ Relazione ^ Scenario ^ Descrizione ^
| **Alternativa** | [[.:crl_erstellen|6.1 Creare CRL]] | Verifica offline |
| **Correlato** | [[it:int:pqcrypt:szenarien:validierung:revocation_check|5.3 Revocation Check]] | Verifica lato client |
| **Prerequisito** | [[.:zertifikat_widerrufen|6.4 Revocare certificato]] | Processo di revoca |
----
<< [[.:crl_erstellen|← 6.1 Creare CRL]] | [[.:start|↑ Panoramica revoca]] | [[.:delta_crl|6.3 Delta-CRL →]] >>
{{tag>scenario revoca ocsp responder tempo-reale}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//