~~NOTOC~~
====== Scenario 6.2: OCSP Responder ======
**Category:** [[.:start|Revocation]] \\
**Complexity:** ⭐⭐⭐⭐ (High) \\
**Prerequisites:** CA infrastructure, OCSP signing certificate \\
**Estimated Time:** 30-45 Minutes
----
===== Description =====
This scenario describes the **implementation of an OCSP Responder** (Online Certificate Status Protocol, RFC 6960). OCSP enables real-time certificate status verification.
**Advantages over CRL:**
* Real-time status
* Smaller responses
* No complete download
* Privacy (only one certificate checked)
----
===== 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
----
===== Code Example: Create OCSP Request =====
using WvdS.Security.Cryptography.X509Certificates.Extensions.PQ;
using System.Security.Cryptography;
using var ctx = PqCryptoContext.Initialize();
// Load certificate to check and issuer
var cert = ctx.LoadCertificate("server.crt.pem");
var issuer = ctx.LoadCertificate("intermediate-ca.crt.pem");
// Create OCSP request
var ocspRequest = ctx.CreateOcspRequest(
certificate: cert,
issuer: issuer,
hashAlgorithm: HashAlgorithmName.SHA256,
nonce: true // Replay protection
);
// Request as DER
byte[] requestBytes = ocspRequest.Encode();
// Send request
using var http = new HttpClient();
var content = new ByteArrayContent(requestBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/ocsp-request");
var ocspUrl = ctx.GetOcspUrl(cert); // Read AIA extension
var response = await http.PostAsync(ocspUrl, content);
var responseBytes = await response.Content.ReadAsByteArrayAsync();
// Parse response
var status = ctx.ParseOcspResponse(responseBytes, cert, issuer);
Console.WriteLine($"OCSP Status: {status.Status}");
Console.WriteLine($" Produced: {status.ProducedAt}");
Console.WriteLine($" This Update: {status.ThisUpdate}");
Console.WriteLine($" Next Update: {status.NextUpdate}");
----
===== Code Example: Implement 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
{
// Parse request
var request = _ctx.ParseOcspRequest(requestBytes);
// Response builder
var responseBuilder = new OcspResponseBuilder();
foreach (var certId in request.CertificateIds)
{
// Look up status in database
var revocationInfo = _revocationDb.GetRevocationStatus(
certId.IssuerNameHash,
certId.IssuerKeyHash,
certId.SerialNumber
);
if (revocationInfo == null)
{
// Unknown certificate
responseBuilder.AddStatus(certId, OcspCertStatus.Unknown);
}
else if (revocationInfo.IsRevoked)
{
// Revoked
responseBuilder.AddStatus(
certId,
OcspCertStatus.Revoked,
revocationInfo.RevocationTime,
revocationInfo.RevocationReason
);
}
else
{
// Valid
responseBuilder.AddStatus(certId, OcspCertStatus.Good);
}
}
// Sign response
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);
}
}
----
===== Create OCSP Responder Certificate =====
// OCSP Responder needs special certificate
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, // Short validity for 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 (no revocation check for 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} (for 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 ^ Meaning ^
| **successful** | 200 | Request processed |
| **malformedRequest** | 200 | Invalid request |
| **internalError** | 200 | Server error |
| **tryLater** | 200 | Temporarily unavailable |
| **sigRequired** | 200 | Signature required |
| **unauthorized** | 200 | Not authorized |
**Important:** OCSP always returns HTTP 200! The status is encoded in the response.
----
===== Industry-Specific OCSP Requirements =====
^ Industry ^ Response Caching ^ Stapling ^ High Availability ^
| **WebPKI** | Maximum 10 min | Mandatory | 99.9% |
| **Enterprise** | Maximum 1 hour | Recommended | Per SLA |
| **Financial Sector** | Maximum 5 min | Mandatory | 99.99% |
| **Healthcare** | Maximum 1 hour | Optional | 99.9% |
----
===== Related Scenarios =====
^ Relationship ^ Scenario ^ Description ^
| **Alternative** | [[.:crl_erstellen|6.1 Create CRL]] | Offline verification |
| **Related** | [[en:int:pqcrypt:szenarien:validierung:revocation_check|5.3 Revocation Check]] | Client-side verification |
| **Prerequisite** | [[.:zertifikat_widerrufen|6.4 Revoke Certificate]] | Revocation process |
----
<< [[.:crl_erstellen|← 6.1 Create CRL]] | [[.:start|↑ Revocation Overview]] | [[.:delta_crl|6.3 Delta CRL →]] >>
{{tag>scenario revocation ocsp responder realtime}}
----
//Wolfgang van der Stille @ EMSR DATA d.o.o. - Post-Quantum Cryptography Professional//