refactor(core/embed): moving specific algorithms into fwutils

[no changelog]
tychovrahe/coresplit/merged
cepetr 3 weeks ago
parent e931661d4d
commit d8475ad145

@ -422,6 +422,7 @@ SOURCE_UNIX = [
'embed/trezorhal/unix/common.c',
'embed/trezorhal/unix/flash_otp.c',
'embed/trezorhal/unix/flash.c',
'embed/trezorhal/unix/fwutils.c',
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/systick.c',

@ -31,25 +31,20 @@
#include <string.h>
#include "blake2s.h"
#include "bootutils.h"
#include "common.h"
#include "flash.h"
#include "error_handling.h"
#include "fwutils.h"
#include "unit_variant.h"
#include "usb.h"
#include TREZOR_BOARD
#include "model.h"
#ifndef TREZOR_EMULATOR
#include "image.h"
#endif
#if USE_OPTIGA && !defined(TREZOR_EMULATOR)
#include "secret.h"
#endif
#define FW_HASHING_CHUNK_SIZE 1024
static void ui_progress(void *context, uint32_t current, uint32_t total) {
mp_obj_t ui_wait_callback = (mp_obj_t)context;
static void ui_progress(mp_obj_t ui_wait_callback, uint32_t current,
uint32_t total) {
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));
@ -153,51 +148,23 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_trezorutils_halt_obj, 0, 1,
/// """
STATIC mp_obj_t mod_trezorutils_firmware_hash(size_t n_args,
const mp_obj_t *args) {
BLAKE2S_CTX ctx;
mp_buffer_info_t chal = {0};
if (n_args > 0 && args[0] != mp_const_none) {
mp_get_buffer_raise(args[0], &chal, MP_BUFFER_READ);
}
if (chal.len != 0) {
if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, chal.buf, chal.len) != 0) {
mp_raise_msg(&mp_type_ValueError, "Invalid challenge.");
}
} else {
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
}
mp_obj_t ui_wait_callback = mp_const_none;
if (n_args > 1 && args[1] != mp_const_none) {
ui_wait_callback = args[1];
}
uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA);
uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE;
ensure((firmware_size % FW_HASHING_CHUNK_SIZE == 0) * sectrue,
"Cannot compute FW hash.");
ui_progress(ui_wait_callback, 0, chunks);
for (int i = 0; i < chunks; i++) {
const void *data = flash_area_get_address(
&FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE);
if (data == NULL) {
mp_raise_msg(&mp_type_RuntimeError, "Failed to read firmware.");
}
blake2s_Update(&ctx, data, FW_HASHING_CHUNK_SIZE);
if (i % 128 == 0) {
ui_progress(ui_wait_callback, i + 1, chunks);
}
}
ui_progress(ui_wait_callback, chunks, chunks);
vstr_t vstr = {0};
vstr_init_len(&vstr, BLAKE2S_DIGEST_LENGTH);
if (blake2s_Final(&ctx, vstr.buf, vstr.len) != 0) {
if (sectrue != firmware_calc_hash(chal.buf, chal.len, (uint8_t *)vstr.buf,
vstr.len, ui_progress, ui_wait_callback)) {
vstr_clear(&vstr);
mp_raise_msg(&mp_type_RuntimeError, "Failed to finalize firmware hash.");
mp_raise_msg(&mp_type_RuntimeError, "Failed to calculate firmware hash.");
}
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
@ -213,13 +180,11 @@ STATIC mp_obj_t mod_trezorutils_firmware_vendor(void) {
#ifdef TREZOR_EMULATOR
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)"EMULATOR", 8);
#else
vendor_header vhdr = {0};
const void *data = flash_area_get_address(&FIRMWARE_AREA, 0, 0);
if (data == NULL || sectrue != read_vendor_header(data, &vhdr)) {
char vendor[64] = {0};
if (sectrue != firmware_get_vendor(vendor, sizeof(vendor))) {
mp_raise_msg(&mp_type_RuntimeError, "Failed to read vendor header.");
}
return mp_obj_new_str_copy(&mp_type_str, (const uint8_t *)vhdr.vstr,
vhdr.vstr_len);
return mp_obj_new_str_copy(&mp_type_str, (byte *)vendor, strlen(vendor));
#endif
}
STATIC MP_DEFINE_CONST_FUN_OBJ_0(mod_trezorutils_firmware_vendor_obj,

@ -622,7 +622,7 @@ static void test_boardloader_version(const boardloader_version_t *version) {
}
static void test_wipe(void) {
invalidate_firmware();
firmware_invalidate_header();
display_clear();
display_text_center(DISPLAY_RESX / 2, DISPLAY_RESY / 2 + 10, "WIPED", -1,
FONT_BOLD, COLOR_WHITE, COLOR_BLACK);

@ -20,9 +20,43 @@
#ifndef TREZORHAL_FWUTILS_H
#define TREZORHAL_FWUTILS_H
#include <stdint.h>
#include "secbool.h"
// 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.
//
// `challenge` is a optional pointer to the challenge data.
// `challenge_len` is the length of the challenge data (1..32).
// `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);
// Reads the firmware vendor string from the header in the firmware area.
//
// `buff` is a pointer to a buffer where the vendor string will be stored.
// `buff_size` is the length of the buffer (reserve at least 64 bytes).
//
// Returns `sectrue` if the vendor string was read successfully, `secfalse`
// otherwise.
secbool firmware_get_vendor(char* buff, size_t buff_size);
// Invalidates the firmware by erasing the first 1KB of the firmware area.
//
// Note: only works when write access to firmware area is enabled by MPU
void invalidate_firmware(void);
void firmware_invalidate_header(void);
#endif // TREZORHAL_FWUTILS_H

@ -17,15 +17,84 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include STM32_HAL_H
#include <string.h>
#include "fwutils.h"
#include "blake2s.h"
#include "error_handling.h"
#include "flash.h"
#include "flash_area.h"
#include "fwutils.h"
#include "image.h"
#include "model.h"
void invalidate_firmware(void) {
#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;
if (challenge_len != 0) {
if (blake2s_InitKey(&ctx, BLAKE2S_DIGEST_LENGTH, challenge,
challenge_len) != 0) {
return secfalse;
}
} else {
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
}
uint32_t firmware_size = flash_area_get_size(&FIRMWARE_AREA);
uint32_t chunks = firmware_size / FW_HASHING_CHUNK_SIZE;
ensure((firmware_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);
}
const void* data = flash_area_get_address(
&FIRMWARE_AREA, i * FW_HASHING_CHUNK_SIZE, FW_HASHING_CHUNK_SIZE);
if (data == NULL) {
return secfalse;
}
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;
}
secbool firmware_get_vendor(char* buff, size_t buff_size) {
const void* data = flash_area_get_address(&FIRMWARE_AREA, 0, 0);
vendor_header vhdr = {0};
if (data == NULL || sectrue != read_vendor_header(data, &vhdr)) {
return secfalse;
}
if (buff == NULL || buff_size < vhdr.vstr_len + 1) {
return secfalse;
}
strncpy(buff, vhdr.vstr, buff_size);
return sectrue;
}
void firmware_invalidate_header(void) {
#ifdef STM32U5
// on stm32u5, we need to disable the instruction cache before erasing the
// firmware - otherwise, the write check will fail

@ -0,0 +1 @@
../stm32f4/fwutils.c
Loading…
Cancel
Save