diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h index 99d5d120db..8c85ac9e5a 100644 --- a/core/embed/trezorhal/secret.h +++ b/core/embed/trezorhal/secret.h @@ -56,6 +56,9 @@ secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]); // Checks if the optiga pairing secret is present in the secret storage secbool secret_optiga_present(void); +// Checks if the optiga pairing secret can be written to the secret storage +secbool secret_optiga_writable(void); + // Erases optiga pairing secret from the secret storage void secret_optiga_erase(void); diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c index 45abb31e98..72a3aefc01 100644 --- a/core/embed/trezorhal/stm32f4/secret.c +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -102,6 +102,8 @@ secbool secret_optiga_present(void) { return (sectrue != secret_wiped()) * sectrue; } +secbool secret_optiga_writable(void) { return secret_wiped(); } + void secret_optiga_erase(void) { secret_erase(); } void secret_prepare_fw(secbool allow_run_with_secret, secbool _trust_all) { diff --git a/core/embed/trezorhal/stm32u5/secret.c b/core/embed/trezorhal/stm32u5/secret.c index b2f49b7a7b..d148f0a54d 100644 --- a/core/embed/trezorhal/stm32u5/secret.c +++ b/core/embed/trezorhal/stm32u5/secret.c @@ -176,6 +176,29 @@ secbool secret_optiga_present(void) { return secret_present(SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); } +secbool secret_optiga_writable(void) { + const uint32_t offset = SECRET_OPTIGA_KEY_OFFSET; + const uint32_t len = SECRET_OPTIGA_KEY_LEN; + + const uint8_t *const secret = + (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len); + + if (secret == NULL) { + return secfalse; + } + + int secret_empty_bytes = 0; + + for (int i = 0; i < len; i++) { + // 0xFF being the default value of the flash memory (before any write) + // 0x00 being the value of the flash memory after manual erase + if (secret[i] == 0xFF) { + secret_empty_bytes++; + } + } + return sectrue * (secret_empty_bytes == len); +} + // Backs up the optiga pairing secret from the secret storage to the backup // register static void secret_optiga_cache(void) { @@ -270,16 +293,25 @@ void secret_prepare_fw(secbool allow_run_with_secret, secbool trust_all) { 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 { - if (secfalse != secret_optiga_present()) { - show_install_restricted_screen(); - } - secret_disable_access(); + secbool optiga_secret_present = secret_optiga_present(); + secbool optiga_secret_writable = secret_optiga_writable(); + if (sectrue == trust_all && sectrue == allow_run_with_secret && + sectrue == optiga_secret_writable && secfalse == optiga_secret_present) { + // Secret is not present and the secret sector is writable. + // This means the U5 chip is unprovisioned. + // Allow trusted firmware (prodtest presumably) to access the secret sector, + // early return here. + return; + } + if (sectrue == allow_run_with_secret && sectrue == optiga_secret_present) { + // Firmware is trusted and the Optiga secret is present, make it available. + secret_optiga_cache(); + } + // Disable access unconditionally. + secret_disable_access(); + if (sectrue != trust_all && sectrue == optiga_secret_present) { + // Untrusted firmware, locked bootloader. Show the restricted screen. + show_install_restricted_screen(); } #else secret_disable_access();