aboutsummaryrefslogtreecommitdiff
path: root/embassy-boot
diff options
context:
space:
mode:
authorRasmus Melchior Jacobsen <[email protected]>2023-04-11 07:36:23 +0200
committerRasmus Melchior Jacobsen <[email protected]>2023-04-11 07:36:23 +0200
commitd8c92c53d647b170cb49ede1b608e58c2dd676d2 (patch)
treed4fb6ee79087b598cad5d5fe5ce023626d4a21be /embassy-boot
parent05b2b2fb5f0f8d52689057c22dd2fa026d6cc796 (diff)
parent1f25d2ba8335300368b32f9ceedf163376dfdb6f (diff)
Merge remote-tracking branch 'upstream/master' into u32-partition
Diffstat (limited to 'embassy-boot')
-rw-r--r--embassy-boot/boot/Cargo.toml4
-rw-r--r--embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs30
-rw-r--r--embassy-boot/boot/src/digest_adapters/mod.rs5
-rw-r--r--embassy-boot/boot/src/digest_adapters/salty.rs29
-rw-r--r--embassy-boot/boot/src/firmware_updater.rs128
-rw-r--r--embassy-boot/boot/src/lib.rs1
6 files changed, 160 insertions, 37 deletions
diff --git a/embassy-boot/boot/Cargo.toml b/embassy-boot/boot/Cargo.toml
index 3312c2f9f..c4ebdaff2 100644
--- a/embassy-boot/boot/Cargo.toml
+++ b/embassy-boot/boot/Cargo.toml
@@ -24,6 +24,7 @@ features = ["defmt"]
24 24
25[dependencies] 25[dependencies]
26defmt = { version = "0.3", optional = true } 26defmt = { version = "0.3", optional = true }
27digest = "0.10"
27log = { version = "0.4", optional = true } 28log = { version = "0.4", optional = true }
28ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true } 29ed25519-dalek = { version = "1.0.1", default_features = false, features = ["u32_backend"], optional = true }
29embassy-sync = { version = "0.1.0", path = "../../embassy-sync" } 30embassy-sync = { version = "0.1.0", path = "../../embassy-sync" }
@@ -37,6 +38,7 @@ log = "0.4"
37env_logger = "0.9" 38env_logger = "0.9"
38rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version 39rand = "0.7" # ed25519-dalek v1.0.1 depends on this exact version
39futures = { version = "0.3", features = ["executor"] } 40futures = { version = "0.3", features = ["executor"] }
41sha1 = "0.10.5"
40 42
41[dev-dependencies.ed25519-dalek] 43[dev-dependencies.ed25519-dalek]
42default_features = false 44default_features = false
@@ -47,4 +49,4 @@ ed25519-dalek = ["dep:ed25519-dalek", "_verify"]
47ed25519-salty = ["dep:salty", "_verify"] 49ed25519-salty = ["dep:salty", "_verify"]
48 50
49#Internal features 51#Internal features
50_verify = [] \ No newline at end of file 52_verify = []
diff --git a/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
new file mode 100644
index 000000000..a184d1c51
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/ed25519_dalek.rs
@@ -0,0 +1,30 @@
1use digest::typenum::U64;
2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
3use ed25519_dalek::Digest as _;
4
5pub struct Sha512(ed25519_dalek::Sha512);
6
7impl Default for Sha512 {
8 fn default() -> Self {
9 Self(ed25519_dalek::Sha512::new())
10 }
11}
12
13impl Update for Sha512 {
14 fn update(&mut self, data: &[u8]) {
15 self.0.update(data)
16 }
17}
18
19impl FixedOutput for Sha512 {
20 fn finalize_into(self, out: &mut digest::Output<Self>) {
21 let result = self.0.finalize();
22 out.as_mut_slice().copy_from_slice(result.as_slice())
23 }
24}
25
26impl OutputSizeUser for Sha512 {
27 type OutputSize = U64;
28}
29
30impl HashMarker for Sha512 {}
diff --git a/embassy-boot/boot/src/digest_adapters/mod.rs b/embassy-boot/boot/src/digest_adapters/mod.rs
new file mode 100644
index 000000000..9b4b4b60c
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/mod.rs
@@ -0,0 +1,5 @@
1#[cfg(feature = "ed25519-dalek")]
2pub(crate) mod ed25519_dalek;
3
4#[cfg(feature = "ed25519-salty")]
5pub(crate) mod salty;
diff --git a/embassy-boot/boot/src/digest_adapters/salty.rs b/embassy-boot/boot/src/digest_adapters/salty.rs
new file mode 100644
index 000000000..2b5dcf3af
--- /dev/null
+++ b/embassy-boot/boot/src/digest_adapters/salty.rs
@@ -0,0 +1,29 @@
1use digest::typenum::U64;
2use digest::{FixedOutput, HashMarker, OutputSizeUser, Update};
3
4pub struct Sha512(salty::Sha512);
5
6impl Default for Sha512 {
7 fn default() -> Self {
8 Self(salty::Sha512::new())
9 }
10}
11
12impl Update for Sha512 {
13 fn update(&mut self, data: &[u8]) {
14 self.0.update(data)
15 }
16}
17
18impl FixedOutput for Sha512 {
19 fn finalize_into(self, out: &mut digest::Output<Self>) {
20 let result = self.0.finalize();
21 out.as_mut_slice().copy_from_slice(result.as_slice())
22 }
23}
24
25impl OutputSizeUser for Sha512 {
26 type OutputSize = U64;
27}
28
29impl HashMarker for Sha512 {}
diff --git a/embassy-boot/boot/src/firmware_updater.rs b/embassy-boot/boot/src/firmware_updater.rs
index 61c902ed0..6aedec003 100644
--- a/embassy-boot/boot/src/firmware_updater.rs
+++ b/embassy-boot/boot/src/firmware_updater.rs
@@ -1,3 +1,4 @@
1use digest::Digest;
1use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind}; 2use embedded_storage::nor_flash::{NorFlash, NorFlashError, NorFlashErrorKind};
2use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash; 3use embedded_storage_async::nor_flash::NorFlash as AsyncNorFlash;
3 4
@@ -121,28 +122,27 @@ impl FirmwareUpdater {
121 122
122 #[cfg(feature = "ed25519-dalek")] 123 #[cfg(feature = "ed25519-dalek")]
123 { 124 {
124 use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; 125 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
126
127 use crate::digest_adapters::ed25519_dalek::Sha512;
125 128
126 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 129 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
127 130
128 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 131 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
129 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 132 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
130 133
131 let mut digest = Sha512::new(); 134 let mut message = [0; 64];
132 for offset in (0.._update_len).step_by(_aligned.len()) { 135 self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)
133 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; 136 .await?;
134 let len = core::cmp::min(_update_len - offset, _aligned.len());
135 digest.update(&_aligned[..len]);
136 }
137 137
138 public_key 138 public_key.verify(&message, &signature).map_err(into_signature_error)?
139 .verify(&digest.finalize(), &signature)
140 .map_err(into_signature_error)?
141 } 139 }
142 #[cfg(feature = "ed25519-salty")] 140 #[cfg(feature = "ed25519-salty")]
143 { 141 {
144 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; 142 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
145 use salty::{PublicKey, Sha512, Signature}; 143 use salty::{PublicKey, Signature};
144
145 use crate::digest_adapters::salty::Sha512;
146 146
147 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError { 147 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError {
148 FirmwareUpdaterError::Signature(signature::Error::default()) 148 FirmwareUpdaterError::Signature(signature::Error::default())
@@ -153,14 +153,10 @@ impl FirmwareUpdater {
153 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; 153 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
154 let signature = Signature::try_from(&signature).map_err(into_signature_error)?; 154 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
155 155
156 let mut digest = Sha512::new(); 156 let mut message = [0; 64];
157 for offset in (0.._update_len).step_by(_aligned.len()) { 157 self.hash::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)
158 self.dfu.read(_state_and_dfu_flash, offset as u32, _aligned).await?; 158 .await?;
159 let len = core::cmp::min(_update_len - offset, _aligned.len());
160 digest.update(&_aligned[..len]);
161 }
162 159
163 let message = digest.finalize();
164 let r = public_key.verify(&message, &signature); 160 let r = public_key.verify(&message, &signature);
165 trace!( 161 trace!(
166 "Verifying with public key {}, signature {} and message {} yields ok: {}", 162 "Verifying with public key {}, signature {} and message {} yields ok: {}",
@@ -175,6 +171,25 @@ impl FirmwareUpdater {
175 self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await 171 self.set_magic(_aligned, SWAP_MAGIC, _state_and_dfu_flash).await
176 } 172 }
177 173
174 /// Verify the update in DFU with any digest.
175 pub async fn hash<F: AsyncNorFlash, D: Digest>(
176 &mut self,
177 dfu_flash: &mut F,
178 update_len: usize,
179 chunk_buf: &mut [u8],
180 output: &mut [u8],
181 ) -> Result<(), FirmwareUpdaterError> {
182 let update_len = update_len as u32;
183 let mut digest = D::new();
184 for offset in (0..update_len).step_by(chunk_buf.len()) {
185 self.dfu.read(dfu_flash, offset, chunk_buf).await?;
186 let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len());
187 digest.update(&chunk_buf[..len]);
188 }
189 output.copy_from_slice(digest.finalize().as_slice());
190 Ok(())
191 }
192
178 /// Mark to trigger firmware swap on next boot. 193 /// Mark to trigger firmware swap on next boot.
179 /// 194 ///
180 /// # Safety 195 /// # Safety
@@ -328,28 +343,26 @@ impl FirmwareUpdater {
328 343
329 #[cfg(feature = "ed25519-dalek")] 344 #[cfg(feature = "ed25519-dalek")]
330 { 345 {
331 use ed25519_dalek::{Digest, PublicKey, Sha512, Signature, SignatureError, Verifier}; 346 use ed25519_dalek::{PublicKey, Signature, SignatureError, Verifier};
347
348 use crate::digest_adapters::ed25519_dalek::Sha512;
332 349
333 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into()); 350 let into_signature_error = |e: SignatureError| FirmwareUpdaterError::Signature(e.into());
334 351
335 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?; 352 let public_key = PublicKey::from_bytes(_public_key).map_err(into_signature_error)?;
336 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?; 353 let signature = Signature::from_bytes(_signature).map_err(into_signature_error)?;
337 354
338 let mut digest = Sha512::new(); 355 let mut message = [0; 64];
339 for offset in (0.._update_len).step_by(_aligned.len()) { 356 self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?;
340 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
341 let len = core::cmp::min(_update_len - offset, _aligned.len());
342 digest.update(&_aligned[..len]);
343 }
344 357
345 public_key 358 public_key.verify(&message, &signature).map_err(into_signature_error)?
346 .verify(&digest.finalize(), &signature)
347 .map_err(into_signature_error)?
348 } 359 }
349 #[cfg(feature = "ed25519-salty")] 360 #[cfg(feature = "ed25519-salty")]
350 { 361 {
351 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH}; 362 use salty::constants::{PUBLICKEY_SERIALIZED_LENGTH, SIGNATURE_SERIALIZED_LENGTH};
352 use salty::{PublicKey, Sha512, Signature}; 363 use salty::{PublicKey, Signature};
364
365 use crate::digest_adapters::salty::Sha512;
353 366
354 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError { 367 fn into_signature_error<E>(_: E) -> FirmwareUpdaterError {
355 FirmwareUpdaterError::Signature(signature::Error::default()) 368 FirmwareUpdaterError::Signature(signature::Error::default())
@@ -360,14 +373,9 @@ impl FirmwareUpdater {
360 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?; 373 let signature: [u8; SIGNATURE_SERIALIZED_LENGTH] = _signature.try_into().map_err(into_signature_error)?;
361 let signature = Signature::try_from(&signature).map_err(into_signature_error)?; 374 let signature = Signature::try_from(&signature).map_err(into_signature_error)?;
362 375
363 let mut digest = Sha512::new(); 376 let mut message = [0; 64];
364 for offset in (0.._update_len).step_by(_aligned.len()) { 377 self.hash_blocking::<_, Sha512>(_state_and_dfu_flash, _update_len, _aligned, &mut message)?;
365 self.dfu.read_blocking(_state_and_dfu_flash, offset as u32, _aligned)?;
366 let len = core::cmp::min(_update_len - offset, _aligned.len());
367 digest.update(&_aligned[..len]);
368 }
369 378
370 let message = digest.finalize();
371 let r = public_key.verify(&message, &signature); 379 let r = public_key.verify(&message, &signature);
372 trace!( 380 trace!(
373 "Verifying with public key {}, signature {} and message {} yields ok: {}", 381 "Verifying with public key {}, signature {} and message {} yields ok: {}",
@@ -382,6 +390,25 @@ impl FirmwareUpdater {
382 self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash) 390 self.set_magic_blocking(_aligned, SWAP_MAGIC, _state_and_dfu_flash)
383 } 391 }
384 392
393 /// Verify the update in DFU with any digest.
394 pub fn hash_blocking<F: NorFlash, D: Digest>(
395 &mut self,
396 dfu_flash: &mut F,
397 update_len: usize,
398 chunk_buf: &mut [u8],
399 output: &mut [u8],
400 ) -> Result<(), FirmwareUpdaterError> {
401 let update_len = update_len as u32;
402 let mut digest = D::new();
403 for offset in (0..update_len).step_by(chunk_buf.len()) {
404 self.dfu.read_blocking(dfu_flash, offset, chunk_buf)?;
405 let len = core::cmp::min((update_len - offset) as usize, chunk_buf.len());
406 digest.update(&chunk_buf[..len]);
407 }
408 output.copy_from_slice(digest.finalize().as_slice());
409 Ok(())
410 }
411
385 /// Mark to trigger firmware swap on next boot. 412 /// Mark to trigger firmware swap on next boot.
386 /// 413 ///
387 /// # Safety 414 /// # Safety
@@ -478,3 +505,32 @@ impl FirmwareUpdater {
478 Ok(self.dfu) 505 Ok(self.dfu)
479 } 506 }
480} 507}
508
509#[cfg(test)]
510mod tests {
511 use futures::executor::block_on;
512 use sha1::{Digest, Sha1};
513
514 use super::*;
515 use crate::mem_flash::MemFlash;
516
517 #[test]
518 fn can_verify_sha1() {
519 const STATE: Partition = Partition::new(0, 4096);
520 const DFU: Partition = Partition::new(65536, 131072);
521
522 let mut flash = MemFlash::<131072, 4096, 8>::default();
523
524 let update = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66];
525 let mut to_write = [0; 4096];
526 to_write[..7].copy_from_slice(update.as_slice());
527
528 let mut updater = FirmwareUpdater::new(DFU, STATE);
529 block_on(updater.write_firmware(0, to_write.as_slice(), &mut flash)).unwrap();
530 let mut chunk_buf = [0; 2];
531 let mut hash = [0; 20];
532 block_on(updater.hash::<_, Sha1>(&mut flash, update.len(), &mut chunk_buf, &mut hash)).unwrap();
533
534 assert_eq!(Sha1::digest(update).as_slice(), hash);
535 }
536}
diff --git a/embassy-boot/boot/src/lib.rs b/embassy-boot/boot/src/lib.rs
index 8b94b6bdc..ef9333d36 100644
--- a/embassy-boot/boot/src/lib.rs
+++ b/embassy-boot/boot/src/lib.rs
@@ -6,6 +6,7 @@
6mod fmt; 6mod fmt;
7 7
8mod boot_loader; 8mod boot_loader;
9mod digest_adapters;
9mod firmware_updater; 10mod firmware_updater;
10mod mem_flash; 11mod mem_flash;
11mod partition; 12mod partition;