OCSP

The producing + client-facing half of RFC 6960 Online Certificate Status Protocol: build a status request over a certificate (pki.ocsp.buildRequest), build and sign a status response as an authorized responder (pki.ocsp.sign), emit an unsigned error response (pki.ocsp.buildErrorResponse), and verify a returned response as a relying party (pki.ocsp.verify). Parsing lives in pki.schema.ocsp; revocation during path validation is pki.path.ocspChecker. Signing rides the shared sign-scheme registry (the same classical + post-quantum set pki.cms.sign uses), so a response is signed under RSA / ECDSA / EdDSA / ML-DSA / SLH-DSA per the responder key. Verification composes the same hardened responder- authorization, signature and currency gates pki.path.ocspChecker runs; there is no weaker second verify path. Fail-closed: verify returns a "unknown" verdict (never a silent accept) for any unmet gate, with one scoped exception: a request-nonce mismatch downgrades only a good to "unknown", leaving a signed, current, authorized revoked reported as revoked with nonceMatched: false (see verify). Malformed input throws a typed OcspError.

pki.ocsp.buildRequest

since 0.2.22 stable
pki.ocsp.buildRequest(query, opts?) -> Buffer | string

Build an OCSPRequest for the status of one or more certificates. query is a { cert, issuer } pair (or an array of them), each certificate given parsed or as DER/PEM; the CertID is derived by hashing the issuer name and key under opts.hashAlgorithm (SHA-1 by default, the RFC 5019 interop choice). The version DEFAULT (v1) is omitted from the DER. Returns the request DER, or PEM when opts.pem is set.

Options

hashAlgorithm  `"sha1"` (default) / `"sha256"` / `"sha384"` / `"sha512"`; the CertID identity hash.
nonce          `true` for a fresh 32-octet CSPRNG nonce (RFC 9654), or a caller Buffer (1..128 octets).
requestorName  a Name (RDN array) placed in the [1] requestorName as a directoryName.
signer         `{ cert, key }` to sign the request (requires requestorName).
profile        `"lightweight"`: one Request, SHA-1 CertID, nonce-only extensions (RFC 5019).
pem            emit a PEM `OCSP REQUEST` string instead of DER.

Example

async function example() {
  var ca = await pki.key.generate("Ed25519");
  var caKey = await pki.key.export(ca.privateKey);
  var caDer = await pki.x509.sign({ subject: "Example CA", subjectPublicKey: await pki.key.export(ca.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
    extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign"], subjectKeyIdentifier: true } }, { key: caKey });
  var leaf = await pki.key.generate("Ed25519");
  var leafDer = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(leaf.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
    { cert: caDer, key: caKey });
  var der = await pki.ocsp.buildRequest({ cert: leafDer, issuer: caDer }, { nonce: true });
}
example();

References

pki.ocsp.sign

since 0.2.22 stable
pki.ocsp.sign(responseData, responder, opts?) -> Promise<Buffer | string>

Build and sign a successful OCSPResponse wrapping a BasicOCSPResponse. responseData names the responderID, an optional producedAt, and one or more per-certificate responses; responder is the { cert, key } signing the response (the issuing CA directly, or a CA-issued delegate bearing id-kp-OCSPSigning + id-pkix-ocsp-nocheck). The signature is computed over the exact ResponseData DER (RFC 6960 sec. 4.2.1: no CMS wrapper, no signed attributes). The responder certificate is embedded in certs [0] so a relying party can find it. Returns the response DER, or PEM.

Options

nonce           a request nonce Buffer to echo back in responseExtensions (RFC 9654).
extendedRevoke  emit the id-pkix-ocsp-extended-revoke extension (RFC 6960 sec. 4.4.8).
embedCert       `false` to omit certs [0] (a direct-CA response the client already trusts).
pem             emit a PEM `OCSP RESPONSE` string instead of DER.

Example

async function example() {
  var ca = await pki.key.generate("Ed25519");
  var responderPkcs8 = await pki.key.export(ca.privateKey);
  // the issuing CA responds directly here, so its own certificate is the responder's
  var caDer = await pki.x509.sign({ subject: "Example CA", subjectPublicKey: await pki.key.export(ca.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
    extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign"], subjectKeyIdentifier: true } },
    { key: responderPkcs8 });
  var responderCertDer = caDer;
  var leaf = await pki.key.generate("Ed25519");
  var leafDer = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(leaf.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
    { cert: caDer, key: responderPkcs8 });
  var resp = await pki.ocsp.sign(
    { responderID: "byName", responses: [{ cert: leafDer, issuer: caDer, status: "good" }] },
    { cert: responderCertDer, key: responderPkcs8 });
}
example();

References

pki.ocsp.buildErrorResponse

since 0.2.22 stable
pki.ocsp.buildErrorResponse(status) -> Buffer | string

Build an UNSIGNED error OCSPResponse -- malformedRequest / internalError / tryLater / sigRequired / unauthorized -- carrying only the responseStatus and no responseBytes (RFC 6960 sec. 2.3: an error message conveys no certificate status and is not signed).

Example

var der = pki.ocsp.buildErrorResponse("tryLater");

References

pki.ocsp.verify

since 0.2.22 stable
pki.ocsp.verify(response, opts) -> Promise<{ status, responderAuthorized, signatureValid, thisUpdate, nextUpdate, revocationReason?, nonceMatched?, reason }>

Verify a returned OCSP response as a relying party (RFC 6960 sec. 3.2 client acceptance). Resolves an AUTHORIZED responder (the issuing CA directly, or a CA-issued delegate bearing id-kp-OCSPSigning + id-pkix-ocsp-nocheck), verifies the signature over tbsResponseData, matches the CertID triple to the target certificate under the CertID's own hashAlgorithm, checks currency (thisUpdate/nextUpdate), and, when opts.requestNonce is supplied, confirms the response nonce echoes it. This runs the same hardened gates pki.path.ocspChecker does. Fail-closed: an unauthorized, stale, or CertID-mismatched response is a "unknown" verdict (never a silent accept); a malformed response's parse fault surfaces as the parser's ocsp/* / asn1/*.

The request-nonce check is reported, and downgrades good alone. Every verdict carries nonceMatched (true / false / null when the client sent no nonce). An unmatched nonce turns a good into "unknown", because a response that is not an answer to this request cannot be relied on to say the certificate is still fine. It does not touch revoked: revocation does not go stale the way non-revocation does, so discarding a signed, current, authorized revoked because it was replayed would hand a soft-failing caller the very certificate the responder refused. A replayed revoked is therefore reported as revoked with nonceMatched: false.

Options

cert            the target certificate (parsed, DER, or PEM) -- REQUIRED.
issuer          its issuer certificate (parsed, DER, or PEM) -- REQUIRED.
time            the validation instant (default: now).
requestNonce    the nonce the client sent; when given, the response MUST echo it (constant-time).
historicalMode  defer a strictly-future revocation (report good) instead of revoking on skew.

Example

async function example() {
  var ca = await pki.key.generate("Ed25519");
  var caKey = await pki.key.export(ca.privateKey);
  var caDer = await pki.x509.sign({ subject: "Example CA", subjectPublicKey: await pki.key.export(ca.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z"),
    extensions: { basicConstraints: { cA: true }, keyUsage: ["keyCertSign"], subjectKeyIdentifier: true } },
    { key: caKey });
  var leaf = await pki.key.generate("Ed25519");
  var leafDer = await pki.x509.sign({ subject: "leaf.example", subjectPublicKey: await pki.key.export(leaf.publicKey),
    notBefore: new Date("2026-01-01T00:00:00Z"), notAfter: new Date("2036-01-01T00:00:00Z") },
    { cert: caDer, key: caKey });
  var responseDer = await pki.ocsp.sign(
    { responderID: "byName", responses: [{ cert: leafDer, issuer: caDer, status: "good" }] },
    { cert: caDer, key: caKey });
  var res = await pki.ocsp.verify(responseDer, { cert: leafDer, issuer: caDer });
  res.status;   // "good" | "revoked" | "unknown"
}
example();

References