feat(nitro-verifier): add expiry-aware intermediate certificate caching#240
Merged
leopoldjoy merged 3 commits intomainfrom Apr 7, 2026
Conversation
Change trustedIntermediateCerts mapping from bytes32=>bool to bytes32=>uint64, where the value is the certificate's notAfter timestamp in seconds (0 = not cached). Cached certs are now automatically treated as untrusted once block.timestamp exceeds their expiry, closing a security gap where cached entries could outlive their X.509 validity. Changes: - INitroEnclaveVerifier.sol: Add certExpiries field to VerifierJournal - NitroEnclaveVerifier.sol: uint64 mapping, expiry checks in _verifyJournal, checkTrustedIntermediateCerts, _cacheNewCert, revokeCert; constructor accepts parallel expiries array - DeployRiscZeroStack.s.sol: Pass empty expiries array to constructor - Tests: 6 new tests for expiry semantics, all existing tests updated - Semver: 0.1.0 -> 0.2.0 CHAIN-3889
Collaborator
✅ Heimdall Review Status
|
…lock.timestamp is always positive
roger-bai-coinbase
approved these changes
Apr 7, 2026
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
trustedIntermediateCertsmapping frombytes32 => booltobytes32 => uint64, where the value is the certificate'snotAftertimestamp in seconds (0 = not cached)block.timestampexceeds their expiry, closing a security gap where cached entries could outlive their X.509 validity periodscertExpiriesfield toVerifierJournalto receive expiry data from the ZK guestProblem
NitroEnclaveVerifiercaches intermediate certificate path digests indefinitely (bytes32 => bool). The ZK guest skips ALL validation (including temporal checks) for trusted-prefix certs, so cached entries with no expiry defeat the purpose of AWS's progressively shorter cert lifetimes (root ~30y, intermediate1 ~20d, intermediate2 ~6d, intermediate3 ~1d, leaf ~3h). An expired intermediate CA key in a lower security posture at AWS could be exfiltrated and used to forge attestations that pass the cached prefix check.Changes
INitroEnclaveVerifier.soluint64[] certExpiriesfield toVerifierJournalstruct (one entry per cert, matchingcerts[]order)NitroEnclaveVerifier.solmapping(bytes32 => bool)→mapping(bytes32 => uint64)(value = notAfter seconds, 0 = not cached)uint64[] memory initializeTrustedCertExpiriesparameter with length validation againstinitializeTrustedCerts_cacheNewCert(): Storesjournal.certExpiries[i]instead oftrue_verifyJournal(): Checksexpiry == 0 || block.timestamp > expiryfor trusted prefix certscheckTrustedIntermediateCerts(): Stops counting at expired certsrevokeCert(): Uses== 0check instead of!boolfor existence0.1.0→0.2.0DeployRiscZeroStack.s.soltrustedCertExpiriesarray (matches existing empty-set deployment pattern)Tests (
NitroEnclaveVerifier.t.sol)6 new tests added:
testExpiredCachedCertFailsVerification— cached cert past expiry returnsIntermediateCertsNotTrustedtestNonExpiredCachedCertPassesVerification— cached cert before expiry passestestCheckTrustedIntermediateCertsStopsAtExpiredCert— prefix count stops at expired certtestCacheNewCertStoresCorrectExpiry— verifies correctuint64storedtestRevokeCertSetsExpiryToZero— revocation clears to 0testConstructorRevertsIfCertExpiriesLengthMismatch— length validationAll 63 tests pass (default + CI profiles). All existing tests updated for
uint64semantics.Security Note
The
certExpiriesvalues originate from X.509notAfterfields in the DER-encoded certificate chain, covered by parent cert signatures. The ZK proof covers the entire journal, so on-chain expiry values are cryptographically verified — not trusted inputs.Related