From 68a45490fc1675f2171131ccbf01f690c4123f01 Mon Sep 17 00:00:00 2001 From: Gerhard de Clercq <11624490+Gerharddc@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:16:09 +0200 Subject: [embassy-usb-dfu] support ed25519 verification This commit adds the ability to verify that USB DFU updates are correctly signed using ed25519. This required adding support to embassy-boot for reading from the DFU partition. --- examples/boot/application/stm32wb-dfu/memory.x | 8 +++---- .../boot/application/stm32wb-dfu/secrets/key.sec | 2 ++ examples/boot/bootloader/stm32wb-dfu/Cargo.toml | 1 + examples/boot/bootloader/stm32wb-dfu/README.md | 26 ++++++++++++++++++++++ examples/boot/bootloader/stm32wb-dfu/memory.x | 8 +++---- .../bootloader/stm32wb-dfu/secrets/key.pub.short | 1 + examples/boot/bootloader/stm32wb-dfu/src/main.rs | 12 ++++++++++ 7 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 examples/boot/application/stm32wb-dfu/secrets/key.sec create mode 100644 examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short (limited to 'examples') diff --git a/examples/boot/application/stm32wb-dfu/memory.x b/examples/boot/application/stm32wb-dfu/memory.x index ff1b800d2..f1e6b053c 100644 --- a/examples/boot/application/stm32wb-dfu/memory.x +++ b/examples/boot/application/stm32wb-dfu/memory.x @@ -1,10 +1,10 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 24K - BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - FLASH : ORIGIN = 0x08008000, LENGTH = 128K - DFU : ORIGIN = 0x08028000, LENGTH = 132K + BOOTLOADER : ORIGIN = 0x08000000, LENGTH = 48K + BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K + FLASH : ORIGIN = 0x0800D000, LENGTH = 120K + DFU : ORIGIN = 0x0802B000, LENGTH = 120K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 32K } diff --git a/examples/boot/application/stm32wb-dfu/secrets/key.sec b/examples/boot/application/stm32wb-dfu/secrets/key.sec new file mode 100644 index 000000000..52e7f125b --- /dev/null +++ b/examples/boot/application/stm32wb-dfu/secrets/key.sec @@ -0,0 +1,2 @@ +untrusted comment: signify secret key +RWRCSwAAAAATdHQF3B4jEIoNZrjADRp2LbjJjNdNNzKwTCe4IB6mDNq96pe53nbNxwbdCc/T4hrz7W+Kx1MwrZ0Yz5xebSK5Z0Kh/3Cdf039U5f+eoTDS2fIGbohyUbrtwKzjyE0qXI= diff --git a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml index 738afb6ec..0bb93b12e 100644 --- a/examples/boot/bootloader/stm32wb-dfu/Cargo.toml +++ b/examples/boot/bootloader/stm32wb-dfu/Cargo.toml @@ -30,6 +30,7 @@ defmt = [ "embassy-usb/defmt", "embassy-usb-dfu/defmt" ] +verify = ["embassy-usb-dfu/ed25519-salty"] [profile.dev] debug = 2 diff --git a/examples/boot/bootloader/stm32wb-dfu/README.md b/examples/boot/bootloader/stm32wb-dfu/README.md index 3c5f268a0..99a7002c4 100644 --- a/examples/boot/bootloader/stm32wb-dfu/README.md +++ b/examples/boot/bootloader/stm32wb-dfu/README.md @@ -28,6 +28,32 @@ cargo objcopy --release -- -O binary fw.bin dfu-util -d c0de:cafe -w -D fw.bin ``` +### 3. Sign Updates Before Flashing (Optional) + +Currently, embassy-usb-dfu only supports a limited implementation of the generic support for ed25519-based update verfication in embassy-boot. This implementation assumes that a signature is simply concatenated to the end of an update binary. For more details, please see https://embassy.dev/book/#_verification and/or refer to the documentation for embassy-boot-dfu. + +To sign (and then verify) application updates, you will first need to generate a key pair: + +``` +signify-openbsd -G -n -p secrets/key.pub -s secrets/key.sec +tail -n1 secrets/key.pub | base64 -d -i - | dd ibs=10 skip=1 > secrets/key.pub.short +``` + +Then you will need to sign all you binaries with the private key: + +``` +cargo objcopy --release -- -O binary fw.bin +shasum -a 512 -b fw.bin | head -c128 | xxd -p -r > target/fw-hash.txt +signify-openbsd -S -s secrets/key.sec -m target/fw-hash.txt -x target/fw-hash.sig +cp fw.bin fw-signed.bin +tail -n1 target/fw-hash.sig | base64 -d -i - | dd ibs=10 skip=1 >> fw-signed.bin +dfu-util -d c0de:cafe -w -D fw-signed.bin +``` + +Finally, as shown in this example with the `verify` feature flag enabled, you then need to embed the public key into your bootloader so that it can verify update signatures. + +N.B. Please note that the exact steps above are NOT a good example of how to manage your keys securely. In a production environment, you should take great care to ensure that (at least the private key) is protected and not leaked into your version control system. + ## Troubleshooting - Make sure your device is in DFU mode before flashing diff --git a/examples/boot/bootloader/stm32wb-dfu/memory.x b/examples/boot/bootloader/stm32wb-dfu/memory.x index 858062631..77c4d2ee2 100644 --- a/examples/boot/bootloader/stm32wb-dfu/memory.x +++ b/examples/boot/bootloader/stm32wb-dfu/memory.x @@ -1,10 +1,10 @@ MEMORY { /* NOTE 1 K = 1 KiBi = 1024 bytes */ - FLASH : ORIGIN = 0x08000000, LENGTH = 24K - BOOTLOADER_STATE : ORIGIN = 0x08006000, LENGTH = 4K - ACTIVE : ORIGIN = 0x08008000, LENGTH = 128K - DFU : ORIGIN = 0x08028000, LENGTH = 132K + FLASH : ORIGIN = 0x08000000, LENGTH = 48K + BOOTLOADER_STATE : ORIGIN = 0x0800C000, LENGTH = 4K + ACTIVE : ORIGIN = 0x0800D000, LENGTH = 120K + DFU : ORIGIN = 0x0802B000, LENGTH = 120K RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K } diff --git a/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short new file mode 100644 index 000000000..7a4de8585 --- /dev/null +++ b/examples/boot/bootloader/stm32wb-dfu/secrets/key.pub.short @@ -0,0 +1 @@ +gBpMSzKg!F!4r \ No newline at end of file diff --git a/examples/boot/bootloader/stm32wb-dfu/src/main.rs b/examples/boot/bootloader/stm32wb-dfu/src/main.rs index 0b643079f..107f243fd 100644 --- a/examples/boot/bootloader/stm32wb-dfu/src/main.rs +++ b/examples/boot/bootloader/stm32wb-dfu/src/main.rs @@ -25,6 +25,12 @@ bind_interrupts!(struct Irqs { // N.B. update to a custom GUID for your own device! const DEVICE_INTERFACE_GUIDS: &[&str] = &["{EAA9A5DC-30BA-44BC-9232-606CDC875321}"]; +// This is a randomly generated example key. +// +// N.B. Please replace with your own! +#[cfg(feature = "verify")] +static PUBLIC_SIGNING_KEY: &[u8; 32] = include_bytes!("../secrets/key.pub.short"); + #[entry] fn main() -> ! { let mut config = embassy_stm32::Config::default(); @@ -57,7 +63,13 @@ fn main() -> ! { let mut config_descriptor = [0; 256]; let mut bos_descriptor = [0; 256]; let mut control_buf = [0; 4096]; + + #[cfg(not(feature = "verify"))] let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate); + + #[cfg(feature = "verify")] + let mut state = Control::new(updater, DfuAttributes::CAN_DOWNLOAD, ResetImmediate, PUBLIC_SIGNING_KEY); + let mut builder = Builder::new( driver, config, -- cgit