diff --git a/legacy/firmware/fsm.c b/legacy/firmware/fsm.c index ff9f7fb54..6c022204d 100644 --- a/legacy/firmware/fsm.c +++ b/legacy/firmware/fsm.c @@ -30,6 +30,7 @@ #include "curves.h" #include "debug.h" #include "ecdsa.h" +#include "flash.h" #include "fsm.h" #include "fw_signatures.h" #include "gettext.h" diff --git a/legacy/firmware/fsm.h b/legacy/firmware/fsm.h index be024faa1..5c43862bd 100644 --- a/legacy/firmware/fsm.h +++ b/legacy/firmware/fsm.h @@ -70,6 +70,8 @@ void fsm_msgWordAck(const WordAck *msg); void fsm_msgSetU2FCounter(const SetU2FCounter *msg); void fsm_msgGetNextU2FCounter(void); void fsm_msgGetFirmwareHash(const GetFirmwareHash *msg); +void fsm_msgGetFirmware(const GetFirmware *msg); +void fsm_msgFirmwareChunkAck(const FirmwareChunkAck *msg); // coin void fsm_msgGetPublicKey(const GetPublicKey *msg); diff --git a/legacy/firmware/fsm_msg_common.h b/legacy/firmware/fsm_msg_common.h index 6442f3202..c4e2fcf27 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -562,3 +562,73 @@ void fsm_msgGetFirmwareHash(const GetFirmwareHash *msg) { msg_write(MessageType_MessageType_FirmwareHash, resp); layoutHome(); } + +static bool in_dump_firmware = false; +static uint8_t sector = 0; +static uint32_t sector_offset = 0; +static uint32_t total_bytes_sent = 0; +#define FIRMWARE_PROGRESS_TOTAL (128 * 1024 * 7 + 64 * 1024) + +void firmware_dump_abort(void) { + in_dump_firmware = false; + sector = 0; + sector_offset = 0; + total_bytes_sent = 0; +} + +void send_next_firmware_chunk(void) { + if (!in_dump_firmware) { + return; + } + if (sector_offset >= flash_sector_size(sector)) { + sector++; + sector_offset = 0; + } + if (sector > FLASH_CODE_SECTOR_LAST) { + fsm_sendSuccess(_("Firmware extracted")); + layoutHome(); + firmware_dump_abort(); + return; + } + RESP_INIT(FirmwareChunk); + if (memory_firmware_read(resp->chunk.bytes, sector, sector_offset, + sizeof(resp->chunk.bytes)) != 0) { + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); + firmware_dump_abort(); + return; + } + sector_offset += sizeof(resp->chunk.bytes); + resp->chunk.size = sizeof(resp->chunk.bytes); + total_bytes_sent += sizeof(resp->chunk.bytes); + layoutProgress(_("Extracting..."), + 1000 * total_bytes_sent / FIRMWARE_PROGRESS_TOTAL); + msg_write(MessageType_MessageType_FirmwareChunk, resp); +} + +void fsm_msgGetFirmware(const GetFirmware *msg) { + (void)msg; + layoutDialogSwipe(&bmp_icon_question, _("Cancel"), _("Confirm"), NULL, + _("Do you want to"), _("extract firmware?"), NULL, + _("Your seed will"), _("not be revealed."), NULL); + if (!protectButton(ButtonRequestType_ButtonRequest_ProtectCall, false)) { + fsm_sendFailure(FailureType_Failure_ActionCancelled, NULL); + layoutHome(); + return; + } + + layoutProgressSwipe(_("Extracting..."), 0); + sector = FLASH_CODE_SECTOR_FIRST; + sector_offset = 0; + total_bytes_sent = 0; + in_dump_firmware = true; + send_next_firmware_chunk(); +} + +void fsm_msgFirmwareChunkAck(const FirmwareChunkAck *msg) { + (void)msg; + if (!in_dump_firmware) { + fsm_sendFailure(FailureType_Failure_UnexpectedMessage, NULL); + } else { + send_next_firmware_chunk(); + } +} diff --git a/legacy/firmware/protob/messages-management.options b/legacy/firmware/protob/messages-management.options index 79c398de9..bc3fb56d9 100644 --- a/legacy/firmware/protob/messages-management.options +++ b/legacy/firmware/protob/messages-management.options @@ -38,3 +38,5 @@ Nonce.nonce max_size:32 GetFirmwareHash.challenge max_size:32 FirmwareHash.hash max_size:32 + +FirmwareChunk.chunk max_size:2048 diff --git a/legacy/memory.c b/legacy/memory.c index 39cebb3f9..5121806fe 100644 --- a/legacy/memory.c +++ b/legacy/memory.c @@ -20,6 +20,7 @@ #include "memory.h" #include #include +#include #include "blake2s.h" #include "flash.h" #include "layout.h" @@ -114,3 +115,16 @@ int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size, return blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); } + +int memory_firmware_read(uint8_t *dest, uint8_t sector, uint32_t offset, + uint32_t size) { + if (sector < FLASH_CODE_SECTOR_FIRST || sector > FLASH_CODE_SECTOR_LAST) { + return 1; + } + const void *data = flash_get_address(sector, offset, size); + if (data == NULL) { + return 1; + } + memcpy(dest, data, size); + return 0; +} diff --git a/legacy/memory.h b/legacy/memory.h index e79267e32..2654a618d 100644 --- a/legacy/memory.h +++ b/legacy/memory.h @@ -96,6 +96,8 @@ int memory_bootloader_hash(uint8_t *hash); int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size, void (*progress_callback)(uint32_t, uint32_t), uint8_t hash[32]); +int memory_firmware_read(uint8_t *dest, uint8_t sector_idx, uint32_t offset, + uint32_t len); static inline void flash_write32(uint32_t addr, uint32_t word) { *(volatile uint32_t *)FLASH_PTR(addr) = word;