fix(security): report OCSP/CRL cache disposition via target.loadedFromSource#1586
Merged
kriszyp merged 1 commit intoJul 8, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request refactors the lazy loading of certificate verification modules to avoid stale implementations when testing, and updates the CRL and OCSP verification flows to pass a context object to the cache table, tracking cache disposition via context.loadedFromSource. Additionally, new unit tests have been added to verify cache hits and misses. The review feedback suggests optimizing module loading by caching the dynamic import promises and lazily loading only the required verification module on-demand based on the verification method.
Contributor
|
Reviewed; no blockers found. |
…mSource The OCSP and CRL verification paths reported the `cached` field (and the trace log) by calling `wasLoadedFromSource?.()` on the record returned by the caching table's `get()`. That plain frozen record has no resource methods, so the call was always `undefined` and `cached` was always `true` (always "cache hit"). `wasLoadedFromSource()` was removed from the Resource base class in #1576, and the Context mirror of the flag is removed in #1590. Observe cache disposition on the RequestTarget of the get instead (#1590 makes `target.loadedFromSource` the sole signal, marked on both hit and miss by the `_loadRecord` path that serves this instance-mode table). - ocsp / crl: pass a RequestTarget as the get id (empty ctor + `target.id = cacheKey` to avoid URL-parsing keys that may contain '/' or '?'); the cert data still travels in the context arg, which the source reads as requestContext. Read `target.loadedFromSource` after the get. CRL is aligned to the same 2-arg `get(target, context)` convention as OCSP. - certificateVerificationSource: read performCRLCheck/performOCSPCheck off the live module object (`.default`) with memoized, per-method dynamic imports. A CJS module's ESM-import namespace snapshots its named exports at first import, so a cached function reference would honor a stale implementation forever — e.g. a test double pinned past its restore, which leaked across test files. - crl: import the PKI.js Ed25519/Ed448 patch directly. CRL signature verification uses PKI.js but previously got the patch only as a side effect of loading the OCSP module; with the per-method import above, a CRL-only path no longer loads OCSP, so it must own its patch dependency (else Ed25519/Ed448 issuers degrade to unknown/failure). Adds unit tests covering fresh-fetch cached:false and cached-read cached:true for both OCSP and CRL. Verified the cert cache table marks target.loadedFromSource true on miss / false on hit despite being instance mode (loadAsInstance unset), and that loading only the CRL module applies the Ed25519 patch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
f293860 to
a391cb8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The OCSP and CRL certificate-verification paths reported the
cachedresult field (and the trace log line) by callingwasLoadedFromSource?.()on the record returned by the caching table'sget(). That value is a plain frozen record with no resource methods, so the call was alwaysundefinedandcachedwas hard-wired totrue— every check logged/reported "cache hit" regardless of whether the certificate status was actually fetched from source.wasLoadedFromSource()was removed from theResourcebase class in #1576, and theContext.loadedFromSourcemirror is removed in #1590.This observes cache disposition on the RequestTarget of the get, which #1590 makes the sole disposition signal.
Changes
ocspVerification.ts/crlVerification.ts— pass aRequestTargetas the get id and readtarget.loadedFromSourceafter the get. The target is built with the empty ctor +target.id = cacheKeyto avoid URL-parsing cache keys that may contain/or?. Cert data still travels in the context (2nd) arg, which the source reads asrequestContext, so the source fetch is unchanged. CRL is aligned to the same 2-argget(target, context)convention as OCSP.certificateVerificationSource.ts— readperformCRLCheck/performOCSPCheckoff the live module object (.default) with memoized, per-method dynamic imports. See "Where to look".crlVerification.ts— import the PKI.js Ed25519/Ed448 patch directly (see "Where to look").cached:falseon a fresh source fetch,cached:trueon the subsequent cached read.Where to look
loadAsInstancemode (the subtle correctness point). The cert cache table is left in the default instance mode (loadAsInstanceis unset, i.e.!== false), notloadAsInstance=false. Verified empirically thattarget.loadedFromSourceis settrueon a miss /falseon a hit anyway:getResourceroutesloadAsInstance !== falsetables through_loadRecord, which callssetLoadedFromSource(target, false)on a cache hit andsetLoadedFromSource(target, true)on a source fetch (viagetFromSource). I did not setloadAsInstance:false— it isn't needed here.certificateVerificationSource.ts— live.defaultread + memoized imports. A CJS module's ESM-import namespace snapshots its named exports at firstimport(), so caching the resolved function reference would pin a stale implementation (e.g. a test double past its restore — which leaked across test files and broke the OCSP source before this). Reading off.default(livemodule.exports) each call fixes it; the memoized per-method import avoids re-hitting the module loader on cache misses.crlVerification.ts— PKI.js Ed25519 patch import (from cross-model review). CRL signature verification uses PKI.js but previously received the Ed25519/Ed448 patch only as a side effect of loading the OCSP module. With the per-method import above, a CRL-only path no longer loads OCSP, so the CRL module now imports the patch itself — otherwise Ed25519/Ed448 issuers would degrade to unknown/failure. Verified that loading only the CRL module applies the patch.Dependency / base
Stacked on #1590 (
kris/loadedfromsource-target-only), which makestarget.loadedFromSourcethe sole cache-disposition signal and removes theContextmirror. Base is set to that branch; once #1590 lands on v5.1 this rebases onto v5.1. Both #1590 and this target v5.1, not main — needs a forward-port to main later.Notes
loadAsInstance:falsewas unnecessary — with no blockers.🤖 Generated with Claude Code (model: Claude Opus 4.8)