refactor(core): simplify secret.h api, hide platform differences

[no changelog]
pull/3708/head
tychovrahe 4 weeks ago committed by TychoVrahe
parent 89c6590e45
commit 1600759457

@ -137,11 +137,11 @@ SOURCE_TREZORHAL = [
'embed/trezorhal/unix/rng.c',
'embed/trezorhal/unix/usb.c',
'embed/trezorhal/unix/random_delays.c',
'embed/trezorhal/unix/secret.c',
]
if TREZOR_MODEL in ('R', 'T3T1'):
SOURCE_TREZORHAL += [
'embed/trezorhal/unix/secret.c',
'embed/trezorhal/unix/optiga_hal.c',
]

@ -258,11 +258,6 @@ int main(void) {
#ifdef STM32U5
tamper_init();
if (sectrue == secret_bhk_locked()) {
delete_secrets();
NVIC_SystemReset();
}
trustzone_init_boardloader();
secret_ensure_initialized();

@ -257,16 +257,6 @@ void ui_screen_fail(void) { screen_install_fail(); }
uint32_t ui_screen_unlock_bootloader_confirm(void) {
return screen_unlock_bootloader_confirm();
}
void ui_screen_install_restricted(void) {
display_clear();
screen_fatal_error_rust(
"INSTALL RESTRICTED",
"Installation of custom firmware is currently restricted.",
"Please visit\ntrezor.io/bootloader");
display_refresh();
}
#else
void ui_screen_install_restricted(void) { screen_install_fail(); }
#endif

@ -62,7 +62,6 @@ void ui_screen_wipe_progress(int pos, int len);
void ui_screen_done(uint8_t restart_seconds, secbool full_redraw);
void ui_screen_fail(void);
void ui_screen_install_restricted(void);
void ui_fadein(void);
void ui_fadeout(void);

@ -193,7 +193,7 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
if (r == UPLOAD_ERR_BOOTLOADER_LOCKED) {
ui_screen_install_restricted();
secret_show_install_restricted_screen();
} else {
ui_screen_fail();
}
@ -325,33 +325,9 @@ void real_jump_to_firmware(void) {
&FIRMWARE_AREA),
"Firmware is corrupted");
#ifdef STM32U5
secret_bhk_provision();
secret_bhk_lock();
#ifdef USE_OPTIGA
if (sectrue == secret_optiga_present()) {
secret_optiga_backup();
secret_hide();
} else {
secret_optiga_hide();
}
#else
secret_hide();
#endif
#endif
#ifdef USE_OPTIGA
#ifdef STM32U5
if ((vhdr.vtrust & VTRUST_SECRET) != 0) {
secret_optiga_hide();
}
#else
if (((vhdr.vtrust & VTRUST_SECRET) != 0) && (sectrue != secret_wiped())) {
ui_screen_install_restricted();
trezor_shutdown();
}
#endif
#endif
secret_prepare_fw(
((vhdr.vtrust & VTRUST_SECRET) == VTRUST_SECRET_ALLOW) * sectrue,
((vhdr.vtrust & VTRUST_ALL) == VTRUST_ALL) * sectrue);
// if all VTRUST flags are unset = ultimate trust => skip the procedure
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {

@ -638,7 +638,8 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
}
#if defined USE_OPTIGA && !defined STM32U5
if (sectrue != secret_wiped() && ((vhdr.vtrust & VTRUST_SECRET) != 0)) {
if (sectrue != secret_wiped() &&
((vhdr.vtrust & VTRUST_SECRET) != VTRUST_SECRET_ALLOW)) {
MSG_SEND_INIT(Failure);
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
MSG_SEND_ASSIGN_STRING(message, "Install restricted");

@ -58,8 +58,14 @@ typedef struct {
#define VTRUST_RED 0x0010
#define VTRUST_CLICK 0x0020
#define VTRUST_STRING 0x0040
#define VTRUST_SECRET \
0x0080 // inverse logic, if set, don't allow to run with secret present
// Two bits for historical reasons. On T2B1, only the lower bit was used with
// inverted logic (due to late inclusion of the secret handling during
// development process). On T3T1, we decided to remedy the situation by
// including the upper bit as well.
#define VTRUST_SECRET 0x0180
#define VTRUST_SECRET_ALLOW 0x0100
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
typedef struct {

@ -93,3 +93,12 @@ const flash_area_t ALL_WIPE_AREA = {
.num_sectors = 21,
},
};
const flash_area_t SECRET_AREA = {
.num_subareas = 1,
.subarea[0] =
{
.first_sector = 0,
.num_sectors = 0,
},
};

@ -36,9 +36,6 @@ secbool secret_ensure_initialized(void);
// Erases the entire secret storage
void secret_erase(void);
// Disables access to the secret storage until next reset
void secret_hide(void);
// Writes the secret header to the secret storage
void secret_write_header(void);
@ -55,30 +52,15 @@ secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]);
// was made unavailable by calling secret_optiga_hide
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]);
// Backs up the optiga pairing secret from the secret storage to the backup
// register
void secret_optiga_backup(void);
// Deletes the optiga pairing secret from the register
void secret_optiga_hide(void);
// Locks the BHK register. Once locked, the BHK register can't be accessed by
// the software. BHK is made available to the SAES peripheral
void secret_bhk_lock(void);
// Verifies that access to the register has been disabled
secbool secret_bhk_locked(void);
// Regenerates the BHK and writes it to the secret storage
void secret_bhk_regenerate(void);
// Provision the secret BHK from the secret storage to the BHK register
// which makes the BHK usable for encryption by the firmware, without having
// read access to it.
void secret_bhk_provision(void);
// Prepares the secret storage for running the firmware
// Provisions secrets/keys to the firmware, depending on the trust level
// Disables access to the secret storage until next reset, if possible
// This function is called by the bootloader before starting the firmware
void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all);
// Checks that the optiga pairing secret is present in the secret storage.
// This functions only works when software has access to the secret storage,
// i.e. in bootloader. Access to secret storage is restricted by calling
// secret_hide.
secbool secret_optiga_present(void);
// Shows a screen informing the user that installation of custom firmware is
// currently restricted
void secret_show_install_restricted_screen(void);

@ -1,21 +1,27 @@
#include "secret.h"
#include <string.h>
#include "common.h"
#include "display.h"
#include "flash.h"
#include "model.h"
#ifdef FANCY_FATAL_ERROR
#include "rust_ui.h"
#endif
static secbool bootloader_locked_set = secfalse;
static secbool bootloader_locked = secfalse;
secbool secret_verify_header(void) {
uint8_t header[sizeof(SECRET_HEADER_MAGIC)] = {0};
uint8_t* addr = (uint8_t*)flash_area_get_address(&SECRET_AREA, 0,
sizeof(SECRET_HEADER_MAGIC));
memcpy(header,
flash_area_get_address(&SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC)),
sizeof(SECRET_HEADER_MAGIC));
if (addr == NULL) {
return secfalse;
}
bootloader_locked =
memcmp(header, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
? sectrue
: secfalse;
bootloader_locked_set = sectrue;
@ -51,20 +57,25 @@ secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) {
return secfalse;
}
memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len);
uint8_t* addr = (uint8_t*)flash_area_get_address(&SECRET_AREA, offset, len);
if (addr == NULL) {
return secfalse;
}
memcpy(data, addr, len);
return sectrue;
}
secbool secret_wiped(void) {
flash_area_get_address(&SECRET_AREA, 0, 1);
flash_area_get_size(&SECRET_AREA);
uint32_t size = flash_area_get_size(&SECRET_AREA);
for (int i = 0; i < size; i += 4) {
uint32_t* addr = (uint32_t*)flash_area_get_address(&SECRET_AREA, i, 4);
if (addr == NULL) {
return secfalse;
}
if (*addr != 0xFFFFFFFF) {
return secfalse;
}
@ -86,3 +97,24 @@ secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
}
void secret_show_install_restricted_screen(void) {
#ifdef FANCY_FATAL_ERROR
display_clear();
screen_fatal_error_rust(
"INSTALL RESTRICTED",
"Installation of custom firmware is currently restricted.",
"Please visit\ntrezor.io/bootloader");
display_refresh();
#endif
}
void secret_prepare_fw(secbool allow_run_with_secret, secbool _trust_all) {
#ifdef USE_OPTIGA
if (sectrue != allow_run_with_secret && sectrue != secret_wiped()) {
secret_show_install_restricted_screen();
trezor_shutdown();
}
#endif
}

@ -11,14 +11,15 @@
static secbool bootloader_locked = secfalse;
secbool secret_verify_header(void) {
uint8_t header[sizeof(SECRET_HEADER_MAGIC)] = {0};
uint8_t *addr = (uint8_t *)flash_area_get_address(
&SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC));
memcpy(header,
flash_area_get_address(&SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC)),
sizeof(SECRET_HEADER_MAGIC));
if (addr == NULL) {
return secfalse;
}
bootloader_locked =
memcmp(header, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0
? sectrue
: secfalse;
return bootloader_locked;
@ -63,41 +64,60 @@ secbool secret_read(uint8_t *data, uint32_t offset, uint32_t len) {
if (sectrue != secret_verify_header()) {
return secfalse;
}
uint8_t *addr = (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len);
if (addr == NULL) {
return secfalse;
}
memcpy(data, addr, len);
return sectrue;
}
void secret_hide(void) {
static void secret_disable_access(void) {
FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP1_ACCDIS_Msk;
FLASH->SECHDPCR |= FLASH_SECHDPCR_HDP2_ACCDIS_Msk;
}
void secret_bhk_lock(void) {
// Locks the BHK register. Once locked, the BHK register can't be accessed by
// the software. BHK is made available to the SAES peripheral
static void secret_bhk_lock(void) {
TAMP_S->SECCFGR = 8 << TAMP_SECCFGR_BKPRWSEC_Pos | TAMP_SECCFGR_BHKLOCK;
}
secbool secret_bhk_locked(void) {
// Verifies that access to the register has been disabled
static secbool secret_bhk_locked(void) {
return ((TAMP_S->SECCFGR & TAMP_SECCFGR_BHKLOCK) == TAMP_SECCFGR_BHKLOCK) *
sectrue;
}
static secbool secret_present(uint32_t offset, uint32_t len) {
uint8_t *optiga_secret =
uint8_t *secret =
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
int optiga_secret_empty_bytes = 0;
if (secret == NULL) {
return secfalse;
}
int secret_empty_bytes = 0;
for (int i = 0; i < len; i++) {
if (optiga_secret[i] == 0xFF) {
optiga_secret_empty_bytes++;
if (secret[i] == 0xFF) {
secret_empty_bytes++;
}
}
return sectrue * (optiga_secret_empty_bytes != len);
return sectrue * (secret_empty_bytes != len);
}
void secret_bhk_provision(void) {
// Provision the secret BHK from the secret storage to the BHK register
// which makes the BHK usable for encryption by the firmware, without having
// read access to it.
static void secret_bhk_load(void) {
if (sectrue == secret_bhk_locked()) {
delete_secrets();
NVIC_SystemReset();
}
uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0};
if (sectrue != secret_present(SECRET_BHK_OFFSET, SECRET_BHK_LEN)) {
@ -139,23 +159,18 @@ void secret_bhk_regenerate(void) {
ensure(flash_lock_write(), "Failed regenerating BHK");
}
secbool secret_optiga_present(void) {
#ifdef USE_OPTIGA
// Checks that the optiga pairing secret is present in the secret storage.
// This functions only works when software has access to the secret storage,
// i.e. in bootloader. Access to secret storage is restricted by calling
// secret_hide.
static secbool secret_optiga_present(void) {
return secret_present(SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
}
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
uint8_t secret_enc[SECRET_OPTIGA_KEY_LEN] = {0};
if (sectrue != secure_aes_ecb_encrypt_hw(secret, sizeof(secret_enc),
secret_enc, SECURE_AES_KEY_DHUK)) {
return secfalse;
}
secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
memzero(secret_enc, sizeof(secret_enc));
secret_optiga_backup();
return sectrue;
}
void secret_optiga_backup(void) {
// Backs up the optiga pairing secret from the secret storage to the backup
// register
static void secret_optiga_cache(void) {
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET,
SECRET_OPTIGA_KEY_LEN);
@ -175,6 +190,18 @@ void secret_optiga_backup(void) {
memzero(secret, sizeof(secret));
}
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
uint8_t secret_enc[SECRET_OPTIGA_KEY_LEN] = {0};
if (sectrue != secure_aes_ecb_encrypt_hw(secret, sizeof(secret_enc),
secret_enc, SECURE_AES_KEY_DHUK)) {
return secfalse;
}
secret_write(secret_enc, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
memzero(secret_enc, sizeof(secret_enc));
secret_optiga_cache();
return sectrue;
}
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
@ -199,14 +226,56 @@ secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
return res;
}
void secret_optiga_hide(void) {
// Deletes the optiga pairing secret from the register
static void secret_optiga_uncache(void) {
volatile uint32_t *reg1 = &TAMP->BKP8R;
for (int i = 0; i < 8; i++) {
*reg1 = 0;
reg1++;
reg1[i] = 0;
}
}
#endif
void secret_erase(void) {
ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase");
}
void secret_show_install_restricted_screen(void) {
// this should never happen on U5
__fatal_error("INTERNAL ERROR", "Install restricted", __FILE__, __LINE__,
__func__);
}
void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) {
/**
* The BHK is copied to the backup registers, which are accessible by the SAES
* peripheral. The BHK register is locked, so the BHK can't be accessed by the
* software.
*
* When optiga is paired, pairing secret is copied to the backup registers
* and access to the secret storage is disabled. Otherwise, access to the
* secret storage kept to allow optiga pairing in prodtest.
*
* Access to the secret storage is disabled for non-official firmware in
* all-cases.
*/
secret_bhk_load();
secret_bhk_lock();
#ifdef USE_OPTIGA
secret_optiga_uncache();
if (sectrue == allow_run_with_secret) {
if (secfalse != secret_optiga_present()) {
secret_optiga_cache();
secret_disable_access();
}
} else {
secret_disable_access();
}
#else
secret_disable_access();
#endif
if (sectrue != trust_all) {
secret_disable_access();
}
}

@ -6,6 +6,8 @@
"version": [0, 0],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": true,
"require_user_click": true,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": true,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": true,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 2],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": true,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": true,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 2],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": true,
"require_user_click": true,

@ -6,6 +6,8 @@
"version": [0, 0],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 0],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": false,
"require_user_click": false,

@ -6,6 +6,8 @@
"version": [0, 1],
"sig_m": 2,
"trust": {
"_reserved": 0,
"_dont_provide_secret": false,
"allow_run_with_secret": false,
"show_vendor_string": true,
"require_user_click": true,

@ -49,6 +49,7 @@ def stm32f4_common_files(env, defines, sources, paths):
"embed/trezorhal/stm32f4/lowlevel.c",
"embed/trezorhal/stm32f4/mpu.c",
"embed/trezorhal/stm32f4/platform.c",
"embed/trezorhal/stm32f4/secret.c",
"embed/trezorhal/stm32f4/systick.c",
"embed/trezorhal/stm32f4/supervise.c",
"embed/trezorhal/stm32f4/random_delays.c",

@ -70,7 +70,6 @@ def configure(
sources += ["embed/trezorhal/optiga/optiga.c"]
sources += ["embed/trezorhal/optiga/optiga_commands.c"]
sources += ["embed/trezorhal/optiga/optiga_transport.c"]
sources += ["embed/trezorhal/stm32f4/secret.c"]
sources += ["vendor/trezor-crypto/hash_to_curve.c"]
features_available.append("optiga")

@ -47,6 +47,7 @@ def _transform_vendor_trust(data: bytes) -> bytes:
class VendorTrust(Struct):
_dont_provide_secret: bool
allow_run_with_secret: bool
show_vendor_string: bool
require_user_click: bool
@ -57,7 +58,9 @@ class VendorTrust(Struct):
SUBCON = c.Transformed(
c.BitStruct(
"_reserved" / c.Default(c.BitsInteger(8), 0),
"_reserved" / c.Default(c.BitsInteger(7), 0b1111111),
"_dont_provide_secret"
/ c.Default(c.Flag, lambda this: not this.allow_run_with_secret),
"allow_run_with_secret" / c.Flag,
"show_vendor_string" / c.Flag,
"require_user_click" / c.Flag,

Loading…
Cancel
Save