mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-22 07:28:10 +00:00
feat(core): implement secret handling in bootloader
This commit is contained in:
parent
58bb702498
commit
e8281385f6
@ -516,3 +516,12 @@ message UnlockedPathRequest {
|
|||||||
*/
|
*/
|
||||||
message ShowDeviceTutorial {
|
message ShowDeviceTutorial {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Unlocks bootloader, !irreversible!
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message UnlockBootloader {
|
||||||
|
}
|
||||||
|
@ -121,6 +121,7 @@ enum MessageType {
|
|||||||
MessageType_UnlockPath = 93 [(bitcoin_only) = true, (wire_in) = true];
|
MessageType_UnlockPath = 93 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
MessageType_UnlockedPathRequest = 94 [(bitcoin_only) = true, (wire_out) = true];
|
MessageType_UnlockedPathRequest = 94 [(bitcoin_only) = true, (wire_out) = true];
|
||||||
MessageType_ShowDeviceTutorial = 95 [(bitcoin_only) = true, (wire_in) = true];
|
MessageType_ShowDeviceTutorial = 95 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
MessageType_UnlockBootloader = 96 [(bitcoin_only) = true, (wire_in) = true];
|
||||||
|
|
||||||
MessageType_SetU2FCounter = 63 [(wire_in) = true];
|
MessageType_SetU2FCounter = 63 [(wire_in) = true];
|
||||||
MessageType_GetNextU2FCounter = 80 [(wire_in) = true];
|
MessageType_GetNextU2FCounter = 80 [(wire_in) = true];
|
||||||
|
@ -20,7 +20,7 @@ if TREZOR_MODEL in ('1', ):
|
|||||||
)
|
)
|
||||||
Return()
|
Return()
|
||||||
|
|
||||||
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb"]
|
FEATURES_WANTED = ["input", "rgb_led", "consumption_mask", "usb", "optiga"]
|
||||||
|
|
||||||
CCFLAGS_MOD = ''
|
CCFLAGS_MOD = ''
|
||||||
CPPPATH_MOD = []
|
CPPPATH_MOD = []
|
||||||
|
@ -92,6 +92,20 @@ SOURCE_MOD += [
|
|||||||
'vendor/trezor-storage/flash_common.c',
|
'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 = [
|
SOURCE_NANOPB = [
|
||||||
'vendor/nanopb/pb_common.c',
|
'vendor/nanopb/pb_common.c',
|
||||||
'vendor/nanopb/pb_decode.c',
|
'vendor/nanopb/pb_decode.c',
|
||||||
@ -114,6 +128,7 @@ SOURCE_TREZORHAL = [
|
|||||||
'embed/trezorhal/unix/rng.c',
|
'embed/trezorhal/unix/rng.c',
|
||||||
'embed/trezorhal/unix/usb.c',
|
'embed/trezorhal/unix/usb.c',
|
||||||
'embed/trezorhal/unix/random_delays.c',
|
'embed/trezorhal/unix/random_delays.c',
|
||||||
|
'embed/trezorhal/unix/secret.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCE_UNIX = [
|
SOURCE_UNIX = [
|
||||||
|
@ -17,7 +17,7 @@ if TREZOR_MODEL in ('DISC1', ):
|
|||||||
action=build_prodtest)
|
action=build_prodtest)
|
||||||
Return()
|
Return()
|
||||||
|
|
||||||
FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb"]
|
FEATURES_WANTED = ["input", "sbu", "sd_card", "rdb_led", "usb", "consumption_mask", "optiga"]
|
||||||
|
|
||||||
CCFLAGS_MOD = ''
|
CCFLAGS_MOD = ''
|
||||||
CPPPATH_MOD = []
|
CPPPATH_MOD = []
|
||||||
|
1
core/embed/bootloader/.changelog.d/+14e1ae91.added
Normal file
1
core/embed/bootloader/.changelog.d/+14e1ae91.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Locked bootloader support: bootloader will disallow installation of unofficial firmware unless the Optiga pairing secret is erased.
|
1
core/embed/bootloader/.changelog.d/+95c27be5.added
Normal file
1
core/embed/bootloader/.changelog.d/+95c27be5.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
Support unlocking the bootloader via `UnlockBootloader` message.
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include TREZOR_BOARD
|
||||||
|
|
||||||
#include "bootui.h"
|
#include "bootui.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#ifdef TREZOR_EMULATOR
|
#ifdef TREZOR_EMULATOR
|
||||||
@ -233,6 +235,12 @@ void ui_screen_boot_empty(bool fading) { screen_boot_empty(fading); }
|
|||||||
// error UI
|
// error UI
|
||||||
void ui_screen_fail(void) { screen_install_fail(); }
|
void ui_screen_fail(void) { screen_install_fail(); }
|
||||||
|
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
uint32_t ui_screen_unlock_bootloader_confirm(void) {
|
||||||
|
return screen_unlock_bootloader_confirm();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// general functions
|
// general functions
|
||||||
|
|
||||||
void ui_fadein(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); }
|
void ui_fadein(void) { display_fade(0, BACKLIGHT_NORMAL, 1000); }
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
#include "stdbool.h"
|
#include "stdbool.h"
|
||||||
|
#include TREZOR_BOARD
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SCREEN_INTRO = 0,
|
SCREEN_INTRO = 0,
|
||||||
@ -68,6 +69,10 @@ void ui_set_initial_setup(bool initial);
|
|||||||
|
|
||||||
void ui_screen_boot_empty(bool fading);
|
void ui_screen_boot_empty(bool fading);
|
||||||
|
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
uint32_t ui_screen_unlock_bootloader_confirm(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
#define INPUT_CANCEL 0x01 // Cancel button
|
#define INPUT_CANCEL 0x01 // Cancel button
|
||||||
#define INPUT_CONFIRM 0x02 // Confirm button
|
#define INPUT_CONFIRM 0x02 // Confirm button
|
||||||
|
@ -24,8 +24,10 @@
|
|||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
|
#include "messages.pb.h"
|
||||||
#include "random_delays.h"
|
#include "random_delays.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "secret.h"
|
||||||
|
|
||||||
#ifdef USE_DMA2D
|
#ifdef USE_DMA2D
|
||||||
#include "dma2d.h"
|
#include "dma2d.h"
|
||||||
@ -149,13 +151,13 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (msg_id) {
|
switch (msg_id) {
|
||||||
case 0: // Initialize
|
case MessageType_MessageType_Initialize:
|
||||||
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
process_msg_Initialize(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
||||||
break;
|
break;
|
||||||
case 1: // Ping
|
case MessageType_MessageType_Ping:
|
||||||
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
|
process_msg_Ping(USB_IFACE_NUM, msg_size, buf);
|
||||||
break;
|
break;
|
||||||
case 5: // WipeDevice
|
case MessageType_MessageType_WipeDevice:
|
||||||
response = ui_screen_wipe_confirm();
|
response = ui_screen_wipe_confirm();
|
||||||
if (INPUT_CANCEL == response) {
|
if (INPUT_CANCEL == response) {
|
||||||
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
|
send_user_abort(USB_IFACE_NUM, "Wipe cancelled");
|
||||||
@ -180,10 +182,10 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
|
|||||||
return SHUTDOWN;
|
return SHUTDOWN;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 6: // FirmwareErase
|
case MessageType_MessageType_FirmwareErase:
|
||||||
process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf);
|
process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf);
|
||||||
break;
|
break;
|
||||||
case 7: // FirmwareUpload
|
case MessageType_MessageType_FirmwareUpload:
|
||||||
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
||||||
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
||||||
ui_screen_fail();
|
ui_screen_fail();
|
||||||
@ -210,9 +212,27 @@ static usb_result_t bootloader_usb_loop(const vendor_header *const vhdr,
|
|||||||
return CONTINUE;
|
return CONTINUE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 55: // GetFeatures
|
case MessageType_MessageType_GetFeatures:
|
||||||
process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
process_msg_GetFeatures(USB_IFACE_NUM, msg_size, buf, vhdr, hdr);
|
||||||
break;
|
break;
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
case MessageType_MessageType_UnlockBootloader:
|
||||||
|
response = ui_screen_unlock_bootloader_confirm();
|
||||||
|
if (INPUT_CANCEL == response) {
|
||||||
|
send_user_abort(USB_IFACE_NUM, "Bootloader unlock cancelled");
|
||||||
|
hal_delay(100);
|
||||||
|
usb_stop();
|
||||||
|
usb_deinit();
|
||||||
|
return RETURN;
|
||||||
|
}
|
||||||
|
process_msg_AttestationDelete(USB_IFACE_NUM, msg_size, buf);
|
||||||
|
screen_unlock_bootloader_success();
|
||||||
|
hal_delay(100);
|
||||||
|
usb_stop();
|
||||||
|
usb_deinit();
|
||||||
|
return SHUTDOWN;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
process_msg_unknown(USB_IFACE_NUM, msg_size, buf);
|
process_msg_unknown(USB_IFACE_NUM, msg_size, buf);
|
||||||
break;
|
break;
|
||||||
@ -522,8 +542,20 @@ int bootloader_main(void) {
|
|||||||
&FIRMWARE_AREA),
|
&FIRMWARE_AREA),
|
||||||
"Firmware is corrupted");
|
"Firmware is corrupted");
|
||||||
|
|
||||||
// if all VTRUST flags are unset = ultimate trust => skip the procedure
|
#ifdef USE_OPTIGA
|
||||||
|
if (((vhdr.vtrust & VTRUST_SECRET) != 0) && (sectrue != secret_wiped())) {
|
||||||
|
display_clear();
|
||||||
|
screen_fatal_error_rust(
|
||||||
|
"INSTALL RESTRICTED",
|
||||||
|
"Installation of custom firmware is currently restricted.",
|
||||||
|
"Please visit\ntrezor.io/bootloader");
|
||||||
|
|
||||||
|
display_refresh();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// if all VTRUST flags are unset = ultimate trust => skip the procedure
|
||||||
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
|
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
|
||||||
ui_fadeout();
|
ui_fadeout();
|
||||||
ui_screen_boot(&vhdr, hdr);
|
ui_screen_boot(&vhdr, hdr);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "flash.h"
|
#include "flash.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include "secret.h"
|
||||||
#include "unit_variant.h"
|
#include "unit_variant.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
@ -572,6 +573,16 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
|||||||
&should_keep_seed, &is_newvendor);
|
&should_keep_seed, &is_newvendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
if (sectrue != secret_wiped() && ((vhdr.vtrust & VTRUST_SECRET) != 0)) {
|
||||||
|
MSG_SEND_INIT(Failure);
|
||||||
|
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||||
|
MSG_SEND_ASSIGN_STRING(message, "Attestation present");
|
||||||
|
MSG_SEND(Failure);
|
||||||
|
return UPLOAD_ERR_ATTESTATION_PRESENT;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t response = INPUT_CANCEL;
|
uint32_t response = INPUT_CANCEL;
|
||||||
if (sectrue == is_new) {
|
if (sectrue == is_new) {
|
||||||
// new installation - auto confirm
|
// new installation - auto confirm
|
||||||
@ -722,3 +733,12 @@ void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
|||||||
MSG_SEND_ASSIGN_STRING(message, "Unexpected message");
|
MSG_SEND_ASSIGN_STRING(message, "Unexpected message");
|
||||||
MSG_SEND(Failure);
|
MSG_SEND(Failure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
void process_msg_AttestationDelete(uint8_t iface_num, uint32_t msg_size,
|
||||||
|
uint8_t *buf) {
|
||||||
|
secret_erase();
|
||||||
|
MSG_SEND_INIT(Success);
|
||||||
|
MSG_SEND(Success);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "secbool.h"
|
#include "secbool.h"
|
||||||
|
#include TREZOR_BOARD
|
||||||
|
|
||||||
#define USB_TIMEOUT 500
|
#define USB_TIMEOUT 500
|
||||||
#define USB_PACKET_SIZE 64
|
#define USB_PACKET_SIZE 64
|
||||||
@ -40,6 +41,7 @@ enum {
|
|||||||
UPLOAD_ERR_USER_ABORT = -7,
|
UPLOAD_ERR_USER_ABORT = -7,
|
||||||
UPLOAD_ERR_FIRMWARE_TOO_BIG = -8,
|
UPLOAD_ERR_FIRMWARE_TOO_BIG = -8,
|
||||||
UPLOAD_ERR_INVALID_CHUNK_HASH = -9,
|
UPLOAD_ERR_INVALID_CHUNK_HASH = -9,
|
||||||
|
UPLOAD_ERR_ATTESTATION_PRESENT = -10,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -66,6 +68,11 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
|||||||
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
||||||
void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
void process_msg_unknown(uint8_t iface_num, uint32_t msg_size, uint8_t *buf);
|
||||||
|
|
||||||
|
#ifdef USE_OPTIGA
|
||||||
|
void process_msg_AttestationDelete(uint8_t iface_num, uint32_t msg_size,
|
||||||
|
uint8_t *buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
secbool bootloader_WipeDevice(void);
|
secbool bootloader_WipeDevice(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -39,6 +39,9 @@ PB_BIND(FirmwareRequest, FirmwareRequest, AUTO)
|
|||||||
PB_BIND(FirmwareUpload, FirmwareUpload, AUTO)
|
PB_BIND(FirmwareUpload, FirmwareUpload, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
PB_BIND(UnlockBootloader, UnlockBootloader, AUTO)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,13 +15,15 @@ typedef enum _MessageType {
|
|||||||
MessageType_MessageType_Ping = 1,
|
MessageType_MessageType_Ping = 1,
|
||||||
MessageType_MessageType_Success = 2,
|
MessageType_MessageType_Success = 2,
|
||||||
MessageType_MessageType_Failure = 3,
|
MessageType_MessageType_Failure = 3,
|
||||||
|
MessageType_MessageType_WipeDevice = 5,
|
||||||
MessageType_MessageType_FirmwareErase = 6,
|
MessageType_MessageType_FirmwareErase = 6,
|
||||||
MessageType_MessageType_FirmwareUpload = 7,
|
MessageType_MessageType_FirmwareUpload = 7,
|
||||||
MessageType_MessageType_FirmwareRequest = 8,
|
MessageType_MessageType_FirmwareRequest = 8,
|
||||||
MessageType_MessageType_Features = 17,
|
MessageType_MessageType_Features = 17,
|
||||||
MessageType_MessageType_ButtonRequest = 26,
|
MessageType_MessageType_ButtonRequest = 26,
|
||||||
MessageType_MessageType_ButtonAck = 27,
|
MessageType_MessageType_ButtonAck = 27,
|
||||||
MessageType_MessageType_GetFeatures = 55
|
MessageType_MessageType_GetFeatures = 55,
|
||||||
|
MessageType_MessageType_UnlockBootloader = 96
|
||||||
} MessageType;
|
} MessageType;
|
||||||
|
|
||||||
typedef enum _FailureType {
|
typedef enum _FailureType {
|
||||||
@ -48,6 +50,10 @@ typedef struct _Initialize {
|
|||||||
char dummy_field;
|
char dummy_field;
|
||||||
} Initialize;
|
} Initialize;
|
||||||
|
|
||||||
|
typedef struct _UnlockBootloader {
|
||||||
|
char dummy_field;
|
||||||
|
} UnlockBootloader;
|
||||||
|
|
||||||
typedef struct _ButtonRequest {
|
typedef struct _ButtonRequest {
|
||||||
bool has_code;
|
bool has_code;
|
||||||
ButtonRequestType code;
|
ButtonRequestType code;
|
||||||
@ -129,8 +135,8 @@ typedef struct _Success {
|
|||||||
|
|
||||||
/* Helper constants for enums */
|
/* Helper constants for enums */
|
||||||
#define _MessageType_MIN MessageType_MessageType_Initialize
|
#define _MessageType_MIN MessageType_MessageType_Initialize
|
||||||
#define _MessageType_MAX MessageType_MessageType_GetFeatures
|
#define _MessageType_MAX MessageType_MessageType_UnlockBootloader
|
||||||
#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_GetFeatures+1))
|
#define _MessageType_ARRAYSIZE ((MessageType)(MessageType_MessageType_UnlockBootloader+1))
|
||||||
|
|
||||||
#define _FailureType_MIN FailureType_Failure_UnexpectedMessage
|
#define _FailureType_MIN FailureType_Failure_UnexpectedMessage
|
||||||
#define _FailureType_MAX FailureType_Failure_ProcessError
|
#define _FailureType_MAX FailureType_Failure_ProcessError
|
||||||
@ -157,6 +163,7 @@ extern "C" {
|
|||||||
#define FirmwareErase_init_default {false, 0}
|
#define FirmwareErase_init_default {false, 0}
|
||||||
#define FirmwareRequest_init_default {0, 0}
|
#define FirmwareRequest_init_default {0, 0}
|
||||||
#define FirmwareUpload_init_default {{{NULL}, NULL}, false, {0, {0}}}
|
#define FirmwareUpload_init_default {{{NULL}, NULL}, false, {0, {0}}}
|
||||||
|
#define UnlockBootloader_init_default {0}
|
||||||
#define Initialize_init_zero {0}
|
#define Initialize_init_zero {0}
|
||||||
#define GetFeatures_init_zero {0}
|
#define GetFeatures_init_zero {0}
|
||||||
#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0}
|
#define Features_init_zero {false, "", 0, 0, 0, false, 0, false, "", false, "", false, "", false, 0, false, {0, {0}}, false, 0, false, "", false, 0, false, 0, false, 0, false, "", false, "", false, 0, false, 0}
|
||||||
@ -168,6 +175,7 @@ extern "C" {
|
|||||||
#define FirmwareErase_init_zero {false, 0}
|
#define FirmwareErase_init_zero {false, 0}
|
||||||
#define FirmwareRequest_init_zero {0, 0}
|
#define FirmwareRequest_init_zero {0, 0}
|
||||||
#define FirmwareUpload_init_zero {{{NULL}, NULL}, false, {0, {0}}}
|
#define FirmwareUpload_init_zero {{{NULL}, NULL}, false, {0, {0}}}
|
||||||
|
#define UnlockBootloader_init_zero {0}
|
||||||
|
|
||||||
/* Field tags (for use in manual encoding/decoding) */
|
/* Field tags (for use in manual encoding/decoding) */
|
||||||
#define ButtonRequest_code_tag 1
|
#define ButtonRequest_code_tag 1
|
||||||
@ -277,6 +285,11 @@ X(a, STATIC, OPTIONAL, BYTES, hash, 2)
|
|||||||
#define FirmwareUpload_CALLBACK pb_default_field_callback
|
#define FirmwareUpload_CALLBACK pb_default_field_callback
|
||||||
#define FirmwareUpload_DEFAULT NULL
|
#define FirmwareUpload_DEFAULT NULL
|
||||||
|
|
||||||
|
#define UnlockBootloader_FIELDLIST(X, a) \
|
||||||
|
|
||||||
|
#define UnlockBootloader_CALLBACK NULL
|
||||||
|
#define UnlockBootloader_DEFAULT NULL
|
||||||
|
|
||||||
extern const pb_msgdesc_t Initialize_msg;
|
extern const pb_msgdesc_t Initialize_msg;
|
||||||
extern const pb_msgdesc_t GetFeatures_msg;
|
extern const pb_msgdesc_t GetFeatures_msg;
|
||||||
extern const pb_msgdesc_t Features_msg;
|
extern const pb_msgdesc_t Features_msg;
|
||||||
@ -288,6 +301,7 @@ extern const pb_msgdesc_t ButtonAck_msg;
|
|||||||
extern const pb_msgdesc_t FirmwareErase_msg;
|
extern const pb_msgdesc_t FirmwareErase_msg;
|
||||||
extern const pb_msgdesc_t FirmwareRequest_msg;
|
extern const pb_msgdesc_t FirmwareRequest_msg;
|
||||||
extern const pb_msgdesc_t FirmwareUpload_msg;
|
extern const pb_msgdesc_t FirmwareUpload_msg;
|
||||||
|
extern const pb_msgdesc_t UnlockBootloader_msg;
|
||||||
|
|
||||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||||
#define Initialize_fields &Initialize_msg
|
#define Initialize_fields &Initialize_msg
|
||||||
@ -301,6 +315,7 @@ extern const pb_msgdesc_t FirmwareUpload_msg;
|
|||||||
#define FirmwareErase_fields &FirmwareErase_msg
|
#define FirmwareErase_fields &FirmwareErase_msg
|
||||||
#define FirmwareRequest_fields &FirmwareRequest_msg
|
#define FirmwareRequest_fields &FirmwareRequest_msg
|
||||||
#define FirmwareUpload_fields &FirmwareUpload_msg
|
#define FirmwareUpload_fields &FirmwareUpload_msg
|
||||||
|
#define UnlockBootloader_fields &UnlockBootloader_msg
|
||||||
|
|
||||||
/* Maximum encoded size of messages (where known) */
|
/* Maximum encoded size of messages (where known) */
|
||||||
/* FirmwareUpload_size depends on runtime parameters */
|
/* FirmwareUpload_size depends on runtime parameters */
|
||||||
@ -314,6 +329,7 @@ extern const pb_msgdesc_t FirmwareUpload_msg;
|
|||||||
#define Initialize_size 0
|
#define Initialize_size 0
|
||||||
#define Ping_size 258
|
#define Ping_size 258
|
||||||
#define Success_size 258
|
#define Success_size 258
|
||||||
|
#define UnlockBootloader_size 0
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
|
@ -9,6 +9,7 @@ enum MessageType {
|
|||||||
MessageType_Ping = 1;
|
MessageType_Ping = 1;
|
||||||
MessageType_Success = 2;
|
MessageType_Success = 2;
|
||||||
MessageType_Failure = 3;
|
MessageType_Failure = 3;
|
||||||
|
MessageType_WipeDevice = 5;
|
||||||
MessageType_FirmwareErase = 6;
|
MessageType_FirmwareErase = 6;
|
||||||
MessageType_FirmwareUpload = 7;
|
MessageType_FirmwareUpload = 7;
|
||||||
MessageType_FirmwareRequest = 8;
|
MessageType_FirmwareRequest = 8;
|
||||||
@ -16,6 +17,7 @@ enum MessageType {
|
|||||||
MessageType_ButtonRequest = 26;
|
MessageType_ButtonRequest = 26;
|
||||||
MessageType_ButtonAck = 27;
|
MessageType_ButtonAck = 27;
|
||||||
MessageType_GetFeatures = 55;
|
MessageType_GetFeatures = 55;
|
||||||
|
MessageType_UnlockBootloader = 96;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -143,3 +145,12 @@ message FirmwareUpload {
|
|||||||
required bytes payload = 1; // firmware to be loaded into device
|
required bytes payload = 1; // firmware to be loaded into device
|
||||||
optional bytes hash = 2; // hash of the payload
|
optional bytes hash = 2; // hash of the payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request: Unlock bootloader, !irreversible!
|
||||||
|
* @start
|
||||||
|
* @next Success
|
||||||
|
* @next Failure
|
||||||
|
*/
|
||||||
|
message UnlockBootloader {
|
||||||
|
}
|
||||||
|
@ -11,4 +11,8 @@
|
|||||||
#define FIX_VERSION_PATCH 0
|
#define FIX_VERSION_PATCH 0
|
||||||
#define FIX_VERSION_BUILD 0
|
#define FIX_VERSION_BUILD 0
|
||||||
|
|
||||||
|
#ifdef TREZOR_MODEL_R
|
||||||
|
#define VERSION_MONOTONIC 2
|
||||||
|
#else
|
||||||
#define VERSION_MONOTONIC 1
|
#define VERSION_MONOTONIC 1
|
||||||
|
#endif
|
||||||
|
@ -165,10 +165,7 @@ int main(void) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined TREZOR_MODEL_1
|
#if !defined TREZOR_MODEL_1
|
||||||
// jump to unprivileged mode
|
drop_privileges();
|
||||||
// http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/CHDBIBGJ.html
|
|
||||||
__asm__ volatile("msr control, %0" ::"r"(0x1));
|
|
||||||
__asm__ volatile("isb");
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_SECP256K1_ZKP
|
#ifdef USE_SECP256K1_ZKP
|
||||||
|
@ -56,6 +56,8 @@ typedef struct {
|
|||||||
#define VTRUST_RED 0x0010
|
#define VTRUST_RED 0x0010
|
||||||
#define VTRUST_CLICK 0x0020
|
#define VTRUST_CLICK 0x0020
|
||||||
#define VTRUST_STRING 0x0040
|
#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)
|
#define VTRUST_ALL (VTRUST_WAIT | VTRUST_RED | VTRUST_CLICK | VTRUST_STRING)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT];
|
extern const flash_area_t STORAGE_AREAS[STORAGE_AREAS_COUNT];
|
||||||
extern const flash_area_t BOARDLOADER_AREA;
|
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 BOOTLOADER_AREA;
|
||||||
extern const flash_area_t FIRMWARE_AREA;
|
extern const flash_area_t FIRMWARE_AREA;
|
||||||
extern const flash_area_t WIPE_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,
|
||||||
|
},
|
||||||
|
};
|
@ -25,4 +25,6 @@ uint32_t screen_install_fail(void);
|
|||||||
void screen_welcome_model(void);
|
void screen_welcome_model(void);
|
||||||
void screen_welcome(void);
|
void screen_welcome(void);
|
||||||
void screen_boot_empty(bool fading);
|
void screen_boot_empty(bool fading);
|
||||||
|
uint32_t screen_unlock_bootloader_confirm(void);
|
||||||
|
void screen_unlock_bootloader_success(void);
|
||||||
void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen);
|
void display_image(int16_t x, int16_t y, const uint8_t* data, uint32_t datalen);
|
||||||
|
@ -858,9 +858,8 @@ pub fn marquee(area: Rect, text: &str, offset: i16, font: Font, fg: Color, bg: C
|
|||||||
pixeldata_dirty();
|
pixeldata_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used on T1 only.
|
pub fn dotted_line(start: Point, width: i16, color: Color, step: i16) {
|
||||||
pub fn dotted_line(start: Point, width: i16, color: Color) {
|
for x in (start.x..width).step_by(step as usize) {
|
||||||
for x in (start.x..width).step_by(2) {
|
|
||||||
display::bar(x, start.y, 1, 1, color.into());
|
display::bar(x, start.y, 1, 1, color.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ pub struct Confirm<'a> {
|
|||||||
buttons: ButtonController<&'static str>,
|
buttons: ButtonController<&'static str>,
|
||||||
/// Whether we are on the info screen (optional extra screen)
|
/// Whether we are on the info screen (optional extra screen)
|
||||||
showing_info_screen: bool,
|
showing_info_screen: bool,
|
||||||
|
two_btn_confirm: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Confirm<'a> {
|
impl<'a> Confirm<'a> {
|
||||||
@ -48,8 +49,10 @@ impl<'a> Confirm<'a> {
|
|||||||
message: Label<&'a str>,
|
message: Label<&'a str>,
|
||||||
alert: Option<Label<&'a str>>,
|
alert: Option<Label<&'a str>>,
|
||||||
button_text: &'static str,
|
button_text: &'static str,
|
||||||
|
two_btn_confirm: bool,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let btn_layout = Self::get_button_layout_general(false, button_text, false);
|
let btn_layout =
|
||||||
|
Self::get_button_layout_general(false, button_text, false, two_btn_confirm);
|
||||||
Self {
|
Self {
|
||||||
bg: Pad::with_background(bg_color).with_clear(),
|
bg: Pad::with_background(bg_color).with_clear(),
|
||||||
bg_color,
|
bg_color,
|
||||||
@ -61,6 +64,7 @@ impl<'a> Confirm<'a> {
|
|||||||
button_text,
|
button_text,
|
||||||
buttons: ButtonController::new(btn_layout),
|
buttons: ButtonController::new(btn_layout),
|
||||||
showing_info_screen: false,
|
showing_info_screen: false,
|
||||||
|
two_btn_confirm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +85,7 @@ impl<'a> Confirm<'a> {
|
|||||||
self.showing_info_screen,
|
self.showing_info_screen,
|
||||||
self.button_text,
|
self.button_text,
|
||||||
self.has_info_screen(),
|
self.has_info_screen(),
|
||||||
|
self.two_btn_confirm,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +94,14 @@ impl<'a> Confirm<'a> {
|
|||||||
showing_info_screen: bool,
|
showing_info_screen: bool,
|
||||||
button_text: &'static str,
|
button_text: &'static str,
|
||||||
has_info_screen: bool,
|
has_info_screen: bool,
|
||||||
|
two_btn_confirm: bool,
|
||||||
) -> ButtonLayout<&'static str> {
|
) -> ButtonLayout<&'static str> {
|
||||||
if showing_info_screen {
|
if showing_info_screen {
|
||||||
ButtonLayout::arrow_none_none()
|
ButtonLayout::arrow_none_none()
|
||||||
} else if has_info_screen {
|
} else if has_info_screen {
|
||||||
ButtonLayout::cancel_armed_info(button_text)
|
ButtonLayout::cancel_armed_info(button_text)
|
||||||
|
} else if two_btn_confirm {
|
||||||
|
ButtonLayout::cancel_armed_none(button_text)
|
||||||
} else {
|
} else {
|
||||||
ButtonLayout::cancel_none_text(button_text)
|
ButtonLayout::cancel_none_text(button_text)
|
||||||
}
|
}
|
||||||
@ -166,6 +174,14 @@ impl<'a> Component for Confirm<'a> {
|
|||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
|
} else if self.two_btn_confirm {
|
||||||
|
match msg {
|
||||||
|
Some(ButtonControllerMsg::Triggered(ButtonPos::Left)) => Some(ConfirmMsg::Cancel),
|
||||||
|
Some(ButtonControllerMsg::Triggered(ButtonPos::Middle)) => {
|
||||||
|
Some(ConfirmMsg::Confirm)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// There is just one main screen without info screen
|
// There is just one main screen without info screen
|
||||||
match msg {
|
match msg {
|
||||||
|
@ -150,7 +150,7 @@ extern "C" fn screen_install_confirm(
|
|||||||
theme::TEXT_NORMAL,
|
theme::TEXT_NORMAL,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut frame = Confirm::new(BLD_BG, title_str, message, alert, "INSTALL")
|
let mut frame = Confirm::new(BLD_BG, title_str, message, alert, "INSTALL", false)
|
||||||
.with_info_screen("FW FINGERPRINT", fingerprint);
|
.with_info_screen("FW FINGERPRINT", fingerprint);
|
||||||
run(&mut frame)
|
run(&mut frame)
|
||||||
}
|
}
|
||||||
@ -160,11 +160,32 @@ extern "C" fn screen_wipe_confirm() -> u32 {
|
|||||||
let message = Label::left_aligned("Seed and firmware will be erased!", theme::TEXT_NORMAL)
|
let message = Label::left_aligned("Seed and firmware will be erased!", theme::TEXT_NORMAL)
|
||||||
.vertically_centered();
|
.vertically_centered();
|
||||||
|
|
||||||
let mut frame = Confirm::new(BLD_BG, "FACTORY RESET", message, None, "RESET");
|
let mut frame = Confirm::new(BLD_BG, "FACTORY RESET", message, None, "RESET", false);
|
||||||
|
|
||||||
run(&mut frame)
|
run(&mut frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn screen_unlock_bootloader_confirm() -> u32 {
|
||||||
|
let message = Label::left_aligned("This action cannot be undone!", theme::TEXT_NORMAL)
|
||||||
|
.vertically_centered();
|
||||||
|
|
||||||
|
let mut frame = Confirm::new(BLD_BG, "UNLOCK BOOTLOADER?", message, None, "UNLOCK", true);
|
||||||
|
|
||||||
|
run(&mut frame)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
extern "C" fn screen_unlock_bootloader_success() {
|
||||||
|
let title = Label::centered("Bootloader unlocked", theme::TEXT_BOLD).vertically_centered();
|
||||||
|
|
||||||
|
let content =
|
||||||
|
Label::centered("Please reconnect the\ndevice", theme::TEXT_NORMAL).vertically_centered();
|
||||||
|
|
||||||
|
let mut frame = ResultScreen::new(BLD_FG, BLD_BG, ICON_SPINNER, title, content, true);
|
||||||
|
show(&mut frame);
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" fn screen_menu(_bld_version: *const cty::c_char) -> u32 {
|
extern "C" fn screen_menu(_bld_version: *const cty::c_char) -> u32 {
|
||||||
run(&mut Menu::new())
|
run(&mut Menu::new())
|
||||||
|
@ -538,6 +538,15 @@ where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Left cancel, armed text and blank on right.
|
||||||
|
pub fn cancel_armed_none(middle: T) -> Self {
|
||||||
|
Self::new(
|
||||||
|
Some(ButtonDetails::cancel_icon()),
|
||||||
|
Some(ButtonDetails::armed_text(middle)),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Left back arrow and middle armed text.
|
/// Left back arrow and middle armed text.
|
||||||
pub fn arrow_armed_none(text: T) -> Self {
|
pub fn arrow_armed_none(text: T) -> Self {
|
||||||
Self::new(
|
Self::new(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
component::{Child, Component, Event, EventCtx, Label, Never, Pad},
|
component::{Child, Component, Event, EventCtx, Label, Never, Pad},
|
||||||
constant::screen,
|
constant::{screen, WIDTH},
|
||||||
display,
|
display,
|
||||||
geometry::{Alignment2D, Offset, Point, Rect},
|
geometry::{Alignment2D, Offset, Point, Rect},
|
||||||
};
|
};
|
||||||
@ -11,7 +11,6 @@ use super::super::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
const FOOTER_AREA_HEIGHT: i16 = 20;
|
const FOOTER_AREA_HEIGHT: i16 = 20;
|
||||||
const MESSAGE_AREA_HEIGHT: i16 = 32;
|
|
||||||
const DIVIDER_POSITION: i16 = 43;
|
const DIVIDER_POSITION: i16 = 43;
|
||||||
|
|
||||||
pub struct ErrorScreen<T> {
|
pub struct ErrorScreen<T> {
|
||||||
@ -55,9 +54,15 @@ impl<T: AsRef<str>> Component for ErrorScreen<T> {
|
|||||||
self.show_icons = false;
|
self.show_icons = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let top_offset = if self.show_icons {
|
||||||
|
Offset::y(11)
|
||||||
|
} else {
|
||||||
|
Offset::y(8)
|
||||||
|
};
|
||||||
|
|
||||||
let message_area = Rect::new(
|
let message_area = Rect::new(
|
||||||
title_area.bottom_left(),
|
title_area.top_left() + top_offset,
|
||||||
title_area.bottom_right() + Offset::y(MESSAGE_AREA_HEIGHT),
|
Point::new(title_area.bottom_right().x, DIVIDER_POSITION),
|
||||||
);
|
);
|
||||||
self.message.place(message_area);
|
self.message.place(message_area);
|
||||||
|
|
||||||
@ -84,12 +89,9 @@ impl<T: AsRef<str>> Component for ErrorScreen<T> {
|
|||||||
}
|
}
|
||||||
self.title.paint();
|
self.title.paint();
|
||||||
self.message.paint();
|
self.message.paint();
|
||||||
// divider line
|
|
||||||
let bar = Rect::from_center_and_size(
|
// // divider line
|
||||||
Point::new(self.area.center().x, DIVIDER_POSITION),
|
display::dotted_line(Point::new(0, DIVIDER_POSITION), WIDTH, FG, 3);
|
||||||
Offset::new(self.area.width(), 1),
|
|
||||||
);
|
|
||||||
display::rect_fill(bar, FG);
|
|
||||||
|
|
||||||
self.footer.paint();
|
self.footer.paint();
|
||||||
}
|
}
|
||||||
|
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 |
|
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
||||||
MPU_RASR_XN_Msk;
|
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->RNR = MPU_REGION_NUMBER2;
|
||||||
MPU->RBAR = FLASH_BASE + 0x110000;
|
MPU->RBAR = FLASH_BASE + 0x110000;
|
||||||
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
MPU->RASR = MPU_RASR_ENABLE_Msk | MPU_RASR_ATTR_FLASH |
|
||||||
LL_MPU_REGION_SIZE_64KB | LL_MPU_REGION_FULL_ACCESS |
|
LL_MPU_REGION_SIZE_128KB | LL_MPU_REGION_FULL_ACCESS |
|
||||||
MPU_RASR_XN_Msk;
|
MPU_RASR_XN_Msk | MPU_SUBREGION_DISABLE(0x0E);
|
||||||
|
|
||||||
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
|
// Firmware (0x08040000 - 0x080FFFFF, 6 * 128 KiB = 1024 KiB except 2/8 at
|
||||||
// start = 768 KiB, read-only)
|
// start = 768 KiB, read-only)
|
||||||
|
@ -195,6 +195,13 @@ void set_core_clock(clock_settings_t settings) {
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
// from util.s
|
||||||
extern void shutdown_privileged(void);
|
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 jump_to_with_flag(uint32_t address, uint32_t register_flag);
|
||||||
void ensure_compatible_settings(void);
|
void ensure_compatible_settings(void);
|
||||||
void clear_otg_hs_memory(void);
|
void clear_otg_hs_memory(void);
|
||||||
|
void drop_privileges(void);
|
||||||
|
|
||||||
extern uint32_t __stack_chk_guard;
|
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],
|
"version": [0, 1],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": true,
|
"show_vendor_string": true,
|
||||||
"require_user_click": true,
|
"require_user_click": true,
|
||||||
"red_background": 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": "T2B1",
|
||||||
|
"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": [
|
||||||
|
"0c0b31408416bd1e813e817599c3320bf775eb1e1843344a1108fdec775fee29",
|
||||||
|
"ed5daba70a99d5c816e6d8bec1c2ae1bb7be804ceddbbe42be772521ca561122"
|
||||||
|
]
|
||||||
|
}
|
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],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": true,
|
||||||
"show_vendor_string": false,
|
"show_vendor_string": false,
|
||||||
"require_user_click": false,
|
"require_user_click": false,
|
||||||
"red_background": false,
|
"red_background": false,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"version": [0, 0],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": true,
|
||||||
"show_vendor_string": false,
|
"show_vendor_string": false,
|
||||||
"require_user_click": false,
|
"require_user_click": false,
|
||||||
"red_background": false,
|
"red_background": false,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"version": [0, 0],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": true,
|
"show_vendor_string": true,
|
||||||
"require_user_click": true,
|
"require_user_click": true,
|
||||||
"red_background": 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],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": false,
|
"show_vendor_string": false,
|
||||||
"require_user_click": false,
|
"require_user_click": false,
|
||||||
"red_background": false,
|
"red_background": false,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"version": [0, 0],
|
"version": [0, 0],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": false,
|
"show_vendor_string": false,
|
||||||
"require_user_click": false,
|
"require_user_click": false,
|
||||||
"red_background": false,
|
"red_background": false,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"version": [0, 1],
|
"version": [0, 1],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": false,
|
"show_vendor_string": false,
|
||||||
"require_user_click": false,
|
"require_user_click": false,
|
||||||
"red_background": false,
|
"red_background": false,
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"version": [0, 1],
|
"version": [0, 1],
|
||||||
"sig_m": 2,
|
"sig_m": 2,
|
||||||
"trust": {
|
"trust": {
|
||||||
|
"allow_run_with_secret": false,
|
||||||
"show_vendor_string": true,
|
"show_vendor_string": true,
|
||||||
"require_user_click": true,
|
"require_user_click": true,
|
||||||
"red_background": true,
|
"red_background": true,
|
||||||
|
@ -70,6 +70,7 @@ def configure(
|
|||||||
sources += ["embed/trezorhal/stm32f4/optiga_hal.c"]
|
sources += ["embed/trezorhal/stm32f4/optiga_hal.c"]
|
||||||
sources += ["embed/trezorhal/optiga/optiga_commands.c"]
|
sources += ["embed/trezorhal/optiga/optiga_commands.c"]
|
||||||
sources += ["embed/trezorhal/optiga/optiga_transport.c"]
|
sources += ["embed/trezorhal/optiga/optiga_transport.c"]
|
||||||
|
sources += ["embed/trezorhal/stm32f4/secret.c"]
|
||||||
|
|
||||||
env.get("ENV")["TREZOR_BOARD"] = board
|
env.get("ENV")["TREZOR_BOARD"] = board
|
||||||
env.get("ENV")["MCU_TYPE"] = mcu
|
env.get("ENV")["MCU_TYPE"] = mcu
|
||||||
|
@ -47,6 +47,7 @@ FirmwareHash = 89
|
|||||||
UnlockPath = 93
|
UnlockPath = 93
|
||||||
UnlockedPathRequest = 94
|
UnlockedPathRequest = 94
|
||||||
ShowDeviceTutorial = 95
|
ShowDeviceTutorial = 95
|
||||||
|
UnlockBootloader = 96
|
||||||
FirmwareErase = 6
|
FirmwareErase = 6
|
||||||
FirmwareUpload = 7
|
FirmwareUpload = 7
|
||||||
FirmwareRequest = 8
|
FirmwareRequest = 8
|
||||||
|
@ -64,6 +64,7 @@ if TYPE_CHECKING:
|
|||||||
UnlockPath = 93
|
UnlockPath = 93
|
||||||
UnlockedPathRequest = 94
|
UnlockedPathRequest = 94
|
||||||
ShowDeviceTutorial = 95
|
ShowDeviceTutorial = 95
|
||||||
|
UnlockBootloader = 96
|
||||||
SetU2FCounter = 63
|
SetU2FCounter = 63
|
||||||
GetNextU2FCounter = 80
|
GetNextU2FCounter = 80
|
||||||
NextU2FCounter = 81
|
NextU2FCounter = 81
|
||||||
|
@ -2628,6 +2628,12 @@ if TYPE_CHECKING:
|
|||||||
def is_type_of(cls, msg: Any) -> TypeGuard["ShowDeviceTutorial"]:
|
def is_type_of(cls, msg: Any) -> TypeGuard["ShowDeviceTutorial"]:
|
||||||
return isinstance(msg, cls)
|
return isinstance(msg, cls)
|
||||||
|
|
||||||
|
class UnlockBootloader(protobuf.MessageType):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_type_of(cls, msg: Any) -> TypeGuard["UnlockBootloader"]:
|
||||||
|
return isinstance(msg, cls)
|
||||||
|
|
||||||
class DebugLinkDecision(protobuf.MessageType):
|
class DebugLinkDecision(protobuf.MessageType):
|
||||||
button: "DebugButton | None"
|
button: "DebugButton | None"
|
||||||
swipe: "DebugSwipeDirection | None"
|
swipe: "DebugSwipeDirection | None"
|
||||||
|
@ -7,7 +7,8 @@ SKIPPED_MESSAGES := Binance Cardano DebugMonero Eos Monero Ontology Ripple SdPro
|
|||||||
DebugLinkLayout DebugLinkResetDebugEvents GetNonce \
|
DebugLinkLayout DebugLinkResetDebugEvents GetNonce \
|
||||||
TxAckInput TxAckOutput TxAckPrev TxAckPaymentRequest \
|
TxAckInput TxAckOutput TxAckPrev TxAckPaymentRequest \
|
||||||
EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \
|
EthereumSignTypedData EthereumTypedDataStructRequest EthereumTypedDataStructAck \
|
||||||
EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial
|
EthereumTypedDataValueRequest EthereumTypedDataValueAck ShowDeviceTutorial \
|
||||||
|
UnlockBootloader
|
||||||
|
|
||||||
ifeq ($(BITCOIN_ONLY), 1)
|
ifeq ($(BITCOIN_ONLY), 1)
|
||||||
SKIPPED_MESSAGES += Ethereum NEM Stellar
|
SKIPPED_MESSAGES += Ethereum NEM Stellar
|
||||||
|
1
python/.changelog.d/+68d5cd56.added
Normal file
1
python/.changelog.d/+68d5cd56.added
Normal file
@ -0,0 +1 @@
|
|||||||
|
trezorctl: support unlocking bootloader via `trezorctl device unlock-bootloader`.
|
@ -299,6 +299,13 @@ def tutorial(client: "TrezorClient") -> str:
|
|||||||
return device.show_device_tutorial(client)
|
return device.show_device_tutorial(client)
|
||||||
|
|
||||||
|
|
||||||
|
@cli.command()
|
||||||
|
@with_client
|
||||||
|
def unlock_bootloader(client: "TrezorClient") -> str:
|
||||||
|
"""Unlocks bootloader. Irreversible."""
|
||||||
|
return device.unlock_bootloader(client)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("enable", type=ChoiceType({"on": True, "off": False}), required=False)
|
@click.argument("enable", type=ChoiceType({"on": True, "off": False}), required=False)
|
||||||
@click.option(
|
@click.option(
|
||||||
|
@ -248,6 +248,12 @@ def show_device_tutorial(client: "TrezorClient") -> "MessageType":
|
|||||||
return client.call(messages.ShowDeviceTutorial())
|
return client.call(messages.ShowDeviceTutorial())
|
||||||
|
|
||||||
|
|
||||||
|
@session
|
||||||
|
@expect(messages.Success, field="message", ret_type=str)
|
||||||
|
def unlock_bootloader(client: "TrezorClient") -> "MessageType":
|
||||||
|
return client.call(messages.UnlockBootloader())
|
||||||
|
|
||||||
|
|
||||||
@expect(messages.Success, field="message", ret_type=str)
|
@expect(messages.Success, field="message", ret_type=str)
|
||||||
@session
|
@session
|
||||||
def set_busy(client: "TrezorClient", expiry_ms: Optional[int]) -> "MessageType":
|
def set_busy(client: "TrezorClient", expiry_ms: Optional[int]) -> "MessageType":
|
||||||
|
@ -47,6 +47,7 @@ def _transform_vendor_trust(data: bytes) -> bytes:
|
|||||||
|
|
||||||
|
|
||||||
class VendorTrust(Struct):
|
class VendorTrust(Struct):
|
||||||
|
allow_run_with_secret: bool
|
||||||
show_vendor_string: bool
|
show_vendor_string: bool
|
||||||
require_user_click: bool
|
require_user_click: bool
|
||||||
red_background: bool
|
red_background: bool
|
||||||
@ -56,7 +57,8 @@ class VendorTrust(Struct):
|
|||||||
|
|
||||||
SUBCON = c.Transformed(
|
SUBCON = c.Transformed(
|
||||||
c.BitStruct(
|
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,
|
"show_vendor_string" / c.Flag,
|
||||||
"require_user_click" / c.Flag,
|
"require_user_click" / c.Flag,
|
||||||
"red_background" / c.Flag,
|
"red_background" / c.Flag,
|
||||||
|
@ -72,6 +72,7 @@ class MessageType(IntEnum):
|
|||||||
UnlockPath = 93
|
UnlockPath = 93
|
||||||
UnlockedPathRequest = 94
|
UnlockedPathRequest = 94
|
||||||
ShowDeviceTutorial = 95
|
ShowDeviceTutorial = 95
|
||||||
|
UnlockBootloader = 96
|
||||||
SetU2FCounter = 63
|
SetU2FCounter = 63
|
||||||
GetNextU2FCounter = 80
|
GetNextU2FCounter = 80
|
||||||
NextU2FCounter = 81
|
NextU2FCounter = 81
|
||||||
@ -3737,6 +3738,10 @@ class ShowDeviceTutorial(protobuf.MessageType):
|
|||||||
MESSAGE_WIRE_TYPE = 95
|
MESSAGE_WIRE_TYPE = 95
|
||||||
|
|
||||||
|
|
||||||
|
class UnlockBootloader(protobuf.MessageType):
|
||||||
|
MESSAGE_WIRE_TYPE = 96
|
||||||
|
|
||||||
|
|
||||||
class DebugLinkDecision(protobuf.MessageType):
|
class DebugLinkDecision(protobuf.MessageType):
|
||||||
MESSAGE_WIRE_TYPE = 100
|
MESSAGE_WIRE_TYPE = 100
|
||||||
FIELDS = {
|
FIELDS = {
|
||||||
|
Loading…
Reference in New Issue
Block a user