Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions verifier/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ or
"os_image_hash_verified": true,
"os_image_is_dev": false, // true=dev image, false=prod, null=unknown/N/A
"os_image_version": "0.5.10", // dstack OS version, null if unknown
"tee_platform": "tdx", // tdx | gcp-tdx | nitro
"attestation_mode": "dstack-tdx", // dstack-tdx | dstack-gcp-tdx | dstack-nitro-enclave | dstack-amd-sev-snp
"report_data": "hex-encoded-64-byte-report-data",
"tcb_status": "UpToDate",
"advisory_ids": [],
Expand Down Expand Up @@ -196,7 +196,7 @@ Beyond pass/fail, the result carries a few descriptive fields so a relying party

- **`os_image_is_dev`** — `true` for a development OS image, `false` for production. Dev images are built for local testing and are not hardened for production use, so a relying party generally wants to reject them.
- **`os_image_version`** — the dstack OS version (e.g. `0.5.10`), useful for enforcing a minimum version.
- **`tee_platform`** — which TEE produced the verified quote: `tdx`, `gcp-tdx`, or `nitro`.
- **`attestation_mode`** — the attestation mode that produced the verified quote, serialized as `AttestationMode`: `dstack-tdx`, `dstack-gcp-tdx`, `dstack-nitro-enclave`, or `dstack-amd-sev-snp`.
- **`key_provider`** — the decoded `app_info.key_provider_info` (`{name, id}`); `name` is e.g. `kms` or `local`. A `local` key provider means the CVM is not KMS-backed, which is itself a dev/insecure posture signal. The raw bytes remain in `app_info.key_provider_info`.

`os_image_is_dev` and `os_image_version` are read from the image's `metadata.json`, which is part of `sha256sum.txt` and therefore bound to the `os_image_hash` that step 3 verifies against the quote — so they are as trustworthy as the os-image-hash check itself. They are `null` when the platform does not expose them (e.g. GCP TDX / Nitro Enclave) or when the image predates the field (images without `is_dev` are always production).
6 changes: 3 additions & 3 deletions verifier/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0

use dstack_types::KeyProviderInfo;
use ra_tls::attestation::AppInfo;
use ra_tls::attestation::{AppInfo, AttestationMode};
use serde::{Deserialize, Serialize};

use serde_human_bytes as serde_bytes;
Expand Down Expand Up @@ -45,8 +45,8 @@ pub struct VerificationDetails {
pub os_image_is_dev: Option<bool>,
/// dstack OS version, from the same metadata.json.
pub os_image_version: Option<String>,
/// "tdx" | "gcp-tdx" | "nitro".
pub tee_platform: Option<String>,
/// Attestation mode that produced the verified quote.
pub attestation_mode: Option<AttestationMode>,
pub report_data: Option<String>,
pub tcb_status: Option<String>,
pub advisory_ids: Vec<String>,
Expand Down
21 changes: 9 additions & 12 deletions verifier/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,6 @@ use crate::types::{
VerificationRequest, VerificationResponse,
};

fn tee_platform_name(quote: &AttestationQuote) -> &'static str {
match quote {
AttestationQuote::DstackTdx(_) => "tdx",
AttestationQuote::DstackGcpTdx(_) => "gcp-tdx",
AttestationQuote::DstackNitroEnclave(_) => "nitro",
AttestationQuote::DstackAmdSevSnp(_) => "sev-snp",
}
}

/// best-effort: None for empty/malformed blobs.
fn decode_key_provider_info(bytes: &[u8]) -> Option<dstack_types::KeyProviderInfo> {
if bytes.is_empty() {
Expand Down Expand Up @@ -560,7 +551,7 @@ impl CvmVerifier {
let verified_attestation = match verified {
Ok(att) => {
details.quote_verified = true;
details.tee_platform = Some(tee_platform_name(&att.quote).to_string());
details.attestation_mode = Some(att.quote.mode());
details.tcb_status = att.report.tdx_report().map(|r| r.status.clone());
details.advisory_ids = att
.report
Expand Down Expand Up @@ -1273,7 +1264,10 @@ mod tests {
assert!(response.details.quote_verified);
assert!(response.details.event_log_verified);
assert!(response.details.os_image_hash_verified);
assert_eq!(response.details.tee_platform.as_deref(), Some("sev-snp"));
assert_eq!(
response.details.attestation_mode,
Some(ra_tls::attestation::AttestationMode::DstackAmdSevSnp)
);
assert!(
!image_cache_dir.exists(),
"SNP verification must not download or cache OS images"
Expand All @@ -1298,6 +1292,9 @@ mod tests {

let response = verifier.verify(request).await.expect("verifier runs");
assert!(response.is_valid, "{:?}", response.reason);
assert_eq!(response.details.tee_platform.as_deref(), Some("sev-snp"));
assert_eq!(
response.details.attestation_mode,
Some(ra_tls::attestation::AttestationMode::DstackAmdSevSnp)
);
}
}
Loading