diff --git a/README.md b/README.md index caaff61..69cb66a 100644 --- a/README.md +++ b/README.md @@ -13,3 +13,94 @@ flowchart LR RP -->|Evidence fa:fa-receipt| V[Veraison] V -->|EAR fa:fa-check-square| RP ``` + +## Building + +The `keybroker-demo` has 2 executables: `keybroker-server` and `keybroker-app`. +These are built with: + +```console +$ cd rust-keybroker +$ cargo build +``` + +By default, the executables are in debug mode and located in directory +`target/debug/`. + +## Running + +The `keybroker-server` and `keybroker-app` can be controlled with command line +options. Use `-h` / `--help` to get their usage, e.g.: + +``` +$ target/debug/keybroker-server --help +A simple web service that can provide keys and secrets in exchange for verifiable attestation tokens. + +Usage: keybroker-server [OPTIONS] + +Options: + -a, --addr + The interface on which this server will listen (use 0.0.0.0 to listen on all interfaces) [default: 127.0.0.1] + -p, --port + The port on which this server will listen [default: 8088] + -e, --endpoint + The address at which this server can be reached to request a key or submit an evidence. It will be set by default to 'http://{addr}', but this value can be overridden with an FQDN for {addr} in order to use name resolution for example. The port number will be appended, so don't leave a trailing '/' to the FQDN + --verifier + The URL where the verifier can be reached [default: http://veraison.test.linaro.org:8080] + -m, --mock-challenge + Use the static CCA example token nonce instead of a randomly generated one + -v, --verbosity... + Increase verbosity + -q, --quiet + Silence all output + --reference-values + File containing a JSON array with base64-encoded known-good RIM values [default: reference-values.json] + -h, --help + Print help + -V, --version + Print version +``` + +The simplest way to get started with `keybroker-server` and `keybroker-app` is +to run them locally in _mocking_ mode (i.e they make use of statically known +values). + +In a terminal, start `keybroker-server` with: + +```console +$ target/debug/keybroker-server -v -m --reference-values <(echo '{ "reference-values": [ "MRMUq3NiA1DPdYg0rlxl2ejC3H/r5ufZZUu+hk4wDUk=" ] }') +INFO starting 11 workers +INFO Actix runtime found; starting in Actix runtime +INFO starting service: "actix-web-service-127.0.0.1:8088", workers: 11, listening on: 127.0.0.1:8088 +``` + +In another terminal, launch `keybroker-app` with: + +```console +$ target/debug/keybroker-app -v -m skywalker +INFO Requesting key named 'skywalker' from the keybroker server with URL http://127.0.0.1:8088/keys/v1/key/skywalker +INFO Submitting evidence to URL http://127.0.0.1:8088/keys/v1/evidence/1923965078 +INFO Attestation success :-) ! The key returned from the keybroker is 'May the force be with you.' +``` + +`keybroker-app` is requesting the key named `skywalker` from `keybroker-server`. +As we are in _mocking_ mode with statically known challenges and evidences, the +attestation succeeds: `keyboker-app` receives the key `May the force be with +you.` from `keybroker-server`. + +## Logging + +`keybroker-server` and `keybroker-app` use Rust's `log` and `stderrlog` crates +for logging. the verbosity can be controlled from the command line with the `-q` +/ `--quiet` (to silence all messages) and `-v` / `--verbose` switches. Note the +`-v` / `--verbose` can be specified multiple times to increase verbosity. + +The mapping that has been implemented in `keybroker-server` and `keybroker-app` is: + +| Log level | Verbosity threshold | `keybroker-*` | +| --------- | ------------------- | -------------------------------------------------------- | +| Error | 0 | Enabled by default, unless invoked with `-q` / `--quiet` | +| Warning | 1 | Enabled by default, unless invoked with `-q` / `--quiet` | +| Info | 2 | Enabled with `-v` or `--verbose` | +| Debug | 3 | Enabled with `-vv` or `-v -v` or `--verbose --verbose` | +| Trace | 4 | Enabled with `-vvv` or `-v -v -v` or ... | diff --git a/rust-keybroker/keybroker-app/Cargo.toml b/rust-keybroker/keybroker-app/Cargo.toml index a215d06..6615a11 100644 --- a/rust-keybroker/keybroker-app/Cargo.toml +++ b/rust-keybroker/keybroker-app/Cargo.toml @@ -12,4 +12,6 @@ categories = ["cryptography", "hardware-support"] [dependencies] keybroker-client = { path = "../keybroker-client" } -clap = { version = "=4.3.24", features = ["derive", "std"] } \ No newline at end of file +clap = { version = "=4.3.24", features = ["derive", "std"] } +log = { version = "0.4.22", features = ["std", "serde"] } +stderrlog = "0.6.0" diff --git a/rust-keybroker/keybroker-app/src/main.rs b/rust-keybroker/keybroker-app/src/main.rs index 6ea98fb..cbd6b44 100644 --- a/rust-keybroker/keybroker-app/src/main.rs +++ b/rust-keybroker/keybroker-app/src/main.rs @@ -18,9 +18,13 @@ struct Args { #[arg(short, long, default_value_t = false)] mock_evidence: bool, - /// Set the application verbosity + /// Increase verbosity + #[arg(short, long, action = clap::ArgAction::Count)] + verbosity: u8, + + /// Silence all output #[arg(short, long, default_value_t = false)] - verbose: bool, + quiet: bool, /// The key name to use key_name: String, @@ -29,7 +33,13 @@ struct Args { fn main() { let args = Args::parse(); - let client = KeyBrokerClient::new(&args.endpoint, args.verbose); + stderrlog::new() + .quiet(args.quiet) + .verbosity(1 + usize::from(args.verbosity)) + .init() + .unwrap(); + + let client = KeyBrokerClient::new(&args.endpoint); let attestation_result = if args.mock_evidence { client.get_key(&args.key_name, &CcaExampleToken {}) @@ -43,16 +53,16 @@ fn main() { 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}'"); + log::info!("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}"); + log::info!("Attestation failure :-( ! {reason}: {details}"); 1 } else { - eprintln!("The key request failed with: {error:?}"); + log::error!("The key request failed with: {error:?}"); 2 } } diff --git a/rust-keybroker/keybroker-client/Cargo.toml b/rust-keybroker/keybroker-client/Cargo.toml index e2a6bcf..e7b65c1 100644 --- a/rust-keybroker/keybroker-client/Cargo.toml +++ b/rust-keybroker/keybroker-client/Cargo.toml @@ -13,8 +13,10 @@ categories = ["cryptography", "hardware-support"] [dependencies] keybroker-common = { path = "../keybroker-common" } base64 = "0.22.1" +log = { version = "0.4.22", features = ["std", "serde"] } rand = "0.8.5" reqwest = { version = "0.12.5", features = ["json", "rustls-tls", "blocking"] } rsa = "0.9.6" +stderrlog = "0.6.0" thiserror = "1.0" -tsm_report = { git = "https://github.com/veracruz-project/cca-utils-rs.git", rev = "cb88b76da722f2991365b159e3d575249dfbbe7d"} \ No newline at end of file +tsm_report = { git = "https://github.com/veracruz-project/cca-utils-rs.git", rev = "cb88b76da722f2991365b159e3d575249dfbbe7d"} diff --git a/rust-keybroker/keybroker-client/src/lib.rs b/rust-keybroker/keybroker-client/src/lib.rs index 02fe64d..d7f3b63 100644 --- a/rust-keybroker/keybroker-client/src/lib.rs +++ b/rust-keybroker/keybroker-client/src/lib.rs @@ -18,7 +18,7 @@ use crate::error::RuntimeErrorKind; /// The trait that must be implemented so a KeybrokerClient can retrieve the evidence it has /// to submit to the Keybroker server. pub trait EvidenceProvider { - fn get_evidence(&self, challenge: &str, verbose: bool) -> Result>; + fn get_evidence(&self, challenge: &str) -> Result>; } /// The CCA example token. @@ -164,7 +164,7 @@ const CCA_EXAMPLE_TOKEN: &[u8] = &[ pub struct CcaExampleToken {} impl EvidenceProvider for CcaExampleToken { - fn get_evidence(&self, _challenge: &str, _verbose: bool) -> Result> { + fn get_evidence(&self, _challenge: &str) -> Result> { Ok(CCA_EXAMPLE_TOKEN.to_vec()) } } @@ -177,13 +177,11 @@ impl EvidenceProvider for CcaExampleToken { pub struct TsmAttestationReport {} impl EvidenceProvider for TsmAttestationReport { - fn get_evidence(&self, challenge: &str, verbose: bool) -> Result> { + fn get_evidence(&self, challenge: &str) -> Result> { match TsmReportPath::new(TsmReportProvider::Cca) { Ok(tsm_report_path) => match URL_SAFE_NO_PAD.decode(challenge) { Ok(challenge) => { - if verbose { - println!("Challenge ({} bytes) = {:02x?}", challenge.len(), challenge); - } + log::info!("Challenge ({} bytes) = {:02x?}", challenge.len(), challenge); if challenge.len() != 64 { return Err(KeybrokerError::RuntimeError( RuntimeErrorKind::ChallengeLength(64, challenge.len()), @@ -225,22 +223,14 @@ pub struct KeyBrokerClient { /// The keybroker URL base address. keybroker_url_base: String, - - /// The session verbosity. - /// - /// The verbose flag serves 2 purposes: help the developer when diagnosing some - /// issue, but also the new comer to the code base when understanding the overall - /// flow is intended. - verbose: bool, } impl KeyBrokerClient { /// Create a session to the keybroker server located at addr:port. - pub fn new(endpoint: &str, verbose: bool) -> KeyBrokerClient { + pub fn new(endpoint: &str) -> KeyBrokerClient { KeyBrokerClient { client: reqwest::blocking::Client::new(), keybroker_url_base: endpoint.to_string(), - verbose, } } @@ -269,11 +259,9 @@ impl KeyBrokerClient { // Construct the URL to request the key. let key_request_url = format!("{}/keys/v1/key/{}", self.keybroker_url_base, key_name); - if self.verbose { - println!( - "Requesting key named '{key_name}' from the keybroker server with URL {key_request_url}" - ); - } + log::info!( + "Requesting key named '{key_name}' from the keybroker server with URL {key_request_url}" + ); // Make the first API call to request the key. match self.client.post(&key_request_url).json(&key_request).send() { @@ -318,9 +306,7 @@ impl KeyBrokerClient { evidence_submission_url: &str, evidence: &[u8], ) -> Result> { - if self.verbose { - println!("Submitting evidence to URL {evidence_submission_url}") - } + log::info!("Submitting evidence to URL {evidence_submission_url}"); // Make the second API call to submit the evidence. match self @@ -411,7 +397,7 @@ impl KeyBrokerClient { }; // Produce the evidence. - let evidence = match evidence_provider.get_evidence(&data.challenge, self.verbose) { + let evidence = match evidence_provider.get_evidence(&data.challenge) { Ok(evidence) => evidence, Err(error) => { // TODO: we may want to notify the keybroker server that something went wrong on our side and that it diff --git a/rust-keybroker/keybroker-server/Cargo.toml b/rust-keybroker/keybroker-server/Cargo.toml index c021248..6728f04 100644 --- a/rust-keybroker/keybroker-server/Cargo.toml +++ b/rust-keybroker/keybroker-server/Cargo.toml @@ -26,3 +26,5 @@ regorus = "0.2.5" serde_json = "1.0.128" anyhow = "1.0.89" phf = "0.11.2" +log = { version = "0.4.22", features = ["std", "serde"] } +stderrlog = "0.6.0" diff --git a/rust-keybroker/keybroker-server/src/challenge.rs b/rust-keybroker/keybroker-server/src/challenge.rs index a41486f..aa33a86 100644 --- a/rust-keybroker/keybroker-server/src/challenge.rs +++ b/rust-keybroker/keybroker-server/src/challenge.rs @@ -45,7 +45,6 @@ pub struct Challenge { pub struct Challenger { challenge_table: HashMap, rng: StdRng, - pub verbose: bool, } // This is the challenge value from from https://git.trustedfirmware.org/TF-M/tf-m-tools/+/refs/heads/main/iat-verifier/tests/data/cca_example_token.cbor @@ -63,7 +62,6 @@ impl Challenger { Challenger { challenge_table: HashMap::new(), rng: StdRng::from_entropy(), - verbose: false, } } @@ -101,16 +99,16 @@ impl Challenger { self.challenge_table.insert(challenge_id, challenge.clone()); - if self.verbose { - println!("Created challenge:"); - println!(" - challenge_id: {}", challenge_id); - println!(" - key_id: {}", challenge.key_id); - println!( - " - challenge value ({} bytes): {:02x?}", - challenge.challenge_value.len(), - challenge.challenge_value - ); - } + log::info!( + "Created challenge:\n\ + - challenge_id: {}\n\ + - key_id: {}\n\ + - challenge value ({} bytes): {:02x?}", + challenge_id, + challenge.key_id, + challenge.challenge_value.len(), + challenge.challenge_value + ); challenge } diff --git a/rust-keybroker/keybroker-server/src/main.rs b/rust-keybroker/keybroker-server/src/main.rs index a638889..d0d0c1f 100644 --- a/rust-keybroker/keybroker-server/src/main.rs +++ b/rust-keybroker/keybroker-server/src/main.rs @@ -42,9 +42,7 @@ async fn request_key( data.endpoint, challenge.challenge_id ); - if data.args.verbose { - println!("Created attestation challenge at {}", location); - } + log::info!("Created attestation challenge at {}", location); HttpResponse::Created() .append_header((http::header::LOCATION, location)) @@ -168,9 +166,13 @@ struct Args { #[arg(short, long, default_value_t = false)] mock_challenge: bool, - /// Set the server verbosity + /// Increase verbosity + #[arg(short, long, action = clap::ArgAction::Count)] + verbosity: u8, + + /// Silence all output #[arg(short, long, default_value_t = false)] - verbose: bool, + quiet: bool, /// File containing a JSON array with base64-encoded known-good RIM values #[arg(long, default_value = "reference-values.json")] @@ -188,9 +190,14 @@ struct ServerState { async fn main() -> std::io::Result<()> { let args = Args::parse(); + stderrlog::new() + .quiet(args.quiet) + .verbosity(1 + usize::from(args.verbosity)) + .init() + .unwrap(); + let mut keystore = KeyStore::new(); - let mut challenger = Challenger::new(); - challenger.verbose = args.verbose; + let challenger = Challenger::new(); // TODO: Just storing one hard-coded item in the store. Would be better to read from an input file. keystore.store_key(