Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

non-blocking API and HTTPS support #17

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
50 changes: 30 additions & 20 deletions c-wrapper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ 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.
#[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,
Expand Down Expand Up @@ -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(_) => {}
Expand Down Expand Up @@ -428,15 +428,15 @@ pub 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 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,
Expand All @@ -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(),
Expand Down Expand Up @@ -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 {
Expand All @@ -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);
Expand Down Expand Up @@ -580,10 +584,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<VeraisonVerificationApi, Error> {
async fn safe_get_verification_api(base_url: &str) -> Result<VeraisonVerificationApi, Error> {
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()?;

Expand Down Expand Up @@ -835,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);

Expand Down Expand Up @@ -916,6 +922,8 @@ mod tests {
)
};

let result = result.await;

// We should have an Ok result
assert_eq!(result, VeraisonResult::Ok);

Expand Down Expand Up @@ -954,6 +962,8 @@ mod tests {
)
};

let result = result.await;

// We should have an Ok result
assert_eq!(result, VeraisonResult::Ok);

Expand Down
2 changes: 1 addition & 1 deletion rust-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"] }
33 changes: 24 additions & 9 deletions rust-client/examples/challenge_response.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,44 @@
// 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;

use veraison_apiclient::*;

fn my_evidence_builder(nonce: &[u8], accept: &[String]) -> Result<(Vec<u8>, String), Error> {
fn my_evidence_builder(
nonce: &[u8],
accept: &[String],
token: Vec<u8>,
) -> Result<(Vec<u8>, 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() {
let base_url = "http://127.0.0.1:8080";
#[async_std::main]
async fn main() {
let base_url = "https://localhost:8080";

let discovery_api_endpoint = format!("{}{}", base_url, "/.well-known/veraison/verification");

let discovery = Discovery::from_base_url(String::from(base_url))
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
.get_verification_api()
.await
.expect("Failed to discover the verification endpoint details.");

let relative_endpoint = verification_api
Expand All @@ -36,13 +50,14 @@ 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();

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),
}
Expand Down
10 changes: 10 additions & 0 deletions rust-client/examples/veraison-root.crt
Original file line number Diff line number Diff line change
@@ -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-----
Loading
Loading