Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to shared memory instead of HSM allocations #156

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions examples/linux/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
#![feature(type_alias_impl_trait)] // Required for embassy

use embassy_executor::Spawner;
use embassy_time::Duration;
use embassy_time::Timer;
use embassy_time::{Duration, Timer};
use heapless::spsc::{Consumer, Producer, Queue};
use heimlig::client::api::Api;
use heimlig::common::jobs::{Request, Response};
use heimlig::common::pool::Memory;
use heimlig::common::pool::Pool;
use heimlig::crypto::rng;
use heimlig::crypto::rng::Rng;
use heimlig::hsm::core::Core;
use heimlig::{client, hsm};
use heimlig::{
client::{self, api::Api},
common::{
jobs::{ExternalMemory, OutParam, Request, Response},
pool::{Memory, Pool},
},
crypto::rng::{self, Rng},
hsm::{self, core::Core},
};
use log::{error, info};
use rand::RngCore;

Expand Down Expand Up @@ -104,13 +104,18 @@ async fn client_task(
// Api
let mut api = Api::new(&mut core_side);

// Random buffer
let random_buffer = [0u8; 16];

loop {
// Send request
Timer::after(Duration::from_millis(1000)).await;
let random_size = 16;
info!(target: "CLIENT", "Sending request: random data (size={})", random_size);
api.get_random(random_size)
.expect("failed to call randomness API");

info!(target: "CLIENT", "Sending request: random data (size={})", random_buffer.len());
api.get_random(OutParam::new(ExternalMemory::from_slice(
random_buffer.as_slice(),
)))
.expect("failed to call randomness API");

// Receive response
loop {
Expand All @@ -121,7 +126,7 @@ async fn client_task(
Response::GetRandom { data } => {
info!(target: "CLIENT",
"Received response: random data (size={}): {}",
data.len(),
data.as_slice().len(),
hex::encode(data.as_slice())
);
break; // Send next request
Expand Down
19 changes: 13 additions & 6 deletions examples/stm32h745i/cm7/src/bin/rng_single_core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use embassy_time::{Duration, Timer};
use heapless::spsc::{Consumer, Producer, Queue};
use heimlig::client;
use heimlig::client::api::Api;
use heimlig::common::jobs::{Request, Response};
use heimlig::common::jobs::{ExternalMemory, OutParam, Request, Response};
use heimlig::common::pool::Memory;
use heimlig::common::pool::Pool;
use heimlig::crypto::rng;
Expand Down Expand Up @@ -123,14 +123,21 @@ async fn client_task(
// Api
let mut api = Api::new(&mut core_side);

// Random buffer
let random_buffer = [0u8; 16];

loop {
// Send requests
Timer::after(Duration::from_millis(1000)).await;
led.set_high();
let random_size = 16;
info!("Sending request: random data (size={})", random_size);
api.get_random(random_size)
.expect("failed to call randomness API");
info!(
"Sending request: random data (size={})",
random_buffer.len()
);
api.get_random(OutParam::new(ExternalMemory::from_slice(
random_buffer.as_slice(),
)))
.expect("failed to call randomness API");

// Receive response
loop {
Expand All @@ -139,7 +146,7 @@ async fn client_task(
Response::GetRandom { data } => {
info!(
"Received response: random data (size={}): {:02x}",
data.len(),
data.as_slice().len(),
data.as_slice()
);
break;
Expand Down
28 changes: 16 additions & 12 deletions heimlig/src/client/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::common::jobs::{Request, Response};
use crate::common::jobs::{OutParam, Request, Response};

#[derive(Clone, Eq, PartialEq, Debug)]
pub enum Error {
Expand All @@ -25,9 +25,9 @@ impl<'a, C: Channel> Api<'a, C> {
Api { channel }
}

/// Request `size` many random bytes.
pub fn get_random(&mut self, size: usize) -> Result<(), Error> {
self.channel.send(Request::GetRandom { size })
/// Request to fill `data` with random bytes.
pub fn get_random(&mut self, data: OutParam) -> Result<(), Error> {
self.channel.send(Request::GetRandom { data })
}

/// Attempt to poll a response and return it.
Expand All @@ -39,7 +39,7 @@ impl<'a, C: Channel> Api<'a, C> {
#[cfg(test)]
mod test {
use crate::client::api::{Api, Channel, Error};
use crate::common::jobs::{Request, Response};
use crate::common::jobs::{ExternalMemory, OutParam, Request, Response};
use crate::common::pool::{Memory, Pool};
use heapless::spsc::{Consumer, Producer, Queue};

Expand Down Expand Up @@ -79,22 +79,26 @@ mod test {

// Send request
let random_len = 16;
api.get_random(random_len)
let data = pool.alloc(random_len).expect("failed to allocate");
api.get_random(OutParam::new(ExternalMemory::from_slice(data.as_slice())))
.expect("failed to call randomness API");
let request = req_rx.dequeue().expect("failed to receive request");
match request {
Request::GetRandom { size } => assert_eq!(size, random_len),
let random_buffer = match request {
Request::GetRandom { data } => data,
_ => panic!("Unexpected request type"),
}
};

assert_eq!(random_buffer.as_slice().len(), random_len);

// Receive response
let data = pool.alloc(random_len).expect("failed to allocate");
resp_tx
.enqueue(Response::GetRandom { data })
.enqueue(Response::GetRandom {
data: random_buffer,
})
.expect("failed to send response");
let response = api.recv_response().expect("failed to receive response");
match response {
Response::GetRandom { data } => assert_eq!(data.len(), random_len),
Response::GetRandom { data } => assert_eq!(data.as_slice().len(), random_len),
_ => panic!("Unexpected response type"),
}
}
Expand Down
144 changes: 121 additions & 23 deletions heimlig/src/common/jobs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::common::pool::PoolChunk;
use core::ptr::NonNull;

use crate::hsm::keystore;
use crate::hsm::keystore::Id;

Expand All @@ -14,41 +15,138 @@ pub enum Error {
KeyStore(keystore::Error),
}

/// Shared memory representation.
#[derive(Eq, PartialEq, Debug)]
pub struct ExternalMemory {
/// Pointer to memory.
ptr: *const u8,
/// Memory size.
size: usize,
}

impl ExternalMemory {
pub fn new(ptr: *const u8, size: usize) -> Self {
Self { ptr, size }
}

pub fn from_slice(data: &[u8]) -> Self {
Self::new(data.as_ptr(), data.len())
}

pub fn as_slice(&self) -> &[u8] {
unsafe { core::slice::from_raw_parts(self.ptr, self.size) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we find ourselves getting tired of calling as_slice explicitly we can think about implementing the Deref trait for ExternalMemory.

}

pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { core::slice::from_raw_parts_mut(self.ptr as *mut _, self.size) }
}
}

impl Default for ExternalMemory {
fn default() -> Self {
Self {
ptr: NonNull::<u8>::dangling().as_ptr(),
size: 0,
}
}
}

/// Shared memory input parameter.
#[derive(Eq, PartialEq, Debug, Default)]
pub struct InParam {
/// Shared memory.
memory: ExternalMemory,
}

impl InParam {
pub fn new(memory: ExternalMemory) -> Self {
Self { memory }
}

pub fn as_slice(&self) -> &[u8] {
self.memory.as_slice()
}
}

/// Shared memory output parameter.
#[derive(Eq, PartialEq, Debug, Default)]
pub struct OutParam {
/// Shared memory.
memory: ExternalMemory,
}

impl OutParam {
pub fn new(memory: ExternalMemory) -> Self {
Self { memory }
}

pub fn as_slice(&self) -> &[u8] {
self.memory.as_slice()
}

pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.memory.as_mut_slice()
}
}

/// Shared memory in/out parameter.
#[derive(Eq, PartialEq, Debug, Default)]
pub struct InOutParam {
/// Shared memory.
memory: ExternalMemory,
}

impl InOutParam {
pub fn new(memory: ExternalMemory) -> Self {
Self { memory }
}

pub fn as_slice(&self) -> &[u8] {
self.memory.as_slice()
}

pub fn as_mut_slice(&mut self) -> &mut [u8] {
self.memory.as_mut_slice()
}
}

/// A request for the HSM to perform a cryptographic task.
#[derive(Eq, PartialEq, Debug)]
pub enum Request {
ImportKey {
id: Id,
data: PoolChunk,
data: InParam,
},
GetRandom {
size: usize,
data: OutParam,
},
EncryptChaChaPoly {
key_id: Id,
nonce: PoolChunk,
aad: Option<PoolChunk>,
plaintext: PoolChunk,
nonce: InParam,
aad: Option<InParam>,
plaintext: InOutParam,
tag: OutParam,
},
EncryptChaChaPolyExternalKey {
key: PoolChunk,
nonce: PoolChunk,
aad: Option<PoolChunk>,
plaintext: PoolChunk,
key: InParam,
nonce: InParam,
aad: Option<InParam>,
plaintext: InOutParam,
tag: OutParam,
},
DecryptChaChaPoly {
key_id: Id,
nonce: PoolChunk,
aad: Option<PoolChunk>,
ciphertext: PoolChunk,
tag: PoolChunk,
nonce: InParam,
aad: Option<InParam>,
ciphertext: InOutParam,
tag: InParam,
},
DecryptChaChaPolyExternalKey {
key: PoolChunk,
nonce: PoolChunk,
aad: Option<PoolChunk>,
ciphertext: PoolChunk,
tag: PoolChunk,
key: InParam,
nonce: InParam,
aad: Option<InParam>,
ciphertext: InOutParam,
tag: InParam,
},
}

Expand All @@ -58,13 +156,13 @@ pub enum Response {
ImportKey,
Error(Error),
GetRandom {
data: PoolChunk,
data: OutParam,
},
EncryptChaChaPoly {
ciphertext: PoolChunk,
tag: PoolChunk,
ciphertext: InOutParam,
tag: OutParam,
},
DecryptChaChaPoly {
plaintext: PoolChunk,
plaintext: InOutParam,
},
}
15 changes: 11 additions & 4 deletions heimlig/src/hsm/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ impl<'a, E: EntropySource, C: Channel, const MAX_CLIENTS: usize> Core<'a, E, C,
mod tests {
use super::*;
use crate::client::api::Channel as ApiChannel;
use crate::common::jobs::{ExternalMemory, OutParam};
use crate::common::pool::Memory;
use crate::config;
use crate::config::keystore::{KEY1, KEY2, KEY3};
Expand Down Expand Up @@ -212,8 +213,11 @@ mod tests {

// Send request from client 1
let size = 65; // Exceed size of a small chunk
let data1 = pool.alloc(size).unwrap();
client1_side
.send(Request::GetRandom { size })
.send(Request::GetRandom {
data: OutParam::new(ExternalMemory::from_slice(data1.as_slice())),
})
.expect("failed to send request");
core.process_next().expect("failed to process next request");
if client2_side.recv().is_some() {
Expand All @@ -222,7 +226,7 @@ mod tests {
match client1_side.recv() {
Some(response) => match response {
Response::GetRandom { data } => {
assert_eq!(data.len(), size)
assert_eq!(data.as_slice().len(), size)
}
_ => {
panic!("Unexpected response type");
Expand All @@ -234,8 +238,11 @@ mod tests {
}

// Send request from client 2
let data2 = pool.alloc(size).unwrap();
client2_side
.send(Request::GetRandom { size })
.send(Request::GetRandom {
data: OutParam::new(ExternalMemory::from_slice(data2.as_slice())),
})
.expect("failed to send request");
core.process_next().expect("failed to process next request");
if client1_side.recv().is_some() {
Expand All @@ -244,7 +251,7 @@ mod tests {
match client2_side.recv() {
Some(response) => match response {
Response::GetRandom { data } => {
assert_eq!(data.len(), size)
assert_eq!(data.as_slice().len(), size)
}
_ => {
panic!("Unexpected response type");
Expand Down
Loading
Loading