From f588dbca983ce5029953b135f0ec6382f6191325 Mon Sep 17 00:00:00 2001 From: Dave Chen Date: Thu, 3 Aug 2023 19:35:45 +0800 Subject: [PATCH 1/8] feat: async processing Signed-off-by: Dave Chen --- c-wrapper/src/lib.rs | 4 +- rust-client/Cargo.toml | 2 +- rust-client/examples/challenge_response.rs | 21 ++++-- rust-client/src/lib.rs | 78 +++++++++++++--------- 4 files changed, 66 insertions(+), 39 deletions(-) diff --git a/c-wrapper/src/lib.rs b/c-wrapper/src/lib.rs index 527fc02..6b522f8 100644 --- a/c-wrapper/src/lib.rs +++ b/c-wrapper/src/lib.rs @@ -536,10 +536,10 @@ pub unsafe extern "C" fn veraison_free_verification_api( // veraison_get_verification_api. // This returns proper Rust errors, meanings that it can be coded using Rust-style error handling, // which helps with the several potential fail points in this flow. -fn safe_get_verification_api(base_url: &str) -> Result { +async fn safe_get_verification_api(base_url: &str) -> Result { let discovery = Discovery::from_base_url(String::from(base_url))?; - let verification_api = discovery.get_verification_api()?; + let verification_api = discovery.get_verification_api().await?; let public_key_der_vec = verification_api.ear_verification_key_as_der()?; diff --git a/rust-client/Cargo.toml b/rust-client/Cargo.toml index 50968fe..2b8b3e4 100644 --- a/rust-client/Cargo.toml +++ b/rust-client/Cargo.toml @@ -26,4 +26,4 @@ features = ["base64", "chrono"] [dev-dependencies] wiremock = "0.5" -async-std = { version = "1.6.5", features = ["attributes"] } +async-std = { version = "1.6.5", features = ["attributes", "tokio1"] } diff --git a/rust-client/examples/challenge_response.rs b/rust-client/examples/challenge_response.rs index e5e089e..ea92988 100644 --- a/rust-client/examples/challenge_response.rs +++ b/rust-client/examples/challenge_response.rs @@ -5,19 +5,27 @@ extern crate veraison_apiclient; use veraison_apiclient::*; -fn my_evidence_builder(nonce: &[u8], accept: &[String]) -> Result<(Vec, String), Error> { +fn my_evidence_builder( + nonce: &[u8], + accept: &[String], + token: Vec, +) -> Result<(Vec, String), Error> { println!("server challenge: {:?}", nonce); println!("acceptable media types: {:#?}", accept); - - Ok(( + let mut token = token; + if token.is_empty() { // some very fake evidence - vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], + token = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + } + Ok(( + token, // the first acceptable evidence type accept[0].to_string(), )) } -fn main() { +#[async_std::main] +async fn main() { let base_url = "http://127.0.0.1:8080"; let discovery = Discovery::from_base_url(String::from(base_url)) @@ -25,6 +33,7 @@ fn main() { let verification_api = discovery .get_verification_api() + .await .expect("Failed to discover the verification endpoint details."); let relative_endpoint = verification_api @@ -42,7 +51,7 @@ fn main() { let nonce = Nonce::Value(vec![0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef]); // alternatively, to let Veraison pick the challenge: "let nonce = Nonce::Size(32);" - match cr.run(nonce, my_evidence_builder) { + match cr.run(nonce, my_evidence_builder, Vec::new()).await { Err(e) => println!("Error: {}", e), Ok(attestation_result) => println!("Attestation Result: {}", attestation_result), } diff --git a/rust-client/src/lib.rs b/rust-client/src/lib.rs index 26a761e..fab43f7 100644 --- a/rust-client/src/lib.rs +++ b/rust-client/src/lib.rs @@ -47,7 +47,8 @@ impl std::fmt::Debug for Error { /// The application is passed the session nonce and the list of supported /// evidence media types and shall return the computed evidence together with /// the selected media type. -type EvidenceCreationCb = fn(nonce: &[u8], accepted: &[String]) -> Result<(Vec, String), Error>; +type EvidenceCreationCb = + fn(nonce: &[u8], accepted: &[String], token: Vec) -> Result<(Vec, String), Error>; /// A builder for ChallengeResponse objects pub struct ChallengeResponseBuilder { @@ -80,7 +81,7 @@ impl ChallengeResponseBuilder { Ok(ChallengeResponse { new_session_url: url::Url::parse(&new_session_url_str) .map_err(|e| Error::ConfigError(e.to_string()))?, - http_client: reqwest::blocking::Client::builder().build()?, + http_client: reqwest::Client::new(), }) } } @@ -95,7 +96,7 @@ impl Default for ChallengeResponseBuilder { /// be run. Always use the [ChallengeResponseBuilder] to instantiate it. pub struct ChallengeResponse { new_session_url: url::Url, - http_client: reqwest::blocking::Client, + http_client: reqwest::Client, } /// Nonce configuration: either the size (Size) of the nonce generated by the @@ -110,19 +111,23 @@ impl ChallengeResponse { /// Run a challenge-response verification session using the supplied nonce /// configuration and evidence creation callback. Returns the raw attestation results, or an /// error on failure. - pub fn run( + pub async fn run( &self, nonce: Nonce, evidence_creation_cb: EvidenceCreationCb, + token: Vec, ) -> Result { // create new c/r verification session on the veraison side - let (session_url, session) = self.new_session(&nonce)?; + let (session_url, session) = self.new_session(&nonce).await?; // invoke the user-provided evidence builder callback with per-session parameters - let (evidence, media_type) = (evidence_creation_cb)(session.nonce(), session.accept())?; + let (evidence, media_type) = + (evidence_creation_cb)(session.nonce(), session.accept(), token)?; // send evidence for verification to the session endpoint - let attestation_result = self.challenge_response(&evidence, &media_type, &session_url)?; + let attestation_result = self + .challenge_response(&evidence, &media_type, &session_url) + .await?; // return veraison's attestation results Ok(attestation_result) @@ -131,9 +136,12 @@ impl ChallengeResponse { /// Ask Veraison to create a new challenge/response session using the supplied nonce /// configuration. On success, the return value is a tuple of the session URL for subsequent /// operations, plus the session data including the nonce and the list of accept types. - pub fn new_session(&self, nonce: &Nonce) -> Result<(String, ChallengeResponseSession), Error> { + pub async fn new_session( + &self, + nonce: &Nonce, + ) -> Result<(String, ChallengeResponseSession), Error> { // ask veraison for a new session object - let resp = self.new_session_request(nonce)?; + let resp = self.new_session_request(nonce).await.unwrap(); // expect 201 and a Location header containing the URI of the newly // allocated session @@ -147,7 +155,7 @@ impl ChallengeResponse { // middleware that is unaware of the API. We need something // more robust here that dispatches based on the Content-Type // header. - let pd: ProblemDetails = resp.json()?; + let pd: ProblemDetails = resp.json().await?; return Err(Error::ApiError(format!( "newSession response has unexpected status: {}. Details: {}", @@ -173,13 +181,13 @@ impl ChallengeResponse { .map_err(|e| Error::ApiError(e.to_string()))?; // decode returned session object - let crs: ChallengeResponseSession = resp.json()?; + let crs: ChallengeResponseSession = resp.json().await?; Ok((session_url.to_string(), crs)) } /// Execute a challenge/response operation with the given evidence. - pub fn challenge_response( + pub async fn challenge_response( &self, evidence: &[u8], media_type: &str, @@ -192,14 +200,16 @@ impl ChallengeResponse { .header(reqwest::header::ACCEPT, CRS_MEDIA_TYPE) .header(reqwest::header::CONTENT_TYPE, media_type) .body(evidence.to_owned()) - .send()?; + .send() + .await + .unwrap(); let status = resp.status(); if status.is_success() { match status { reqwest::StatusCode::OK => { - let crs: ChallengeResponseSession = resp.json()?; + let crs: ChallengeResponseSession = resp.json().await?; if crs.status != "complete" { return Err(Error::ApiError(format!( @@ -226,7 +236,7 @@ impl ChallengeResponse { ))), } } else { - let pd: ProblemDetails = resp.json()?; + let pd: ProblemDetails = resp.json().await?; Err(Error::ApiError(format!( "session response has error status: {}. Details: {}", @@ -235,14 +245,16 @@ impl ChallengeResponse { } } - fn new_session_request(&self, nonce: &Nonce) -> Result { + async fn new_session_request(&self, nonce: &Nonce) -> Result { let u = self.new_session_request_url(nonce)?; let r = self .http_client .post(u.as_str()) .header(reqwest::header::ACCEPT, CRS_MEDIA_TYPE) - .send()?; + .send() + .await + .unwrap(); Ok(r) } @@ -324,7 +336,7 @@ pub struct VerificationApi { ear_verification_key: jsonwebkey::JsonWebKey, media_types: Vec, version: String, - service_state: ServiceState, + //service_state: ServiceState, api_endpoints: std::collections::HashMap, } @@ -371,7 +383,7 @@ impl VerificationApi { /// Indicates whether the service is starting, ready, terminating or down. pub fn service_state(&self) -> &ServiceState { - &self.service_state + &ServiceState::Ready } /// Gets the API endpoint associated with a specific endpoint name. @@ -401,10 +413,12 @@ impl VerificationApi { /// /// Use [`Discovery::from_base_url()`] to create an instance of this structure for the /// Veraison service instance that you are communicating with. +/// +/// Currently, only discovery of the verification API is implemented. pub struct Discovery { - provisioning_url: url::Url, //TODO: The provisioning URL discovery is not implemented yet. + _provisioning_url: url::Url, verification_url: url::Url, - http_client: reqwest::blocking::Client, + http_client: reqwest::Client, } impl Discovery { @@ -414,29 +428,31 @@ impl Discovery { let base_url = url::Url::parse(&base_url_str).map_err(|e| Error::ConfigError(e.to_string()))?; - let mut provisioning_url = base_url.clone(); - provisioning_url.set_path(".well-known/veraison/provisioning"); + let mut _provisioning_url = base_url.clone(); + _provisioning_url.set_path(".well-known/veraison/provisioning"); let mut verification_url = base_url; verification_url.set_path(".well-known/veraison/verification"); Ok(Discovery { - provisioning_url, + _provisioning_url, verification_url, - http_client: reqwest::blocking::Client::builder().build()?, + http_client: reqwest::Client::new(), }) } /// Obtains the capabilities and endpoints of the Veraison verification service. - pub fn get_verification_api(&self) -> Result { + pub async fn get_verification_api(&self) -> Result { let response = self .http_client .get(self.verification_url.as_str()) .header(reqwest::header::ACCEPT, DISCOVERY_MEDIA_TYPE) - .send()?; + .send() + .await + .unwrap(); match response.status() { - reqwest::StatusCode::OK => Ok(response.json::()?), + reqwest::StatusCode::OK => Ok(response.json::().await?), _ => Err(Error::ApiError(String::from( "Failed to discover verification endpoint information.", ))), @@ -529,7 +545,7 @@ mod tests { .build() .unwrap(); - let rv = cr.new_session(&nonce).expect("unexpected failure"); + let rv = cr.new_session(&nonce).await.expect("unexpected failure"); // Expect we are given the expected location URL assert_eq!(rv.0, format!("{}/1234", mock_server.uri())); @@ -571,6 +587,7 @@ mod tests { let rv = cr .challenge_response(&evidence_value, media_type, &session_url) + .await .expect("unexpected failure"); // Expect we are given the expected attestation result @@ -619,10 +636,11 @@ mod tests { let verification_api = discovery .get_verification_api() + .await .expect("Failed to get verification endpoint details."); // Check that we've pulled and deserialized everything that we expect - assert_eq!(verification_api.service_state, ServiceState::Ready); + //assert_eq!(verification_api.service_state, ServiceState::Ready); assert_eq!(verification_api.version, String::from("commit-cb11fa0")); assert_eq!(verification_api.media_types.len(), 5); assert_eq!( From 386f347d7ad058153e3798e494610e070f69d626 Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Sat, 11 May 2024 19:20:21 +0200 Subject: [PATCH 2/8] cherry pick ear_verification_key_as_string from veraison Signed-off-by: Thomas Fossati --- rust-client/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust-client/src/lib.rs b/rust-client/src/lib.rs index fab43f7..e6466e5 100644 --- a/rust-client/src/lib.rs +++ b/rust-client/src/lib.rs @@ -357,6 +357,11 @@ impl VerificationApi { .map_err(|e| Error::DataConversionError(e.to_string())) } + /// Obtains the EAR verification public key as a JSON string. + pub fn ear_verification_key_as_string(&self) -> String { + self.ear_verification_key.to_string() + } + /// Obtains the signature algorithm scheme used with the EAR. pub fn ear_verification_algorithm(&self) -> String { match &self.ear_verification_key.algorithm { From 1eb24f76eb816a1303b6e5f81ae85bd5adf43a24 Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Tue, 8 Oct 2024 15:40:47 +0200 Subject: [PATCH 3/8] feat: add HTTPS support Signed-off-by: Thomas Fossati --- rust-client/examples/challenge_response.rs | 10 ++- rust-client/examples/veraison-root.crt | 10 +++ rust-client/src/lib.rs | 100 +++++++++++++++++++-- 3 files changed, 110 insertions(+), 10 deletions(-) create mode 100644 rust-client/examples/veraison-root.crt diff --git a/rust-client/examples/challenge_response.rs b/rust-client/examples/challenge_response.rs index ea92988..548278d 100644 --- a/rust-client/examples/challenge_response.rs +++ b/rust-client/examples/challenge_response.rs @@ -26,9 +26,14 @@ fn my_evidence_builder( #[async_std::main] async fn main() { - let base_url = "http://127.0.0.1:8080"; + let base_url = "https://localhost:8080"; - let discovery = Discovery::from_base_url(String::from(base_url)) + let discovery_api_endpoint = format!("{}{}", base_url, "/.well-known/veraison/verification"); + + let discovery = DiscoveryBuilder::new() + .with_url(discovery_api_endpoint) + .with_root_certificate("veraison-root.crt".into()) + .build() .expect("Failed to start API discovery with the service."); let verification_api = discovery @@ -45,6 +50,7 @@ async fn main() { // create a ChallengeResponse object let cr = ChallengeResponseBuilder::new() .with_new_session_url(api_endpoint) + .with_root_certificate("veraison-root.crt".into()) .build() .unwrap(); diff --git a/rust-client/examples/veraison-root.crt b/rust-client/examples/veraison-root.crt new file mode 100644 index 0000000..e894c3d --- /dev/null +++ b/rust-client/examples/veraison-root.crt @@ -0,0 +1,10 @@ +-----BEGIN CERTIFICATE----- +MIIBfDCCASGgAwIBAgIUGFllXaV04uJz42tPnHXwOkaux50wCgYIKoZIzj0EAwIw +EzERMA8GA1UECgwIVmVyYWlzb24wHhcNMjQwNTIxMTAxNzA1WhcNMzQwNTE5MTAx +NzA1WjATMREwDwYDVQQKDAhWZXJhaXNvbjBZMBMGByqGSM49AgEGCCqGSM49AwEH +A0IABCYxQeR0gnM4/4CvQBmIgNSm6SAal29OYm7GBpq/y0rZWolA3FlHChm3nIZe +qXAtKvK4rkolWSLiaRNN1mEWYG6jUzBRMB0GA1UdDgQWBBTq/aQhL7+hx9EOG+X0 +Q/YbAWuGDjAfBgNVHSMEGDAWgBTq/aQhL7+hx9EOG+X0Q/YbAWuGDjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQCAqRST0CFtgWVXpBtYoTldREXb +hGryGCivO3Jkv6LZ5wIhAMqlRBGBPbz8sgS+QQCA0pbhXFt7kMQpH3hrR/tEIeW2 +-----END CERTIFICATE----- diff --git a/rust-client/src/lib.rs b/rust-client/src/lib.rs index e6466e5..be0baf3 100644 --- a/rust-client/src/lib.rs +++ b/rust-client/src/lib.rs @@ -1,6 +1,14 @@ // Copyright 2022 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 +use std::{ + fs::File, + io::Read, + path::{Path, PathBuf}, +}; + +use reqwest::{Certificate, ClientBuilder}; + #[derive(thiserror::Error, PartialEq, Eq)] pub enum Error { #[error("configuration error: {0}")] @@ -23,6 +31,12 @@ impl From for Error { } } +impl From for Error { + fn from(re: std::io::Error) -> Self { + Error::ConfigError(re.to_string()) + } +} + impl From for Error { fn from(e: jsonwebkey::ConversionError) -> Self { Error::DataConversionError(e.to_string()) @@ -53,7 +67,7 @@ type EvidenceCreationCb = /// A builder for ChallengeResponse objects pub struct ChallengeResponseBuilder { new_session_url: Option, - // TODO(tho) add TLS config / authn tokens etc. + root_certificate: Option, } impl ChallengeResponseBuilder { @@ -61,6 +75,7 @@ impl ChallengeResponseBuilder { pub fn new() -> Self { Self { new_session_url: None, + root_certificate: None, } } @@ -72,16 +87,32 @@ impl ChallengeResponseBuilder { self } + pub fn with_root_certificate(mut self, v: PathBuf) -> ChallengeResponseBuilder { + self.root_certificate = Some(v); + self + } + /// Instantiate a valid ChallengeResponse object, or fail with an error. pub fn build(self) -> Result { let new_session_url_str = self .new_session_url .ok_or_else(|| Error::ConfigError("missing API endpoint".to_string()))?; + let mut http_client_builder: ClientBuilder = reqwest::ClientBuilder::new(); + + if self.root_certificate.is_some() { + let mut buf = Vec::new(); + File::open(self.root_certificate.unwrap())?.read_to_end(&mut buf)?; + let cert = Certificate::from_pem(&buf)?; + http_client_builder = http_client_builder.add_root_certificate(cert); + } + + let http_client = http_client_builder.build()?; + Ok(ChallengeResponse { new_session_url: url::Url::parse(&new_session_url_str) .map_err(|e| Error::ConfigError(e.to_string()))?, - http_client: reqwest::Client::new(), + http_client, }) } } @@ -413,6 +444,64 @@ impl VerificationApi { } } +/// A builder for VerificationApi objects +pub struct DiscoveryBuilder { + url: Option, + root_certificate: Option, +} + +impl DiscoveryBuilder { + /// default constructor + pub fn new() -> Self { + Self { + url: None, + root_certificate: None, + } + } + + /// Use this method to supply the URL of the discovery endpoint + /// TODO(tho) + pub fn with_url(mut self, v: String) -> DiscoveryBuilder { + self.url = Some(v); + self + } + + pub fn with_root_certificate(mut self, v: PathBuf) -> DiscoveryBuilder { + self.root_certificate = Some(v); + self + } + + /// Instantiate a valid Discovery object, or fail with an error. + pub fn build(self) -> Result { + let url = self + .url + .ok_or_else(|| Error::ConfigError("missing API endpoint".to_string()))?; + + let mut http_client_builder: ClientBuilder = reqwest::ClientBuilder::new(); + + if self.root_certificate.is_some() { + let mut buf = Vec::new(); + File::open(self.root_certificate.unwrap())?.read_to_end(&mut buf)?; + let cert = Certificate::from_pem(&buf)?; + http_client_builder = http_client_builder.add_root_certificate(cert); + } + + let http_client = http_client_builder.build()?; + + Ok(Discovery { + verification_url: url::Url::parse(&url) + .map_err(|e| Error::ConfigError(e.to_string()))?, + http_client, + }) + } +} + +impl Default for DiscoveryBuilder { + fn default() -> Self { + Self::new() + } +} + /// This structure allows Veraison endpoints and service capabilities to be discovered /// dynamically. /// @@ -421,7 +510,6 @@ impl VerificationApi { /// /// Currently, only discovery of the verification API is implemented. pub struct Discovery { - _provisioning_url: url::Url, verification_url: url::Url, http_client: reqwest::Client, } @@ -433,14 +521,10 @@ impl Discovery { let base_url = url::Url::parse(&base_url_str).map_err(|e| Error::ConfigError(e.to_string()))?; - let mut _provisioning_url = base_url.clone(); - _provisioning_url.set_path(".well-known/veraison/provisioning"); - let mut verification_url = base_url; verification_url.set_path(".well-known/veraison/verification"); Ok(Discovery { - _provisioning_url, verification_url, http_client: reqwest::Client::new(), }) @@ -645,7 +729,7 @@ mod tests { .expect("Failed to get verification endpoint details."); // Check that we've pulled and deserialized everything that we expect - //assert_eq!(verification_api.service_state, ServiceState::Ready); + assert_eq!(*verification_api.service_state(), ServiceState::Ready); assert_eq!(verification_api.version, String::from("commit-cb11fa0")); assert_eq!(verification_api.media_types.len(), 5); assert_eq!( From 1191194379f5ae66d9d574b1b924f5798b5920a7 Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Thu, 10 Oct 2024 14:21:04 +0200 Subject: [PATCH 4/8] fix: force the rustls backend to be used for HTTPS requests Work around annoying MacOSX system-wide policy Signed-off-by: Thomas Fossati --- rust-client/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/rust-client/src/lib.rs b/rust-client/src/lib.rs index be0baf3..8390c42 100644 --- a/rust-client/src/lib.rs +++ b/rust-client/src/lib.rs @@ -100,6 +100,8 @@ impl ChallengeResponseBuilder { let mut http_client_builder: ClientBuilder = reqwest::ClientBuilder::new(); + http_client_builder = http_client_builder.use_rustls_tls(); + if self.root_certificate.is_some() { let mut buf = Vec::new(); File::open(self.root_certificate.unwrap())?.read_to_end(&mut buf)?; @@ -367,7 +369,7 @@ pub struct VerificationApi { ear_verification_key: jsonwebkey::JsonWebKey, media_types: Vec, version: String, - //service_state: ServiceState, + service_state: ServiceState, api_endpoints: std::collections::HashMap, } @@ -419,7 +421,7 @@ impl VerificationApi { /// Indicates whether the service is starting, ready, terminating or down. pub fn service_state(&self) -> &ServiceState { - &ServiceState::Ready + &self.service_state } /// Gets the API endpoint associated with a specific endpoint name. @@ -479,6 +481,8 @@ impl DiscoveryBuilder { let mut http_client_builder: ClientBuilder = reqwest::ClientBuilder::new(); + http_client_builder = http_client_builder.use_rustls_tls(); + if self.root_certificate.is_some() { let mut buf = Vec::new(); File::open(self.root_certificate.unwrap())?.read_to_end(&mut buf)?; @@ -729,7 +733,7 @@ mod tests { .expect("Failed to get verification endpoint details."); // Check that we've pulled and deserialized everything that we expect - assert_eq!(*verification_api.service_state(), ServiceState::Ready); + assert_eq!(verification_api.service_state, ServiceState::Ready); assert_eq!(verification_api.version, String::from("commit-cb11fa0")); assert_eq!(verification_api.media_types.len(), 5); assert_eq!( From ebf52fd6e996b4e8971cbc62d02a738911fba1cd Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Thu, 10 Oct 2024 16:49:03 +0200 Subject: [PATCH 5/8] fix: leftovers Signed-off-by: Thomas Fossati --- rust-client/examples/challenge_response.rs | 2 +- rust-client/src/lib.rs | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/rust-client/examples/challenge_response.rs b/rust-client/examples/challenge_response.rs index 548278d..e078136 100644 --- a/rust-client/examples/challenge_response.rs +++ b/rust-client/examples/challenge_response.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Contributors to the Veraison project. +// Copyright 2022-2024 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 extern crate veraison_apiclient; diff --git a/rust-client/src/lib.rs b/rust-client/src/lib.rs index b6ac3ca..87ca841 100644 --- a/rust-client/src/lib.rs +++ b/rust-client/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2022 Contributors to the Veraison project. +// Copyright 2022-2024 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 #![allow(clippy::multiple_crate_versions)] @@ -176,7 +176,7 @@ impl ChallengeResponse { nonce: &Nonce, ) -> Result<(String, ChallengeResponseSession), Error> { // ask veraison for a new session object - let resp = self.new_session_request(nonce).await.unwrap(); + let resp = self.new_session_request(nonce).await?; // expect 201 and a Location header containing the URI of the newly // allocated session @@ -236,8 +236,7 @@ impl ChallengeResponse { .header(reqwest::header::CONTENT_TYPE, media_type) .body(evidence.to_owned()) .send() - .await - .unwrap(); + .await?; let status = resp.status(); @@ -464,7 +463,6 @@ impl DiscoveryBuilder { } /// Use this method to supply the URL of the discovery endpoint - /// TODO(tho) pub fn with_url(mut self, v: String) -> DiscoveryBuilder { self.url = Some(v); self From a7542fcd9d14688a164f9cf1a3ddb1e82d086e8a Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Thu, 10 Oct 2024 19:04:24 +0200 Subject: [PATCH 6/8] fix: async c-wrappers Signed-off-by: Thomas Fossati --- c-wrapper/src/lib.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/c-wrapper/src/lib.rs b/c-wrapper/src/lib.rs index 33193b9..a098ec8 100644 --- a/c-wrapper/src/lib.rs +++ b/c-wrapper/src/lib.rs @@ -302,7 +302,7 @@ struct ShimVerificationApi { /// It is the caller's responsibility to ensure that `out_session` is /// not a null pointer. #[no_mangle] -pub unsafe extern "C" fn open_challenge_response_session( +pub async unsafe extern "C" fn open_challenge_response_session( new_session_url: *const libc::c_char, nonce_size: libc::size_t, nonce: *const u8, @@ -349,7 +349,7 @@ pub unsafe extern "C" fn open_challenge_response_session( // This now won't panic because we dealt with errors by early return above. let cr = cr.unwrap(); - let newsession = cr.new_session(&nonce_converted); + let newsession = cr.new_session(&nonce_converted).await; match newsession { Ok(_) => {} @@ -436,7 +436,7 @@ pub unsafe extern "C" fn open_challenge_response_session( /// - The `media_type` parameter is a non-NULL pointer to a valid NUL-terminated character string that /// will not be mutated for the duration of this function call. #[no_mangle] -pub unsafe extern "C" fn challenge_response( +pub async unsafe extern "C" fn challenge_response( session: *mut ChallengeResponseSession, evidence_size: libc::size_t, evidence: *const u8, @@ -459,11 +459,15 @@ pub unsafe extern "C" fn challenge_response( // Actually call the client let client_result = match shim_session.client.as_ref() { - Some(client) => client.challenge_response( - evidence_bytes, - media_type_str, - shim_session.session_url_cstring.to_str().unwrap(), - ), + Some(client) => { + client + .challenge_response( + evidence_bytes, + media_type_str, + shim_session.session_url_cstring.to_str().unwrap(), + ) + .await + } // If we have no client, it means that the session was never properly established in the first place. None => Err(Error::ConfigError( "Cannot supply evidence because there is no session endpoint.".to_string(), @@ -531,7 +535,7 @@ pub unsafe extern "C" fn free_challenge_response_session(session: *mut Challenge /// It is the caller's responsibility to ensure that `out_api` is /// not a null pointer. #[no_mangle] -pub unsafe extern "C" fn veraison_get_verification_api( +pub async unsafe extern "C" fn veraison_get_verification_api( veraison_service_base_url: *const libc::c_char, out_api: *mut *mut VeraisonVerificationApi, ) -> VeraisonResult { @@ -541,7 +545,7 @@ pub unsafe extern "C" fn veraison_get_verification_api( url_cstr.to_str().unwrap() }; - let api = safe_get_verification_api(url_str); + let api = safe_get_verification_api(url_str).await; if let Err(e) = api { return stub_verification_api_from_error(&e, out_api); From ce19c35f46128099fadc85bf5da8855f8b15d523 Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Thu, 10 Oct 2024 19:07:31 +0200 Subject: [PATCH 7/8] fix(c-wrapper): tests Signed-off-by: Thomas Fossati --- c-wrapper/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/c-wrapper/src/lib.rs b/c-wrapper/src/lib.rs index a098ec8..5df4330 100644 --- a/c-wrapper/src/lib.rs +++ b/c-wrapper/src/lib.rs @@ -839,6 +839,8 @@ mod tests { let result = unsafe { veraison_get_verification_api(base_url.as_ptr(), &mut verification_api) }; + let result = result.await; + // We should have an Ok result assert_eq!(result, VeraisonResult::Ok); @@ -920,6 +922,8 @@ mod tests { ) }; + let result = result.await; + // We should have an Ok result assert_eq!(result, VeraisonResult::Ok); @@ -958,6 +962,8 @@ mod tests { ) }; + let result = result.await; + // We should have an Ok result assert_eq!(result, VeraisonResult::Ok); From 555b66ffa9c4527f330786560c17a8ad137ff78a Mon Sep 17 00:00:00 2001 From: Thomas Fossati Date: Thu, 10 Oct 2024 22:11:44 +0200 Subject: [PATCH 8/8] doc(c-wrapper): fix indentations Signed-off-by: Thomas Fossati --- c-wrapper/src/lib.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/c-wrapper/src/lib.rs b/c-wrapper/src/lib.rs index 5df4330..1ea4c3a 100644 --- a/c-wrapper/src/lib.rs +++ b/c-wrapper/src/lib.rs @@ -294,10 +294,10 @@ struct ShimVerificationApi { /// It is the caller's responsibility to ensure that `nonce` is: /// /// - **EITHER** a null pointer (in which case the nonce challenge is issued on -/// the server side) +/// the server side) /// - **OR** a pointer to a valid buffer of initialized data of at -/// least `nonce_size` bytes, which will not be mutated for the duration -/// of this function call. +/// least `nonce_size` bytes, which will not be mutated for the duration +/// of this function call. /// /// It is the caller's responsibility to ensure that `out_session` is /// not a null pointer. @@ -428,13 +428,13 @@ pub async unsafe extern "C" fn open_challenge_response_session( /// The caller guarantees the following: /// /// - The `session` parameter is a non-NULL pointer to a valid structure that was received from a prior -/// successful call to [`open_challenge_response_session()`]. Do not call this function with a NULL -/// pointer or a pointer to uninitialized data. Also do not call this function with a pointer to a -/// failed session. +/// successful call to [`open_challenge_response_session()`]. Do not call this function with a NULL +/// pointer or a pointer to uninitialized data. Also do not call this function with a pointer to a +/// failed session. /// - The `evidence` parameter is not NULL, and points to a valid data buffer of at least `evidence_size` -/// bytes that will not be mutated for the duration of this function call. +/// bytes that will not be mutated for the duration of this function call. /// - The `media_type` parameter is a non-NULL pointer to a valid NUL-terminated character string that -/// will not be mutated for the duration of this function call. +/// will not be mutated for the duration of this function call. #[no_mangle] pub async unsafe extern "C" fn challenge_response( session: *mut ChallengeResponseSession,