From 9718d8775a84881d18bc977c117c94a42578cf3d Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Sat, 19 Sep 2026 21:49:46 -0700 Subject: [PATCH 1/2] docs(verifier): say what event_log_verified actually covers The field documented itself as verifying RTMR 0-2 digests "through replay comparison with the quote". Nothing in dstack-verifier or dstack-attest replays a boot-time event log: the flag is set once the runtime event log replays to its register and the app identity decodes out of its payloads. A TDX quote's RTMR 0-2 entries reach only the `--debug` diff and the three named ACPI digests the lite path cross-checks. Correct the comment rather than the code. Replaying RTMR 0-2 would add nothing: those registers are already checked against measurements recomputed from the OS image, which does not trust the host's event log at all, and is the stronger of the two checks. --- dstack/verifier/README.md | 4 ++-- dstack/verifier/src/types.rs | 20 ++++++++++++++------ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/dstack/verifier/README.md b/dstack/verifier/README.md index 8529dc1f6..40db89e34 100644 --- a/dstack/verifier/README.md +++ b/dstack/verifier/README.md @@ -35,7 +35,7 @@ against the returned evidence. "is_valid": true, "details": { "quote_verified": true, - "event_log_verified": true, // See "Verification Process" for semantics + "event_log_verified": true, // runtime event log only; see "Verification Process" "os_image_hash_verified": true, "acpi_tables_verified": true, // true only when TDX ACPI table contents are verified "os_image_is_dev": false, // true=dev image, false=prod, null=unknown/N/A @@ -237,7 +237,7 @@ $ curl -s -d @quote.json localhost:8080/verify | jq The verifier performs the following verification steps: 1. **Quote Verification**: Validates the platform quote using the platform verifier: DCAP for TDX, AMD SNP report verification for SEV-SNP, NSM for Nitro Enclaves, and AWS NitroTPM attestation-document verification for EC2 NitroTPM. -2. **Event Log Verification**: Replays event logs to ensure RTMR/PCR values match and extracts app information. For RTMR3 and AWS NitroTPM PCR14 launch measurements, both the digest and payload integrity are verified. For TDX RTMR 0-2 boot-time measurements, only the digests are verified; the payload content is not validated as dstack does not define semantics for these payloads. +2. **Event Log Verification**: Replays the runtime event log — RTMR3 on TDX, the corresponding launch measurement on SEV-SNP and AWS NitroTPM PCR14 — to ensure it reproduces the quoted register, and extracts app information from its payloads. Both the digests and the payloads are verified there, because `app_id`, `compose_hash` and the rest are read out of them. `event_log_verified` reports that step only. The boot-time event log a TDX quote carries is not replayed: RTMR 0-2 are verified in step 3 by comparing the quoted values against measurements recomputed from the OS image, which does not depend on the host's event log, and dstack defines no semantics for its payloads. 3. **OS Image Hash Verification**: - Treats `vm_config` and any attached measurement material as untrusted inputs until they are bound to the hardware quote - For the full-image TDX path, downloads or loads the image identified by `os_image_hash`, checks the image checksum manifest, uses dstack-mr to compute expected MRTD/RTMR0-2, and compares them against the verified measurements from the quote diff --git a/dstack/verifier/src/types.rs b/dstack/verifier/src/types.rs index d9d71442b..031e692ac 100644 --- a/dstack/verifier/src/types.rs +++ b/dstack/verifier/src/types.rs @@ -79,13 +79,21 @@ impl PolicyBootInfo { #[derive(Debug, Clone, Default, Serialize)] pub struct VerificationDetails { pub quote_verified: bool, - /// Indicates that the event log was verified against the quote. + /// Indicates that the runtime event log was replayed against the quote and + /// the app identity was decoded from it. /// - /// For RTMR3 (runtime measurements), both the digest and payload integrity are verified - /// by replaying the event log and comparing against the quote. For RTMR 0-2 (boot-time - /// measurements), only the digests are verified through replay comparison with the quote; - /// the payload content is not validated. dstack does not define semantics for RTMR 0-2 - /// event log payloads. + /// That is RTMR3 on TDX, and the corresponding launch PCR on SEV-SNP and + /// AWS NitroTPM: both the digests and the payloads are verified, because + /// `app_id`, `compose_hash` and the rest are read out of those payloads. + /// + /// It says nothing about the boot-time event log. Nothing replays the + /// RTMR 0-2 entries a TDX quote carries, and that is deliberate: those + /// registers are verified by comparing the quoted values against + /// measurements recomputed from the OS image (see `os_image_hash_verified` + /// and `acpi_tables_verified`), which does not depend on the host's event + /// log at all. The boot event log is carried for diagnostics -- the + /// `--debug` RTMR diff and the three named ACPI digests the TDX lite path + /// cross-checks -- and dstack defines no semantics for its payloads. pub event_log_verified: bool, pub os_image_hash_verified: bool, /// Indicates that TDX ACPI table contents were verified. From 33a742d319ec7c5d1fc75bbbfa9dbaeec37fcd0e Mon Sep 17 00:00:00 2001 From: Kevin Wang Date: Tue, 22 Sep 2026 23:38:16 -0700 Subject: [PATCH 2/2] docs(verifier): correct per-platform event_log_verified semantics SEV-SNP has no runtime event log (identity comes from mr_config via HOST_DATA), Nitro Enclave and GCP TDX were missing, and the replay runs during quote verification, so a mismatch fails quote_verified. The --debug diff does not read event log entries, and the lite ACPI digest check is fatal rather than diagnostic. --- dstack/verifier/README.md | 4 ++-- dstack/verifier/src/types.rs | 30 +++++++++++++++++------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/dstack/verifier/README.md b/dstack/verifier/README.md index 40db89e34..4572e4daf 100644 --- a/dstack/verifier/README.md +++ b/dstack/verifier/README.md @@ -35,7 +35,7 @@ against the returned evidence. "is_valid": true, "details": { "quote_verified": true, - "event_log_verified": true, // runtime event log only; see "Verification Process" + "event_log_verified": true, // app identity decoded; see "Verification Process" "os_image_hash_verified": true, "acpi_tables_verified": true, // true only when TDX ACPI table contents are verified "os_image_is_dev": false, // true=dev image, false=prod, null=unknown/N/A @@ -237,7 +237,7 @@ $ curl -s -d @quote.json localhost:8080/verify | jq The verifier performs the following verification steps: 1. **Quote Verification**: Validates the platform quote using the platform verifier: DCAP for TDX, AMD SNP report verification for SEV-SNP, NSM for Nitro Enclaves, and AWS NitroTPM attestation-document verification for EC2 NitroTPM. -2. **Event Log Verification**: Replays the runtime event log — RTMR3 on TDX, the corresponding launch measurement on SEV-SNP and AWS NitroTPM PCR14 — to ensure it reproduces the quoted register, and extracts app information from its payloads. Both the digests and the payloads are verified there, because `app_id`, `compose_hash` and the rest are read out of them. `event_log_verified` reports that step only. The boot-time event log a TDX quote carries is not replayed: RTMR 0-2 are verified in step 3 by comparing the quoted values against measurements recomputed from the OS image, which does not depend on the host's event log, and dstack defines no semantics for its payloads. +2. **Event Log Verification**: Decodes app information (`app_id`, `compose_hash`, ...) from evidence bound to the quote and reports it as `event_log_verified`. On dstack TDX, GCP TDX and AWS NitroTPM it is read from the runtime event log, whose digests and payloads step 1 already replayed against the quoted register (RTMR3, plus TPM PCR14 on GCP; PCR14 on NitroTPM), so a replay mismatch fails quote verification. SEV-SNP has no runtime event log and takes it from `mr_config`, bound through HOST_DATA; Nitro Enclaves derive it from the PCRs. The RTMR 0-2 entries of a TDX event log are not replayed: on dstack TDX those registers are verified in step 3 against measurements recomputed from the OS image, which does not depend on the host's event log, and dstack defines no semantics for their payloads. 3. **OS Image Hash Verification**: - Treats `vm_config` and any attached measurement material as untrusted inputs until they are bound to the hardware quote - For the full-image TDX path, downloads or loads the image identified by `os_image_hash`, checks the image checksum manifest, uses dstack-mr to compute expected MRTD/RTMR0-2, and compares them against the verified measurements from the quote diff --git a/dstack/verifier/src/types.rs b/dstack/verifier/src/types.rs index 031e692ac..5d37d9e15 100644 --- a/dstack/verifier/src/types.rs +++ b/dstack/verifier/src/types.rs @@ -79,21 +79,25 @@ impl PolicyBootInfo { #[derive(Debug, Clone, Default, Serialize)] pub struct VerificationDetails { pub quote_verified: bool, - /// Indicates that the runtime event log was replayed against the quote and - /// the app identity was decoded from it. + /// Indicates that the app identity was decoded from evidence bound to the + /// quote. /// - /// That is RTMR3 on TDX, and the corresponding launch PCR on SEV-SNP and - /// AWS NitroTPM: both the digests and the payloads are verified, because - /// `app_id`, `compose_hash` and the rest are read out of those payloads. + /// On dstack TDX, GCP TDX and AWS NitroTPM that evidence is the runtime + /// event log, already replayed during quote verification against RTMR3 + /// (plus TPM PCR14 on GCP) or PCR14 on NitroTPM, so a replay mismatch fails + /// `quote_verified` rather than this flag. Digests and payloads are both + /// covered, because `app_id`, `compose_hash` and the rest are read out of + /// the payloads. SEV-SNP has no runtime event log and takes the identity + /// from `mr_config`, bound through HOST_DATA; Nitro Enclave derives it from + /// the PCRs. /// - /// It says nothing about the boot-time event log. Nothing replays the - /// RTMR 0-2 entries a TDX quote carries, and that is deliberate: those - /// registers are verified by comparing the quoted values against - /// measurements recomputed from the OS image (see `os_image_hash_verified` - /// and `acpi_tables_verified`), which does not depend on the host's event - /// log at all. The boot event log is carried for diagnostics -- the - /// `--debug` RTMR diff and the three named ACPI digests the TDX lite path - /// cross-checks -- and dstack defines no semantics for its payloads. + /// It says nothing about the RTMR 0-2 entries a TDX event log carries; + /// nothing replays them. On dstack TDX those registers are verified by + /// comparing the quoted values against measurements recomputed from the OS + /// image (see `os_image_hash_verified`), which does not depend on the + /// host's event log. The TDX lite path only reads the three named ACPI + /// digests from it and requires them to match the recomputed ones; dstack + /// defines no semantics for the other payloads. pub event_log_verified: bool, pub os_image_hash_verified: bool, /// Indicates that TDX ACPI table contents were verified.