Skip to content

Attestation providers

Hardware attestation providers for Levels 1–3. See Tutorial: Hardware attestation for usage and mocking patterns.

Scope: extend_manifest_hash() + get_attestation_report() run once at agent startup and prove which manifest was active when the TEE was initialised. They do not continuously monitor runtime state. For periodic freshness proofs use attest_runtime_state() — see RuntimeAttestationReport.

Base types

AttestationProvider

Bases: ABC

Interface all providers implement.

extend_manifest_hash abstractmethod

extend_manifest_hash(manifest_json: dict[str, Any]) -> None

Extend the manifest hash into the hardware measurement register.

Called once at agent startup. The result is the boot-time attestation: it proves which manifest was active when the TEE was initialised, but does not continuously track runtime state changes after that point.

get_attestation_report abstractmethod

get_attestation_report() -> AttestationReport

Return the boot-time platform attestation report.

verify_manifest_in_report abstractmethod

verify_manifest_in_report(report: AttestationReport, manifest_json: dict[str, Any]) -> bool

Return True if the report contains the expected manifest hash.

attest_runtime_state abstractmethod

attest_runtime_state(nonce: bytes, context_hash: str) -> RuntimeAttestationReport

Return a fresh hardware quote binding current runtime state to TEE identity.

Unlike extend_manifest_hash() + get_attestation_report() which run once at startup, this method can be called periodically or per-N-calls to produce a hardware-signed freshness proof of the agent's current runtime state.

The hardware sets the guest-controlled field (REPORT_DATA on SNP) to: sha256(nonce || bytes.fromhex(context_hash.split(":")[-1])) and signs it together with the unchanged boot measurement, so a verifier holding the nonce can confirm both TEE identity and current state.

The boot measurement (MEASUREMENT / MRTD / PCR values) is immutable — this call does not re-measure the TEE. It produces a fresh hardware signature over new caller-supplied data in the user-controlled field.

Parameters:

Name Type Description Default
nonce bytes

Freshness token supplied by the verifier (16–32 bytes). A new nonce must be used for each challenge to prevent replay.

required
context_hash str

sha256: of the current runtime context. Callers compute this from system_prompt_hash, policy_hash, tool_catalog_hash, and any other state that must be proven fresh. Use canonical JSON + sha256 for determinism.

required

Raises:

Type Description
AttestationUnavailableError

If the hardware device is not accessible or (for TPM) the Attestation Key has not been provisioned.

manifest_pre_image

manifest_pre_image(manifest_json: dict[str, Any]) -> bytes

RFC 8785 canonical JSON of manifest with attestation block excluded.

This is the exact byte sequence extended into the hardware register and recorded in manifest_hash_in_report (spec Section 3.3).

manifest_hash_value

manifest_hash_value(manifest_json: dict[str, Any]) -> str

Return sha256: of the manifest pre-image.

AttestationReport dataclass

Portable attestation report returned by all providers.

RuntimeAttestationReport dataclass

Fresh hardware quote binding current runtime state to the TEE's boot measurement.

Produced by attest_runtime_state() on demand — distinct from the one-time AttestationReport produced at startup. The hardware signs both its immutable boot measurement (MEASUREMENT / MRTD / PCRs) and the caller-supplied REPORT_DATA = sha256(nonce || context_hash_bytes), so a verifier can confirm:

  1. TEE identity — same boot measurement as at startup (hardware hasn't changed)
  2. Current state — context_hash matches what the agent claims to be running
  3. Freshness — nonce is unique per challenge, preventing replay

The boot measurement itself never changes — this call does not re-measure the TEE firmware or kernel. What it adds is a hardware-signed certificate that a specific runtime state was active at a specific moment in that TEE.

AttestationUnavailableError

Bases: RuntimeError

Raised when the attestation hardware or daemon is not accessible.

Callers MUST NOT treat this as a silent success. An agent that cannot produce hardware attestation MUST NOT claim Level 1+ conformance.

Level 1 - TPM

TPMProvider

Bases: AttestationProvider

TPM 2.0 attestation provider.

Supports generic TPM 2.0 (PCR 15) and AWS Nitro Enclaves (PCR 8). Uses tpm2-tools CLI for PCR extension and quote generation.

On AWS Nitro, the NSM device (/dev/nsm) is detected automatically and PCR 8 is used instead of the default PCR 15.

For CI environments without a hardware TPM, install swtpm and set TPM2TOOLS_TCTI=swtpm: or TPM2TOOLS_TCTI=device:/dev/tpm0.

Raises:

Type Description
AttestationUnavailableError

If tpm2-tools is not installed or the TPM device is not accessible.

extend_manifest_hash

extend_manifest_hash(manifest_json: dict[str, Any]) -> None

Extend the manifest hash into PCR self._pcr using tpm2_extend.

The extended value is the SHA-256 of the RFC 8785 canonical manifest (attestation block excluded). This ensures the PCR value is deterministically bound to the exact manifest that was approved.

Raises:

Type Description
AttestationUnavailableError

If tpm2_extend fails.

get_attestation_report

get_attestation_report() -> AttestationReport

Read current PCR values and generate a TPM2 quote.

Raises:

Type Description
AttestationUnavailableError

If tpm2_pcrread or tpm2_quote fails.

verify_manifest_in_report

verify_manifest_in_report(report: AttestationReport, manifest_json: dict[str, Any]) -> bool

Check that the PCR in the report contains the expected manifest hash.

The expected value is the cumulative PCR extension value after the manifest hash was extended. For a PCR starting at 0x00..00: new_pcr = SHA-256(current_pcr_value || manifest_hash_bytes)

For simplicity, the SDK checks that the report's manifest_hash matches the hash we would compute from the manifest. A full PCR replay verification requires the pre-extension PCR value, which callers must supply for production use.

attest_runtime_state

attest_runtime_state(nonce: bytes, context_hash: str) -> RuntimeAttestationReport

TPM quote over current PCR state with nonce as qualifying data.

Requires a pre-provisioned Attestation Key (AK) passed as ak_context at construction time. To provision one:

tpm2_createprimary -c primary.ctx
tpm2_create -C primary.ctx -G rsa -u ak.pub -r ak.priv
tpm2_load -C primary.ctx -u ak.pub -r ak.priv -c ak.ctx

The quote covers the current value of PCR self._pcr (already extended with the manifest hash at startup) and the qualifying data sha256(nonce || context_hash_bytes), which the hardware signs together.

Note: Unlike SEV-SNP / TDX (where REPORT_DATA is freely caller-controlled), TPM PCR values accumulate — the boot-time extension cannot be undone. The qualifying data carries the freshness proof; the PCR proves TEE identity.

Level 2 - SEV-SNP and TDX

SEVSNPProvider

Bases: AttestationProvider

AMD SEV-SNP attestation via the kernel configfs-TSM interface.

For bare-metal / non-paravisor SNP guests (kernel 6.7+) where the guest controls REPORT_DATA. Binds the manifest hash into REPORT_DATA: the first 32 bytes carry sha256(manifest_pre_image), the rest is zero.

Report parsing and signature verification use :mod:._snp_verify, which was validated against a real SNP report. Hardware-validated end to end on a non-paravisor SEV-SNP guest (GCP N2D, AMD Milan): the manifest digest lands in the guest-controlled REPORT_DATA and the report verifies against the AMD VCEK chain. On Azure confidential VMs use :class:AzureCVMProvider instead (the guest cannot set REPORT_DATA there — the paravisor binds the vTPM AK into it).

Requirements
  • AMD EPYC (Milan or later) SNP guest, kernel 6.7+ with sev-guest driver
  • /sys/kernel/config/tsm/report present and a registered provider
  • root (configfs writes)

Parameters:

Name Type Description Default
require_vcek_verification bool

when True, fetch the VCEK from the AMD KDS at report time and verify the report signature + chain; a failure raises. Requires network and the httpx extra.

False
product str

AMD product line for KDS lookups ("Milan", "Genoa", "Turin").

'Milan'

extend_manifest_hash

extend_manifest_hash(manifest_json: dict[str, Any]) -> None

Request an SNP report with REPORT_DATA = sha256(pre_image) || 0x00*32.

attest_runtime_state

attest_runtime_state(nonce: bytes, context_hash: str) -> RuntimeAttestationReport

Fresh SNP report with REPORT_DATA = sha256(nonce || context_hash_bytes).

TDXProvider

Bases: AttestationProvider

Intel TDX attestation via the kernel configfs-TSM interface.

Hardware-validated on a non-paravisor Intel TDX guest (GCP C3, kernel 6.17). On such a guest the configfs-TSM tdx_guest provider returns a full remotely-verifiable DCAP quote (v4, ECDSA-P256) with the PCK certificate chain embedded, not a bare local TDREPORT. The guest controls REPORTDATA, so the manifest hash is bound there: the first 32 bytes carry sha256(manifest_pre_image), the rest is zero.

Quote parsing and signature/PCK-chain verification live in :mod:._tdx_verify and were validated against a real TDX quote. Azure TDX (behind a Hyper-V paravisor, like Azure SNP) surfaces attestation through the vTPM instead and is a separate follow-up.

Requirements
  • Intel TDX trust domain, kernel 6.7+ with the tdx-guest driver and the configfs-TSM interface, and an in-guest quote-generation path (GCP C3)
  • /sys/kernel/config/tsm/report present with the tdx_guest provider
  • root (configfs writes)

Parameters:

Name Type Description Default
require_quote_verification bool

when True, verify the DCAP quote signature + PCK chain (to the pinned Intel SGX Root CA) at report time; a failure raises.

False

extend_manifest_hash

extend_manifest_hash(manifest_json: dict[str, Any]) -> None

Obtain a TDX quote with REPORTDATA = sha256(pre_image) || 0x00*32.

attest_runtime_state

attest_runtime_state(nonce: bytes, context_hash: str) -> RuntimeAttestationReport

Fresh TDX quote with REPORTDATA = sha256(nonce || context_hash_bytes).

Level 3 - OPAQUE (not implemented)

Not implemented

OPAQUE managed runtime attestation is not implemented. The managed service is not generally available, and the SDK does not verify the TRACE claim such a service would return (no claim-signature check, no service_measurement verification). OPAQUEProvider therefore fails closed at construction. Use a locally-verifiable provider (SEV-SNP / TDX / Azure CVM) for Level 1+ attestation. Tracked with issue #201 (§5).

OPAQUEProvider

Bases: AttestationProvider

OPAQUE managed runtime attestation — NOT IMPLEMENTED.

The OPAQUE managed attestation service is not generally available, and the SDK does not verify the TRACE claim such a service would return (no claim signature check and no verification of the service's own enclave measurement). Rather than ship a path that looks like verification but is not (see issue #201 §5), this provider is explicitly disabled: constructing it raises AttestationUnavailableError.

It will be implemented when the managed service is available and a real claim-verification path exists (signature verified against a pinned OPAQUE key, plus a service_measurement check per spec §3.3). Until then, use a locally-verifiable provider (SEV-SNP / TDX / Azure CVM) for Level 1+.

Auto-provider

select_provider

select_provider(level: int = 0) -> AttestationProvider

Return the best available attestation provider for level.

Parameters:

Name Type Description Default
level int

Minimum conformance level required (0-3).

0

Raises:

Type Description
AttestationUnavailableError

If level > 0 and no hardware provider is available.

SoftwareProvider

Bases: AttestationProvider

Level 0 software-only fallback — no hardware attestation.

Produces a manifest hash using pure software SHA-256. Suitable for development and staging. MUST NOT be used for Level 1+ conformance.

attest_runtime_state

attest_runtime_state(nonce: bytes, context_hash: str) -> RuntimeAttestationReport

Software-only runtime state binding — no hardware involved.

Useful for development and testing. MUST NOT be used to satisfy Level 1+ conformance claims because there is no hardware signing.