diff --git a/examples/linux/src/main.rs b/examples/linux/src/main.rs index ef93446f..86b09d68 100644 --- a/examples/linux/src/main.rs +++ b/examples/linux/src/main.rs @@ -2,26 +2,29 @@ use core::iter::Enumerate; use embassy_executor::Spawner; -use embassy_time::{Duration, queue}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::mutex::Mutex; +use embassy_time::Duration; use embassy_time::Timer; use heapless::spsc::{Consumer, Producer, Queue}; use heimlig::client::api::Api; -use heimlig::common::jobs::{Request, Response}; +use heimlig::common::jobs::{Request, RequestType, Response}; +use heimlig::common::queues; +use heimlig::common::queues::{RequestSink, ResponseSink}; use heimlig::crypto::rng; use heimlig::crypto::rng::Rng; use heimlig::hsm::core::Core; use heimlig::hsm::keystore::NoKeyStore; -use embassy_sync::mutex::Mutex; -use embassy_sync::blocking_mutex::raw::NoopRawMutex; -use heimlig::common::queues; -use heimlig::common::queues::{RequestSink, ResponseSink}; +use heimlig::hsm::workers::rng_worker::RngWorker; use log::{error, info}; use rand::RngCore; // Request and response queues between tasks const QUEUE_SIZE: usize = 8; -static mut CLIENT_TO_HSM: Queue = Queue::new(); -static mut HSM_TO_CLIENT: Queue = Queue::new(); +static mut CLIENT_TO_CORE: Queue = Queue::new(); +static mut CORE_TO_CLIENT: Queue = Queue::new(); +static mut CORE_TO_RNG_WORKER: Queue = Queue::new(); +static mut RNG_WORKER_TO_CORE: Queue = Queue::new(); struct EntropySource {} @@ -89,29 +92,60 @@ impl<'a> Iterator for ResponseQueueSource<'_, 'a> { #[embassy_executor::task] async fn hsm_task( - req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, - resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + client_req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, + client_resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + rng_req_tx: Producer<'static, Request<'_>, QUEUE_SIZE>, + rng_req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, + rng_resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + rng_resp_rx: Consumer<'static, Response<'_>, QUEUE_SIZE>, ) { - // Channel - let requests_source = RequestQueueSource { consumer: req_rx }; - let responses_sink = ResponseQueueSink { producer: resp_tx }; + // Channels + let client_requests = RequestQueueSource { + consumer: client_req_rx, + }; + let client_responses = ResponseQueueSink { + producer: client_resp_tx, + }; + let rng_requests_rx = RequestQueueSource { + consumer: rng_req_rx, + }; + let rng_requests_tx = RequestQueueSink { + producer: rng_req_tx, + }; + let rng_responses_rx = ResponseQueueSource { + consumer: rng_resp_rx, + }; + let rng_responses_tx = ResponseQueueSink { + producer: rng_resp_tx, + }; let rng = Rng::new(EntropySource {}, None); - let key_store = NoKeyStore{}; + let mut rng_worker = RngWorker { + rng, + requests: rng_requests_rx.enumerate(), + responses: rng_responses_tx, + }; + let key_store = NoKeyStore {}; let key_store = Mutex::::new(key_store); let mut core: Core< NoopRawMutex, NoKeyStore, Enumerate>, - ResponseQueueSink<'_,'_>, + ResponseQueueSink<'_, '_>, RequestQueueSink<'_, '_>, Enumerate>, - > = Core::new(&key_store, requests_source.enumerate(), responses_sink); + > = Core::new(&key_store, client_requests.enumerate(), client_responses); + core.add_worker_channel( + &[RequestType::GetRandom], + rng_requests_tx, + rng_responses_rx.enumerate(), + ); - /*loop { - core.process_next().expect("failed to process next request"); + loop { + core.execute().expect("failed to forward request"); + rng_worker.execute().expect("failed to process request"); Timer::after(Duration::from_millis(100)).await; - }*/ + } } #[embassy_executor::task] @@ -166,14 +200,23 @@ async fn main(spawner: Spawner) { // Queues // Unsafe: Access to mutable static only happens here. Static lifetime is required by embassy tasks. - let (req_tx, req_rx) = unsafe { CLIENT_TO_HSM.split() }; - let (resp_tx, resp_rx) = unsafe { HSM_TO_CLIENT.split() }; + let (client_req_tx, client_req_rx) = unsafe { CLIENT_TO_CORE.split() }; + let (client_resp_tx, client_resp_rx) = unsafe { CORE_TO_CLIENT.split() }; + let (rng_resp_tx, rng_resp_rx) = unsafe { CORE_TO_RNG_WORKER.split() }; + let (rng_req_tx, rng_req_rx) = unsafe { RNG_WORKER_TO_CORE.split() }; // Start tasks spawner - .spawn(hsm_task(req_rx, resp_tx)) - .expect("failed to spawn HSM task"); + .spawn(hsm_task( + client_req_rx, + client_resp_tx, + rng_req_tx, + rng_req_rx, + rng_resp_tx, + rng_resp_rx, + )) + .expect("Failed to spawn HSM task"); spawner - .spawn(client_task(resp_rx, req_tx)) - .expect("failed to spawn client task"); + .spawn(client_task(client_resp_rx, client_req_tx)) + .expect("Failed to spawn client task"); } diff --git a/examples/stm32h745i/cm4/Cargo.lock b/examples/stm32h745i/cm4/Cargo.lock index c4537b47..5fdb246c 100644 --- a/examples/stm32h745i/cm4/Cargo.lock +++ b/examples/stm32h745i/cm4/Cargo.lock @@ -515,7 +515,7 @@ source = "git+https://github.com/embassy-rs/embassy.git#2a4ebdc150ba7c32d7dacc12 dependencies = [ "defmt", "embassy-futures", - "embassy-sync", + "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy.git)", "embassy-time", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", @@ -593,14 +593,14 @@ dependencies = [ "embassy-futures", "embassy-hal-internal", "embassy-net-driver", - "embassy-sync", + "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy.git)", "embassy-time", "embassy-usb-driver", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", "embedded-hal-async", "embedded-hal-nb", - "embedded-io", + "embedded-io 0.5.0", "embedded-io-async", "embedded-storage", "embedded-storage-async", @@ -616,6 +616,19 @@ dependencies = [ "vcell", ] +[[package]] +name = "embassy-sync" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0dad296a6f70bfdc32ef52442a31f98c28e1608893c1cecc9b6f419bab005a0" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io 0.4.0", + "futures-util", + "heapless", +] + [[package]] name = "embassy-sync" version = "0.2.0" @@ -687,6 +700,12 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + [[package]] name = "embedded-io" version = "0.5.0" @@ -703,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1394754ad749a560b25a0c70dcd2b66a450824a1311fc475bb2ccbfabe7f8414" dependencies = [ "defmt", - "embedded-io", + "embedded-io 0.5.0", ] [[package]] @@ -883,6 +902,7 @@ dependencies = [ "ecdsa", "ed25519-dalek", "elliptic-curve", + "embassy-sync 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array", "heapless", "p256", diff --git a/examples/stm32h745i/cm7/Cargo.lock b/examples/stm32h745i/cm7/Cargo.lock index dbd3c6e4..33f41d6e 100644 --- a/examples/stm32h745i/cm7/Cargo.lock +++ b/examples/stm32h745i/cm7/Cargo.lock @@ -515,7 +515,7 @@ source = "git+https://github.com/embassy-rs/embassy.git#2a4ebdc150ba7c32d7dacc12 dependencies = [ "defmt", "embassy-futures", - "embassy-sync", + "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy.git)", "embassy-time", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", @@ -593,14 +593,14 @@ dependencies = [ "embassy-futures", "embassy-hal-internal", "embassy-net-driver", - "embassy-sync", + "embassy-sync 0.2.0 (git+https://github.com/embassy-rs/embassy.git)", "embassy-time", "embassy-usb-driver", "embedded-hal 0.2.7", "embedded-hal 1.0.0-rc.1", "embedded-hal-async", "embedded-hal-nb", - "embedded-io", + "embedded-io 0.5.0", "embedded-io-async", "embedded-storage", "embedded-storage-async", @@ -616,6 +616,19 @@ dependencies = [ "vcell", ] +[[package]] +name = "embassy-sync" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0dad296a6f70bfdc32ef52442a31f98c28e1608893c1cecc9b6f419bab005a0" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io 0.4.0", + "futures-util", + "heapless", +] + [[package]] name = "embassy-sync" version = "0.2.0" @@ -687,6 +700,12 @@ dependencies = [ "nb 1.1.0", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + [[package]] name = "embedded-io" version = "0.5.0" @@ -703,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1394754ad749a560b25a0c70dcd2b66a450824a1311fc475bb2ccbfabe7f8414" dependencies = [ "defmt", - "embedded-io", + "embedded-io 0.5.0", ] [[package]] @@ -883,6 +902,7 @@ dependencies = [ "ecdsa", "ed25519-dalek", "elliptic-curve", + "embassy-sync 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "generic-array", "heapless", "p256", @@ -1311,6 +1331,7 @@ dependencies = [ "defmt-rtt", "embassy-executor", "embassy-stm32", + "embassy-sync 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "embassy-time", "heapless", "heimlig", diff --git a/examples/stm32h745i/cm7/Cargo.toml b/examples/stm32h745i/cm7/Cargo.toml index a3d31b1c..4ab031e8 100644 --- a/examples/stm32h745i/cm7/Cargo.toml +++ b/examples/stm32h745i/cm7/Cargo.toml @@ -19,8 +19,9 @@ cortex-m-rt = { version = "0.7", default-features = false } defmt = { version = "0.3", default-features = false } defmt-rtt = { version = "0.4", default-features = false } embassy-executor = { git = "https://github.com/embassy-rs/embassy.git", version = "0.2", features = ["arch-cortex-m", "defmt", "executor-thread", "integrated-timers", "nightly"] } -embassy-time = { git = "https://github.com/embassy-rs/embassy.git", version = "0.1", features = ["defmt", "defmt-timestamp-uptime", "nightly", "tick-hz-32_768", "unstable-traits"] } embassy-stm32 = { git = "https://github.com/embassy-rs/embassy.git", version = "0.1", features = ["nightly", "defmt", "stm32h745xi-cm7", "time-driver-any", "exti", "unstable-pac", "unstable-traits"] } +embassy-sync = { version = "0.2", default-features = false } +embassy-time = { git = "https://github.com/embassy-rs/embassy.git", version = "0.1", features = ["defmt", "defmt-timestamp-uptime", "nightly", "tick-hz-32_768", "unstable-traits"] } heapless = { version = "0.7", default-features = false } panic-probe = { version = "0.3", features = ["print-defmt"] } rand = { version = "0.8", default-features = false } diff --git a/examples/stm32h745i/cm7/src/bin/rng_single_core.rs b/examples/stm32h745i/cm7/src/bin/rng_single_core.rs index ca7ff663..f0cf327b 100644 --- a/examples/stm32h745i/cm7/src/bin/rng_single_core.rs +++ b/examples/stm32h745i/cm7/src/bin/rng_single_core.rs @@ -2,18 +2,25 @@ #![no_main] #![feature(type_alias_impl_trait)] +use core::iter::Enumerate; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::peripherals::RNG; use embassy_stm32::rng::{InterruptHandler, Rng}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; +use embassy_sync::mutex::Mutex; use embassy_time::{Duration, Timer}; use heapless::spsc::{Consumer, Producer, Queue}; -use heimlig::client::api::{Api, RequestSink}; -use heimlig::common::jobs::{Request, Response}; +use heimlig::client::api::Api; +use heimlig::common::jobs::{Request, RequestType, Response}; +use heimlig::common::queues; +use heimlig::common::queues::{RequestSink, ResponseSink}; use heimlig::crypto::rng; -use heimlig::hsm::core::{Core, ResponseSink}; +use heimlig::hsm::core::Core; +use heimlig::hsm::keystore::NoKeyStore; +use heimlig::hsm::workers::rng_worker::RngWorker; use rand_core::RngCore; use {defmt_rtt as _, panic_probe as _}; @@ -26,8 +33,10 @@ bind_interrupts!(struct Irqs { static mut MEMORY: [u8; 256] = [0; 256]; const QUEUE_SIZE: usize = 8; -static mut CLIENT_TO_HSM: Queue = Queue::::new(); -static mut HSM_TO_CLIENT: Queue = Queue::::new(); +static mut CLIENT_TO_CORE: Queue = Queue::new(); +static mut CORE_TO_CLIENT: Queue = Queue::new(); +static mut CORE_TO_RNG_WORKER: Queue = Queue::new(); +static mut RNG_WORKER_TO_CORE: Queue = Queue::new(); struct EntropySource { rng: Rng<'static, RNG>, @@ -46,10 +55,10 @@ struct RequestQueueSink<'ch, 'a> { } impl<'a> RequestSink<'a> for RequestQueueSink<'_, 'a> { - fn send(&mut self, request: Request<'a>) -> Result<(), heimlig::client::api::Error> { + fn send(&mut self, request: Request<'a>) -> Result<(), queues::Error> { self.producer .enqueue(request) - .map_err(|_| heimlig::client::api::Error::QueueFull) + .map_err(|_| queues::Error::QueueFull) } fn ready(&self) -> bool { @@ -74,10 +83,10 @@ struct ResponseQueueSink<'ch, 'a> { } impl<'a> ResponseSink<'a> for ResponseQueueSink<'_, 'a> { - fn send(&mut self, response: Response<'a>) -> Result<(), heimlig::hsm::core::Error> { + fn send(&mut self, response: Response<'a>) -> Result<(), queues::Error> { self.producer .enqueue(response) - .map_err(|_| heimlig::hsm::core::Error::QueueFull) + .map_err(|_| queues::Error::QueueFull) } fn ready(&self) -> bool { self.producer.ready() @@ -98,21 +107,61 @@ impl<'a> Iterator for ResponseQueueSource<'_, 'a> { #[embassy_executor::task] async fn hsm_task( - req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, - resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + client_req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, + client_resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + rng_req_tx: Producer<'static, Request<'_>, QUEUE_SIZE>, + rng_req_rx: Consumer<'static, Request<'_>, QUEUE_SIZE>, + rng_resp_tx: Producer<'static, Response<'_>, QUEUE_SIZE>, + rng_resp_rx: Consumer<'static, Response<'_>, QUEUE_SIZE>, rng: Rng<'static, RNG>, ) { info!("HSM task started"); - // Channel - let requests_source = RequestQueueSource { consumer: req_rx }; - let responses_sink = ResponseQueueSink { producer: resp_tx }; + // Channels + let client_requests = RequestQueueSource { + consumer: client_req_rx, + }; + let client_responses = ResponseQueueSink { + producer: client_resp_tx, + }; + let rng_requests_rx = RequestQueueSource { + consumer: rng_req_rx, + }; + let rng_requests_tx = RequestQueueSink { + producer: rng_req_tx, + }; + let rng_responses_rx = ResponseQueueSource { + consumer: rng_resp_rx, + }; + let rng_responses_tx = ResponseQueueSink { + producer: rng_resp_tx, + }; let rng = rng::Rng::new(EntropySource { rng }, None); - let mut core = Core::new_without_key_store(rng, requests_source.enumerate(), responses_sink); + let mut rng_worker = RngWorker { + rng, + requests: rng_requests_rx.enumerate(), + responses: rng_responses_tx, + }; + let key_store = NoKeyStore {}; + let key_store = Mutex::::new(key_store); + let mut core: Core< + NoopRawMutex, + NoKeyStore, + Enumerate>, + ResponseQueueSink<'_, '_>, + RequestQueueSink<'_, '_>, + Enumerate>, + > = Core::new(&key_store, client_requests.enumerate(), client_responses); + core.add_worker_channel( + &[RequestType::GetRandom], + rng_requests_tx, + rng_responses_rx.enumerate(), + ); loop { - core.process_next().expect("failed to process next request"); + core.execute().expect("failed to forward request"); + rng_worker.execute().expect("failed to process request"); Timer::after(Duration::from_millis(100)).await; } } @@ -196,14 +245,24 @@ async fn main(spawner: Spawner) { // Queues // Unsafe: Access to mutable static only happens here. Static lifetime is required by embassy tasks. - let (req_tx, req_rx) = unsafe { CLIENT_TO_HSM.split() }; - let (resp_tx, resp_rx) = unsafe { HSM_TO_CLIENT.split() }; + let (client_req_tx, client_req_rx) = unsafe { CLIENT_TO_CORE.split() }; + let (client_resp_tx, client_resp_rx) = unsafe { CORE_TO_CLIENT.split() }; + let (rng_resp_tx, rng_resp_rx) = unsafe { CORE_TO_RNG_WORKER.split() }; + let (rng_req_tx, rng_req_rx) = unsafe { RNG_WORKER_TO_CORE.split() }; // Start tasks spawner - .spawn(hsm_task(req_rx, resp_tx, rng)) - .expect("failed to spawn HSM task"); + .spawn(hsm_task( + client_req_rx, + client_resp_tx, + rng_req_tx, + rng_req_rx, + rng_resp_tx, + rng_resp_rx, + rng, + )) + .expect("Failed to spawn HSM task"); spawner - .spawn(client_task(resp_rx, req_tx, led)) - .expect("failed to spawn client task"); + .spawn(client_task(client_resp_rx, client_req_tx, led)) + .expect("Failed to spawn client task"); } diff --git a/heimlig/src/hsm/workers/chachapoly_worker.rs b/heimlig/src/hsm/workers/chachapoly_worker.rs index 78c418b7..f8b64b12 100644 --- a/heimlig/src/hsm/workers/chachapoly_worker.rs +++ b/heimlig/src/hsm/workers/chachapoly_worker.rs @@ -34,6 +34,9 @@ impl< if self.responses.ready() { let mut key_buffer = Zeroizing::new([0u8; MAX_KEY_SIZE]); let response = match self.requests.next() { + None => { + None // Nothing to process + } Some(( _request_id, Request::DecryptChaChaPoly { @@ -49,8 +52,8 @@ impl< .expect("Failed to lock key store") .export(key_id, key_buffer.as_mut_slice()) { - Ok(key) => self.decrypt(key, nonce, aad, ciphertext, tag), - Err(e) => Response::Error(Error::KeyStore(e)), + Ok(key) => Some(self.decrypt(key, nonce, aad, ciphertext, tag)), + Err(e) => Some(Response::Error(Error::KeyStore(e))), }, Some(( _request_id, @@ -67,8 +70,8 @@ impl< .expect("Failed to lock key store") .export(key_id, key_buffer.as_mut_slice()) { - Ok(key) => self.encrypt(key, nonce, aad, plaintext, tag), - Err(e) => Response::Error(Error::KeyStore(e)), + Ok(key) => Some(self.encrypt(key, nonce, aad, plaintext, tag)), + Err(e) => Some(Response::Error(Error::KeyStore(e))), }, Some(( _request_id, @@ -79,7 +82,7 @@ impl< plaintext, tag, }, - )) => self.encrypt_external_key(key, nonce, aad, plaintext, tag), + )) => Some(self.encrypt_external_key(key, nonce, aad, plaintext, tag)), Some(( _request_id, Request::DecryptChaChaPolyExternalKey { @@ -89,12 +92,14 @@ impl< ciphertext, tag, }, - )) => self.decrypt_external_key(key, nonce, aad, ciphertext, tag), + )) => Some(self.decrypt_external_key(key, nonce, aad, ciphertext, tag)), _ => { - panic!("Return unexpected request error"); // Return error here instead? Should never happen. + panic!("Encountered unexpected request"); // Integration error. Return error here instead? } }; - self.responses.send(response)?; + if let Some(response) = response { + return self.responses.send(response); + } Ok(()) } else { Err(queues::Error::QueueFull) diff --git a/heimlig/src/hsm/workers/rng_worker.rs b/heimlig/src/hsm/workers/rng_worker.rs index a78b1147..dba09185 100644 --- a/heimlig/src/hsm/workers/rng_worker.rs +++ b/heimlig/src/hsm/workers/rng_worker.rs @@ -28,15 +28,17 @@ impl< pub fn execute(&mut self) -> Result<(), queues::Error> { if self.responses.ready() { match self.requests.next() { + None => { + Ok(()) // Nothing to process + } Some((_id, Request::GetRandom { output })) => { let response = self.get_random(output); - self.responses.send(response)?; + self.responses.send(response) } _ => { - todo!("Return unexpected request error") + panic!("Encountered unexpected request"); // Integration error. Return error here instead? } } - Ok(()) // Nothing to process } else { Err(queues::Error::QueueFull) } diff --git a/heimlig/tests/api_core_integration.rs b/heimlig/tests/api_core_integration.rs index 9b7fdbb9..af1ad606 100644 --- a/heimlig/tests/api_core_integration.rs +++ b/heimlig/tests/api_core_integration.rs @@ -132,25 +132,25 @@ mod tests { ResponseQueueSource<'ch, 'data>, ResponseQueueSink<'ch, 'data>, ) { - let (rng_requests_tx, rng_requests_rx): ( + let (requests_tx, requests_rx): ( Producer, Consumer, ) = requests.split(); + let (response_tx, response_rx): ( + Producer, + Consumer, + ) = responses.split(); let requests_rx = RequestQueueSource { - consumer: rng_requests_rx, + consumer: requests_rx, }; let requests_tx = RequestQueueSink { - producer: rng_requests_tx, + producer: requests_tx, }; - let (response_rng_tx, response_rng_rx): ( - Producer, - Consumer, - ) = responses.split(); let response_rx = ResponseQueueSource { - consumer: response_rng_rx, + consumer: response_rx, }; let response_tx = ResponseQueueSink { - producer: response_rng_tx, + producer: response_tx, }; (requests_rx, requests_tx, response_rx, response_tx) }