feat(attestation)!: pin verification to archived collateral with VerifyMode - #93
Open
samlaf wants to merge 1 commit into
Open
feat(attestation)!: pin verification to archived collateral with VerifyMode#93samlaf wants to merge 1 commit into
samlaf wants to merge 1 commit into
Conversation
…fyMode Closes flashbots#84 Second of two changes for that issue, on top of flashbots#85. Reporting the endorsements a verification consumed is half of provenance. The other half is running the same verification again later, against that snapshot, and getting the same answer. Nothing exposed that: the public entry points always fetched and always read the wall clock, and the only way to supply a bundle was through variants that also took a bare timestamp. API before and after -------------------- AttestationVerifier verify_attestation(msg, input) -> verify_attestation(msg, input, mode) verify_attestation_sync(msg, input) -> verify_attestation_sync(msg, input, mode) dcap verify_dcap_attestation(q, input, pccs) -> verify_dcap_attestation(q, input, mode, pccs) verify_dcap_attestation_sync(q, input, pccs) -> verify_dcap_attestation_sync(q, input, mode, pccs) verify_dcap_attestation_with_given_timestamp( q, input, pccs, Option<collateral>, now, override_azure_outdated_tcb) -> (removed) verify_dcap_attestation_with_timestamp_sync( q, input, pccs, Option<collateral>, now, override_azure_outdated_tcb) -> (removed) azure verify_azure_attestation(a, input, pccs, override) -> verify_azure_attestation(a, input, mode, pccs, override) verify_azure_attestation_sync(a, input, pccs, override) -> verify_azure_attestation_sync(a, input, mode, pccs, override) new enum VerifyMode { Live, Archived(EndorsementSnapshot) } DcapVerificationError::ArchivedWithoutDcapCollateral Why this shape -------------- One input instead of two. The removed variants took the collateral and the instant as separate arguments, so a caller could pair a pinned bundle with the wrong instant, or a live fetch with a pinned instant, and get a verdict that reproduces nothing. VerifyMode::Archived takes the EndorsementSnapshot that flashbots#85 hands back, so the bundle and the instant it was held to travel together and the mistake has no spelling. The mixed case is refused too: an archived snapshot with no bundle for the DCAP leg fails with ArchivedWithoutDcapCollateral rather than being completed by a fetch. The mode reaches the verifier. The measurement-policy check lives on AttestationVerifier, and a relying party re-checking archived evidence needs both it and the pinned instant. The removed variants sat below the verifier, so that combination did not exist. The mode is a parameter of the call rather than the builder because it is a fact about one verification, not about the verifier: the same instance serves a live handshake and an archive replay. One instant for both Azure legs. The DCAP leg reports the instant it evaluated at, and the vTPM AK chain is checked at that same instant, in either mode. The wall clock is read in exactly one place. The Azure TCB override leaves the public surface. It rode along on the removed variants only because the Azure verifier and the fixture tests shared them. Both now call the crate-private body that the two public entry points wrap, so the override is an argument of the Azure leg and nothing else. Only Azure has a reason to relax TCB checks. Live is behaviour-preserving. Every existing caller passes VerifyMode::Live and gets what it got before: collateral from the PCCS or Intel, freshness at the wall clock. The two in-tree callers, attested-tls and attestation-provider-server, needed only that argument. GCP checks and Archived mode ---------------------------- The GCP host provenance check from flashbots#54 stays live in either mode, as does the firmware fetch for the quote's MRTD. Neither rests on signed material a replay could re-verify: the provenance document is an unsigned JSON object whose trust is the TLS connection to Google's bucket, so archiving it would not make a replay stronger. The docs on VerifyMode::Archived and verify_attestation state the carve-out. Whether Archived should skip the provenance lookup instead is left open. BREAKING CHANGE: verify_attestation and verify_attestation_sync take a VerifyMode; the DCAP and Azure entry points take mode before pccs; the *_with_given_timestamp variants are gone, replaced by VerifyMode::Archived, which fails with DcapVerificationError::ArchivedWithoutDcapCollateral when its snapshot carries no DCAP bundle.
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.
Closes #84. Second of two changes for that issue, on top of #85.
This finalizes the feature that I actually needed to re-verify archived quotes. Made some small cleanups to the function names and architecture (for example passing a QuoteVerifier to verifyQuote) at the same time, lmkwyt.
LLM Summary
Reporting the endorsements a verification consumed is half of provenance. The other half is running the same verification again later, against that snapshot, and getting the same answer. Nothing exposed that: the public entry points always fetched and always read the wall clock, and the only way to supply a bundle was through variants that also took a bare timestamp.
API before and after
Why this shape
One input instead of two. The removed variants took the collateral and the instant as separate arguments, so a caller could pair a pinned bundle with the wrong instant, or a live fetch with a pinned instant, and get a verdict that reproduces nothing. VerifyMode::Archived takes the EndorsementSnapshot that #85 hands back, so the bundle and the instant it was held to travel together and the mistake has no spelling. The mixed case is refused too: an archived snapshot with no bundle for the DCAP leg fails with ArchivedWithoutDcapCollateral rather than being completed by a fetch.
The mode reaches the verifier. The measurement-policy check lives on AttestationVerifier, and a relying party re-checking archived evidence needs both it and the pinned instant. The removed variants sat below the verifier, so that combination did not exist. The mode is a parameter of the call rather than the builder because it is a fact about one verification, not about the verifier: the same instance serves a live handshake and an archive replay.
One instant for both Azure legs. The DCAP leg reports the instant it evaluated at, and the vTPM AK chain is checked at that same instant, in either mode. The wall clock is read in exactly one place.
The Azure TCB override leaves the public surface. It rode along on the removed variants only because the Azure verifier and the fixture tests shared them. Both now call the crate-private body that the two public entry points wrap, so the override is an argument of the Azure leg and nothing else. Only Azure has a reason to relax TCB checks.
Live is behaviour-preserving. Every existing caller passes VerifyMode::Live and gets what it got before: collateral from the PCCS or Intel, freshness at the wall clock. The two in-tree callers, attested-tls and attestation-provider-server, needed only that argument.
GCP checks and Archived mode
The GCP host provenance check from #54 stays live in either mode, as does the firmware fetch for the quote's MRTD. Neither rests on signed material a replay could re-verify: the provenance document is an unsigned JSON object whose trust is the TLS connection to Google's bucket, so archiving it would not make a replay stronger. The docs on VerifyMode::Archived and verify_attestation state the carve-out. Whether Archived should skip the provenance lookup instead is left open.
BREAKING CHANGE: verify_attestation and verify_attestation_sync take a VerifyMode; the DCAP and Azure entry points take mode before pccs; the *_with_given_timestamp variants are gone, replaced by VerifyMode::Archived, which fails with
DcapVerificationError::ArchivedWithoutDcapCollateral when its snapshot carries no DCAP bundle.