1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-06 12:51:21 +00:00

feat(core): use U5 DHUK to encrypt optiga pairing secret in flash

[no changelog]
This commit is contained in:
tychovrahe 2024-03-06 15:53:50 +01:00 committed by TychoVrahe
parent e060ac68c5
commit 8a18cfe0d4
7 changed files with 106 additions and 53 deletions

View File

@ -442,10 +442,6 @@ int bootloader_main(void) {
#endif #endif
#endif #endif
#ifdef STM32U5
ensure(secret_ensure_initialized(), "secret reinitialized");
#endif
ui_screen_boot_empty(false); ui_screen_boot_empty(false);
mpu_config_bootloader(); mpu_config_bootloader();

View File

@ -141,9 +141,13 @@ int main(void) {
unit_variant_init(); unit_variant_init();
#ifdef STM32U5
secure_aes_init();
#endif
#ifdef USE_OPTIGA #ifdef USE_OPTIGA
uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0};
secbool secret_ok = secret_optiga_extract(secret); secbool secret_ok = secret_optiga_get(secret);
#endif #endif
mpu_config_firmware_initial(); mpu_config_firmware_initial();
@ -166,10 +170,6 @@ int main(void) {
set_core_clock(CLOCK_180_MHZ); set_core_clock(CLOCK_180_MHZ);
#endif #endif
#ifdef STM32U5
secure_aes_init();
#endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
button_init(); button_init();
#endif #endif

View File

@ -59,6 +59,7 @@
#include "memzero.h" #include "memzero.h"
#ifdef STM32U5 #ifdef STM32U5
#include "secure_aes.h"
#include "stm32u5xx_ll_utils.h" #include "stm32u5xx_ll_utils.h"
#else #else
#include "stm32f4xx_ll_utils.h" #include "stm32f4xx_ll_utils.h"
@ -584,6 +585,9 @@ int main(void) {
display_reinit(); display_reinit();
display_orientation(0); display_orientation(0);
random_delays_init(); random_delays_init();
#ifdef STM32U5
secure_aes_init();
#endif
#ifdef USE_HASH_PROCESSOR #ifdef USE_HASH_PROCESSOR
hash_processor_init(); hash_processor_init();
#endif #endif

View File

@ -33,12 +33,21 @@
#include "secret.h" #include "secret.h"
#include "sha2.h" #include "sha2.h"
#include TREZOR_BOARD
#ifdef STM32U5
#include "secure_aes.h"
#endif
typedef enum { typedef enum {
OPTIGA_PAIRING_UNPAIRED = 0, OPTIGA_PAIRING_UNPAIRED = 0,
OPTIGA_PAIRING_PAIRED, OPTIGA_PAIRING_PAIRED,
OPTIGA_PAIRING_ERR_RNG, OPTIGA_PAIRING_ERR_RNG,
OPTIGA_PAIRING_ERR_READ, OPTIGA_PAIRING_ERR_READ_FLASH,
OPTIGA_PAIRING_ERR_HANDSHAKE, OPTIGA_PAIRING_ERR_WRITE_FLASH,
OPTIGA_PAIRING_ERR_WRITE_OPTIGA,
OPTIGA_PAIRING_ERR_HANDSHAKE1,
OPTIGA_PAIRING_ERR_HANDSHAKE2,
} optiga_pairing; } optiga_pairing;
static optiga_pairing optiga_pairing_state = OPTIGA_PAIRING_UNPAIRED; static optiga_pairing optiga_pairing_state = OPTIGA_PAIRING_UNPAIRED;
@ -72,11 +81,20 @@ static bool optiga_paired(void) {
case OPTIGA_PAIRING_ERR_RNG: case OPTIGA_PAIRING_ERR_RNG:
details = "optiga_get_random error"; details = "optiga_get_random error";
break; break;
case OPTIGA_PAIRING_ERR_READ: case OPTIGA_PAIRING_ERR_READ_FLASH:
details = "failed to read pairing secret"; details = "failed to read pairing secret from flash";
break; break;
case OPTIGA_PAIRING_ERR_HANDSHAKE: case OPTIGA_PAIRING_ERR_WRITE_FLASH:
details = "optiga_sec_chan_handshake"; details = "failed to write pairing secret to flash";
break;
case OPTIGA_PAIRING_ERR_WRITE_OPTIGA:
details = "failed to write pairing secret to Optiga";
break;
case OPTIGA_PAIRING_ERR_HANDSHAKE1:
details = "failed optiga_sec_chan_handshake 1";
break;
case OPTIGA_PAIRING_ERR_HANDSHAKE2:
details = "failed optiga_sec_chan_handshake 2";
break; break;
default: default:
break; break;
@ -122,50 +140,57 @@ static bool set_metadata(uint16_t oid, const optiga_metadata *metadata) {
} }
void pair_optiga(void) { void pair_optiga(void) {
// The pairing key may already be written and locked. The success of the
// pairing procedure is determined by optiga_sec_chan_handshake(). Therefore
// it is OK for some of the intermediate operations to fail.
uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0}; uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0};
optiga_result ret = OPTIGA_SUCCESS;
if (secret_optiga_extract(secret) != sectrue) { if (secret_optiga_get(secret) != sectrue) {
// Generate the pairing secret.
if (OPTIGA_SUCCESS != optiga_get_random(secret, sizeof(secret))) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG;
return;
}
random_xor(secret, sizeof(secret));
// Enable writing the pairing secret to OPTIGA. // Enable writing the pairing secret to OPTIGA.
optiga_metadata metadata = {0}; optiga_metadata metadata = {0};
metadata.change = OPTIGA_META_ACCESS_ALWAYS; metadata.change = OPTIGA_META_ACCESS_ALWAYS;
metadata.execute = OPTIGA_META_ACCESS_ALWAYS; metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
metadata.data_type = TYPE_PTFBIND; metadata.data_type = TYPE_PTFBIND;
set_metadata(OID_KEY_PAIRING, &metadata); // Ignore result. (void)set_metadata(OID_KEY_PAIRING, &metadata);
// Generate pairing secret. // Store the pairing secret in OPTIGA.
ret = optiga_get_random(secret, sizeof(secret)); if (OPTIGA_SUCCESS != optiga_set_data_object(OID_KEY_PAIRING, false, secret,
if (OPTIGA_SUCCESS != ret) { sizeof(secret))) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG; optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_OPTIGA;
return; return;
} }
// Store pairing secret. // Execute the handshake to verify that the secret was stored correctly in
ret = // Optiga.
optiga_set_data_object(OID_KEY_PAIRING, false, secret, sizeof(secret)); if (OPTIGA_SUCCESS != optiga_sec_chan_handshake(secret, sizeof(secret))) {
if (OPTIGA_SUCCESS == ret) { optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE1;
secret_erase(); return;
secret_write_header();
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
} }
// Verify whether the secret was stored correctly in flash and OPTIGA. // Store the pairing secret in the flash memory.
if (sectrue != secret_optiga_set(secret)) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_FLASH;
return;
}
// Reload the pairing secret from the flash memory.
memzero(secret, sizeof(secret)); memzero(secret, sizeof(secret));
if (secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN) != if (sectrue != secret_optiga_get(secret)) {
sectrue) { optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH;
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ;
return; return;
} }
} }
ret = optiga_sec_chan_handshake(secret, sizeof(secret)); // Execute the handshake to verify that the secret is stored correctly in both
// Optiga and MCU flash.
optiga_result ret = optiga_sec_chan_handshake(secret, sizeof(secret));
memzero(secret, sizeof(secret)); memzero(secret, sizeof(secret));
if (OPTIGA_SUCCESS != ret) { if (OPTIGA_SUCCESS != ret) {
optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE; optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE2;
return; return;
} }

View File

@ -15,7 +15,7 @@
secbool secret_bootloader_locked(void); secbool secret_bootloader_locked(void);
void secret_write(uint8_t* data, uint32_t offset, uint32_t len); void secret_write(const uint8_t* data, uint32_t offset, uint32_t len);
secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len); secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len);
@ -31,12 +31,14 @@ void secret_hide(void);
void secret_write_header(void); void secret_write_header(void);
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]);
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]);
void secret_optiga_backup(void); void secret_optiga_backup(void);
void secret_optiga_hide(void); void secret_optiga_hide(void);
secbool secret_optiga_extract(uint8_t* dest);
void secret_bhk_lock(void); void secret_bhk_lock(void);
secbool secret_bhk_locked(void); secbool secret_bhk_locked(void);

View File

@ -37,7 +37,7 @@ void secret_write_header(void) {
secret_write(header, 0, SECRET_HEADER_LEN); secret_write(header, 0, SECRET_HEADER_LEN);
} }
void secret_write(uint8_t* data, uint32_t offset, uint32_t len) { void secret_write(const uint8_t* data, uint32_t offset, uint32_t len) {
ensure(flash_unlock_write(), "secret write"); ensure(flash_unlock_write(), "secret write");
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]), ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]),
@ -76,6 +76,13 @@ void secret_erase(void) {
ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase"); ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase");
} }
secbool secret_optiga_extract(uint8_t* dest) { secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
secret_erase();
secret_write_header();
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
return sectrue;
}
secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
} }

View File

@ -6,6 +6,7 @@
#include "memzero.h" #include "memzero.h"
#include "model.h" #include "model.h"
#include "rng.h" #include "rng.h"
#include "secure_aes.h"
static secbool bootloader_locked = secfalse; static secbool bootloader_locked = secfalse;
@ -48,7 +49,7 @@ void secret_write_header(void) {
secret_write(header, 0, SECRET_HEADER_LEN); secret_write(header, 0, SECRET_HEADER_LEN);
} }
void secret_write(uint8_t *data, uint32_t offset, uint32_t len) { void secret_write(const uint8_t *data, uint32_t offset, uint32_t len) {
ensure(flash_unlock_write(), "secret write"); ensure(flash_unlock_write(), "secret write");
for (int i = 0; i < len / 16; i++) { for (int i = 0; i < len / 16; i++) {
ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16), ensure(flash_area_write_quadword(&SECRET_AREA, offset + (i * 16),
@ -142,6 +143,18 @@ secbool secret_optiga_present(void) {
return secret_present(SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN); 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) { void secret_optiga_backup(void) {
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0}; uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET, secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET,
@ -162,22 +175,28 @@ void secret_optiga_backup(void) {
memzero(secret, sizeof(secret)); memzero(secret, sizeof(secret));
} }
secbool secret_optiga_extract(uint8_t *dest) { secbool secret_optiga_get(uint8_t dest[SECRET_OPTIGA_KEY_LEN]) {
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
bool all_zero = true; bool all_zero = true;
volatile uint32_t *reg1 = &TAMP->BKP8R; volatile uint32_t *reg1 = &TAMP->BKP8R;
for (int i = 0; i < 8; i++) { for (int i = 0; i < 8; i++) {
uint32_t val = *reg1++; secret[i] = reg1[i];
if (val != 0) { if (secret[i] != 0) {
all_zero = false; all_zero = false;
} }
for (int j = 0; j < 4; j++) {
dest[i * 4 + j] = (val >> (j * 8)) & 0xFF;
}
} }
return all_zero ? secfalse : sectrue; if (all_zero) {
return secfalse;
}
secbool res = secure_aes_ecb_decrypt_hw(
(uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK);
memzero(secret, sizeof(secret));
return res;
} }
void secret_optiga_hide(void) { void secret_optiga_hide(void) {