feat(attestation-service): serve evidence for the operator's deploy verification - #259
Merged
samlaf merged 1 commit intoAug 19, 2026
Conversation
…erification Fixes SEI-181 An operator who has just provisioned a node holds only a liveness signal: :7878 opened. Everything they do next — publishing the node's address, handing it to later nodes as a bootnode — trusts that the endpoint is their node, and nothing yet proves it. A recycled IP, a clone, or a node booted with the wrong manifest all pass a port check, and the one evidence RPC already served is no help here: tx-io evidence is a deliberately timeless, cacheable document, so a replayed copy of it verifies perfectly at an impostor endpoint. getDeployVerificationEvidence upgrades the signal to an attested one. The caller sends a fresh deployment_nonce; the service derives deploy_verification_binding(network_id, deployment_nonce) from its own manifest-derived identity and quotes over it. The verifier recomputes the binding from its own manifest copy and the nonce it sent, then verifies the envelope against its measurement policy. A passing quote proves a measured node holding the expected manifest minted evidence for this exact request. The caller contributes freshness and nothing else, so the method cannot be used as an oracle to quote transcripts of the caller's choosing. The binding helper existed, tested but unused, as deploy_preflight_binding(network_id, nonce, context). Both halves of that name change here. The context tail is dropped: this RPC is its only caller, the question it answers is fixed, and a future flow that needs to bind something else gets its own domain string rather than a context value — separate domains are what keep an answer to one question from passing as an answer to another. The digest is unchanged by the removal (SHA256(x || "") is SHA256(x)); the pinned vector moves only because the old one exercised a non-empty context. "Verification" replaces "preflight" because the check can only succeed after the node is fully up — a joiner binds :7878 only once the root-key handshake has completed — so what it precedes is the operator's reliance, not the node's flight. Membership itself is granted by that handshake and its admission policy, never by this check; the RPC guards the operator's own decisions. The live-TEE suite gains test_deploy_verification_relying_party: the verifier's full path against a genesis pair, and rejection of the same evidence against another request's nonce and against another network's identity. The deploy-side verifier that consumes this is SEI-183.
samlaf
deleted the
sl/sei-181-feat-deploy-preflight-attestation-evidence-rpc
branch
August 19, 2026 17:34
samlaf
added a commit
to SeismicSystems/seismic
that referenced
this pull request
Aug 19, 2026
Part of SEI-181. Related to SeismicSystems/enclave#259 The attestation service's binding list gains getDeployVerificationEvidence(deployment_nonce), answering with deploy_verification_binding(network_id, deployment_nonce): the caller contributes only freshness. The deploy-verification paragraph now also states the check's boundary — it guards the operator's own decisions (publishing the node's address, handing it to later nodes as a bootnode); membership is granted by the attested root-key handshake and its admission policy, never by this check.
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.
Fixes SEI-181
An operator who has just provisioned a node holds only a liveness signal: :7878 opened. Everything they do next — publishing the node's address, handing it to later nodes as a bootnode — trusts that the endpoint is their node, and nothing yet proves it. A recycled IP, a clone, or a node booted with the wrong manifest all pass a port check, and the one evidence RPC already served is no help here: tx-io evidence is a deliberately timeless, cacheable document, so a replayed copy of it verifies perfectly at an impostor endpoint.
getDeployVerificationEvidence upgrades the signal to an attested one. The caller sends a fresh deployment_nonce; the service derives deploy_verification_binding(network_id, deployment_nonce) from its own manifest-derived identity and quotes over it. The verifier recomputes the binding from its own manifest copy and the nonce it sent, then verifies the envelope against its measurement policy. A passing quote proves a measured node holding the expected manifest minted evidence for this exact request. The caller contributes freshness and nothing else, so the method cannot be used as an oracle to quote transcripts of the caller's choosing.
The binding helper existed, tested but unused, as
deploy_preflight_binding(network_id, nonce, context). Both halves of that name change here. The context tail is dropped: this RPC is its only caller, the question it answers is fixed, and a future flow that needs to bind something else gets its own domain string rather than a context value — separate domains are what keep an answer to one question from passing as an answer to another. The digest is unchanged by the removal (SHA256(x || "") is SHA256(x)); the pinned vector moves only because the old one exercised a non-empty context. "Verification" replaces "preflight" because the check can only succeed after the node is fully up — a joiner binds :7878 only once the root-key handshake has completed — so what it precedes is the operator's reliance, not the node's flight. Membership itself is granted by that handshake and its admission policy, never by this check; the RPC guards the operator's own decisions.
The live-TEE suite gains test_deploy_verification_relying_party: the verifier's full path against a genesis pair, and rejection of the same evidence against another request's nonce and against another network's identity.
The deploy-side verifier that consumes this is SEI-183.