All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 6s
repository checks / lockfiles, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 41s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m14s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m39s
standards workspaces build + test / joulecontract-rs (joulecontract/joulecontract-rs, joulecontract-rs, linux-arm64, true) (pull_request) Successful in 1m8s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 3m53s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, -p sandbox-tee --features amd-kds,intel-pcs, sandbox-rs, linux) (pull_request) Successful in 2m39s
standards workspaces build + test / proof-rs (proof-conformance, proof/proof-rs, proof-rs, linux, true) (pull_request) Successful in 3m54s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 7m37s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 2m49s
The TDX path (#399) and its PCK chain check (#415) had only met quotes this crate built itself. This runs the reference host inside a TDX guest and records the result as evidence anyone can re-check offline. sandbox-runtime examples: - confidential_run_tdx, run inside the guest. It takes quotes through configfs-tsm and derives the PCK anchor from a probe quote's chain, checked to Intel's root, which the verifier's side supplies. It seals an S6 run against a challenge, then checks the attestation: verified against the challenge, refused against another and against none. - verify_run now reads the evidence kind. For TDX its anchor argument is Intel's root, and the PCK is derived from the quote's chain checked to it. SEV-SNP is unchanged, and the 2026-10-21 SEV-SNP evidence still verifies. - sandbox-runtime's dev-dependencies enable sandbox-tee's intel-pcs feature for these examples. sandbox/proof/hardware/2026-10-21-tdx: the attestation (with the DCAP v4 quote), the challenge, Intel's published root certificate, and a README saying what it shows and what it does not. The unit is a placeholder and revocation lists were not consulted. Checked on our side, away from the guest: - The quote's chain is PCK Certificate, then PCK Platform CA, then Root CA, and its root is byte-identical to Intel's published root (SHA-256 44:A0:19:6B:…:74:D3). - verify_run on the build host verifies the run, and refuses another challenge and no challenge. - An attestation with its outcome changed is refused (report-data binding mismatch). - Another certificate given as the root yields no anchor. Co-Authored-By: Claude Opus 5.5 <[email protected]>
96 lines
4.2 KiB
Rust
96 lines
4.2 KiB
Rust
//! Seal a confidential run on TDX hardware and verify it as a third party
|
|
//! would (SPEC §7.6): the TDX counterpart of `confidential_run`.
|
|
//!
|
|
//! Run as root inside a TDX guest with `configfs-tsm`:
|
|
//!
|
|
//! ```text
|
|
//! confidential_run_tdx <challenge-hex> <intel-root.der>
|
|
//! ```
|
|
//!
|
|
//! `intel-root.der` is Intel's published root CA certificate, which the
|
|
//! verifier pins. The PCK anchor is derived from the chain a quote carries,
|
|
//! checked to that root, so the trust comes from the root and not from the
|
|
//! quote. The host seals an S6 run whose quote the platform makes over the
|
|
//! run's binding and the challenge, and the attestation is verified against
|
|
//! the challenge, against another, and against none. It prints the verdicts
|
|
//! and the attestation as JSON.
|
|
|
|
use ed25519_dalek::SigningKey;
|
|
use sandbox_attest::{DeviceIdentity, Outcome, TeeKind};
|
|
use sandbox_capability::Grants;
|
|
use sandbox_meter::{DeviceEnergy, Provenance};
|
|
use sandbox_runtime::{verify_run_evidence, Host, RunReport, TeeConfig};
|
|
use sandbox_schema::{ContentId, DeviceClass, Tier};
|
|
use sandbox_tee::policy::{TeeAnchor, TeePolicy};
|
|
use sandbox_tee::provider::{AttestationProvider, ConfigfsTsmProvider};
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().collect();
|
|
let (Some(challenge_hex), Some(root_path)) = (args.get(1), args.get(2)) else {
|
|
eprintln!("usage: confidential_run_tdx <challenge-hex> <intel-root.der>");
|
|
std::process::exit(2);
|
|
};
|
|
let challenge: [u8; 32] =
|
|
hex::decode(challenge_hex).ok().and_then(|v| v.try_into().ok()).expect("a 32-byte hex challenge");
|
|
let root = std::fs::read(root_path).expect("read Intel's root certificate");
|
|
let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).expect("a clock after 1970");
|
|
|
|
// A probe quote carries the platform's PCK chain; check it to the root.
|
|
let probe = ConfigfsTsmProvider::for_kind(TeeKind::Tdx).report(&[0; 64]).expect("a TDX quote");
|
|
let pck = sandbox_tee::intel_pcs::pck_from_quote(&probe, &root, now.as_secs()).expect("a PCK chain to Intel's root");
|
|
let anchor = TeeAnchor::Tdx(pck);
|
|
let policy = TeePolicy::tdx_baseline();
|
|
|
|
let host = Host::new("confidential-vm", "steward.hardware-check", SigningKey::from_bytes(&[1; 32]), SigningKey::from_bytes(&[2; 32]))
|
|
.with_tee(TeeConfig {
|
|
provider: Box::new(ConfigfsTsmProvider::for_kind(TeeKind::Tdx)),
|
|
policy: policy.clone(),
|
|
anchor: anchor.clone(),
|
|
});
|
|
let report = RunReport {
|
|
device_energy: vec![DeviceEnergy { class: DeviceClass::Cpu, measured_uj: None, estimated_uj: 1, provenance: Provenance::Estimator }],
|
|
device_identity: vec![DeviceIdentity { class: DeviceClass::Cpu, model: "confidential guest".into(), driver: "host".into() }],
|
|
outcome: Outcome::Completed,
|
|
journal: None,
|
|
storage: None,
|
|
};
|
|
let now_us = now.as_micros() as u64;
|
|
let sealed = match host.seal_run_with_mechanism(
|
|
ContentId::of_bytes(b"hardware check unit"),
|
|
ContentId::of_bytes(b"hardware check image"),
|
|
&Grants::default(),
|
|
Tier::S6,
|
|
report,
|
|
0,
|
|
[0; 8],
|
|
now_us,
|
|
now_us + 1,
|
|
None,
|
|
Some(challenge),
|
|
) {
|
|
Ok(s) => s,
|
|
Err(e) => {
|
|
println!("{}", serde_json::json!({ "sealed": false, "error": e.to_string(), "probe_hex": hex::encode(&probe) }));
|
|
std::process::exit(1);
|
|
}
|
|
};
|
|
let a = &sealed.attestation;
|
|
let tee = a.tee.as_ref().expect("an S6 run carries TEE evidence");
|
|
let verified = verify_run_evidence(a, Some(&challenge), &policy, &anchor);
|
|
let mut other = challenge;
|
|
other[0] ^= 1;
|
|
println!(
|
|
"{}",
|
|
serde_json::json!({
|
|
"sealed": true,
|
|
"verified": verified.is_ok(),
|
|
"verify_error": verified.err().map(|e| e.to_string()),
|
|
"refused_another_challenge": verify_run_evidence(a, Some(&other), &policy, &anchor).is_err(),
|
|
"refused_no_challenge": verify_run_evidence(a, None, &policy, &anchor).is_err(),
|
|
"kind": format!("{:?}", tee.kind),
|
|
"measurement_hex": tee.measurement_hex,
|
|
"tcb": tee.tcb,
|
|
"attestation": a,
|
|
})
|
|
);
|
|
}
|