[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.
This commit is contained in:
Gerhard de Clercq
2025-04-15 20:16:09 +02:00
parent f7405493c1
commit 68a45490fc
13 changed files with 114 additions and 11 deletions

View File

@@ -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
}

View File

@@ -0,0 +1,2 @@
untrusted comment: signify secret key
RWRCSwAAAAATdHQF3B4jEIoNZrjADRp2LbjJjNdNNzKwTCe4IB6mDNq96pe53nbNxwbdCc/T4hrz7W+Kx1MwrZ0Yz5xebSK5Z0Kh/3Cdf039U5f+eoTDS2fIGbohyUbrtwKzjyE0qXI=

View File

@@ -30,6 +30,7 @@ defmt = [
"embassy-usb/defmt",
"embassy-usb-dfu/defmt"
]
verify = ["embassy-usb-dfu/ed25519-salty"]
[profile.dev]
debug = 2

View File

@@ -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

View File

@@ -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
}

View File

@@ -0,0 +1 @@
gB<EFBFBD><EFBFBD>p<EFBFBD>M<EFBFBD>S<EFBFBD><EFBFBD>z<EFBFBD><EFBFBD>Kg<EFBFBD><19>!<21>F<EFBFBD><46><02><>!4<>r

View File

@@ -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,