mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-10 08:38:07 +00:00
refactor(core): make secret api more versatile, secret layout model dependent
[no changelog]
This commit is contained in:
parent
2a6189c3ae
commit
e53cddf65e
@ -21,6 +21,7 @@
|
||||
|
||||
#include <rtl/sizedefs.h>
|
||||
#include "bootloaders/bootloader_hashes.h"
|
||||
#include "secret_layout.h"
|
||||
|
||||
#define MODEL_NAME "D002"
|
||||
#define MODEL_FULL_NAME "Trezor DIY 2"
|
||||
|
36
core/embed/models/D002/secret_layout.h
Normal file
36
core/embed/models/D002/secret_layout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -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"
|
||||
|
31
core/embed/models/T2B1/secret_layout.h
Normal file
31
core/embed/models/T2B1/secret_layout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "bootloaders/bootloader_hashes.h"
|
||||
#include "secret_layout.h"
|
||||
|
||||
#include <rtl/sizedefs.h>
|
||||
|
||||
|
41
core/embed/models/T3B1/secret_layout.h
Normal file
41
core/embed/models/T3B1/secret_layout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "bootloaders/bootloader_hashes.h"
|
||||
#include "secret_layout.h"
|
||||
|
||||
#include <rtl/sizedefs.h>
|
||||
|
||||
|
41
core/embed/models/T3T1/secret_layout.h
Normal file
41
core/embed/models/T3T1/secret_layout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -21,6 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <rtl/sizedefs.h>
|
||||
#include "secret_layout.h"
|
||||
|
||||
#include "bootloaders/bootloader_hashes.h"
|
||||
|
||||
|
51
core/embed/models/T3W1/secret_layout.h
Normal file
51
core/embed/models/T3W1/secret_layout.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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
|
@ -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:
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <rtl/cli.h>
|
||||
@ -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;
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <SDL.h>
|
||||
|
||||
#include <io/display.h>
|
||||
#include <sec/secret.h>
|
||||
#include <util/flash.h>
|
||||
#include <util/flash_otp.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
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) {
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <io/display.h>
|
||||
#include <sec/secret.h>
|
||||
#include <sys/system.h>
|
||||
#include <sys/systimer.h>
|
||||
#include <util/flash.h>
|
||||
@ -57,7 +58,6 @@
|
||||
#endif
|
||||
|
||||
#ifdef USE_TROPIC
|
||||
#include <sec/secret.h>
|
||||
#include <sec/tropic.h>
|
||||
#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();
|
||||
|
@ -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) {
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <sec/optiga.h>
|
||||
#include <sec/optiga_commands.h>
|
||||
#include <sec/optiga_transport.h>
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
#include <sys/systick.h>
|
||||
|
||||
#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
|
||||
|
@ -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
|
||||
|
42
core/embed/sec/secret/inc/sec/secret_keys.h
Normal file
42
core/embed/sec/secret/inc/sec/secret_keys.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <trezor_types.h>
|
||||
|
||||
#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 <ed25519-donna/ed25519.h>
|
||||
|
||||
secbool secret_key_tropic_public(curve25519_key dest);
|
||||
|
||||
secbool secret_key_tropic_pairing(curve25519_key dest);
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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) {
|
||||
|
35
core/embed/sec/secret/stm32f4/secret_keys.c
Normal file
35
core/embed/sec/secret/stm32f4/secret_keys.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef SECURE_MODE
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
|
||||
#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
|
@ -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) {
|
||||
|
47
core/embed/sec/secret/stm32u5/secret_keys.c
Normal file
47
core/embed/sec/secret/stm32u5/secret_keys.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef SECURE_MODE
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
|
||||
#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
|
@ -17,158 +17,156 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <memzero.h>
|
||||
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sec/secret.h>
|
||||
#include <sys/mpu.h>
|
||||
#include <util/flash.h>
|
||||
|
||||
#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();
|
||||
}
|
||||
|
58
core/embed/sec/secret/unix/secret_keys.c
Normal file
58
core/embed/sec/secret/unix/secret_keys.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef SECURE_MODE
|
||||
|
||||
#include <trezor_bsp.h>
|
||||
#include <trezor_model.h>
|
||||
#include <trezor_rtl.h>
|
||||
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
|
||||
#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
|
@ -22,7 +22,7 @@
|
||||
#include <trezor_rtl.h>
|
||||
#include <trezor_types.h>
|
||||
|
||||
#include <sec/secret.h>
|
||||
#include <sec/secret_keys.h>
|
||||
#include <sec/tropic.h>
|
||||
|
||||
#include <libtropic.h>
|
||||
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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",
|
||||
|
Loading…
Reference in New Issue
Block a user