Skip to content

boot: zephyr: support encrypted images over USB DFU on a single slot - #2750

Open
benner wants to merge 1 commit into
mcu-tools:mainfrom
benner:feat/usb-dfu-encrypted-single-slot
Open

boot: zephyr: support encrypted images over USB DFU on a single slot#2750
benner wants to merge 1 commit into
mcu-tools:mainfrom
benner:feat/usb-dfu-encrypted-single-slot

Conversation

@benner

@benner benner commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

With a single application slot MCUboot jumps directly to the primary
slot, so an encrypted image from USB DFU (which, unlike serial recovery,
has no decrypt-on-upload) is never decrypted and faults.

Decrypt during validation: if the primary slot fails validation while
still flagged encrypted, decrypt in place via boot_handle_enc_fw() and
revalidate; an already-decrypted slot passes and is not decrypted again.
This happens on the same boot, right after wait_for_usb_dfu() returns,
so no reboot is needed. Relax the BOOT_ENCRYPT_IMAGE single-slot
dependency for USB DFU, which requires slot validation since that gates
the decrypt, and build boot_serial_encryption.c.

@benner
benner marked this pull request as ready for review June 2, 2026 17:02
@benner
benner requested review from de-nordic and nordicjm as code owners June 2, 2026 17:02
@benner

benner commented Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Tested on nucleo_l432kc board:

% dfu-util -a 0 -D build/serial-recovery/zephyr/zephyr.signed.encrypted.bin
dfu-util 0.11

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2021 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

dfu-util: Warning: Invalid DFU suffix signature
dfu-util: A valid DFU suffix will be required in a future dfu-util release
Opening DFU capable USB device...
Device ID 1209:0101
Run-Time device DFU version 0110
Claiming USB DFU (Run-Time) Interface...
Setting Alternate Interface zero...
Determining device status...
DFU state(0) = appIDLE, status(0) = No error condition is present
Device really in Run-Time Mode, send DFU detach request...
Device will detach and reattach...
Opening DFU USB Device...
Claiming USB DFU Interface...
Setting Alternate Interface #0 ...
Determining device status...
DFU state(2) = dfuIDLE, status(0) = No error condition is present
DFU mode device DFU version 0110
Device returned transfer size 128
Copying data from PC to DFU device
Download	[=========================] 100%        38379 bytes
Download done.
DFU state(2) = dfuIDLE, status(0) = No error condition is present
Done!
[20:03:04.266] Connected to /dev/ttyACM0
*** Using Zephyr OS build v4.4.0-2787-gca3476979aaa ***
[0:0:0.4,0] <inf> mcuboot: Starting bootloader
[0:0:0.9,0] <inf> mcuboot: Wait[0:0:0.12,0] <inf> usb_cdc_acm: Device suspended
ing for USB DFU
[0:0:0.121,0] <inf> usb_cdc_acm: Device resumed
[0:0:0.125,0] <inf> usb_cdc_acm: from suspend
[0:0:0.363,0] <inf> usb_cdc_acm: Device configured
[0:0:10.433,0] <inf> usb_cdc_acm: Device suspended
[0:0:10.564,0] <inf> usb_cdc_acm: Device resumed
[0:0:10.569,0] <inf> usb_cdc_acm: from suspend
[0:0:10.802,0] <inf> usb_cdc_acm: Device configured
[0:0:18.134,0] <inf> usb_dfu: USB DFU Completed
[0:0:18.139,0] <inf> mcuboot: USB DFU wait time elapsed
[0:0:18.190,0] <inf> mcuboot: Primary slot is encrypted; decrypting in place
[0:0:19.483,0] <inf> mcuboot: Bootloader chainload address offset: 0xf000
[0:0:19.490,0] <inf> mcuboot: Image version: v0.0.0
[0:0:19.495,0] <inf> mcuboot: Jumping to the first image slot

@nordicjm nordicjm left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't look like the right place? It should decrypt after the image has been received, not after the board is rebooted

@de-nordic de-nordic added the area: zephyr Affects the Zephyr port label Jun 10, 2026
@benner
benner force-pushed the feat/usb-dfu-encrypted-single-slot branch from 4a14868 to 8ac7cd3 Compare June 14, 2026 14:36
@benner
benner requested a review from davidvincze as a code owner June 14, 2026 14:36
With a single application slot MCUboot jumps directly to the primary
slot, so an encrypted image from USB DFU (which, unlike serial recovery,
has no decrypt-on-upload) is never decrypted and faults.

Decrypt during validation: if the primary slot fails validation while
still flagged encrypted, decrypt in place via boot_handle_enc_fw() and
revalidate; an already-decrypted slot passes and is not decrypted again.
This happens on the same boot, right after wait_for_usb_dfu() returns,
so no reboot is needed. Relax the BOOT_ENCRYPT_IMAGE single-slot
dependency for USB DFU, which requires slot validation since that gates
the decrypt, and build boot_serial_encryption.c.

Signed-off-by: Nerijus Bendžiūnas <nerijus.bendziunas@gmail.com>
@benner
benner force-pushed the feat/usb-dfu-encrypted-single-slot branch from 8ac7cd3 to 4a933a5 Compare June 14, 2026 15:38
@benner

benner commented Jun 14, 2026

Copy link
Copy Markdown
Contributor Author

I tried the post-wait_for_usb_dfu() placement but kept the decrypt in boot_go().

On the "decrypt after reboot" point — that was a leftover reference in the commit/PR message from earlier work, not part of this PR. boot_go() decrypts on the same boot, right after wait_for_usb_dfu() returns, so no reboot is involved. I've updated the commit message.

Moving the decrypt out of boot_go() doesn't change when it runs, but it adds a second full validation per boot: after the wait there's no reliable way to tell a finished download from a timeout, so a helper must validate the slot every boot to decide whether to decrypt.

(A clean "image received" signal would need exposing it from Zephyr; the legacy USB stack has none and is deprecated, the new stack does, so mcuboot would need porting there first.)

@nordicjm

Copy link
Copy Markdown
Collaborator

(A clean "image received" signal would need exposing it from Zephyr; the legacy USB stack has none and is deprecated, the new stack does, so mcuboot would need porting there first.)

That is a good point, does the new stack have such a callback? Because nothing should be using the legacy stack anymore, someone needs to port MCUboot to use the new stack

@benner

benner commented Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

does the new stack have such a callback?

Yes — the new USB device stack's DFU class publishes USBD_MSG_DFU_DOWNLOAD_COMPLETED via the usbd message system when the download finishes (subsys/usb/device_next/class/usbd_dfu.c), which is exactly the "image received" signal the legacy stack lacks.

someone needs to port MCUboot to use the new stack

Agreed. Once I'm unblocked on the rest of this DFU work, I'm happy to look into the migration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: zephyr Affects the Zephyr port

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants