Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Sealed peer channel (Tier 2): `ca2a_runtime.channel` (`SealedChannel`, `generate_channel_keypair`, `open_sealed`). HPKE-style X25519 -> HKDF-SHA256 -> ChaCha20-Poly1305 sealing a payload to the peer's attested key; only the peer's private key opens it, and a wrong key or tampered ciphertext fails closed. Claim C4 (sealed-payload confidentiality) is now a validated experiment at the cryptographic layer. The enclave-binding of the private key (a hardware property) and live-path wiring remain open.
- Cross-operator attestation (Claim C6) validated in software: a two-operator harness composing the SEV-SNP verifier, measurement pinning, and the sealed channel demonstrates independent keys, mutual attestation, confidential cross-operator delegation, and binary-swap detection. Synthetic report vectors (a genuine report needs SEV-SNP hardware); real hardware end to end remains open. **All six claims (C1-C6) are now validated experiments.**
- cA2A-compatible conformance suite: `tests/conformance/` with a normative README (stable MUST/SHOULD test IDs across delegation, scope-policy, attestation, sealed channel, provenance, and the inbound pipeline) and runnable checks that exercise every MUST-level requirement. Wired into CI and documented at `docs/spec/conformance.md`; ties to the CHARTER trademark language.
- TPM 2.0 attestation backend: `ca2a_runtime.tee.tpm` (TPMS_ATTEST parsing, `TpmProvider`) and `ca2a_verify.tpm.verify_tpm_quote` (AK chain to a caller-supplied vendor root, AK signature over the attest blob (ECDSA or RSA), magic/type checks, and qualifying-data/PCR-digest binding), all fail-closed. Synthetic-vector validated; TPM AK roots are per-vendor so the caller supplies its trusted roots. Quote generation requires a real TPM.
- Intel TDX attestation backend: `ca2a_runtime.tee.tdx` (DCAP Quote v4 parsing, `TdxProvider`) and `ca2a_verify.tdx.verify_tdx_quote` (PCK chain to a trusted Intel root, QE report signature, attestation-key binding, quote signature, and MRTD/report-data binding), all fail-closed. Chain path validated against the genuine Intel SGX Root CA; multi-level signature path validated with a synthetic self-consistent quote. Quote generation requires a real TDX guest.
- Transport-agnostic inbound peer request handler: `ca2a_runtime.peer.handle_peer_request` with `PeerRequest` / `PeerResult`. Composes the full pipeline (verify chain, intersect scope and enforce, open a sealed payload with the enclave key, emit a linked provenance record) fail-closed. A transport parses its wire format into a `PeerRequest`; cA2A does not define the transport (profile, not protocol).
- RFC 8785 (JSON Canonicalization Scheme) canonicalization: `ca2a_runtime.canonical.canonicalize`. Credential and provenance bodies are now signed over the JCS encoding (UTF-16 key ordering, JCS string escaping, literal non-ASCII, shortest-decimal integers), so cA2A signatures are cross-verifiable with agent-manifest. ASCII credentials are byte-identical to the previous encoding, so existing signatures still verify.
Expand All @@ -28,6 +29,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Live A2A transport wiring for the peer-enforcement decision core, including binding the seal to a verified attestation report (Tier 2)
- Cedar policy engine binding for the local policy (Tier 2)
- TPM attestation backend (Tier 3); end-to-end SEV-SNP and TDX validation against real hardware quotes
- End-to-end SEV-SNP, TDX, and TPM validation against real hardware quotes on a confidential VM

[Unreleased]: https://github.com/agentrust-io/ca2a/commits/main
2 changes: 1 addition & 1 deletion LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ cA2A is a pre-release profile in active design. This document states plainly wha

- **Runtime peer-delegation enforcement.** The runtime does not yet accept a delegation credential on a live inbound peer call, verify it in the request path, and intersect the delegated scope with a local Cedar policy. This is Tier 2 on the roadmap.
- **Sealed peer channel.** The channel is implemented: a payload is sealed to the peer's attested X25519 key (X25519 ECDH, HKDF-SHA256, ChaCha20-Poly1305), and only the holder of the peer's private key can open it. The remaining gap is the hardware property that the private key never leaves the peer's enclave (established by attestation), and wiring the seal to a verified report on a live inbound call. Until that end-to-end binding lands on hardware, do not assume a payload is confined to a specific attested measurement.
- **Real hardware attestation.** The **SEV-SNP verifier is implemented**: report parsing, VCEK certificate chain verification, ECDSA-P384 report-signature verification, and measurement/report-data binding, all fail-closed. The chain path is validated against the genuine AMD Milan root chain; the report-signature path is validated with synthetic vectors, since a real report plus VCEK pair needs SEV-SNP hardware. Report generation (`SevSnpProvider.attest`) still requires a real SEV-SNP guest. The **Intel TDX verifier is also implemented** (DCAP Quote v4: PCK chain to the genuine Intel SGX Root CA, QE report, attestation-key binding, quote signature, MRTD binding; synthetic-quote validated, quote generation needs a TDX guest). **The TPM backend is not yet implemented (Tier 3).** Until a backend verifies a real quote end to end against a golden measurement on hardware, cA2A must not be described as fully attested across trust domains.
- **Real hardware attestation.** The **SEV-SNP verifier is implemented**: report parsing, VCEK certificate chain verification, ECDSA-P384 report-signature verification, and measurement/report-data binding, all fail-closed. The chain path is validated against the genuine AMD Milan root chain; the report-signature path is validated with synthetic vectors, since a real report plus VCEK pair needs SEV-SNP hardware. Report generation (`SevSnpProvider.attest`) still requires a real SEV-SNP guest. The **Intel TDX verifier** (DCAP Quote v4: PCK chain to the genuine Intel SGX Root CA, QE report, attestation-key binding, quote signature, MRTD binding) and the **TPM 2.0 verifier** (AK chain to a caller-supplied vendor root, AK signature, magic/type, qualifying-data and PCR-digest binding) are also implemented and synthetic-vector validated; quote generation needs the respective hardware. Until a backend verifies a real quote end to end against a golden measurement on hardware, cA2A must not be described as fully attested across trust domains.

## Out of scope

Expand Down
3 changes: 2 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ Real hardware attestation verification (SEV-SNP VCEK chain, Intel TDX quote via

- **SEV-SNP verifier: landed.** Report parsing, VCEK chain verification (validated against the real AMD Milan root), ECDSA-P384 report-signature verification, and measurement/report-data binding, all fail-closed. Report generation still requires a real SEV-SNP guest. See `ca2a_verify.sev_snp` and [docs/spec/attestation.md](docs/spec/attestation.md).
- **TDX verifier: landed.** DCAP Quote v4 parsing, PCK chain to the genuine Intel SGX Root CA, QE report signature, attestation-key binding, quote signature, and MRTD binding, all fail-closed. Quote generation requires a real TDX guest. See `ca2a_verify.tdx`.
- **TPM 2.0 verifier: landed.** TPMS_ATTEST parsing, AK chain to a caller-supplied vendor root, AK signature (ECDSA or RSA), magic/type checks, and qualifying-data/PCR-digest binding, all fail-closed. Quote generation requires a real TPM. See `ca2a_verify.tpm`.
- **Cross-operator attestation (C6): validated in software.** A two-operator harness (SEV-SNP verifier + measurement pinning + sealed channel) shows independent keys, mutual attestation, confidential cross-operator delegation, and binary-swap detection. All six claims (C1-C6) are now validated experiments.
- **Pending:** the TPM backend; end-to-end validation of the SEV-SNP and TDX signature paths against real hardware quotes on a confidential VM; and a transport that parses real A2A wire messages into a `PeerRequest`.
- **Pending:** end-to-end validation of the SEV-SNP, TDX, and TPM signature paths against real hardware quotes on a confidential VM; and a transport that parses real A2A wire messages into a `PeerRequest`.

## v1.0: Stable profile

Expand Down
10 changes: 8 additions & 2 deletions docs/spec/attestation.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ An `AttestationReport` carries `platform`, `measurement`, the bound `public_key`
| `software-only` | none | Available; for development and CI. Reports `platform: software-only`, never a hardware platform string. |
| `sev-snp` | AMD SEV-SNP | Verifier implemented (see below). Report generation requires a real SEV-SNP guest. |
| `tdx` | Intel TDX | Verifier implemented (see below). Quote generation requires a real TDX guest. |
| `tpm` | TPM 2.0 / vTPM | Tier 3, not yet implemented |
| `tpm` | TPM 2.0 / vTPM | Verifier implemented (see below). Quote generation requires a real TPM. |
| `opaque` | OPAQUE Confidential Runtime | Tier 3, explicit opt-in, not auto-selected |

## SEV-SNP verification
Expand All @@ -39,9 +39,15 @@ An `AttestationReport` carries `platform`, `measurement`, the bound `public_key`

**What is validated.** The chain-verification path accepts the genuine self-signed Intel SGX Root CA fetched from Intel (`tests/fixtures/tdx/`) and rejects an untrusted root. The multi-level signature path (PCK to QE report to attestation key to quote) is exercised end to end with a synthetic self-consistent quote, because a genuine quote requires a TDX guest. Byte offsets follow the Intel DCAP Quote v4 layout; end-to-end validation against a real hardware quote requires a TDX guest and remains open.

## TPM verification

`ca2a_verify.tpm.verify_tpm_quote` appraises a TPM 2.0 quote (`TPMS_ATTEST`) offline: the AK certificate chain is verified to a trusted root, the AK signature over the attest blob is verified (ECDSA-SHA256 or RSA PKCS#1 v1.5), the structure is confirmed to be a TPM-generated quote (magic and type), and the qualifying data (the verifier's nonce) and the PCR digest (the platform measurement) are checked against expected values.

**What is validated.** Unlike SEV-SNP and TDX, TPM attestation keys chain to per-vendor EK roots, so there is no single published root to validate against; the caller supplies the vendor roots it trusts, and the verifier is exercised against synthetic self-consistent vectors. Producing a quote (`TpmProvider.attest`) fails closed off a real TPM.

## Fail closed

Providers without a backend `detect()` to False, so they are never selected automatically, and verification fails closed when evidence is absent or invalid. This is deliberate: cA2A must not be described as attested across trust domains until a real hardware backend verifies a quote against a golden measurement on hardware. The TPM backend remains Tier 3. See [LIMITATIONS.md](../../LIMITATIONS.md).
Providers without a backend `detect()` to False, so they are never selected automatically, and verification fails closed when evidence is absent or invalid. This is deliberate: cA2A must not be described as attested across trust domains until a backend verifies a quote against a golden measurement on real hardware. See [LIMITATIONS.md](../../LIMITATIONS.md).

## Why this is the critical path

Expand Down
190 changes: 95 additions & 95 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,95 +1,95 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "ca2a-runtime"
version = "0.1.0"
description = "Confidential agent-to-agent runtime: attested, attenuated delegation and sealed peer channels for A2A"
readme = "README.md"
license = { text = "MIT" }
authors = [
{ name = "AgentTrust Contributors", email = "oss@agentrust.io" },
]
keywords = ["a2a", "agent-to-agent", "delegation", "tee", "attestation", "confidential-computing", "ai-agents"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Security",
]
requires-python = ">=3.11"
dependencies = [
"cryptography>=42.0",
"pyyaml>=6.0",
]

[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=5.0",
"ruff>=0.4",
"mypy>=1.10",
"types-pyyaml",
"bandit[toml]>=1.7",
"pip-audit>=2.6",
]

[project.scripts]
ca2a = "ca2a_runtime.cli:main"

[project.urls]
Homepage = "https://github.com/agentrust-io/ca2a"
Repository = "https://github.com/agentrust-io/ca2a"
Documentation = "https://github.com/agentrust-io/ca2a/tree/main/docs"
"Bug Tracker" = "https://github.com/agentrust-io/ca2a/issues"

[tool.hatch.build.targets.wheel]
packages = ["src/ca2a_runtime", "src/ca2a_verify"]

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "-v --tb=short"
pythonpath = ["src"]

[tool.ruff]
src = ["src"]
line-length = 100
target-version = "py311"

[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "C4", "PIE", "T20", "RET", "SIM"]
ignore = ["E501"]

[tool.ruff.lint.per-file-ignores]
"src/ca2a_runtime/benchmarks.py" = ["T201"]
"src/ca2a_runtime/cli.py" = ["T201"]
"scripts/gen_example_chain.py" = ["T201"]
"scripts/gen_agt_evidence.py" = ["T201"]

[tool.bandit]
skips = ["B101"]

[tool.coverage.run]
source = ["src"]
omit = ["*/cli.py", "*/benchmarks.py"]

[tool.coverage.report]
fail_under = 70

[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true
warn_return_any = false
files = ["src/ca2a_runtime", "src/ca2a_verify"]

[[tool.mypy.overrides]]
module = ["ca2a_runtime.tee.sev_snp", "ca2a_runtime.tee.tdx", "ca2a_verify.tdx", "ca2a_runtime.channel.sealed"]
warn_unused_ignores = false
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "ca2a-runtime"
version = "0.1.0"
description = "Confidential agent-to-agent runtime: attested, attenuated delegation and sealed peer channels for A2A"
readme = "README.md"
license = { text = "MIT" }
authors = [
{ name = "AgentTrust Contributors", email = "oss@agentrust.io" },
]
keywords = ["a2a", "agent-to-agent", "delegation", "tee", "attestation", "confidential-computing", "ai-agents"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Security",
]
requires-python = ">=3.11"
dependencies = [
"cryptography>=42.0",
"pyyaml>=6.0",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-asyncio>=0.23",
"pytest-cov>=5.0",
"ruff>=0.4",
"mypy>=1.10",
"types-pyyaml",
"bandit[toml]>=1.7",
"pip-audit>=2.6",
]
[project.scripts]
ca2a = "ca2a_runtime.cli:main"
[project.urls]
Homepage = "https://github.com/agentrust-io/ca2a"
Repository = "https://github.com/agentrust-io/ca2a"
Documentation = "https://github.com/agentrust-io/ca2a/tree/main/docs"
"Bug Tracker" = "https://github.com/agentrust-io/ca2a/issues"
[tool.hatch.build.targets.wheel]
packages = ["src/ca2a_runtime", "src/ca2a_verify"]
[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"
addopts = "-v --tb=short"
pythonpath = ["src"]
[tool.ruff]
src = ["src"]
line-length = 100
target-version = "py311"
[tool.ruff.lint]
select = ["E", "F", "W", "I", "UP", "B", "C4", "PIE", "T20", "RET", "SIM"]
ignore = ["E501"]
[tool.ruff.lint.per-file-ignores]
"src/ca2a_runtime/benchmarks.py" = ["T201"]
"src/ca2a_runtime/cli.py" = ["T201"]
"scripts/gen_example_chain.py" = ["T201"]
"scripts/gen_agt_evidence.py" = ["T201"]
[tool.bandit]
skips = ["B101"]
[tool.coverage.run]
source = ["src"]
omit = ["*/cli.py", "*/benchmarks.py"]
[tool.coverage.report]
fail_under = 70
[tool.mypy]
python_version = "3.11"
strict = true
ignore_missing_imports = true
warn_return_any = false
files = ["src/ca2a_runtime", "src/ca2a_verify"]
[[tool.mypy.overrides]]
module = ["ca2a_runtime.tee.sev_snp", "ca2a_runtime.tee.tdx", "ca2a_runtime.tee.tpm", "ca2a_verify.tdx", "ca2a_verify.tpm", "ca2a_runtime.channel.sealed"]
warn_unused_ignores = false
3 changes: 3 additions & 0 deletions src/ca2a_runtime/tee/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from ca2a_runtime.tee.base import AttestationReport, BaseProvider
from ca2a_runtime.tee.sev_snp import SevSnpProvider, SevSnpReport
from ca2a_runtime.tee.tdx import TdxProvider, TdxQuote
from ca2a_runtime.tee.tpm import TpmProvider, TpmQuote

__all__ = [
"AttestationReport",
Expand All @@ -16,4 +17,6 @@
"SevSnpReport",
"TdxProvider",
"TdxQuote",
"TpmProvider",
"TpmQuote",
]
Loading
Loading