mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-04-11 04:45:45 +00:00
feat(core): support handling of tropic keys in secret sector
[no changelog]
This commit is contained in:
parent
2a335650b8
commit
d0b4e7ebeb
@ -11,7 +11,7 @@ PRODUCTION = 0 if BOOTLOADER_QA else ARGUMENTS.get('PRODUCTION', '0') == '1'
|
||||
HW_REVISION = ARGUMENTS.get('HW_REVISION', None)
|
||||
UI_DEBUG_OVERLAY = ARGUMENTS.get('UI_DEBUG_OVERLAY', '0') == '1'
|
||||
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d"]
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga", "dma2d", "tropic"]
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
|
@ -164,7 +164,7 @@ static bool set_metadata(cli_t* cli, uint16_t oid,
|
||||
}
|
||||
|
||||
void pair_optiga(cli_t* cli) {
|
||||
uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0};
|
||||
uint8_t secret[SECRET_KEY_LEN] = {0};
|
||||
|
||||
if (secret_optiga_get(secret) != sectrue) {
|
||||
if (secret_optiga_writable() != sectrue) {
|
||||
|
@ -57,7 +57,7 @@ void optiga_init_and_configure(void) {
|
||||
|
||||
optiga_init();
|
||||
|
||||
uint8_t secret[SECRET_OPTIGA_KEY_LEN] = {0};
|
||||
uint8_t secret[SECRET_KEY_LEN] = {0};
|
||||
secbool secret_ok = secret_optiga_get(secret);
|
||||
|
||||
if (sectrue == secret_ok) {
|
||||
|
@ -23,18 +23,24 @@
|
||||
|
||||
#ifdef KERNEL_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_OPTIGA_KEY_LEN 32
|
||||
#define SECRET_TROPIC_KEY_LEN 32
|
||||
|
||||
#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)
|
||||
#define SECRET_BHK_LEN 32
|
||||
|
||||
// Writes data to the secret storage
|
||||
void secret_write(const uint8_t* data, uint32_t offset, uint32_t len);
|
||||
@ -54,10 +60,12 @@ void secret_erase(void);
|
||||
// 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_OPTIGA_KEY_LEN]);
|
||||
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
|
||||
@ -65,7 +73,7 @@ secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]);
|
||||
// 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_OPTIGA_KEY_LEN]);
|
||||
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);
|
||||
@ -75,10 +83,24 @@ secbool secret_optiga_writable(void);
|
||||
|
||||
// Erases optiga pairing secret from the secret storage
|
||||
void secret_optiga_erase(void);
|
||||
#endif
|
||||
|
||||
secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_TROPIC_KEY_LEN]);
|
||||
#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_TROPIC_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);
|
||||
|
||||
void secret_tropic_erase(void);
|
||||
|
||||
#endif
|
||||
|
||||
// Regenerates the BHK and writes it to the secret storage
|
||||
void secret_bhk_regenerate(void);
|
||||
|
@ -123,15 +123,15 @@ void secret_erase(void) {
|
||||
mpu_restore(mpu_mode);
|
||||
}
|
||||
|
||||
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
|
||||
secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) {
|
||||
secret_erase();
|
||||
secret_write_header();
|
||||
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
||||
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_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);
|
||||
secbool secret_optiga_get(uint8_t dest[SECRET_KEY_LEN]) {
|
||||
return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN);
|
||||
}
|
||||
|
||||
secbool secret_optiga_present(void) {
|
||||
|
@ -32,6 +32,11 @@
|
||||
|
||||
#ifdef KERNEL_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
|
||||
|
||||
static secbool bootloader_locked = secfalse;
|
||||
|
||||
secbool secret_verify_header(void) {
|
||||
@ -64,20 +69,6 @@ static secbool secret_ensure_initialized(void) {
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool secret_bootloader_locked(void) {
|
||||
#if defined BOOTLOADER || defined BOARDLOADER
|
||||
return secret_optiga_present();
|
||||
#else
|
||||
const volatile uint32_t *reg1 = &TAMP->BKP8R;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (reg1[i] != 0) {
|
||||
return sectrue;
|
||||
}
|
||||
}
|
||||
return secfalse;
|
||||
#endif
|
||||
}
|
||||
|
||||
void secret_write_header(void) {
|
||||
uint8_t header[SECRET_HEADER_LEN] = {0};
|
||||
memcpy(header, SECRET_HEADER_MAGIC, 4);
|
||||
@ -130,9 +121,9 @@ static secbool secret_bhk_locked(void) {
|
||||
sectrue;
|
||||
}
|
||||
|
||||
static secbool secret_present(uint32_t offset, uint32_t len) {
|
||||
static secbool secret_key_present(uint32_t offset) {
|
||||
uint8_t *secret =
|
||||
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
|
||||
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, SECRET_KEY_LEN);
|
||||
|
||||
if (secret == NULL) {
|
||||
return secfalse;
|
||||
@ -142,7 +133,7 @@ static secbool secret_present(uint32_t offset, uint32_t len) {
|
||||
|
||||
int secret_empty_bytes = 0;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (int i = 0; i < SECRET_KEY_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) {
|
||||
@ -152,7 +143,102 @@ static secbool secret_present(uint32_t offset, uint32_t len) {
|
||||
|
||||
mpu_restore(mpu_mode);
|
||||
|
||||
return sectrue * (secret_empty_bytes != len);
|
||||
return sectrue * (secret_empty_bytes != SECRET_KEY_LEN);
|
||||
}
|
||||
|
||||
__attribute__((unused)) static secbool secret_key_writable(uint32_t offset) {
|
||||
const uint8_t *const secret =
|
||||
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, SECRET_KEY_LEN);
|
||||
|
||||
if (secret == NULL) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET);
|
||||
|
||||
int secret_empty_bytes = 0;
|
||||
|
||||
for (int i = 0; i < SECRET_KEY_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++;
|
||||
}
|
||||
}
|
||||
|
||||
mpu_restore(mpu_mode);
|
||||
|
||||
return sectrue * (secret_empty_bytes == SECRET_KEY_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};
|
||||
|
||||
secbool ok = secret_read((uint8_t *)secret, key_offset, SECRET_KEY_LEN);
|
||||
|
||||
volatile uint32_t *reg = &TAMP->BKP0R;
|
||||
reg += reg_offset;
|
||||
if (sectrue == ok) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*reg = ((uint32_t *)secret)[i];
|
||||
reg++;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*reg = 0;
|
||||
reg++;
|
||||
}
|
||||
}
|
||||
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)) {
|
||||
return secfalse;
|
||||
}
|
||||
secret_write(secret_enc, key_offset, SECRET_KEY_LEN);
|
||||
memzero(secret_enc, sizeof(secret_enc));
|
||||
secret_key_cache(reg_offset, key_offset);
|
||||
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};
|
||||
|
||||
bool all_zero = true;
|
||||
volatile uint32_t *reg = &TAMP->BKP0R;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
secret[i] = reg[i + reg_offset];
|
||||
|
||||
if (secret[i] != 0) {
|
||||
all_zero = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_zero) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
secbool res = secure_aes_ecb_decrypt_hw((uint8_t *)secret, SECRET_KEY_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) {
|
||||
volatile uint32_t *reg = &TAMP->BKP0R;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
reg[i + reg_offset] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Provision the secret BHK from the secret storage to the BHK register
|
||||
@ -163,14 +249,14 @@ static void secret_bhk_load(void) {
|
||||
reboot_device();
|
||||
}
|
||||
|
||||
uint32_t secret[SECRET_BHK_LEN / sizeof(uint32_t)] = {0};
|
||||
uint32_t secret[SECRET_KEY_LEN / sizeof(uint32_t)] = {0};
|
||||
|
||||
if (sectrue != secret_present(SECRET_BHK_OFFSET, SECRET_BHK_LEN)) {
|
||||
if (sectrue != secret_key_present(SECRET_BHK_OFFSET)) {
|
||||
secret_bhk_regenerate();
|
||||
}
|
||||
|
||||
secbool ok =
|
||||
secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_BHK_LEN);
|
||||
secret_read((uint8_t *)secret, SECRET_BHK_OFFSET, SECRET_KEY_LEN);
|
||||
|
||||
volatile uint32_t *reg1 = &TAMP->BKP0R;
|
||||
if (sectrue == ok) {
|
||||
@ -215,126 +301,171 @@ void secret_bhk_regenerate(void) {
|
||||
// i.e. in bootloader. Access to secret storage is restricted by calling
|
||||
// secret_hide.
|
||||
secbool secret_optiga_present(void) {
|
||||
return secret_present(SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
||||
return secret_key_present(SECRET_OPTIGA_KEY_OFFSET);
|
||||
}
|
||||
|
||||
secbool secret_optiga_writable(void) {
|
||||
const uint32_t offset = SECRET_OPTIGA_KEY_OFFSET;
|
||||
const uint32_t len = SECRET_OPTIGA_KEY_LEN;
|
||||
return secret_key_writable(SECRET_OPTIGA_KEY_OFFSET);
|
||||
}
|
||||
|
||||
const uint8_t *const secret =
|
||||
(uint8_t *)flash_area_get_address(&SECRET_AREA, offset, len);
|
||||
secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) {
|
||||
return secret_key_set(secret, REG_OPTIGA_KEY_OFFSET,
|
||||
SECRET_OPTIGA_KEY_OFFSET);
|
||||
}
|
||||
|
||||
if (secret == NULL) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
mpu_mode_t mpu_mode = mpu_reconfig(MPU_MODE_SECRET);
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
mpu_restore(mpu_mode);
|
||||
|
||||
return sectrue * (secret_empty_bytes == len);
|
||||
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) {
|
||||
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);
|
||||
|
||||
volatile uint32_t *reg1 = &TAMP->BKP8R;
|
||||
if (sectrue == ok) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*reg1 = ((uint32_t *)secret)[i];
|
||||
reg1++;
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*reg1 = 0;
|
||||
reg1++;
|
||||
}
|
||||
}
|
||||
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_SP)) {
|
||||
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};
|
||||
|
||||
bool all_zero = true;
|
||||
volatile uint32_t *reg1 = &TAMP->BKP8R;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
secret[i] = reg1[i];
|
||||
|
||||
if (secret[i] != 0) {
|
||||
all_zero = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_zero) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
secbool res = secure_aes_ecb_decrypt_hw(
|
||||
(uint8_t *)secret, SECRET_OPTIGA_KEY_LEN, dest, SECURE_AES_KEY_DHUK_SP);
|
||||
|
||||
memzero(secret, sizeof(secret));
|
||||
return res;
|
||||
secret_key_cache(REG_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_OFFSET);
|
||||
}
|
||||
|
||||
// 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[i] = 0;
|
||||
}
|
||||
static void secret_optiga_uncache(void) { secret_key_uncache(8); }
|
||||
|
||||
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_TROPIC_KEY_LEN]) {
|
||||
return secfalse;
|
||||
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_TROPIC_KEY_LEN]) {
|
||||
return secfalse;
|
||||
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_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_and(res1, res2);
|
||||
}
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void secret_optiga_erase(void) {
|
||||
uint8_t value[SECRET_OPTIGA_KEY_LEN] = {0};
|
||||
secret_write(value, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void secret_se_uncache(void) {
|
||||
#ifdef USE_OPTIGA
|
||||
secret_optiga_uncache();
|
||||
#endif
|
||||
#ifdef USE_TROPIC
|
||||
secret_tropic_uncache();
|
||||
#endif
|
||||
}
|
||||
|
||||
void secret_se_cache(void) {
|
||||
#ifdef USE_OPTIGA
|
||||
secret_optiga_cache();
|
||||
#endif
|
||||
#ifdef USE_TROPIC
|
||||
secret_tropic_cache();
|
||||
#endif
|
||||
}
|
||||
|
||||
secbool secret_se_present(void) {
|
||||
#ifdef USE_OPTIGA
|
||||
secbool res1 = secret_optiga_present();
|
||||
#else
|
||||
secbool res1 = secfalse;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TROPIC
|
||||
secbool res2 = secret_tropic_present();
|
||||
#else
|
||||
secbool res2 = secfalse;
|
||||
#endif
|
||||
|
||||
return secbool_or(res1, res2);
|
||||
}
|
||||
|
||||
secbool secret_se_writable(void) {
|
||||
#ifdef USE_OPTIGA
|
||||
secbool res1 = secret_optiga_writable();
|
||||
#else
|
||||
secbool res1 = sectrue;
|
||||
#endif
|
||||
|
||||
#ifdef USE_TROPIC
|
||||
secbool res2 = secret_optiga_writable();
|
||||
#else
|
||||
secbool res2 = sectrue;
|
||||
#endif
|
||||
|
||||
return secbool_and(res1, res2);
|
||||
}
|
||||
|
||||
secbool secret_bootloader_locked(void) {
|
||||
#if defined BOOTLOADER || defined BOARDLOADER
|
||||
return secret_se_present();
|
||||
#else
|
||||
const volatile uint32_t *reg1 = &TAMP->BKP8R;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (reg1[i] != 0) {
|
||||
return sectrue;
|
||||
}
|
||||
}
|
||||
return secfalse;
|
||||
#endif
|
||||
}
|
||||
|
||||
void secret_prepare_fw(secbool allow_run_with_secret,
|
||||
secbool allow_provisioning_access) {
|
||||
/**
|
||||
@ -352,31 +483,27 @@ void secret_prepare_fw(secbool allow_run_with_secret,
|
||||
|
||||
secret_bhk_load();
|
||||
secret_bhk_lock();
|
||||
#ifdef USE_OPTIGA
|
||||
secret_optiga_uncache();
|
||||
secbool optiga_secret_present = secret_optiga_present();
|
||||
secbool optiga_secret_writable = secret_optiga_writable();
|
||||
if (sectrue == allow_provisioning_access &&
|
||||
sectrue == optiga_secret_writable && secfalse == optiga_secret_present) {
|
||||
// Secret is not present and the secret sector is writable.
|
||||
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 == optiga_secret_present) {
|
||||
// Firmware is trusted and the Optiga secret is present, make it available.
|
||||
secret_optiga_cache();
|
||||
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 == optiga_secret_present) {
|
||||
if (sectrue != allow_run_with_secret && sectrue == SE_secret_present) {
|
||||
// Untrusted firmware, locked bootloader. Show the restricted screen.
|
||||
show_install_restricted_screen();
|
||||
}
|
||||
#else
|
||||
secret_disable_access();
|
||||
#endif
|
||||
}
|
||||
|
||||
void secret_init(void) {
|
||||
|
@ -133,15 +133,15 @@ void secret_erase(void) {
|
||||
mpu_restore(mpu_mode);
|
||||
}
|
||||
|
||||
secbool secret_optiga_set(const uint8_t secret[SECRET_OPTIGA_KEY_LEN]) {
|
||||
secbool secret_optiga_set(const uint8_t secret[SECRET_KEY_LEN]) {
|
||||
secret_erase();
|
||||
secret_write_header();
|
||||
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_OPTIGA_KEY_LEN);
|
||||
secret_write(secret, SECRET_OPTIGA_KEY_OFFSET, SECRET_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);
|
||||
secbool secret_optiga_get(uint8_t dest[SECRET_KEY_LEN]) {
|
||||
return secret_read(dest, SECRET_OPTIGA_KEY_OFFSET, SECRET_KEY_LEN);
|
||||
}
|
||||
|
||||
secbool secret_optiga_present(void) {
|
||||
@ -152,13 +152,13 @@ secbool secret_optiga_writable(void) { return secret_wiped(); }
|
||||
|
||||
void secret_optiga_erase(void) { secret_erase(); }
|
||||
|
||||
secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_TROPIC_KEY_LEN]) {
|
||||
memcpy(dest, &SECRET_TROPIC_TREZOR_PRIVKEY_BYTES, SECRET_TROPIC_KEY_LEN);
|
||||
secbool secret_tropic_get_trezor_privkey(uint8_t dest[SECRET_KEY_LEN]) {
|
||||
memcpy(dest, &SECRET_TROPIC_TREZOR_PRIVKEY_BYTES, SECRET_KEY_LEN);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool secret_tropic_get_tropic_pubkey(uint8_t dest[SECRET_TROPIC_KEY_LEN]) {
|
||||
memcpy(dest, &SECRET_TROPIC_PUBKEY_BYTES, SECRET_TROPIC_KEY_LEN);
|
||||
secbool secret_tropic_get_tropic_pubkey(uint8_t dest[SECRET_KEY_LEN]) {
|
||||
memcpy(dest, &SECRET_TROPIC_PUBKEY_BYTES, SECRET_KEY_LEN);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
|
@ -48,8 +48,8 @@ bool tropic_init(void) {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t tropic_secret_tropic_pubkey[SECRET_TROPIC_KEY_LEN] = {0};
|
||||
uint8_t tropic_secret_trezor_privkey[SECRET_TROPIC_KEY_LEN] = {0};
|
||||
uint8_t tropic_secret_tropic_pubkey[SECRET_KEY_LEN] = {0};
|
||||
uint8_t tropic_secret_trezor_privkey[SECRET_KEY_LEN] = {0};
|
||||
|
||||
if (!tropic_hal_init()) {
|
||||
goto cleanup;
|
||||
@ -66,7 +66,7 @@ bool tropic_init(void) {
|
||||
secret_tropic_get_trezor_privkey(tropic_secret_trezor_privkey);
|
||||
|
||||
if (pubkey_ok == sectrue && privkey_ok == sectrue) {
|
||||
uint8_t trezor_pubkey[SECRET_TROPIC_KEY_LEN] = {0};
|
||||
uint8_t trezor_pubkey[SECRET_KEY_LEN] = {0};
|
||||
curve25519_scalarmult_basepoint(trezor_pubkey,
|
||||
tropic_secret_trezor_privkey);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user