Summary

  • A stapled OCSP response is a signed statement about one CertID at defined times. Signature validity proves responder authority over that statement; it does not prove the responder knew every later revocation event or generated the answer for this handshake.
  • producedAt, thisUpdate and nextUpdate are different clocks. Cache acquisition, HTTP age, server installation, client clock and maximum-age policy add more. Collapsing them into “valid until” hides the exact replay and propagation window.
  • TLS carries status evidence; it does not assign the consequence. Defensible acceptance requires CertID match, authorized signer, acceptable status and time, observed chain coverage, negotiated carriage, Must-Staple evaluation, explicit soft- or hard-fail policy and the running client's final decision.

The green response that survived the red event

The responder had signed a good answer at 09:55. The server fetched and cached it at 09:57. The certificate was revoked in the issuer's system at 10:07. Four minutes later, a client received the cached answer during a new TLS handshake.

The staple's signature verified. Its thisUpdate was not in the future. Its nextUpdate had not passed. The server had not invented a status or altered a byte. Yet the answer did not contain the later event.

Calling the response “fake” would obscure the control failure. Calling the connection “revocation checked” would do the same. The first confuses currency with authenticity; the second converts a chain of bounded decisions into a verdict no single component was authorized to make.

The useful incident question is narrower: what exactly did this response say, who could say it, for which certificate, over which interval, and under whose failure policy was it accepted?

CertID names the question

OCSP does not ask whether “the site” or “the chain” is good. Its CertID combines the issuer name hash, issuer key hash, certificate serial number and a hash algorithm. The response has authority only if that identity matches the certificate under evaluation.

A perfectly signed response for another serial is not partial evidence. It answers another question. A response attached to the leaf also says nothing by itself about an intermediate certificate. Chain position must remain visible.

RFC 6960 gives good a deliberately limited meaning. At minimum, no certificate with the requested serial that is currently within its validity interval is recorded as revoked. The word does not necessarily prove that a certificate was ever issued. It does not promise that the responder has already ingested an event that occurred after the status was last known correct.

This is why logs need the leaf and chain fingerprints, issuer, serial, exact CertID and the certificate entry to which each response was attached. ocsp=good without the named object has almost no forensic authority.

A signature grants authority, not omniscience

A definitive OCSP response must be signed by the certificate issuer or by a responder explicitly authorized by that issuer for OCSP signing. The client must validate that relationship as well as the cryptographic signature.

Those checks answer a vital question: was this signer allowed to assert status for this certificate? They do not answer whether the signer possessed the newest issuer state at the instant of the handshake.

An unauthorized responder with a mathematically valid signature fails authority. An authorized responder with a valid signature but an earlier view may pass authenticity while retaining a bounded information age. These are separate failure dimensions.

Production evidence should therefore preserve the responder certificate, issuer relationship, OCSP-signing authorization, signature result and raw response hash. A certificate-chain success flag cannot substitute for the delegation proof.

Three protocol clocks, then the clocks the protocol cannot see

producedAt is when the response was signed. thisUpdate is the most recent time at which the asserted status was known correct. nextUpdate says when newer information will be available at or before that time.

These are not aliases for expiry. RFC 6960 allows responses to be produced in advance. RFC 9919's high-volume profile makes caching explicit and requires nextUpdate; a client checks that its current time lies between thisUpdate and nextUpdate.

The running system adds clocks that are absent from the signed object: issuer revocation time, responder ingestion time, HTTP Date and Age, server fetch time, cache revalidation, credential installation, handshake time and client wall clock. Monitoring also needs a monotonic observation time so a wall-clock rollback does not make old evidence look young.

Clock skew is a controlled allowance, not free freshness. A future thisUpdate beyond the allowance, a passed nextUpdate or a response older than the application's maximum age must remain separately diagnosable.

The incident's four-minute gap was therefore not solved by reading only nextUpdate. That field bounded the responder's publication schedule. It did not certify that every later event had propagated through issuer, responder, HTTP cache, server memory and client policy.

The cache is inside the security model

Stapling exists partly to avoid a client contacting the responder for every connection. It reduces latency, protects browsing privacy and prevents responder availability from sitting directly on the handshake path. Reuse is not an implementation accident; it is a design property.

RFC 9919 treats HTTP caching as part of the operating contract. Date, Last-Modified, Expires, ETag and Cache-Control can govern reuse and revalidation. Cache lifetime must end before the OCSP response's own update boundary. A stale proxy result can trigger a no-cache retry.

That creates two distinct questions. Is the response acceptable under its signed time fields? Is the server's copy as recent as its refresh policy promised? The first is client validation. The second is server operation. Both can succeed or fail independently.

A server should record fetch origin, HTTP headers, raw hash, acquisition time, revalidation outcome, refresh deadline and the moment the response entered the active credential set. A fleet that loaded a valid staple at startup but stopped refreshing has an operational defect before clients begin rejecting it.

A nonce cannot be retrofitted into a shared staple

The OCSP nonce extension binds a request to its response. It lets a requester seek a response tied to fresh random material instead of accepting an old copy. RFC 8954 also recognizes that responders may omit the nonce and that shorter validity periods can limit replay exposure.

A reusable staple cannot normally contain a different client nonce for every handshake. It is cached specifically so many clients can receive the same signed object. That does not make stapling unsound. It means a staple's freshness authority comes from its signed interval, local age limits and refresh discipline, not from proof that the responder answered this client moments ago.

Telemetry should never label a staple “nonce fresh” merely because it was carried in a new handshake. New carriage and new production are different events.

TLS transports the answer; the client assigns the consequence

In TLS 1.2 and earlier, a client advertises status_request, and a supporting server can return a CertificateStatus message. TLS 1.3 associates status information with certificate entries. IANA assigns extension value 5 to status_request; status_request_v2 is not used in TLS 1.3.

Those mechanisms prove interoperability, not acceptance. A client still has to parse the bytes, match CertID, validate the signer, evaluate status and time, and decide what a failure means.

Presence is not success. BoringSSL explicitly exposes the received data as raw bytes that are not guaranteed to be well formed. OpenSSL separates requesting status, installing a server response and inspecting what the client received. A callback metric can prove that code ran without proving that a valid response reached a client.

Absence is not one outcome either. The client may not have requested status. The handshake may be resumed without a certificate exchange. The server may decline to acknowledge the request. The certificate may or may not carry a TLS Feature requirement. The client may soft-fail or reject.

Record ClientHello request state, full versus resumed handshake, returned response count, chain position, each validation result and the final application-visible reason. stapled=true is inventory, not a security decision.

Must-Staple governs omission, not truth

The TLS Feature extension commonly called Must-Staple is designed to resist silent downgrade. A server using such a certificate must satisfy the client's status request for the listed feature. If it does not, a client may refuse the connection.

That policy changes the authority of missing evidence. It prevents an attacker or broken server from converting “status required” into “status unavailable, continue.” But enforcement is not universal merely because the extension exists.

Nor does Must-Staple bless present bytes. A mismatched CertID, unauthorized signer, invalid signature, stale interval, unknown status or explicit revocation still fails its own check. The certificate feature says evidence must be supplied; OCSP validation determines whether that evidence is acceptable.

Operations must therefore test both paths: omit a required staple and present a bad one. A client that rejects only the latter has not enforced the omission contract. A dashboard that counts only response presence cannot tell the difference.

One response is not a chain policy

TLS before 1.3 commonly exposes one stapled response for the leaf. TLS 1.3 can associate responses with multiple certificate entries. OpenSSL represents that distinction through a single response in older TLS and a response stack in TLS 1.3; entries can be absent.

The existence of multi-certificate plumbing does not establish a universal requirement to staple every intermediate. It does require the observer to preserve cardinality and position. “OCSP enabled” is too broad to answer whether the leaf was checked, an intermediate was covered or policy required both.

Session resumption adds another limit. OpenSSL notes that its status callback is not called when no certificates are exchanged. A resumed connection can rely on prior authentication state according to the protocol and implementation, but it cannot be logged as a new certificate-and-staple observation.

APIs are plumbing; refresh is a running control

OpenSSL exposes separate helpers to find the requested CertID, extract status, check thisUpdate and nextUpdate with clock leeway and maximum age, and verify signature and responder authority. No one helper is the verdict. The application composes them and owns the consequence.

Maximum age matters especially when nextUpdate is absent outside profiles that require it. OpenSSL warns that an ancient response can otherwise appear valid. A local age ceiling must be explicit, versioned and observable.

GnuTLS can integrate OCSP into certificate verification and report missing status under Must-Staple. On the server side it also requires periodic renewal. Credentials in use are read-only, so a running system may need a refreshed credential set and controlled swap.

BoringSSL recommends fetching, configuring and refreshing responses eagerly instead of performing network access inside a handshake callback. That separates responder outages from handshake latency, but moves authority into the refresh scheduler. The scheduler, cache and credential swap become security components.

The governing evidence is running state: which response hash each process served, when it was installed, when refresh last succeeded, which deadline applies and which handshakes accepted or rejected it.

The negative tests that keep “good” bounded

Present a correctly signed response for the wrong serial. Sign with a responder that lacks issuer authorization. Move thisUpdate into the future beyond skew. Serve an expired response from a proxy and confirm a no-cache retry. Remove nextUpdate, age the response and verify the local maximum.

Replay an unexpired good response after a later revocation event and measure the accepted window rather than calling it a forged answer. Omit a required staple. Present malformed bytes. Cover the leaf but not an intermediate required by local policy. Resume a TLS 1.3 session and verify telemetry does not claim a new status exchange.

Stop the server refresh job while leaving handshakes healthy. The system should alert before the response expires. Roll back a clock. The monotonic age should continue increasing. Take the responder offline. Handshakes should keep using a known acceptable cached object without blocking on synchronous network access, then fail according to policy when evidence can no longer be accepted.

These tests produce an evidence ladder: identity, signer authority, signed time, cache lineage, TLS carriage, client validation and final policy. Only the complete ladder can authorize the label “accepted with current status evidence.”

Sources