ARM CCA Realm attestation: a CBOR/COSE CCA token collection (platform token
signed by the operator-pinned CPAK/IAK + realm token signed by the RAK, with
the H(RAK) platform-realm binding enforced). Vendor arm.cca, fail-closed zero
value, real COSE_Sign1 verification.
armcca branched before the registry landed and carried its own parallel copy
(extraVerifiers map + a duplicate registerVerifier + a second VerifierFor
lookup). Converged to the one registry: deleted that block so armcca.go's
init() registers through the canonical registerVerifier in verifier.go, and
repointed its self-registration test to RegisteredVerifier. There is one
registry, one lookup, one dispatch path — no second way.
go.mod: unioned the require blocks (cbor/v2, go-sev-guest, go-tdx-guest,
veraison/ccatoken, go-cose); go mod tidy clean; ccatoken is v1.4.0 and its
transitive jwx/v2, secp256k1/v4 carry their major in the import path — no dep
bumped to a new major. doc.go + verifier.go: ARM CCA is now a real 6th Kind,
not pending. verifier_test.go: TestRegistry_RoutesEveryKind covers all six.
go build/vet/test + go test -race ./attest/... green; gofmt clean.
COSE_Sign1/CBOR attestation document verifier (ES384, pinned AWS Nitro
Enclaves Root G1). go.mod conflict with the TDX require-block resolved by
unioning all four direct deps (cbor/v2, go-sev-guest, go-tdx-guest, go-cose);
go mod tidy clean, no version bumped.
The switch+registry coexistence introduced here is transient — the next
commit folds Dispatch into the single init() registry.
Adds the ARM Confidential Compute Architecture (CCA / RME Realms) TEE
attestation Kind to the one-verifier seam, alongside SEV-SNP/TDX/NVTrust.
Orthogonal and self-contained, in its own files (armcca.go, armcca_test.go).
Verification follows the IETF RATS model + the ARM CCA token format and is
built on exactly the two named primitives — CBOR (fxamacker/cbor/v2) and
COSE (veraison/go-cose) — plus stdlib:
- parse the CBOR collection envelope (CMW tag 907 or legacy EAT tag 399)
into the platform + realm COSE_Sign1 tokens
- verify the platform token COSE_Sign1 against an operator-pinned CPAK
(ARMCCA.TrustAnchors; empty => refuse, no insecure mode)
- extract the RAK from the realm claims (raw P-384 point or COSE_Key, per
realm-profile presence) and verify the realm token COSE_Sign1 under it
- enforce the platform<->realm binding: platform nonce == H_alg(RAK)
- map RIM -> Measurement, realm challenge -> ReportData (freshness),
REM/config/lifecycle/profiles -> Extra; CompositeHash over verified fields
- refusal taxonomy: bad COSE sig -> ErrSignatureInvalid; broken binding ->
ErrChainInvalid; malformed -> ErrInvalidEvidence; stale nonce / wrong
measurement / missing anchor -> ErrPolicy
KindARMCCA self-registers via init() into a per-file registry (VerifierFor);
it edits no shared file. Wiring Dispatch's switch to consult the registry is a
one-line maintainer follow-up, kept out of this change by file scope.
Tested against real ARM CCA token vectors from the Veraison / Trusted-Firmware
RMM corpus (CMW/tag-907 P-384 CPAK + EAT/tag-399 P-256 IAK), cross-checked
against the canonical veraison/ccatoken reference (a test-only dependency),
with tamper / broken-binding / wrong-key / stale-nonce / malformed refusal
coverage. ccatoken/psatoken/jwx stay out of the production import graph.
Adds AWS Nitro Enclaves as an orthogonal hardware Kind behind the existing
one-Verifier seam, mirroring the SEV-SNP/NVTrust pattern (struct + Verify +
compile-time guard; wired into Dispatch).
Nitro.Verify performs real, end-to-end verification of a Nitro attestation
document (CBOR-encoded COSE_Sign1, RFC 9052):
1. Parse the COSE_Sign1 envelope, tagged (CBOR tag 18) or untagged.
2. CBOR-decode the attestation-document payload with a hardened decoder
(duplicate map keys rejected) and validate its shape per the AWS CDDL
(module_id, digest=="SHA384", timestamp, pcrs 0..31 of 48 bytes,
certificate, cabundle).
3. Require the leaf certificate's key to be ECDSA P-384.
4. Build the X.509 chain leaf -> cabundle intermediates -> the pinned AWS
Nitro Enclaves Root G1, anchored ONLY at the embedded root (never the
cabundle's own root), ExtKeyUsageAny (Nitro leaves carry no EKU), CRL
disabled per AWS.
5. Verify the COSE_Sign1 signature against the leaf P-384 key, binding the
protected-header algorithm to ES384 (kills algorithm substitution).
6. Map PCR0 -> Measurement, nonce -> ReportData, user_data -> HostData; all
PCRs into Extra. Enforce caller policy: WithNitroPCRs, the generic
WithExpectedMeasurement (PCR0) / WithExpectedReportData (nonce), and
WithNitroMaxAge freshness.
The trust anchor is pinned, not taken from the evidence: the embedded AWS
root PEM is self-checked at parse time against the AWS-published SHA-256
fingerprint 641a0321...79bb5b. No insecure mode — a document that does not
chain to the pinned AWS root is refused. WithNitroRoots overrides the anchor
for deterministic tests only (mirrors the SEV WithKDSGetter test override).
Tests (white-box, hermetic, no network): a self-consistent vector built with
real cryptography (P-384 root/intermediate/leaf chain, real COSE_Sign1/ES384
via go-cose, real CBOR via fxamacker), the genuine pinned-root authenticity
check (fingerprint/CN/curve/self-signature/validity), and a full tamper matrix
(bad signature, tampered payload, wrong/unrelated root, expired/broken chain,
wrong/absent PCR, measurement/nonce mismatch, stale/future timestamp, wrong
digest, bad PCR length, non-P384 leaf, algorithm substitution, duplicate CBOR
key, bad CBOR). CompositeHash determinism + content-binding asserted.
Deps: github.com/fxamacker/cbor/v2 v2.9.2, github.com/veraison/go-cose v1.3.0.
TDX was a fail-loud stub (Verify returned ErrNotImplemented, parsing nothing).
It now performs the complete Intel TDX DCAP attestation flow via the canonical
Google verifier github.com/google/go-tdx-guest (v0.3.1, sibling of the
go-sev-guest used by KindSEVSNP), matching the SEV path's rigor:
- Parse the DCAP v4 quote (QuoteV4 only) via go-tdx-guest/abi.
- Verify the PCK certificate chain embedded in the quote's signed
certification data up to the Intel SGX Root CA pinned inside go-tdx-guest
(verify/trusted_root.pem) — the trust anchor is never taken from the quote.
- Verify the Quoting Enclave (QE) report signature and the attestation-key
binding (QE report data == SHA-256(att key || QE auth data)).
- Verify the TD report (TDQuoteBody) ECDSA-P256 signature.
- Fetch Intel PCS collateral (TCB Info + QE Identity + PCK/Root CRLs) and
enforce TCB status (UpToDate) and revocation. GetCollateral and
CheckRevocations are ON; DefaultOptions leaves them off, so we set them.
- Fold MRTD + the four RTMRs into a 48-byte SHA-384 TD measurement root
(Measurement); raw registers + MRSEAM/TD_ATTRIBUTES/XFAM/etc. in Extra.
- Enforce caller policy (expected measurement / report-data nonce binding)
in constant time, and bind CompositeHash to the canonical TD fields.
(nil, err) always means refuse — no partial report, no best-effort fallback.
go-tdx-guest error strings are classified onto the package refusal taxonomy
(ErrInvalidEvidence / ErrSignatureInvalid / ErrChainInvalid / ErrPolicy).
Tests (attest/tdx_test.go) run offline against a REAL Intel Sapphire Rapids
TDX quote + Intel collateral committed verbatim to testdata/ (from the
go-tdx-guest corpus; the go-tdx-guest `testing` getter is linux-gated, so a
small replay getter is used here):
- real SPR quote passes the full DCAP cryptographic chain;
- full production path refuses the fixture on TCB status (upstream
deliberately bumped the sample TCB SVN above the quote) -> ErrPolicy;
- tamper rejection: flipped MRTD breaks the TD report signature, flipped
ECDSA sig rejected, bad version / truncation / garbage -> ErrInvalidEvidence;
- measurement fold + composite hash determinism + policy binding;
- no-fallback when Intel PCS is unreachable; stale-clock refusal; Dispatch
routing; context cancellation.
verifier_test.go: retired TestStubsReturnNotImplemented /
TestDispatch_StubKindsReturnNotImplemented (TDX was the last stub kind they
asserted) now that TDX is real — mirrors the earlier NVTrust promotion which
already edited this file. go.mod/go.sum: add go-tdx-guest v0.3.1 (latest, < v1).
GOWORK=off go build/vet/test/-race ./... all green.
Extract the canonical vendor-neutral attestation verifier out of luxfi/mpc
into its own orthogonal leaf module github.com/luxfi/cc so the MPC custody
system, the TEE custody extension, and the confidential-AI / proof-of-AI
system can all depend on ONE verifier and the verifier depends on none of
their domains.
- attest: Verifier interface, VerifiedReport, Option, Dispatch.
KindSEVSNP (PROD, go-sev-guest + AMD KDS), KindTDX (fail-loud stub),
KindNVTrust (NEW, PROD local-RIM mode).
- attest/nvidia: GPU evidence parser, signed-RIM verifier + measurement
matcher, NRAS remote JWS client (moved verbatim from mpc/pkg/attestation/
nvidia — clean stdlib-only leaf).
- KindNVTrust replaces the former KindNRAS stub with a real, cloud-free
verify: parse GPU evidence, verify the NVIDIA-signed RIM against an
operator-pinned key, match every measurement to the signed golden value.
No insecure mode; empty RIM/roots is refused.
Leaf builds + tests green standalone (GOWORK=off).