aboutsummaryrefslogtreecommitdiff
path: root/embassy-usb-dfu
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-usb-dfu')
-rw-r--r--embassy-usb-dfu/Cargo.toml5
-rw-r--r--embassy-usb-dfu/README.md6
-rw-r--r--embassy-usb-dfu/src/dfu.rs33
3 files changed, 41 insertions, 3 deletions
diff --git a/embassy-usb-dfu/Cargo.toml b/embassy-usb-dfu/Cargo.toml
index ca108c1a2..8b2467bca 100644
--- a/embassy-usb-dfu/Cargo.toml
+++ b/embassy-usb-dfu/Cargo.toml
@@ -43,3 +43,8 @@ esp32c3-hal = { version = "0.13.0", optional = true, default-features = false }
43dfu = [] 43dfu = []
44application = [] 44application = []
45defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"] 45defmt = ["dep:defmt", "embassy-boot/defmt", "embassy-usb/defmt"]
46ed25519-dalek = ["embassy-boot/ed25519-dalek", "_verify"]
47ed25519-salty = ["embassy-boot/ed25519-salty", "_verify"]
48
49# Internal features
50_verify = []
diff --git a/embassy-usb-dfu/README.md b/embassy-usb-dfu/README.md
index bdd5b033a..a81b98279 100644
--- a/embassy-usb-dfu/README.md
+++ b/embassy-usb-dfu/README.md
@@ -4,3 +4,9 @@ An implementation of the USB DFU 1.1 protocol using embassy-boot. It has 2 compo
4 4
5* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention. 5* DFU protocol mode, enabled by the `dfu` feature. This mode corresponds to the transfer phase DFU protocol described by the USB IF. It supports DFU_DNLOAD requests if marked by the user, and will automatically reset the chip once a DFU transaction has been completed. It also responds to DFU_GETSTATUS, DFU_GETSTATE, DFU_ABORT, and DFU_CLRSTATUS with no user intervention.
6* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system. 6* DFU runtime mode, enabled by the `application feature`. This mode allows users to expose a DFU interface on their USB device, informing the host of the capability to DFU over USB, and allowing the host to reset the device into its bootloader to complete a DFU operation. Supports DFU_GETSTATUS and DFU_DETACH. When detach/reset is seen by the device as described by the standard, will write a new DFU magic number into the bootloader state in flash, and reset the system.
7
8## Verification
9
10Embassy-boot provides functionality to verify that an update binary has been correctly signed using ed25519 as described in https://embassy.dev/book/#_verification. Even though the linked procedure describes the signature being concatenated to the end of the update binary, embassy-boot does not force this and is flexible in terms of how the signature for a binary is distributed. The current implementation in embassy-usb-dfu does however assume that the signature is 64 bytes long and concatenated to the end of the update binary since this is the simplest way to make it work with the usb-dfu mechanism. I.e. embassy-usb-dfu does not currently offer the same flexibility as embassy-boot.
11
12To enable verification, you need to enable either the `ed25519-dalek` or the `ed25519-salty` feature with `ed25519-salty` being recommended.
diff --git a/embassy-usb-dfu/src/dfu.rs b/embassy-usb-dfu/src/dfu.rs
index 0f39d906b..9a2f125fb 100644
--- a/embassy-usb-dfu/src/dfu.rs
+++ b/embassy-usb-dfu/src/dfu.rs
@@ -19,11 +19,19 @@ pub struct Control<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_S
19 offset: usize, 19 offset: usize,
20 buf: AlignedBuffer<BLOCK_SIZE>, 20 buf: AlignedBuffer<BLOCK_SIZE>,
21 reset: RST, 21 reset: RST,
22
23 #[cfg(feature = "_verify")]
24 public_key: &'static [u8; 32],
22} 25}
23 26
24impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> { 27impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Control<'d, DFU, STATE, RST, BLOCK_SIZE> {
25 /// Create a new DFU instance to handle DFU transfers. 28 /// Create a new DFU instance to handle DFU transfers.
26 pub fn new(updater: BlockingFirmwareUpdater<'d, DFU, STATE>, attrs: DfuAttributes, reset: RST) -> Self { 29 pub fn new(
30 updater: BlockingFirmwareUpdater<'d, DFU, STATE>,
31 attrs: DfuAttributes,
32 reset: RST,
33 #[cfg(feature = "_verify")] public_key: &'static [u8; 32],
34 ) -> Self {
27 Self { 35 Self {
28 updater, 36 updater,
29 attrs, 37 attrs,
@@ -32,6 +40,9 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Co
32 offset: 0, 40 offset: 0,
33 buf: AlignedBuffer([0; BLOCK_SIZE]), 41 buf: AlignedBuffer([0; BLOCK_SIZE]),
34 reset, 42 reset,
43
44 #[cfg(feature = "_verify")]
45 public_key,
35 } 46 }
36 } 47 }
37 48
@@ -102,7 +113,23 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
102 if final_transfer { 113 if final_transfer {
103 debug!("Receiving final transfer"); 114 debug!("Receiving final transfer");
104 115
105 match self.updater.mark_updated() { 116 #[cfg(feature = "_verify")]
117 let update_res: Result<(), FirmwareUpdaterError> = {
118 const SIGNATURE_LEN: usize = 64;
119
120 let mut signature = [0; SIGNATURE_LEN];
121 let update_len = (self.offset - SIGNATURE_LEN) as u32;
122
123 self.updater.read_dfu(update_len, &mut signature).and_then(|_| {
124 self.updater
125 .verify_and_mark_updated(self.public_key, &signature, update_len)
126 })
127 };
128
129 #[cfg(not(feature = "_verify"))]
130 let update_res = self.updater.mark_updated();
131
132 match update_res {
106 Ok(_) => { 133 Ok(_) => {
107 self.status = Status::Ok; 134 self.status = Status::Ok;
108 self.state = State::ManifestSync; 135 self.state = State::ManifestSync;
@@ -168,7 +195,7 @@ impl<'d, DFU: NorFlash, STATE: NorFlash, RST: Reset, const BLOCK_SIZE: usize> Ha
168 Some(InResponse::Accepted(&buf[0..1])) 195 Some(InResponse::Accepted(&buf[0..1]))
169 } 196 }
170 Ok(Request::Upload) if self.attrs.contains(DfuAttributes::CAN_UPLOAD) => { 197 Ok(Request::Upload) if self.attrs.contains(DfuAttributes::CAN_UPLOAD) => {
171 //TODO: FirmwareUpdater does not provide a way of reading the active partition, can't upload. 198 //TODO: FirmwareUpdater provides a way of reading the active partition so we could in theory add functionality to upload firmware.
172 Some(InResponse::Rejected) 199 Some(InResponse::Rejected)
173 } 200 }
174 _ => None, 201 _ => None,