diff --git a/embed/bootloader/bootui.c b/embed/bootloader/bootui.c index e4e1b4d62..95787ba16 100644 --- a/embed/bootloader/bootui.c +++ b/embed/bootloader/bootui.c @@ -89,8 +89,20 @@ void ui_screen_third(void) display_text_center(120, 220, "Open trezor.io/start", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); } +// buttons + +static void ui_confirm_cancel_buttons(void) +{ + display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4); + display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL); + display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4); + display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); +} + // info UI + + void ui_screen_info(secbool buttons, const vendor_header * const vhdr, const image_header * const hdr) { display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); @@ -120,10 +132,7 @@ void ui_screen_info(secbool buttons, const vendor_header * const vhdr, const ima if (sectrue == buttons) { display_text_center(120, 170, "Connect to host?", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); - display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4); - display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL); - display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4); - display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); + ui_confirm_cancel_buttons(); } else { display_text_center(120, 220, "Open trezor.io/start", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); } @@ -151,19 +160,43 @@ void ui_screen_info_fingerprint(const image_header * const hdr) // install UI -void ui_screen_install_confirm(void) +void ui_screen_install_confirm_upgrade(const vendor_header * const vhdr, const image_header * const hdr) { display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); display_text(16, 32, "Firmware update", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BLACK, COLOR_WHITE); - display_text(55, 70, "Do you want to", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); - display_text(55, 95, "update firmware?", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + display_text(55, 70, "Update firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + char ver_str[32]; + mini_snprintf(ver_str, sizeof(ver_str), "to version %d.%d.%d.%d?", + (int)(hdr->version & 0xFF), + (int)((hdr->version >> 8) & 0xFF), + (int)((hdr->version >> 16) & 0xFF), + (int)((hdr->version >> 24) & 0xFF) + ); + display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + ui_confirm_cancel_buttons(); +} - display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4); - display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL); - display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4); - display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); +void ui_screen_install_confirm_newvendor(const vendor_header * const vhdr, const image_header * const hdr) +{ + display_bar(0, 0, DISPLAY_RESX, DISPLAY_RESY, COLOR_WHITE); + display_text(16, 32, "Re-install firmware", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + display_bar(16, 44, DISPLAY_RESX - 14 * 2, 1, COLOR_BLACK); + display_icon(16, 54, 32, 32, toi_icon_info + 12, sizeof(toi_icon_info) - 12, COLOR_BLACK, COLOR_WHITE); + display_text(55, 70, "Install firmware by", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + display_text(55, 95, vhdr->vstr, vhdr->vstr_len, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + char ver_str[32]; + mini_snprintf(ver_str, sizeof(ver_str), "(version %d.%d.%d.%d)?", + (int)(hdr->version & 0xFF), + (int)((hdr->version >> 8) & 0xFF), + (int)((hdr->version >> 16) & 0xFF), + (int)((hdr->version >> 24) & 0xFF) + ); + display_text(55, 120, ver_str, -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); + display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, COLOR_BL_FAIL, COLOR_WHITE, 0); + ui_confirm_cancel_buttons(); } void ui_screen_install(void) @@ -175,7 +208,7 @@ void ui_screen_install(void) void ui_screen_install_progress_erase(int pos, int len) { - display_loader(200 + 200 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK); + display_loader(250 * pos / len, -20, COLOR_BL_PROCESS, COLOR_WHITE, toi_icon_install, sizeof(toi_icon_install), COLOR_BLACK); } void ui_screen_install_progress_upload(int pos) @@ -195,11 +228,7 @@ void ui_screen_wipe_confirm(void) display_text(55, 95, "wipe the device?", -1, FONT_NORMAL, COLOR_BLACK, COLOR_WHITE, 0); display_text_center(120, 170, "Seed will be erased!", -1, FONT_NORMAL, COLOR_BL_FAIL, COLOR_WHITE, 0); - - display_bar_radius(9, 184, 108, 50, COLOR_BL_FAIL, COLOR_WHITE, 4); - display_icon(9 + (108 - 16) / 2, 184 + (50 - 16) / 2, 16, 16, toi_icon_cancel + 12, sizeof(toi_icon_cancel) - 12, COLOR_WHITE, COLOR_BL_FAIL); - display_bar_radius(123, 184, 108, 50, COLOR_BL_DONE, COLOR_WHITE, 4); - display_icon(123 + (108 - 19) / 2, 184 + (50 - 16) / 2, 20, 16, toi_icon_confirm + 12, sizeof(toi_icon_confirm) - 12, COLOR_WHITE, COLOR_BL_DONE); + ui_confirm_cancel_buttons(); } void ui_screen_wipe(void) diff --git a/embed/bootloader/bootui.h b/embed/bootloader/bootui.h index c0e67b731..f2e4aebfe 100644 --- a/embed/bootloader/bootui.h +++ b/embed/bootloader/bootui.h @@ -15,7 +15,8 @@ void ui_screen_third(void); void ui_screen_info(secbool buttons, const vendor_header * const vhdr, const image_header * const hdr); void ui_screen_info_fingerprint(const image_header * const hdr); -void ui_screen_install_confirm(void); +void ui_screen_install_confirm_upgrade(const vendor_header * const vhdr, const image_header * const hdr); +void ui_screen_install_confirm_newvendor(const vendor_header * const vhdr, const image_header * const hdr); void ui_screen_install(void); void ui_screen_install_progress_erase(int pos, int len); void ui_screen_install_progress_upload(int pos); diff --git a/embed/bootloader/main.c b/embed/bootloader/main.c index c3aa6b1f9..5d828ab7c 100644 --- a/embed/bootloader/main.c +++ b/embed/bootloader/main.c @@ -159,28 +159,11 @@ static secbool bootloader_usb_loop(const vendor_header * const vhdr, const image } break; case 6: // FirmwareErase - // skip confirmation when no firmware is present - if (vhdr && hdr) { - ui_fadeout(); - ui_screen_install_confirm(); - ui_fadein(); - int response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); - if (INPUT_CANCEL == response) { - ui_fadeout(); - ui_screen_info(secfalse, vhdr, hdr); - ui_fadein(); - send_user_abort(USB_IFACE_NUM, "Firmware install cancelled"); - break; - } - } - ui_fadeout(); - ui_screen_install(); - ui_fadein(); process_msg_FirmwareErase(USB_IFACE_NUM, msg_size, buf); break; case 7: // FirmwareUpload r = process_msg_FirmwareUpload(USB_IFACE_NUM, msg_size, buf); - if (r < 0) { // error + if (r < 0 && r != -4) { // error, but not user abort (-4) ui_fadeout(); ui_screen_fail(); ui_fadein(); diff --git a/embed/bootloader/messages.c b/embed/bootloader/messages.c index f1137aeff..e91b1c140 100644 --- a/embed/bootloader/messages.c +++ b/embed/bootloader/messages.c @@ -315,14 +315,9 @@ static bool _read_payload(pb_istream_t *stream, const pb_field_t *field, void ** chunk_size = stream->bytes_left; while (stream->bytes_left) { - // update loader - if (firmware_block == 0) { - // first chunk is 0 - 200 - // followed by erase 200 - 400 - ui_screen_install_progress_upload(200 * chunk_written / chunk_size); - } else { - // remaining chunks are 400 - 1000 - ui_screen_install_progress_upload(400 + 600 * (firmware_block * IMAGE_CHUNK_SIZE + chunk_written) / (firmware_block * IMAGE_CHUNK_SIZE + firmware_remaining)); + // update loader but skip first block + if (firmware_block > 0) { + ui_screen_install_progress_upload(250 + 750 * (firmware_block * IMAGE_CHUNK_SIZE + chunk_written) / (firmware_block * IMAGE_CHUNK_SIZE + firmware_remaining)); } // read data if (!pb_read(stream, (pb_byte_t *)(chunk_buffer + chunk_written), (stream->bytes_left > BUFSIZE) ? BUFSIZE : stream->bytes_left)) { @@ -354,26 +349,28 @@ static int version_compare(uint32_t vera, uint32_t verb) return a - b; } -static secbool is_legit_upgrade(const vendor_header * const new_vhdr, const image_header * const new_hdr) +static void detect_installation(vendor_header *current_vhdr, image_header *current_hdr, const vendor_header * const new_vhdr, const image_header * const new_hdr, secbool *is_new, secbool *is_upgrade) { - vendor_header current_vhdr; - if (sectrue != load_vendor_header_keys((const uint8_t *)FIRMWARE_START, ¤t_vhdr)) { - return secfalse; + *is_new = secfalse; + *is_upgrade = secfalse; + if (sectrue != load_vendor_header_keys((const uint8_t *)FIRMWARE_START, 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)) { + *is_new = sectrue; + return; } uint8_t hash1[32], hash2[32]; vendor_keys_hash(new_vhdr, hash1); - vendor_keys_hash(¤t_vhdr, hash2); + vendor_keys_hash(current_vhdr, hash2); if (0 != memcmp(hash1, hash2, 32)) { - return secfalse; + return; } - image_header current_hdr; - 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, ¤t_hdr)) { - return secfalse; + if (version_compare(new_hdr->version, current_hdr->fix_version) < 0) { + return; } - if (version_compare(new_hdr->version, current_hdr.fix_version) < 0) { - return secfalse; - } - return sectrue; + *is_upgrade = sectrue; } int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *buf) @@ -410,7 +407,44 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *bu return -3; } - if (sectrue != is_legit_upgrade(&vhdr, &hdr)) { + vendor_header current_vhdr; + image_header current_hdr; + secbool is_new = secfalse, is_upgrade = secfalse; + detect_installation(¤t_vhdr, ¤t_hdr, &vhdr, &hdr, &is_new, &is_upgrade); + + int response = INPUT_CANCEL; + if (sectrue == is_new) { + // new installation - auto confirm + response = INPUT_CONFIRM; + } else + if (sectrue == is_upgrade) { + // firmware upgrade + ui_fadeout(); + ui_screen_install_confirm_upgrade(&vhdr, &hdr); + ui_fadein(); + response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); + } else { + // new firmware vendor + ui_fadeout(); + ui_screen_install_confirm_newvendor(&vhdr, &hdr); + ui_fadein(); + response = ui_user_input(INPUT_CONFIRM | INPUT_CANCEL); + } + + if (INPUT_CANCEL == response) { + ui_fadeout(); + ui_screen_info(secfalse, ¤t_vhdr, ¤t_hdr); + ui_fadein(); + send_user_abort(USB_IFACE_NUM, "Firmware install cancelled"); + return -4; + } + + ui_fadeout(); + ui_screen_install(); + ui_fadein(); + + // if firmware is not upgrade, erase storage + if (sectrue != is_upgrade) { const uint8_t sectors_storage[] = { FLASH_SECTOR_STORAGE_1, FLASH_SECTOR_STORAGE_2, @@ -428,7 +462,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *bu MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Firmware too big"); MSG_SEND(Failure); - return -3; + return -5; } if (sectrue != check_single_hash(hdr.hashes + firmware_block * 32, chunk_buffer + firstskip, chunk_size - firstskip)) { @@ -436,7 +470,7 @@ int process_msg_FirmwareUpload(uint8_t iface_num, uint32_t msg_size, uint8_t *bu MSG_SEND_ASSIGN_VALUE(code, FailureType_Failure_ProcessError); MSG_SEND_ASSIGN_STRING(message, "Invalid chunk hash"); MSG_SEND(Failure); - return -4; + return -6; } ensure(flash_unlock(), NULL);