Skip to content

[Guardian] Verify Nitro enclave attestation + pin PCR0#666

Open
mskd12 wants to merge 11 commits into
mainfrom
deepakmaram/guardian-attestation-verify
Open

[Guardian] Verify Nitro enclave attestation + pin PCR0#666
mskd12 wants to merge 11 commits into
mainfrom
deepakmaram/guardian-attestation-verify

Conversation

@mskd12

@mskd12 mskd12 commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

What

Turns verify_enclave_attestation from a no-op stub into real AWS Nitro attestation verification, and threads an expected PCR0 measurement through every consumer that reads guardian S3 state.

Why

A guardian publishes an attestation document alongside its session signing key. Until now we trusted that key blindly. This change makes any reader (KP provisioner-init, hashi monitor/auditor) cryptographically verify, on first use of each session, that:

  • the attestation's COSE signature chains to the AWS Nitro root and is fresh;
  • the document commits to the same signing key we're about to trust (doc.public_key == signing_pub_key);
  • the enclave image matches an operator-pinned measurement (PCR0).

How

  • verify_enclave_attestation(attestation, signing_pubkey, build_pcrs) (hashi-types): parses + verifies via fastcrypto::nitro_attestation, binds the signing key, and pins PCR0. parse_nitro_attestation(.., true, true, true) keeps PCR0 in pcr_map even if zero so the pin can't be bypassed by a missing entry.
  • BuildPcrs — known-good measurement an attestation is pinned to. Construction mandates PCR0. Records only PCR0 because in a StageX reproducible single-binary build it's the only measurement carrying signal. Follow-up (noted in TODO(check C)): a commit -> BuildPcrs allowlist keyed on untrusted_git_revision, to span all the valid images during an upgrade.
  • Threading: GuardianReader / GuardianSessionKeyCache / get_verified_enclave_pubkey / GetGuardianInfoResponse::verify all take build_pcrs; provisioner and monitor configs gain expected_pcr0 (hex).
  • non-enclave-dev feature (hashi-types, mirrored from hashi-guardian): stubs verification to a no-op so off-enclave e2e/dev consumers accept the mock document the guardian emits outside an enclave. Never enabled in prod.
  • fastcrypto pinned to merged main ecbf72b (the AWS Nitro module, fastcrypto #971).

Notes for reviewers

  • Sample-config expected_pcr0 values are all-zero placeholders; real PCR0s are filled in at provisioning from the reproducible build.
  • Real verification only runs in enclave (prod) builds; CI/dev exercise the non-enclave-dev / test stub path.

mskd12 and others added 2 commits June 5, 2026 19:10
…ey anchor)

`verify_enclave_attestation` now actually verifies the AWS Nitro attestation via
fastcrypto's `nitro_attestation` module instead of being a no-op:

- parse + verify the COSE_Sign1 signature and the X.509 cert chain to the AWS
  Nitro root, freshness checked against now (ms).
- anchor the document's `public_key` to the session signing pubkey — the enclave
  binds its signing key into the attestation.

Gated behind `non-enclave-dev` (+ cfg(test)) so off-enclave/dev/e2e builds, which
run a mock enclave, accept the stub document; the feature propagates from
hashi-guardian's existing `non-enclave-dev`. Pins fastcrypto to the
`nitro-attestation` branch.

TODO(check C): pin the document's PCRs against an expected set.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`ExpectedPcrs` mandates PCR0 at construction (`ExpectedPcrs::new`), and is
threaded from config to `verify_enclave_attestation`, which pins the
attestation's PCR0 (the EIF image hash) after the COSE/cert/pubkey checks:

- source -> sink: an `expected_pcr0` config field -> `GuardianReader::new` ->
  `GuardianSessionKeyCache` -> `get_verified_enclave_pubkey`, plus
  `GetGuardianInfoResponse::verify(&ExpectedPcrs)` for the relay path.
- Both the provisioner (`ProvisionerConfig`) and the monitor auditor
  (`hashi-monitor` `Config`) supply `expected_pcr0`; sample YAMLs + README updated.

A single mandatory PCR0 for now; accepting multiple measurements during a
software upgrade is a follow-up (TODO on `ExpectedPcrs`).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mskd12 mskd12 force-pushed the deepakmaram/guardian-attestation-verify branch from 0e8ac5e to 293abf5 Compare June 6, 2026 06:06
@mskd12 mskd12 changed the title [Guardian] Verify Nitro enclave attestation + pin PCRs [Guardian] Verify Nitro enclave attestation + pin PCR0 Jun 6, 2026
mskd12 and others added 5 commits June 9, 2026 15:17
- Drop needless `return` in verify_enclave_attestation dev stub (clippy).
- Add expected_pcr0 to the two hashi-monitor test Config literals.
- Commit the hex Cargo.lock entry for hashi-monitor (docs is-dirty).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…attestation-verify

# Conflicts:
#	crates/hashi-guardian-init/src/provisioner.rs
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A build's measurement set is the durable concept; the future commit->PCRs
allowlist will be a separate type keyed on untrusted_git_revision.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mskd12 mskd12 marked this pull request as ready for review June 9, 2026 23:07
@mskd12 mskd12 requested a review from bmwill as a code owner June 9, 2026 23:07
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
mskd12 and others added 3 commits June 17, 2026 17:32
The AWS Nitro attestation module (fastcrypto #971) merged to main, so pin
to main HEAD instead of the nitro-attestation branch tip. Drop the now-stale
no-op TODO on get_verified_enclave_pubkey: it takes build_pcrs and binds the
logged signing key to the attestation's public_key.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Main's tip (ecbf72b) carries a breaking AVSS rework (fastcrypto #954, #974)
the MPC code isn't migrated to, so the merged nitro module can't be taken
from main yet. Pin to the nitro-attestation branch tip (our prior base +
the nitro module) and TODO moving to a main rev once #954/#974 are adopted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0xsiddharthks added a commit that referenced this pull request Jun 18, 2026
Replace the node's on-chain ephemeral-key pin with attestation. The committee
node builds a PcrAllowlist from the on-chain guardian build (the PCR0 anchor
from the parent PR) and calls GetGuardianInfoResponse::verify, which checks the
signed_info signature and pins the live attestation's PCR0. A guardian that
reboots with a fresh ephemeral key is now trusted because attestation vouches
for it — no on-chain key pin to go stale. Falls back to a signature-only check
when no build is pinned on-chain yet; the BTC 2-of-2 still gates funds. The
non-enclave-dev feature stubs the attestation leg to a no-op off-enclave
(dev/e2e), where only the signature is enforced.

Deletes the now-dead verify_guardian_signing_pubkey / verify_signing_pub_key_matches
and their tests; keeps the BTC-key pin and verify_guardian_signed_info.

Adds a CARGO_FEATURES build arg to docker/hashi/Containerfile (empty default =
prod-safe) so the dev node image can be built with non-enclave-dev; the
devnet build opts in (sui-operations, separate PR). A prod node image builds
without it, enforcing real attestation.

Depends on #666 + #675 (PcrAllowlist + verify + the hashi-types non-enclave-dev
feature); does not compile until those land on main. Will rebase + compile-verify
once they merge.
/// Expected enclave-image measurement: PCR0 as hex, pinned against every
/// session's attestation. Required (a value is needed even in non-Nitro dev,
/// where verification is a no-op).
pub expected_pcr0: String,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not BuildPcrs?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants