Skip to content

Fix certificate cache key malleability#35

Open
leanthebean wants to merge 1 commit into
base:mainfrom
leanthebean:security/cert-cache-canonical-id
Open

Fix certificate cache key malleability#35
leanthebean wants to merge 1 commit into
base:mainfrom
leanthebean:security/cert-cache-canonical-id

Conversation

@leanthebean

Copy link
Copy Markdown
Contributor

Summary

  • Key non-root certificate cache entries by keccak256(tbsCertificate) instead of full DER bytes.
  • Keep the AWS Nitro root pinned to ROOT_CA_CERT_HASH and reject malleable root aliases.
  • Update docs, demo script output, and regression tests for the new cache key semantics.

Security issue

CertManager.verifyCACertWithHints previously used keccak256(raw cert bytes) as the verification cache key. The outer X.509 certificate signature is ECDSA P-384, and low-S is intentionally not enforced because AWS Nitro signatures may not be low-S. That means a valid certificate can have a byte-distinct (r, n-s) signature twin with the same signed TBS, subject, and public key.

Because verifiedParent is write-once, a caller could cache a shadow parent under the malleated full-DER hash, then pin a genuine child certificate to that alternate parent. Honest warm validation using the canonical certificate chain would later hit parent cert mismatch, producing a persistent denial of service for the hinted Nitro attestation path.

Fix

Non-root certificate cache identity now derives from the signed tbsCertificate bytes. ECDSA signature malleability only changes the outer signature bytes, so canonical and malleated encodings of the same certificate resolve to the same cache entry. The pinned root remains keyed by ROOT_CA_CERT_HASH; if a malleated root encoding verifies under the root key, CertManager rejects it as root cert alias so it cannot become a second trusted parent cache key.

This preserves support for AWS Nitro P-384 signatures without adding a low-S requirement, while removing the malleable bytes from the cache identity used by verifiedParent.

Tests

  • forge fmt
  • forge test

Added regression coverage showing that:

  • a malleated non-root certificate and its canonical encoding share the same TBS cache key;
  • the canonical certificate warm path succeeds after the malleated encoding has been cached;
  • a malleated root alias reverts with root cert alias.

Addresses CAT finding 15bf935b-8ecd-4cd6-aba6-40123684840c.

@leanthebean leanthebean force-pushed the security/cert-cache-canonical-id branch from e2604cd to c649735 Compare June 18, 2026 20:32
Key non-root certificate verification cache entries by the signed tbsCertificate instead of the full DER bytes so ECDSA signature malleability cannot create shadow cache identities. Keep the pinned root under ROOT_CA_CERT_HASH and reject malleable aliases of that trust anchor.

Add regression coverage for malleated certificate signatures and update docs/scripts to use the returned cache key.
@leanthebean leanthebean force-pushed the security/cert-cache-canonical-id branch from c649735 to 3242d80 Compare June 18, 2026 20:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant