diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f46f656e5f..6ec19bcd6f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 by default). - Change store implementations to use littlefs2’s `DynFilesystem` trait instead of being generic over the storage implementation. +- Add `nonce` argument to `wrap_key` and `unwrap_key` syscalls. +- Use nonce as IV for Aes256Cbc mechanism. ### Fixed diff --git a/src/api.rs b/src/api.rs index a792c6cfaaa..327dec41c9f 100644 --- a/src/api.rs +++ b/src/api.rs @@ -312,6 +312,7 @@ pub mod request { - wrapping_key: KeyId - wrapped_key: Message - associated_data: Message + - nonce: ShortData - attributes: StorageAttributes Verify: @@ -327,6 +328,7 @@ pub mod request { - wrapping_key: KeyId - key: KeyId - associated_data: ShortData + - nonce: Option RequestUserConsent: - level: consent::Level diff --git a/src/client.rs b/src/client.rs index 1c9cf1d9c02..cf6e88001a6 100644 --- a/src/client.rs +++ b/src/client.rs @@ -119,6 +119,7 @@ pub trait PollClient { } } +#[must_use = "Syscalls must be polled with the `syscall` macro"] pub struct FutureResult<'c, T, C: ?Sized> where C: PollClient, @@ -536,15 +537,18 @@ pub trait CryptoClient: PollClient { wrapping_key: KeyId, wrapped_key: Message, associated_data: &[u8], + nonce: &[u8], attributes: StorageAttributes, ) -> ClientResult<'c, reply::UnwrapKey, Self> { let associated_data = Message::from_slice(associated_data).map_err(|_| ClientError::DataTooLarge)?; + let nonce = ShortData::from_slice(nonce).map_err(|_| ClientError::DataTooLarge)?; self.request(request::UnwrapKey { mechanism, wrapping_key, wrapped_key, associated_data, + nonce, attributes, }) } @@ -555,6 +559,7 @@ pub trait CryptoClient: PollClient { wrapping_key: KeyId, key: KeyId, associated_data: &[u8], + nonce: Option, ) -> ClientResult<'_, reply::WrapKey, Self> { let associated_data = Bytes::from_slice(associated_data).map_err(|_| ClientError::DataTooLarge)?; @@ -563,6 +568,7 @@ pub trait CryptoClient: PollClient { wrapping_key, key, associated_data, + nonce, }) } } diff --git a/src/client/mechanisms.rs b/src/client/mechanisms.rs index 0d0dab65e44..522841186d9 100644 --- a/src/client/mechanisms.rs +++ b/src/client/mechanisms.rs @@ -8,16 +8,24 @@ pub trait Aes256Cbc: CryptoClient { &'c mut self, key: KeyId, message: &[u8], + iv: &[u8], ) -> ClientResult<'c, reply::Decrypt, Self> { - self.decrypt(Mechanism::Aes256Cbc, key, message, &[], &[], &[]) + self.decrypt(Mechanism::Aes256Cbc, key, message, &[], iv, &[]) } fn wrap_key_aes256cbc( &mut self, wrapping_key: KeyId, key: KeyId, + iv: Option<&[u8; 16]>, ) -> ClientResult<'_, reply::WrapKey, Self> { - self.wrap_key(Mechanism::Aes256Cbc, wrapping_key, key, &[]) + self.wrap_key( + Mechanism::Aes256Cbc, + wrapping_key, + key, + &[], + iv.and_then(|iv| ShortData::from_slice(iv).ok()), + ) } } @@ -81,6 +89,7 @@ pub trait Chacha8Poly1305: CryptoClient { wrapping_key, Message::from_slice(wrapped_key).map_err(|_| ClientError::DataTooLarge)?, associated_data, + &[], StorageAttributes::new().set_persistence(location), ) } @@ -90,12 +99,14 @@ pub trait Chacha8Poly1305: CryptoClient { wrapping_key: KeyId, key: KeyId, associated_data: &[u8], + nonce: Option<&[u8; 12]>, ) -> ClientResult<'c, reply::WrapKey, Self> { self.wrap_key( Mechanism::Chacha8Poly1305, wrapping_key, key, associated_data, + nonce.and_then(|nonce| ShortData::from_slice(nonce).ok()), ) } } diff --git a/src/mechanisms/aes256cbc.rs b/src/mechanisms/aes256cbc.rs index 6b0ca4c8fcb..192cbda0be5 100644 --- a/src/mechanisms/aes256cbc.rs +++ b/src/mechanisms/aes256cbc.rs @@ -31,8 +31,15 @@ impl Encrypt for super::Aes256Cbc { .try_into() .map_err(|_| Error::InternalError)?; - let zero_iv = [0u8; 16]; - let cipher = Aes256CbcEnc::new_from_slices(&symmetric_key, &zero_iv).unwrap(); + let iv = if let Some(nonce) = &request.nonce { + nonce + .as_slice() + .try_into() + .map_err(|_| Error::MechanismParamInvalid)? + } else { + [0u8; 16] + }; + let cipher = Aes256CbcEnc::new_from_slices(&symmetric_key, &iv).unwrap(); // buffer must have enough space for message+padding let mut buffer = request.message.clone(); @@ -83,7 +90,7 @@ impl WrapKey for super::Aes256Cbc { key: request.wrapping_key, message, associated_data: request.associated_data.clone(), - nonce: None, + nonce: request.nonce.clone(), }; let encryption_reply = ::encrypt(keystore, &encryption_request)?; @@ -117,8 +124,16 @@ impl Decrypt for super::Aes256Cbc { .try_into() .map_err(|_| Error::InternalError)?; - let zero_iv = [0u8; 16]; - let cipher = Aes256CbcDec::new_from_slices(&symmetric_key, &zero_iv).unwrap(); + let iv = if request.nonce.is_empty() { + [0u8; 16] + } else { + request + .nonce + .as_slice() + .try_into() + .map_err(|_| Error::MechanismParamInvalid)? + }; + let cipher = Aes256CbcDec::new_from_slices(&symmetric_key, &iv).unwrap(); // buffer must have enough space for message+padding let mut buffer = request.message.clone(); diff --git a/src/mechanisms/chacha8poly1305.rs b/src/mechanisms/chacha8poly1305.rs index 9fe96030bc1..e2cb68cf9c4 100644 --- a/src/mechanisms/chacha8poly1305.rs +++ b/src/mechanisms/chacha8poly1305.rs @@ -183,7 +183,7 @@ impl WrapKey for super::Chacha8Poly1305 { key: request.wrapping_key, message, associated_data: request.associated_data.clone(), - nonce: None, + nonce: request.nonce.clone(), }; let encryption_reply = ::encrypt(keystore, &encryption_request)?; diff --git a/src/serde_extensions.rs b/src/serde_extensions.rs index 8c372d1a3e9..fa298269665 100644 --- a/src/serde_extensions.rs +++ b/src/serde_extensions.rs @@ -180,6 +180,7 @@ where /// A result returned by [`ExtensionClient`][] and clients using it. pub type ExtensionResult<'a, E, T, C> = Result, ClientError>; +#[must_use = "Syscalls must be polled with the `syscall` macro"] /// A future of an [`ExtensionResult`][]. pub struct ExtensionFutureResult<'c, E, T, C: ?Sized> { client: &'c mut C,