Status: Draft v0.1 Last updated: 2026-06-04 Stability: Unstable , expect breaking changes before v1.0 —
This document is the interface specification for the cmcp-verify Python library. Implementation is separate from this spec. All type stubs below define the public interface that the implementation must satisfy.
from dataclasses import dataclass
from enum import Enum
from typing import Optional
import datetime
class TEEProvider(Enum):
TPM = "tpm"
SEV_SNP = "sev-snp"
TDX = "tdx"
OPAQUE = "opaque"
SOFTWARE_ONLY = "software-only"
class VerificationStatus(Enum):
VERIFIED = "verified"
UNVERIFIED = "unverified"
PARTIALLY_VERIFIED = "partially_verified"
@dataclass
class VerificationResult:
status: VerificationStatus
verified_fields: list[str] # fields successfully verified
unverified_fields: list[str] # fields present but not verified (provider not supported, etc.)
failure_reason: Optional[str] # None if status != UNVERIFIED
attestation_age_seconds: int # how old the attestation is
is_attestation_fresh: bool # attestation_age_seconds < configured validity window
@dataclass
class ApprovedHashes:
policy_bundle_hash: str # sha256 hex string of approved policy bundle
tool_catalog_hash: str # sha256 hex string of approved tool catalog
def verify_trace_claim(
claim_json: dict,
approved: ApprovedHashes,
max_attestation_age_seconds: int = 86400,
*,
trusted_public_key_hex: Optional[str] = None,
agent_manifest: Optional[dict] = None,
trusted_agent_manifest_keys: Optional[dict[str, bytes]] = None,
) -> VerificationResult:
"""
Verify a TRACE Claim without trusting the operator.
Steps:
1. Verify tee_public_key is bound to attestation_report (provider-specific)
2. Verify signature over canonical claim body using tee_public_key
3. Check policy_bundle.hash against approved.policy_bundle_hash
4. Check tool_catalog.hash against approved.tool_catalog_hash
5. If agent_manifest and trusted_agent_manifest_keys are provided, verify
the Agent Manifest issuer signature with agent-manifest SDK
verify_manifest() and cross-check gateway.agent_identity:
manifest_id, agent_id/authenticated_subject, subject_source, policy hash,
catalog hash, and manifest expiry.
6. Check attestation freshness (timestamp within max_attestation_age_seconds)
7. Verify audit chain continuity (audit_chain_root, audit_chain_tip)
Returns VerificationResult with status and details.
"""
...
trusted_agent_manifest_keys keeps cMCP’s runtime-facing shape as raw Ed25519
public key bytes keyed by issuer key_id; the verifier base64url-encodes those
keys when calling the Agent Manifest SDK.
| Confirm the quote’s qualifying_data matches SHA-256(tee_public_key | session_id) from the TRACE Claim – this binds the quote to the specific runtime instance. |
| Confirm report.REPORT_DATA == SHA-256(tee_public_key | session_id) (bytes 0-31 of REPORT_DATA). |
| Confirm TD_REPORT.REPORT_DATA == SHA-256(tee_public_key | session_id). |
| Confirm TD_REPORT.MRTD | RTMR0 | RTMR1 | RTMR2 | RTMR3 == attestation_report.measurement (concatenated). |
| The endpoint returns: {verified: true | false, measurement_matched: true | false, error?: string}. |
VerificationStatus.PARTIALLY_VERIFIED is returned when:
VerificationError enum:
Phase 1 must support TPM and SEV-SNP at minimum. TDX is high priority for the first release. Opaque is handled by the managed runtime and does not require a separate implementation path.
SOFTWARE_ONLY is a valid enum value for local development and CI environments. A claim with provider: software-only must always return VerificationStatus.PARTIALLY_VERIFIED with failure_reason set, never VERIFIED.
from cmcp_verify import verify_trace_claim, ApprovedHashes
import json
trace_claim = json.load(open("session-trace.json"))
approved = ApprovedHashes(
policy_bundle_hash="sha256:abc123...",
tool_catalog_hash="sha256:def456..."
)
result = verify_trace_claim(trace_claim, approved)
print(f"Status: {result.status.value}")
print(f"Verified fields: {result.verified_fields}")
if not result.is_attestation_fresh:
print(f"WARNING: attestation is {result.attestation_age_seconds}s old")
As noted in threat-model.md, T.1 (server swap / tool identity) is only closed if the agent or the agent’s runtime runs verify_trace_claim before sending traffic. Attestation without verification is post-hoc evidence, not a runtime gate.