mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-26 01:18:28 +00:00
feat(core): prevent installing and running of incompatible firmware, prevent bootloader downgrade
This commit is contained in:
parent
99d4b0185a
commit
115f7daaaa
1
core/.changelog.d/2623.added
Normal file
1
core/.changelog.d/2623.added
Normal file
@ -0,0 +1 @@
|
||||
Add model info to image and check when installing bootloader, prevent bootloader downgrade
|
1
core/embed/boardloader/.changelog.d/2623.added
Normal file
1
core/embed/boardloader/.changelog.d/2623.added
Normal file
@ -0,0 +1 @@
|
||||
Check image model when replacing bootloader
|
@ -53,14 +53,8 @@ struct BoardCapabilities capablities
|
||||
__attribute__((section(".capabilities_section"))) = {
|
||||
.header = CAPABILITIES_HEADER,
|
||||
.model_tag = MODEL_NAME,
|
||||
.model_length = MODEL_NAME_MAX_LENGTH,
|
||||
#if defined TREZOR_MODEL_T
|
||||
.model_name = "TREZORT",
|
||||
#elif defined TREZOR_MODEL_R
|
||||
.model_name = "TREZORR",
|
||||
#else
|
||||
#error Unknown model
|
||||
#endif
|
||||
.model_length = sizeof(uint32_t),
|
||||
.model_name = HW_MODEL,
|
||||
.version_tag = BOARDLOADER_VERSION,
|
||||
.version_length = sizeof(struct BoardloaderVersion),
|
||||
.version = {.version_major = VERSION_MAJOR,
|
||||
@ -93,17 +87,29 @@ static uint32_t check_sdcard(void) {
|
||||
|
||||
sdcard_power_off();
|
||||
|
||||
image_header hdr;
|
||||
if (sectrue == read_status) {
|
||||
const image_header *hdr =
|
||||
read_image_header((const uint8_t *)sdcard_buf, BOOTLOADER_IMAGE_MAGIC,
|
||||
BOOTLOADER_IMAGE_MAXSIZE);
|
||||
|
||||
if ((sectrue == read_status) &&
|
||||
(sectrue ==
|
||||
load_image_header((const uint8_t *)sdcard_buf, BOOTLOADER_IMAGE_MAGIC,
|
||||
BOOTLOADER_IMAGE_MAXSIZE, BOARDLOADER_KEY_M,
|
||||
BOARDLOADER_KEY_N, BOARDLOADER_KEYS, &hdr))) {
|
||||
return hdr.codelen;
|
||||
} else {
|
||||
return 0;
|
||||
if (hdr != (const image_header *)sdcard_buf) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_model(hdr)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_header_sig(hdr, BOARDLOADER_KEY_M,
|
||||
BOARDLOADER_KEY_N,
|
||||
BOARDLOADER_KEYS)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return hdr->codelen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void progress_callback(int pos, int len) { display_printf("."); }
|
||||
@ -220,18 +226,21 @@ int main(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
image_header hdr;
|
||||
const image_header *hdr =
|
||||
read_image_header((const uint8_t *)BOOTLOADER_START,
|
||||
BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE);
|
||||
|
||||
ensure(load_image_header((const uint8_t *)BOOTLOADER_START,
|
||||
BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE,
|
||||
BOARDLOADER_KEY_M, BOARDLOADER_KEY_N,
|
||||
BOARDLOADER_KEYS, &hdr),
|
||||
ensure(hdr == (const image_header *)BOOTLOADER_START ? sectrue : secfalse,
|
||||
"invalid bootloader header");
|
||||
|
||||
ensure(check_image_header_sig(hdr, BOARDLOADER_KEY_M, BOARDLOADER_KEY_N,
|
||||
BOARDLOADER_KEYS),
|
||||
"invalid bootloader signature");
|
||||
|
||||
const uint8_t sectors[] = {
|
||||
FLASH_SECTOR_BOOTLOADER,
|
||||
};
|
||||
ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE, sectors, 1),
|
||||
ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE, sectors, 1),
|
||||
"invalid bootloader hash");
|
||||
|
||||
ensure_compatible_settings();
|
||||
|
1
core/embed/bootloader/.changelog.d/2623.added
Normal file
1
core/embed/bootloader/.changelog.d/2623.added
Normal file
@ -0,0 +1 @@
|
||||
Add model info to image and check when installing/running firmware
|
@ -215,31 +215,6 @@ void ui_screen_firmware_info(const vendor_header *const vhdr,
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
void ui_screen_firmware_fingerprint(const image_header *const hdr) {
|
||||
display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_BL_BG);
|
||||
display_text(16, 32, "Firmware fingerprint", -1, FONT_NORMAL, COLOR_BL_FG,
|
||||
COLOR_BL_BG);
|
||||
display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BL_FG);
|
||||
|
||||
static const char *hexdigits = "0123456789abcdef";
|
||||
char fingerprint_str[64];
|
||||
for (int i = 0; i < 32; i++) {
|
||||
fingerprint_str[i * 2] = hexdigits[(hdr->fingerprint[i] >> 4) & 0xF];
|
||||
fingerprint_str[i * 2 + 1] = hexdigits[hdr->fingerprint[i] & 0xF];
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
display_text_center(120, 70 + i * 25, fingerprint_str + i * 16, 16,
|
||||
FONT_MONO, COLOR_BL_FG, COLOR_BL_BG);
|
||||
}
|
||||
|
||||
display_bar_radius(9, 184, 222, 50, COLOR_BL_DONE, COLOR_BL_BG, 4);
|
||||
display_icon(9 + (222 - 19) / 2, 184 + (50 - 16) / 2, 20, 16,
|
||||
toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12,
|
||||
COLOR_BL_BG, COLOR_BL_DONE);
|
||||
PIXELDATA_DIRTY();
|
||||
display_refresh();
|
||||
}
|
||||
|
||||
// install UI
|
||||
|
||||
void ui_screen_install_confirm_upgrade(const vendor_header *const vhdr,
|
||||
|
@ -34,7 +34,6 @@ void ui_screen_welcome_third(void);
|
||||
|
||||
void ui_screen_firmware_info(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
void ui_screen_firmware_fingerprint(const image_header* const hdr);
|
||||
|
||||
void ui_screen_install_confirm_upgrade(const vendor_header* const vhdr,
|
||||
const image_header* const hdr);
|
||||
|
@ -10,7 +10,11 @@
|
||||
g_header:
|
||||
.byte 'T','R','Z','B' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
#ifdef TREZOR_MODEL_T
|
||||
.word 0 // expiry
|
||||
#else
|
||||
.word 1 // expiry
|
||||
#endif
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
@ -20,7 +24,10 @@ g_header:
|
||||
.byte FIX_VERSION_MINOR // fix_vminor
|
||||
.byte FIX_VERSION_PATCH // fix_vpatch
|
||||
.byte FIX_VERSION_BUILD // fix_vbuild
|
||||
. = . + 8 // reserved
|
||||
.word HW_MODEL // type of the designated hardware
|
||||
.byte HW_REVISION // revision of the designated hardware
|
||||
.byte VERSION_MONOTONIC // monotonic version of the binary
|
||||
. = . + 2 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
. = . + 415 // reserved
|
||||
.byte 0 // sigmask
|
||||
|
@ -159,7 +159,7 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
break;
|
||||
case 7: // FirmwareUpload
|
||||
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0 && r != -4) { // error, but not user abort (-4)
|
||||
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
||||
ui_fadeout();
|
||||
ui_screen_fail();
|
||||
ui_fadein();
|
||||
@ -193,10 +193,9 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
}
|
||||
}
|
||||
|
||||
secbool load_vendor_header_keys(const uint8_t *const data,
|
||||
vendor_header *const vhdr) {
|
||||
return load_vendor_header(data, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
|
||||
BOOTLOADER_KEYS, vhdr);
|
||||
secbool check_vendor_header_keys(const vendor_header *const vhdr) {
|
||||
return check_vendor_header_sig(vhdr, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
|
||||
BOOTLOADER_KEYS);
|
||||
}
|
||||
|
||||
static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
|
||||
@ -303,23 +302,40 @@ int main(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
const image_header *hdr = NULL;
|
||||
vendor_header vhdr;
|
||||
image_header hdr;
|
||||
// detect whether the devices contains a valid firmware
|
||||
// detect whether the device contains a valid firmware
|
||||
secbool firmware_present = sectrue;
|
||||
|
||||
if (sectrue != read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr)) {
|
||||
firmware_present = secfalse;
|
||||
}
|
||||
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_vendor_header_keys(&vhdr);
|
||||
}
|
||||
|
||||
secbool firmware_present =
|
||||
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr);
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_vendor_header_lock(&vhdr);
|
||||
}
|
||||
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = load_image_header(
|
||||
(const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC,
|
||||
FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr);
|
||||
hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
if (hdr != (const image_header *)(FIRMWARE_START + vhdr.hdrlen)) {
|
||||
firmware_present = secfalse;
|
||||
}
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_image_model(hdr);
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present =
|
||||
check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub);
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present =
|
||||
check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT);
|
||||
}
|
||||
|
||||
@ -357,26 +373,35 @@ int main(void) {
|
||||
// ... or we have stay_in_bootloader flag to force it
|
||||
if (touched || stay_in_bootloader == sectrue) {
|
||||
// no ui_fadeout(); - we already start from black screen
|
||||
ui_screen_firmware_info(&vhdr, &hdr);
|
||||
ui_screen_firmware_info(&vhdr, hdr);
|
||||
ui_fadein();
|
||||
|
||||
// and start the usb loop
|
||||
if (bootloader_usb_loop(&vhdr, &hdr) != sectrue) {
|
||||
if (bootloader_usb_loop(&vhdr, hdr) != sectrue) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ensure(load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
|
||||
ensure(read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr),
|
||||
"invalid vendor header");
|
||||
|
||||
ensure(check_vendor_header_keys(&vhdr), "invalid vendor header signature");
|
||||
|
||||
ensure(check_vendor_header_lock(&vhdr), "unauthorized vendor keys");
|
||||
|
||||
ensure(load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
|
||||
vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr),
|
||||
hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
ensure(hdr == (const image_header *)(FIRMWARE_START + vhdr.hdrlen) ? sectrue
|
||||
: secfalse,
|
||||
"invalid firmware header");
|
||||
|
||||
ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
ensure(check_image_model(hdr), "wrong firmware model");
|
||||
|
||||
ensure(check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub),
|
||||
"invalid firmware signature");
|
||||
|
||||
ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT),
|
||||
"invalid firmware hash");
|
||||
|
||||
@ -384,7 +409,7 @@ int main(void) {
|
||||
|
||||
if ((vhdr.vtrust & VTRUST_ALL) != VTRUST_ALL) {
|
||||
// ui_fadeout(); // no fadeout - we start from black screen
|
||||
ui_screen_boot(&vhdr, &hdr);
|
||||
ui_screen_boot(&vhdr, hdr);
|
||||
ui_fadein();
|
||||
|
||||
int delay = (vhdr.vtrust & VTRUST_WAIT) ^ VTRUST_WAIT;
|
||||
|
@ -403,8 +403,7 @@ static bool _read_payload(pb_istream_t *stream, const pb_field_t *field,
|
||||
return true;
|
||||
}
|
||||
|
||||
secbool load_vendor_header_keys(const uint8_t *const data,
|
||||
vendor_header *const vhdr);
|
||||
secbool check_vendor_header_keys(const vendor_header *const vhdr);
|
||||
|
||||
static int version_compare(uint32_t vera, uint32_t verb) {
|
||||
int a, b;
|
||||
@ -422,8 +421,8 @@ static int version_compare(uint32_t vera, uint32_t verb) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static void detect_installation(vendor_header *current_vhdr,
|
||||
image_header *current_hdr,
|
||||
static void detect_installation(const vendor_header *current_vhdr,
|
||||
const image_header *current_hdr,
|
||||
const vendor_header *const new_vhdr,
|
||||
const image_header *const new_hdr,
|
||||
secbool *is_new, secbool *is_upgrade,
|
||||
@ -431,16 +430,17 @@ static void detect_installation(vendor_header *current_vhdr,
|
||||
*is_new = secfalse;
|
||||
*is_upgrade = secfalse;
|
||||
*is_downgrade_wipe = secfalse;
|
||||
if (sectrue !=
|
||||
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, current_vhdr)) {
|
||||
if (sectrue != check_vendor_header_keys(current_vhdr)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
if (sectrue !=
|
||||
load_image_header((const uint8_t *)FIRMWARE_START + current_vhdr->hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
|
||||
current_vhdr->vsig_m, current_vhdr->vsig_n,
|
||||
current_vhdr->vpub, current_hdr)) {
|
||||
if (sectrue != check_image_model(current_hdr)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
if (sectrue != check_image_header_sig(current_hdr, current_vhdr->vsig_m,
|
||||
current_vhdr->vsig_n,
|
||||
current_vhdr->vpub)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
@ -472,7 +472,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk size");
|
||||
MSG_SEND(Failure);
|
||||
return -1;
|
||||
return UPLOAD_ERR_INVALID_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static image_header hdr;
|
||||
@ -483,29 +483,81 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
if (headers_offset == 0) {
|
||||
// first block and headers are not yet parsed
|
||||
vendor_header vhdr;
|
||||
if (sectrue != load_vendor_header_keys(CHUNK_BUFFER_PTR, &vhdr)) {
|
||||
|
||||
if (sectrue != read_vendor_header(CHUNK_BUFFER_PTR, &vhdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header");
|
||||
MSG_SEND(Failure);
|
||||
return -2;
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER;
|
||||
}
|
||||
if (sectrue != load_image_header(CHUNK_BUFFER_PTR + vhdr.hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC,
|
||||
FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m,
|
||||
vhdr.vsig_n, vhdr.vpub, &hdr)) {
|
||||
|
||||
if (sectrue != check_vendor_header_keys(&vhdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header signature");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG;
|
||||
}
|
||||
|
||||
const image_header *received_hdr =
|
||||
read_image_header(CHUNK_BUFFER_PTR + vhdr.hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
if (received_hdr !=
|
||||
(const image_header *)(CHUNK_BUFFER_PTR + vhdr.hdrlen)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware header");
|
||||
MSG_SEND(Failure);
|
||||
return -3;
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_model(received_hdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Wrong firmware model");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_MODEL;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_header_sig(received_hdr, vhdr.vsig_m,
|
||||
vhdr.vsig_n, vhdr.vpub)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware signature");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG;
|
||||
}
|
||||
|
||||
memcpy(&hdr, received_hdr, sizeof(hdr));
|
||||
|
||||
vendor_header current_vhdr;
|
||||
image_header current_hdr;
|
||||
|
||||
secbool is_new = secfalse;
|
||||
detect_installation(¤t_vhdr, ¤t_hdr, &vhdr, &hdr, &is_new,
|
||||
&is_upgrade, &is_downgrade_wipe);
|
||||
|
||||
if (sectrue !=
|
||||
read_vendor_header((const uint8_t *)FIRMWARE_START, ¤t_vhdr)) {
|
||||
is_new = sectrue;
|
||||
}
|
||||
|
||||
const image_header *current_hdr = NULL;
|
||||
|
||||
if (is_new == secfalse) {
|
||||
current_hdr = read_image_header(
|
||||
(const uint8_t *)FIRMWARE_START + current_vhdr.hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
if (current_hdr !=
|
||||
(const image_header *)FIRMWARE_START + current_vhdr.hdrlen) {
|
||||
is_new = sectrue;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_new == secfalse) {
|
||||
detect_installation(¤t_vhdr, current_hdr, &vhdr, &hdr, &is_new,
|
||||
&is_upgrade, &is_downgrade_wipe);
|
||||
}
|
||||
|
||||
int response = INPUT_CANCEL;
|
||||
if (sectrue == is_new) {
|
||||
@ -528,10 +580,10 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
|
||||
if (INPUT_CANCEL == response) {
|
||||
ui_fadeout();
|
||||
ui_screen_firmware_info(¤t_vhdr, ¤t_hdr);
|
||||
ui_screen_firmware_info(¤t_vhdr, current_hdr);
|
||||
ui_fadein();
|
||||
send_user_abort(iface_num, "Firmware install cancelled");
|
||||
return -4;
|
||||
return UPLOAD_ERR_USER_ABORT;
|
||||
}
|
||||
|
||||
headers_offset = IMAGE_HEADER_SIZE + vhdr.hdrlen;
|
||||
@ -572,7 +624,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Firmware too big");
|
||||
MSG_SEND(Failure);
|
||||
return -5;
|
||||
return UPLOAD_ERR_FIRMWARE_TOO_BIG;
|
||||
}
|
||||
|
||||
if (sectrue != check_single_hash(hdr.hashes + firmware_block * 32,
|
||||
@ -591,7 +643,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk hash");
|
||||
MSG_SEND(Failure);
|
||||
return -6;
|
||||
return UPLOAD_ERR_INVALID_CHUNK_HASH;
|
||||
}
|
||||
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
@ -654,11 +706,11 @@ int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Could not erase flash");
|
||||
MSG_SEND(Failure);
|
||||
return -1;
|
||||
return WIPE_ERR_CANNOT_ERASE;
|
||||
} else {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND(Success);
|
||||
return 0;
|
||||
return WIPE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,24 @@
|
||||
|
||||
#define FIRMWARE_UPLOAD_CHUNK_RETRY_COUNT 2
|
||||
|
||||
enum {
|
||||
UPLOAD_OK = 0,
|
||||
UPLOAD_ERR_INVALID_CHUNK_SIZE = -1,
|
||||
UPLOAD_ERR_INVALID_VENDOR_HEADER = -2,
|
||||
UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG = -3,
|
||||
UPLOAD_ERR_INVALID_IMAGE_HEADER = -4,
|
||||
UPLOAD_ERR_INVALID_IMAGE_MODEL = -5,
|
||||
UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG = -6,
|
||||
UPLOAD_ERR_USER_ABORT = -7,
|
||||
UPLOAD_ERR_FIRMWARE_TOO_BIG = -8,
|
||||
UPLOAD_ERR_INVALID_CHUNK_HASH = -9,
|
||||
};
|
||||
|
||||
enum {
|
||||
WIPE_OK = 0,
|
||||
WIPE_ERR_CANNOT_ERASE = -1,
|
||||
};
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size);
|
||||
|
||||
|
1
core/embed/bootloader_ci/.changelog.d/2623.added
Normal file
1
core/embed/bootloader_ci/.changelog.d/2623.added
Normal file
@ -0,0 +1 @@
|
||||
Add model info to image and check when installing/running firmware
|
@ -10,7 +10,11 @@
|
||||
g_header:
|
||||
.byte 'T','R','Z','B' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
#ifdef TREZOR_MODEL_T
|
||||
.word 0 // expiry
|
||||
#else
|
||||
.word 1 // expiry
|
||||
#endif
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
@ -20,7 +24,10 @@ g_header:
|
||||
.byte FIX_VERSION_MINOR // fix_vminor
|
||||
.byte FIX_VERSION_PATCH // fix_vpatch
|
||||
.byte FIX_VERSION_BUILD // fix_vbuild
|
||||
. = . + 8 // reserved
|
||||
.word HW_MODEL // type of the designated hardware
|
||||
.byte HW_REVISION // revision of the designated hardware
|
||||
.byte VERSION_MONOTONIC // monotonic version
|
||||
. = . + 2 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
. = . + 415 // reserved
|
||||
.byte 0 // sigmask
|
||||
|
@ -134,7 +134,7 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
break;
|
||||
case 7: // FirmwareUpload
|
||||
r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf);
|
||||
if (r < 0 && r != -4) { // error, but not user abort (-4)
|
||||
if (r < 0 && r != UPLOAD_ERR_USER_ABORT) { // error, but not user abort
|
||||
ui_screen_fail();
|
||||
usb_stop();
|
||||
usb_deinit();
|
||||
@ -163,10 +163,9 @@ static secbool bootloader_usb_loop(const vendor_header *const vhdr,
|
||||
}
|
||||
}
|
||||
|
||||
secbool load_vendor_header_keys(const uint8_t *const data,
|
||||
vendor_header *const vhdr) {
|
||||
return load_vendor_header(data, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
|
||||
BOOTLOADER_KEYS, vhdr);
|
||||
secbool check_vendor_header_keys(vendor_header *const vhdr) {
|
||||
return check_vendor_header_sig(vhdr, BOOTLOADER_KEY_M, BOOTLOADER_KEY_N,
|
||||
BOOTLOADER_KEYS);
|
||||
}
|
||||
|
||||
static secbool check_vendor_header_lock(const vendor_header *const vhdr) {
|
||||
@ -227,24 +226,40 @@ int main(void) {
|
||||
|
||||
display_clear();
|
||||
|
||||
const image_header *hdr = NULL;
|
||||
vendor_header vhdr;
|
||||
image_header hdr;
|
||||
// detect whether the device contains a valid firmware
|
||||
secbool firmware_present = sectrue;
|
||||
|
||||
// detect whether the devices contains a valid firmware
|
||||
if (sectrue != read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr)) {
|
||||
firmware_present = secfalse;
|
||||
}
|
||||
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_vendor_header_keys(&vhdr);
|
||||
}
|
||||
|
||||
secbool firmware_present =
|
||||
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr);
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_vendor_header_lock(&vhdr);
|
||||
}
|
||||
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = load_image_header(
|
||||
(const uint8_t *)(FIRMWARE_START + vhdr.hdrlen), FIRMWARE_IMAGE_MAGIC,
|
||||
FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr);
|
||||
hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
if (hdr != (const image_header *)(FIRMWARE_START + vhdr.hdrlen)) {
|
||||
firmware_present = secfalse;
|
||||
}
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present = check_image_model(hdr);
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present =
|
||||
check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub);
|
||||
}
|
||||
if (sectrue == firmware_present) {
|
||||
firmware_present =
|
||||
check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT);
|
||||
}
|
||||
|
||||
@ -260,17 +275,26 @@ int main(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ensure(load_vendor_header_keys((const uint8_t *)FIRMWARE_START, &vhdr),
|
||||
ensure(read_vendor_header((const uint8_t *)FIRMWARE_START, &vhdr),
|
||||
"invalid vendor header");
|
||||
|
||||
ensure(check_vendor_header_keys(&vhdr), "invalid vendor header signature");
|
||||
|
||||
ensure(check_vendor_header_lock(&vhdr), "unauthorized vendor keys");
|
||||
|
||||
ensure(load_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
|
||||
vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub, &hdr),
|
||||
hdr = read_image_header((const uint8_t *)(FIRMWARE_START + vhdr.hdrlen),
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
ensure(hdr == (const image_header *)(FIRMWARE_START + vhdr.hdrlen) ? sectrue
|
||||
: secfalse,
|
||||
"invalid firmware header");
|
||||
|
||||
ensure(check_image_contents(&hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
ensure(check_image_model(hdr), "wrong firmware model");
|
||||
|
||||
ensure(check_image_header_sig(hdr, vhdr.vsig_m, vhdr.vsig_n, vhdr.vpub),
|
||||
"invalid firmware signature");
|
||||
|
||||
ensure(check_image_contents(hdr, IMAGE_HEADER_SIZE + vhdr.hdrlen,
|
||||
FIRMWARE_SECTORS, FIRMWARE_SECTORS_COUNT),
|
||||
"invalid firmware hash");
|
||||
|
||||
|
@ -401,8 +401,7 @@ static bool _read_payload(pb_istream_t *stream, const pb_field_t *field,
|
||||
return true;
|
||||
}
|
||||
|
||||
secbool load_vendor_header_keys(const uint8_t *const data,
|
||||
vendor_header *const vhdr);
|
||||
secbool check_vendor_header_keys(const vendor_header *const vhdr);
|
||||
|
||||
static int version_compare(uint32_t vera, uint32_t verb) {
|
||||
int a, b;
|
||||
@ -420,8 +419,8 @@ static int version_compare(uint32_t vera, uint32_t verb) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
static void detect_installation(vendor_header *current_vhdr,
|
||||
image_header *current_hdr,
|
||||
static void detect_installation(const vendor_header *current_vhdr,
|
||||
const image_header *current_hdr,
|
||||
const vendor_header *const new_vhdr,
|
||||
const image_header *const new_hdr,
|
||||
secbool *is_new, secbool *is_upgrade,
|
||||
@ -429,16 +428,17 @@ static void detect_installation(vendor_header *current_vhdr,
|
||||
*is_new = secfalse;
|
||||
*is_upgrade = secfalse;
|
||||
*is_downgrade_wipe = secfalse;
|
||||
if (sectrue !=
|
||||
load_vendor_header_keys((const uint8_t *)FIRMWARE_START, current_vhdr)) {
|
||||
if (sectrue != check_vendor_header_keys(current_vhdr)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
if (sectrue !=
|
||||
load_image_header((const uint8_t *)FIRMWARE_START + current_vhdr->hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE,
|
||||
current_vhdr->vsig_m, current_vhdr->vsig_n,
|
||||
current_vhdr->vpub, current_hdr)) {
|
||||
if (sectrue != check_image_model(current_hdr)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
if (sectrue != check_image_header_sig(current_hdr, current_vhdr->vsig_m,
|
||||
current_vhdr->vsig_n,
|
||||
current_vhdr->vpub)) {
|
||||
*is_new = sectrue;
|
||||
return;
|
||||
}
|
||||
@ -470,7 +470,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk size");
|
||||
MSG_SEND(Failure);
|
||||
return -1;
|
||||
return UPLOAD_ERR_INVALID_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
static image_header hdr;
|
||||
@ -481,29 +481,80 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
if (headers_offset == 0) {
|
||||
// first block and headers are not yet parsed
|
||||
vendor_header vhdr;
|
||||
if (sectrue != load_vendor_header_keys(chunk_buffer, &vhdr)) {
|
||||
|
||||
if (sectrue != read_vendor_header(chunk_buffer, &vhdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header");
|
||||
MSG_SEND(Failure);
|
||||
return -2;
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER;
|
||||
}
|
||||
if (sectrue != load_image_header(chunk_buffer + vhdr.hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC,
|
||||
FIRMWARE_IMAGE_MAXSIZE, vhdr.vsig_m,
|
||||
vhdr.vsig_n, vhdr.vpub, &hdr)) {
|
||||
|
||||
if (sectrue != check_vendor_header_keys(&vhdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid vendor header signature");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG;
|
||||
}
|
||||
|
||||
const image_header *received_hdr =
|
||||
read_image_header(chunk_buffer + vhdr.hdrlen, FIRMWARE_IMAGE_MAGIC,
|
||||
FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
if (received_hdr != (const image_header *)chunk_buffer + vhdr.hdrlen) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware header");
|
||||
MSG_SEND(Failure);
|
||||
return -3;
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_model(received_hdr)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Wrong firmware model");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_MODEL;
|
||||
}
|
||||
|
||||
if (sectrue != check_image_header_sig(received_hdr, vhdr.vsig_m,
|
||||
vhdr.vsig_n, vhdr.vpub)) {
|
||||
MSG_SEND_INIT(Failure);
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid firmware signature");
|
||||
MSG_SEND(Failure);
|
||||
return UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG;
|
||||
}
|
||||
|
||||
memcpy(&hdr, received_hdr, sizeof(hdr));
|
||||
|
||||
vendor_header current_vhdr;
|
||||
image_header current_hdr;
|
||||
|
||||
secbool is_new = secfalse;
|
||||
detect_installation(¤t_vhdr, ¤t_hdr, &vhdr, &hdr, &is_new,
|
||||
&is_upgrade, &is_downgrade_wipe);
|
||||
|
||||
if (sectrue !=
|
||||
read_vendor_header((const uint8_t *)FIRMWARE_START, ¤t_vhdr)) {
|
||||
is_new = sectrue;
|
||||
}
|
||||
|
||||
const image_header *current_hdr = NULL;
|
||||
|
||||
if (is_new == secfalse) {
|
||||
current_hdr = read_image_header(
|
||||
(const uint8_t *)FIRMWARE_START + current_vhdr.hdrlen,
|
||||
FIRMWARE_IMAGE_MAGIC, FIRMWARE_IMAGE_MAXSIZE);
|
||||
|
||||
if (current_hdr !=
|
||||
(const image_header *)FIRMWARE_START + current_vhdr.hdrlen) {
|
||||
is_new = sectrue;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_new == secfalse) {
|
||||
detect_installation(¤t_vhdr, current_hdr, &vhdr, &hdr, &is_new,
|
||||
&is_upgrade, &is_downgrade_wipe);
|
||||
}
|
||||
|
||||
// no user confirmations, go directly to upload
|
||||
|
||||
@ -539,7 +590,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Firmware too big");
|
||||
MSG_SEND(Failure);
|
||||
return -5;
|
||||
return UPLOAD_ERR_FIRMWARE_TOO_BIG;
|
||||
}
|
||||
|
||||
if (sectrue != check_single_hash(hdr.hashes + firmware_block * 32,
|
||||
@ -558,7 +609,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size,
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Invalid chunk hash");
|
||||
MSG_SEND(Failure);
|
||||
return -6;
|
||||
return UPLOAD_ERR_INVALID_CHUNK_HASH;
|
||||
}
|
||||
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
@ -621,11 +672,11 @@ int process_msg_WipeDevice(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) {
|
||||
MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError);
|
||||
MSG_SEND_ASSIGN_STRING(message, "Could not erase flash");
|
||||
MSG_SEND(Failure);
|
||||
return -1;
|
||||
return WIPE_ERR_CANNOT_ERASE;
|
||||
} else {
|
||||
MSG_SEND_INIT(Success);
|
||||
MSG_SEND(Success);
|
||||
return 0;
|
||||
return WIPE_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,24 @@
|
||||
|
||||
#define FIRMWARE_UPLOAD_CHUNK_RETRY_COUNT 2
|
||||
|
||||
enum {
|
||||
UPLOAD_OK = 0,
|
||||
UPLOAD_ERR_INVALID_CHUNK_SIZE = -1,
|
||||
UPLOAD_ERR_INVALID_VENDOR_HEADER = -2,
|
||||
UPLOAD_ERR_INVALID_VENDOR_HEADER_SIG = -3,
|
||||
UPLOAD_ERR_INVALID_IMAGE_HEADER = -4,
|
||||
UPLOAD_ERR_INVALID_IMAGE_MODEL = -5,
|
||||
UPLOAD_ERR_INVALID_IMAGE_HEADER_SIG = -6,
|
||||
UPLOAD_ERR_USER_ABORT = -7,
|
||||
UPLOAD_ERR_FIRMWARE_TOO_BIG = -8,
|
||||
UPLOAD_ERR_INVALID_CHUNK_HASH = -9,
|
||||
};
|
||||
|
||||
enum {
|
||||
WIPE_OK = 0,
|
||||
WIPE_ERR_CANNOT_ERASE = -1,
|
||||
};
|
||||
|
||||
secbool msg_parse_header(const uint8_t *buf, uint16_t *msg_id,
|
||||
uint32_t *msg_size);
|
||||
|
||||
|
@ -20,12 +20,14 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "blake2s.h"
|
||||
#include "board_capabilities.h"
|
||||
#include "common.h"
|
||||
#include "flash.h"
|
||||
#include "image.h"
|
||||
|
||||
// symbols from bootloader.bin => bootloader.o
|
||||
extern const uint32_t _binary_embed_firmware_bootloader_bin_start;
|
||||
extern const uint32_t _binary_embed_firmware_bootloader_bin_size;
|
||||
extern const void _binary_embed_firmware_bootloader_bin_start;
|
||||
extern const void _binary_embed_firmware_bootloader_bin_size;
|
||||
|
||||
/*
|
||||
static secbool known_bootloader(const uint8_t *hash, int len) {
|
||||
@ -97,6 +99,48 @@ void check_and_replace_bootloader(void) {
|
||||
(const uint32_t *)&_binary_embed_firmware_bootloader_bin_start;
|
||||
const uint32_t len =
|
||||
(const uint32_t)&_binary_embed_firmware_bootloader_bin_size;
|
||||
|
||||
const image_header *new_bld_hdr = read_image_header(
|
||||
(uint8_t *)data, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE);
|
||||
|
||||
ensure(new_bld_hdr == (const image_header *)data ? sectrue : secfalse,
|
||||
"Invalid embedded bootloader");
|
||||
|
||||
ensure(check_image_model(new_bld_hdr), "Incompatible embedded bootloader");
|
||||
|
||||
const image_header *current_bld_hdr = read_image_header(
|
||||
bl_data, BOOTLOADER_IMAGE_MAGIC, BOOTLOADER_IMAGE_MAXSIZE);
|
||||
|
||||
// cannot find valid header for current bootloader, something is wrong
|
||||
ensure(current_bld_hdr == (const image_header *)bl_data ? sectrue : secfalse,
|
||||
"Invalid bootloader header");
|
||||
|
||||
ensure(check_image_model(current_bld_hdr), "Incompatible bootloader found");
|
||||
|
||||
if (new_bld_hdr->monotonic < current_bld_hdr->monotonic) {
|
||||
// reject downgrade
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t board_name = get_board_name();
|
||||
if (board_name == 0 || strncmp((const char *)&board_name, "T2T1", 4) == 0) {
|
||||
// no board capabilities, assume Model T
|
||||
if ((strncmp((const char *)&new_bld_hdr->hw_model, "T2T1", 4) != 0) &&
|
||||
(new_bld_hdr->hw_model != 0)) {
|
||||
// reject non-model T bootloader
|
||||
// 0 represents pre-model check bootloader
|
||||
ensure(secfalse, "Incompatible embedded bootloader");
|
||||
}
|
||||
}
|
||||
// at this point, due to the previous check_image_model call, we know that the
|
||||
// new_bld_hdr is
|
||||
// meant for the same model as this firmware, so we can check the board name
|
||||
// against the firmware hw_model.
|
||||
else if (board_name != HW_MODEL) {
|
||||
// reject incompatible bootloader
|
||||
ensure(secfalse, "Incompatible embedded bootloader");
|
||||
}
|
||||
|
||||
ensure(flash_erase(FLASH_SECTOR_BOOTLOADER), NULL);
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
for (int i = 0; i < len / sizeof(uint32_t); i++) {
|
||||
|
@ -13,7 +13,11 @@
|
||||
g_header:
|
||||
.byte 'T','R','Z','F' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
#ifdef TREZOR_MODEL_T
|
||||
.word 0 // expiry
|
||||
#else
|
||||
.word 1 // expiry
|
||||
#endif
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
@ -23,7 +27,10 @@ g_header:
|
||||
.byte FIX_VERSION_MINOR // fix_vminor
|
||||
.byte FIX_VERSION_PATCH // fix_vpatch
|
||||
.byte FIX_VERSION_BUILD // fix_vbuild
|
||||
. = . + 8 // reserved
|
||||
.word HW_MODEL // type of the designated hardware
|
||||
.byte HW_REVISION // revision of the designated hardware
|
||||
.byte VERSION_MONOTONIC // monotonic version of the binary
|
||||
. = . + 2 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
|
||||
#if !defined TREZOR_MODEL_1
|
||||
|
@ -7,3 +7,5 @@
|
||||
#define FIX_VERSION_MINOR 4
|
||||
#define FIX_VERSION_PATCH 0
|
||||
#define FIX_VERSION_BUILD 0
|
||||
|
||||
#define VERSION_MONOTONIC 1
|
||||
|
@ -10,7 +10,11 @@
|
||||
g_header:
|
||||
.byte 'T','R','Z','F' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
#ifdef TREZOR_MODEL_T
|
||||
.word 0 // expiry
|
||||
#else
|
||||
.word 1 // expiry
|
||||
#endif
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
@ -20,7 +24,10 @@ g_header:
|
||||
.byte FIX_VERSION_MINOR // fix_vminor
|
||||
.byte FIX_VERSION_PATCH // fix_vpatch
|
||||
.byte FIX_VERSION_BUILD // fix_vbuild
|
||||
. = . + 8 // reserved
|
||||
.word HW_MODEL // type of the designated hardware
|
||||
.byte HW_REVISION // revision of the designated hardware
|
||||
.byte VERSION_MONOTONIC // monotonic version of the binary
|
||||
. = . + 2 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
. = . + 415 // reserved
|
||||
.byte 0 // sigmask
|
||||
|
@ -7,3 +7,5 @@
|
||||
#define FIX_VERSION_MINOR 1
|
||||
#define FIX_VERSION_PATCH 0
|
||||
#define FIX_VERSION_BUILD 0
|
||||
|
||||
#define VERSION_MONOTONIC 1
|
||||
|
@ -10,7 +10,11 @@
|
||||
g_header:
|
||||
.byte 'T','R','Z','F' // magic
|
||||
.word g_header_end - g_header // hdrlen
|
||||
#ifdef TREZOR_MODEL_T
|
||||
.word 0 // expiry
|
||||
#else
|
||||
.word 1 // expiry
|
||||
#endif
|
||||
.word _codelen // codelen
|
||||
.byte VERSION_MAJOR // vmajor
|
||||
.byte VERSION_MINOR // vminor
|
||||
@ -20,7 +24,10 @@ g_header:
|
||||
.byte FIX_VERSION_MINOR // fix_vminor
|
||||
.byte FIX_VERSION_PATCH // fix_vpatch
|
||||
.byte FIX_VERSION_BUILD // fix_vbuild
|
||||
. = . + 8 // reserved
|
||||
.word HW_MODEL // type of the designated hardware
|
||||
.byte HW_REVISION // revision of the designated hardware
|
||||
.byte VERSION_MONOTONIC // monotonic version of the binary
|
||||
. = . + 2 // reserved
|
||||
. = . + 512 // hash1 ... hash16
|
||||
. = . + 415 // reserved
|
||||
.byte 0 // sigmask
|
||||
|
@ -7,3 +7,5 @@
|
||||
#define FIX_VERSION_MINOR 1
|
||||
#define FIX_VERSION_PATCH 0
|
||||
#define FIX_VERSION_BUILD 0
|
||||
|
||||
#define VERSION_MONOTONIC 1
|
||||
|
@ -24,11 +24,11 @@
|
||||
#define handle_fault(msg) \
|
||||
(__fatal_error("Fault detected", msg, __FILE__, __LINE__, __func__))
|
||||
|
||||
static uint8_t board_name[MODEL_NAME_MAX_LENGTH + 1] = {0};
|
||||
static uint32_t board_name = 0;
|
||||
|
||||
static struct BoardloaderVersion boardloader_version;
|
||||
|
||||
const uint8_t *get_board_name() { return board_name; }
|
||||
const uint32_t get_board_name() { return board_name; }
|
||||
|
||||
const struct BoardloaderVersion *get_boardloader_version() {
|
||||
return &boardloader_version;
|
||||
@ -49,7 +49,6 @@ void parse_boardloader_capabilities() {
|
||||
while (pos <= end - 2) {
|
||||
enum CapabilityTag tag = pos[0];
|
||||
uint8_t length = pos[1];
|
||||
uint8_t used_length;
|
||||
pos += 2;
|
||||
|
||||
if (pos + length > end) {
|
||||
@ -61,9 +60,10 @@ void parse_boardloader_capabilities() {
|
||||
// not used yet, just advance pointer
|
||||
break;
|
||||
case MODEL_NAME:
|
||||
used_length = MIN(MODEL_NAME_MAX_LENGTH, length);
|
||||
memcpy(board_name, pos, used_length);
|
||||
board_name[MODEL_NAME_MAX_LENGTH] = 0;
|
||||
if (length != sizeof(uint32_t)) {
|
||||
break;
|
||||
}
|
||||
memcpy((uint8_t *)&board_name, pos, sizeof(uint32_t));
|
||||
break;
|
||||
case BOARDLOADER_VERSION:
|
||||
if (length != sizeof(boardloader_version)) {
|
||||
|
@ -38,7 +38,6 @@ Last tag must be terminator or all space used.
|
||||
#define BOARD_CAPABILITIES_ADDR 0x0800BF00
|
||||
#define BOARD_CAPABILITIES_SIZE 256
|
||||
#define CAPABILITIES_HEADER "TRZC"
|
||||
#define MODEL_NAME_MAX_LENGTH 16
|
||||
|
||||
enum CapabilityTag {
|
||||
TERMINATOR = 0x00,
|
||||
@ -62,7 +61,7 @@ struct __attribute__((packed)) BoardCapabilities {
|
||||
uint8_t header[4];
|
||||
uint8_t model_tag;
|
||||
uint8_t model_length;
|
||||
uint8_t model_name[MODEL_NAME_MAX_LENGTH];
|
||||
uint32_t model_name;
|
||||
uint8_t version_tag;
|
||||
uint8_t version_length;
|
||||
struct BoardloaderVersion version;
|
||||
@ -76,7 +75,7 @@ struct __attribute__((packed)) BoardCapabilities {
|
||||
*/
|
||||
void parse_boardloader_capabilities();
|
||||
|
||||
const uint8_t* get_board_name();
|
||||
const uint32_t get_board_name();
|
||||
const struct BoardloaderVersion* get_boardloader_version();
|
||||
|
||||
#endif
|
||||
|
@ -50,57 +50,84 @@ static secbool compute_pubkey(uint8_t sig_m, uint8_t sig_n,
|
||||
return sectrue * (0 == ed25519_cosi_combine_publickeys(res, keys, sig_m));
|
||||
}
|
||||
|
||||
secbool load_image_header(const uint8_t *const data, const uint32_t magic,
|
||||
const uint32_t maxsize, uint8_t key_m, uint8_t key_n,
|
||||
const uint8_t *const *keys, image_header *const hdr) {
|
||||
memcpy(&hdr->magic, data, 4);
|
||||
if (hdr->magic != magic) return secfalse;
|
||||
const image_header *read_image_header(const uint8_t *const data,
|
||||
const uint32_t magic,
|
||||
const uint32_t maxsize) {
|
||||
const image_header *hdr = (const image_header *)data;
|
||||
|
||||
memcpy(&hdr->hdrlen, data + 4, 4);
|
||||
if (hdr->hdrlen != IMAGE_HEADER_SIZE) return secfalse;
|
||||
if (hdr->magic != magic) {
|
||||
return NULL;
|
||||
}
|
||||
if (hdr->hdrlen != IMAGE_HEADER_SIZE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&hdr->expiry, data + 8, 4);
|
||||
// TODO: expiry mechanism needs to be ironed out before production or those
|
||||
// devices won't accept expiring bootloaders (due to boardloader write
|
||||
// protection).
|
||||
if (hdr->expiry != 0) return secfalse;
|
||||
// lowest bit is used for breaking compatibility between old TT bootloaders
|
||||
// and non TT images
|
||||
// which is evaluated in check_image_model function
|
||||
if ((hdr->expiry & 0xFFFFFFFE) != 0) return secfalse;
|
||||
|
||||
memcpy(&hdr->codelen, data + 12, 4);
|
||||
if (hdr->codelen > (maxsize - hdr->hdrlen)) return secfalse;
|
||||
if ((hdr->hdrlen + hdr->codelen) < 4 * 1024) return secfalse;
|
||||
if ((hdr->hdrlen + hdr->codelen) % 512 != 0) return secfalse;
|
||||
|
||||
memcpy(&hdr->version, data + 16, 4);
|
||||
memcpy(&hdr->fix_version, data + 20, 4);
|
||||
return hdr;
|
||||
}
|
||||
|
||||
memcpy(hdr->hashes, data + 32, 512);
|
||||
secbool check_image_model(const image_header *const hdr) {
|
||||
// abusing expiry field to break compatibility of non-TT images with existing
|
||||
// bootloaders/boardloaders
|
||||
#ifdef TREZOR_MODEL_T
|
||||
if (hdr->expiry == 0 && hdr->hw_model == 0 && hdr->hw_revision == 0) {
|
||||
// images for model TT older than this check
|
||||
return sectrue;
|
||||
}
|
||||
#else
|
||||
if ((hdr->expiry & 0x01) == 0) {
|
||||
// for models other than TT, expiry == 0 is unacceptable, as the image will
|
||||
// run on bootloaders older that this check
|
||||
return secfalse;
|
||||
}
|
||||
#endif
|
||||
|
||||
memcpy(&hdr->sigmask, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE, 1);
|
||||
if (hdr->hw_model != HW_MODEL) {
|
||||
return secfalse;
|
||||
}
|
||||
if (hdr->hw_revision != HW_REVISION) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
memcpy(hdr->sig, data + IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE + 1,
|
||||
IMAGE_SIG_SIZE - 1);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool check_image_header_sig(const image_header *const hdr, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys) {
|
||||
// check header signature
|
||||
|
||||
BLAKE2S_CTX ctx;
|
||||
uint8_t fingerprint[32];
|
||||
|
||||
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
|
||||
blake2s_Update(&ctx, data, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE);
|
||||
blake2s_Update(&ctx, hdr, IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE);
|
||||
for (int i = 0; i < IMAGE_SIG_SIZE; i++) {
|
||||
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
|
||||
}
|
||||
blake2s_Final(&ctx, hdr->fingerprint, BLAKE2S_DIGEST_LENGTH);
|
||||
|
||||
blake2s_Final(&ctx, fingerprint, BLAKE2S_DIGEST_LENGTH);
|
||||
|
||||
ed25519_public_key pub;
|
||||
if (sectrue != compute_pubkey(key_m, key_n, keys, hdr->sigmask, pub))
|
||||
return secfalse;
|
||||
|
||||
return sectrue *
|
||||
(0 == ed25519_sign_open(hdr->fingerprint, BLAKE2S_DIGEST_LENGTH, pub,
|
||||
(0 == ed25519_sign_open(fingerprint, BLAKE2S_DIGEST_LENGTH, pub,
|
||||
*(const ed25519_signature *)hdr->sig));
|
||||
}
|
||||
|
||||
secbool read_vendor_header(const uint8_t *const data,
|
||||
vendor_header *const vhdr) {
|
||||
secbool __wur read_vendor_header(const uint8_t *const data,
|
||||
vendor_header *const vhdr) {
|
||||
memcpy(&vhdr->magic, data, 4);
|
||||
if (vhdr->magic != 0x565A5254) return secfalse; // TRZV
|
||||
|
||||
@ -110,6 +137,8 @@ secbool read_vendor_header(const uint8_t *const data,
|
||||
memcpy(&vhdr->expiry, data + 8, 4);
|
||||
if (vhdr->expiry != 0) return secfalse;
|
||||
|
||||
vhdr->origin = data;
|
||||
|
||||
memcpy(&vhdr->version, data + 12, 2);
|
||||
|
||||
memcpy(&vhdr->vsig_m, data + 14, 1);
|
||||
@ -143,10 +172,9 @@ secbool read_vendor_header(const uint8_t *const data,
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool load_vendor_header(const uint8_t *const data, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys,
|
||||
vendor_header *const vhdr) {
|
||||
if (sectrue != read_vendor_header(data, vhdr)) {
|
||||
secbool check_vendor_header_sig(const vendor_header *const vhdr, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys) {
|
||||
if (vhdr == NULL) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
@ -155,7 +183,7 @@ secbool load_vendor_header(const uint8_t *const data, uint8_t key_m,
|
||||
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
|
||||
BLAKE2S_CTX ctx;
|
||||
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
|
||||
blake2s_Update(&ctx, data, vhdr->hdrlen - IMAGE_SIG_SIZE);
|
||||
blake2s_Update(&ctx, vhdr->origin, vhdr->hdrlen - IMAGE_SIG_SIZE);
|
||||
for (int i = 0; i < IMAGE_SIG_SIZE; i++) {
|
||||
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
|
||||
}
|
||||
|
@ -45,12 +45,14 @@ typedef struct {
|
||||
uint32_t codelen;
|
||||
uint32_t version;
|
||||
uint32_t fix_version;
|
||||
// uint8_t reserved[8];
|
||||
uint32_t hw_model;
|
||||
uint8_t hw_revision;
|
||||
uint8_t monotonic;
|
||||
uint8_t reserved_0[2];
|
||||
uint8_t hashes[512];
|
||||
// uint8_t reserved[415];
|
||||
uint8_t reserved_1[415];
|
||||
uint8_t sigmask;
|
||||
uint8_t sig[64];
|
||||
uint8_t fingerprint[32];
|
||||
} image_header;
|
||||
|
||||
#define MAX_VENDOR_PUBLIC_KEYS 8
|
||||
@ -76,20 +78,26 @@ typedef struct {
|
||||
const uint8_t *vimg;
|
||||
uint8_t sigmask;
|
||||
uint8_t sig[64];
|
||||
const uint8_t *origin; // pointer to the underlying data
|
||||
} vendor_header;
|
||||
|
||||
secbool __wur load_image_header(const uint8_t *const data, const uint32_t magic,
|
||||
const uint32_t maxsize, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys,
|
||||
image_header *const hdr);
|
||||
const image_header *read_image_header(const uint8_t *const data,
|
||||
const uint32_t magic,
|
||||
const uint32_t maxsize);
|
||||
|
||||
secbool __wur load_vendor_header(const uint8_t *const data, uint8_t key_m,
|
||||
uint8_t key_n, const uint8_t *const *keys,
|
||||
vendor_header *const vhdr);
|
||||
secbool __wur check_image_model(const image_header *const hdr);
|
||||
|
||||
secbool __wur check_image_header_sig(const image_header *const hdr,
|
||||
uint8_t key_m, uint8_t key_n,
|
||||
const uint8_t *const *keys);
|
||||
|
||||
secbool __wur read_vendor_header(const uint8_t *const data,
|
||||
vendor_header *const vhdr);
|
||||
|
||||
secbool __wur check_vendor_header_sig(const vendor_header *const vhdr,
|
||||
uint8_t key_m, uint8_t key_n,
|
||||
const uint8_t *const *keys);
|
||||
|
||||
void vendor_header_hash(const vendor_header *const vhdr, uint8_t *hash);
|
||||
|
||||
secbool __wur check_single_hash(const uint8_t *const hash,
|
||||
|
@ -9,16 +9,27 @@ def add_font(font_name, font, defines, sources):
|
||||
sources.append(sourcefile)
|
||||
|
||||
|
||||
def get_hw_model_as_number(hw_model):
|
||||
return int.from_bytes(hw_model.encode(), 'little')
|
||||
|
||||
|
||||
|
||||
def configure_board(model, env, defines, sources):
|
||||
model_r_version = 4
|
||||
|
||||
if model in ('1',):
|
||||
board = 'trezor_1.h'
|
||||
display = 'vg-2864ksweg01.c'
|
||||
hw_model = get_hw_model_as_number('T1B1')
|
||||
hw_revision = 0
|
||||
elif model in ('T',):
|
||||
board = 'trezor_t.h'
|
||||
display = 'st7789v.c'
|
||||
hw_model = get_hw_model_as_number('T2T1')
|
||||
hw_revision = 0
|
||||
elif model in ('R',):
|
||||
hw_model = get_hw_model_as_number('T2B1')
|
||||
hw_revision = model_r_version
|
||||
if model_r_version == 3:
|
||||
board = 'trezor_r_v3.h'
|
||||
display = "ug-2828tswig01.c"
|
||||
@ -29,5 +40,7 @@ def configure_board(model, env, defines, sources):
|
||||
raise Exception("Unknown model")
|
||||
|
||||
defines += [f'TREZOR_BOARD=\\"boards/{board}\\"', ]
|
||||
defines += [f'HW_MODEL={hw_model}', ]
|
||||
defines += [f'HW_REVISION={hw_revision}', ]
|
||||
sources += [f'embed/trezorhal/displays/{display}', ]
|
||||
env.get('ENV')['TREZOR_BOARD'] = board
|
||||
|
Loading…
Reference in New Issue
Block a user