OCSP
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
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
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
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
- spec RFC 6960
pki.ocsp.verify
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();