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

feat: add a keybroker client implementation #8

1 change: 1 addition & 0 deletions rust-keybroker/keybroker-app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ categories = ["cryptography", "hardware-support"]

[dependencies]
keybroker-client = { path = "../keybroker-client" }
clap = { version = "=4.3.24", features = ["derive", "std"] }
58 changes: 57 additions & 1 deletion rust-keybroker/keybroker-app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,62 @@
// Copyright 2024 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

use clap::Parser;
use keybroker_client::error::Error as KeybrokerError;
use keybroker_client::{CcaExampleToken, KeyBrokerClient, TsmAttestationReport};
use std::process;

/// Structure for parsing and storing the command-line arguments
#[derive(Clone, Parser, Debug)]
#[command(version, about, long_about = None)]
struct Args {
/// The address this client should connect to to request a key.
#[arg(short, long, default_value = "http://127.0.0.1:8088")]
endpoint: String,

/// Use a CCA example token (instead of the TSM report)
#[arg(short, long, default_value_t = false)]
mock_evidence: bool,

/// Set the application verbosity
#[arg(short, long, default_value_t = false)]
verbose: bool,

/// The key name to use
key_name: String,
}

fn main() {
println!("Hello, world!");
let args = Args::parse();

let client = KeyBrokerClient::new(&args.endpoint, args.verbose);

let attestation_result = if args.mock_evidence {
client.get_key(&args.key_name, &CcaExampleToken {})
} else {
client.get_key(&args.key_name, &TsmAttestationReport {})
};

// If the attestation was successful, print the key we got from the keybroker and exit with code 0.
// If the attestation failed for genuine attestation related error, print the reason and exit with code 1.
// For any other kind of error (crypto, network connectivity, ...), print an hopefully useful message to diagnose the issue and exit with code 2.
let code = match attestation_result {
Ok(key) => {
let plainstring_key = String::from_utf8(key).unwrap();
println!("Attestation success :-) ! The key returned from the keybroker is '{plainstring_key}'");
0
}

Err(error) => {
if let KeybrokerError::AttestationFailure(reason, details) = error {
println!("Attestation failure :-( ! {reason}: {details}");
1
} else {
eprintln!("The key request failed with: {error:?}");
2
}
}
};

process::exit(code)
}
6 changes: 6 additions & 0 deletions rust-keybroker/keybroker-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,9 @@ categories = ["cryptography", "hardware-support"]

[dependencies]
keybroker-common = { path = "../keybroker-common" }
base64 = "0.22.1"
rand = "0.8.5"
reqwest = { version = "0.12.5", features = ["json", "rustls-tls", "blocking"] }
rsa = "0.9.6"
thiserror = "1.0"
tsm_report = { git = "https://github.com/veracruz-project/cca-utils-rs.git", rev = "cb88b76da722f2991365b159e3d575249dfbbe7d"}
62 changes: 62 additions & 0 deletions rust-keybroker/keybroker-client/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2024 Contributors to the Veraison project.
// SPDX-License-Identifier: Apache-2.0

use thiserror::Error;

/// Top-level error type for a keybroker client.
#[derive(Error, Debug)]
pub enum Error {
/// Represents genuine attestation failures.
#[error("Attestation failure: {0} ({1})")]
AttestationFailure(String, String),
/// Represents all kind of runtime errors that can be faced by a client, like a bogus HTTP connection for example.
#[error(transparent)]
RuntimeError(#[from] RuntimeErrorKind),
}

/// Enumeration holding the different kind of runtime errors (in contrast to genuine
/// attestation failure) that a client can get.
#[derive(Error, Debug)]
pub enum RuntimeErrorKind {
/// Can not connect to the keybroker server.
#[error("HTTP connection to {0} failed with error: {1}")]
HTTPConnect(String, String),

/// Unexpected response from the keybroker server.
#[error("Unhandled HTTP response: {0}")]
HTTPResponse(String),

/// Represents errors due to base64 decoding.
#[error("Failed to base64-decode {0} with error: {1}")]
Base64Decode(String, String),

/// Represents errors due to base64 decoding.
#[error("Failed to JSON-deserialize {0} with error: {1}")]
JSONDeserialize(String, String),

/// Represents errors related to TSM report generation.
#[error(transparent)]
TSMReport(#[from] tsm_report::TsmReportError),

/// Represents errors in the key decryption.
#[error("Failed to decrypt {0} with error: {1}")]
Decrypt(String, String),

/// Represents errors in the retrieval of the challenge from the keybroker server.
#[error("Challenge retrieval error: {0}")]
ChallengeRetrieval(String),

/// Represents the error when the challenge has an incorrect number of bytes.
#[error("Challenge length error, expecting {0} but got {1} instead")]
ChallengeLength(usize, usize),

/// Represents error that occured when attempting to generate the evidence.
#[error("Evidence generation error: {0}")]
EvidenceGeneration(String),

/// Used when the response from the keybroker is missing the location field.
#[error("Missing location field in HTTP requets")]
MissingLocation,
}

pub type Result<T> = std::result::Result<T, Error>;
Loading