From dd6111a7923910c0f8336e3f8454a77f0764d7a3 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 30 Mar 2026 19:06:35 +0000 Subject: [PATCH 1/6] switch AttestSledAgent to an async trait --- Cargo.lock | 1 + Cargo.toml | 1 + verifier/Cargo.toml | 1 + verifier/src/lib.rs | 12 +++++++++++ verifier/src/sled_agent.rs | 42 +++++++++++++++----------------------- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8b6bd2..196338c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1081,6 +1081,7 @@ dependencies = [ name = "dice-verifier" version = "0.3.0-pre0" dependencies = [ + "async-trait", "attest-data", "const-oid", "ed25519-dalek", diff --git a/Cargo.toml b/Cargo.toml index 2632cb6..6fb0374 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ resolver = "2" [workspace.dependencies] anyhow = { version = "1.0.100", default-features = false } +async-trait = "0.1.89" attest.path = "attest" chrono = { version = "0.4.42", default-features=false } clap = { version = "4.5.51", features = ["derive", "env"] } diff --git a/verifier/Cargo.toml b/verifier/Cargo.toml index d05cfad..3245be0 100644 --- a/verifier/Cargo.toml +++ b/verifier/Cargo.toml @@ -7,6 +7,7 @@ license = "MPL-2.0" [dependencies] attest-data = { path = "../attest-data", features = ["std"] } +async-trait.workspace = true const-oid.workspace = true ed25519-dalek = { workspace = true, features = ["std"] } env_logger.workspace = true diff --git a/verifier/src/lib.rs b/verifier/src/lib.rs index ed1882e..5992c41 100644 --- a/verifier/src/lib.rs +++ b/verifier/src/lib.rs @@ -81,6 +81,18 @@ pub trait Attest { fn attest(&self, nonce: &Nonce) -> Result; } +/// All the same operations as `Attest` but provided as `async fn`. For some +/// implementations ([`AttestSledAgent`]) this makes use implementation and use +/// somewhat more straightforward. +/// +/// See corresponding documentation on [`Attest`] for all items. +#[async_trait::async_trait] +pub trait AttestAsync { + async fn get_measurement_log(&self) -> Result; + async fn get_certificates(&self) -> Result; + async fn attest(&self, nonce: &Nonce) -> Result; +} + /// Errors related to the creation of signature verifiers for certs in a /// `PkiPath`. #[derive(Debug, Error)] diff --git a/verifier/src/sled_agent.rs b/verifier/src/sled_agent.rs index dd7fcf1..b59ab70 100644 --- a/verifier/src/sled_agent.rs +++ b/verifier/src/sled_agent.rs @@ -2,44 +2,37 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::{Attest, AttestError}; +use crate::{AttestAsync, AttestError}; use std::net::SocketAddrV6; use attest_data::{Attestation, Log, Measurement, Nonce}; use sled_agent_client::Client as SledAgentClient; use sled_agent_types_versions::latest::rot as SledAgentTypes; -use tokio::runtime::{Builder, Runtime}; use x509_cert::{der::DecodePem, Certificate, PkiPath}; pub struct AttestSledAgent { client: SledAgentClient, - rt: Runtime, } impl AttestSledAgent { pub fn new(addr: SocketAddrV6, log: &slog::Logger) -> Self { - let rt = Builder::new_current_thread() - .enable_time() - .enable_io() - .build() - .unwrap(); let client = SledAgentClient::new( &format!("http://{addr}"), log.new(slog::o!("SledAgentClient" => addr.to_string())), ); - Self { client, rt } + Self { client } } } -impl Attest for AttestSledAgent { - fn get_measurement_log(&self) -> Result { +#[async_trait::async_trait] +impl AttestAsync for AttestSledAgent { + async fn get_measurement_log(&self) -> Result { let mut log = Log::default(); let measurments = self - .rt - .block_on( - self.client.rot_measurement_log(&SledAgentTypes::Rot::Oxide), - )? + .client + .rot_measurement_log(&SledAgentTypes::Rot::Oxide) + .await? .into_inner(); for m in measurments.0 { assert!(log.push(match m { @@ -51,13 +44,11 @@ impl Attest for AttestSledAgent { Ok(log) } - fn get_certificates(&self) -> Result { + async fn get_certificates(&self) -> Result { let certs = self - .rt - .block_on( - self.client - .rot_certificate_chain(&SledAgentTypes::Rot::Oxide), - )? + .client + .rot_certificate_chain(&SledAgentTypes::Rot::Oxide) + .await? .into_inner(); Ok(certs .0 @@ -66,14 +57,15 @@ impl Attest for AttestSledAgent { .collect::, _>>()?) } - fn attest(&self, nonce: &Nonce) -> Result { + async fn attest(&self, nonce: &Nonce) -> Result { let &Nonce::N32(nonce) = nonce; let attestation = self - .rt - .block_on(self.client.rot_attest( + .client + .rot_attest( &SledAgentTypes::Rot::Oxide, &SledAgentTypes::Nonce::N32(nonce.0), - ))? + ) + .await? .into_inner(); let attestation = match attestation { SledAgentTypes::Attestation::Ed25519(d) => { From 912dcefae7551b9ef133191ea985017edd021efe Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 30 Mar 2026 22:11:08 +0000 Subject: [PATCH 2/6] move the rest of it --- verifier/src/hiffy.rs | 89 +++++++++++++++++++++++--------------- verifier/src/ipcc.rs | 37 +++++++++++----- verifier/src/lib.rs | 17 ++------ verifier/src/mock.rs | 7 +-- verifier/src/sled_agent.rs | 4 +- 5 files changed, 88 insertions(+), 66 deletions(-) diff --git a/verifier/src/hiffy.rs b/verifier/src/hiffy.rs index b08899e..9769a1a 100644 --- a/verifier/src/hiffy.rs +++ b/verifier/src/hiffy.rs @@ -19,19 +19,24 @@ use crate::{Attest, AttestError}; /// This trait implements the hubris attestation API exposed by the `attest` /// task in the RoT and proxied through the `sprot` task in the SP. +#[async_trait::async_trait] pub trait AttestSprot { - fn attest_len(&self) -> Result; - fn attest( + async fn attest_len(&self) -> Result; + async fn attest( &self, nonce: &Nonce32, out: &mut [u8], ) -> Result<(), AttestHiffyError>; - fn cert_chain_len(&self) -> Result; - fn cert_len(&self, index: u32) -> Result; - fn cert(&self, index: u32, out: &mut [u8]) -> Result<(), AttestHiffyError>; - fn log(&self, out: &mut [u8]) -> Result<(), AttestHiffyError>; - fn log_len(&self) -> Result; - fn record(&self, data: &[u8]) -> Result<(), AttestHiffyError>; + async fn cert_chain_len(&self) -> Result; + async fn cert_len(&self, index: u32) -> Result; + async fn cert( + &self, + index: u32, + out: &mut [u8], + ) -> Result<(), AttestHiffyError>; + async fn log(&self, out: &mut [u8]) -> Result<(), AttestHiffyError>; + async fn log_len(&self) -> Result; + async fn record(&self, data: &[u8]) -> Result<(), AttestHiffyError>; } /// The `AttestHiffy` type can speak to the `Attest` tasks via either the RoT @@ -115,7 +120,7 @@ impl AttestHiffy { /// This convenience function encapsulates a pattern common to /// the hiffy command line for the `Attest` operations that get the /// lengths of the data returned in leases. - fn get_len_cmd( + async fn get_len_cmd( &self, op: &str, args: Option, @@ -137,7 +142,7 @@ impl AttestHiffy { /// This convenience function encapsulates a pattern common to the hiffy /// command line for the `Attest` operations that return blobs in chunks. - fn get_chunk( + async fn get_chunk( &self, op: &str, length: usize, @@ -168,8 +173,9 @@ impl AttestHiffy { } } +#[async_trait::async_trait] impl AttestSprot for AttestHiffy { - fn attest( + async fn attest( &self, nonce: &Nonce32, out: &mut [u8], @@ -188,28 +194,34 @@ impl AttestSprot for AttestHiffy { attestation_tmp.path(), None, Some(&nonce_tmp.path().to_string_lossy()), - )?; + ) + .await?; Ok(attestation_tmp.read_exact(&mut out[..])?) } /// Get length of the measurement log in bytes. - fn attest_len(&self) -> Result { - self.get_len_cmd("attest_len", None) + async fn attest_len(&self) -> Result { + self.get_len_cmd("attest_len", None).await } /// Get length of the certificate chain from the Attest task. This cert /// chain may be self signed or will terminate at the intermediate before /// the root. - fn cert_chain_len(&self) -> Result { - self.get_len_cmd("cert_chain_len", None) + async fn cert_chain_len(&self) -> Result { + self.get_len_cmd("cert_chain_len", None).await } /// Get length of the certificate at the provided index in bytes. - fn cert_len(&self, index: u32) -> Result { + async fn cert_len(&self, index: u32) -> Result { self.get_len_cmd("cert_len", Some(format!("index={index}"))) + .await } - fn cert(&self, index: u32, out: &mut [u8]) -> Result<(), AttestHiffyError> { + async fn cert( + &self, + index: u32, + out: &mut [u8], + ) -> Result<(), AttestHiffyError> { for offset in (0..out.len() - Self::CHUNK_SIZE).step_by(Self::CHUNK_SIZE) { @@ -220,7 +232,8 @@ impl AttestSprot for AttestHiffy { tmp.path(), Some(&format!("index={index},offset={offset}")), None, - )?; + ) + .await?; tmp.read_exact(&mut out[offset..offset + Self::CHUNK_SIZE])?; } @@ -234,7 +247,8 @@ impl AttestSprot for AttestHiffy { tmp.path(), Some(&format!("index={index},offset={offset}")), None, - )?; + ) + .await?; tmp.read_exact(&mut out[offset..])?; } @@ -243,7 +257,7 @@ impl AttestSprot for AttestHiffy { /// Get measurement log. This function assumes that the slice provided /// is sufficiently large to hold the log. - fn log(&self, out: &mut [u8]) -> Result<(), AttestHiffyError> { + async fn log(&self, out: &mut [u8]) -> Result<(), AttestHiffyError> { for offset in (0..out.len() - Self::CHUNK_SIZE).step_by(Self::CHUNK_SIZE) { @@ -254,7 +268,8 @@ impl AttestSprot for AttestHiffy { tmp.path(), Some(&format!("offset={offset}")), None, - )?; + ) + .await?; tmp.read_exact(&mut out[offset..offset + Self::CHUNK_SIZE])?; } @@ -268,7 +283,8 @@ impl AttestSprot for AttestHiffy { tmp.path(), Some(&format!("offset={offset}")), None, - )?; + ) + .await?; tmp.read_exact(&mut out[offset..])?; } @@ -276,12 +292,12 @@ impl AttestSprot for AttestHiffy { } /// Get length of the measurement log in bytes. - fn log_len(&self) -> Result { - self.get_len_cmd("log_len", None) + async fn log_len(&self) -> Result { + self.get_len_cmd("log_len", None).await } /// Record the sha3 hash of a file. - fn record(&self, data: &[u8]) -> Result<(), AttestHiffyError> { + async fn record(&self, data: &[u8]) -> Result<(), AttestHiffyError> { let digest = Sha3_256::digest(data); let mut tmp = NamedTempFile::new()?; tmp.write_all(digest.as_slice())?; @@ -302,23 +318,24 @@ impl AttestSprot for AttestHiffy { } } +#[async_trait::async_trait] impl Attest for AttestHiffy { - fn get_measurement_log(&self) -> Result { - let log_len = self.log_len()?; + async fn get_measurement_log(&self) -> Result { + let log_len = self.log_len().await?; let mut log = vec![0u8; log_len as usize]; - self.log(&mut log)?; + self.log(&mut log).await?; let (log, _): (Log, _) = hubpack::deserialize(&log).map_err(AttestError::Deserialize)?; Ok(log) } - fn get_certificates(&self) -> Result { + async fn get_certificates(&self) -> Result { let mut cert_chain = PkiPath::new(); - for index in 0..self.cert_chain_len()? { - let cert_len = self.cert_len(index)?; + for index in 0..self.cert_chain_len().await? { + let cert_len = self.cert_len(index).await?; let mut cert = vec![0u8; cert_len as usize]; - self.cert(index, &mut cert)?; + self.cert(index, &mut cert).await?; let cert = Certificate::from_der(&cert)?; @@ -328,11 +345,11 @@ impl Attest for AttestHiffy { Ok(cert_chain) } - fn attest(&self, nonce: &Nonce) -> Result { + async fn attest(&self, nonce: &Nonce) -> Result { let nonce: &Nonce32 = nonce.try_into()?; - let attest_len = self.attest_len()?; + let attest_len = self.attest_len().await?; let mut out = vec![0u8; attest_len as usize]; - AttestSprot::attest(self, nonce, &mut out)?; + AttestSprot::attest(self, nonce, &mut out).await?; let (attestation, _): (Attestation, _) = hubpack::deserialize(&out).map_err(AttestError::Deserialize)?; diff --git a/verifier/src/ipcc.rs b/verifier/src/ipcc.rs index 7a965cd..fb7a957 100644 --- a/verifier/src/ipcc.rs +++ b/verifier/src/ipcc.rs @@ -18,19 +18,34 @@ use crate::{Attest, AttestError}; /// The `AttestIpcc` type communicates with the RoT `Attest` task through the /// IPCC interface / pub struct AttestIpcc { - handle: IpccHandle, + handle: tokio::sync::Mutex, } impl AttestIpcc { /// Creates a new `Ipcc` instance. pub fn new() -> Result { - let handle = IpccHandle::new()?; + let handle = tokio::sync::Mutex::new(IpccHandle::new()?); Ok(Self { handle }) } + + // Doing an actaul RoT request is mildly interesting, so this is a function to + // describe the interestingness once. + async fn do_rot_request( + &self, + message: &[u8], + response: &mut [u8], + ) -> Result { + let handle = self.handle.lock().await; + // `block_in_place` for the request because it is possible the RoT is + // otherwise occupied and this request will synchronously block for some + // amount of time. + tokio::task::block_in_place(|| handle.rot_request(message, response)) + } } +#[async_trait::async_trait] impl Attest for AttestIpcc { - fn get_measurement_log(&self) -> Result { + async fn get_measurement_log(&self) -> Result { let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; let len = attest_data::messages::serialize( @@ -40,8 +55,8 @@ impl Attest for AttestIpcc { ) .map_err(AttestError::Serialize)?; let len = self - .handle - .rot_request(&rot_message[..len], &mut rot_resp)?; + .do_rot_request(&rot_message[..len], &mut rot_resp) + .await?; let data = attest_data::messages::parse_response( &rot_resp[..len], RotToHost::RotMeasurementLog, @@ -54,7 +69,7 @@ impl Attest for AttestIpcc { Ok(log) } - fn get_certificates(&self) -> Result { + async fn get_certificates(&self) -> Result { let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; let len = attest_data::messages::serialize( @@ -64,8 +79,8 @@ impl Attest for AttestIpcc { ) .map_err(AttestError::Serialize)?; let len = self - .handle - .rot_request(&rot_message[..len], &mut rot_resp)?; + .do_rot_request(&rot_message[..len], &mut rot_resp) + .await?; let cert_chain_bytes = attest_data::messages::parse_response( &rot_resp[..len], RotToHost::RotCertificates, @@ -95,7 +110,7 @@ impl Attest for AttestIpcc { Ok(certs) } - fn attest(&self, nonce: &Nonce) -> Result { + async fn attest(&self, nonce: &Nonce) -> Result { let nonce: &Nonce32 = nonce.try_into()?; let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; @@ -109,8 +124,8 @@ impl Attest for AttestIpcc { ) .map_err(AttestError::Serialize)?; let len = self - .handle - .rot_request(&rot_message[..len], &mut rot_resp)?; + .do_rot_request(&rot_message[..len], &mut rot_resp) + .await?; let data = attest_data::messages::parse_response( &rot_resp[..len], RotToHost::RotAttestation, diff --git a/verifier/src/lib.rs b/verifier/src/lib.rs index 5992c41..d14afac 100644 --- a/verifier/src/lib.rs +++ b/verifier/src/lib.rs @@ -62,34 +62,23 @@ pub enum AttestError { /// The `Attest` trait is implemented by types that provide access to the RoT /// attestation API. These types are generally proxies that shuttle data over /// some transport between the caller and the RoT. +#[async_trait::async_trait] pub trait Attest { /// Get the measurement log from the attest task. The Log is transmitted /// with no integrity protection so its trustworthiness must be established /// by an external process (see `verify_attestation`). - fn get_measurement_log(&self) -> Result; + async fn get_measurement_log(&self) -> Result; /// Get the certificate chain from the attest task. This cert chain is a /// PKI path (per RFC 6066) starting with the leaf cert for the attestation /// signer and terminating at the intermediate before the root. The /// trustworthiness of this certificate chain must be established through /// an external process (see `verify_cert_chain`). - fn get_certificates(&self) -> Result; + async fn get_certificates(&self) -> Result; /// Get an attestation from the attest task. An attestation is a signature /// over the (hubpack serialized) measurement Log and the provided Nonce. /// To prevent replay attacks each Nonce used must be unique and /// unpredictable. Generally the Nonce should be generated from the /// platform's random number generator (see `Nonce::from_platform_rng`). - fn attest(&self, nonce: &Nonce) -> Result; -} - -/// All the same operations as `Attest` but provided as `async fn`. For some -/// implementations ([`AttestSledAgent`]) this makes use implementation and use -/// somewhat more straightforward. -/// -/// See corresponding documentation on [`Attest`] for all items. -#[async_trait::async_trait] -pub trait AttestAsync { - async fn get_measurement_log(&self) -> Result; - async fn get_certificates(&self) -> Result; async fn attest(&self, nonce: &Nonce) -> Result; } diff --git a/verifier/src/mock.rs b/verifier/src/mock.rs index 2c83c6c..5197644 100644 --- a/verifier/src/mock.rs +++ b/verifier/src/mock.rs @@ -54,16 +54,17 @@ impl AttestMock { } } +#[async_trait::async_trait] impl Attest for AttestMock { - fn get_measurement_log(&self) -> Result { + async fn get_measurement_log(&self) -> Result { Ok(self.log.clone()) } - fn get_certificates(&self) -> Result { + async fn get_certificates(&self) -> Result { Ok(self.certs.clone()) } - fn attest(&self, nonce: &Nonce) -> Result { + async fn attest(&self, nonce: &Nonce) -> Result { let nonce: &Nonce32 = nonce.try_into()?; let mut buf = vec![0u8; Log::MAX_SIZE]; let len = hubpack::serialize(&mut buf, &self.log) diff --git a/verifier/src/sled_agent.rs b/verifier/src/sled_agent.rs index b59ab70..aba0ad4 100644 --- a/verifier/src/sled_agent.rs +++ b/verifier/src/sled_agent.rs @@ -2,7 +2,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at https://mozilla.org/MPL/2.0/. -use crate::{AttestAsync, AttestError}; +use crate::{Attest, AttestError}; use std::net::SocketAddrV6; @@ -26,7 +26,7 @@ impl AttestSledAgent { } #[async_trait::async_trait] -impl AttestAsync for AttestSledAgent { +impl Attest for AttestSledAgent { async fn get_measurement_log(&self) -> Result { let mut log = Log::default(); let measurments = self From f0bc0797b40fd13b40c027454948da8a8a673860 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 30 Mar 2026 22:41:44 +0000 Subject: [PATCH 3/6] asyncify the rest of it --- Cargo.lock | 1 + verifier-cli/Cargo.toml | 1 + verifier-cli/src/main.rs | 21 +++++++++++++++------ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 196338c..e356965 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5775,6 +5775,7 @@ dependencies = [ "slog-stdlog", "slog-term", "tempfile", + "tokio", "x509-cert", ] diff --git a/verifier-cli/Cargo.toml b/verifier-cli/Cargo.toml index 258a151..e34e787 100644 --- a/verifier-cli/Cargo.toml +++ b/verifier-cli/Cargo.toml @@ -26,6 +26,7 @@ tempfile.workspace = true dice-verifier.path = "../verifier" x509-cert = { workspace = true, default-features = true } serde_json.workspace = true +tokio = { workspace = true, features = ["rt", "macros", "full"] } [features] ipcc = ["dice-verifier/ipcc"] diff --git a/verifier-cli/src/main.rs b/verifier-cli/src/main.rs index 44abdf0..6093f55 100644 --- a/verifier-cli/src/main.rs +++ b/verifier-cli/src/main.rs @@ -205,7 +205,8 @@ impl fmt::Display for Encoding { } } -fn main() -> Result<()> { +#[tokio::main] +async fn main() -> Result<()> { let args = Args::parse(); let stderr_decorator = slog_term::TermDecorator::new().build(); @@ -246,6 +247,7 @@ fn main() -> Result<()> { Nonce::try_from(nonce).context("Nonce from file contents")?; let attestation = attest .attest(&nonce) + .await .context("Getting attestation with provided Nonce")?; // serialize attestation to json & write to file @@ -261,6 +263,7 @@ fn main() -> Result<()> { AttestCommand::CertChain => { let cert_chain = attest .get_certificates() + .await .context("Getting attestation certificate chain")?; for cert in cert_chain { @@ -277,6 +280,7 @@ fn main() -> Result<()> { AttestCommand::Log => { let log = attest .get_measurement_log() + .await .context("Getting attestation measurement log")?; let mut log = serde_json::to_string(&log) .context("Encode measurement log as JSON")?; @@ -317,7 +321,7 @@ fn main() -> Result<()> { corpus.as_deref(), self_signed, &w, - )?, + ).await?, None => { if corpus.is_none() && !skip_appraisal { return Err(anyhow!("no corpus provided but not instructed to skip measurement log appraisal")); @@ -329,7 +333,7 @@ fn main() -> Result<()> { corpus.as_deref(), self_signed, work_dir.as_ref(), - )? + ).await? } }; @@ -358,7 +362,7 @@ fn main() -> Result<()> { verify_measurements(&cert_chain, &log, &corpus)?; } AttestCommand::MeasurementSet => { - let set = measurement_set(attest.as_ref())?; + let set = measurement_set(attest.as_ref()).await?; for item in set.into_iter() { println!("* {item}"); } @@ -368,15 +372,17 @@ fn main() -> Result<()> { Ok(()) } -fn measurement_set(attest: &dyn Attest) -> Result { +async fn measurement_set(attest: &dyn Attest) -> Result { info!("getting measurement log"); let log = attest .get_measurement_log() + .await .context("Get measurement log from attestor")?; let mut cert_chain = Vec::new(); let certs = attest .get_certificates() + .await .context("Get certificate chain from attestor")?; for (index, cert) in certs.iter().enumerate() { @@ -431,7 +437,7 @@ fn verify_measurements( .context("Verify measurements") } -fn verify( +async fn verify( attest: &dyn Attest, ca_cert: Option<&Path>, corpus: Option<&Path>, @@ -453,6 +459,7 @@ fn verify( info!("getting attestation"); let attestation = attest .attest(&nonce) + .await .context("Get attestation with nonce")?; // serialize attestation to json & write to file @@ -471,6 +478,7 @@ fn verify( info!("getting measurement log"); let log = attest .get_measurement_log() + .await .context("Get measurement log from attestor")?; let mut log = serde_json::to_string(&log) .context("Serialize measurement log to JSON")?; @@ -494,6 +502,7 @@ fn verify( let certs = attest .get_certificates() + .await .context("Get certificate chain from attestor")?; // the first cert in the chain / the leaf cert is the one From c008287fb6c62654094d9d145ba9d08d90dcf811 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 30 Mar 2026 22:50:21 +0000 Subject: [PATCH 4/6] rustfmtttttt --- verifier-cli/src/main.rs | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/verifier-cli/src/main.rs b/verifier-cli/src/main.rs index 6093f55..360de62 100644 --- a/verifier-cli/src/main.rs +++ b/verifier-cli/src/main.rs @@ -315,13 +315,16 @@ async fn main() -> Result<()> { // Use the directory provided by the caller to hold intermediate // files, or fall back to a temp dir. let platform_id = match work_dir { - Some(w) => verify( - attest.as_ref(), - ca_cert.as_deref(), - corpus.as_deref(), - self_signed, - &w, - ).await?, + Some(w) => { + verify( + attest.as_ref(), + ca_cert.as_deref(), + corpus.as_deref(), + self_signed, + &w, + ) + .await? + } None => { if corpus.is_none() && !skip_appraisal { return Err(anyhow!("no corpus provided but not instructed to skip measurement log appraisal")); @@ -333,7 +336,8 @@ async fn main() -> Result<()> { corpus.as_deref(), self_signed, work_dir.as_ref(), - ).await? + ) + .await? } }; From d7c69095ada89e6d26d26ef8eadc108ed486a110 Mon Sep 17 00:00:00 2001 From: iximeow Date: Mon, 30 Mar 2026 23:36:50 +0000 Subject: [PATCH 5/6] process spawning also should be async --- verifier/Cargo.toml | 4 ++-- verifier/src/hiffy.rs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/verifier/Cargo.toml b/verifier/Cargo.toml index 3245be0..47ce680 100644 --- a/verifier/Cargo.toml +++ b/verifier/Cargo.toml @@ -21,7 +21,7 @@ sha3.workspace = true sled-agent-client = { workspace = true, optional = true } sled-agent-types-versions = { workspace = true, optional = true } slog.workspace = true -tokio = { workspace = true, features = [ "net", "rt", "time" ], optional = true } +tokio = { workspace = true, features = [ "net", "rt", "time", "process" ] } tempfile.workspace = true thiserror.workspace = true x509-cert = { workspace = true, default-features = true } @@ -34,4 +34,4 @@ attest-data = { path = "../attest-data", features = ["std", "testing"] } testing = [] ipcc = ["libipcc"] mock = ["ed25519-dalek/pem"] -sled-agent = ["sled-agent-client", "sled-agent-types-versions", "tokio"] +sled-agent = ["sled-agent-client", "sled-agent-types-versions"] diff --git a/verifier/src/hiffy.rs b/verifier/src/hiffy.rs index 9769a1a..592b51e 100644 --- a/verifier/src/hiffy.rs +++ b/verifier/src/hiffy.rs @@ -9,10 +9,11 @@ use std::{ fmt, io::{Read, Write}, path::Path, - process::{Command, Output}, + process::Output, }; use tempfile::NamedTempFile; use thiserror::Error; +use tokio::process::Command; use x509_cert::{der::Decode, Certificate, PkiPath}; use crate::{Attest, AttestError}; @@ -136,7 +137,7 @@ impl AttestHiffy { cmd.arg(format!("--arguments={a}")); } - let output = cmd.output().map_err(AttestHiffyError::Humility)?; + let output = cmd.output().await.map_err(AttestHiffyError::Humility)?; Self::u32_from_cmd_output(output) } @@ -164,7 +165,7 @@ impl AttestHiffy { cmd.arg(format!("--input={i}")); } - let output = cmd.output()?; + let output = cmd.output().await?; if output.status.success() { Ok(()) } else { @@ -309,7 +310,7 @@ impl AttestSprot for AttestHiffy { cmd.arg(format!("--input={}", tmp.path().to_string_lossy())); cmd.arg("--arguments=algorithm=Sha3_256"); - let output = cmd.output()?; + let output = cmd.output().await?; if output.status.success() { Ok(()) } else { From 1d3084b514389847e8e0f5d966d2be4f18d02d32 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 1 Apr 2026 00:51:16 +0000 Subject: [PATCH 6/6] review --- verifier-cli/Cargo.toml | 2 +- verifier-cli/src/main.rs | 4 +-- verifier/src/ipcc.rs | 61 ++++++++++++++++++++-------------------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/verifier-cli/Cargo.toml b/verifier-cli/Cargo.toml index e34e787..8d52dfc 100644 --- a/verifier-cli/Cargo.toml +++ b/verifier-cli/Cargo.toml @@ -26,7 +26,7 @@ tempfile.workspace = true dice-verifier.path = "../verifier" x509-cert = { workspace = true, default-features = true } serde_json.workspace = true -tokio = { workspace = true, features = ["rt", "macros", "full"] } +tokio = { workspace = true, features = ["full"] } [features] ipcc = ["dice-verifier/ipcc"] diff --git a/verifier-cli/src/main.rs b/verifier-cli/src/main.rs index 360de62..0fb2154 100644 --- a/verifier-cli/src/main.rs +++ b/verifier-cli/src/main.rs @@ -33,7 +33,7 @@ fn get_attest(interface: Interface, log: &Logger) -> Result> { slog::info!(log, "attesting via {interface:?}"); match interface { #[cfg(feature = "ipcc")] - Interface::Ipcc => Ok(Box::new(AttestIpcc::new()?)), + Interface::Ipcc => Ok(Box::new(AttestIpcc::new())), Interface::Rot => Ok(Box::new(AttestHiffy::new(AttestTask::Rot))), #[cfg(feature = "sled-agent")] Interface::SledAgent(addr) => { @@ -205,7 +205,7 @@ impl fmt::Display for Encoding { } } -#[tokio::main] +#[tokio::main(flavor = "current_thread")] async fn main() -> Result<()> { let args = Args::parse(); diff --git a/verifier/src/ipcc.rs b/verifier/src/ipcc.rs index fb7a957..da3acc4 100644 --- a/verifier/src/ipcc.rs +++ b/verifier/src/ipcc.rs @@ -16,30 +16,35 @@ use x509_cert::{ use crate::{Attest, AttestError}; /// The `AttestIpcc` type communicates with the RoT `Attest` task through the -/// IPCC interface / -pub struct AttestIpcc { - handle: tokio::sync::Mutex, -} +/// IPCC interface / . +/// +/// The actual handle to the IPCC interface is created and released on-demand. +pub struct AttestIpcc {} impl AttestIpcc { /// Creates a new `Ipcc` instance. - pub fn new() -> Result { - let handle = tokio::sync::Mutex::new(IpccHandle::new()?); - Ok(Self { handle }) + pub fn new() -> Self { + Self {} } - // Doing an actaul RoT request is mildly interesting, so this is a function to + // Doing an actual RoT request is mildly interesting, so this is a function to // describe the interestingness once. async fn do_rot_request( &self, - message: &[u8], - response: &mut [u8], - ) -> Result { - let handle = self.handle.lock().await; - // `block_in_place` for the request because it is possible the RoT is - // otherwise occupied and this request will synchronously block for some - // amount of time. - tokio::task::block_in_place(|| handle.rot_request(message, response)) + message: Vec, + ) -> Result, IpccError> { + // `spawn_blocking` for the request because it is possible the RoT is + // otherwise occupied and opening or doing the request will + // synchronously block for some amount of time. + let req = tokio::task::spawn_blocking(move || { + let handle = IpccHandle::new()?; + let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; + let len = handle.rot_request(message.as_slice(), &mut rot_resp)?; + rot_resp.truncate(len); + Ok(rot_resp) + }); + req.await + .expect("handle is not aborted, and we propagate panics") } } @@ -47,18 +52,16 @@ impl AttestIpcc { impl Attest for AttestIpcc { async fn get_measurement_log(&self) -> Result { let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; - let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; let len = attest_data::messages::serialize( &mut rot_message, &HostToRotCommand::GetMeasurementLog, |_| 0, ) .map_err(AttestError::Serialize)?; - let len = self - .do_rot_request(&rot_message[..len], &mut rot_resp) - .await?; + rot_message.truncate(len); + let rot_resp = self.do_rot_request(rot_message).await?; let data = attest_data::messages::parse_response( - &rot_resp[..len], + &rot_resp, RotToHost::RotMeasurementLog, ) .map_err(AttestError::HostToRot)?; @@ -71,18 +74,16 @@ impl Attest for AttestIpcc { async fn get_certificates(&self) -> Result { let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; - let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; let len = attest_data::messages::serialize( &mut rot_message, &HostToRotCommand::GetCertificates, |_| 0, ) .map_err(AttestError::Serialize)?; - let len = self - .do_rot_request(&rot_message[..len], &mut rot_resp) - .await?; + rot_message.truncate(len); + let rot_resp = self.do_rot_request(rot_message).await?; let cert_chain_bytes = attest_data::messages::parse_response( - &rot_resp[..len], + &rot_resp, RotToHost::RotCertificates, ) .map_err(AttestError::HostToRot)?; @@ -113,7 +114,6 @@ impl Attest for AttestIpcc { async fn attest(&self, nonce: &Nonce) -> Result { let nonce: &Nonce32 = nonce.try_into()?; let mut rot_message = vec![0; attest_data::messages::MAX_REQUEST_SIZE]; - let mut rot_resp = vec![0; IPCC_MAX_DATA_SIZE]; let len = attest_data::messages::serialize( &mut rot_message, &HostToRotCommand::Attest, @@ -123,11 +123,10 @@ impl Attest for AttestIpcc { }, ) .map_err(AttestError::Serialize)?; - let len = self - .do_rot_request(&rot_message[..len], &mut rot_resp) - .await?; + rot_message.truncate(len); + let rot_resp = self.do_rot_request(rot_message).await?; let data = attest_data::messages::parse_response( - &rot_resp[..len], + &rot_resp, RotToHost::RotAttestation, ) .map_err(AttestError::HostToRot)?;