Skip to content

OCSP responder (RFC 6960) #884

@Manuthor

Description

@Manuthor

Summary

Implement an OCSP (Online Certificate Status Protocol) responder endpoint (RFC 6960) so relying parties can query the revocation status of certificates issued by the Cosmian KMS CA in real time, without downloading full CRLs.

Impact

  • TLS stacks, browsers, and PKI-aware applications check OCSP before trusting a certificate
  • Without an OCSP responder, the Cosmian CA cannot be used as a trust anchor in environments that require live revocation checks (e.g., mutual TLS for KMIP clients)
  • Enables OCSP stapling for TLS certificates issued by Cosmian, improving performance for relying parties
  • Required for compliance with CA/Browser Forum Baseline Requirements when operating a publicly trusted CA

How revocation works in this codebase

The revoke_operation() in crate/server/src/core/operations/revoke.rs transitions a certificate's KMIP State to Compromised or Deactivated. The serial number of each certificate is computed in crate/server/src/core/operations/certify/mod.rs (create_subject_key_identifier_value()) and set as the X.509 serial number via x509_builder.set_serial_number(...).

The OCSP responder maps from the serial number in the incoming OCSP request to the matching certificate object's State to determine the revocation status.

Implementation plan

1. Serial-number-based lookup

Add a method to ObjectsStore in crate/interfaces/src/stores/objects_store.rs:

/// Find a certificate object by its X.509 serial number (hex-encoded or DER bytes).
async fn find_certificate_by_serial(
    &self,
    serial_hex: &str,
    user: &str,
) -> InterfaceResult<Option<(String, Object, Attributes)>>;

Implement in all three DB backends (SQLite, PostgreSQL, Redis-findex) by scanning the attributes JSON blob for the x509_cert.serial_number field, or by adding a dedicated cert_serial index column.

2. OCSP route handlers (crate/server/src/routes/ocsp/)

crate/server/src/routes/ocsp/
  mod.rs       ← scope registration
  handler.rs   ← GET + POST /ocsp/ handlers
  build.rs     ← OCSP response builder

GET /ocsp/{base64-request} and POST /ocsp/:

  1. Parse the ASN.1 OCSP request using openssl::ocsp::OcspRequest (from the openssl crate already in the workspace).
  2. Extract the CertId from the request: issuer name hash, issuer key hash, serial number.
  3. Verify the issuer hashes match the configured CA certificate (ca_uid).
  4. Look up the certificate by serial number via find_certificate_by_serial().
  5. Determine status:
    • Object not found → unknown
    • State::Active or State::PreActivegood
    • State::Compromisedrevoked with CRLReason::keyCompromise
    • State::Deactivated or State::Destroyedrevoked with CRLReason::cessationOfOperation
  6. Build the OcspBasicResponse using openssl::ocsp::OcspBasicResponse:
    • thisUpdate = now
    • nextUpdate = now + [ocsp].cache_ttl_secs
  7. Sign the response with the CA's private key via the existing sign_operation() KMS call on the ca_uid key.
  8. Return 200 OK with Content-Type: application/ocsp-response.

3. Response caching

Cache signed OCSP responses in-memory:

// In KMS struct or a dedicated OcspCache
struct OcspCache {
    entries: DashMap<String, (Bytes, Instant)>,  // serial_hex → (signed_response, expires_at)
}

On cache hit (not expired), return the cached response immediately without re-signing. Cache TTL configurable via [ocsp].cache_ttl_secs (default: 86400 = 24 h).

4. Config TOML

[ocsp]
enabled = false
ca_uid = "..."           # UID of the CA certificate object in the KMS
cache_ttl_secs = 86400   # OCSP response validity window

5. Scope registration (crate/server/src/routes/mod.rs)

Add the /ocsp scope alongside the existing routes, wrapped with the same auth middlewares.

Files to create / modify

File Change
crate/interfaces/src/stores/objects_store.rs Add find_certificate_by_serial()
crate/server_database/src/stores/sql/ Implement find_certificate_by_serial for SQLite + PostgreSQL
crate/server_database/src/stores/redis/ Implement for Redis-findex backend
crate/server/src/routes/ocsp/mod.rs New: scope registration
crate/server/src/routes/ocsp/handler.rs New: GET + POST OCSP handlers
crate/server/src/routes/ocsp/build.rs New: OCSP response builder + cache
crate/server/src/routes/mod.rs Register /ocsp scope
crate/server/src/config/ New [ocsp] config block

Acceptance criteria

  • openssl ocsp -issuer ca.pem -cert leaf.pem -url http://kms.example.com/ocsp/ returns good for an active certificate.
  • After calling ckms certificates revoke <uid>, the same openssl ocsp call returns revoked.
  • A serial number not matching any known certificate returns unknown.
  • Cached responses are served without re-signing within the TTL window.
  • All OCSP routes return 404 when ocsp.enabled = false.

References

Effort: Small (2–3 weeks) | No prerequisites

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions