diff --git a/core/embed/models/D002/model_D002.h b/core/embed/models/D002/model_D002.h index 3dc4f73476..d8a9d31b8f 100644 --- a/core/embed/models/D002/model_D002.h +++ b/core/embed/models/D002/model_D002.h @@ -21,6 +21,7 @@ #include #include "bootloaders/bootloader_hashes.h" +#include "secret_layout.h" #define MODEL_NAME "D002" #define MODEL_FULL_NAME "Trezor DIY 2" diff --git a/core/embed/models/D002/secret_layout.h b/core/embed/models/D002/secret_layout.h new file mode 100644 index 0000000000..5db2ed5f59 --- /dev/null +++ b/core/embed/models/D002/secret_layout.h @@ -0,0 +1,36 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define SECRET_NUM_KEY_SLOTS 0 + +// first page: static +#define SECRET_HEADER_OFFSET 0x00 +#define SECRET_HEADER_LEN 0x10 + +#define SECRET_MONOTONIC_COUNTER_0_OFFSET 0x10 +#define SECRET_MONOTONIC_COUNTER_0_LEN 0x400 + +#define SECRET_MONOTONIC_COUNTER_1_OFFSET (0x410) +#define SECRET_MONOTONIC_COUNTER_1_LEN 0x400 + +// second page: refreshed on wallet wipe +#define SECRET_BHK_OFFSET 0x2000 +#define SECRET_BHK_LEN 0x20 diff --git a/core/embed/models/T2B1/model_T2B1.h b/core/embed/models/T2B1/model_T2B1.h index a003855177..b49ab40fdb 100644 --- a/core/embed/models/T2B1/model_T2B1.h +++ b/core/embed/models/T2B1/model_T2B1.h @@ -20,6 +20,7 @@ #pragma once #include "bootloaders/bootloader_hashes.h" +#include "secret_layout.h" #define MODEL_NAME "Safe 3" #define MODEL_FULL_NAME "Trezor Safe 3" diff --git a/core/embed/models/T2B1/secret_layout.h b/core/embed/models/T2B1/secret_layout.h new file mode 100644 index 0000000000..63fc83109c --- /dev/null +++ b/core/embed/models/T2B1/secret_layout.h @@ -0,0 +1,31 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define SECRET_NUM_KEY_SLOTS 1 + +// first page: static +#define SECRET_HEADER_OFFSET 0x00 +#define SECRET_HEADER_LEN 0x10 + +#define SECRET_KEY_SLOT_0_OFFSET 0x10 +#define SECRET_KEY_SLOT_0_LEN 0x20 + +#define SECRET_OPTIGA_SLOT 0 diff --git a/core/embed/models/T3B1/model_T3B1.h b/core/embed/models/T3B1/model_T3B1.h index f9afa212ae..93322bc638 100644 --- a/core/embed/models/T3B1/model_T3B1.h +++ b/core/embed/models/T3B1/model_T3B1.h @@ -20,6 +20,7 @@ #pragma once #include "bootloaders/bootloader_hashes.h" +#include "secret_layout.h" #include diff --git a/core/embed/models/T3B1/secret_layout.h b/core/embed/models/T3B1/secret_layout.h new file mode 100644 index 0000000000..eace671f4d --- /dev/null +++ b/core/embed/models/T3B1/secret_layout.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define SECRET_NUM_KEY_SLOTS 1 + +// first page: static +#define SECRET_HEADER_OFFSET 0x00 +#define SECRET_HEADER_LEN 0x10 + +#define SECRET_KEY_SLOT_0_OFFSET 0x10 +#define SECRET_KEY_SLOT_0_LEN 0x20 + +#define SECRET_MONOTONIC_COUNTER_0_OFFSET 0x30 +#define SECRET_MONOTONIC_COUNTER_0_LEN 0x400 + +#define SECRET_MONOTONIC_COUNTER_1_OFFSET (0x430) +#define SECRET_MONOTONIC_COUNTER_1_LEN 0x400 + +// second page: refreshed on wallet wipe +#define SECRET_BHK_OFFSET 0x2000 +#define SECRET_BHK_LEN 0x20 + +#define SECRET_OPTIGA_SLOT 0 diff --git a/core/embed/models/T3T1/model_T3T1.h b/core/embed/models/T3T1/model_T3T1.h index 4895a3fbcf..ae5351fa11 100644 --- a/core/embed/models/T3T1/model_T3T1.h +++ b/core/embed/models/T3T1/model_T3T1.h @@ -20,6 +20,7 @@ #pragma once #include "bootloaders/bootloader_hashes.h" +#include "secret_layout.h" #include diff --git a/core/embed/models/T3T1/secret_layout.h b/core/embed/models/T3T1/secret_layout.h new file mode 100644 index 0000000000..eace671f4d --- /dev/null +++ b/core/embed/models/T3T1/secret_layout.h @@ -0,0 +1,41 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define SECRET_NUM_KEY_SLOTS 1 + +// first page: static +#define SECRET_HEADER_OFFSET 0x00 +#define SECRET_HEADER_LEN 0x10 + +#define SECRET_KEY_SLOT_0_OFFSET 0x10 +#define SECRET_KEY_SLOT_0_LEN 0x20 + +#define SECRET_MONOTONIC_COUNTER_0_OFFSET 0x30 +#define SECRET_MONOTONIC_COUNTER_0_LEN 0x400 + +#define SECRET_MONOTONIC_COUNTER_1_OFFSET (0x430) +#define SECRET_MONOTONIC_COUNTER_1_LEN 0x400 + +// second page: refreshed on wallet wipe +#define SECRET_BHK_OFFSET 0x2000 +#define SECRET_BHK_LEN 0x20 + +#define SECRET_OPTIGA_SLOT 0 diff --git a/core/embed/models/T3W1/model_T3W1.h b/core/embed/models/T3W1/model_T3W1.h index 32c60d8dfa..9578d49733 100644 --- a/core/embed/models/T3W1/model_T3W1.h +++ b/core/embed/models/T3W1/model_T3W1.h @@ -21,6 +21,7 @@ #pragma once #include +#include "secret_layout.h" #include "bootloaders/bootloader_hashes.h" diff --git a/core/embed/models/T3W1/secret_layout.h b/core/embed/models/T3W1/secret_layout.h new file mode 100644 index 0000000000..5f0d6cd5a4 --- /dev/null +++ b/core/embed/models/T3W1/secret_layout.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#define SECRET_NUM_KEY_SLOTS 3 + +// first page: static +#define SECRET_HEADER_OFFSET 0x00 +#define SECRET_HEADER_LEN 0x10 + +#define SECRET_KEY_SLOT_0_OFFSET 0x10 +#define SECRET_KEY_SLOT_0_LEN 0x20 + +#define SECRET_MONOTONIC_COUNTER_0_OFFSET 0x30 +#define SECRET_MONOTONIC_COUNTER_0_LEN 0x400 + +#define SECRET_MONOTONIC_COUNTER_1_OFFSET (0x430) +#define SECRET_MONOTONIC_COUNTER_1_LEN 0x400 + +#define SECRET_KEY_SLOT_1_OFFSET 0x830 +#define SECRET_KEY_SLOT_1_LEN 0x20 + +#define SECRET_KEY_SLOT_2_OFFSET 0x850 +#define SECRET_KEY_SLOT_2_LEN 0x20 +#define SECRET_KEY_SLOT_2_PUBLIC 1 + +// second page: refreshed on wallet wipe +#define SECRET_BHK_OFFSET 0x2000 +#define SECRET_BHK_LEN 0x20 + +// slot assignments +#define SECRET_OPTIGA_SLOT 0 +#define SECRET_TROPIC_TREZOR_PRIVKEY_SLOT 1 +#define SECRET_TROPIC_TROPIC_PUBKEY_SLOT 2 diff --git a/core/embed/projects/bootloader/emulator.c b/core/embed/projects/bootloader/emulator.c index 54e476637d..a55bdc00df 100644 --- a/core/embed/projects/bootloader/emulator.c +++ b/core/embed/projects/bootloader/emulator.c @@ -155,8 +155,7 @@ int main(int argc, char **argv) { } break; #ifdef LOCKABLE_BOOTLOADER case 'l': - // write bootloader-lock secret - secret_write_header(); + secret_lock_bootloader(); break; #endif default: diff --git a/core/embed/projects/prodtest/cmd/prodtest_optiga.c b/core/embed/projects/prodtest/cmd/prodtest_optiga.c index 32959af0ff..1a559f21d8 100644 --- a/core/embed/projects/prodtest/cmd/prodtest_optiga.c +++ b/core/embed/projects/prodtest/cmd/prodtest_optiga.c @@ -19,6 +19,7 @@ #ifdef USE_OPTIGA +#include #include #include @@ -164,10 +165,10 @@ static bool set_metadata(cli_t* cli, uint16_t oid, } void pair_optiga(cli_t* cli) { - uint8_t secret[SECRET_KEY_LEN] = {0}; + uint8_t secret[32] = {0}; - if (secret_optiga_get(secret) != sectrue) { - if (secret_optiga_writable() != sectrue) { + if (secret_key_get(SECRET_OPTIGA_SLOT, secret, sizeof(secret)) != sectrue) { + if (secret_key_writable(SECRET_OPTIGA_SLOT) != sectrue) { // optiga pairing secret is unwritable, so fail optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_FLASH; return; @@ -203,14 +204,14 @@ void pair_optiga(cli_t* cli) { } // Store the pairing secret in the flash memory. - if (sectrue != secret_optiga_set(secret)) { + if (sectrue != secret_key_set(SECRET_OPTIGA_SLOT, secret, sizeof(secret))) { optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_FLASH; return; } // Reload the pairing secret from the flash memory. memzero(secret, sizeof(secret)); - if (sectrue != secret_optiga_get(secret)) { + if (sectrue != secret_key_get(SECRET_OPTIGA_SLOT, secret, sizeof(secret))) { optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH; return; } diff --git a/core/embed/projects/prodtest/emulator.c b/core/embed/projects/prodtest/emulator.c index 74748e7abe..4e30d3c637 100644 --- a/core/embed/projects/prodtest/emulator.c +++ b/core/embed/projects/prodtest/emulator.c @@ -1,16 +1,16 @@ #include #include +#include #include #include #include +#include #include #include -#include - int prodtest_main(void); void usage(void) { @@ -54,6 +54,10 @@ int main(int argc, char **argv) { flash_init(); flash_otp_init(); +#ifdef LOCKABLE_BOOTLOADER + secret_lock_bootloader(); +#endif + int opt; while ((opt = getopt(argc, argv, "h")) != -1) { switch (opt) { diff --git a/core/embed/projects/unix/main.c b/core/embed/projects/unix/main.c index 2d8c263ab8..8358b35703 100644 --- a/core/embed/projects/unix/main.c +++ b/core/embed/projects/unix/main.c @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -57,7 +58,6 @@ #endif #ifdef USE_TROPIC -#include #include #endif @@ -528,6 +528,10 @@ MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); +#ifdef LOCKABLE_BOOTLOADER + secret_lock_bootloader(); +#endif + system_init(&rsod_panic_handler); drivers_init(); diff --git a/core/embed/sec/monoctr/stm32u5/monoctr.c b/core/embed/sec/monoctr/stm32u5/monoctr.c index e984927ab3..ef6102ed35 100644 --- a/core/embed/sec/monoctr/stm32u5/monoctr.c +++ b/core/embed/sec/monoctr/stm32u5/monoctr.c @@ -29,14 +29,25 @@ static int32_t get_offset(monoctr_type_t type) { switch (type) { case MONOCTR_BOOTLOADER_VERSION: - return SECRET_MONOTONIC_COUNTER_OFFSET; + return SECRET_MONOTONIC_COUNTER_0_OFFSET; case MONOCTR_FIRMWARE_VERSION: - return SECRET_MONOTONIC_COUNTER2_OFFSET; + return SECRET_MONOTONIC_COUNTER_1_OFFSET; default: return -1; } } +static size_t get_length(monoctr_type_t type) { + switch (type) { + case MONOCTR_BOOTLOADER_VERSION: + return SECRET_MONOTONIC_COUNTER_0_LEN; + case MONOCTR_FIRMWARE_VERSION: + return SECRET_MONOTONIC_COUNTER_1_LEN; + default: + return 0; + } +} + secbool monoctr_write(monoctr_type_t type, uint8_t value) { if (value > MONOCTR_MAX_VALUE) { return secfalse; @@ -72,13 +83,14 @@ secbool monoctr_write(monoctr_type_t type, uint8_t value) { secbool monoctr_read(monoctr_type_t type, uint8_t *value) { int32_t offset = get_offset(type); + size_t length = get_length(type); if (offset < 0) { return secfalse; } - const uint8_t *counter_addr = flash_area_get_address( - &SECRET_AREA, offset, SECRET_MONOTONIC_COUNTER_LEN); + const uint8_t *counter_addr = + flash_area_get_address(&SECRET_AREA, offset, length); if (counter_addr == NULL) { return secfalse; @@ -90,7 +102,7 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { int i = 0; - for (i = 0; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) { + for (i = 0; i < length / 16; i++) { secbool not_cleared = sectrue; for (int j = 0; j < 16; j++) { if (counter_addr[i * 16 + j] != 0xFF) { @@ -106,7 +118,7 @@ secbool monoctr_read(monoctr_type_t type, uint8_t *value) { } } - for (; i < SECRET_MONOTONIC_COUNTER_LEN / 16; i++) { + for (; i < length / 16; i++) { secbool not_cleared = sectrue; for (int j = 0; j < 16; j++) { if (counter_addr[i * 16 + j] != 0xFF) { diff --git a/core/embed/sec/optiga/optiga_config.c b/core/embed/sec/optiga/optiga_config.c index de05dabe8a..b38294d078 100644 --- a/core/embed/sec/optiga/optiga_config.c +++ b/core/embed/sec/optiga/optiga_config.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include "memzero.h" @@ -57,8 +57,8 @@ void optiga_init_and_configure(void) { optiga_init(); - uint8_t secret[SECRET_KEY_LEN] = {0}; - secbool secret_ok = secret_optiga_get(secret); + uint8_t secret[OPTIGA_PAIRING_SECRET_SIZE] = {0}; + secbool secret_ok = secret_key_optiga_pairing(secret); if (sectrue == secret_ok) { // If the shielded connection cannot be established, reset Optiga and diff --git a/core/embed/sec/secret/inc/sec/secret.h b/core/embed/sec/secret/inc/sec/secret.h index 96355cc9bd..76b29b1b70 100644 --- a/core/embed/sec/secret/inc/sec/secret.h +++ b/core/embed/sec/secret/inc/sec/secret.h @@ -23,105 +23,112 @@ #ifdef SECURE_MODE -#define SECRET_KEY_LEN 32 - -// first page: static -#define SECRET_HEADER_MAGIC "TRZS" -#define SECRET_HEADER_LEN 16 -#define SECRET_OPTIGA_KEY_OFFSET 16 - -#define SECRET_MONOTONIC_COUNTER_OFFSET 48 -#define SECRET_MONOTONIC_COUNTER_LEN 1024 -#define SECRET_MONOTONIC_COUNTER2_OFFSET (SECRET_MONOTONIC_COUNTER_LEN + 48) - -#define SECRET_TROPIC_TRZ_PRIVKEY_OFFSET \ - (SECRET_MONOTONIC_COUNTER_LEN + SECRET_MONOTONIC_COUNTER2_OFFSET) -#define SECRET_TROPIC_TRO_PUBKEY_OFFSET \ - (SECRET_TROPIC_TRZ_PRIVKEY_OFFSET + SECRET_KEY_LEN) - -// second page: refreshed on wallet wipe -#define SECRET_BHK_OFFSET (1024 * 8) - -// Writes data to the secret storage +/** + * @brief Writes data to the secret storage. + * + * @param data Pointer to the data to write. + * @param offset Offset in the storage to begin writing. + * @param len Number of bytes to write. + */ void secret_write(const uint8_t* data, uint32_t offset, uint32_t len); -// Reads data from the secret storage +/** + * @brief Reads data from the secret storage. + * + * @param data Pointer to buffer where read data will be stored. + * @param offset Offset in the storage to begin reading. + * @param len Number of bytes to read. + * @return secbool sectrue on successful read, secfalse otherwise. + */ secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len); -// Checks if the secret storage has been wiped -secbool secret_wiped(void); +/** + * @brief Writes a key to the secret storage. + * + * Encrypts the secret if encryption is available on the platform. + * + * @param slot Index of the key slot. + * @param key Pointer to the key data. + * @param len Length of the key in bytes. + * @return secbool sectrue if the key was written successfully, secfalse + * otherwise. + */ +secbool secret_key_set(uint8_t slot, const uint8_t* key, size_t len); -// Verifies that the secret storage has the correct header -secbool secret_verify_header(void); +/** + * @brief Reads a secret key from the storage. + * + * Decrypts the secret if encryption is available on the platform. + * + * @param slot Index of the key slot. + * @param dest Pointer to destination buffer for the key. + * @param len Length of the dest buffer. + * @return secbool secrue if the key was read successfully, secfalse otherwise. + */ +secbool secret_key_get(uint8_t slot, uint8_t* dest, size_t len); -// Erases the entire secret storage -void secret_erase(void); +/** + * @brief Checks if a secret key slot is writable. + * + * @param slot Index of the key slot. + * @return secbool sectrue if the key slot can be written, secfalse otherwise. + */ +secbool secret_key_writable(uint8_t slot); -// Writes the secret header to the secret storage -void secret_write_header(void); - -#ifdef USE_OPTIGA -// OPTIGA KEYS -// Writes optiga pairing secret to the secret storage -// Encrypts the secret if encryption is available on the platform -// Returns true if the secret was written successfully -secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]); - -// Reads optiga pairing secret -// Decrypts the secret if encryption is available on the platform -// Returns true if the secret was read successfully -// Reading can fail if optiga is not paired, the pairing secret was not -// provisioned to the firmware (by calling secret_optiga_backup), or the secret -// was made unavailable by calling secret_optiga_hide -secbool secret_optiga_get(uint8_t dest[SECRET_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); -#endif - -#ifdef USE_TROPIC -// TROPIC KEYS -secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_KEY_LEN]); - -secbool secret_tropic_get_tropic_pubkey(uint8_t dest[SECRET_KEY_LEN]); - -secbool secret_tropic_set(const uint8_t privkey[SECRET_KEY_LEN], - const uint8_t pubkey[SECRET_KEY_LEN]); - -secbool secret_tropic_present(void); - -secbool secret_tropic_writable(void); - -#endif - -// Regenerates the BHK and writes it to the secret storage +/** + * @brief Regenerates the BHK and writes it to the secret storage. + */ void secret_bhk_regenerate(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 +/** + * @brief Prepares the secret storage for running the firmware. + * + * Provisions secrets and 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. + * + * @param allow_run_with_secret Allow firmware to run with secret access. + * @param allow_provisioning_access Allow provisioning access to secrets. + */ void secret_prepare_fw(secbool allow_run_with_secret, secbool allow_provisioning_access); -// Prepares the secret storage for running the boardloader and next stages -// Ensures that secret storage access is enabled -// This function is called by the boardloader +/** + * @brief Initializes the secret storage for running the boardloader and next + * stages. + * + * Ensures that secret storage access is enabled. + * This function is called by the boardloader. + */ void secret_init(void); #ifdef LOCKABLE_BOOTLOADER -// Unlocks the bootloader, all neccessary keys are erased + +/** + * @brief Unlocks the bootloader and erases all necessary keys. + */ void secret_unlock_bootloader(void); + +#ifdef TREZOR_EMULATOR + +/** + * @brief Locks the bootloader (emulator only). + */ +void secret_lock_bootloader(void); +#endif #endif #endif // SECURE_MODE #ifdef LOCKABLE_BOOTLOADER -// Checks if bootloader is locked, that is the secret storage contains optiga -// pairing secret on platforms where access to the secret storage cannot be -// restricted for unofficial firmware + +/** + * @brief Checks if the bootloader is locked. + * + * On platforms where secret storage access cannot be restricted for unofficial + * firmware, a locked bootloader indicates presence of a non-public key. + * + * @return secbool sectrue if bootloader is locked, secfalse otherwise. + */ secbool secret_bootloader_locked(void); #endif diff --git a/core/embed/sec/secret/inc/sec/secret_keys.h b/core/embed/sec/secret/inc/sec/secret_keys.h new file mode 100644 index 0000000000..6008840c7c --- /dev/null +++ b/core/embed/sec/secret/inc/sec/secret_keys.h @@ -0,0 +1,42 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#ifdef SECURE_MODE + +#ifdef USE_OPTIGA + +#define OPTIGA_PAIRING_SECRET_SIZE 32 +secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]); + +#endif + +#ifdef USE_TROPIC + +#include + +secbool secret_key_tropic_public(curve25519_key dest); + +secbool secret_key_tropic_pairing(curve25519_key dest); +#endif + +#endif diff --git a/core/embed/sec/secret/stm32f4/secret.c b/core/embed/sec/secret/stm32f4/secret.c index e661c8e178..e367c54af9 100644 --- a/core/embed/sec/secret/stm32f4/secret.c +++ b/core/embed/sec/secret/stm32f4/secret.c @@ -26,12 +26,23 @@ #ifdef KERNEL_MODE +#ifdef SECRET_NUM_KEY_SLOTS + +#define SECRET_HEADER_MAGIC "TRZS" +#define SECRET_HEADER_MAGIC_LEN (sizeof(SECRET_HEADER_MAGIC) - 1) + +#define SECRET_NUM_MAX_SLOTS 1 + +_Static_assert(SECRET_NUM_MAX_SLOTS >= SECRET_NUM_KEY_SLOTS, + "Exceeded max slots"); +_Static_assert(SECRET_KEY_SLOT_0_LEN == 32, "Invalid key slot length"); + static secbool bootloader_locked_set = secfalse; static secbool bootloader_locked = secfalse; secbool secret_verify_header(void) { - uint8_t* addr = (uint8_t*)flash_area_get_address(&SECRET_AREA, 0, - sizeof(SECRET_HEADER_MAGIC)); + uint8_t* addr = (uint8_t*)flash_area_get_address( + &SECRET_AREA, SECRET_HEADER_OFFSET, SECRET_HEADER_LEN); if (addr == NULL) { return secfalse; @@ -40,7 +51,7 @@ secbool secret_verify_header(void) { mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); bootloader_locked = - memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 + memcmp(addr, SECRET_HEADER_MAGIC, SECRET_HEADER_MAGIC_LEN) == 0 ? sectrue : secfalse; @@ -65,8 +76,8 @@ void secret_unlock_bootloader(void) { secret_erase(); } void secret_write_header(void) { uint8_t header[SECRET_HEADER_LEN] = {0}; - memcpy(header, SECRET_HEADER_MAGIC, 4); - secret_write(header, 0, SECRET_HEADER_LEN); + memcpy(header, SECRET_HEADER_MAGIC, SECRET_HEADER_MAGIC_LEN); + secret_write(header, SECRET_HEADER_OFFSET, SECRET_HEADER_LEN); } void secret_write(const uint8_t* data, uint32_t offset, uint32_t len) { @@ -98,7 +109,7 @@ secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) { return sectrue; } -secbool secret_wiped(void) { +static secbool secret_wiped(void) { uint32_t size = flash_area_get_size(&SECRET_AREA); secbool wiped = sectrue; @@ -127,22 +138,54 @@ void secret_erase(void) { mpu_restore(mpu_mode); } -secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) { +secbool secret_key_set(uint8_t slot, const uint8_t* key, size_t len) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + + if (len != SECRET_KEY_SLOT_0_LEN) { + return secfalse; + } + + uint32_t offset = SECRET_KEY_SLOT_0_OFFSET; + secret_erase(); secret_write_header(); - secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN); + secret_write(key, offset, len); return sectrue; } -secbool secret_optiga_get(uint8_t dest[SECRET_KEY_LEN]) { - return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN); +secbool secret_key_get(uint8_t slot, uint8_t* dest, size_t len) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + + if (len != SECRET_KEY_SLOT_0_LEN) { + return secfalse; + } + + uint32_t offset = SECRET_KEY_SLOT_0_OFFSET; + + return secret_read(dest, offset, len); } -secbool secret_optiga_present(void) { +static secbool secret_key_present(uint8_t slot) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + return (sectrue != secret_wiped()) * sectrue; } -secbool secret_optiga_writable(void) { return secret_wiped(); } +secbool secret_key_writable(uint8_t slot) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + + return secret_wiped(); +} + +#endif void secret_prepare_fw(secbool allow_run_with_secret, secbool allow_provisioning_access) { diff --git a/core/embed/sec/secret/stm32f4/secret_keys.c b/core/embed/sec/secret/stm32f4/secret_keys.c new file mode 100644 index 0000000000..5d3af1e93c --- /dev/null +++ b/core/embed/sec/secret/stm32f4/secret_keys.c @@ -0,0 +1,35 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef SECURE_MODE + +#include +#include +#include + +#include +#include + +#ifdef USE_OPTIGA +secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) { + return secret_key_get(SECRET_OPTIGA_SLOT, dest, OPTIGA_PAIRING_SECRET_SIZE); +} +#endif + +#endif diff --git a/core/embed/sec/secret/stm32u5/secret.c b/core/embed/sec/secret/stm32u5/secret.c index cd92614624..71bca8f30d 100644 --- a/core/embed/sec/secret/stm32u5/secret.c +++ b/core/embed/sec/secret/stm32u5/secret.c @@ -32,14 +32,75 @@ #ifdef SECURE_MODE -#define REG_BHK_OFFSET 0 -#define REG_OPTIGA_KEY_OFFSET 8 -#define REG_TROPIC_TRZ_PRIVKEY_OFFSET 16 -#define REG_TROPIC_TRO_PUBKEY_OFFSET 24 +#define SECRET_HEADER_MAGIC "TRZS" +#define SECRET_HEADER_MAGIC_LEN (sizeof(SECRET_HEADER_MAGIC) - 1) -secbool secret_verify_header(void) { +#define SECRET_BHK_REG_OFFSET 0 + +#define SECRET_NUM_MAX_SLOTS 3 + +#ifndef SECRET_KEY_SLOT_0_OFFSET +#define SECRET_KEY_SLOT_0_OFFSET 0 +#define SECRET_KEY_SLOT_0_LEN 0 +#endif + +#ifndef SECRET_KEY_SLOT_1_OFFSET +#define SECRET_KEY_SLOT_1_OFFSET 0 +#define SECRET_KEY_SLOT_1_LEN 0 +#endif + +#ifndef SECRET_KEY_SLOT_2_OFFSET +#define SECRET_KEY_SLOT_2_OFFSET 0 +#define SECRET_KEY_SLOT_2_LEN 0 +#endif + +#define SECRET_KEY_MAX_LEN (24 * sizeof(uint32_t)) + +_Static_assert(SECRET_NUM_MAX_SLOTS >= SECRET_NUM_KEY_SLOTS); +_Static_assert(SECRET_KEY_SLOT_0_LEN + SECRET_KEY_SLOT_1_LEN + + SECRET_KEY_SLOT_2_LEN <= + SECRET_KEY_MAX_LEN, + "secret key slots too large"); +_Static_assert(SECRET_KEY_SLOT_0_LEN % 16 == 0, + "secret key length must be multiple of 16 bytes"); +_Static_assert(SECRET_KEY_SLOT_1_LEN % 16 == 0, + "secret key length must be multiple of 16 bytes"); +_Static_assert(SECRET_KEY_SLOT_2_LEN % 16 == 0, + "secret key length must be multiple of 16 bytes"); + +static uint32_t secret_slot_offsets[SECRET_NUM_MAX_SLOTS] = { + SECRET_KEY_SLOT_0_OFFSET, + SECRET_KEY_SLOT_1_OFFSET, + SECRET_KEY_SLOT_2_OFFSET, +}; + +static uint32_t secret_slot_lengths[SECRET_NUM_MAX_SLOTS] = { + SECRET_KEY_SLOT_0_LEN, + SECRET_KEY_SLOT_1_LEN, + SECRET_KEY_SLOT_2_LEN, +}; + +static secbool secret_slot_public[SECRET_NUM_MAX_SLOTS] = { +#ifdef SECRET_KEY_SLOT_0_PUBLIC + sectrue, +#else + secfalse, +#endif +#ifdef SECRET_KEY_SLOT_1_PUBLIC + sectrue, +#else + secfalse, +#endif +#ifdef SECRET_KEY_SLOT_2_PUBLIC + sectrue, +#else + secfalse, +#endif +}; + +static secbool secret_verify_header(void) { uint8_t *addr = (uint8_t *)flash_area_get_address( - &SECRET_AREA, 0, sizeof(SECRET_HEADER_MAGIC)); + &SECRET_AREA, SECRET_HEADER_OFFSET, SECRET_HEADER_LEN); if (addr == NULL) { return secfalse; @@ -48,7 +109,7 @@ secbool secret_verify_header(void) { mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); secbool header_present = - memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 + memcmp(addr, SECRET_HEADER_MAGIC, SECRET_HEADER_MAGIC_LEN) == 0 ? sectrue : secfalse; @@ -57,6 +118,18 @@ secbool secret_verify_header(void) { return header_present; } +static void secret_erase(void) { + mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); + ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); + mpu_restore(mpu_mode); +} + +static void secret_write_header(void) { + uint8_t header[SECRET_HEADER_LEN] = {0}; + memcpy(header, SECRET_HEADER_MAGIC, SECRET_HEADER_MAGIC_LEN); + secret_write(header, SECRET_HEADER_OFFSET, SECRET_HEADER_LEN); +} + static secbool secret_ensure_initialized(void) { if (sectrue != secret_verify_header()) { ensure(erase_storage(NULL), "erase storage failed"); @@ -67,12 +140,6 @@ static secbool secret_ensure_initialized(void) { return sectrue; } -void secret_write_header(void) { - uint8_t header[SECRET_HEADER_LEN] = {0}; - memcpy(header, SECRET_HEADER_MAGIC, 4); - secret_write(header, 0, SECRET_HEADER_LEN); -} - void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) { mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); ensure(flash_unlock_write(), "secret write"); @@ -119,9 +186,41 @@ static secbool secret_bhk_locked(void) { sectrue; } -static secbool secret_key_present(uint32_t offset) { +static secbool secret_is_slot_valid(uint8_t slot) { + return ((slot < SECRET_NUM_KEY_SLOTS) && (secret_slot_offsets[slot] != 0)) * + sectrue; +} + +static uint32_t secret_get_slot_offset(uint8_t slot) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return 0; + } + return secret_slot_offsets[slot]; +} + +static uint32_t secret_get_slot_len(uint8_t slot) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return 0; + } + return secret_slot_lengths[slot]; +} + +static size_t secret_get_reg_offset(uint8_t slot) { + // SECRET_BHK_LEN is in bytes; each reg is 32 bits = 4 bytes + size_t cumulative = SECRET_BHK_LEN / sizeof(uint32_t); + + for (uint8_t i = 0; i < slot; i++) { + if (sectrue == secret_is_slot_valid(i)) { + cumulative += (secret_slot_lengths[i] / sizeof(uint32_t)); + } + } + + return cumulative; +} + +static secbool secret_record_present(uint32_t offset, uint32_t len) { uint8_t *secret = - (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, SECRET_KEY_LEN); + (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len); if (secret == NULL) { return secfalse; @@ -131,7 +230,7 @@ static secbool secret_key_present(uint32_t offset) { int secret_empty_bytes = 0; - for (int i = 0; i < SECRET_KEY_LEN; i++) { + 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[i] == 0x00) { @@ -141,12 +240,30 @@ static secbool secret_key_present(uint32_t offset) { mpu_restore(mpu_mode); - return sectrue * (secret_empty_bytes != SECRET_KEY_LEN); + return sectrue * (secret_empty_bytes != len); } -__attribute__((unused)) static secbool secret_key_writable(uint32_t offset) { +static secbool secret_key_present(uint8_t slot) { + if (sectrue != secret_is_slot_valid(slot)) { + return secfalse; + } + + uint32_t offset = secret_get_slot_offset(slot); + uint32_t len = secret_get_slot_len(slot); + + return secret_record_present(offset, len); +} + +secbool secret_key_writable(uint8_t slot) { + if (sectrue != secret_is_slot_valid(slot)) { + return secfalse; + } + + uint32_t offset = secret_get_slot_offset(slot); + uint32_t len = secret_get_slot_len(slot); + const uint8_t *const secret = - (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, SECRET_KEY_LEN); + (uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len); if (secret == NULL) { return secfalse; @@ -156,7 +273,7 @@ __attribute__((unused)) static secbool secret_key_writable(uint32_t offset) { int secret_empty_bytes = 0; - for (int i = 0; i < SECRET_KEY_LEN; i++) { + 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) { @@ -166,24 +283,27 @@ __attribute__((unused)) static secbool secret_key_writable(uint32_t offset) { mpu_restore(mpu_mode); - return sectrue * (secret_empty_bytes == SECRET_KEY_LEN); + return sectrue * (secret_empty_bytes == len); } -__attribute__((unused)) static void secret_key_cache(uint8_t reg_offset, - uint32_t key_offset) { - uint32_t secret[SECRET_KEY_LEN / sizeof(uint32_t)] = {0}; +static void secret_key_cache(uint8_t slot) { + uint32_t offset = secret_get_slot_offset(slot); + uint32_t len = secret_get_slot_len(slot); + size_t reg_offset = secret_get_reg_offset(slot); - secbool ok = secret_read((uint8_t *)secret, key_offset, SECRET_KEY_LEN); + uint32_t secret[SECRET_KEY_MAX_LEN] = {0}; + + secbool ok = secret_read((uint8_t *)secret, offset, len); volatile uint32_t *reg = &TAMP->BKP0R; reg += reg_offset; if (sectrue == ok) { - for (int i = 0; i < (SECRET_KEY_LEN / sizeof(uint32_t)); i++) { - *reg = ((uint32_t *)secret)[i]; + for (int i = 0; i < (len / sizeof(uint32_t)); i++) { + *reg = secret[i]; reg++; } } else { - for (int i = 0; i < (SECRET_KEY_LEN / sizeof(uint32_t)); i++) { + for (int i = 0; i < (len / sizeof(uint32_t)); i++) { *reg = 0; reg++; } @@ -191,28 +311,46 @@ __attribute__((unused)) static void secret_key_cache(uint8_t reg_offset, memzero(secret, sizeof(secret)); } -__attribute__((unused)) static secbool secret_key_set( - const uint8_t secret[SECRET_KEY_LEN], uint8_t reg_offset, - uint32_t key_offset) { - uint8_t secret_enc[SECRET_KEY_LEN] = {0}; - if (sectrue != secure_aes_ecb_encrypt_hw(secret, sizeof(secret_enc), - secret_enc, - SECURE_AES_KEY_DHUK_SP)) { +secbool secret_key_set(uint8_t slot, const uint8_t *key, size_t len) { + if (sectrue != secret_is_slot_valid(slot)) { return secfalse; } - secret_write(secret_enc, key_offset, SECRET_KEY_LEN); + + uint32_t offset = secret_get_slot_offset(slot); + uint32_t slot_len = secret_get_slot_len(slot); + + if (slot_len != len) { + return secfalse; + } + + uint8_t secret_enc[SECRET_KEY_MAX_LEN] = {0}; + if (sectrue != + secure_aes_ecb_encrypt_hw(key, len, secret_enc, SECURE_AES_KEY_DHUK_SP)) { + return secfalse; + } + secret_write(secret_enc, offset, len); memzero(secret_enc, sizeof(secret_enc)); - secret_key_cache(reg_offset, key_offset); + secret_key_cache(slot); return sectrue; } -__attribute__((unused)) static secbool secret_key_get( - uint8_t dest[SECRET_KEY_LEN], uint8_t reg_offset) { - uint32_t secret[SECRET_KEY_LEN / sizeof(uint32_t)] = {0}; +secbool secret_key_get(uint8_t slot, uint8_t *dest, size_t len) { + if (sectrue != secret_is_slot_valid(slot)) { + return secfalse; + } + + uint32_t slot_len = secret_get_slot_len(slot); + size_t reg_offset = secret_get_reg_offset(slot); + + if (slot_len != len) { + return secfalse; + } + + uint32_t secret[SECRET_KEY_MAX_LEN] = {0}; bool all_zero = true; volatile uint32_t *reg = &TAMP->BKP0R; - for (int i = 0; i < (SECRET_KEY_LEN / sizeof(uint32_t)); i++) { + for (int i = 0; i < (len / sizeof(uint32_t)); i++) { secret[i] = reg[i + reg_offset]; if (secret[i] != 0) { @@ -224,21 +362,33 @@ __attribute__((unused)) static secbool secret_key_get( return secfalse; } - secbool res = secure_aes_ecb_decrypt_hw((uint8_t *)secret, SECRET_KEY_LEN, - dest, SECURE_AES_KEY_DHUK_SP); + secbool res = secure_aes_ecb_decrypt_hw((uint8_t *)secret, len, dest, + SECURE_AES_KEY_DHUK_SP); memzero(secret, sizeof(secret)); return res; } // Deletes the secret from the register -__attribute__((unused)) static void secret_key_uncache(uint8_t reg_offset) { +__attribute__((unused)) static void secret_key_uncache(uint8_t slot) { + size_t reg_offset = secret_get_reg_offset(slot); + uint32_t slot_len = secret_get_slot_len(slot); + volatile uint32_t *reg = &TAMP->BKP0R; - for (int i = 0; i < 8; i++) { + for (int i = 0; i < slot_len / sizeof(uint32_t); i++) { reg[i + reg_offset] = 0; } } +static void secret_key_erase(uint8_t slot) { + uint8_t value[SECRET_KEY_MAX_LEN] = {0}; + + uint32_t offset = secret_get_slot_offset(slot); + uint32_t slot_len = secret_get_slot_len(slot); + + secret_write(value, offset, slot_len); +} + // 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. @@ -247,23 +397,23 @@ static void secret_bhk_load(void) { reboot_device(); } - uint32_t secret[SECRET_KEY_LEN / sizeof(uint32_t)] = {0}; + uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0}; - if (sectrue != secret_key_present(SECRET_BHK_OFFSET)) { + if (sectrue != secret_record_present(SECRET_BHK_OFFSET, SECRET_BHK_LEN)) { secret_bhk_regenerate(); } secbool ok = - secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_KEY_LEN); + secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_BHK_LEN); volatile uint32_t *reg1 = &TAMP->BKP0R; if (sectrue == ok) { - for (int i = 0; i < (SECRET_KEY_LEN / sizeof(uint32_t)); i++) { + for (int i = 0; i < (SECRET_BHK_LEN / sizeof(uint32_t)); i++) { *reg1 = ((uint32_t *)secret)[i]; reg1++; } } else { - for (int i = 0; i < (SECRET_KEY_LEN / sizeof(uint32_t)); i++) { + for (int i = 0; i < (SECRET_BHK_LEN / sizeof(uint32_t)); i++) { *reg1 = 0; reg1++; } @@ -293,199 +443,88 @@ void secret_bhk_regenerate(void) { ensure(flash_lock_write(), "Failed regenerating BHK"); } -#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. -secbool secret_optiga_present(void) { - return secret_key_present(SECRET_OPTIGA_KEY_OFFSET); -} - -secbool secret_optiga_writable(void) { - return secret_key_writable(SECRET_OPTIGA_KEY_OFFSET); -} - -secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) { - return secret_key_set(secret, REG_OPTIGA_KEY_OFFSET, - SECRET_OPTIGA_KEY_OFFSET); -} - -secbool secret_optiga_get(uint8_t dest[SECRET_KEY_LEN]) { - return secret_key_get(dest, REG_OPTIGA_KEY_OFFSET); -} - -// Backs up the optiga pairing secret from the secret storage to the backup -// register -static void secret_optiga_cache(void) { - if (sectrue == secret_optiga_present()) { - secret_key_cache(REG_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_OFFSET); +static void secret_keys_uncache(void) { + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i)) { + secret_key_uncache(i); + } } } -// Deletes the optiga pairing secret from the register -static void secret_optiga_uncache(void) { secret_key_uncache(8); } - -static void secret_optiga_erase(void) { - uint8_t value[SECRET_KEY_LEN] = {0}; - secret_write(value, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN); -} - -#endif - -#ifdef USE_TROPIC -secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_KEY_LEN]) { - return secret_key_get(dest, REG_TROPIC_TRZ_PRIVKEY_OFFSET); -} - -secbool secret_tropic_get_tropic_pubkey(uint8_t dest[SECRET_KEY_LEN]) { - return secret_key_get(dest, REG_TROPIC_TRO_PUBKEY_OFFSET); -} - -secbool secret_tropic_set(const uint8_t privkey[SECRET_KEY_LEN], - const uint8_t pubkey[SECRET_KEY_LEN]) { - secbool res1 = secret_key_set(privkey, REG_TROPIC_TRZ_PRIVKEY_OFFSET, - SECRET_TROPIC_TRZ_PRIVKEY_OFFSET); - - if (sectrue != res1) { - return secfalse; - } - - secbool res2 = secret_key_set(pubkey, REG_TROPIC_TRO_PUBKEY_OFFSET, - SECRET_TROPIC_TRO_PUBKEY_OFFSET); - - return res2; -} - -secbool secret_tropic_present(void) { - secbool res1 = secret_key_present(SECRET_TROPIC_TRZ_PRIVKEY_OFFSET); - - secbool res2 = secret_key_present(SECRET_TROPIC_TRO_PUBKEY_OFFSET); - - return secbool_and(res1, res2); -} - -secbool secret_tropic_present_any(void) { - secbool res1 = secret_key_present(SECRET_TROPIC_TRZ_PRIVKEY_OFFSET); - - secbool res2 = secret_key_present(SECRET_TROPIC_TRO_PUBKEY_OFFSET); - - return secbool_or(res1, res2); -} - -secbool secret_tropic_writable(void) { - secbool res1 = secret_key_writable(SECRET_TROPIC_TRZ_PRIVKEY_OFFSET); - - secbool res2 = secret_key_writable(SECRET_TROPIC_TRO_PUBKEY_OFFSET); - - return secbool_or(res1, res2); -} - -static void secret_tropic_erase(void) { - uint8_t value[SECRET_KEY_LEN] = {0}; - secret_write(value, SECRET_TROPIC_TRZ_PRIVKEY_OFFSET, SECRET_KEY_LEN); - secret_write(value, SECRET_TROPIC_TRO_PUBKEY_OFFSET, SECRET_KEY_LEN); -} - -// Backs up the tropic pairing secret from the secret storage to the backup -// register -static void secret_tropic_cache(void) { - if (sectrue == secret_tropic_present()) { - secret_key_cache(REG_TROPIC_TRZ_PRIVKEY_OFFSET, - SECRET_TROPIC_TRZ_PRIVKEY_OFFSET); - secret_key_cache(REG_TROPIC_TRO_PUBKEY_OFFSET, - SECRET_TROPIC_TRO_PUBKEY_OFFSET); +static void secret_keys_cache(void) { + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i) && + sectrue == secret_key_present(i)) { + secret_key_cache(i); + } } } -// Deletes the tropic pairing secret from the register -static void secret_tropic_uncache(void) { - secret_key_uncache(REG_TROPIC_TRZ_PRIVKEY_OFFSET); - secret_key_uncache(REG_TROPIC_TRO_PUBKEY_OFFSET); +static void secret_keys_cache_public(void) { + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if ((sectrue == secret_is_slot_valid(i)) && + (sectrue == secret_key_present(i)) && + (sectrue == secret_slot_public[i])) { + secret_key_cache(i); + } + } } -#endif +// return sectrue if all the key slots are valid and contain a key +static secbool secret_keys_present(void) { + secbool result = sectrue; -void secret_erase(void) { - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); - mpu_restore(mpu_mode); + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i)) { + result = secbool_and(result, secret_key_present(i)); + } + } + + return result; } -static void secret_se_uncache(void) { -#ifdef USE_OPTIGA - secret_optiga_uncache(); -#endif -#ifdef USE_TROPIC - secret_tropic_uncache(); -#endif +#if defined BOOTLOADER || defined BOARDLOADER +// return sectrue if any non-public key slot is valid and contains a key +static secbool secret_keys_present_any(void) { + secbool result = secfalse; + + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i) && + sectrue != secret_slot_public[i]) { + result = secbool_or(result, secret_key_present(i)); + } + } + + return result; } - -static void secret_se_cache(void) { -#ifdef USE_OPTIGA - secret_optiga_cache(); -#endif -#ifdef USE_TROPIC - secret_tropic_cache(); -#endif -} - -static secbool secret_se_present(void) { -#ifdef USE_OPTIGA - secbool res1 = secret_optiga_present(); -#else - secbool res1 = sectrue; #endif -#ifdef USE_TROPIC - secbool res2 = secret_tropic_present(); -#else - secbool res2 = sectrue; -#endif +// return sectrue if at least one key slot is writable +static secbool secret_keys_writable(void) { + secbool result = secfalse; - return secbool_and(res1, res2); -} + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i)) { + result = secbool_or(result, secret_key_writable(i)); + } + } -__attribute__((unused)) static secbool secret_se_present_any(void) { -#ifdef USE_OPTIGA - secbool res1 = secret_optiga_present(); -#else - secbool res1 = secfalse; -#endif - -#ifdef USE_TROPIC - secbool res2 = secret_tropic_present_any(); -#else - secbool res2 = secfalse; -#endif - - return secbool_or(res1, res2); -} - -static secbool secret_se_writable(void) { -#ifdef USE_OPTIGA - secbool res1 = secret_optiga_writable(); -#else - secbool res1 = secfalse; -#endif - -#ifdef USE_TROPIC - secbool res2 = secret_tropic_writable(); -#else - secbool res2 = secfalse; -#endif - - return secbool_or(res1, res2); + return result; } #ifdef LOCKABLE_BOOTLOADER secbool secret_bootloader_locked(void) { #if defined BOOTLOADER || defined BOARDLOADER - return secret_se_present_any(); + return secret_keys_present_any(); #else - const volatile uint32_t *reg1 = &TAMP->BKP8R; - for (int i = 0; i < 24; i++) { - if (reg1[i] != 0) { + // in firmware, we determine bootloader state by checking if bootloader + // has provided any non-public key + for (int i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + uint32_t val[SECRET_KEY_MAX_LEN] = {0}; + size_t len = secret_get_slot_len(i); + if (secfalse == secret_slot_public[i] && + sectrue == secret_key_get(i, (uint8_t *)val, len)) { + memzero(val, sizeof(val)); return sectrue; } } @@ -494,12 +533,12 @@ secbool secret_bootloader_locked(void) { } void secret_unlock_bootloader(void) { -#ifdef USE_OPTIGA - secret_optiga_erase(); -#endif -#ifdef USE_TROPIC - secret_tropic_erase(); -#endif + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + if (sectrue == secret_is_slot_valid(i) && + sectrue != secret_slot_public[i]) { + secret_key_erase(i); + } + } } #endif @@ -519,29 +558,35 @@ void secret_prepare_fw(secbool allow_run_with_secret, * all-cases. */ - secret_bhk_load(); - secret_bhk_lock(); - secret_se_uncache(); - secbool se_secret_present = secret_se_present(); - secbool se_secret_writable = secret_se_writable(); - if (sectrue == allow_provisioning_access && sectrue == se_secret_writable && - secfalse == se_secret_present) { - // SE 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 == se_secret_present) { - // Firmware is trusted, and the SE secret is present, make it available. - secret_se_cache(); - } - // Disable access unconditionally. - secret_disable_access(); - if (sectrue != allow_run_with_secret && sectrue == se_secret_present) { + if (sectrue != allow_run_with_secret && + secfalse != secret_bootloader_locked()) { // Untrusted firmware, locked bootloader. Show the restricted screen. show_install_restricted_screen(); } + + secret_bhk_load(); + secret_bhk_lock(); + secret_keys_uncache(); + secbool secret_present = secret_keys_present(); + secbool secret_writable = secret_keys_writable(); + if (sectrue == allow_provisioning_access && sectrue == secret_writable && + secfalse == secret_present) { + // Secret keys are not present and they are writable. + // This means the U5 chip is unprovisioned. + // Allow trusted firmware (prodtest presumably) to access the secret sector, + // early return here. + secret_keys_cache(); + return; + } + if (sectrue == allow_run_with_secret && sectrue == secret_present) { + // Firmware is trusted, and the secret keys are present, make it available. + secret_keys_cache(); + } else { + // Make only public keys available. + secret_keys_cache_public(); + } + // Disable access unconditionally. + secret_disable_access(); } void secret_init(void) { diff --git a/core/embed/sec/secret/stm32u5/secret_keys.c b/core/embed/sec/secret/stm32u5/secret_keys.c new file mode 100644 index 0000000000..8bd6ce39be --- /dev/null +++ b/core/embed/sec/secret/stm32u5/secret_keys.c @@ -0,0 +1,47 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef SECURE_MODE + +#include +#include +#include + +#include +#include + +#ifdef USE_OPTIGA +secbool secret_key_optiga_pairing(uint8_t dest[OPTIGA_PAIRING_SECRET_SIZE]) { + return secret_key_get(SECRET_OPTIGA_SLOT, dest, OPTIGA_PAIRING_SECRET_SIZE); +} +#endif + +#ifdef USE_TROPIC +secbool secret_key_tropic_public(curve25519_key dest) { + return secret_key_get(SECRET_TROPIC_TROPIC_PUBKEY_SLOT, dest, + sizeof(curve25519_key)); +} + +secbool secret_key_tropic_pairing(curve25519_key dest) { + return secret_key_get(SECRET_TROPIC_TREZOR_PRIVKEY_SLOT, dest, + sizeof(curve25519_key)); +} +#endif + +#endif diff --git a/core/embed/sec/secret/unix/secret.c b/core/embed/sec/secret/unix/secret.c index 8a94baf879..1df7135c49 100644 --- a/core/embed/sec/secret/unix/secret.c +++ b/core/embed/sec/secret/unix/secret.c @@ -17,158 +17,156 @@ * along with this program. If not, see . */ +#include + #include #include #include -#include -#include #ifdef KERNEL_MODE -static uint8_t SECRET_TROPIC_TREZOR_PRIVKEY_BYTES[] = { - 0xf0, 0xc4, 0xaa, 0x04, 0x8f, 0x00, 0x13, 0xa0, 0x96, 0x84, 0xdf, - 0x05, 0xe8, 0xa2, 0x2e, 0xf7, 0x21, 0x38, 0x98, 0x28, 0x2b, 0xa9, - 0x43, 0x12, 0xf3, 0x13, 0xdf, 0x2d, 0xce, 0x8d, 0x41, 0x64}; - -static uint8_t SECRET_TROPIC_PUBKEY_BYTES[] = { - 0x31, 0xE9, 0x0A, 0xF1, 0x50, 0x45, 0x10, 0xEE, 0x4E, 0xFD, 0x79, - 0x13, 0x33, 0x41, 0x48, 0x15, 0x89, 0xA2, 0x89, 0x5C, 0xC5, 0xFB, - 0xB1, 0x3E, 0xD5, 0x71, 0x1C, 0x1E, 0x9B, 0x81, 0x98, 0x72}; - -static secbool bootloader_locked_set = secfalse; -static secbool bootloader_locked = secfalse; - -secbool secret_verify_header(void) { - uint8_t* addr = (uint8_t*)flash_area_get_address(&SECRET_AREA, 0, - sizeof(SECRET_HEADER_MAGIC)); - - if (addr == NULL) { - return secfalse; - } - - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - - bootloader_locked = - memcmp(addr, SECRET_HEADER_MAGIC, sizeof(SECRET_HEADER_MAGIC)) == 0 - ? sectrue - : secfalse; - - mpu_restore(mpu_mode); - - bootloader_locked_set = sectrue; - return bootloader_locked; -} - #ifdef LOCKABLE_BOOTLOADER -secbool secret_bootloader_locked(void) { - if (bootloader_locked_set != sectrue) { - // Set bootloader_locked. - secret_verify_header(); - } - - return bootloader_locked; -} - -void secret_unlock_bootloader(void) { secret_erase(); } +static secbool bootloader_locked = secfalse; #endif -void secret_write_header(void) { - uint8_t header[SECRET_HEADER_LEN] = {0}; - memcpy(header, SECRET_HEADER_MAGIC, 4); - secret_write(header, 0, SECRET_HEADER_LEN); -} +#ifndef SECRET_NUM_KEY_SLOTS +#define SECRET_NUM_KEY_SLOTS 0 +#endif -void secret_write(const uint8_t* data, uint32_t offset, uint32_t len) { - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - ensure(flash_unlock_write(), "secret write"); - for (int i = 0; i < len; i++) { - ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]), - "secret write"); - } - ensure(flash_lock_write(), "secret write"); - mpu_restore(mpu_mode); -} +#ifdef SECRET_KEY_SLOT_0_LEN +static uint8_t secret_key_slot0[SECRET_KEY_SLOT_0_LEN] = {0}; +#endif +#ifdef SECRET_KEY_SLOT_1_LEN +static uint8_t secret_key_slot1[SECRET_KEY_SLOT_1_LEN] = {0}; +#endif +#ifdef SECRET_KEY_SLOT_2_LEN +static uint8_t secret_key_slot2[SECRET_KEY_SLOT_2_LEN] = {0}; +#endif -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); - - if (addr == NULL) { - return secfalse; - } - - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - memcpy(data, addr, len); - mpu_restore(mpu_mode); - - return sectrue; -} - -secbool secret_wiped(void) { - uint32_t size = flash_area_get_size(&SECRET_AREA); - secbool wiped = sectrue; - - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - - for (int i = 0; i < size; i += 4) { - uint32_t* addr = (uint32_t*)flash_area_get_address(&SECRET_AREA, i, 4); - if (addr == NULL) { - wiped = secfalse; +size_t secret_get_slot_len(uint8_t slot) { + switch (slot) { +#ifdef SECRET_KEY_SLOT_0_LEN + case 0: + return SECRET_KEY_SLOT_0_LEN; +#endif +#ifdef SECRET_KEY_SLOT_1_LEN + case 1: + return SECRET_KEY_SLOT_1_LEN; +#endif +#ifdef SECRET_KEY_SLOT_2_LEN + case 2: + return SECRET_KEY_SLOT_2_LEN; +#endif + default: break; - } - if (*addr != 0xFFFFFFFF) { - wiped = secfalse; - break; - } } + return 0; +} - mpu_restore(mpu_mode); - - return wiped; +uint8_t* secret_get_slot_ptr(uint8_t slot) { + switch (slot) { +#ifdef SECRET_KEY_SLOT_0_LEN + case 0: + return secret_key_slot0; +#endif +#ifdef SECRET_KEY_SLOT_1_LEN + case 1: + return secret_key_slot1; +#endif +#ifdef SECRET_KEY_SLOT_2_LEN + case 2: + return secret_key_slot2; +#endif + default: + break; + } + return NULL; } void secret_erase(void) { - mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET); - ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); - mpu_restore(mpu_mode); + for (uint8_t i = 0; i < SECRET_NUM_KEY_SLOTS; i++) { + uint8_t* slot_ptr = secret_get_slot_ptr(i); + if (slot_ptr != NULL) { + memzero(slot_ptr, secret_get_slot_len(i)); + } + } } -secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) { +#ifdef LOCKABLE_BOOTLOADER +secbool secret_bootloader_locked(void) { return bootloader_locked; } + +void secret_unlock_bootloader(void) { secret_erase(); - secret_write_header(); - secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN); + bootloader_locked = secfalse; +} + +void secret_lock_bootloader(void) { bootloader_locked = sectrue; } +#endif + +secbool secret_key_set(uint8_t slot, const uint8_t* key, size_t len) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + + if (len != secret_get_slot_len(slot)) { + return secfalse; + } + + uint8_t* slot_ptr = secret_get_slot_ptr(slot); + if (slot_ptr == NULL) { + return secfalse; + } + + memcpy(slot_ptr, key, len); return sectrue; } -secbool secret_optiga_get(uint8_t dest[SECRET_KEY_LEN]) { - return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN); -} +secbool secret_key_get(uint8_t slot, uint8_t* dest, size_t len) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } -secbool secret_optiga_present(void) { - return (sectrue != secret_wiped()) * sectrue; -} + if (len != secret_get_slot_len(slot)) { + return secfalse; + } -secbool secret_optiga_writable(void) { return secret_wiped(); } + uint8_t* slot_ptr = secret_get_slot_ptr(slot); + if (slot_ptr == NULL) { + return secfalse; + } -secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_KEY_LEN]) { - memcpy(dest, &SECRET_TROPIC_TREZOR_PRIVKEY_BYTES, SECRET_KEY_LEN); + memcpy(dest, slot_ptr, len); return sectrue; } -secbool secret_tropic_get_tropic_pubkey(uint8_t dest[SECRET_KEY_LEN]) { - memcpy(dest, &SECRET_TROPIC_PUBKEY_BYTES, SECRET_KEY_LEN); - return sectrue; +static secbool secret_key_present(uint8_t slot) { + if (slot >= SECRET_NUM_KEY_SLOTS) { + return secfalse; + } + + uint8_t* slot_ptr = secret_get_slot_ptr(slot); + if (slot_ptr == NULL) { + return secfalse; + } + + for (size_t i = 0; i < secret_get_slot_len(slot); i++) { + if (slot_ptr[i] != 0) { + return sectrue; + } + } + return secfalse; +} + +secbool secret_key_writable(uint8_t slot) { + return secret_key_present(slot) == secfalse; } void secret_prepare_fw(secbool allow_run_with_secret, secbool allow_provisioning_access) { (void)allow_provisioning_access; #ifdef LOCKABLE_BOOTLOADER - if (sectrue != allow_run_with_secret && sectrue != secret_wiped()) { + if (sectrue != allow_run_with_secret && sectrue != bootloader_locked) { // This function does not return show_install_restricted_screen(); } diff --git a/core/embed/sec/secret/unix/secret_keys.c b/core/embed/sec/secret/unix/secret_keys.c new file mode 100644 index 0000000000..c489bff1de --- /dev/null +++ b/core/embed/sec/secret/unix/secret_keys.c @@ -0,0 +1,58 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef SECURE_MODE + +#include +#include +#include + +#include +#include + +#ifdef USE_TROPIC + +static uint8_t SECRET_TROPIC_PAIRING_BYTES[] = { + 0xf0, 0xc4, 0xaa, 0x04, 0x8f, 0x00, 0x13, 0xa0, 0x96, 0x84, 0xdf, + 0x05, 0xe8, 0xa2, 0x2e, 0xf7, 0x21, 0x38, 0x98, 0x28, 0x2b, 0xa9, + 0x43, 0x12, 0xf3, 0x13, 0xdf, 0x2d, 0xce, 0x8d, 0x41, 0x64}; + +static uint8_t SECRET_TROPIC_PUBKEY_BYTES[] = { + 0x31, 0xE9, 0x0A, 0xF1, 0x50, 0x45, 0x10, 0xEE, 0x4E, 0xFD, 0x79, + 0x13, 0x33, 0x41, 0x48, 0x15, 0x89, 0xA2, 0x89, 0x5C, 0xC5, 0xFB, + 0xB1, 0x3E, 0xD5, 0x71, 0x1C, 0x1E, 0x9B, 0x81, 0x98, 0x72}; + +_Static_assert(sizeof(SECRET_TROPIC_PAIRING_BYTES) == sizeof(curve25519_key), + "Invalid size of Tropic pairing key"); + +_Static_assert(sizeof(SECRET_TROPIC_PUBKEY_BYTES) == sizeof(curve25519_key), + "Invalid size of Tropic public key"); + +secbool secret_key_tropic_public(curve25519_key dest) { + memcpy(dest, SECRET_TROPIC_PUBKEY_BYTES, sizeof(curve25519_key)); + return sectrue; +} + +secbool secret_key_tropic_pairing(curve25519_key dest) { + memcpy(dest, SECRET_TROPIC_PAIRING_BYTES, sizeof(curve25519_key)); + return sectrue; +} +#endif + +#endif diff --git a/core/embed/sec/tropic/tropic.c b/core/embed/sec/tropic/tropic.c index d0f7575804..8d0c76331d 100644 --- a/core/embed/sec/tropic/tropic.c +++ b/core/embed/sec/tropic/tropic.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include @@ -48,8 +48,8 @@ bool tropic_init(void) { return true; } - uint8_t tropic_secret_tropic_pubkey[SECRET_KEY_LEN] = {0}; - uint8_t tropic_secret_trezor_privkey[SECRET_KEY_LEN] = {0}; + curve25519_key tropic_secret_tropic_pubkey = {0}; + curve25519_key tropic_secret_trezor_privkey = {0}; if (!tropic_hal_init()) { goto cleanup; @@ -60,13 +60,11 @@ bool tropic_init(void) { goto cleanup; } - secbool pubkey_ok = - secret_tropic_get_tropic_pubkey(tropic_secret_tropic_pubkey); - secbool privkey_ok = - secret_tropic_get_trezor_privkey(tropic_secret_trezor_privkey); + secbool pubkey_ok = secret_key_tropic_public(tropic_secret_tropic_pubkey); + secbool privkey_ok = secret_key_tropic_pairing(tropic_secret_trezor_privkey); if (pubkey_ok == sectrue && privkey_ok == sectrue) { - uint8_t trezor_pubkey[SECRET_KEY_LEN] = {0}; + uint8_t trezor_pubkey[32] = {0}; curve25519_scalarmult_basepoint(trezor_pubkey, tropic_secret_trezor_privkey); diff --git a/core/site_scons/models/stm32f4_common.py b/core/site_scons/models/stm32f4_common.py index 8b79b2af02..fc46c2b8eb 100644 --- a/core/site_scons/models/stm32f4_common.py +++ b/core/site_scons/models/stm32f4_common.py @@ -69,6 +69,7 @@ def stm32f4_common_files(env, defines, sources, paths): "embed/sec/random_delays/stm32/random_delays.c", "embed/sec/rng/stm32/rng.c", "embed/sec/secret/stm32f4/secret.c", + "embed/sec/secret/stm32f4/secret_keys.c", "embed/sec/time_estimate/stm32/time_estimate.c", "embed/sys/dbg/stm32/dbg_printf.c", "embed/sys/irq/stm32/irq.c", diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index 2f768f1e76..9600013b95 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -88,6 +88,7 @@ def stm32u5_common_files(env, features_wanted, defines, sources, paths): "embed/sec/random_delays/stm32/random_delays.c", "embed/sec/rng/stm32/rng.c", "embed/sec/secret/stm32u5/secret.c", + "embed/sec/secret/stm32u5/secret_keys.c", "embed/sec/secure_aes/stm32u5/secure_aes.c", "embed/sec/secure_aes/stm32u5/secure_aes_unpriv.c", "embed/sec/time_estimate/stm32/time_estimate.c", diff --git a/core/site_scons/models/unix_common.py b/core/site_scons/models/unix_common.py index 7c0f9c7373..7b33206c24 100644 --- a/core/site_scons/models/unix_common.py +++ b/core/site_scons/models/unix_common.py @@ -36,6 +36,7 @@ def unix_common_files(env, defines, sources, paths): "embed/sec/entropy/unix/entropy.c", "embed/sec/random_delays/unix/random_delays.c", "embed/sec/secret/unix/secret.c", + "embed/sec/secret/unix/secret_keys.c", "embed/sec/monoctr/unix/monoctr.c", "embed/sec/rng/unix/rng.c", "embed/sec/time_estimate/unix/time_estimate.c",