Commit Graph
5 Commits
Author SHA1 Message Date
zeekay 41c32bd4a8 cc/attest: canonical TEE attestation verifier (#222 stage 1)
Adds the canonical TEE attestation verifier package at cc/attest. This
is the home for chain validation + trust anchor management; the
luxcpp/crypto/attestation parser primitives feed bytes here BEFORE
their measurement output is trusted.

Stage 1 — SEV-SNP — PRODUCTION:
  - cc/attest/sev.go: SEVSNP{} verifier built on
    github.com/google/go-sev-guest v0.14.1. Live VCEK fetch from AMD
    KDS, ARK→ASK→VCEK chain validation, signature verify against the
    leaf, MEASUREMENT/REPORT_DATA/HOST_DATA/CHIP_ID extraction,
    caller-supplied policy gates (WithExpectedReportData,
    WithExpectedMeasurement). 197 LOC.
  - testdata/: real-vendor Milan attestation report + VCEK leaf
    committed verbatim from the upstream go-sev-guest test corpus.
    Tests replay the AMD KDS responses via SimpleGetter so CI never
    hits the network.
  - 9 SEV-SNP tests passing (happy path, dispatch, length reject,
    tampered signature, wrong report_data, wrong measurement,
    deterministic composite hash, unknown kind, stub-panic guard).

Stage 2 — TDX — STUB (#222 stage 2):
  - cc/attest/tdx.go: TDX{}.Verify panics with ErrNotImplemented so
    any caller routing TDX evidence during stage 1 fails LOUD. Plan
    documented inline: go-tdx-guest + Intel PCS + QE/TDX module
    identity pinning.

Stage 3 — NRAS — STUB (#222 stage 3):
  - cc/attest/nras.go: NRAS{}.Verify panics with ErrNotImplemented.
    Plan: lift the existing pkg/attestation/nvidia NRAS client into
    the cc/attest contract with a JWKS cache.

Wire-in:
  - pkg/attestation/composite.go gains VerifyEvidence(ctx, opts...)
    which dispatches each Evidence blob to cc/attest by Issuer.
    Callers (kms release gate, scheduler) MUST invoke this before
    accepting parser output.

Doc:
  - cc/attest/doc.go states the production/stub matrix and the
    layering contract between the C-ABI parser and this package.
2026-04-28 00:47:37 -07:00
zeekay 5b400e656a nras: delete SkipSignature kill-switch (Red audit F4)
VerifyOptions.SkipSignature was a test-only boolean that bypassed
JWS verification entirely. Removed unconditionally. Production has
always required verification; the only caller was a test that
exercised the skip path. JWS verification is now non-optional.
2025-12-28 17:46:45 -08:00
zeekay 4d1c8f6d3d nras/jws: enforce alg ↔ key-type binding (Red audit F3)
verifyJWS dispatched on the JWS header alg, then handed off to the
shared verifySignature helper which dispatched on the public-key type.
A token forged with header alg=EdDSA against a trust root that holds
an *rsa.PublicKey for the same kid would: (1) take the EdDSA branch
in verifyJWS, (2) call verifySignature(rsaPub, signedInput, sig),
(3) hit the *rsa.PublicKey case and run RSA-PSS over attacker-chosen
signedInput, (4) accept whatever sig forged. Classic CVE-2015-9235
algorithm-substitution shape.

Fix: the JWS path no longer routes through verifySignature. Each alg
arm in verifyJWS asserts the trust-root key type before any
verification primitive runs; for ECDSA the curve is also bound to
the alg (ES256→P-256, ES384→P-384). alg=none (any case) and unknown
algs are refused with explicit sentinels.

The companion verifySignature in rim.go is intentionally retained
for the RIM detached-signature path: RIM has no alg envelope, so
key-type dispatch is the only correct choice there. Splitting the
two paths is the only correct factoring; merging them re-introduces
this attack.

Sentinels:
  ErrAlgKeyTypeMismatch — alg announced does not match key type
  ErrAlgNoneRefused     — alg=none rejected unconditionally
  ErrUnknownAlg         — alg not recognized

Algs supported: EdDSA, ES256, ES384, PS256, PS384.

Tests (8/8 PASS, -race clean):
  TestVerifyJWS_EdDSA_Valid
  TestVerifyJWS_ES256_Valid
  TestVerifyJWS_PS256_Valid
  TestVerifyJWS_EdDSA_AgainstRSAPub_Rejected   (the substitution attack)
  TestVerifyJWS_ES256_AgainstEd25519Pub_Rejected
  TestVerifyJWS_ES256_AgainstP384Pub_Rejected  (curve mismatch)
  TestVerifyJWS_AlgNone_Refused
  TestVerifyJWS_UnknownAlg_Refused

Pre-existing nvidia package tests (RIM ed25519/ECDSA/RSA-PSS, NRAS
ES256 happy path, etc.) continue to pass.

LOC delta: nras_client.go +107/-65, nras_jws_test.go +178/-0.
2025-12-28 17:40:08 -08:00
zeekay 1996f1adc4 v0.61+v0.62: scheduler trust gate + NVIDIA attestation primitives
v0.61 — wire the scheduler workload-policy gate into the MPC SignGate.
SignGate gains optional Scheduler + Worker fields; AuthorizeSign now
runs scheduler.Eligible(worker, ci.PolicyID) BEFORE the policy
verifier and short-circuits on insufficient trust posture. Existing
callers that pass nil Scheduler are unaffected.

  pkg/scheduler/policy_gate.go     — TrustMode/IOLevel enums,
                                     WorkloadPolicy.Eligible(Worker)
  pkg/scheduler/service_drain.go   — AuthorizeDrain + AuthorizeSession
  pkg/mpc/sign_orchestrator.go     — Scheduler/Worker fields,
                                     WithScheduler(...), two-stage gate

v0.62 — NVIDIA Confidential-Compute attestation primitives. Clean-room
parsers + verifiers against the publicly documented nvTrust schema
(Apache-2 derived); no NVIDIA proprietary code vendored.

  pkg/attestation/nvidia/gpu_report.go   — GPU evidence-report parser
  pkg/attestation/nvidia/nras_client.go  — NRAS HTTP client + JWS verify
  pkg/attestation/nvidia/rim.go          — RIM signature + value match
  pkg/attestation/nvidia/composite.go    — VerifiedBundle (CPU+GPU bind)

Tests (57 passing, -race clean):
  pkg/scheduler                        — 11 (truth-table, drain,
                                          session, orchestrator
                                          integration)
  pkg/attestation/nvidia               — 46 (parser, RIM Ed25519/ECDSA/
                                          RSA-PSS, NRAS happy/error/
                                          signature paths, ECDSA JOSE)
  pkg/attestation/nvidia (hwattest)    — 3, env-skipped without real GPU

Sibling v0.60 reconciliation: pkg/registry + pkg/attestation already
land WorkerCapability + CompositeAttestation envelope using lattice
trust types. nvidia.VerifiedBundle is renamed (was Composite-) to
avoid collision with pkg/attestation.CompositeAttestation; the
canonical envelope wraps the verified blobs this package emits.

Residual: lattice/v7/types is not yet published, so pkg/registry +
pkg/attestation cannot compile against luxfi/[email protected]; the
sibling v0.60 work tracks that. pkg/policy still has a pre-existing
unresolved import of luxfi/fhe/threshold (should be /pkg/threshold);
sign_orchestrator_scheduler_test.go is ready to run as soon as that
upstream issue is fixed by its owner.
2025-12-28 16:53:46 -08:00
zeekay 5403f97d6d feat(registry,attestation): trust + capability registry foundation
Build the GPU-runtime trust registry that gates every dispatch decision
against typed capability records and a deterministic attestation root.

Reference: LP-137-TRUST-REGISTRY.md.

pkg/registry:
  - types.go: WorkerCapability, NodeCapability, GPUArch, GPUBackend,
    PeerInterconnect with Validate() that enforces TEE-arch + attestation
    invariants at the API edge.
  - policy.go: LanePolicy (operator-controlled), WorkloadPolicy
    (per-request), and a single canonical Eligible(lane, workload, worker)
    check that runs twelve gates in fixed order. Privacy-class consistency
    is re-checked on the hot path so a stale worker record cannot bypass
    the API edge.

pkg/attestation:
  - composite.go: CompositeAttestation envelope over CPU TEE + GPU TEE +
    platform evidence. Root() is RFC 8949 §4.2 deterministic CBOR via
    fxamacker/cbor (already a direct dep) followed by SHA-256. The same
    encoder is used by Marshal so Root and the wire form agree byte-for-
    byte. Validate() rejects malformed envelopes including
    composite-trust-without-GPU-evidence.

Tests (103 pass): truth-table eligibility coverage, gate-ordering
regression, sensitivity-to-every-field digest, deterministic-bytes
round-trip, garbage-decode rejection.

go.mod: promote luxfi/lattice/v7 from indirect to direct require, add
local replace pointing at ../lattice (mirrors the existing fhe pattern).
Drop the replace once luxfi/lattice publishes a tag containing
types/trust.go.
2025-12-28 16:47:09 -08:00