diff --git a/legacy/firmware/.changelog.d/2239.added b/legacy/firmware/.changelog.d/2239.added new file mode 100644 index 000000000..42f72dcd5 --- /dev/null +++ b/legacy/firmware/.changelog.d/2239.added @@ -0,0 +1 @@ +Add firmware hashing functionality. diff --git a/legacy/firmware/Makefile b/legacy/firmware/Makefile index c48a2e65a..d51f82921 100644 --- a/legacy/firmware/Makefile +++ b/legacy/firmware/Makefile @@ -107,6 +107,7 @@ OBJS += ../vendor/trezor-crypto/sha2.o OBJS += ../vendor/trezor-crypto/sha3.o OBJS += ../vendor/trezor-crypto/blake256.o OBJS += ../vendor/trezor-crypto/blake2b.o +OBJS += ../vendor/trezor-crypto/blake2s.o OBJS += ../vendor/trezor-crypto/groestl.o OBJS += ../vendor/trezor-crypto/hasher.o diff --git a/legacy/firmware/fsm.h b/legacy/firmware/fsm.h index 3dfd195a9..be024faa1 100644 --- a/legacy/firmware/fsm.h +++ b/legacy/firmware/fsm.h @@ -69,6 +69,7 @@ void fsm_msgRecoveryDevice(const RecoveryDevice *msg); void fsm_msgWordAck(const WordAck *msg); void fsm_msgSetU2FCounter(const SetU2FCounter *msg); void fsm_msgGetNextU2FCounter(void); +void fsm_msgGetFirmwareHash(const GetFirmwareHash *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 e9195a964..cc9e2625c 100644 --- a/legacy/firmware/fsm_msg_common.h +++ b/legacy/firmware/fsm_msg_common.h @@ -536,3 +536,15 @@ void fsm_msgGetNextU2FCounter() { msg_write(MessageType_MessageType_NextU2FCounter, resp); layoutHome(); } + +void fsm_msgGetFirmwareHash(const GetFirmwareHash *msg) { + RESP_INIT(FirmwareHash); + if (memory_firmware_hash(msg->challenge.bytes, msg->challenge.size, + resp->hash.bytes) != 0) { + fsm_sendFailure(FailureType_Failure_FirmwareError, NULL); + return; + } + + resp->hash.size = sizeof(resp->hash.bytes); + msg_write(MessageType_MessageType_FirmwareHash, resp); +} diff --git a/legacy/firmware/protob/messages-management.options b/legacy/firmware/protob/messages-management.options index 2ae1aa081..79c398de9 100644 --- a/legacy/firmware/protob/messages-management.options +++ b/legacy/firmware/protob/messages-management.options @@ -35,3 +35,6 @@ RecoveryDevice.label max_size:33 WordAck.word max_size:12 Nonce.nonce max_size:32 + +GetFirmwareHash.challenge max_size:32 +FirmwareHash.hash max_size:32 diff --git a/legacy/flash.c b/legacy/flash.c index 9747cbc47..839a2a2a4 100644 --- a/legacy/flash.c +++ b/legacy/flash.c @@ -69,6 +69,13 @@ const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size) { return (const void *)FLASH_PTR(addr); } +uint32_t flash_sector_size(uint8_t sector) { + if (sector >= FLASH_SECTOR_COUNT) { + return 0; + } + return FLASH_SECTOR_TABLE[sector + 1] - FLASH_SECTOR_TABLE[sector]; +} + secbool flash_erase(uint8_t sector) { ensure(flash_unlock_write(), NULL); svc_flash_erase_sector(sector); diff --git a/legacy/flash.h b/legacy/flash.h index 4a53dc4f5..1b8657d07 100644 --- a/legacy/flash.h +++ b/legacy/flash.h @@ -42,7 +42,7 @@ secbool __wur flash_unlock_write(void); secbool __wur flash_lock_write(void); const void *flash_get_address(uint8_t sector, uint32_t offset, uint32_t size); - +uint32_t flash_sector_size(uint8_t sector); secbool __wur flash_erase(uint8_t sector); secbool __wur flash_write_byte(uint8_t sector, uint32_t offset, uint8_t data); secbool __wur flash_write_word(uint8_t sector, uint32_t offset, uint32_t data); diff --git a/legacy/memory.c b/legacy/memory.c index 32853140e..3f8abbc9c 100644 --- a/legacy/memory.c +++ b/legacy/memory.c @@ -20,6 +20,8 @@ #include "memory.h" #include #include +#include "blake2s.h" +#include "flash.h" #include "sha2.h" #define FLASH_OPTION_BYTES_1 (*(const uint64_t *)0x1FFFC000) @@ -82,3 +84,27 @@ int memory_bootloader_hash(uint8_t *hash) { sha256_Raw(hash, 32, hash); return 32; } + +int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size, + uint8_t hash[BLAKE2S_DIGEST_LENGTH]) { + BLAKE2S_CTX ctx; + if (challenge_size != 0) { + if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, challenge, + challenge_size) != 0) { + return 1; + } + } else { + blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); + } + + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + uint32_t size = flash_sector_size(i); + const void *data = flash_get_address(i, 0, size); + if (data == NULL) { + return 1; + } + blake2s_Update(&ctx, data, size); + } + + return blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); +} diff --git a/legacy/memory.h b/legacy/memory.h index 72fcb23ee..56584a905 100644 --- a/legacy/memory.h +++ b/legacy/memory.h @@ -93,6 +93,8 @@ extern uint8_t *emulator_flash_base; void memory_protect(void); void memory_write_unlock(void); int memory_bootloader_hash(uint8_t *hash); +int memory_firmware_hash(const uint8_t *challenge, uint32_t challenge_size, + uint8_t hash[32]); static inline void flash_write32(uint32_t addr, uint32_t word) { *(volatile uint32_t *)FLASH_PTR(addr) = word;