fix(cli): let verifiers pin a TPM CA bundle - #548
Conversation
|
🟡 Contributor Check: MEDIUM
Automated check by AgenTrust Contributor Check. |
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
imran-siddique
left a comment
There was a problem hiding this comment.
Read the CLI change rather than the test plan. Approving.
The bundle is passed through as the caller's own bytes. _load_tpm_ca_bundle parses with load_pem_x509_certificates purely as a validity gate and then returns the file contents unchanged, rather than returning the parsed certificates re-serialized. That is the right call for a pinned trust anchor: the verifier compares against exactly what the operator put on disk, and a round trip through the parser is one more place for the bytes to change without anyone noticing.
Rejection happens before verification, and the empty case is covered. Unreadable file, non-PEM content, and a syntactically valid file containing zero certificates all raise ClickException before verify is reached. The zero-certificate case is the one usually missed, because load_pem_x509_certificates returns an empty list rather than raising, and an empty bundle would otherwise read as "no CA pinned" instead of as an error.
Scope holds. Only trusted_tpm_ca_pem is set. trusted_ark_pem and trusted_intel_root_pem stay unset, chain and quote validation are untouched, and the help text keeps the option TPM-only so nobody reaches for it on an SEV-SNP or TDX claim.
Non-blocking, and you already scoped it out correctly against #453, but worth recording on the thread for whoever uses this on Azure: this works for one of the two vTPM AK certificate hierarchies Azure issues concurrently. The Global Virtual TPM CA - 03 chain carries no AIA extension, so no pinned root makes it chain, and that is a producer-side problem this option cannot solve. Separating that from the verifier-side input was the right boundary to draw.
|
Approved, and it will merge as soon as this is rebased. #546 landed a few minutes after I reviewed and put a conflict in your way that has nothing to do with your change. Rebase onto I resolved it locally before asking you to, so this is verified rather than assumed:
The approval stands, so no re-review is needed. Push the rebase and it goes in. |
Signed-off-by: Noah Ingwers <98993329+noah-ing@users.noreply.github.com>
c385840 to
fa74712
Compare
|
Rebased onto |
What
Add
--trusted-tpm-ca FILEtocmcp verify. The command reads and parse-checks a non-empty PEM X.509 certificate bundle, then supplies those exact caller-controlled bytes to the existingtrusted_tpm_ca_pemverifier input.The option, tests, and documentation are explicitly TPM 2.0-only. This change does not add AMD SEV-SNP or Intel TDX CLI trust inputs.
Why
The TPM quote-verification path merged in #469 requires a verifier-owned CA bundle, but only Python callers could provide it. A CLI caller could supply a complete signed TPM claim and still had no way to authenticate its attestation-key chain, leaving the claim partially verified.
This is a narrow usability follow-up to #469 and the now-closed #370. It is separate from #520/#453: that work concerns producer-side assembly and hardware validation of one Azure vTPM certificate hierarchy, while this change exposes the already-existing verifier-side trust input.
Security impact
Positive, narrowly scoped trust-boundary wiring. The trust bundle remains an explicit, verifier-controlled input; cMCP does not trust a root carried by the claim and does not silently select a bundled default. Unreadable or malformed bundle input is rejected before claim verification.
Only
trusted_tpm_ca_pemis passed. The CLI does not settrusted_ark_pemortrusted_intel_root_pem, does not change TPM chain or quote validation, and does not change how AMD SEV-SNP or Intel TDX claims are evaluated.Test plan
pytest tests/unit/ -v --tb=short --cov=src— 1,240 passed, 6 skipped, 1 xfailed; 85.06% coverageruff check src/ tests/passesmypy src/cmcp_runtime/ src/cmcp_verify/passes — 63 source filesbandit -r src/ -c pyproject.tomlpasses — no findingspip-audit --skip-editable --ignore-vuln CVE-2026-69247passes — no known vulnerabilities, one repository-documented ignore--trusted-tpm-catwine checkpasses for both artifactsFocused regressions verify that malformed PEM is rejected before verification, valid bundle bytes reach
trusted_tpm_ca_pemexactly, unrelated platform trust inputs are omitted, and CLI help keeps the option TPM-only.DCO sign-off