From 2c6a5a6a33ac5b51b9df25c6fd76c57db06c7312 Mon Sep 17 00:00:00 2001 From: Arnaud de Grandmaison Date: Fri, 4 Oct 2024 16:09:36 +0200 Subject: [PATCH 1/3] feat: use Rust standard logging. This commit removes all the "println" that were in the repository to use Rust's standard "log" crate instead (which is maitained by the Rust core team). All the library / infrastructure parts of the keybroker-demo repository only use the "log::error", "log::warn", "log::info", "log::debug" functions from the logging facade. The actual executables (keybroker-server, keybroker-app) instantiate and configure an implementation of a logger. The stderrlog is used here as it is simple minimal logger, but https://docs.rs/log/latest/log/ lists many more available logging implementations. The keybroker-server and keyborker-app do use the same command line options with respect to logging control (verbose / quiet). The verbose switch can be specified multiple times to increase verbosity. Signed-off-by: Arnaud de Grandmaison --- rust-keybroker/keybroker-app/Cargo.toml | 4 ++- rust-keybroker/keybroker-app/src/main.rs | 22 ++++++++---- rust-keybroker/keybroker-client/Cargo.toml | 4 ++- rust-keybroker/keybroker-client/src/lib.rs | 34 ++++++------------- rust-keybroker/keybroker-server/Cargo.toml | 2 ++ .../keybroker-server/src/challenge.rs | 22 ++++++------ rust-keybroker/keybroker-server/src/main.rs | 21 ++++++++---- 7 files changed, 58 insertions(+), 51 deletions(-) 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( From 4cf16755700bbed8032de5cdb8851fab03ce41d0 Mon Sep 17 00:00:00 2001 From: Arnaud de Grandmaison Date: Mon, 7 Oct 2024 10:18:24 +0200 Subject: [PATCH 2/3] doc: improve documentation. This adds 2 sections on building and running the keybroker-demo executables. It also adds a section about logging and how the verbosity is controlled from the commadn line. Signed-off-by: Arnaud de Grandmaison --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/README.md b/README.md index caaff61..0f1c079 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 ../testdata/rims-matching.json +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 ... | \ No newline at end of file From 072ea3d478f5f22f47f245eed431149b64de8c14 Mon Sep 17 00:00:00 2001 From: Arnaud de Grandmaison Date: Mon, 7 Oct 2024 14:26:08 +0200 Subject: [PATCH 3/3] doc: update command line example. Use a more transparent way of passing the reference value to the keybroker-server in the example in the documentation. Signed-off-by: Arnaud de Grandmaison --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0f1c079..69cb66a 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ values). In a terminal, start `keybroker-server` with: ```console -$ target/debug/keybroker-server -v -m --reference-values ../testdata/rims-matching.json +$ 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 @@ -103,4 +103,4 @@ The mapping that has been implemented in `keybroker-server` and `keybroker-app` | 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 ... | \ No newline at end of file +| Trace | 4 | Enabled with `-vvv` or `-v -v -v` or ... |