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.
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.
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.