Skip to content

Commit

Permalink
Add error support to hash and HMAC board API (#429)
Browse files Browse the repository at this point in the history
Fixes #176

Co-authored-by: Zhou Fang <[email protected]>
Co-authored-by: Julien Cretin <[email protected]>
  • Loading branch information
3 people authored Apr 22, 2024
1 parent cb57433 commit bd5a2f2
Show file tree
Hide file tree
Showing 11 changed files with 147 additions and 40 deletions.
12 changes: 11 additions & 1 deletion crates/board/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
# Changelog

## 0.6.1-git
## 0.7.0-git

### Major

- Change `crypto::{Hash,Hmac}` to depend on `crypto::WithError`

### Minor

- Add `crypto::{HashApi,HmacApi}` helpers for `crypto::{Hash,Hmac}`
- Add `crypto::NoError` helper for `crypto::WithError`
- Add `crypto::WithError` to add error support to RustCrypto (fix #176)

### Patch

Expand Down
2 changes: 1 addition & 1 deletion crates/board/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/board/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "wasefire-board-api"
version = "0.6.1-git"
version = "0.7.0-git"
authors = ["Julien Cretin <[email protected]>"]
license = "Apache-2.0"
publish = true
Expand Down
118 changes: 108 additions & 10 deletions crates/board/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,21 @@
#[cfg(feature = "internal-api-crypto-hash")]
use crypto_common::BlockSizeUser;
#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
use crypto_common::Output;
#[cfg(feature = "internal-api-crypto-hmac")]
use crypto_common::KeyInit;
use crypto_common::{InvalidLength, KeyInit};
#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
use digest::Update;
#[cfg(feature = "internal-api-crypto-hmac")]
use digest::{FixedOutput, MacMarker};
#[cfg(feature = "internal-api-crypto-hash")]
use digest::{FixedOutputReset, HashMarker};
#[cfg(feature = "internal-api-crypto-hmac")]
use wasefire_error::Code;

#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
use crate::Support;
use crate::{Error, Support};

#[cfg(feature = "internal-api-crypto-aead")]
pub mod aead;
Expand Down Expand Up @@ -71,21 +75,52 @@ pub trait Api: Send {
/// Hash interface.
#[cfg(feature = "internal-api-crypto-hash")]
pub trait Hash:
Support<bool> + Send + Default + BlockSizeUser + Update + FixedOutputReset + HashMarker
Support<bool> + Send + Default + BlockSizeUser + Update + FixedOutputReset + HashMarker + WithError
{
}
/// HMAC interface.
#[cfg(feature = "internal-api-crypto-hmac")]
pub trait Hmac: Support<bool> + Send + KeyInit + Update + FixedOutput + MacMarker {}
pub trait Hmac:
Support<bool> + Send + KeyInit + Update + FixedOutput + MacMarker + WithError
{
}

#[cfg(feature = "internal-api-crypto-hash")]
impl<
T: Support<bool> + Send + Default + BlockSizeUser + Update + FixedOutputReset + HashMarker,
> Hash for T
impl<T> Hash for T where T: Support<bool>
+ Send
+ Default
+ BlockSizeUser
+ Update
+ FixedOutputReset
+ HashMarker
+ WithError
{
}
#[cfg(feature = "internal-api-crypto-hmac")]
impl<T: Support<bool> + Send + KeyInit + Update + FixedOutput + MacMarker> Hmac for T {}
impl<T> Hmac for T where T: Support<bool> + Send + KeyInit + Update + FixedOutput + MacMarker + WithError
{}

/// Adds error support to operations with an infallible signature.
#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
pub trait WithError {
/// Executes a seemingly infallible operation with error support.
///
/// The closure may actually call multiple seemingly infaillible operations. Each such call
/// should support running after a previous one failed. This funtion returns an error if any
/// such call failed.
fn with_error<T>(operation: impl FnOnce() -> T) -> Result<T, Error>;
}

/// Helper trait for infaillible operations.
#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
pub trait NoError {}

#[cfg(any(feature = "internal-api-crypto-hash", feature = "internal-api-crypto-hmac"))]
impl<T: NoError> WithError for T {
fn with_error<R>(operation: impl FnOnce() -> R) -> Result<R, Error> {
Ok(operation())
}
}

/// AES-128-CCM interface.
#[cfg(feature = "api-crypto-aes128-ccm")]
Expand Down Expand Up @@ -158,8 +193,71 @@ impl crate::Supported for sha2::Sha256 {}
impl crate::Supported for sha2::Sha384 {}

#[cfg(feature = "internal-software-crypto-hmac")]
impl<D: Support<bool> + Default + BlockSizeUser + Update + FixedOutput + HashMarker> Support<bool>
for hmac::SimpleHmac<D>
impl<D> Support<bool> for hmac::SimpleHmac<D>
where D: Support<bool> + Default + BlockSizeUser + Update + FixedOutput + HashMarker + WithError
{
const SUPPORT: bool = D::SUPPORT;
}

#[cfg(feature = "software-crypto-sha256")]
impl NoError for sha2::Sha256 {}

#[cfg(feature = "software-crypto-sha384")]
impl NoError for sha2::Sha384 {}

#[cfg(feature = "internal-software-crypto-hmac")]
impl<D> WithError for hmac::SimpleHmac<D>
where D: Support<bool> + Default + BlockSizeUser + Update + FixedOutput + HashMarker + WithError
{
fn with_error<T>(operation: impl FnOnce() -> T) -> Result<T, Error> {
D::with_error(operation)
}
}

/// Hash wrapper with error support.
#[cfg(feature = "internal-api-crypto-hash")]
pub struct HashApi<T: Hash>(T);

/// HMAC wrapper with error support.
#[cfg(feature = "internal-api-crypto-hmac")]
pub struct HmacApi<T: Hmac>(T);

#[cfg(feature = "internal-api-crypto-hash")]
impl<T: Hash> HashApi<T> {
/// Creates a hash wrapper.
pub fn new() -> Result<Self, Error> {
T::with_error(|| T::default()).map(HashApi)
}

/// Updates the hash with the provided data.
pub fn update(&mut self, data: &[u8]) -> Result<(), Error> {
T::with_error(|| self.0.update(data))
}

/// Finalizes the hash to the provided output.
pub fn finalize_into(self, out: &mut Output<T>) -> Result<(), Error> {
T::with_error(|| self.0.finalize_into(out))
}
}

#[cfg(feature = "internal-api-crypto-hmac")]
impl<T: Hmac> HmacApi<T> {
/// Creates an HMAC wrapper.
pub fn new(key: &[u8]) -> Result<Self, Error> {
match T::with_error(|| T::new_from_slice(key)) {
Ok(Ok(x)) => Ok(HmacApi(x)),
Ok(Err(InvalidLength)) => Err(Error::user(Code::InvalidLength)),
Err(e) => Err(e),
}
}

/// Updates the HMAC with the provided data.
pub fn update(&mut self, data: &[u8]) -> Result<(), Error> {
T::with_error(|| self.0.update(data))
}

/// Finalizes the HMAC to the provided output.
pub fn finalize_into(self, out: &mut Output<T>) -> Result<(), Error> {
T::with_error(|| self.0.finalize_into(out))
}
}
2 changes: 1 addition & 1 deletion crates/runner-host/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/runner-nordic/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion crates/scheduler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Minor

- Migrate to `crypto::{Hash,Hmac}` depending on `crypto::WithError`
- Change `led::{get,set}()` to never trap and return an error instead

### Patch
Expand Down Expand Up @@ -124,4 +125,4 @@

## 0.1.0

<!-- Increment to skip CHANGELOG.md test: 32 -->
<!-- Increment to skip CHANGELOG.md test: 33 -->
2 changes: 1 addition & 1 deletion crates/scheduler/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/scheduler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ generic-array = { version = "0.14.7", default-features = false }
portable-atomic = { version = "1.6.0", default-features = false }
typenum = { version = "1.17.0", default-features = false }
wasefire-applet-api = { version = "0.6.0", path = "../api", features = ["host"] }
wasefire-board-api = { version = "0.6.1-git", path = "../board" }
wasefire-board-api = { version = "0.7.0-git", path = "../board" }
wasefire-error = { version = "0.1.0", path = "../error" }
wasefire-logger = { version = "0.1.4", path = "../logger" }
wasefire-store = { version = "0.2.4-git", path = "../store", optional = true }
Expand Down
8 changes: 4 additions & 4 deletions crates/scheduler/src/applet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,13 @@ impl<B: Board> Default for AppletHashes<B> {
#[cfg(feature = "internal-hash-context")]
pub enum HashContext<B: Board> {
#[cfg(feature = "board-api-crypto-sha256")]
Sha256(board::crypto::Sha256<B>),
Sha256(board::crypto::HashApi<board::crypto::Sha256<B>>),
#[cfg(feature = "board-api-crypto-sha384")]
Sha384(board::crypto::Sha384<B>),
Sha384(board::crypto::HashApi<board::crypto::Sha384<B>>),
#[cfg(feature = "board-api-crypto-hmac-sha256")]
HmacSha256(board::crypto::HmacSha256<B>),
HmacSha256(board::crypto::HmacApi<board::crypto::HmacSha256<B>>),
#[cfg(feature = "board-api-crypto-hmac-sha384")]
HmacSha384(board::crypto::HmacSha384<B>),
HmacSha384(board::crypto::HmacApi<board::crypto::HmacSha384<B>>),
_Impossible(board::Impossible<B>),
}

Expand Down
34 changes: 16 additions & 18 deletions crates/scheduler/src/call/crypto/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,16 @@ fn initialize<B: Board>(mut call: SchedulerCall<B, api::initialize::Sig>) {
let result = try {
let context = match convert_hash_algorithm::<B>(*algorithm)?? {
#[cfg(feature = "board-api-crypto-sha256")]
Algorithm::Sha256 => HashContext::Sha256(board::crypto::Sha256::<B>::default()),
Algorithm::Sha256 => board::crypto::HashApi::new().map(HashContext::Sha256),
#[cfg(feature = "board-api-crypto-sha384")]
Algorithm::Sha384 => HashContext::Sha384(board::crypto::Sha384::<B>::default()),
Algorithm::Sha384 => board::crypto::HashApi::new().map(HashContext::Sha384),
#[allow(unreachable_patterns)]
_ => Err(Trap)?,
};
Ok(scheduler.applet.hashes.insert(context)? as u32)
match context {
Ok(context) => Ok(scheduler.applet.hashes.insert(context)? as u32),
Err(error) => Err(error),
}
};
call.reply(result);
}
Expand All @@ -79,7 +82,7 @@ fn update<B: Board>(mut call: SchedulerCall<B, api::update::Sig>) {
let api::update::Params { id, data, length } = call.read();
let scheduler = call.scheduler();
let memory = scheduler.applet.store.memory();
let result = try {
let result: Result<Result<(), _>, _> = try {
let data = memory.get(*data, *length)?;
match scheduler.applet.hashes.get_mut(*id as usize)? {
#[cfg(feature = "board-api-crypto-sha256")]
Expand All @@ -88,7 +91,6 @@ fn update<B: Board>(mut call: SchedulerCall<B, api::update::Sig>) {
HashContext::Sha384(context) => context.update(data),
_ => trap_use!(data),
}
Ok(())
};
call.reply(result);
}
Expand All @@ -101,7 +103,7 @@ fn finalize<B: Board>(mut call: SchedulerCall<B, api::finalize::Sig>) {
let result = try {
let context = scheduler.applet.hashes.take(*id as usize)?;
match context {
_ if *digest == 0 => (),
_ if *digest == 0 => Ok(()),
#[cfg(feature = "board-api-crypto-sha256")]
HashContext::Sha256(context) => {
let digest = memory.get_array_mut::<32>(*digest)?;
Expand All @@ -114,7 +116,6 @@ fn finalize<B: Board>(mut call: SchedulerCall<B, api::finalize::Sig>) {
}
_ => trap_use!(memory),
}
Ok(())
};
call.reply(result);
}
Expand All @@ -134,17 +135,16 @@ fn hmac_initialize<B: Board>(mut call: SchedulerCall<B, api::hmac_initialize::Si
let key = memory.get(*key, *key_len)?;
let context = match convert_hmac_algorithm::<B>(*algorithm)?? {
#[cfg(feature = "board-api-crypto-hmac-sha256")]
Algorithm::Sha256 => HashContext::HmacSha256(
board::crypto::HmacSha256::<B>::new_from_slice(key).map_err(|_| Trap)?,
),
Algorithm::Sha256 => board::crypto::HmacApi::new(key).map(HashContext::HmacSha256),
#[cfg(feature = "board-api-crypto-hmac-sha384")]
Algorithm::Sha384 => HashContext::HmacSha384(
board::crypto::HmacSha384::<B>::new_from_slice(key).map_err(|_| Trap)?,
),
Algorithm::Sha384 => board::crypto::HmacApi::new(key).map(HashContext::HmacSha384),
#[allow(unreachable_patterns)]
_ => trap_use!(key),
};
Ok(scheduler.applet.hashes.insert(context)? as u32)
match context {
Ok(context) => Ok(scheduler.applet.hashes.insert(context)? as u32),
Err(error) => Err(error),
}
};
call.reply(result);
}
Expand All @@ -154,7 +154,7 @@ fn hmac_update<B: Board>(mut call: SchedulerCall<B, api::hmac_update::Sig>) {
let api::hmac_update::Params { id, data, length } = call.read();
let scheduler = call.scheduler();
let memory = scheduler.applet.store.memory();
let result = try {
let result: Result<Result<(), _>, _> = try {
let data = memory.get(*data, *length)?;
match scheduler.applet.hashes.get_mut(*id as usize)? {
#[cfg(feature = "board-api-crypto-hmac-sha256")]
Expand All @@ -163,7 +163,6 @@ fn hmac_update<B: Board>(mut call: SchedulerCall<B, api::hmac_update::Sig>) {
HashContext::HmacSha384(context) => context.update(data),
_ => trap_use!(data),
}
Ok(())
};
call.reply(result);
}
Expand All @@ -176,7 +175,7 @@ fn hmac_finalize<B: Board>(mut call: SchedulerCall<B, api::hmac_finalize::Sig>)
let result = try {
let context = scheduler.applet.hashes.take(*id as usize)?;
match context {
_ if *hmac == 0 => (),
_ if *hmac == 0 => Ok(()),
#[cfg(feature = "board-api-crypto-hmac-sha256")]
HashContext::HmacSha256(context) => {
let hmac = memory.get_array_mut::<32>(*hmac)?;
Expand All @@ -189,7 +188,6 @@ fn hmac_finalize<B: Board>(mut call: SchedulerCall<B, api::hmac_finalize::Sig>)
}
_ => trap_use!(memory),
}
Ok(())
};
call.reply(result);
}
Expand Down

0 comments on commit bd5a2f2

Please sign in to comment.