fix(security): bind cnf.jwk fingerprint to TEE report_data (CRYPTO-001) - #259
Merged
Merged
Conversation
…re verification (CRYPTO-001) The verifier previously accepted any Ed25519 keypair because it extracted the public key from the claim it was verifying with no check that the key was hardware-attested. An attacker could generate a fresh keypair, sign a fraudulent TRACE Claim, embed their own public key in cnf.jwk, and _verify_signature() would return sig_ok=True. Fix (gateway): startup.py now constructs the TEE attestation nonce as SHA-256(public_key_bytes) || random_salt(32 bytes). The TEE hardware commits this into the signed report_data field, binding the keypair to the attestation report at instance startup. Fix (verifier): new _verify_key_binding() in cmcp_verify/verify.py extracts trace.runtime.nonce (base64url), decodes it, takes the first 32 bytes, and compares to SHA-256(cnf.jwk.x public key bytes). A mismatch sets failure_reason = PUBLIC_KEY_NOT_BOUND regardless of Ed25519 result, since a substituted key means the signing key cannot be trusted. Software-only/Level-0 mode logs a warning and skips the check, consistent with other Level-0 behaviors. The out-of-band trusted_public_key_hex cross-check is preserved as a separate "trusted_public_key" verified field for callers that pin the key externally. Closes #140 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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
_verify_signature()accepted any Ed25519 keypair because the verifier used the public key from the claim being verified, with no check that the key was hardware-attested. An attacker could generate their own keypair, sign a fraudulent claim, embed their public key incnf.jwk, and verification passed.startup.py): constructs the TEE nonce asSHA-256(public_key_bytes) || random_salt(32)so the hardware attestation report binds the specific keypair viareport_data[:32].cmcp_verify/verify.py): new_verify_key_binding()extractstrace.runtime.nonce, takes first 32 bytes, and compares toSHA-256(cnf.jwk.x). Mismatch setsfailure_reason = PUBLIC_KEY_NOT_BOUNDunconditionally (higher-priority than signature failure). Software-only/Level-0 logs a warning and skips, consistent with other Level-0 behaviors.Test plan
test_tee_key_binding_happy_path: valid key with matching report_data fingerprint passestest_tee_key_binding_attack_path_mismatched_fingerprint: attacker re-signs with fresh key, nonce encodes gateway fingerprint, fails withPUBLIC_KEY_NOT_BOUNDtest_tee_key_binding_absent_nonce_fails: hardware claim with no nonce fails withPUBLIC_KEY_NOT_BOUNDtest_tee_key_binding_software_only_exempt: software-only provider exempt, no penaltytest_verify.pypassCloses #140
🤖 Generated with Claude Code