diff --git a/core/embed/sys/syscall/stm32/syscall_dispatch.c b/core/embed/sys/syscall/stm32/syscall_dispatch.c index 7f38d0b7e9..129364f6aa 100644 --- a/core/embed/sys/syscall/stm32/syscall_dispatch.c +++ b/core/embed/sys/syscall/stm32/syscall_dispatch.c @@ -93,16 +93,6 @@ static secbool storage_init_callback_wrapper( return result; } -static firmware_hash_callback_t firmware_hash_callback = NULL; - -static void firmware_hash_callback_wrapper(void *context, uint32_t progress, - uint32_t total) { - g_in_app_callback = true; - invoke_app_callback((uint32_t)context, progress, total, - firmware_hash_callback); - g_in_app_callback = false; -} - __attribute((no_stack_protector)) void syscall_handler(uint32_t *args, uint32_t syscall) { switch (syscall) { @@ -687,17 +677,16 @@ __attribute((no_stack_protector)) void syscall_handler(uint32_t *args, args[0] = firmware_get_vendor__verified(buff, buff_size); } break; - case SYSCALL_FIRMWARE_CALC_HASH: { + case SYSCALL_FIRMWARE_HASH_START: { const uint8_t *challenge = (const uint8_t *)args[0]; size_t challenge_len = args[1]; - uint8_t *hash = (uint8_t *)args[2]; - size_t hash_len = args[3]; - firmware_hash_callback = (firmware_hash_callback_t)args[4]; - void *callback_context = (void *)args[5]; + args[0] = firmware_hash_start__verified(challenge, challenge_len); + } break; - args[0] = firmware_calc_hash__verified( - challenge, challenge_len, hash, hash_len, - firmware_hash_callback_wrapper, callback_context); + case SYSCALL_FIRMWARE_HASH_CONTINUE: { + uint8_t *hash = (uint8_t *)args[0]; + size_t hash_len = args[1]; + args[0] = firmware_hash_continue__verified(hash, hash_len); } break; #ifdef USE_BLE diff --git a/core/embed/sys/syscall/stm32/syscall_numbers.h b/core/embed/sys/syscall/stm32/syscall_numbers.h index 0a20eeb2e8..1b65a6ae39 100644 --- a/core/embed/sys/syscall/stm32/syscall_numbers.h +++ b/core/embed/sys/syscall/stm32/syscall_numbers.h @@ -137,7 +137,8 @@ typedef enum { SYSCALL_RNG_GET, SYSCALL_FIRMWARE_GET_VENDOR, - SYSCALL_FIRMWARE_CALC_HASH, + SYSCALL_FIRMWARE_HASH_START, + SYSCALL_FIRMWARE_HASH_CONTINUE, SYSCALL_BLE_START, SYSCALL_BLE_ISSUE_COMMAND, diff --git a/core/embed/sys/syscall/stm32/syscall_stubs.c b/core/embed/sys/syscall/stm32/syscall_stubs.c index bd43f460b3..0ad82bb1d3 100644 --- a/core/embed/sys/syscall/stm32/syscall_stubs.c +++ b/core/embed/sys/syscall/stm32/syscall_stubs.c @@ -631,24 +631,14 @@ secbool firmware_get_vendor(char *buff, size_t buff_size) { SYSCALL_FIRMWARE_GET_VENDOR); } -static firmware_hash_callback_t firmware_hash_callback = NULL; - -static void firmware_hash_callback_wrapper(void *context, uint32_t progress, - uint32_t total) { - firmware_hash_callback(context, progress, total); - syscall_return_from_callback(0); +int firmware_hash_start(const uint8_t *challenge, size_t challenge_len) { + return (int)syscall_invoke2((uint32_t)challenge, challenge_len, + SYSCALL_FIRMWARE_HASH_START); } -secbool firmware_calc_hash(const uint8_t *challenge, size_t challenge_len, - uint8_t *hash, size_t hash_len, - firmware_hash_callback_t callback, - void *callback_context) { - firmware_hash_callback = callback; - - return syscall_invoke6((uint32_t)challenge, challenge_len, (uint32_t)hash, - hash_len, (uint32_t)firmware_hash_callback_wrapper, - (uint32_t)callback_context, - SYSCALL_FIRMWARE_CALC_HASH); +int firmware_hash_continue(uint8_t *hash, size_t hash_len) { + return (int)syscall_invoke2((uint32_t)hash, hash_len, + SYSCALL_FIRMWARE_HASH_CONTINUE); } #ifdef USE_BLE diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.c b/core/embed/sys/syscall/stm32/syscall_verifiers.c index 53c724828c..0b04ea539b 100644 --- a/core/embed/sys/syscall/stm32/syscall_verifiers.c +++ b/core/embed/sys/syscall/stm32/syscall_verifiers.c @@ -712,25 +712,29 @@ access_violation: // --------------------------------------------------------------------- -secbool firmware_calc_hash__verified(const uint8_t *challenge, - size_t challenge_len, uint8_t *hash, - size_t hash_len, - firmware_hash_callback_t callback, - void *callback_context) { +int firmware_hash_start__verified(const uint8_t *challenge, + size_t challenge_len) { if (!probe_read_access(challenge, challenge_len)) { goto access_violation; } + return firmware_hash_start(challenge, challenge_len); + +access_violation: + apptask_access_violation(); + return -1; +} + +int firmware_hash_continue__verified(uint8_t *hash, size_t hash_len) { if (!probe_write_access(hash, hash_len)) { goto access_violation; } - return firmware_calc_hash(challenge, challenge_len, hash, hash_len, callback, - callback_context); + return firmware_hash_continue(hash, hash_len); access_violation: apptask_access_violation(); - return secfalse; + return -1; } secbool firmware_get_vendor__verified(char *buff, size_t buff_size) { diff --git a/core/embed/sys/syscall/stm32/syscall_verifiers.h b/core/embed/sys/syscall/stm32/syscall_verifiers.h index 6d53d7a979..880e350aa6 100644 --- a/core/embed/sys/syscall/stm32/syscall_verifiers.h +++ b/core/embed/sys/syscall/stm32/syscall_verifiers.h @@ -183,11 +183,10 @@ void entropy_get__verified(uint8_t *buf); // --------------------------------------------------------------------- #include -secbool firmware_calc_hash__verified(const uint8_t *challenge, - size_t challenge_len, uint8_t *hash, - size_t hash_len, - firmware_hash_callback_t callback, - void *callback_context); +int firmware_hash_start__verified(const uint8_t *challenge, + size_t challenge_len); + +int firmware_hash_continue__verified(uint8_t *hash, size_t hash_len); secbool firmware_get_vendor__verified(char *buff, size_t buff_size); diff --git a/core/embed/upymod/modtrezorutils/modtrezorutils.c b/core/embed/upymod/modtrezorutils/modtrezorutils.c index eef23b41e1..4ea30c92b5 100644 --- a/core/embed/upymod/modtrezorutils/modtrezorutils.c +++ b/core/embed/upymod/modtrezorutils/modtrezorutils.c @@ -49,15 +49,6 @@ #include #endif -static void ui_progress(void *context, uint32_t current, uint32_t total) { - mp_obj_t ui_wait_callback = (mp_obj_t)context; - - if (mp_obj_is_callable(ui_wait_callback)) { - mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(current), - mp_obj_new_int(total)); - } -} - /// def consteq(sec: bytes, pub: bytes) -> bool: /// """ /// Compares the private information in `sec` with public, user-provided @@ -168,14 +159,31 @@ STATIC mp_obj_t mod_trezorutils_firmware_hash(size_t n_args, vstr_t vstr = {0}; vstr_init_len(&vstr, BLAKE2S_DIGEST_LENGTH); - if (sectrue != firmware_calc_hash(chal.buf, chal.len, (uint8_t *)vstr.buf, - vstr.len, ui_progress, ui_wait_callback)) { + if (firmware_hash_start(chal.buf, chal.len) < 0) { vstr_clear(&vstr); - mp_raise_msg(&mp_type_RuntimeError, "Failed to calculate firmware hash."); + mp_raise_msg(&mp_type_RuntimeError, "Failed to start firmware hash."); + } + + int progress = 0; + + while (progress < 100) { + progress = firmware_hash_continue((uint8_t *)vstr.buf, vstr.len); + + if (progress < 0) { + vstr_clear(&vstr); + mp_raise_msg(&mp_type_RuntimeError, "Failed to calculate firmware hash."); + break; + } + + if (mp_obj_is_callable(ui_wait_callback)) { + mp_call_function_2_protected(ui_wait_callback, mp_obj_new_int(progress), + mp_obj_new_int(100)); + } } return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); } + STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_firmware_hash_obj, 0, 2, mod_trezorutils_firmware_hash); diff --git a/core/embed/util/fwutils/fwutils.c b/core/embed/util/fwutils/fwutils.c index 0c9c60166a..1473e47f22 100644 --- a/core/embed/util/fwutils/fwutils.c +++ b/core/embed/util/fwutils/fwutils.c @@ -21,9 +21,11 @@ #include #include +#include #include #include #include + #include "blake2s.h" #include "flash_area.h" @@ -31,51 +33,76 @@ #define FW_HASHING_CHUNK_SIZE 1024 -secbool firmware_calc_hash(const uint8_t* challenge, size_t challenge_len, - uint8_t* hash, size_t hash_len, - firmware_hash_callback_t callback, - void* callback_context) { - BLAKE2S_CTX ctx; +typedef struct { + bool initialized; + BLAKE2S_CTX blake; + uint32_t fw_offset; + uint32_t fw_size; + +} firmware_hash_context_t; + +static firmware_hash_context_t g_hash_context[SYSTASK_MAX_TASKS]; + +int firmware_hash_start(const uint8_t* challenge, size_t challenge_len) { + firmware_hash_context_t* ctx = &g_hash_context[systask_id(systask_active())]; + + int err; if (challenge_len != 0) { - if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, challenge, - challenge_len) != 0) { - return secfalse; - } + err = blake2s_InitKey(&ctx->blake, BLAKE2S_DIGEST_LENGTH, challenge, + challenge_len); } else { - blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); + err = blake2s_Init(&ctx->blake, BLAKE2S_DIGEST_LENGTH); } - uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA); - uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE; + if (err != 0) { + return -1; + } - ensure((firmware_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue, + ctx->fw_offset = 0; + ctx->fw_size = flash_area_get_size(&FIRMWARE_AREA); + + ensure((ctx->fw_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue, "Cannot compute FW hash."); - for (int i = 0; i < chunks; i++) { - if (callback != NULL && (i % 128 == 0)) { - callback(callback_context, i, chunks); + ctx->initialized = true; + return 0; +} + +int firmware_hash_continue(uint8_t* hash, size_t hash_len) { + firmware_hash_context_t* ctx = &g_hash_context[systask_id(systask_active())]; + + memset(hash, 0, hash_len); + + if (!ctx->initialized) { + return -1; + } + + int n_chunks = 128; + + while (ctx->fw_offset < ctx->fw_size && n_chunks > 0) { + const void* chunk_ptr = flash_area_get_address( + &FIRMWARE_AREA, ctx->fw_offset, FW_HASHING_CHUNK_SIZE); + + int err = blake2s_Update(&ctx->blake, chunk_ptr, FW_HASHING_CHUNK_SIZE); + if (err != 0) { + ctx->initialized = false; + return -1; } - const void* data = flash_area_get_address( - &FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE); + ctx->fw_offset += FW_HASHING_CHUNK_SIZE; + --n_chunks; + } - if (data == NULL) { - return secfalse; + if (ctx->fw_offset >= ctx->fw_size) { + ctx->initialized = false; + int err = blake2s_Final(&ctx->blake, hash, hash_len); + if (err != 0) { + return -1; } - - blake2s_Update(&ctx, data, FW_HASHING_CHUNK_SIZE); } - if (callback != NULL) { - callback(callback_context, chunks, chunks); - } - - if (blake2s_Final(&ctx, hash, hash_len) != 0) { - return secfalse; - } - - return sectrue; + return (100 * ctx->fw_offset) / ctx->fw_size; } secbool firmware_get_vendor(char* buff, size_t buff_size) { diff --git a/core/embed/util/fwutils/inc/util/fwutils.h b/core/embed/util/fwutils/inc/util/fwutils.h index 69c77a2f2c..2e8b4d504c 100644 --- a/core/embed/util/fwutils/inc/util/fwutils.h +++ b/core/embed/util/fwutils/inc/util/fwutils.h @@ -22,26 +22,23 @@ #include -// Callback function for firmware hash calculation. -typedef void (*firmware_hash_callback_t)(void* context, uint32_t progress, - uint32_t total); - -// Calculates hash of the firmware area. +// (Re)starts calculation of the firmware hash // -// `challenge` is a optional pointer to the challenge data. +// `challenge` is a pointer to the challenge data (optional, can be NULL). // `challenge_len` is the length of the challenge data (1..32). +// +// Return 0 on success, -1 on error. +int firmware_hash_start(const uint8_t* challenge, size_t challenge_len); + +// Continues with the firmware hash calculation. +// // `hash` is a pointer to a buffer where the hash will be stored. // `hash_len` is size of the buffer (must be at least 32). -// `callback` is an optional callback function that will be called during the -// hash calculation. -// `callback_context` is a pointer that will be passed to the callback function. // -// Returns `sectrue` if the hash was calculated successfully, `secfalse` -// otherwise. -secbool firmware_calc_hash(const uint8_t* challenge, size_t challenge_len, - uint8_t* hash, size_t hash_len, - firmware_hash_callback_t callback, - void* callback_context); +// Return value between 0 and 100 indicates the progress of the hash +// calculation. 100 means the hash was calculated successfully and +// `hash` contains the hash. -1 means an error occurred during the +int firmware_hash_continue(uint8_t* hash, size_t hash_len); // Reads the firmware vendor string from the header in the firmware area. //