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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Certificate-chain verification now delegates to agent-manifest's shared generic verifier (`agent-manifest>=0.5`) instead of ca2a's own copy. `ca2a_verify.verify_cert_chain` (used by the SEV-SNP VCEK, TDX PCK, and TPM AK chains alike) is now a thin wrapper over `agent_manifest.verify_cert_chain`, re-raising `CertChainError` as `AttestationFailed` to preserve ca2a's contract. This removes the org's last duplicated cert-chain verifier; ca2a keeps its own report/quote parsers, per-format signature checks, appraisal shapes, trust-root pinning, and `verify_offer` semantics. Behavior unchanged (all 201 tests pass unchanged).
- Bumped `agentrust-trace` to `>=0.4`. The previous `<0.4` cap worked around the
published 0.3.0 lacking the TRACE A2A `delegation` block that cA2A records
carry; 0.4.0 ships that block, so the cap is removed. cA2A still owns the
Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ dependencies = [
# (see ROADMAP Tier 0). Pin a compatible minor; cross-repo skew is a known
# risk documented in LIMITATIONS.md.
"agentrust-trace>=0.4",
# Shared hardware-attestation verification (generic cert-chain verifier,
# SNP/TDX/TPM primitives) consumed via PyPI instead of duplicated per repo.
"agent-manifest>=0.5",
"rfc8785>=0.1",
]

Expand Down
38 changes: 15 additions & 23 deletions src/ca2a_verify/sev_snp.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
from cryptography.hazmat.primitives.hashes import SHA256, SHA384
from cryptography.hazmat.primitives.hashes import SHA384

from ca2a_runtime.errors import AttestationFailed
from ca2a_runtime.tee.sev_snp import SEV_GUEST_DEVICE, SIG_ALGO_ECDSA_P384_SHA384, SevSnpReport
Expand All @@ -33,30 +33,22 @@ def verify_cert_chain(
) -> None:
"""Verify a leaf-to-root certificate chain against a set of trusted roots.

``chain`` is ordered leaf first (VCEK), root last (ARK). Each certificate
must be directly issued by the next, and the final certificate must match a
trusted root by fingerprint. Raises AttestationFailed on any failure.
``chain`` is ordered leaf first (VCEK), root last (ARK). Delegates to
agent-manifest's shared, algorithm-agnostic cert-chain verifier (one
implementation across the org, consumed via PyPI) and re-raises its failure
as AttestationFailed to preserve ca2a's error contract. Used for the SEV-SNP
VCEK chain, the TDX PCK chain, and the TPM AK chain alike. Raises
AttestationFailed on any failure.
"""
if not chain:
raise AttestationFailed("empty certificate chain")

for i in range(len(chain) - 1):
child, issuer = chain[i], chain[i + 1]
try:
child.verify_directly_issued_by(issuer)
except (ValueError, TypeError, InvalidSignature) as exc:
raise AttestationFailed(
f"certificate at position {i} is not validly issued by the next",
detail=str(exc),
) from exc

root = chain[-1]
trusted = {c.fingerprint(SHA256()) for c in trusted_roots}
if root.fingerprint(SHA256()) not in trusted:
from agent_manifest import CertChainError
from agent_manifest import verify_cert_chain as _shared_verify_cert_chain

try:
_shared_verify_cert_chain(chain, trusted_roots)
except CertChainError as exc:
raise AttestationFailed(
"chain root is not a trusted AMD root",
detail=root.subject.rfc4514_string(),
)
"certificate chain verification failed", detail=str(exc)
) from exc


def verify_sev_snp_report(
Expand Down