Add incremental hash to FirmwareUpdater

This adds support for computing any hash over the update in the dtu area by providing a closure to the hash update function.
This commit is contained in:
Rasmus Melchior Jacobsen 2023-04-03 14:59:55 +02:00
parent 0909a6cd3f
commit 8aaffe82e7
2 changed files with 43 additions and 26 deletions

View File

@ -118,13 +118,13 @@ impl FirmwareUpdater {
_state_and_dfu_flash: &mut F, _state_and_dfu_flash: &mut F,
_public_key: &[u8], _public_key: &[u8],
_signature: &[u8], _signature: &[u8],
_update_len: usize, _update_len: u32,
_aligned: &mut [u8], _aligned: &mut [u8],
) -> Result<(), FirmwareUpdaterError> { ) -> Result<(), FirmwareUpdaterError> {
let _read_size = _aligned.len(); let _read_size = _aligned.len();
assert_eq!(_aligned.len(), F::WRITE_SIZE); assert_eq!(_aligned.len(), F::WRITE_SIZE);
assert!(_update_len <= self.dfu.len()); assert!(_update_len <= self.dfu.len() as u32);
#[cfg(feature = "ed25519-dalek")] #[cfg(feature = "ed25519-dalek")]
{ {
@ -136,11 +136,8 @@ impl FirmwareUpdater {
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
let mut digest = Sha512::new(); let mut digest = Sha512::new();
for offset in (0.._update_len).step_by(_aligned.len()) { self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))
self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; .await?;
let len = core::cmp::min(_update_len - offset, _aligned.len());
digest.update(&_aligned[..len]);
}
public_key public_key
.verify(&digest.finalize(), &signature) .verify(&digest.finalize(), &signature)
@ -161,11 +158,8 @@ impl FirmwareUpdater {
let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
let mut digest = Sha512::new(); let mut digest = Sha512::new();
for offset in (0.._update_len).step_by(_aligned.len()) { self.incremental_hash(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))
self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; .await?;
let len = core::cmp::min(_update_len - offset, _aligned.len());
digest.update(&_aligned[..len]);
}
let message = digest.finalize(); let message = digest.finalize();
let r = public_key.verify(&message, &signature); let r = public_key.verify(&message, &signature);
@ -182,6 +176,22 @@ impl FirmwareUpdater {
self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await
} }
/// Iterate through the DFU and process all bytes with the provided closure.
pub async fn incremental_hash<F: AsyncNorFlash>(
&mut self,
dfu_flash: &mut F,
update_len: u32,
aligned: &mut [u8],
mut update: impl FnMut(&[u8]),
) -> Result<(), FirmwareUpdaterError> {
for offset in (0..update_len).step_by(aligned.len()) {
self.dfu.read(dfu_flash, offset, aligned).await?;
let len = core::cmp::min((update_len - offset) as usize, aligned.len());
update(&aligned[..len]);
}
Ok(())
}
/// Mark to trigger firmware swap on next boot. /// Mark to trigger firmware swap on next boot.
/// ///
/// # Safety /// # Safety
@ -317,14 +327,13 @@ impl FirmwareUpdater {
_state_and_dfu_flash: &mut F, _state_and_dfu_flash: &mut F,
_public_key: &[u8], _public_key: &[u8],
_signature: &[u8], _signature: &[u8],
_update_len: usize, _update_len: u32,
_aligned: &mut [u8], _aligned: &mut [u8],
) -> Result<(), FirmwareUpdaterError> { ) -> Result<(), FirmwareUpdaterError> {
let _end = self.dfu.from + _update_len;
let _read_size = _aligned.len(); let _read_size = _aligned.len();
assert_eq!(_aligned.len(), F::WRITE_SIZE); assert_eq!(_aligned.len(), F::WRITE_SIZE);
assert!(_end <= self.dfu.to); assert!(_update_len <= self.dfu.len() as u32);
#[cfg(feature = "ed25519-dalek")] #[cfg(feature = "ed25519-dalek")]
{ {
@ -336,11 +345,7 @@ impl FirmwareUpdater {
let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
let mut digest = Sha512::new(); let mut digest = Sha512::new();
for offset in (0.._update_len).step_by(_aligned.len()) { self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?;
self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
let len = core::cmp::min(_update_len - offset, _aligned.len());
digest.update(&_aligned[..len]);
}
public_key public_key
.verify(&digest.finalize(), &signature) .verify(&digest.finalize(), &signature)
@ -361,11 +366,7 @@ impl FirmwareUpdater {
let signature = Signature::try_from(&signature).map_err(into_signature_error)?; let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
let mut digest = Sha512::new(); let mut digest = Sha512::new();
for offset in (0.._update_len).step_by(_aligned.len()) { self.incremental_hash_blocking(_state_and_dfu_flash, _update_len, _aligned, |x| digest.update(x))?;
self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
let len = core::cmp::min(_update_len - offset, _aligned.len());
digest.update(&_aligned[..len]);
}
let message = digest.finalize(); let message = digest.finalize();
let r = public_key.verify(&message, &signature); let r = public_key.verify(&message, &signature);
@ -382,6 +383,22 @@ impl FirmwareUpdater {
self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash)
} }
/// Iterate through the DFU and process all bytes with the provided closure.
pub fn incremental_hash_blocking<F: NorFlash>(
&mut self,
dfu_flash: &mut F,
update_len: u32,
aligned: &mut [u8],
mut update: impl FnMut(&[u8]),
) -> Result<(), FirmwareUpdaterError> {
for offset in (0..update_len).step_by(aligned.len()) {
self.dfu.read_blocking(dfu_flash, offset, aligned)?;
let len = core::cmp::min((update_len - offset) as usize, aligned.len());
update(&aligned[..len]);
}
Ok(())
}
/// Mark to trigger firmware swap on next boot. /// Mark to trigger firmware swap on next boot.
/// ///
/// # Safety /// # Safety

View File

@ -308,7 +308,7 @@ mod tests {
&mut flash, &mut flash,
&public_key.to_bytes(), &public_key.to_bytes(),
&signature.to_bytes(), &signature.to_bytes(),
firmware_len, firmware_len as u32,
&mut aligned, &mut aligned,
)) ))
.is_ok()); .is_ok());