diff --git a/heimlig/src/crypto/aes/cmac.rs b/heimlig/src/crypto/aes/cmac.rs index 869f330b..f4ce71e0 100644 --- a/heimlig/src/crypto/aes/cmac.rs +++ b/heimlig/src/crypto/aes/cmac.rs @@ -134,7 +134,7 @@ define_aes_cmac_impl!( #[cfg(test)] mod test { use super::*; - use crate::crypto::aes::{test::*, CMAC_TAG_SIZE, KEY128_SIZE, KEY192_SIZE, KEY256_SIZE}; + use crate::crypto::aes::{test::*, KEY128_SIZE, KEY192_SIZE, KEY256_SIZE}; macro_rules! define_aes_cmac_calculate_verify_test { ( diff --git a/heimlig/src/hsm/core.rs b/heimlig/src/hsm/core.rs index 0fe3e1ba..16f9e9ea 100644 --- a/heimlig/src/hsm/core.rs +++ b/heimlig/src/hsm/core.rs @@ -393,14 +393,14 @@ impl< request_id, key_id, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), + None => Self::no_key_store_response(client_id, request_id), Some(key_store) => { let is_available = key_store.lock().await.deref_mut().is_key_available(key_id); - Ok(Response::IsKeyAvailable { + Response::IsKeyAvailable { client_id, request_id, is_available, - }) + } } }, Request::ImportSymmetricKey { @@ -410,7 +410,7 @@ impl< data, overwrite, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), + None => Self::no_key_store_response(client_id, request_id), Some(key_store) => { let result = key_store .lock() @@ -418,11 +418,11 @@ impl< .deref_mut() .import_symmetric_key(key_id, data, overwrite); match result { - Ok(()) => Ok(Response::ImportSymmetricKey { + Ok(()) => Response::ImportSymmetricKey { client_id, request_id, - }), - Err(e) => Ok(Self::key_store_error_response(client_id, request_id, e)), + }, + Err(e) => Self::key_store_error_response(client_id, request_id, e), } } }, @@ -434,7 +434,7 @@ impl< private_key, overwrite, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), + None => Self::no_key_store_response(client_id, request_id), Some(key_store) => { let result = key_store.lock().await.deref_mut().import_key_pair( key_id, @@ -443,11 +443,11 @@ impl< overwrite, ); match result { - Ok(()) => Ok(Response::ImportKeyPair { + Ok(()) => Response::ImportKeyPair { client_id, request_id, - }), - Err(e) => Ok(Self::key_store_error_response(client_id, request_id, e)), + }, + Err(e) => Self::key_store_error_response(client_id, request_id, e), } } }, @@ -457,25 +457,20 @@ impl< key_id, data, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), - Some(key_store) => { - let exported_key = key_store - .lock() - .await - .deref_mut() - .export_symmetric_key(key_id, data); - match exported_key { - Ok(written) => { - let written_len = written.len(); - Ok(Response::ExportSymmetricKey { - client_id, - request_id, - key: &mut data[..written_len], - }) - } - Err(e) => Ok(Self::key_store_error_response(client_id, request_id, e)), - } - } + None => Self::no_key_store_response(client_id, request_id), + Some(key_store) => key_store + .lock() + .await + .deref_mut() + .export_symmetric_key_to_slice(key_id, data) + .map_or_else( + |e| Self::key_store_error_response(client_id, request_id, e), + |()| Response::ExportSymmetricKey { + client_id, + request_id, + key: data, + }, + ), }, Request::ExportPublicKey { client_id, @@ -483,25 +478,20 @@ impl< key_id, public_key, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), - Some(key_store) => { - let exported_key = key_store - .lock() - .await - .deref_mut() - .export_public_key(key_id, public_key); - match exported_key { - Ok(written) => { - let exported_key_len = written.len(); - Ok(Response::ExportPublicKey { - client_id, - request_id, - public_key: &mut public_key[..exported_key_len], - }) - } - Err(e) => Ok(Self::key_store_error_response(client_id, request_id, e)), - } - } + None => Self::no_key_store_response(client_id, request_id), + Some(key_store) => key_store + .lock() + .await + .deref_mut() + .export_public_key_to_slice(key_id, public_key) + .map_or_else( + |e| Self::key_store_error_response(client_id, request_id, e), + |()| Response::ExportPublicKey { + client_id, + request_id, + public_key, + }, + ), }, Request::ExportPrivateKey { client_id, @@ -509,30 +499,27 @@ impl< key_id, private_key, } => match self.key_store { - None => Ok(Self::no_key_store_response(client_id, request_id)), - Some(key_store) => { - let exported_key = key_store - .lock() - .await - .deref_mut() - .export_private_key(key_id, private_key); - match exported_key { - Ok(written) => { - let written_len = written.len(); - Ok(Response::ExportPrivateKey { - client_id, - request_id, - private_key: &mut private_key[..written_len], - }) - } - Err(e) => Ok(Self::key_store_error_response(client_id, request_id, e)), - } - } + None => Self::no_key_store_response(client_id, request_id), + Some(key_store) => key_store + .lock() + .await + .deref_mut() + .export_private_key_to_slice(key_id, private_key) + .map_or_else( + |e| Self::key_store_error_response(client_id, request_id, e), + |()| Response::ExportPrivateKey { + client_id, + request_id, + private_key, + }, + ), + }, + req => Response::Error { + client_id: req.get_client_id(), + request_id: req.get_request_id(), + error: jobs::Error::UnexpectedRequestType, }, - _ => Err(Error::Internal(InternalError::UnexpectedCoreRequest( - request.get_type(), - ))), - }?; + }; self.send_to_client(response).await } diff --git a/heimlig/src/hsm/keystore.rs b/heimlig/src/hsm/keystore.rs index 65d1ad3f..719d9590 100644 --- a/heimlig/src/hsm/keystore.rs +++ b/heimlig/src/hsm/keystore.rs @@ -1,3 +1,7 @@ +use core::ops::Deref; + +use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; + /// Identifier to reference HSM keys #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Ord, PartialOrd)] pub struct KeyId(pub u32); @@ -113,6 +117,23 @@ impl KeyType { } } +#[derive(Zeroize, ZeroizeOnDrop)] +pub struct ZeroizableVec(pub heapless::Vec); + +impl Deref for ZeroizableVec { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.0.as_slice() + } +} + +type KeyData = Zeroizing>; + +pub type SymmetricKey = KeyData<{ KeyType::MAX_SYMMETRIC_KEY_SIZE }>; +pub type PublicKey = KeyData<{ KeyType::MAX_PUBLIC_KEY_SIZE }>; +pub type PrivateKey = KeyData<{ KeyType::MAX_PRIVATE_KEY_SIZE }>; + pub trait InsecureKeyStore { fn get_key_info(&self, id: KeyId) -> Result; @@ -140,32 +161,67 @@ pub trait InsecureKeyStore { /// Unlike `export_symmetric_key()`, this function exports keys even if their permissions do not /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. /// Workers operate inside Heimlig and are trusted. + fn export_symmetric_key_insecure(&self, id: KeyId) -> Result; + + /// Read a symmetric key from storage. /// - /// returns: The number of bytes written to `dest` or and error. - fn export_symmetric_key_insecure<'data>( + /// Unlike `export_symmetric_key()`, this function exports keys even if their permissions do not + /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. + /// Workers operate inside Heimlig and are trusted. + fn export_symmetric_key_insecure_to_slice( &self, id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + dst: &mut [u8], + ) -> Result<(), Error> { + let key = self.export_symmetric_key_insecure(id)?; + if key.len() != dst.len() { + return Err(Error::InvalidBufferSize); + } + dst.copy_from_slice(key.deref()); + Ok(()) + } - fn export_public_key_insecure<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + /// Read an asymmetric public key from storage. + /// + /// Unlike `export_public_key()`, this function exports keys even if their permissions do not + /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. + /// Workers operate inside Heimlig and are trusted. + fn export_public_key_insecure(&self, id: KeyId) -> Result; + + /// Read an asymmetric public key from storage. + /// + /// Unlike `export_public_key()`, this function exports keys even if their permissions do not + /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. + /// Workers operate inside Heimlig and are trusted. + fn export_public_key_insecure_to_slice(&self, id: KeyId, dst: &mut [u8]) -> Result<(), Error> { + let key = self.export_public_key_insecure(id)?; + if key.len() != dst.len() { + return Err(Error::InvalidBufferSize); + } + dst.copy_from_slice(key.deref()); + Ok(()) + } /// Read an asymmetric private key from storage. /// /// Unlike `export_private_key()`, this function exports keys even if their permissions do not /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. /// Workers operate inside Heimlig and are trusted. + fn export_private_key_insecure(&self, id: KeyId) -> Result; + + /// Read an asymmetric private key from storage. /// - /// returns: The number of bytes written to `dest` or and error. - fn export_private_key_insecure<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + /// Unlike `export_private_key()`, this function exports keys even if their permissions do not + /// allow it. It is supposed to be used by workers and is not reachable from outside Heimlig. + /// Workers operate inside Heimlig and are trusted. + fn export_private_key_insecure_to_slice(&self, id: KeyId, dst: &mut [u8]) -> Result<(), Error> { + let key = self.export_private_key_insecure(id)?; + if key.len() != dst.len() { + return Err(Error::InvalidBufferSize); + } + dst.copy_from_slice(key.deref()); + Ok(()) + } /// Delete the key for given ID. /// @@ -200,31 +256,43 @@ pub trait KeyStore { ) -> Result<(), Error>; /// Read a symmetric key from storage. - /// - /// returns: The number of bytes written to `dest` or and error. - fn export_symmetric_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + fn export_symmetric_key(&self, id: KeyId) -> Result; + + /// Read a symmetric key from storage. + fn export_symmetric_key_to_slice(&self, id: KeyId, dst: &mut [u8]) -> Result<(), Error> { + let key = self.export_symmetric_key(id)?; + if key.len() != dst.len() { + return Err(Error::InvalidBufferSize); + } + dst.copy_from_slice(key.deref()); + Ok(()) + } /// Read an asymmetric public key from storage. - /// - /// returns: The number of bytes written to `dest` or and error. - fn export_public_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + fn export_public_key(&self, id: KeyId) -> Result; + + /// Read an asymmetric public key from storage. + fn export_public_key_to_slice(&self, id: KeyId, dst: &mut [u8]) -> Result<(), Error> { + let key = self.export_public_key(id)?; + if key.len() != dst.len() { + return Err(Error::InvalidBufferSize); + } + dst.copy_from_slice(key.deref()); + Ok(()) + } /// Read an asymmetric private key from storage. - /// - /// returns: The number of bytes written to `dest` or and error. - fn export_private_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error>; + fn export_private_key(&self, id: KeyId) -> Result; + + /// Read an asymmetric private key from storage. + fn export_private_key_to_slice(&self, id: KeyId, dest: &mut [u8]) -> Result<(), Error> { + let key = self.export_private_key(id)?; + if key.len() != dest.len() { + return Err(Error::InvalidBufferSize); + } + dest.copy_from_slice(key.deref()); + Ok(()) + } /// Delete the key for given ID. /// @@ -289,11 +357,7 @@ impl KeyStore for T { self.import_key_pair_insecure(id, public_key, private_key) } - fn export_symmetric_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_symmetric_key(&self, id: KeyId) -> Result { let key_info = self.get_key_info(id)?; if !key_info.permissions.export_private { return Err(Error::NotAllowed); @@ -301,26 +365,18 @@ impl KeyStore for T { if !key_info.ty.is_symmetric() { return Err(Error::InvalidKeyType); }; - self.export_symmetric_key_insecure(id, dest) + self.export_symmetric_key_insecure(id) } - fn export_public_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_public_key(&self, id: KeyId) -> Result { let key_info = self.get_key_info(id)?; if !key_info.ty.is_asymmetric() { return Err(Error::InvalidKeyType); } - self.export_public_key_insecure(id, dest) + self.export_public_key_insecure(id) } - fn export_private_key<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_private_key(&self, id: KeyId) -> Result { let key_info = self.get_key_info(id)?; if !key_info.permissions.export_private { return Err(Error::NotAllowed); @@ -328,7 +384,7 @@ impl KeyStore for T { if !key_info.ty.is_asymmetric() { return Err(Error::InvalidKeyType); } - self.export_private_key_insecure(id, dest) + self.export_private_key_insecure(id) } fn delete(&mut self, id: KeyId) -> Result<(), Error> { diff --git a/heimlig/src/hsm/workers/aes_worker.rs b/heimlig/src/hsm/workers/aes_worker.rs index a9bcac97..a74bde3c 100644 --- a/heimlig/src/hsm/workers/aes_worker.rs +++ b/heimlig/src/hsm/workers/aes_worker.rs @@ -18,12 +18,11 @@ use crate::{ KEY128_SIZE, KEY192_SIZE, KEY256_SIZE, }, }, - hsm::keystore::{self, KeyId, KeyInfo, KeyType}, + hsm::keystore::{self, KeyId, KeyInfo, KeyType, SymmetricKey}, }; use cbc::cipher::block_padding::Pkcs7; use embassy_sync::{blocking_mutex::raw::RawMutex, mutex::Mutex}; use futures::{Sink, SinkExt, Stream, StreamExt}; -use zeroize::Zeroizing; pub struct AesWorker< 'data, @@ -209,10 +208,7 @@ impl< aad: &[u8], tag: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -223,10 +219,10 @@ impl< } Ok((key, key_info)) => match key_info.ty { KeyType::Symmetric(16) => { - aes128gcm_encrypt_in_place_detached(key, iv, aad, buffer, tag) + aes128gcm_encrypt_in_place_detached(&key, iv, aad, buffer, tag) } KeyType::Symmetric(32) => { - aes256gcm_encrypt_in_place_detached(key, iv, aad, buffer, tag) + aes256gcm_encrypt_in_place_detached(&key, iv, aad, buffer, tag) } _ => { return Response::Error { @@ -300,10 +296,7 @@ impl< aad: &[u8], tag: &[u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -314,10 +307,10 @@ impl< } Ok((key, key_info)) => match key_info.ty { KeyType::Symmetric(16) => { - aes128gcm_decrypt_in_place_detached(key, iv, aad, buffer, tag) + aes128gcm_decrypt_in_place_detached(&key, iv, aad, buffer, tag) } KeyType::Symmetric(32) => { - aes256gcm_decrypt_in_place_detached(key, iv, aad, buffer, tag) + aes256gcm_decrypt_in_place_detached(&key, iv, aad, buffer, tag) } _ => { return Response::Error { @@ -387,10 +380,7 @@ impl< buffer: &'data mut [u8], plaintext_size: usize, ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -401,13 +391,13 @@ impl< } Ok((key, key_info)) => match key_info.ty { KeyType::Symmetric(16) => { - aes128cbc_encrypt::(key, iv, buffer, plaintext_size) + aes128cbc_encrypt::(&key, iv, buffer, plaintext_size) } KeyType::Symmetric(24) => { - aes192cbc_encrypt::(key, iv, buffer, plaintext_size) + aes192cbc_encrypt::(&key, iv, buffer, plaintext_size) } KeyType::Symmetric(32) => { - aes256cbc_encrypt::(key, iv, buffer, plaintext_size) + aes256cbc_encrypt::(&key, iv, buffer, plaintext_size) } _ => { return Response::Error { @@ -481,10 +471,7 @@ impl< iv: &[u8], buffer: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -494,9 +481,9 @@ impl< } } Ok((key, key_info)) => match key_info.ty { - KeyType::Symmetric(16) => aes128cbc_decrypt::(key, iv, buffer), - KeyType::Symmetric(24) => aes192cbc_decrypt::(key, iv, buffer), - KeyType::Symmetric(32) => aes256cbc_decrypt::(key, iv, buffer), + KeyType::Symmetric(16) => aes128cbc_decrypt::(&key, iv, buffer), + KeyType::Symmetric(24) => aes192cbc_decrypt::(&key, iv, buffer), + KeyType::Symmetric(32) => aes256cbc_decrypt::(&key, iv, buffer), _ => { return Response::Error { client_id, @@ -568,10 +555,7 @@ impl< message: &[u8], tag: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -581,9 +565,9 @@ impl< } } Ok((key, key_info)) => match key_info.ty { - KeyType::Symmetric(16) => aes128_cmac_calculate(key, message, tag), - KeyType::Symmetric(24) => aes192_cmac_calculate(key, message, tag), - KeyType::Symmetric(32) => aes256_cmac_calculate(key, message, tag), + KeyType::Symmetric(16) => aes128_cmac_calculate(&key, message, tag), + KeyType::Symmetric(24) => aes192_cmac_calculate(&key, message, tag), + KeyType::Symmetric(32) => aes256_cmac_calculate(&key, message, tag), _ => { return Response::Error { client_id, @@ -649,10 +633,7 @@ impl< message: &[u8], tag: &[u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -662,9 +643,9 @@ impl< } } Ok((key, key_info)) => match key_info.ty { - KeyType::Symmetric(16) => aes128_cmac_verify(key, message, tag), - KeyType::Symmetric(24) => aes192_cmac_verify(key, message, tag), - KeyType::Symmetric(32) => aes256_cmac_verify(key, message, tag), + KeyType::Symmetric(16) => aes128_cmac_verify(&key, message, tag), + KeyType::Symmetric(24) => aes192_cmac_verify(&key, message, tag), + KeyType::Symmetric(32) => aes256_cmac_verify(&key, message, tag), _ => { return Response::Error { client_id, @@ -722,15 +703,14 @@ impl< } } - async fn export_key_and_key_info<'a>( + async fn export_key_and_key_info( &mut self, key_id: KeyId, - key_buffer: &'a mut [u8], - ) -> Result<(&'a [u8], KeyInfo), keystore::Error> { + ) -> Result<(SymmetricKey, KeyInfo), keystore::Error> { // Lock keystore only once let locked_key_store = self.key_store.lock().await; Ok(( - locked_key_store.export_symmetric_key_insecure(key_id, key_buffer)?, + locked_key_store.export_symmetric_key_insecure(key_id)?, keystore::KeyStore::get_key_info(*locked_key_store, key_id)?, )) } diff --git a/heimlig/src/hsm/workers/chachapoly_worker.rs b/heimlig/src/hsm/workers/chachapoly_worker.rs index 240df9d2..90565855 100644 --- a/heimlig/src/hsm/workers/chachapoly_worker.rs +++ b/heimlig/src/hsm/workers/chachapoly_worker.rs @@ -1,11 +1,9 @@ use crate::common::jobs::{ClientId, Error, Request, RequestId, Response}; use crate::crypto; -use crate::crypto::chacha20poly1305::KEY_SIZE; use crate::hsm::keystore::{self, KeyId}; use embassy_sync::blocking_mutex::raw::RawMutex; use embassy_sync::mutex::Mutex; use futures::{Sink, SinkExt, Stream, StreamExt}; -use zeroize::Zeroizing; pub struct ChaChaPolyWorker< 'data, @@ -101,14 +99,13 @@ impl< aad: &'data [u8], tag: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KEY_SIZE]); - let export = self + let key = self .key_store .lock() .await - .export_symmetric_key_insecure(key_id, key_buffer.as_mut_slice()); - match export { - Ok(key) => self.encrypt(client_id, request_id, key, nonce, aad, plaintext, tag), + .export_symmetric_key_insecure(key_id); + match key { + Ok(key) => self.encrypt(client_id, request_id, &key, nonce, aad, plaintext, tag), Err(e) => Response::Error { client_id, request_id, @@ -128,14 +125,13 @@ impl< aad: &'data [u8], tag: &'data [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KEY_SIZE]); - let export = self + let key = self .key_store .lock() .await - .export_symmetric_key_insecure(key_id, key_buffer.as_mut_slice()); - match export { - Ok(key) => self.decrypt(client_id, request_id, key, nonce, aad, ciphertext, tag), + .export_symmetric_key_insecure(key_id); + match key { + Ok(key) => self.decrypt(client_id, request_id, &key, nonce, aad, ciphertext, tag), Err(e) => Response::Error { client_id, request_id, diff --git a/heimlig/src/hsm/workers/ecc_worker.rs b/heimlig/src/hsm/workers/ecc_worker.rs index 445b4e2a..69aa0853 100644 --- a/heimlig/src/hsm/workers/ecc_worker.rs +++ b/heimlig/src/hsm/workers/ecc_worker.rs @@ -5,7 +5,7 @@ use crate::crypto::ecdsa::{ nist_p256_verify_prehashed, nist_p384_generate_key_pair, nist_p384_sign, nist_p384_sign_prehashed, nist_p384_verify, nist_p384_verify_prehashed, }; -use crate::hsm::keystore; +use crate::hsm::keystore::{self, PrivateKey, PublicKey}; use crate::hsm::keystore::{Curve, KeyId, KeyInfo, KeyType}; use core::ops::DerefMut; use embassy_sync::blocking_mutex::raw::RawMutex; @@ -206,10 +206,7 @@ impl< prehashed: bool, signature: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_PRIVATE_KEY_SIZE]); - let private_key_and_info = self - .export_private_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let private_key_and_info = self.export_private_key_and_key_info(key_id).await; let result = match private_key_and_info { Err(e) => { @@ -222,16 +219,16 @@ impl< Ok((private_key, key_info)) => match key_info.ty { KeyType::Asymmetric(Curve::NistP256) => { if prehashed { - nist_p256_sign_prehashed(private_key, message, signature) + nist_p256_sign_prehashed(&private_key, message, signature) } else { - nist_p256_sign(private_key, message, signature) + nist_p256_sign(&private_key, message, signature) } } KeyType::Asymmetric(Curve::NistP384) => { if prehashed { - nist_p384_sign_prehashed(private_key, message, signature) + nist_p384_sign_prehashed(&private_key, message, signature) } else { - nist_p384_sign(private_key, message, signature) + nist_p384_sign(&private_key, message, signature) } } _ => { @@ -314,10 +311,7 @@ impl< prehashed: bool, signature: &[u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_PUBLIC_KEY_SIZE]); - let public_key_and_info = self - .export_public_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let public_key_and_info = self.export_public_key_and_key_info(key_id).await; let result = match public_key_and_info { Err(e) => { @@ -330,16 +324,16 @@ impl< Ok((public_key, key_info)) => match key_info.ty { KeyType::Asymmetric(Curve::NistP256) => { if prehashed { - nist_p256_verify_prehashed(public_key, message, signature) + nist_p256_verify_prehashed(&public_key, message, signature) } else { - nist_p256_verify(public_key, message, signature) + nist_p256_verify(&public_key, message, signature) } } KeyType::Asymmetric(Curve::NistP384) => { if prehashed { - nist_p384_verify_prehashed(public_key, message, signature) + nist_p384_verify_prehashed(&public_key, message, signature) } else { - nist_p384_verify(public_key, message, signature) + nist_p384_verify(&public_key, message, signature) } } _ => { @@ -423,30 +417,28 @@ impl< } } - async fn export_private_key_and_key_info<'a>( + async fn export_private_key_and_key_info( &mut self, key_id: KeyId, - key_buffer: &'a mut [u8], - ) -> Result<(&'a [u8], KeyInfo), keystore::Error> { + ) -> Result<(PrivateKey, KeyInfo), keystore::Error> { // Lock keystore only once let locked_key_store = self.key_store.lock().await; Ok(( - locked_key_store.export_private_key_insecure(key_id, key_buffer)?, + locked_key_store.export_private_key_insecure(key_id)?, keystore::KeyStore::get_key_info(*locked_key_store, key_id)?, )) } - async fn export_public_key_and_key_info<'a>( + async fn export_public_key_and_key_info( &mut self, key_id: KeyId, - key_buffer: &'a mut [u8], - ) -> Result<(&'a [u8], KeyInfo), keystore::Error> { + ) -> Result<(PublicKey, KeyInfo), keystore::Error> { // Lock keystore only once let locked_key_store = self.key_store.lock().await; Ok(( - locked_key_store.export_public_key(key_id, key_buffer)?, + locked_key_store.export_public_key(key_id)?, keystore::KeyStore::get_key_info(*locked_key_store, key_id)?, )) } diff --git a/heimlig/src/hsm/workers/hmac_worker.rs b/heimlig/src/hsm/workers/hmac_worker.rs index f8cc49aa..359af23d 100644 --- a/heimlig/src/hsm/workers/hmac_worker.rs +++ b/heimlig/src/hsm/workers/hmac_worker.rs @@ -6,11 +6,10 @@ use crate::{ hmac_sha3_256_calculate, hmac_sha3_256_verify, hmac_sha3_384_calculate, hmac_sha3_384_verify, hmac_sha3_512_calculate, hmac_sha3_512_verify, }, - hsm::keystore::{self, KeyId, KeyInfo, KeyType}, + hsm::keystore::{self, KeyId, KeyInfo, SymmetricKey}, }; use embassy_sync::{blocking_mutex::raw::RawMutex, mutex::Mutex}; use futures::{Sink, SinkExt, Stream, StreamExt}; -use zeroize::Zeroizing; pub struct HmacWorker< 'data, @@ -112,10 +111,7 @@ impl< message: &[u8], tag: &'data mut [u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -133,12 +129,12 @@ impl< }; } match hash_algorithm { - HashAlgorithm::Sha2_256 => hmac_sha2_256_calculate(key, message, tag), - HashAlgorithm::Sha2_384 => hmac_sha2_384_calculate(key, message, tag), - HashAlgorithm::Sha2_512 => hmac_sha2_512_calculate(key, message, tag), - HashAlgorithm::Sha3_256 => hmac_sha3_256_calculate(key, message, tag), - HashAlgorithm::Sha3_384 => hmac_sha3_384_calculate(key, message, tag), - HashAlgorithm::Sha3_512 => hmac_sha3_512_calculate(key, message, tag), + HashAlgorithm::Sha2_256 => hmac_sha2_256_calculate(&key, message, tag), + HashAlgorithm::Sha2_384 => hmac_sha2_384_calculate(&key, message, tag), + HashAlgorithm::Sha2_512 => hmac_sha2_512_calculate(&key, message, tag), + HashAlgorithm::Sha3_256 => hmac_sha3_256_calculate(&key, message, tag), + HashAlgorithm::Sha3_384 => hmac_sha3_384_calculate(&key, message, tag), + HashAlgorithm::Sha3_512 => hmac_sha3_512_calculate(&key, message, tag), } } }; @@ -196,10 +192,7 @@ impl< message: &[u8], tag: &[u8], ) -> Response<'data> { - let mut key_buffer = Zeroizing::new([0u8; KeyType::MAX_SYMMETRIC_KEY_SIZE]); - let key_and_info = self - .export_key_and_key_info(key_id, key_buffer.as_mut_slice()) - .await; + let key_and_info = self.export_key_and_key_info(key_id).await; let result = match key_and_info { Err(e) => { return Response::Error { @@ -217,12 +210,12 @@ impl< }; } match hash_algorithm { - HashAlgorithm::Sha2_256 => hmac_sha2_256_verify(key, message, tag), - HashAlgorithm::Sha2_384 => hmac_sha2_384_verify(key, message, tag), - HashAlgorithm::Sha2_512 => hmac_sha2_512_verify(key, message, tag), - HashAlgorithm::Sha3_256 => hmac_sha3_256_verify(key, message, tag), - HashAlgorithm::Sha3_384 => hmac_sha3_384_verify(key, message, tag), - HashAlgorithm::Sha3_512 => hmac_sha3_512_verify(key, message, tag), + HashAlgorithm::Sha2_256 => hmac_sha2_256_verify(&key, message, tag), + HashAlgorithm::Sha2_384 => hmac_sha2_384_verify(&key, message, tag), + HashAlgorithm::Sha2_512 => hmac_sha2_512_verify(&key, message, tag), + HashAlgorithm::Sha3_256 => hmac_sha3_256_verify(&key, message, tag), + HashAlgorithm::Sha3_384 => hmac_sha3_384_verify(&key, message, tag), + HashAlgorithm::Sha3_512 => hmac_sha3_512_verify(&key, message, tag), } } }; @@ -274,12 +267,11 @@ impl< async fn export_key_and_key_info<'a>( &mut self, key_id: KeyId, - key_buffer: &'a mut [u8], - ) -> Result<(&'a [u8], KeyInfo), keystore::Error> { + ) -> Result<(SymmetricKey, KeyInfo), keystore::Error> { // Lock keystore only once let locked_key_store = self.key_store.lock().await; Ok(( - locked_key_store.export_symmetric_key_insecure(key_id, key_buffer)?, + locked_key_store.export_symmetric_key_insecure(key_id)?, keystore::KeyStore::get_key_info(*locked_key_store, key_id)?, )) } diff --git a/heimlig/src/integration/memory_key_store.rs b/heimlig/src/integration/memory_key_store.rs index 6e7d916c..21b35ec8 100644 --- a/heimlig/src/integration/memory_key_store.rs +++ b/heimlig/src/integration/memory_key_store.rs @@ -1,5 +1,8 @@ -use crate::hsm::keystore::{Error, InsecureKeyStore, KeyId, KeyInfo}; +use crate::hsm::keystore::{ + Error, InsecureKeyStore, KeyId, KeyInfo, PrivateKey, PublicKey, SymmetricKey, ZeroizableVec, +}; use heapless::Vec; +use zeroize::Zeroizing; pub struct MemoryKeyStore { storage: [u8; STORAGE_SIZE], @@ -68,11 +71,7 @@ impl InsecureKeyStore Ok(()) } - fn export_public_key_insecure<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_public_key_insecure(&self, id: KeyId) -> Result { let key_layout = self.layout.get(id).ok_or(Error::InvalidKeyId)?; assert!(key_layout.info.ty.is_asymmetric()); if key_layout.actual_size == 0 { @@ -82,42 +81,31 @@ impl InsecureKeyStore assert_eq!(key_layout.actual_size % 3, 0); let private_key_size = key_layout.actual_size / 3; let public_key_size = 2 * private_key_size; - if dest.len() < public_key_size { - return Err(Error::InvalidBufferSize); - } + let offset = key_layout.offset; let src = &self.storage[offset..(offset + public_key_size)]; - let dest = &mut dest[..src.len()]; - dest.copy_from_slice(src); - Ok(dest) + + Ok(Zeroizing::new(ZeroizableVec( + heapless::Vec::from_slice(src).unwrap(), + ))) } - fn export_symmetric_key_insecure<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_symmetric_key_insecure(&self, id: KeyId) -> Result { let key_layout = self.layout.get(id).ok_or(Error::InvalidKeyId)?; assert!(key_layout.info.ty.is_symmetric()); if key_layout.actual_size == 0 { return Err(Error::KeyNotFound); } - if dest.len() < key_layout.actual_size { - return Err(Error::InvalidBufferSize); - } let offset = key_layout.offset; let size = key_layout.actual_size; let src = &self.storage[offset..(offset + size)]; - let dest = &mut dest[..src.len()]; - dest.copy_from_slice(src); - Ok(dest) + + Ok(Zeroizing::new(ZeroizableVec( + heapless::Vec::from_slice(src).unwrap(), + ))) } - fn export_private_key_insecure<'data>( - &self, - id: KeyId, - dest: &'data mut [u8], - ) -> Result<&'data [u8], Error> { + fn export_private_key_insecure(&self, id: KeyId) -> Result { let key_layout = self.layout.get(id).ok_or(Error::InvalidKeyId)?; assert!(key_layout.info.ty.is_asymmetric()); if key_layout.actual_size == 0 { @@ -127,14 +115,13 @@ impl InsecureKeyStore assert_eq!(key_layout.actual_size % 3, 0); let private_key_size = key_layout.actual_size / 3; let public_key_size = 2 * private_key_size; - if dest.len() < private_key_size { - return Err(Error::InvalidBufferSize); - } + let offset = key_layout.offset + public_key_size; let src = &self.storage[offset..(offset + private_key_size)]; - let dest = &mut dest[..src.len()]; - dest.copy_from_slice(src); - Ok(dest) + + Ok(Zeroizing::new(ZeroizableVec( + heapless::Vec::from_slice(src).unwrap(), + ))) } fn delete_insecure(&mut self, id: KeyId) -> Result<(), Error> { @@ -249,7 +236,7 @@ impl TryFrom<&[KeyInfo]> #[cfg(test)] pub(crate) mod test { use super::*; - use crate::hsm::keystore::{Curve, Error, KeyId, KeyInfo, KeyPermissions, KeyStore, KeyType}; + use crate::hsm::keystore::{Curve, KeyPermissions, KeyStore, KeyType}; const TOTAL_KEY_SIZE: usize = KEY1_INFO.ty.key_size() + KEY2_INFO.ty.key_size(); const KEY1_INFO: KeyInfo = KeyInfo { @@ -279,7 +266,6 @@ pub(crate) mod test { let key_infos: [KeyInfo; 2] = [KEY1_INFO, KEY2_INFO]; let mut src_buffer = [0u8; KEY2_INFO.ty.key_size()]; - let mut dest_buffer = [0u8; KEY2_INFO.ty.key_size()]; let mut key_store = MemoryKeyStore::<{ TOTAL_KEY_SIZE }, 2>::try_new(&key_infos) .expect("failed to create key store"); for key_id in 0..10 { @@ -288,12 +274,8 @@ pub(crate) mod test { assert!(!InsecureKeyStore::is_key_available(&key_store, key_id)); assert!(KeyStore::size(&key_store, key_id).is_err()); assert!(InsecureKeyStore::size(&key_store, key_id).is_err()); - assert!(key_store - .export_public_key(key_id, &mut dest_buffer) - .is_err()); - assert!(key_store - .export_private_key(key_id, &mut dest_buffer) - .is_err()); + assert!(key_store.export_public_key(key_id).is_err()); + assert!(key_store.export_private_key(key_id).is_err()); } // Store first key @@ -303,19 +285,11 @@ pub(crate) mod test { .is_ok()); assert!(KeyStore::is_key_available(&key_store, KEY1_INFO.id)); assert!(InsecureKeyStore::is_key_available(&key_store, KEY1_INFO.id)); - assert_eq!( - key_store - .export_symmetric_key(KEY1_INFO.id, &mut dest_buffer) - .expect("failed to retrieve key from store") - .len(), - KEY1_INFO.ty.key_size() - ); - assert!(dest_buffer[0..KEY1_INFO.ty.key_size()] - .iter() - .all(|byte| *byte == 1)); - assert!(dest_buffer[KEY1_INFO.ty.key_size()..] - .iter() - .all(|byte| *byte == 0)); + let key = key_store + .export_symmetric_key(KEY1_INFO.id) + .expect("failed to retrieve key from store"); + assert_eq!(key.len(), KEY1_INFO.ty.key_size()); + assert!(key.iter().all(|byte| *byte == 1)); // Store second key src_buffer.fill(2); @@ -333,30 +307,16 @@ pub(crate) mod test { assert!(InsecureKeyStore::is_key_available(&key_store, KEY1_INFO.id)); assert_eq!( key_store - .export_public_key( - KEY2_INFO.id, - &mut dest_buffer[..KEY2_INFO.ty.public_key_size()] - ) + .export_public_key(KEY2_INFO.id,) .expect("failed to retrieve key from store") .len(), KEY2_INFO.ty.public_key_size() ); - assert_eq!( - key_store - .export_private_key( - KEY2_INFO.id, - &mut dest_buffer[KEY2_INFO.ty.public_key_size()..] - ) - .expect("failed to retrieve key from store") - .len(), - KEY2_INFO.ty.private_key_size() - ); - assert!(dest_buffer[0..KEY2_INFO.ty.key_size()] - .iter() - .all(|byte| *byte == 2)); - assert!(dest_buffer[KEY2_INFO.ty.key_size()..] - .iter() - .all(|byte| *byte == 0)); + let key = key_store + .export_private_key(KEY2_INFO.id) + .expect("failed to retrieve key from store"); + assert_eq!(key.len(), KEY2_INFO.ty.private_key_size()); + assert!(key.iter().all(|byte| *byte == 2)); // Delete keys assert_eq!(key_store.delete(UNKNOWN_KEY_ID), Err(Error::InvalidKeyId)); @@ -388,7 +348,6 @@ pub(crate) mod test { }; let key_infos: [KeyInfo; 1] = [NOTHING_ALLOWED_KEY]; let src_buffer = [0u8; NOTHING_ALLOWED_KEY.ty.key_size()]; - let mut dest_buffer = [0u8; NOTHING_ALLOWED_KEY.ty.key_size()]; let mut key_store = MemoryKeyStore::<{ TOTAL_KEY_SIZE }, 2>::try_new(&key_infos) .expect("failed to create key store"); match key_store.import_symmetric_key(NOTHING_ALLOWED_KEY.id, &src_buffer, false) { @@ -402,12 +361,12 @@ pub(crate) mod test { Ok(_) => panic!("Operation should have failed"), Err(e) => assert_eq!(e, Error::NotAllowed), } - match key_store.export_symmetric_key(NOTHING_ALLOWED_KEY.id, &mut dest_buffer) { + match key_store.export_symmetric_key(NOTHING_ALLOWED_KEY.id) { Ok(_) => panic!("Operation should have failed"), Err(e) => assert_eq!(e, Error::NotAllowed), } assert!(key_store - .export_symmetric_key_insecure(NOTHING_ALLOWED_KEY.id, &mut dest_buffer) + .export_symmetric_key_insecure(NOTHING_ALLOWED_KEY.id) .is_ok()); } diff --git a/heimlig/tests/ecdsa.rs b/heimlig/tests/ecdsa.rs index 11bab8c6..dc0e1340 100644 --- a/heimlig/tests/ecdsa.rs +++ b/heimlig/tests/ecdsa.rs @@ -62,7 +62,10 @@ async fn sign_verify_nist_p256() { // Export public key let org_request_id = api - .export_public_key(ASYM_NIST_P256_KEY.id, &mut large_public_key_buffer) + .export_public_key( + ASYM_NIST_P256_KEY.id, + &mut large_public_key_buffer[..ASYM_NIST_P256_KEY.ty.public_key_size()], + ) .await .expect("failed to send request"); let Response::ExportPublicKey { @@ -78,7 +81,10 @@ async fn sign_verify_nist_p256() { // Export private key let org_request_id = api - .export_private_key(ASYM_NIST_P256_KEY.id, &mut large_private_key_buffer) + .export_private_key( + ASYM_NIST_P256_KEY.id, + &mut large_private_key_buffer[..ASYM_NIST_P256_KEY.ty.private_key_size()], + ) .await .expect("failed to send request"); let Response::ExportPrivateKey { diff --git a/heimlig/tests/misc.rs b/heimlig/tests/misc.rs index 1d5d1d5c..7c7aa787 100644 --- a/heimlig/tests/misc.rs +++ b/heimlig/tests/misc.rs @@ -56,7 +56,10 @@ async fn generate_symmetric_key() { // Export key let org_request_id = api - .export_symmetric_key(SYM_256_KEY.id, &mut large_key_buffer) + .export_symmetric_key( + SYM_256_KEY.id, + &mut large_key_buffer[..SYM_256_KEY.ty.key_size()], + ) .await .expect("failed to send request"); let Response::ExportSymmetricKey {