Skip to content

Commit

Permalink
feat(keybroker-client): add a client library and a demo application
Browse files Browse the repository at this point in the history
The core of the functionality is provided as a library, with 2 main routines:
 - get_wrapped_key: is the core routine to get a key, with the crypto
   related to the ephemeral wrapping key left to the caller.
 - get_key: is a convenience routine which calls get_wrapped_key and handle
   the crypto when there is no specific requirement.

The demo application illustrates how to use the client library to connect
to the keybroker server and get an attestation. This enables running a
demo of the 2 API calls needed to request the key, supply the evidence
and RSA-decrypt the result.

Co-authored-by: Paul Howard <paul.howard@arm.com>
Signed-off-by: Arnaud de Grandmaison <arnaud.degrandmaison@arm.com>
  • Loading branch information
Arnaud-de-Grandmaison-ARM and paulhowardarm committed Sep 20, 2024
1 parent befccb3 commit 8b10f98
Show file tree
Hide file tree
Showing 5 changed files with 567 additions and 10 deletions.
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"] }
50 changes: 49 additions & 1 deletion rust-keybroker/keybroker-app/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,54 @@
// 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};

/// 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,

/// The key to use
#[arg(short, long, default_value = "skywalker")]
key_name: 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,
}

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 {})
};

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}'")
}

Err(error) => {
if let KeybrokerError::AttestationFailure(reason, details) = error {
println!("Attestation failure :-( ! {reason}: {details}")
} else {
panic!("The key request failed with: {error:?}");
}
}
}
}
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

0 comments on commit 8b10f98

Please sign in to comment.