What changed, and why it matters
This commit changes how Passport's bootloader checks firmware updates. Previously, if the currently-running firmware failed validation, the bootloader would skip verifying the new update's signature and could install it anyway. Now the new firmware's signature is always verified before installation, even when the current firmware is invalid. This closes a path where a corrupted or attacker-controlled running firmware might be able to load an unsigned or wrongly-signed update.
Treat this as a security hardening fix and include it in firmware releases. Users should update to a bootloader/firmware version containing this commit. Developers should review whether any other bootloader paths can reach do_update() without signature verification, and confirm that verify_signature() covers both production and user-signed firmware keys correctly.
Security signals we found
Bypassed/missing cryptographic verification path hardened
Firmware update signature check moved to unconditional execution
Current firmware invalid state no longer skips new firmware signature verification
Bootloader update flow change
Evidence from the diff
In ports/stm32/boards/Passport/bootloader/update.c, the original flow only called verify_signature() and calculate_spi_hash() inside the branch where verify_current_firmware(true) returned SEC_TRUE. If current firmware was invalid, execution fell through to do_update() without validating the SPI header’s signature. The patch moves signature verification (calculate_spi_hash + verify_signature) outside that branch so it always runs, while keeping board-hash/timestamp/anti-rollback checks conditional on current firmware validity. It also hoists is_spi_fw_user_signed to the top of the function. The change is a hardening fix: it ensures an incoming update must be cryptographically signed before do_update() is reached, regardless of the state of the running firmware.
Changed components
Passport bootloader firmware update module (ports/stm32/boards/Passport/bootloader/update.c)Inspect captured patch +30 / −26
diff --git a/ports/stm32/boards/Passport/bootloader/update.c b/ports/stm32/boards/Passport/bootloader/update.c
index 26aa1d0..5e0913f 100644
--- a/ports/stm32/boards/Passport/bootloader/update.c
+++ b/ports/stm32/boards/Passport/bootloader/update.c
@@ -338,6 +338,9 @@ void update_firmware(void) {
}
}
+ bool is_spi_fw_user_signed = spihdr.signature.pubkey1 == FW_USER_KEY;
+ bool is_current_firmware_valid = false;
+
// Handle the firmware hash update
get_current_board_hash(current_board_hash);
@@ -353,13 +356,12 @@ void update_firmware(void) {
#ifdef DEBUG_PRINT_UPDATE_HASH
printf("Verifying current firmware before update\r\n");
#endif
- if (verify_current_firmware(true) == SEC_TRUE) {
+ is_current_firmware_valid = verify_current_firmware(true) == SEC_TRUE;
+ if (is_current_firmware_valid) {
#ifdef DEBUG_PRINT_UPDATE_HASH
printf(" Current firmware is valid, so doing more checks.\r\n");
#endif
- bool is_spi_fw_user_signed = spihdr.signature.pubkey1 == FW_USER_KEY;
-
#ifdef PRODUCTION_BUILD
uint32_t current_firmware_timestamp = se_get_firmware_timestamp(current_board_hash);
if (current_firmware_timestamp == 0) {
@@ -393,29 +395,36 @@ void update_firmware(void) {
}
}
#endif
+ }
+#ifdef DEBUG_PRINT_UPDATE_HASH
+ else {
+ printf(" Current firmware is INVALID - fall through to try the update.\r\n");
+ }
+#endif
- calculate_spi_hash(&spihdr, spi_fw_hash, sizeof(spi_fw_hash));
+ calculate_spi_hash(&spihdr, spi_fw_hash, sizeof(spi_fw_hash));
#ifdef DEBUG_PRINT_UPDATE_HASH
- printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
- bytes_to_hex_str((void*)&spihdr, sizeof(spihdr), str_buf, 64, "\r\n");
- printf("spihdr\r\n%s\r\n", str_buf);
- bytes_to_hex_str((void*)spi_fw_hash, sizeof(spi_fw_hash), str_buf, 64, "\r\n");
- printf("spi_fw_hash\r\n%s\r\n", str_buf);
- printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
+ printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
+ bytes_to_hex_str((void*)&spihdr, sizeof(spihdr), str_buf, 64, "\r\n");
+ printf("spihdr\r\n%s\r\n", str_buf);
+ bytes_to_hex_str((void*)spi_fw_hash, sizeof(spi_fw_hash), str_buf, 64, "\r\n");
+ printf("spi_fw_hash\r\n%s\r\n", str_buf);
+ printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");
#endif
- // Verify the signature and bail if it fails
- if (verify_signature(&spihdr, spi_fw_hash, sizeof(spi_fw_hash)) == SEC_FALSE) {
- error4:
- if (ui_show_error("PASSPORT", "Update Error",
- "The firmware update is not properly signed and will not be installed.", &ICON_SHUTDOWN,
- &ICON_CHECKMARK, true) == KEY_RIGHT_SELECT) {
- goto out;
- } else {
- ui_ask_shutdown();
- goto error4;
- }
+ // Verify the incoming firmware signature before attempting to install it.
+ if (verify_signature(&spihdr, spi_fw_hash, sizeof(spi_fw_hash)) == SEC_FALSE) {
+ error4:
+ if (ui_show_error("PASSPORT", "Update Error",
+ "The firmware update is not properly signed and will not be installed.", &ICON_SHUTDOWN,
+ &ICON_CHECKMARK, true) == KEY_RIGHT_SELECT) {
+ goto out;
+ } else {
+ ui_ask_shutdown();
+ goto error4;
}
+ }
+ if (is_current_firmware_valid) {
/*
* Calculate a new board hash based on the SPI firmware and then
* reprogram the board hash in the SE. If the update fails it
@@ -456,11 +465,6 @@ void update_firmware(void) {
}
}
}
-#ifdef DEBUG_PRINT_UPDATE_HASH
- else {
- printf(" Current firmware is INVALID - fall through to try the update.\r\n");
- }
-#endif
rc = do_update(FW_HEADER_SIZE + spihdr.info.fwlength);
if (rc < 0) {
Why this scored 59/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.