prototype: tee-attestation package for TMP router attestation RFC (backs adcontextprotocol/adcp#5770)#395
Draft
ohalushchak-exadel wants to merge 1 commit into
Draft
Conversation
…extprotocol/adcp#5770) Adds a stand-alone Go package that implements both sides of the wire shape proposed in the spec RFC: - Emit path: Nsm interface (matches the AWS Nitro NSM AttestationDoc request shape) plus a mock Nsm that generates real COSE_Sign1 documents signed by a caller-owned test CA. Same wire format as production Nitro, so the verifier code path is byte-for-byte identical between mock and prod. - Verify path: full 9-step verification flow from the normative page — nonce echo, expiry, freshness, format support, COSE_Sign1 parse, cert-chain to a caller-supplied root, ECDSA-P384 signature check, slot-bound nonce, binding rule (RFC 7638 thumbprint), measurement-policy hook. Returns typed VerifyError values naming the failure modes the spec defines. Wired against a `nitro` build tag placeholder for a real /dev/nsm impl; real wiring lands in a follow-up. Router integration deferred until the byte layout in the spec is settled — the whole point of building this prototype is bokelley's finding on the spec PR that the slot bytes are what you learn by binding against a real Nitro document. The finding is documented in nitro/PROJECTION.md and is the primary deliverable: the spec's "same user-data slot" wording is a category error for Nitro (which has three separate fields: `nonce`, `public_key`, `user_data`), and the cleanest projection uses those dedicated fields directly rather than inventing a synthetic packing. That feeds back into the spec's slot-projection registry item and, transitively, its GCP-vs-Nitro asymmetry (GCP is a JWT, not a raw slot). Round-trip test covers the happy path plus all 8 failure modes from the spec's failure-mode table: nonce_mismatch, envelope_expired, unsupported_format, platform_verification_failed (tampered document AND wrong root), signing_key_not_bound, measurement_disallowed, per-request path without nonce echo. All 11 tests pass on the mock; no Nitro hardware required. Not in this prototype (explicit non-goals in the README): - Real Nitro NSM wiring - TDX / SEV-SNP / GCP Confidential Space - Router integration (cmd/router, router/) - X-TMP-Attestation per-request header carrier - KMS-bound in-enclave key custody Deps: github.com/veraison/go-cose, github.com/fxamacker/cbor/v2. Both pure Go, no cgo.
ohalushchak-exadel
force-pushed
the
ohalushchak-exadel/tee-attestation-prototype
branch
from
July 2, 2026 11:25
b68f712 to
efde51d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft prototype. Not for merge. This exists to answer the byte-layout question bokelley raised on adcontextprotocol/adcp#5770 — his sequencing recommendation was "prototype the Nitro emit-path + one verifier kit in adcp-go first, then promote the proven envelope." This is that.
What this is
A stand-alone
tee-attestation/Go package that implements both sides of the wire shape proposed in the spec RFC:Nsminterface matching the AWS Nitro NSMAttestationDocrequest shape, plus a mockNsmthat generates real COSE_Sign1 documents signed by a caller-owned test CA. Same wire format as production Nitro, so the verifier code path is byte-for-byte identical between mock and prod.docs/trusted-match/router-attestation.mdx: nonce echo, expiry, freshness, format support, COSE_Sign1 parse, cert-chain to a caller-supplied root, ECDSA-P384 signature check, slot-bound nonce, binding rule (RFC 7638 thumbprint), measurement-policy hook. Returns typedVerifyErrorvalues naming the failure modes from the spec's failure-mode table.Primary deliverable: the byte-layout finding
The whole point of building this is
tee-attestation/nitro/PROJECTION.md. Short version:nonce,public_key,user_data), not one shared slot. This prototype uses them directly:nonce(raw bytes) → Nitrononcefieldsigning_key(raw Ed25519 pubkey bytes) → Nitropublic_keyfielduser_datafield → intentionally unused, reserved for extensionpublic_keyfield is documented as "the public key that the enclave wants to have attested" — exactly what the binding rule anchors against. Raw bytes are simpler than JCS-encoded JWK, and the verifier reconstructs the JWK deterministically to run the thumbprint check.The spec's slot-projection registry item needs one normative entry per format (Nitro / TDX / SEV-SNP / GCP), not a single "slot" description. That's the payload back into the spec PR.
Round-trip evidence
roundtrip_test.go— 11 tests covering the happy path plus every failure mode from the spec's failure-mode table:TestNitroRoundTripTestVerifyRejectsNonceMismatchnonce_mismatchTestVerifyRejectsExpiredEnvelopeenvelope_expiredTestVerifyRejectsUnsupportedFormatunsupported_formatTestVerifyRejectsTamperedDocumentplatform_verification_failedTestVerifyRejectsSwappedSigningKeysigning_key_not_boundTestVerifyRejectsWrongRootplatform_verification_failedTestVerifyRejectsPolicyDisallowmeasurement_disallowedTestVerifyAcceptsPerRequestPathWithoutNonceEchoX-TMP-Attestationcode path)TestEnvelopeJSONRoundTripTestJWKThumbprintStableAll pass. Run locally with
go test ./tee-attestation/...— no Nitro tooling required.Explicitly not in this PR
nsm_real.gois a stub behind anitrobuild tag. Running against a real Nitro instance is the follow-up.cmd/routerandrouter/do not use this package. Wiring lands once the spec's byte layout is settled — the whole point of building this prototype was that adopting the wire before it's proven ripples every spec change into production code.X-TMP-Attestationper-request header carrier. Envelope + verifier first.Dependencies added
github.com/veraison/go-cose— COSE_Sign1 sign/verify. Pure Go, actively maintained by the Veraison working group (IETF RATS).github.com/fxamacker/cbor/v2— CBOR encode/decode with Core Deterministic Encoding option. Pure Go.Both are pure Go — no CGO added.
Test plan
go test ./tee-attestation/...— 11 tests pass.go vet ./tee-attestation/...— clean.gofmt -l tee-attestation/— clean.go build ./...— full-repo build unchanged.public_keyfield, raw nonce innoncefield) is the right factoring for the spec's slot-projection registry item.🤖 Generated with Claude Code