diff --git a/rust-keybroker/keybroker-app/Cargo.toml b/rust-keybroker/keybroker-app/Cargo.toml index c78734f..a215d06 100644 --- a/rust-keybroker/keybroker-app/Cargo.toml +++ b/rust-keybroker/keybroker-app/Cargo.toml @@ -12,3 +12,4 @@ categories = ["cryptography", "hardware-support"] [dependencies] keybroker-client = { path = "../keybroker-client" } +clap = { version = "=4.3.24", features = ["derive", "std"] } \ No newline at end of file diff --git a/rust-keybroker/keybroker-app/src/main.rs b/rust-keybroker/keybroker-app/src/main.rs index dbb2a8a..6ea98fb 100644 --- a/rust-keybroker/keybroker-app/src/main.rs +++ b/rust-keybroker/keybroker-app/src/main.rs @@ -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) } diff --git a/rust-keybroker/keybroker-client/Cargo.toml b/rust-keybroker/keybroker-client/Cargo.toml index b4214c7..e2a6bcf 100644 --- a/rust-keybroker/keybroker-client/Cargo.toml +++ b/rust-keybroker/keybroker-client/Cargo.toml @@ -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"} \ No newline at end of file diff --git a/rust-keybroker/keybroker-client/src/error.rs b/rust-keybroker/keybroker-client/src/error.rs new file mode 100644 index 0000000..5dbc171 --- /dev/null +++ b/rust-keybroker/keybroker-client/src/error.rs @@ -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 = std::result::Result; diff --git a/rust-keybroker/keybroker-client/src/lib.rs b/rust-keybroker/keybroker-client/src/lib.rs index 7c2006e..02fe64d 100644 --- a/rust-keybroker/keybroker-client/src/lib.rs +++ b/rust-keybroker/keybroker-client/src/lib.rs @@ -1,17 +1,457 @@ // Copyright 2024 Contributors to the Veraison project. // SPDX-License-Identifier: Apache-2.0 -pub fn add(left: usize, right: usize) -> usize { - left + right +use base64::engine::general_purpose::URL_SAFE_NO_PAD; +use base64::prelude::*; +use keybroker_common::{ + BackgroundCheckKeyRequest, ErrorInformation, PublicWrappingKey, WrappedKeyData, +}; +use reqwest::StatusCode; +use rsa::{traits::PublicKeyParts, BigUint, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey}; +use tsm_report::{TsmReportData, TsmReportPath, TsmReportProvider}; + +pub mod error; +use crate::error::Error as KeybrokerError; +use crate::error::Result; +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>; +} + +/// The CCA example token. +const CCA_EXAMPLE_TOKEN: &[u8] = &[ + 0xd9, 0x01, 0x8f, 0xa2, 0x19, 0xac, 0xca, 0x59, 0x05, 0xe7, 0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, + 0x22, 0xa0, 0x59, 0x05, 0x7a, 0xa9, 0x19, 0x01, 0x09, 0x78, 0x1c, 0x68, 0x74, 0x74, 0x70, 0x3a, + 0x2f, 0x2f, 0x61, 0x72, 0x6d, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x43, 0x41, 0x2d, 0x53, 0x53, + 0x44, 0x2f, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x0a, 0x58, 0x20, 0xb5, 0x97, 0x3c, 0xb6, 0x8b, 0xaa, + 0x9f, 0xc5, 0x55, 0x58, 0x78, 0x6b, 0x7e, 0xc6, 0x7f, 0x69, 0xe4, 0x0d, 0xf5, 0xba, 0x5a, 0xa9, + 0x21, 0xcd, 0x0c, 0x27, 0xf4, 0x05, 0x87, 0xa0, 0x11, 0xea, 0x19, 0x09, 0x5c, 0x58, 0x20, 0x7f, + 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, + 0x01, 0x00, 0x58, 0x21, 0x01, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, + 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10, 0x1f, 0x1e, 0x1d, + 0x1c, 0x1b, 0x1a, 0x19, 0x18, 0x19, 0x09, 0x61, 0x44, 0xcf, 0xcf, 0xcf, 0xcf, 0x19, 0x09, 0x5b, + 0x19, 0x30, 0x03, 0x19, 0x09, 0x62, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0x19, 0x09, + 0x60, 0x78, 0x3a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x69, + 0x73, 0x6f, 0x6e, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x2e, 0x77, 0x65, 0x6c, + 0x6c, 0x2d, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2f, 0x76, 0x65, 0x72, 0x61, 0x69, 0x73, 0x6f, 0x6e, + 0x2f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x19, 0x09, 0x5f, + 0x8d, 0xa4, 0x01, 0x69, 0x52, 0x53, 0x45, 0x5f, 0x42, 0x4c, 0x31, 0x5f, 0x32, 0x05, 0x58, 0x20, + 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, + 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, + 0x02, 0x58, 0x20, 0x9a, 0x27, 0x1f, 0x2a, 0x91, 0x6b, 0x0b, 0x6e, 0xe6, 0xce, 0xcb, 0x24, 0x26, + 0xf0, 0xb3, 0x20, 0x6e, 0xf0, 0x74, 0x57, 0x8b, 0xe5, 0x5d, 0x9b, 0xc9, 0x4f, 0x6f, 0x3f, 0xe3, + 0xab, 0x86, 0xaa, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x67, 0x52, + 0x53, 0x45, 0x5f, 0x42, 0x4c, 0x32, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, + 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, + 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x53, 0xc2, 0x34, 0xe5, + 0xe8, 0x47, 0x2b, 0x6a, 0xc5, 0x1c, 0x1a, 0xe1, 0xca, 0xb3, 0xfe, 0x06, 0xfa, 0xd0, 0x53, 0xbe, + 0xb8, 0xeb, 0xfd, 0x89, 0x77, 0xb0, 0x10, 0x65, 0x5b, 0xfd, 0xd3, 0xc3, 0x06, 0x67, 0x73, 0x68, + 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x65, 0x52, 0x53, 0x45, 0x5f, 0x53, 0x05, 0x58, 0x20, + 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, + 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, + 0x02, 0x58, 0x20, 0x11, 0x21, 0xcf, 0xcc, 0xd5, 0x91, 0x3f, 0x0a, 0x63, 0xfe, 0xc4, 0x0a, 0x6f, + 0xfd, 0x44, 0xea, 0x64, 0xf9, 0xdc, 0x13, 0x5c, 0x66, 0x63, 0x4b, 0xa0, 0x01, 0xd1, 0x0b, 0xcf, + 0x43, 0x02, 0xa2, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x66, 0x41, + 0x50, 0x5f, 0x42, 0x4c, 0x31, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, + 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, + 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x15, 0x71, 0xb5, 0xec, 0x78, + 0xbd, 0x68, 0x51, 0x2b, 0xf7, 0x83, 0x0b, 0xb6, 0xa2, 0xa4, 0x4b, 0x20, 0x47, 0xc7, 0xdf, 0x57, + 0xbc, 0xe7, 0x9e, 0xb8, 0xa1, 0xc0, 0xe5, 0xbe, 0xa0, 0xa5, 0x01, 0x06, 0x67, 0x73, 0x68, 0x61, + 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x66, 0x41, 0x50, 0x5f, 0x42, 0x4c, 0x32, 0x05, 0x58, 0x20, + 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, + 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, + 0x02, 0x58, 0x20, 0x10, 0x15, 0x9b, 0xaf, 0x26, 0x2b, 0x43, 0xa9, 0x2d, 0x95, 0xdb, 0x59, 0xda, + 0xe1, 0xf7, 0x2c, 0x64, 0x51, 0x27, 0x30, 0x16, 0x61, 0xe0, 0xa3, 0xce, 0x4e, 0x38, 0xb2, 0x95, + 0xa9, 0x7c, 0x58, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x67, 0x53, + 0x43, 0x50, 0x5f, 0x42, 0x4c, 0x31, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, + 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, + 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x10, 0x12, 0x2e, 0x85, + 0x6b, 0x3f, 0xcd, 0x49, 0xf0, 0x63, 0x63, 0x63, 0x17, 0x47, 0x61, 0x49, 0xcb, 0x73, 0x0a, 0x1a, + 0xa1, 0xcf, 0xaa, 0xd8, 0x18, 0x55, 0x2b, 0x72, 0xf5, 0x6d, 0x6f, 0x68, 0x06, 0x67, 0x73, 0x68, + 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x67, 0x53, 0x43, 0x50, 0x5f, 0x42, 0x4c, 0x32, 0x05, + 0x58, 0x20, 0xf1, 0x4b, 0x49, 0x87, 0x90, 0x4b, 0xcb, 0x58, 0x14, 0xe4, 0x45, 0x9a, 0x05, 0x7e, + 0xd4, 0xd2, 0x0f, 0x58, 0xa6, 0x33, 0x15, 0x22, 0x88, 0xa7, 0x61, 0x21, 0x4d, 0xcd, 0x28, 0x78, + 0x0b, 0x56, 0x02, 0x58, 0x20, 0xaa, 0x67, 0xa1, 0x69, 0xb0, 0xbb, 0xa2, 0x17, 0xaa, 0x0a, 0xa8, + 0x8a, 0x65, 0x34, 0x69, 0x20, 0xc8, 0x4c, 0x42, 0x44, 0x7c, 0x36, 0xba, 0x5f, 0x7e, 0xa6, 0x5f, + 0x42, 0x2c, 0x1f, 0xe5, 0xd8, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, + 0x67, 0x41, 0x50, 0x5f, 0x42, 0x4c, 0x33, 0x31, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, + 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, + 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x2e, 0x6d, + 0x31, 0xa5, 0x98, 0x3a, 0x91, 0x25, 0x1b, 0xfa, 0xe5, 0xae, 0xfa, 0x1c, 0x0a, 0x19, 0xd8, 0xba, + 0x3c, 0xf6, 0x01, 0xd0, 0xe8, 0xa7, 0x06, 0xb4, 0xcf, 0xa9, 0x66, 0x1a, 0x6b, 0x8a, 0x06, 0x67, + 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x63, 0x52, 0x4d, 0x4d, 0x05, 0x58, 0x20, + 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, + 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, + 0x02, 0x58, 0x20, 0xa1, 0xfb, 0x50, 0xe6, 0xc8, 0x6f, 0xae, 0x16, 0x79, 0xef, 0x33, 0x51, 0x29, + 0x6f, 0xd6, 0x71, 0x34, 0x11, 0xa0, 0x8c, 0xf8, 0xdd, 0x17, 0x90, 0xa4, 0xfd, 0x05, 0xfa, 0xe8, + 0x68, 0x81, 0x64, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x69, 0x48, + 0x57, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, + 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, + 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x1a, 0x25, + 0x24, 0x02, 0x97, 0x2f, 0x60, 0x57, 0xfa, 0x53, 0xcc, 0x17, 0x2b, 0x52, 0xb9, 0xff, 0xca, 0x69, + 0x8e, 0x18, 0x31, 0x1f, 0xac, 0xd0, 0xf3, 0xb0, 0x6e, 0xca, 0xae, 0xf7, 0x9e, 0x17, 0x06, 0x67, + 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0xa4, 0x01, 0x69, 0x46, 0x57, 0x5f, 0x43, 0x4f, 0x4e, + 0x46, 0x49, 0x47, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, + 0x8b, 0x15, 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, + 0xc0, 0xfa, 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x9a, 0x92, 0xad, 0xbc, 0x0c, 0xee, 0x38, + 0xef, 0x65, 0x8c, 0x71, 0xce, 0x1b, 0x1b, 0xf8, 0xc6, 0x56, 0x68, 0xf1, 0x66, 0xbf, 0xb2, 0x13, + 0x64, 0x4c, 0x89, 0x5c, 0xcb, 0x1a, 0xd0, 0x7a, 0x25, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, + 0x35, 0x36, 0xa4, 0x01, 0x6c, 0x54, 0x42, 0x5f, 0x46, 0x57, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x47, 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, + 0xa2, 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, + 0x97, 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0x23, 0x89, 0x03, 0x18, 0x0c, 0xc1, 0x04, 0xec, 0x2c, + 0x5d, 0x8b, 0x3f, 0x20, 0xc5, 0xbc, 0x61, 0xb3, 0x89, 0xec, 0x0a, 0x96, 0x7d, 0xf8, 0xcc, 0x20, + 0x8c, 0xdc, 0x7c, 0xd4, 0x54, 0x17, 0x4f, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, + 0xa4, 0x01, 0x6d, 0x53, 0x4f, 0x43, 0x5f, 0x46, 0x57, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, + 0x05, 0x58, 0x20, 0x53, 0x78, 0x79, 0x63, 0x07, 0x53, 0x5d, 0xf3, 0xec, 0x8d, 0x8b, 0x15, 0xa2, + 0xe2, 0xdc, 0x56, 0x41, 0x41, 0x9c, 0x3d, 0x30, 0x60, 0xcf, 0xe3, 0x22, 0x38, 0xc0, 0xfa, 0x97, + 0x3f, 0x7a, 0xa3, 0x02, 0x58, 0x20, 0xe6, 0xc2, 0x1e, 0x8d, 0x26, 0x0f, 0xe7, 0x18, 0x82, 0xde, + 0xbd, 0xb3, 0x39, 0xd2, 0x40, 0x2a, 0x2c, 0xa7, 0x64, 0x85, 0x29, 0xbc, 0x23, 0x03, 0xf4, 0x86, + 0x49, 0xbc, 0xe0, 0x38, 0x00, 0x17, 0x06, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0x58, + 0x60, 0x21, 0x51, 0x20, 0x92, 0xd6, 0xd0, 0x2a, 0xe6, 0xbe, 0x2f, 0xe3, 0x93, 0x0e, 0xa5, 0x1f, + 0xd6, 0x98, 0x96, 0x32, 0x24, 0x56, 0xe9, 0xdf, 0xc7, 0x32, 0x5e, 0x0b, 0x78, 0x68, 0xb6, 0x90, + 0x73, 0x2a, 0x0c, 0x0f, 0x07, 0x77, 0xc1, 0x15, 0x40, 0x4b, 0xe1, 0xfc, 0x83, 0x9b, 0x7d, 0x30, + 0x4f, 0x4f, 0xe6, 0xfa, 0x46, 0xae, 0x12, 0xa3, 0x08, 0x3a, 0xcf, 0x24, 0x06, 0x67, 0x91, 0x06, + 0xbf, 0xae, 0x50, 0x31, 0x79, 0xdd, 0x50, 0x33, 0x49, 0x12, 0xbf, 0xc6, 0xda, 0x33, 0x6d, 0xd6, + 0x18, 0x25, 0x43, 0x54, 0x4d, 0xb5, 0x88, 0xd6, 0xae, 0x67, 0x35, 0x7a, 0xfd, 0xb0, 0x5f, 0x95, + 0xb7, 0x19, 0xac, 0xd1, 0x59, 0x02, 0x23, 0xd2, 0x84, 0x44, 0xa1, 0x01, 0x38, 0x22, 0xa0, 0x59, + 0x01, 0xb6, 0xa7, 0x0a, 0x58, 0x40, 0x6e, 0x86, 0xd6, 0xd9, 0x7c, 0xc7, 0x13, 0xbc, 0x6d, 0xd4, + 0x3d, 0xbc, 0xe4, 0x91, 0xa6, 0xb4, 0x03, 0x11, 0xc0, 0x27, 0xa8, 0xbf, 0x85, 0xa3, 0x9d, 0xa6, + 0x3e, 0x9c, 0xe4, 0x4c, 0x13, 0x2a, 0x8a, 0x11, 0x9d, 0x29, 0x6f, 0xae, 0x6a, 0x69, 0x99, 0xe9, + 0xbf, 0x3e, 0x44, 0x71, 0xb0, 0xce, 0x01, 0x24, 0x5d, 0x88, 0x94, 0x24, 0xc3, 0x1e, 0x89, 0x79, + 0x3b, 0x3b, 0x1d, 0x6b, 0x15, 0x04, 0x19, 0xac, 0xcc, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, + 0x36, 0x19, 0xac, 0xd0, 0x67, 0x73, 0x68, 0x61, 0x2d, 0x32, 0x35, 0x36, 0x19, 0xac, 0xcb, 0x58, + 0x40, 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, + 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, + 0x31, 0x33, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67, 0x73, 0x2e, 0x54, 0x68, 0x65, + 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, + 0x20, 0x19, 0xac, 0xcd, 0x58, 0x61, 0x04, 0x76, 0xf9, 0x88, 0x09, 0x1b, 0xe5, 0x85, 0xed, 0x41, + 0x80, 0x1a, 0xec, 0xfa, 0xb8, 0x58, 0x54, 0x8c, 0x63, 0x05, 0x7e, 0x16, 0xb0, 0xe6, 0x76, 0x12, + 0x0b, 0xbd, 0x0d, 0x2f, 0x9c, 0x29, 0xe0, 0x56, 0xc5, 0xd4, 0x1a, 0x01, 0x30, 0xeb, 0x9c, 0x21, + 0x51, 0x78, 0x99, 0xdc, 0x23, 0x14, 0x6b, 0x28, 0xe1, 0xb0, 0x62, 0xbd, 0x3e, 0xa4, 0xb3, 0x15, + 0xfd, 0x21, 0x9f, 0x1c, 0xbb, 0x52, 0x8c, 0xb6, 0xe7, 0x4c, 0xa4, 0x9b, 0xe1, 0x67, 0x73, 0x73, + 0x4f, 0x61, 0xa1, 0xca, 0x61, 0x03, 0x1b, 0x2b, 0xbf, 0x3d, 0x91, 0x8f, 0x2f, 0x94, 0xff, 0xc4, + 0x22, 0x8e, 0x50, 0x91, 0x95, 0x44, 0xae, 0x19, 0xac, 0xce, 0x58, 0x20, 0x31, 0x13, 0x14, 0xab, + 0x73, 0x62, 0x03, 0x50, 0xcf, 0x75, 0x88, 0x34, 0xae, 0x5c, 0x65, 0xd9, 0xe8, 0xc2, 0xdc, 0x7f, + 0xeb, 0xe6, 0xe7, 0xd9, 0x65, 0x4b, 0xbe, 0x86, 0x4e, 0x30, 0x0d, 0x49, 0x19, 0xac, 0xcf, 0x84, + 0x58, 0x20, 0x24, 0xd5, 0xb0, 0xa2, 0x96, 0xcc, 0x05, 0xcb, 0xd8, 0x06, 0x8c, 0x50, 0x67, 0xc5, + 0xbd, 0x47, 0x3b, 0x77, 0x0d, 0xda, 0x6a, 0xe0, 0x82, 0xfe, 0x3b, 0xa3, 0x0a, 0xbe, 0x3f, 0x9a, + 0x6a, 0xb1, 0x58, 0x20, 0x78, 0x8f, 0xc0, 0x90, 0xbf, 0xc6, 0xb8, 0xed, 0x90, 0x31, 0x52, 0xba, + 0x84, 0x14, 0xe7, 0x3d, 0xaf, 0x5b, 0x8c, 0x7b, 0xb1, 0xe7, 0x9a, 0xd5, 0x02, 0xab, 0x06, 0x99, + 0xb6, 0x59, 0xed, 0x16, 0x58, 0x20, 0xda, 0xc4, 0x6a, 0x58, 0x41, 0x5d, 0xc3, 0xa0, 0x0d, 0x7a, + 0x74, 0x18, 0x52, 0x00, 0x8e, 0x9c, 0xae, 0x64, 0xf5, 0x2d, 0x03, 0xb9, 0xf7, 0x6d, 0x76, 0xf4, + 0xb3, 0x64, 0x4f, 0xef, 0xc4, 0x16, 0x58, 0x20, 0x32, 0xc6, 0xaf, 0xc6, 0x27, 0xe5, 0x55, 0x85, + 0xc0, 0x31, 0x55, 0x35, 0x9f, 0x33, 0x1a, 0x0e, 0x22, 0x5f, 0x68, 0x40, 0xdb, 0x94, 0x7d, 0xd9, + 0x6e, 0xfa, 0xb8, 0x1b, 0xe2, 0x67, 0x19, 0x39, 0x58, 0x60, 0x6e, 0xaf, 0x8c, 0x12, 0xcd, 0x0f, + 0xc0, 0xd6, 0x2b, 0x3d, 0x3b, 0x84, 0xa1, 0x6a, 0x6b, 0x76, 0x28, 0xdb, 0xc8, 0xe3, 0x46, 0xfb, + 0x9f, 0x09, 0x44, 0xda, 0x5a, 0x81, 0xd0, 0x09, 0x32, 0x33, 0x9c, 0x6d, 0x6b, 0xd1, 0xf8, 0x91, + 0xea, 0x64, 0xc0, 0xb0, 0x42, 0xf5, 0x1c, 0xa3, 0x31, 0x87, 0xed, 0xbb, 0xe7, 0xf0, 0xa3, 0x95, + 0x98, 0x55, 0x06, 0x89, 0x09, 0x3b, 0x0d, 0x99, 0xbb, 0xf3, 0x8e, 0x93, 0x2c, 0x5e, 0x2e, 0x18, + 0x26, 0xc4, 0xdb, 0xc3, 0xed, 0x3e, 0x49, 0x44, 0x18, 0xb0, 0x4f, 0x79, 0x1d, 0x88, 0xda, 0x64, + 0xec, 0x3a, 0x3f, 0x16, 0x50, 0x96, 0x51, 0xe7, 0x30, 0x97, +]; + +/// An EvidenceProvider mock. +/// +/// The CcaExampleToken implementation of the EvidenceProvider trait is really +/// nothing but a mock, ignoring the challenge and returning the static evidence +/// that is used in the CCA exemple. This is useful during bring-up or debug to +/// un-tie the link between the key request and the evidence submission. +pub struct CcaExampleToken {} + +impl EvidenceProvider for CcaExampleToken { + fn get_evidence(&self, _challenge: &str, _verbose: bool) -> Result> { + Ok(CCA_EXAMPLE_TOKEN.to_vec()) + } } -#[cfg(test)] -mod tests { - use super::*; +/// A TSM attestation report implementation of EvidenceProvider. +/// +/// The TsmAttestationReport implementation of the EvidenceProvider trait uses +/// Linux's TSM attestation report infrastructure to construct an evidence from +/// a challenge. +pub struct TsmAttestationReport {} + +impl EvidenceProvider for TsmAttestationReport { + fn get_evidence(&self, challenge: &str, verbose: bool) -> 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); + } + if challenge.len() != 64 { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::ChallengeLength(64, challenge.len()), + )); + }; + match tsm_report_path.attestation_report(TsmReportData::Cca(challenge)) { + Ok(ar) => Ok(ar), + Err(error) => Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::TSMReport(error), + )), + } + } + Err(error) => Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::Base64Decode( + "the attestation challenge".to_string(), + format!("{error:?}"), + ), + )), + }, + Err(error) => Err(KeybrokerError::RuntimeError(RuntimeErrorKind::TSMReport( + error, + ))), + } + } +} + +#[derive(Debug)] +struct AttestationChallenge { + pub challenge: String, + pub evidence_submission_url: String, +} + +/// The KeyBrokerSession models the communication with a keybroker server. +#[derive(Debug)] +pub struct KeyBrokerClient { + /// The client this session will use to interact with the keybroker server + /// over HTTP with post calls. A blocking client is used for simplicity. + client: reqwest::blocking::Client, + + /// 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 { + KeyBrokerClient { + client: reqwest::blocking::Client::new(), + keybroker_url_base: endpoint.to_string(), + verbose, + } + } + + /// The first API call to request the key. This gets all the required + /// attestation challenge material: the challenge it self, and the url + /// where to submit the evidence. + fn request_key( + self: &KeyBrokerClient, + key_name: &str, + pub_key: &RsaPublicKey, + ) -> Result { + // Create base64 strings for the public key modulus and exponent parts. + let k_mod_base64 = URL_SAFE_NO_PAD.encode(BigUint::to_bytes_be(pub_key.n())); + let k_exp_base64 = URL_SAFE_NO_PAD.encode(BigUint::to_bytes_be(pub_key.e())); + + // ... and turn them into an API-level input + let key_request = BackgroundCheckKeyRequest { + pubkey: PublicWrappingKey { + kty: "RSA".to_string(), + alg: "RSA1_5".to_string(), + n: k_mod_base64, + e: k_exp_base64, + }, + }; + + // 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}" + ); + } + + // Make the first API call to request the key. + match self.client.post(&key_request_url).json(&key_request).send() { + Ok(resp) => { + let evidence_submission_url = match resp.headers().get(reqwest::header::LOCATION) { + Some(url) => url.to_str().unwrap().to_owned(), + None => { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::MissingLocation, + )) + } + }; + + let ac = match resp.json::() { + Ok(ac) => ac, + Err(error) => { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::JSONDeserialize( + "the attestation challenge".to_string(), + format!("{error:?}"), + ), + )) + } + }; + + Ok(AttestationChallenge { + challenge: ac.challenge, + evidence_submission_url, + }) + } + Err(error) => Err(KeybrokerError::RuntimeError(RuntimeErrorKind::HTTPConnect( + key_request_url, + format!("{error:?}"), + ))), + } + } + + /// Submit the evidence. + /// In case of success, this returns the decoded key from the server. + fn submit_evidence( + self: &KeyBrokerClient, + evidence_submission_url: &str, + evidence: &[u8], + ) -> Result> { + if self.verbose { + println!("Submitting evidence to URL {evidence_submission_url}") + } + + // Make the second API call to submit the evidence. + match self + .client + .post(evidence_submission_url) + .header( + reqwest::header::CONTENT_TYPE, + "application/eat-collection; profile=\"http://arm.com/CCA-SSD/1.0.0\"", + ) + .body(URL_SAFE_NO_PAD.encode(evidence)) + .send() + { + Ok(resp) => { + let wrapped_data_name = "the wrapped data from the server".to_string(); + match resp.status() { + // Assume first that we are following the happy path: our evidence was "accepted". + StatusCode::OK => { + let wrapped_data = match resp.json::() { + Ok(wrapped_data) => wrapped_data, + Err(error) => { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::JSONDeserialize( + "the evidence WrappedKeyData".to_string(), + format!("{error:?}"), + ), + )) + } + }; + match URL_SAFE_NO_PAD.decode(wrapped_data.data) { + Ok(ciphertext) => Ok(ciphertext), + Err(error) => Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::Base64Decode( + wrapped_data_name, + format!("{error:?}"), + ), + )), + } + } + + // Our evidence has been rejected for some "good" reasons. + StatusCode::FORBIDDEN => { + let wrapped_data = match resp.json::() { + Ok(wrapped_data) => wrapped_data, + Err(error) => { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::JSONDeserialize( + "the evidence ErrorInformation".to_string(), + format!("{error:?}"), + ), + )) + } + }; + Err(crate::error::Error::AttestationFailure( + wrapped_data.r#type, + wrapped_data.detail, + )) + } + + // We have a genuine and/or unhandled error :-() + status => Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::HTTPResponse(format!("{status:?}")), + )), + } + } + + Err(error) => Err(KeybrokerError::RuntimeError(RuntimeErrorKind::HTTPConnect( + evidence_submission_url.to_string(), + format!("{error:?}"), + ))), + } + } + + /// Get the wrapped key, decryption left to the caller. + pub fn get_wrapped_key( + self: &KeyBrokerClient, + key_name: &str, + evidence_provider: &EP, + pub_key: &RsaPublicKey, + ) -> Result> { + // First API call: request the challenge. + let data = match self.request_key(key_name, pub_key) { + Ok(data) => data, + Err(error) => { + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::ChallengeRetrieval(format!("{error:?}")), + )) + } + }; + + // Produce the evidence. + let evidence = match evidence_provider.get_evidence(&data.challenge, self.verbose) { + Ok(evidence) => evidence, + Err(error) => { + // TODO: we may want to notify the keybroker server that something went wrong on our side and that it + // should release any resource it has allocated for us. This could possibly be done using some + // form of "abandon" request, or we could simulate this by submitting a bogus evidence (which will + // not give a successful attestation, but that's expected). OTOH, the server will also need to + // have some form of timeout associated with all the key requests and have some garbage collection + // pass to be run from time to time. A well behaved client could be kind though and notify the + // keybroker server. + return Err(KeybrokerError::RuntimeError( + RuntimeErrorKind::EvidenceGeneration(format!("{error:?}")), + )); + } + }; + + // Second API call: submit the evidence, and return the attestation result. + self.submit_evidence(&data.evidence_submission_url, &evidence) + } + + /// This returns the plain text. + pub fn get_key( + self: &KeyBrokerClient, + key_name: &str, + evidence_provider: &EP, + ) -> Result> { + // Create an ephemeral wrapping key-pair for our own use. + let mut rng = rand::thread_rng(); + let priv_key = RsaPrivateKey::new(&mut rng, 1024 /* bits */) + .expect("Failed to generate ephemeral wrapping key."); + let pub_key = RsaPublicKey::from(&priv_key); - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); + match self.get_wrapped_key(key_name, evidence_provider, &pub_key) { + Ok(ciphertext) => match priv_key.decrypt(Pkcs1v15Encrypt, &ciphertext) { + Ok(plaintext) => Ok(plaintext), + Err(error) => Err(KeybrokerError::RuntimeError(RuntimeErrorKind::Decrypt( + "ciphertext".to_string(), + format!("{error:?}"), + ))), + }, + other => other, + } } } diff --git a/rust-keybroker/keybroker-server/src/challenge.rs b/rust-keybroker/keybroker-server/src/challenge.rs index a71745c..a41486f 100644 --- a/rust-keybroker/keybroker-server/src/challenge.rs +++ b/rust-keybroker/keybroker-server/src/challenge.rs @@ -18,6 +18,7 @@ //! use crate::error::Result; use keybroker_common::PublicWrappingKey; +use rand::{rngs::StdRng, Rng, SeedableRng}; use std::collections::HashMap; /// Represents a single challenge, and provides the challenge value ("nonce") while also remembering the information @@ -43,6 +44,8 @@ pub struct Challenge { /// This structure provides a hash map of challenges, keyed on the integer challenge identifier. 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 @@ -59,6 +62,8 @@ impl Challenger { pub fn new() -> Challenger { Challenger { challenge_table: HashMap::new(), + rng: StdRng::from_entropy(), + verbose: false, } } @@ -70,27 +75,43 @@ impl Challenger { &mut self, key_id: &str, wrapping_key: &PublicWrappingKey, + mock_challenge: bool, ) -> Challenge { // All challenges are given random u32 identities - let mut challenge_id: u32 = rand::random(); + let mut challenge_id: u32 = self.rng.gen(); // Simple lightweight collision avoidance - probably not needed given u32 distribution space, // but it's easy to do. Also allows us to throw out zero if we get it. while challenge_id == 0 || self.challenge_table.contains_key(&challenge_id) { - challenge_id = rand::random(); + challenge_id = self.rng.gen(); } let challenge = Challenge { challenge_id, key_id: key_id.to_owned(), wrapping_key: wrapping_key.clone(), - // TODO: We should create a random nonce here. The use of this mock value allows the - // server to be tested with a hard-coded example attestation token during development. - challenge_value: CCA_EXAMPLE_TOKEN_NONCE.to_vec(), + challenge_value: if mock_challenge { + CCA_EXAMPLE_TOKEN_NONCE.to_vec() + } else { + let mut v: Vec = vec![0; 64]; + self.rng.fill(&mut v[..]); + v + }, }; 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 + ); + } + challenge } diff --git a/rust-keybroker/keybroker-server/src/main.rs b/rust-keybroker/keybroker-server/src/main.rs index e24aba1..d2571f8 100644 --- a/rust-keybroker/keybroker-server/src/main.rs +++ b/rust-keybroker/keybroker-server/src/main.rs @@ -25,7 +25,8 @@ async fn request_key( // Get a new challenge from the challenger. let mut challenger = data.challenger.lock().expect("Poisoned challenger lock."); - let challenge = challenger.create_challenge(&key_id, &key_request.pubkey); + let challenge = + challenger.create_challenge(&key_id, &key_request.pubkey, data.args.mock_challenge); // TODO: The "accept" list is being hardcoded for Arm CCA here - it should come from the verifier. let attestation_challenge = AttestationChallenge { @@ -36,12 +37,13 @@ async fn request_key( }; let location = format!( - "{}:{}/keys/v1/evidence/{}", - data.args.baseurl, data.args.port, challenge.challenge_id + "{}/keys/v1/evidence/{}", + data.endpoint, challenge.challenge_id ); - // TODO: Remove this println - tracer message for dev purposes only. - println!("Created attestation challenge at {}", location); + if data.args.verbose { + println!("Created attestation challenge at {}", location); + } HttpResponse::Created() .append_header((http::header::LOCATION, location)) @@ -118,7 +120,7 @@ async fn submit_evidence( } else { let error_info = ErrorInformation { r#type: "AttestationFailure".to_string(), - detail: "The attestation result is not in policy..".to_string(), + detail: "The attestation result is not in policy.".to_string(), }; HttpResponse::Forbidden().json(error_info) @@ -127,7 +129,7 @@ async fn submit_evidence( Err(_) => { let error_info = ErrorInformation { r#type: "AttestationFailure".to_string(), - detail: "No attestation result was obtained..".to_string(), + detail: "No attestation result was obtained.".to_string(), }; HttpResponse::Forbidden().json(error_info) @@ -139,19 +141,37 @@ async fn submit_evidence( #[derive(Clone, Parser, Debug)] #[command(version, about, long_about = None)] struct Args { - /// The port on which the web server will listen + /// The interface on which this server will listen (use 0.0.0.0 to listen on all interfaces) + #[arg(short, long, default_value = "127.0.0.1")] + addr: String, + + /// The port on which this server will listen #[arg(short, long, default_value_t = 8088)] port: u16, - #[arg(short, long, default_value = "http://127.0.0.1")] - baseurl: String, + /// 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. + #[arg(short, long, default_value = None)] + endpoint: Option, - #[arg(short, long, default_value = "http://veraison.test.linaro.org:8080")] + /// The URL where the verifier can be reached + #[arg(long, default_value = "http://veraison.test.linaro.org:8080")] verifier: String, + + /// Use the static CCA example token nonce instead of a randomly generated one + #[arg(short, long, default_value_t = false)] + mock_challenge: bool, + + /// Set the server verbosity + #[arg(short, long, default_value_t = false)] + verbose: bool, } struct ServerState { args: Args, + endpoint: String, keystore: Mutex, challenger: Mutex, } @@ -161,7 +181,8 @@ async fn main() -> std::io::Result<()> { let args = Args::parse(); let mut keystore = KeyStore::new(); - let challenger = Challenger::new(); + let mut challenger = Challenger::new(); + challenger.verbose = args.verbose; // TODO: Just storing one hard-coded item in the store. Would be better to read from an input file. keystore.store_key( @@ -171,6 +192,10 @@ async fn main() -> std::io::Result<()> { let server_state = ServerState { args: args.clone(), + endpoint: match args.endpoint { + Some(url) => format!("{}:{}", url, args.port), + None => format!("http://{}:{}", args.addr, args.port), + }, keystore: Mutex::new(keystore), challenger: Mutex::new(challenger), }; @@ -183,7 +208,7 @@ async fn main() -> std::io::Result<()> { .service(submit_evidence); App::new().app_data(app_data.clone()).service(scope) }) - .bind(("127.0.0.1", args.port))? + .bind((args.addr, args.port))? .run() .await }