mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-29 08:40:57 +00:00
feat(core): use U5 DHUK to encrypt optiga pairing secret in flash
[no changelog]
This commit is contained in:
parent
e060ac68c5
commit
8a18cfe0d4
@ -442,10 +442,6 @@ int bootloader_main(void) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef STM32U5
|
||||
ensure(secret_ensure_initialized(), "secret reinitialized");
|
||||
#endif
|
||||
|
||||
ui_screen_boot_empty(false);
|
||||
|
||||
mpu_config_bootloader();
|
||||
|
@ -141,9 +141,13 @@ int main(void) {
|
||||
|
||||
unit_variant_init();
|
||||
|
||||
#ifdef STM32U5
|
||||
secure_aes_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0};
|
||||
secbool secret_ok = secret_optiga_extract(secret);
|
||||
secbool secret_ok = secret_optiga_get(secret);
|
||||
#endif
|
||||
|
||||
mpu_config_firmware_initial();
|
||||
@ -166,10 +170,6 @@ int main(void) {
|
||||
set_core_clock(CLOCK_180_MHZ);
|
||||
#endif
|
||||
|
||||
#ifdef STM32U5
|
||||
secure_aes_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_BUTTON
|
||||
button_init();
|
||||
#endif
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "memzero.h"
|
||||
|
||||
#ifdef STM32U5
|
||||
#include "secure_aes.h"
|
||||
#include "stm32u5xx_ll_utils.h"
|
||||
#else
|
||||
#include "stm32f4xx_ll_utils.h"
|
||||
@ -584,6 +585,9 @@ int main(void) {
|
||||
display_reinit();
|
||||
display_orientation(0);
|
||||
random_delays_init();
|
||||
#ifdef STM32U5
|
||||
secure_aes_init();
|
||||
#endif
|
||||
#ifdef USE_HASH_PROCESSOR
|
||||
hash_processor_init();
|
||||
#endif
|
||||
|
@ -33,12 +33,21 @@
|
||||
#include "secret.h"
|
||||
#include "sha2.h"
|
||||
|
||||
#include TREZOR_BOARD
|
||||
|
||||
#ifdef STM32U5
|
||||
#include "secure_aes.h"
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
OPTIGA_PAIRING_UNPAIRED = 0,
|
||||
OPTIGA_PAIRING_PAIRED,
|
||||
OPTIGA_PAIRING_ERR_RNG,
|
||||
OPTIGA_PAIRING_ERR_READ,
|
||||
OPTIGA_PAIRING_ERR_HANDSHAKE,
|
||||
OPTIGA_PAIRING_ERR_READ_FLASH,
|
||||
OPTIGA_PAIRING_ERR_WRITE_FLASH,
|
||||
OPTIGA_PAIRING_ERR_WRITE_OPTIGA,
|
||||
OPTIGA_PAIRING_ERR_HANDSHAKE1,
|
||||
OPTIGA_PAIRING_ERR_HANDSHAKE2,
|
||||
} optiga_pairing;
|
||||
|
||||
static optiga_pairing optiga_pairing_state = OPTIGA_PAIRING_UNPAIRED;
|
||||
@ -72,11 +81,20 @@ static bool optiga_paired(void) {
|
||||
case OPTIGA_PAIRING_ERR_RNG:
|
||||
details = "optiga_get_random error";
|
||||
break;
|
||||
case OPTIGA_PAIRING_ERR_READ:
|
||||
details = "failed to read pairing secret";
|
||||
case OPTIGA_PAIRING_ERR_READ_FLASH:
|
||||
details = "failed to read pairing secret from flash";
|
||||
break;
|
||||
case OPTIGA_PAIRING_ERR_HANDSHAKE:
|
||||
details = "optiga_sec_chan_handshake";
|
||||
case OPTIGA_PAIRING_ERR_WRITE_FLASH:
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
@ -122,50 +140,57 @@ static bool set_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
||||
}
|
||||
|
||||
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};
|
||||
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.
|
||||
optiga_metadata metadata = {0};
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.data_type = TYPE_PTFBIND;
|
||||
set_metadata(OID_KEY_PAIRING, &metadata); // Ignore result.
|
||||
(void)set_metadata(OID_KEY_PAIRING, &metadata);
|
||||
|
||||
// Generate pairing secret.
|
||||
ret = optiga_get_random(secret, sizeof(secret));
|
||||
if (OPTIGA_SUCCESS != ret) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_RNG;
|
||||
// Store the pairing secret in OPTIGA.
|
||||
if (OPTIGA_SUCCESS != optiga_set_data_object(OID_KEY_PAIRING, false, secret,
|
||||
sizeof(secret))) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_WRITE_OPTIGA;
|
||||
return;
|
||||
}
|
||||
|
||||
// Store pairing secret.
|
||||
ret =
|
||||
optiga_set_data_object(OID_KEY_PAIRING, false, secret, sizeof(secret));
|
||||
if (OPTIGA_SUCCESS == ret) {
|
||||
secret_erase();
|
||||
secret_write_header();
|
||||
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
||||
// Execute the handshake to verify that the secret was stored correctly in
|
||||
// Optiga.
|
||||
if (OPTIGA_SUCCESS != optiga_sec_chan_handshake(secret, sizeof(secret))) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE1;
|
||||
return;
|
||||
}
|
||||
|
||||
// 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));
|
||||
if (secret_read(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN) !=
|
||||
sectrue) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ;
|
||||
if (sectrue != secret_optiga_get(secret)) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_READ_FLASH;
|
||||
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));
|
||||
if (OPTIGA_SUCCESS != ret) {
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE;
|
||||
optiga_pairing_state = OPTIGA_PAIRING_ERR_HANDSHAKE2;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
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);
|
||||
|
||||
@ -31,12 +31,14 @@ void secret_hide(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_hide(void);
|
||||
|
||||
secbool secret_optiga_extract(uint8_t* dest);
|
||||
|
||||
void secret_bhk_lock(void);
|
||||
|
||||
secbool secret_bhk_locked(void);
|
||||
|
@ -37,7 +37,7 @@ void secret_write_header(void) {
|
||||
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");
|
||||
for (int i = 0; i < len; 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");
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "memzero.h"
|
||||
#include "model.h"
|
||||
#include "rng.h"
|
||||
#include "secure_aes.h"
|
||||
|
||||
static secbool bootloader_locked = secfalse;
|
||||
|
||||
@ -48,7 +49,7 @@ void secret_write_header(void) {
|
||||
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");
|
||||
for (int i = 0; i < len / 16; i++) {
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
uint32_t secret[SECRET_OPTIGA_KEY_LEN / sizeof(uint32_t)] = {0};
|
||||
secbool ok = secret_read((uint8_t *)secret, SECRET_OPTIGA_KEY_OFFSET,
|
||||
@ -162,22 +175,28 @@ void secret_optiga_backup(void) {
|
||||
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;
|
||||
volatile uint32_t *reg1 = &TAMP->BKP8R;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user