@@ -346,3 +346,52 @@ contract CertManagerTest is Test {
346346 return der;
347347 }
348348}
349+
350+ /// @dev Exposes the internal revocation-chain walk and lets tests seed the `verifiedParent`
351+ /// cache directly so the broken-chain (fail-closed) behaviour can be exercised in isolation.
352+ contract RevocationChainHarness is CertManager {
353+ constructor () CertManager (new P384Verifier ()) {}
354+
355+ function setParent (bytes32 child , bytes32 parent ) external {
356+ verifiedParent[child] = parent;
357+ }
358+
359+ function requireCachedChainNotRevoked (bytes32 certHash ) external view {
360+ _requireCachedChainNotRevoked (certHash);
361+ }
362+ }
363+
364+ /// @dev Regression coverage for BLOCKSEC-5249 finding L-01: `_requireCachedChainNotRevoked`
365+ /// previously fell through and returned silently when a cached chain terminated at
366+ /// bytes32(0) without reaching the pinned root, i.e. it failed open on a broken chain.
367+ contract RequireCachedChainNotRevokedTest is Test {
368+ RevocationChainHarness internal cm;
369+
370+ bytes32 internal constant CHILD = bytes32 (uint256 (1 ));
371+ bytes32 internal constant PARENT = bytes32 (uint256 (2 ));
372+
373+ function setUp () public {
374+ cm = new RevocationChainHarness ();
375+ }
376+
377+ function test_PassesWhenChainReachesPinnedRoot () public {
378+ bytes32 root = cm.ROOT_CA_CERT_HASH ();
379+ cm.setParent (CHILD, PARENT);
380+ cm.setParent (PARENT, root);
381+ // Walks CHILD -> PARENT -> ROOT and returns without reverting.
382+ cm.requireCachedChainNotRevoked (CHILD);
383+ }
384+
385+ function test_RevertsWhenChainDoesNotReachRoot () public {
386+ // verifiedParent[PARENT] is unset (bytes32(0)), so the chain is broken: it can never
387+ // reach ROOT_CA_CERT_HASH. The fixed function must fail closed instead of returning.
388+ cm.setParent (CHILD, PARENT);
389+ vm.expectRevert ("incomplete cert chain " );
390+ cm.requireCachedChainNotRevoked (CHILD);
391+ }
392+
393+ function test_RevertsOnZeroCertHash () public {
394+ vm.expectRevert ("incomplete cert chain " );
395+ cm.requireCachedChainNotRevoked (bytes32 (0 ));
396+ }
397+ }
0 commit comments