diff --git a/common/protob/messages-management.proto b/common/protob/messages-management.proto index 0caa98320..e3d933880 100644 --- a/common/protob/messages-management.proto +++ b/common/protob/messages-management.proto @@ -516,3 +516,12 @@ message UnlockedPathRequest { */ message ShowDeviceTutorial { } + +/** + * Request: Delete attestation from the device, !irreversible! + * @start + * @next Success + * @next Failure + */ +message AttestationDelete { +} diff --git a/common/protob/messages.proto b/common/protob/messages.proto index dd8119141..71c2b582a 100644 --- a/common/protob/messages.proto +++ b/common/protob/messages.proto @@ -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]; diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 0eaf184e6..bb6f685a4 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -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 = [] diff --git a/core/SConscript.bootloader_emu b/core/SConscript.bootloader_emu index 0f8ea3eb8..025ea3f5a 100644 --- a/core/SConscript.bootloader_emu +++ b/core/SConscript.bootloader_emu @@ -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 = [ diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index a1be842ae..e679bca12 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -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 = [] diff --git a/core/embed/bootloader/main.c b/core/embed/bootloader/main.c index a33c67b78..6f6474087 100644 --- a/core/embed/bootloader/main.c +++ b/core/embed/bootloader/main.c @@ -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) { diff --git a/core/embed/bootloader/version.h b/core/embed/bootloader/version.h index 79d0537d9..4a109a2ca 100644 --- a/core/embed/bootloader/version.h +++ b/core/embed/bootloader/version.h @@ -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 diff --git a/core/embed/firmware/main.c b/core/embed/firmware/main.c index dca0931a1..7674d0fff 100644 --- a/core/embed/firmware/main.c +++ b/core/embed/firmware/main.c @@ -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 diff --git a/core/embed/lib/image.h b/core/embed/lib/image.h index ce31fc87e..b26d00c63 100644 --- a/core/embed/lib/image.h +++ b/core/embed/lib/image.h @@ -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 { diff --git a/core/embed/models/layout_common.h b/core/embed/models/layout_common.h index a7d464465..57f12ff34 100644 --- a/core/embed/models/layout_common.h +++ b/core/embed/models/layout_common.h @@ -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; diff --git a/core/embed/models/model_T2B1_layout.c b/core/embed/models/model_T2B1_layout.c deleted file mode 120000 index e68955d8d..000000000 --- a/core/embed/models/model_T2B1_layout.c +++ /dev/null @@ -1 +0,0 @@ -model_T2T1_layout.c \ No newline at end of file diff --git a/core/embed/models/model_T2B1_layout.c b/core/embed/models/model_T2B1_layout.c new file mode 100644 index 000000000..478a89aa9 --- /dev/null +++ b/core/embed/models/model_T2B1_layout.c @@ -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, + }, +}; diff --git a/core/embed/prodtest/main.c b/core/embed/prodtest/main.c index 1c63fbe81..c753a3d39 100644 --- a/core/embed/prodtest/main.c +++ b/core/embed/prodtest/main.c @@ -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")) { diff --git a/core/embed/trezorhal/mpu.h b/core/embed/trezorhal/mpu.h index 9d30af77b..11db67559 100644 --- a/core/embed/trezorhal/mpu.h +++ b/core/embed/trezorhal/mpu.h @@ -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 diff --git a/core/embed/trezorhal/secret.h b/core/embed/trezorhal/secret.h new file mode 100644 index 000000000..a5a8be8ef --- /dev/null +++ b/core/embed/trezorhal/secret.h @@ -0,0 +1,18 @@ + +#include +#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); diff --git a/core/embed/trezorhal/stm32f4/mpu.c b/core/embed/trezorhal/stm32f4/mpu.c index 75fa6916b..680252266 100644 --- a/core/embed/trezorhal/stm32f4/mpu.c +++ b/core/embed/trezorhal/stm32f4/mpu.c @@ -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"); +} diff --git a/core/embed/trezorhal/stm32f4/platform.c b/core/embed/trezorhal/stm32f4/platform.c index e2dd41a95..2624a7746 100644 --- a/core/embed/trezorhal/stm32f4/platform.c +++ b/core/embed/trezorhal/stm32f4/platform.c @@ -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); diff --git a/core/embed/trezorhal/stm32f4/platform.h b/core/embed/trezorhal/stm32f4/platform.h index 9af69c2df..d41af2d43 100644 --- a/core/embed/trezorhal/stm32f4/platform.h +++ b/core/embed/trezorhal/stm32f4/platform.h @@ -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; diff --git a/core/embed/trezorhal/stm32f4/secret.c b/core/embed/trezorhal/stm32f4/secret.c new file mode 100644 index 000000000..d8d032dec --- /dev/null +++ b/core/embed/trezorhal/stm32f4/secret.c @@ -0,0 +1,59 @@ +#include "secret.h" +#include +#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"); +} diff --git a/core/embed/trezorhal/unix/secret.c b/core/embed/trezorhal/unix/secret.c new file mode 100644 index 000000000..24fee45f9 --- /dev/null +++ b/core/embed/trezorhal/unix/secret.c @@ -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) {} diff --git a/core/embed/vendorheader/D001/vendor_unsafe.json b/core/embed/vendorheader/D001/vendor_unsafe.json index 32bd4b1cc..16a223e52 100644 --- a/core/embed/vendorheader/D001/vendor_unsafe.json +++ b/core/embed/vendorheader/D001/vendor_unsafe.json @@ -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, diff --git a/core/embed/vendorheader/T2B1/vendor_prodtest.json b/core/embed/vendorheader/T2B1/vendor_prodtest.json new file mode 100644 index 000000000..3a561ef35 --- /dev/null +++ b/core/embed/vendorheader/T2B1/vendor_prodtest.json @@ -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" + ] +} diff --git a/core/embed/vendorheader/T2B1/vendor_prodtest.toif b/core/embed/vendorheader/T2B1/vendor_prodtest.toif new file mode 100644 index 000000000..8c25f0ddd Binary files /dev/null and b/core/embed/vendorheader/T2B1/vendor_prodtest.toif differ diff --git a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json b/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json index 77aa81286..325e759e8 100644 --- a/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json +++ b/core/embed/vendorheader/T2B1/vendor_qa_DO_NOT_SIGN.json @@ -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, diff --git a/core/embed/vendorheader/T2B1/vendor_satoshilabs.json b/core/embed/vendorheader/T2B1/vendor_satoshilabs.json index d4aeaa389..7dc70d901 100644 --- a/core/embed/vendorheader/T2B1/vendor_satoshilabs.json +++ b/core/embed/vendorheader/T2B1/vendor_satoshilabs.json @@ -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, diff --git a/core/embed/vendorheader/T2B1/vendor_unsafe.json b/core/embed/vendorheader/T2B1/vendor_unsafe.json index 41699ae41..dc1159f26 100644 --- a/core/embed/vendorheader/T2B1/vendor_unsafe.json +++ b/core/embed/vendorheader/T2B1/vendor_unsafe.json @@ -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, diff --git a/core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin b/core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin new file mode 100644 index 000000000..e003fbe67 Binary files /dev/null and b/core/embed/vendorheader/T2B1/vendorheader_prodtest_unsigned.bin differ diff --git a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin b/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin index fac4d1b46..f0fcd329d 100644 Binary files a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin and b/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_signed_dev.bin differ diff --git a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin b/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin index 5c4a762e5..4e17570bc 100644 Binary files a/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin and b/core/embed/vendorheader/T2B1/vendorheader_qa_DO_NOT_SIGN_unsigned.bin differ diff --git a/core/embed/vendorheader/T2B1/vendorheader_satoshilabs_unsigned.bin b/core/embed/vendorheader/T2B1/vendorheader_satoshilabs_unsigned.bin index c59fed81a..0c3622d04 100644 Binary files a/core/embed/vendorheader/T2B1/vendorheader_satoshilabs_unsigned.bin and b/core/embed/vendorheader/T2B1/vendorheader_satoshilabs_unsigned.bin differ diff --git a/core/embed/vendorheader/T2T1/vendor_prodtest.json b/core/embed/vendorheader/T2T1/vendor_prodtest.json index ca4d021e1..1d3a36686 100644 --- a/core/embed/vendorheader/T2T1/vendor_prodtest.json +++ b/core/embed/vendorheader/T2T1/vendor_prodtest.json @@ -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, diff --git a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json b/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json index cbd85714b..6fab49ebb 100644 --- a/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json +++ b/core/embed/vendorheader/T2T1/vendor_qa_DO_NOT_SIGN.json @@ -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, diff --git a/core/embed/vendorheader/T2T1/vendor_satoshilabs.json b/core/embed/vendorheader/T2T1/vendor_satoshilabs.json index 9e40a08d6..59dbf90cb 100644 --- a/core/embed/vendorheader/T2T1/vendor_satoshilabs.json +++ b/core/embed/vendorheader/T2T1/vendor_satoshilabs.json @@ -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, diff --git a/core/embed/vendorheader/T2T1/vendor_unsafe.json b/core/embed/vendorheader/T2T1/vendor_unsafe.json index 54e8ce9db..7d266f28d 100644 --- a/core/embed/vendorheader/T2T1/vendor_unsafe.json +++ b/core/embed/vendorheader/T2T1/vendor_unsafe.json @@ -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, diff --git a/core/site_scons/boards/trezor_r_v10.py b/core/site_scons/boards/trezor_r_v10.py index d3ad10089..fa704d94b 100644 --- a/core/site_scons/boards/trezor_r_v10.py +++ b/core/site_scons/boards/trezor_r_v10.py @@ -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 diff --git a/core/src/trezor/enums/MessageType.py b/core/src/trezor/enums/MessageType.py index 75b9228f0..027eb82f6 100644 --- a/core/src/trezor/enums/MessageType.py +++ b/core/src/trezor/enums/MessageType.py @@ -47,6 +47,7 @@ FirmwareHash = 89 UnlockPath = 93 UnlockedPathRequest = 94 ShowDeviceTutorial = 95 +AttestationDelete = 96 FirmwareErase = 6 FirmwareUpload = 7 FirmwareRequest = 8 diff --git a/core/src/trezor/enums/__init__.py b/core/src/trezor/enums/__init__.py index e562b556f..d528c7de5 100644 --- a/core/src/trezor/enums/__init__.py +++ b/core/src/trezor/enums/__init__.py @@ -64,6 +64,7 @@ if TYPE_CHECKING: UnlockPath = 93 UnlockedPathRequest = 94 ShowDeviceTutorial = 95 + AttestationDelete = 96 SetU2FCounter = 63 GetNextU2FCounter = 80 NextU2FCounter = 81 diff --git a/core/src/trezor/messages.py b/core/src/trezor/messages.py index f111e2375..768432c0c 100644 --- a/core/src/trezor/messages.py +++ b/core/src/trezor/messages.py @@ -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" diff --git a/legacy/firmware/protob/Makefile b/legacy/firmware/protob/Makefile index 35cad8d0f..cca46f500 100644 --- a/legacy/firmware/protob/Makefile +++ b/legacy/firmware/protob/Makefile @@ -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 diff --git a/python/src/trezorlib/cli/device.py b/python/src/trezorlib/cli/device.py index be38a7d87..92c920721 100644 --- a/python/src/trezorlib/cli/device.py +++ b/python/src/trezorlib/cli/device.py @@ -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( diff --git a/python/src/trezorlib/device.py b/python/src/trezorlib/device.py index 87fde1755..51147438a 100644 --- a/python/src/trezorlib/device.py +++ b/python/src/trezorlib/device.py @@ -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": diff --git a/python/src/trezorlib/firmware/vendor.py b/python/src/trezorlib/firmware/vendor.py index a9fd0ebce..d4314d6d7 100644 --- a/python/src/trezorlib/firmware/vendor.py +++ b/python/src/trezorlib/firmware/vendor.py @@ -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, diff --git a/python/src/trezorlib/messages.py b/python/src/trezorlib/messages.py index 2d6926b4c..d948822ad 100644 --- a/python/src/trezorlib/messages.py +++ b/python/src/trezorlib/messages.py @@ -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 = {