mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-07-24 07:28:34 +00:00
feat(core): add prodtest and secret handling for T2B1
[no changelog]
This commit is contained in:
parent
74759310bb
commit
324502cc17
@ -516,3 +516,12 @@ message UnlockedPathRequest {
|
||||
*/
|
||||
message ShowDeviceTutorial {
|
||||
}
|
||||
|
||||
/**
|
||||
* Request: Delete attestation from the device, !irreversible!
|
||||
* @start
|
||||
* @next Success
|
||||
* @next Failure
|
||||
*/
|
||||
message AttestationDelete {
|
||||
}
|
||||
|
@ -121,6 +121,7 @@ enum MessageType {
|
||||
MessageType_UnlockPath = 93 [(bitcoin_only) = true, (wire_in) = true];
|
||||
MessageType_UnlockedPathRequest = 94 [(bitcoin_only) = true, (wire_out) = true];
|
||||
MessageType_ShowDeviceTutorial = 95 [(bitcoin_only) = true, (wire_in) = true];
|
||||
MessageType_AttestationDelete = 96 [(bitcoin_only) = true, (wire_in) = true];
|
||||
|
||||
MessageType_SetU2FCounter = 63 [(wire_in) = true];
|
||||
MessageType_GetNextU2FCounter = 80 [(wire_in) = true];
|
||||
|
@ -20,7 +20,7 @@ if TREZOR_MODEL in ('1', ):
|
||||
)
|
||||
Return()
|
||||
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb"]
|
||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga"]
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
|
@ -92,6 +92,20 @@ SOURCE_MOD += [
|
||||
'vendor/trezor-storage/flash_common.c',
|
||||
]
|
||||
|
||||
if TREZOR_MODEL in ('1', ):
|
||||
SOURCE_MOD += [
|
||||
'embed/models/model_T1B1_layout.c',
|
||||
]
|
||||
elif TREZOR_MODEL in ('T', ):
|
||||
SOURCE_MOD += [
|
||||
'embed/models/model_T2T1_layout.c',
|
||||
]
|
||||
elif TREZOR_MODEL in ('R', ):
|
||||
SOURCE_MOD += [
|
||||
'embed/models/model_T2B1_layout.c',
|
||||
]
|
||||
|
||||
|
||||
SOURCE_NANOPB = [
|
||||
'vendor/nanopb/pb_common.c',
|
||||
'vendor/nanopb/pb_decode.c',
|
||||
@ -114,6 +128,7 @@ SOURCE_TREZORHAL = [
|
||||
'embed/trezorhal/unix/rng.c',
|
||||
'embed/trezorhal/unix/usb.c',
|
||||
'embed/trezorhal/unix/random_delays.c',
|
||||
'embed/trezorhal/unix/secret.c',
|
||||
]
|
||||
|
||||
SOURCE_UNIX = [
|
||||
|
@ -17,7 +17,7 @@ if TREZOR_MODEL in ('DISC1', ):
|
||||
action=build_prodtest)
|
||||
Return()
|
||||
|
||||
FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb"]
|
||||
FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mask", "optiga"]
|
||||
|
||||
CCFLAGS_MOD = ''
|
||||
CPPPATH_MOD = []
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "image.h"
|
||||
#include "random_delays.h"
|
||||
#include "secbool.h"
|
||||
#include "secret.h"
|
||||
|
||||
#ifdef USE_DMA2D
|
||||
#include "dma2d.h"
|
||||
@ -522,6 +523,19 @@ int bootloader_main(void) {
|
||||
&FIRMWARE_AREA),
|
||||
"Firmware is corrupted");
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
if (((vhdr.vtrust & VTRUST_SECRET) != 0) && (sectrue != secret_wiped())) {
|
||||
display_clear();
|
||||
screen_fatal_error_rust(
|
||||
"ATTESTATION PRESENT",
|
||||
"You need to delete device attestation to run unofficial firmware",
|
||||
"RECONNECT THE DEVICE");
|
||||
|
||||
display_refresh();
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
// if all VTRUST flags are unset = ultimate trust => skip the procedure
|
||||
|
||||
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
|
||||
|
@ -11,4 +11,8 @@
|
||||
#define FIX_VERSION_PATCH 0
|
||||
#define FIX_VERSION_BUILD 0
|
||||
|
||||
#ifdef TREZOR_MODEL_R
|
||||
#define VERSION_MONOTONIC 2
|
||||
#else
|
||||
#define VERSION_MONOTONIC 1
|
||||
#endif
|
||||
|
@ -165,10 +165,7 @@ int main(void) {
|
||||
#endif
|
||||
|
||||
#if !defined TREZOR_MODEL_1
|
||||
// jump to unprivileged mode
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html
|
||||
__asm__ volatile("msr control, %0" ::"r"(0x1));
|
||||
__asm__ volatile("isb");
|
||||
drop_privileges();
|
||||
#endif
|
||||
|
||||
#ifdef USE_SECP256K1_ZKP
|
||||
|
@ -56,6 +56,8 @@ typedef struct {
|
||||
#define VTRUST_RED 0x0010
|
||||
#define VTRUST_CLICK 0x0020
|
||||
#define VTRUST_STRING 0x0040
|
||||
#define VTRUST_SECRET \
|
||||
0x0080 // inverse logic, if set, don't allow to run with secret present
|
||||
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
|
||||
|
||||
typedef struct {
|
||||
|
@ -14,6 +14,7 @@
|
||||
|
||||
extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT];
|
||||
extern const flash_area_t BOARDLOADER_AREA;
|
||||
extern const flash_area_t SECRET_AREA;
|
||||
extern const flash_area_t BOOTLOADER_AREA;
|
||||
extern const flash_area_t FIRMWARE_AREA;
|
||||
extern const flash_area_t WIPE_AREA;
|
||||
|
@ -1 +0,0 @@
|
||||
model_T2T1_layout.c
|
87
core/embed/models/model_T2B1_layout.c
Normal file
87
core/embed/models/model_T2B1_layout.c
Normal file
@ -0,0 +1,87 @@
|
||||
#include "flash.h"
|
||||
#include "model.h"
|
||||
|
||||
const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT] = {
|
||||
{
|
||||
.num_subareas = 1,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 4,
|
||||
.num_sectors = 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
.num_subareas = 1,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 16,
|
||||
.num_sectors = 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const flash_area_t BOARDLOADER_AREA = {
|
||||
.num_subareas = 1,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 0,
|
||||
.num_sectors = 3,
|
||||
},
|
||||
};
|
||||
|
||||
const flash_area_t SECRET_AREA = {
|
||||
.num_subareas = 1,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 12,
|
||||
.num_sectors = 1,
|
||||
},
|
||||
};
|
||||
|
||||
const flash_area_t BOOTLOADER_AREA = {
|
||||
.num_subareas = 1,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 5,
|
||||
.num_sectors = 1,
|
||||
},
|
||||
};
|
||||
|
||||
const flash_area_t FIRMWARE_AREA = {
|
||||
.num_subareas = 2,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 6,
|
||||
.num_sectors = 6,
|
||||
},
|
||||
.subarea[1] =
|
||||
{
|
||||
.first_sector = 17,
|
||||
.num_sectors = 7,
|
||||
},
|
||||
};
|
||||
|
||||
const flash_area_t WIPE_AREA = {
|
||||
.num_subareas = 4,
|
||||
.subarea[0] =
|
||||
{
|
||||
.first_sector = 4,
|
||||
.num_sectors = 1,
|
||||
},
|
||||
.subarea[1] =
|
||||
{
|
||||
.first_sector = 6,
|
||||
.num_sectors = 6,
|
||||
},
|
||||
.subarea[2] =
|
||||
{
|
||||
.first_sector = 13,
|
||||
.num_sectors = 2, // sector 15 skipped due to bootloader MPU
|
||||
// settings, sector 12 is secret
|
||||
},
|
||||
.subarea[3] =
|
||||
{
|
||||
.first_sector = 16,
|
||||
.num_sectors = 8,
|
||||
},
|
||||
};
|
@ -30,15 +30,24 @@
|
||||
#include "i2c.h"
|
||||
#include "mini_printf.h"
|
||||
#include "model.h"
|
||||
#include "mpu.h"
|
||||
#include "random_delays.h"
|
||||
#include "rng.h"
|
||||
#include "sbu.h"
|
||||
#include "sdcard.h"
|
||||
#include "secbool.h"
|
||||
#include "secret.h"
|
||||
#include "touch.h"
|
||||
#include "usb.h"
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
#include "optiga_commands.h"
|
||||
#include "optiga_hal.h"
|
||||
#include "optiga_transport.h"
|
||||
#endif
|
||||
|
||||
#include "memzero.h"
|
||||
#include "stm32f4xx_ll_utils.h"
|
||||
|
||||
#ifdef TREZOR_MODEL_T
|
||||
#define MODEL_IDENTIFIER "TREZOR2-"
|
||||
@ -91,6 +100,15 @@ static void vcp_readline(char *buf, size_t len) {
|
||||
}
|
||||
}
|
||||
|
||||
static void vcp_printf_ex(const char *fmt, ...) {
|
||||
static char buf[128];
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
int r = mini_vsnprintf(buf, sizeof(buf), fmt, va);
|
||||
va_end(va);
|
||||
vcp_puts(buf, r);
|
||||
}
|
||||
|
||||
static void vcp_printf(const char *fmt, ...) {
|
||||
static char buf[128];
|
||||
va_list va;
|
||||
@ -101,6 +119,45 @@ static void vcp_printf(const char *fmt, ...) {
|
||||
vcp_puts("\r\n", 2);
|
||||
}
|
||||
|
||||
static void vcp_write_as_hex(uint8_t *data, uint16_t len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
vcp_printf_ex("%02X", data[i]);
|
||||
}
|
||||
vcp_puts("\r\n", 2);
|
||||
}
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
static uint8_t get_byte_from_hex(const char *hex) {
|
||||
uint8_t result = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
result <<= 4;
|
||||
if (hex[i] >= '0' && hex[i] <= '9') {
|
||||
result |= hex[i] - '0';
|
||||
} else if (hex[i] >= 'A' && hex[i] <= 'F') {
|
||||
result |= hex[i] - 'A' + 10;
|
||||
} else if (hex[i] >= 'a' && hex[i] <= 'f') {
|
||||
result |= hex[i] - 'a' + 10;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int get_from_hex(uint8_t *buf, uint16_t buf_len, const char *hex) {
|
||||
int len = 0;
|
||||
for (int i = 0; i < buf_len; i++) {
|
||||
uint8_t b = get_byte_from_hex(hex + i * 2);
|
||||
if (b == 0) {
|
||||
break;
|
||||
}
|
||||
buf[i] = b;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void usb_init_all(void) {
|
||||
enum {
|
||||
VCP_PACKET_LEN = 64,
|
||||
@ -185,7 +242,7 @@ static void test_display(const char *colors) {
|
||||
c = 0xFFFF;
|
||||
break;
|
||||
}
|
||||
display_bar(i * w, 0, i * w + w, 240, c);
|
||||
display_bar(i * w, 0, i * w + w, DISPLAY_RESY, c);
|
||||
}
|
||||
display_refresh();
|
||||
vcp_printf("OK");
|
||||
@ -481,6 +538,13 @@ static void test_otp_write(const char *args) {
|
||||
}
|
||||
|
||||
static void test_otp_write_device_variant(const char *args) {
|
||||
#ifdef USE_OPTIGA
|
||||
// if (sectrue != is_optiga_locked()) {
|
||||
// vcp_printf("ERROR: NOT LOCKED");
|
||||
// return;
|
||||
// }
|
||||
#endif
|
||||
|
||||
volatile char data[32];
|
||||
memzero((char *)data, sizeof(data));
|
||||
data[0] = 1;
|
||||
@ -516,6 +580,100 @@ static void test_otp_write_device_variant(const char *args) {
|
||||
vcp_printf("OK");
|
||||
}
|
||||
|
||||
void cpuid_read(void) {
|
||||
uint32_t cpuid[3];
|
||||
cpuid[0] = LL_GetUID_Word0();
|
||||
cpuid[1] = LL_GetUID_Word1();
|
||||
cpuid[2] = LL_GetUID_Word2();
|
||||
|
||||
vcp_write_as_hex((uint8_t *)cpuid, sizeof(cpuid));
|
||||
}
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
void pair_optiga(void) {
|
||||
if (secret_wiped()) {
|
||||
// secret_write_header();
|
||||
//
|
||||
// uint8_t data[] = {0, 0, 0, 0}; // todo replace by real key
|
||||
//
|
||||
// secret_write(data, SECRET_OPTIGA_KEY_OFFSET, sizeof(data));
|
||||
}
|
||||
}
|
||||
|
||||
void optiga_lock(void) {}
|
||||
|
||||
void optigaid_read(void) {
|
||||
uint8_t optiga_id[27];
|
||||
size_t data_size = 0;
|
||||
|
||||
optiga_open_application();
|
||||
optiga_get_data_object(0xE0C2, false, optiga_id, sizeof(optiga_id),
|
||||
&data_size);
|
||||
|
||||
vcp_write_as_hex(optiga_id, sizeof(optiga_id));
|
||||
}
|
||||
|
||||
void certinf_read(void) {
|
||||
uint8_t cert[507];
|
||||
|
||||
// todo feed real data
|
||||
for (int i = 0; i < sizeof(cert); i++) {
|
||||
cert[i] = i;
|
||||
}
|
||||
|
||||
vcp_write_as_hex(cert, sizeof(cert));
|
||||
}
|
||||
|
||||
void certdev_write(char *data) {
|
||||
// expected 507
|
||||
uint8_t data_bytes[1024];
|
||||
|
||||
int len = get_from_hex(data_bytes, sizeof(data_bytes), data);
|
||||
|
||||
(void)len;
|
||||
// TODO: write to optiga
|
||||
|
||||
vcp_printf("OK");
|
||||
}
|
||||
|
||||
void keyfido_handshake(char *data) {
|
||||
// expected 97
|
||||
uint8_t data_bytes[1024];
|
||||
|
||||
int len = get_from_hex(data_bytes, sizeof(data_bytes), data);
|
||||
|
||||
(void)len;
|
||||
// todo
|
||||
|
||||
vcp_printf("OK");
|
||||
}
|
||||
|
||||
void keyfido_write(char *data) {
|
||||
// expected 81
|
||||
uint8_t data_bytes[1024];
|
||||
|
||||
int len = get_from_hex(data_bytes, sizeof(data_bytes), data);
|
||||
|
||||
(void)len;
|
||||
// todo
|
||||
|
||||
vcp_printf("OK");
|
||||
}
|
||||
|
||||
void certfido_write(char *data) {
|
||||
// expected 465
|
||||
uint8_t data_bytes[1024];
|
||||
|
||||
int len = get_from_hex(data_bytes, sizeof(data_bytes), data);
|
||||
|
||||
(void)len;
|
||||
// todo
|
||||
|
||||
vcp_printf("OK");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define BACKLIGHT_NORMAL 150
|
||||
|
||||
int main(void) {
|
||||
@ -527,8 +685,10 @@ int main(void) {
|
||||
#ifdef USE_BUTTON
|
||||
button_init();
|
||||
#endif
|
||||
#ifdef USE_TOUCH
|
||||
#ifdef USE_I2C
|
||||
i2c_init();
|
||||
#endif
|
||||
#ifdef USE_TOUCH
|
||||
touch_init();
|
||||
#endif
|
||||
#ifdef USE_SBU
|
||||
@ -536,7 +696,18 @@ int main(void) {
|
||||
#endif
|
||||
usb_init_all();
|
||||
|
||||
#ifdef USE_OPTIGA
|
||||
optiga_init();
|
||||
pair_optiga();
|
||||
// todo authenticate optiga communication
|
||||
// todo delete optiga pairing key from RAM
|
||||
#endif
|
||||
|
||||
display_reinit();
|
||||
|
||||
mpu_config_prodtest();
|
||||
drop_privileges();
|
||||
|
||||
display_clear();
|
||||
draw_border(1, 3);
|
||||
|
||||
@ -551,7 +722,8 @@ int main(void) {
|
||||
|
||||
display_fade(0, BACKLIGHT_NORMAL, 1000);
|
||||
|
||||
char line[128];
|
||||
char line[2048]; // expecting hundreds of bytes represented as hexadecimal
|
||||
// characters
|
||||
|
||||
for (;;) {
|
||||
vcp_readline(line, sizeof(line));
|
||||
@ -559,6 +731,9 @@ int main(void) {
|
||||
if (startswith(line, "PING")) {
|
||||
vcp_printf("OK");
|
||||
|
||||
} else if (startswith(line, "CPUID READ")) {
|
||||
cpuid_read();
|
||||
|
||||
} else if (startswith(line, "BORDER")) {
|
||||
test_border();
|
||||
|
||||
@ -584,6 +759,23 @@ int main(void) {
|
||||
#ifdef USE_SBU
|
||||
} else if (startswith(line, "SBU ")) {
|
||||
test_sbu(line + 4);
|
||||
#endif
|
||||
#ifdef USE_OPTIGA
|
||||
} else if (startswith(line, "OPTIGAID READ")) {
|
||||
optigaid_read();
|
||||
} else if (startswith(line, "CERTINF READ")) {
|
||||
certinf_read();
|
||||
} else if (startswith(line, "CERTDEV WRITE ")) {
|
||||
certdev_write(line + 14);
|
||||
} else if (startswith(line, "KEYFIDO HANDSHAKE ")) {
|
||||
keyfido_handshake(line + 18);
|
||||
} else if (startswith(line, "KEYFIDO WRITE ")) {
|
||||
keyfido_write(line + 14);
|
||||
} else if (startswith(line, "CERTFIDO WRITE ")) {
|
||||
certfido_write(line + 15);
|
||||
} else if (startswith(line, "LOCK")) {
|
||||
optiga_lock();
|
||||
|
||||
#endif
|
||||
|
||||
} else if (startswith(line, "OTP READ")) {
|
||||
|
@ -23,5 +23,6 @@
|
||||
void mpu_config_off(void);
|
||||
void mpu_config_bootloader(void);
|
||||
void mpu_config_firmware(void);
|
||||
void mpu_config_prodtest(void);
|
||||
|
||||
#endif
|
||||
|
18
core/embed/trezorhal/secret.h
Normal file
18
core/embed/trezorhal/secret.h
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
#define SECRET_HEADER_MAGIC "TRZS"
|
||||
#define SECRET_HEADER_LEN 16
|
||||
#define SECRET_OPTIGA_KEY_OFFSET 16
|
||||
#define SECRET_OPTIGA_KEY_LEN 32
|
||||
|
||||
void secret_write(uint8_t* data, uint32_t offset, uint32_t len);
|
||||
|
||||
secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len);
|
||||
|
||||
secbool secret_wiped(void);
|
||||
|
||||
void secret_erase(void);
|
||||
|
||||
void secret_write_header(void);
|
@ -125,12 +125,13 @@ void mpu_config_firmware(void) {
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
// Storage#2 (0x08110000 - 0x0811FFFF, 64 KiB, read-write, execute never)
|
||||
// Secret + Storage#2 (0x08100000 - 0x0811FFFF, 16 Kib + 64 KiB, read-write,
|
||||
// execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER2;
|
||||
MPU->RBAR = FLASH_BASE + 0x110000;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0x0E);
|
||||
|
||||
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
|
||||
// start = 768 KiB, read-only)
|
||||
@ -193,3 +194,98 @@ void mpu_config_firmware(void) {
|
||||
__asm__ volatile("dsb");
|
||||
__asm__ volatile("isb");
|
||||
}
|
||||
|
||||
void mpu_config_prodtest(void) {
|
||||
// Disable MPU
|
||||
HAL_MPU_Disable();
|
||||
|
||||
// Note: later entries overwrite previous ones
|
||||
|
||||
// // Boardloader (0x08000000 - 0x0800BFFF, 48 KiB, read-only, execute never)
|
||||
// MPU->RNR = MPU_REGION_NUMBER0;
|
||||
// MPU->RBAR = FLASH_BASE;
|
||||
// MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
// LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO |
|
||||
// MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0);
|
||||
|
||||
// Secret area (0x08100000 - 0x08103FFF, 16 KiB, read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER0;
|
||||
MPU->RBAR = FLASH_BASE + 0x100000;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_16KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
|
||||
// Bootloader (0x08020000 - 0x0803FFFF, 64 KiB, read-only)
|
||||
MPU->RNR = MPU_REGION_NUMBER1;
|
||||
MPU->RBAR = FLASH_BASE + 0x20000;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_PRIV_RO_URO;
|
||||
|
||||
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
|
||||
// start = 768 KiB, read-only)
|
||||
MPU->RNR = MPU_REGION_NUMBER2;
|
||||
MPU->RBAR = FLASH_BASE;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_SUBREGION_DISABLE(0x03);
|
||||
|
||||
// Firmware extra (0x08120000 - 0x081FFFFF, 7 * 128 KiB = 1024 KiB except 1/8
|
||||
// at start = 896 KiB, read-only)
|
||||
MPU->RNR = MPU_REGION_NUMBER3;
|
||||
MPU->RBAR = FLASH_BASE + 0x100000;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_1MB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_SUBREGION_DISABLE(0x01);
|
||||
|
||||
// SRAM (0x20000000 - 0x2002FFFF, 192 KiB = 256 KiB except 2/8 at end,
|
||||
// read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER4;
|
||||
MPU->RBAR = SRAM_BASE;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
|
||||
LL_MPU_REGION_SIZE_256KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xC0);
|
||||
|
||||
#ifdef USE_SDRAM
|
||||
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never)
|
||||
// SDRAM (0xC0000000 - 0xDFFFFFFF, read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER5;
|
||||
MPU->RBAR = 0;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH |
|
||||
LL_MPU_REGION_SIZE_4GB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0xBB);
|
||||
#else
|
||||
// Peripherals (0x40000000 - 0x5FFFFFFF, read-write, execute never)
|
||||
// External RAM (0x60000000 - 0x7FFFFFFF, read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER5;
|
||||
MPU->RBAR = PERIPH_BASE;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_PERIPH |
|
||||
LL_MPU_REGION_SIZE_1GB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
#endif
|
||||
|
||||
#if defined STM32F427xx || defined STM32F429xx
|
||||
// CCMRAM (0x10000000 - 0x1000FFFF, read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER6;
|
||||
MPU->RBAR = CCMDATARAM_BASE;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_SRAM |
|
||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
#elif STM32F405xx
|
||||
// no CCMRAM
|
||||
#else
|
||||
#error Unsupported MCU
|
||||
#endif
|
||||
|
||||
// OTP (0x1FFF7800 - 0x1FFF7C00, read-write, execute never)
|
||||
MPU->RNR = MPU_REGION_NUMBER7;
|
||||
MPU->RBAR = FLASH_OTP_BASE;
|
||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||
LL_MPU_REGION_SIZE_1KB | LL_MPU_REGION_FULL_ACCESS |
|
||||
MPU_RASR_XN_Msk;
|
||||
|
||||
// Enable MPU
|
||||
HAL_MPU_Enable(LL_MPU_CTRL_HARDFAULT_NMI);
|
||||
|
||||
__asm__ volatile("dsb");
|
||||
__asm__ volatile("isb");
|
||||
}
|
||||
|
@ -195,6 +195,13 @@ void set_core_clock(clock_settings_t settings) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void drop_privileges(void) {
|
||||
// jump to unprivileged mode
|
||||
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html
|
||||
__asm__ volatile("msr control, %0" ::"r"(0x1));
|
||||
__asm__ volatile("isb");
|
||||
}
|
||||
|
||||
// from util.s
|
||||
extern void shutdown_privileged(void);
|
||||
|
||||
|
@ -40,6 +40,7 @@ void jump_to_unprivileged(uint32_t address);
|
||||
void jump_to_with_flag(uint32_t address, uint32_t register_flag);
|
||||
void ensure_compatible_settings(void);
|
||||
void clear_otg_hs_memory(void);
|
||||
void drop_privileges(void);
|
||||
|
||||
extern uint32_t __stack_chk_guard;
|
||||
|
||||
|
59
core/embed/trezorhal/stm32f4/secret.c
Normal file
59
core/embed/trezorhal/stm32f4/secret.c
Normal file
@ -0,0 +1,59 @@
|
||||
#include "secret.h"
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
#include "flash.h"
|
||||
#include "model.h"
|
||||
|
||||
static secbool verify_header(void) {
|
||||
uint8_t header[SECRET_HEADER_LEN] = {0};
|
||||
|
||||
memcpy(header, flash_area_get_address(&SECRET_AREA, 0, SECRET_HEADER_LEN),
|
||||
SECRET_HEADER_LEN);
|
||||
|
||||
return memcmp(header, SECRET_HEADER_MAGIC, 4) == 0 ? sectrue : secfalse;
|
||||
}
|
||||
|
||||
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(uint8_t* data, uint32_t offset, uint32_t len) {
|
||||
ensure(flash_unlock_write(), "secret write");
|
||||
for (int i = 0; i < len; i++) {
|
||||
ensure(flash_area_write_byte(&SECRET_AREA, offset + i, data[i]),
|
||||
"secret write");
|
||||
}
|
||||
ensure(flash_lock_write(), "secret write");
|
||||
}
|
||||
|
||||
secbool secret_read(uint8_t* data, uint32_t offset, uint32_t len) {
|
||||
if (sectrue != verify_header()) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
memcpy(data, flash_area_get_address(&SECRET_AREA, offset, len), len);
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool secret_wiped(void) {
|
||||
flash_area_get_address(&SECRET_AREA, 0, 1);
|
||||
|
||||
flash_area_get_size(&SECRET_AREA);
|
||||
|
||||
uint32_t size = flash_area_get_size(&SECRET_AREA);
|
||||
|
||||
for (int i = 0; i < size; i += 4) {
|
||||
uint32_t* addr = (uint32_t*)flash_area_get_address(&SECRET_AREA, i, 4);
|
||||
if (*addr != 0xFFFFFFFF) {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
void secret_erase(void) {
|
||||
ensure(flash_area_erase(&SECRET_AREA, NULL), "secret erase");
|
||||
}
|
9
core/embed/trezorhal/unix/secret.c
Normal file
9
core/embed/trezorhal/unix/secret.c
Normal file
@ -0,0 +1,9 @@
|
||||
#include "secret.h"
|
||||
|
||||
void secret_write(uint8_t* data, uint32_t offset, uint32_t len) {}
|
||||
|
||||
void secret_read(uint8_t* data, uint32_t offset, uint32_t len) {}
|
||||
|
||||
secbool secret_wiped(void) { return secfalse; }
|
||||
|
||||
void secret_erase(void) {}
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 1],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": true,
|
||||
"require_user_click": true,
|
||||
"red_background": true,
|
||||
|
19
core/embed/vendorheader/T2B1/vendor_prodtest.json
Normal file
19
core/embed/vendorheader/T2B1/vendor_prodtest.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"header_len": 4608,
|
||||
"text": "UNSAFE, FACTORY TEST ONLY",
|
||||
"hw_model": null,
|
||||
"expiry": 0,
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": true,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
"delay": 0
|
||||
},
|
||||
"pubkeys": [
|
||||
"c17d221529b70da08aa42ccb1b2cef773736a7d48434209f6eb16b1b474716d2",
|
||||
"6622ee8403464acfc2fe1e20311937b115e60771f3ee6e70f22bf2921977e534"
|
||||
]
|
||||
}
|
BIN
core/embed/vendorheader/T2B1/vendor_prodtest.toif
Normal file
BIN
core/embed/vendorheader/T2B1/vendor_prodtest.toif
Normal file
Binary file not shown.
@ -6,6 +6,7 @@
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": true,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": true,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": true,
|
||||
"require_user_click": true,
|
||||
"red_background": true,
|
||||
|
BIN
core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin
Normal file
BIN
core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -6,6 +6,7 @@
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 0],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 1],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": false,
|
||||
"require_user_click": false,
|
||||
"red_background": false,
|
||||
|
@ -6,6 +6,7 @@
|
||||
"version": [0, 1],
|
||||
"sig_m": 2,
|
||||
"trust": {
|
||||
"allow_run_with_secret": false,
|
||||
"show_vendor_string": true,
|
||||
"require_user_click": true,
|
||||
"red_background": true,
|
||||
|
@ -70,6 +70,7 @@ def configure(
|
||||
sources += ["embed/trezorhal/stm32f4/optiga_hal.c"]
|
||||
sources += ["embed/trezorhal/optiga/optiga_commands.c"]
|
||||
sources += ["embed/trezorhal/optiga/optiga_transport.c"]
|
||||
sources += ["embed/trezorhal/stm32f4/secret.c"]
|
||||
|
||||
env.get("ENV")["TREZOR_BOARD"] = board
|
||||
env.get("ENV")["MCU_TYPE"] = mcu
|
||||
|
@ -47,6 +47,7 @@ FirmwareHash = 89
|
||||
UnlockPath = 93
|
||||
UnlockedPathRequest = 94
|
||||
ShowDeviceTutorial = 95
|
||||
AttestationDelete = 96
|
||||
FirmwareErase = 6
|
||||
FirmwareUpload = 7
|
||||
FirmwareRequest = 8
|
||||
|
@ -64,6 +64,7 @@ if TYPE_CHECKING:
|
||||
UnlockPath = 93
|
||||
UnlockedPathRequest = 94
|
||||
ShowDeviceTutorial = 95
|
||||
AttestationDelete = 96
|
||||
SetU2FCounter = 63
|
||||
GetNextU2FCounter = 80
|
||||
NextU2FCounter = 81
|
||||
|
@ -2628,6 +2628,12 @@ if TYPE_CHECKING:
|
||||
def is_type_of(cls, msg: Any) -> TypeGuard["ShowDeviceTutorial"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class AttestationDelete(protobuf.MessageType):
|
||||
|
||||
@classmethod
|
||||
def is_type_of(cls, msg: Any) -> TypeGuard["AttestationDelete"]:
|
||||
return isinstance(msg, cls)
|
||||
|
||||
class DebugLinkDecision(protobuf.MessageType):
|
||||
button: "DebugButton | None"
|
||||
swipe: "DebugSwipeDirection | None"
|
||||
|
@ -7,7 +7,8 @@ SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdPro
|
||||
DebugLinkLayout DebugLinkResetDebugEvents GetNonce \
|
||||
TxAckInput TxAckOutput TxAckPrev TxAckPaymentRequest \
|
||||
EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \
|
||||
EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial
|
||||
EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial \
|
||||
AttestationDelete
|
||||
|
||||
ifeq ($(BITCOIN_ONLY), 1)
|
||||
SKIPPED_MESSAGES += Ethereum NEM Stellar
|
||||
|
@ -299,6 +299,13 @@ def tutorial(client: "TrezorClient") -> str:
|
||||
return device.show_device_tutorial(client)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@with_client
|
||||
def attestation_delete(client: "TrezorClient") -> str:
|
||||
"""Delete device attestation. Irreversible."""
|
||||
return device.attestation_delete(client)
|
||||
|
||||
|
||||
@cli.command()
|
||||
@click.argument("enable", type=ChoiceType({"on": True, "off": False}), required=False)
|
||||
@click.option(
|
||||
|
@ -248,6 +248,12 @@ def show_device_tutorial(client: "TrezorClient") -> "MessageType":
|
||||
return client.call(messages.ShowDeviceTutorial())
|
||||
|
||||
|
||||
@session
|
||||
@expect(messages.Success, field="message", ret_type=str)
|
||||
def attestation_delete(client: "TrezorClient") -> "MessageType":
|
||||
return client.call(messages.AttestationDelete())
|
||||
|
||||
|
||||
@expect(messages.Success, field="message", ret_type=str)
|
||||
@session
|
||||
def set_busy(client: "TrezorClient", expiry_ms: Optional[int]) -> "MessageType":
|
||||
|
@ -47,6 +47,7 @@ def _transform_vendor_trust(data: bytes) -> bytes:
|
||||
|
||||
|
||||
class VendorTrust(Struct):
|
||||
allow_run_with_secret: bool
|
||||
show_vendor_string: bool
|
||||
require_user_click: bool
|
||||
red_background: bool
|
||||
@ -56,7 +57,8 @@ class VendorTrust(Struct):
|
||||
|
||||
SUBCON = c.Transformed(
|
||||
c.BitStruct(
|
||||
"_reserved" / c.Default(c.BitsInteger(9), 0),
|
||||
"_reserved" / c.Default(c.BitsInteger(8), 0),
|
||||
"allow_run_with_secret" / c.Flag,
|
||||
"show_vendor_string" / c.Flag,
|
||||
"require_user_click" / c.Flag,
|
||||
"red_background" / c.Flag,
|
||||
|
@ -72,6 +72,7 @@ class MessageType(IntEnum):
|
||||
UnlockPath = 93
|
||||
UnlockedPathRequest = 94
|
||||
ShowDeviceTutorial = 95
|
||||
AttestationDelete = 96
|
||||
SetU2FCounter = 63
|
||||
GetNextU2FCounter = 80
|
||||
NextU2FCounter = 81
|
||||
@ -3737,6 +3738,10 @@ class ShowDeviceTutorial(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 95
|
||||
|
||||
|
||||
class AttestationDelete(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 96
|
||||
|
||||
|
||||
class DebugLinkDecision(protobuf.MessageType):
|
||||
MESSAGE_WIRE_TYPE = 100
|
||||
FIELDS = {
|
||||
|
Loading…
Reference in New Issue
Block a user