@@ -361,8 +361,9 @@ document signature.
361361Once the leaf and its CA chain are cached and unexpired, a later attestation signed by
362362the same leaf is a ** single transaction** (` validateAttestationWithHints ` ) carrying
363363only the COSE signature hints. The cabundle certs are not re-verified — they are
364- reloaded by ` keccak256(cert) ` identity, checked against their original cached parent,
365- and their cached metadata is re-checked.
364+ reloaded by verification cache key (` ROOT_CA_CERT_HASH ` for the pinned root,
365+ ` keccak256(tbsCertificate) ` for non-root certs), checked against their original cached
366+ parent, and their cached metadata is re-checked.
366367
367368Practical reuse cases:
368369
@@ -371,12 +372,12 @@ Practical reuse cases:
371372 document → 2 transactions;
372373- ** CA chain and leaf cached:** validate the document only → 1 transaction.
373374
374- ** Cache reuse** is allowed when: the submitted DER hashes to a cached cert; the cert
375- is unexpired (` notAfter ≥ block.timestamp ` ); the cached CA/client role matches; and
376- ` parentCertHash ` matches the parent used during cold verification; and neither the cert
377- nor its cached parent chain is revoked. The cache is global on-chain state — once any
378- caller verifies a cert, others reuse it until expiry or revocation, but only under the
379- same parent binding.
375+ ** Cache reuse** is allowed when: the submitted DER contains a TBS that hashes to a
376+ cached cert; the cert is unexpired (` notAfter ≥ block.timestamp ` ); the cached CA/client
377+ role matches; ` parentCertHash ` matches the parent used during cold verification; and
378+ neither the cert nor its cached parent chain is revoked. The cache is global on-chain
379+ state — once any caller verifies a cert, others reuse it until expiry or revocation,
380+ but only under the same parent binding.
380381
381382### Revocation model
382383AWS's Nitro attestation documentation disables CRL checking in its sample validation
@@ -410,23 +411,24 @@ cached descendant cannot keep verifying through an ancestor that was later revok
410411Revocation is checked independently of ` notAfter ` , so a revoked cert is untrusted even if
411412its X.509 validity period has not expired.
412413
413- ` loadVerified ` is intentionally a raw cache read. A non-empty return value means the cert
414- metadata was cached previously; it does not imply the cert is currently trusted, unexpired,
415- or unrevoked.
414+ ` loadVerified ` is intentionally a raw cache read by verification cache key . A non-empty
415+ return value means the cert metadata was cached previously; it does not imply the cert is
416+ currently trusted, unexpired, or unrevoked.
416417
417418** First-verified parent pinning.** A cached cert is pinned to the parent it was first
418- verified under: cold verification records ` verifiedParent[certHash] ` once, and every
419- later warm reuse requires the caller to present that exact ` parentCertHash ` (a mismatch
420- reverts with ` parent cert mismatch ` ). This is a deliberate, conservative binding — warm
421- reuse skips signature verification, so it must reflect the precise chain that was
422- cryptographically checked, not merely * a* valid same-subject issuer. The liveness
423- consequence is that if the same certificate is genuinely issued under two different CA
424- objects (for example a same-key CA renewal that produces new DER bytes, hence a new
425- parent hash), the cached leaf keeps verifying only through its first parent; a second
426- caller chaining it through the renewed parent must wait for the cached entry to expire.
427- For AWS Nitro this is effectively a non-issue because leaf certificates are short-lived
428- (~ 3h) and expire long before their issuing CA is rotated, so the binding self-heals; it
429- is documented here as a known edge rather than a fixed bug.
419+ verified under: cold verification records ` verifiedParent[certHash] ` once, where
420+ ` certHash ` is the canonical cache key, and every later warm reuse requires the caller to
421+ present that exact ` parentCertHash ` (a mismatch reverts with ` parent cert mismatch ` ).
422+ This is a deliberate, conservative binding — warm reuse skips signature verification,
423+ so it must reflect the precise chain that was cryptographically checked, not merely * a*
424+ valid same-subject issuer. The liveness consequence is that if the same certificate is
425+ genuinely issued under two different CA objects (for example a same-key CA renewal that
426+ produces a new TBS, hence a new parent hash), the cached leaf keeps verifying only
427+ through its first parent; a second caller chaining it through the renewed parent must
428+ wait for the cached entry to expire. For AWS Nitro this is effectively a non-issue
429+ because leaf certificates are short-lived (~ 3h) and expire long before their issuing CA
430+ is rotated, so the binding self-heals; it is documented here as a known edge rather than
431+ a fixed bug.
430432
431433** Warm-only guard.** ` validateAttestationWithHints ` re-runs the cabundle checks with an
432434* empty* hint stream. Cached certs return before signature verification; a missing cert
0 commit comments