From 07231d936e41335b3ec44c4c6eb336be006890d0 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sun, 27 Jan 2019 11:58:30 +0100 Subject: [PATCH] introduce new memory layout firmware header is now stored with code, not within the storage sectors --- Makefile.include | 4 +- bootloader/bootloader.c | 80 +++--- bootloader/bootloader.h | 14 +- bootloader/firmware_align.py | 2 +- bootloader/firmware_sign.py | 135 +++++---- bootloader/firmware_sign_split.py | 8 +- bootloader/signatures.c | 120 +++++++- bootloader/signatures.h | 41 ++- bootloader/usb.c | 456 +++++++++++------------------- bootloader/usb.h | 2 +- bootloader/usb_desc.h | 75 +++++ bootloader/usb_erase.h | 44 +++ bootloader/usb_send.h | 86 ++++++ emulator/memory.c | 3 +- firmware/Makefile | 3 +- firmware/config.c | 11 +- firmware/header.S | 33 +++ firmware/trezor.h | 5 +- firmware/version.h | 7 + memory.c | 4 +- memory.h | 85 +++--- memory_app_1.8.0.ld | 31 ++ setup.c | 2 +- supervise.c | 6 +- 24 files changed, 774 insertions(+), 483 deletions(-) create mode 100644 bootloader/usb_desc.h create mode 100644 bootloader/usb_erase.h create mode 100644 bootloader/usb_send.h create mode 100644 firmware/header.S create mode 100644 firmware/version.h create mode 100644 memory_app_1.8.0.ld diff --git a/Makefile.include b/Makefile.include index fdf6b5fca..029dddae7 100644 --- a/Makefile.include +++ b/Makefile.include @@ -134,8 +134,10 @@ endif ifeq ($(MEMORY_PROTECT), 0) CFLAGS += -DMEMORY_PROTECT=0 +$(info MEMORY_PROTECT=0) else CFLAGS += -DMEMORY_PROTECT=1 +$(info MEMORY_PROTECT=1) endif ifeq ($(DEBUG_RNG), 1) @@ -159,7 +161,7 @@ flash: $(NAME).bin $(OPENOCD) -c "init; reset halt; flash write_image erase $(NAME).bin 0x8000000; exit" upload: sign - trezorctl firmware_update -f $(NAME).bin + trezorctl firmware_update -f $(NAME).bin -s sign: $(NAME).bin $(PYTHON) ../bootloader/firmware_sign.py -f $(NAME).bin diff --git a/bootloader/bootloader.c b/bootloader/bootloader.c index 292632db2..4c561783f 100644 --- a/bootloader/bootloader.c +++ b/bootloader/bootloader.c @@ -24,6 +24,7 @@ #include #include "bootloader.h" +#include "signatures.h" #include "buttons.h" #include "setup.h" #include "usb.h" @@ -33,8 +34,9 @@ #include "layout.h" #include "rng.h" #include "timer.h" +#include "memory.h" -void layoutFirmwareHash(const uint8_t *hash) +void layoutFirmwareFingerprint(const uint8_t *hash) { char str[4][17]; for (int i = 0; i < 4; i++) { @@ -43,40 +45,41 @@ void layoutFirmwareHash(const uint8_t *hash) layoutDialog(&bmp_icon_question, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL); } -void show_halt(void) +bool get_button_response(void) +{ + do { + delay(100000); + buttonUpdate(); + } while (!button.YesUp && !button.NoUp); + return button.YesUp; +} + +static void show_halt(void) { - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); shutdown(); } -void show_unofficial_warning(const uint8_t *hash) +static void show_unofficial_warning(const uint8_t *hash) { layoutDialog(&bmp_icon_warning, "Abort", "I'll take the risk", NULL, "WARNING!", NULL, "Unofficial firmware", "detected.", NULL, NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - - if (button.NoUp) { - show_halt(); // no button was pressed -> halt + bool but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt(); } - layoutFirmwareHash(hash); + layoutFirmwareFingerprint(hash); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - - if (button.NoUp) { - show_halt(); // no button was pressed -> halt + but = get_button_response(); + if (!but) { // no button was pressed -> halt + show_halt(); } // everything is OK, user pressed 2x Continue -> continue program } -void __attribute__((noreturn)) load_app(int signed_firmware) +static void __attribute__((noreturn)) load_app(int signed_firmware) { // zero out SRAM memset_reg(_ram_start, _ram_end, 0); @@ -84,27 +87,11 @@ void __attribute__((noreturn)) load_app(int signed_firmware) jump_to_firmware((const vector_table_t *) FLASH_PTR(FLASH_APP_START), signed_firmware); } -bool firmware_present(void) -{ -#ifndef APPVER - if (memcmp(FLASH_PTR(FLASH_META_MAGIC), "TRZR", 4)) { // magic does not match - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 4096) { // firmware reports smaller size than 4kB - return false; - } - if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size - return false; - } -#endif - return true; -} - -void bootloader_loop(void) +static void bootloader_loop(void) { oledClear(); oledDrawBitmap(0, 0, &bmp_logo64); - if (firmware_present()) { + if (firmware_present_new()) { oledDrawStringCenter(90, 10, "TREZOR", FONT_STANDARD); oledDrawStringCenter(90, 30, "Bootloader", FONT_STANDARD); oledDrawStringCenter(90, 50, VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH), FONT_STANDARD); @@ -115,7 +102,7 @@ void bootloader_loop(void) } oledRefresh(); - usbLoop(firmware_present()); + usbLoop(); } int main(void) @@ -136,19 +123,26 @@ int main(void) uint16_t state = gpio_port_read(BTN_PORT); int unpressed = ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO); - if (firmware_present() && unpressed) { + if (firmware_present_new() && unpressed) { oledClear(); oledDrawBitmap(40, 0, &bmp_logo64_empty); oledRefresh(); - uint8_t hash[32]; - int signed_firmware = signatures_ok(hash); + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + + uint8_t fingerprint[32]; + int signed_firmware = signatures_new_ok(hdr, fingerprint); if (SIG_OK != signed_firmware) { - show_unofficial_warning(hash); + show_unofficial_warning(fingerprint); timer_init(); } + if (SIG_OK != check_firmware_hashes(hdr)) { + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Broken firmware", "detected.", NULL, "Unplug your TREZOR,", "reinstall firmware.", NULL); + shutdown(); + } + mpu_config_off(); load_app(signed_firmware); } diff --git a/bootloader/bootloader.h b/bootloader/bootloader.h index c7f214f08..6f70df227 100644 --- a/bootloader/bootloader.h +++ b/bootloader/bootloader.h @@ -21,20 +21,20 @@ #define __BOOTLOADER_H__ #define VERSION_MAJOR 1 -#define VERSION_MINOR 6 -#define VERSION_PATCH 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 #define STR(X) #X #define VERSTR(X) STR(X) #define VERSION_MAJOR_CHAR "\x01" -#define VERSION_MINOR_CHAR "\x06" -#define VERSION_PATCH_CHAR "\x01" +#define VERSION_MINOR_CHAR "\x08" +#define VERSION_PATCH_CHAR "\x00" +#include #include -#include "memory.h" -void layoutFirmwareHash(const uint8_t *hash); -bool firmware_present(void); +void layoutFirmwareFingerprint(const uint8_t *hash); +bool get_button_response(void); #endif diff --git a/bootloader/firmware_align.py b/bootloader/firmware_align.py index 3d766862f..ab5b1c6bf 100755 --- a/bootloader/firmware_align.py +++ b/bootloader/firmware_align.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 import sys import os diff --git a/bootloader/firmware_sign.py b/bootloader/firmware_sign.py index 2b3a2c17e..a7b8e13cf 100755 --- a/bootloader/firmware_sign.py +++ b/bootloader/firmware_sign.py @@ -7,10 +7,6 @@ import struct import ecdsa -try: - raw_input -except: - raw_input = input SLOTS = 3 @@ -22,8 +18,9 @@ pubkeys = { 5: "047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45", } -INDEXES_START = len("TRZR") + struct.calcsize(" size: + raise ValueError("Chunk too big already") + if len(data) == size: + return data + return data + b"\xFF" * (size - len(data)) - meta = b"TRZR" # magic - if data[:4] == b"TRZR": - meta += data[4 : 4 + struct.calcsize(" 0: + chunk = pad_to_size(sector, end - start) + hashes.append(hashlib.sha256(chunk).digest()) + else: + hashes.append(b"\x00" * 32) + start = end + end += 64 * 1024 + return hashes + + +def check_hashes(data): + expected_hashes = data[0x20 : 0x20 + 16 * 32] + hashes = b"" + for h in prepare_hashes(data[FWHEADER_SIZE:]): + hashes += h + + if expected_hashes == hashes: + print("HASHES OK") else: - meta += struct.pack(" SLOTS: raise Exception("Invalid slot") @@ -145,28 +171,28 @@ def sign(data, is_pem): print("(blank private key removes the signature on given index)") pem_key = "" while True: - key = raw_input() + key = input() pem_key += key + "\n" if key == "": break if pem_key.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, "\x00" * 64) + return modify(data, slot, 0, b"\x00" * 64) key = ecdsa.SigningKey.from_pem(pem_key) else: print("Paste SECEXP (in hex) and press Enter:") print("(blank private key removes the signature on given index)") - secexp = raw_input() + secexp = input() if secexp.strip() == "": # Blank key,let's remove existing signature from slot - return modify(data, slot, 0, "\x00" * 64) + return modify(data, slot, 0, b"\x00" * 64) key = ecdsa.SigningKey.from_secret_exponent( secexp=int(secexp, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256, ) - to_sign = prepare(data)[256:] # without meta + to_sign = get_header(data, zero_signatures=True) # Locate proper index of current signing key pubkey = "04" + key.get_verifying_key().to_string().hex() @@ -207,20 +233,21 @@ def main(args): data = open(args.path, "rb").read() assert len(data) % 4 == 0 - if data[:4] != b"TRZR": - print("Metadata has been added...") - data = prepare(data) - - if data[:4] != b"TRZR": + if data[:4] != b"TRZF": raise Exception("Firmware header expected") + data = update_hashes_in_header(data) + print("Firmware size %d bytes" % len(data)) + check_size(data) check_signatures(data) + check_hashes(data) if args.sign: data = sign(data, args.pem) check_signatures(data) + check_hashes(data) fp = open(args.path, "wb") fp.write(data) diff --git a/bootloader/firmware_sign_split.py b/bootloader/firmware_sign_split.py index 47b18e497..25c4b341f 100755 --- a/bootloader/firmware_sign_split.py +++ b/bootloader/firmware_sign_split.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python -from __future__ import print_function +#!/usr/bin/env python3 import hashlib import os import subprocess @@ -7,10 +6,7 @@ import ecdsa from binascii import hexlify, unhexlify print('master secret:', end='') -try: - h = raw_input() -except: - h = input() +h = input() if h: h = unhexlify(h).encode('ascii') else: diff --git a/bootloader/signatures.c b/bootloader/signatures.c index e178ecec7..512117de5 100644 --- a/bootloader/signatures.c +++ b/bootloader/signatures.c @@ -17,7 +17,6 @@ * along with this library. If not, see . */ -#include #include #include "signatures.h" @@ -25,6 +24,11 @@ #include "secp256k1.h" #include "sha2.h" #include "bootloader.h" +#include "memory.h" +#include "memzero.h" + +const uint32_t FIRMWARE_MAGIC_OLD = 0x525a5254; // TRZR +const uint32_t FIRMWARE_MAGIC_NEW = 0x465a5254; // TRZF #define PUBKEYS 5 @@ -38,19 +42,45 @@ static const uint8_t * const pubkey[PUBKEYS] = { #define SIGNATURES 3 -int signatures_ok(uint8_t *store_hash) +#define FLASH_META_START 0x08008000 +#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) +#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) +#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) +#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) +#define FLASH_OLD_APP_START 0x08010000 +#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) +#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) +#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) + +bool firmware_present_old(void) +{ + if (memcmp(FLASH_PTR(FLASH_META_START), &FIRMWARE_MAGIC_OLD, 4)) { // magic does not match + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) < 8192) { // firmware reports smaller size than 8192 + return false; + } + if (*((const uint32_t *)FLASH_PTR(FLASH_META_CODELEN)) > FLASH_APP_LEN) { // firmware reports bigger size than flash size + return false; + } + + return true; +} + +int signatures_old_ok(void) { const uint32_t codelen = *((const uint32_t *)FLASH_META_CODELEN); const uint8_t sigindex1 = *((const uint8_t *)FLASH_META_SIGINDEX1); const uint8_t sigindex2 = *((const uint8_t *)FLASH_META_SIGINDEX2); const uint8_t sigindex3 = *((const uint8_t *)FLASH_META_SIGINDEX3); - uint8_t hash[32]; - sha256_Raw((const uint8_t *)FLASH_APP_START, codelen, hash); - if (store_hash) { - memcpy(store_hash, hash, 32); + if (codelen > FLASH_APP_LEN) { + return false; } + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_OLD_APP_START), codelen, hash); + if (sigindex1 < 1 || sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex2 < 1 || sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index if (sigindex3 < 1 || sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index @@ -71,3 +101,81 @@ int signatures_ok(uint8_t *store_hash) return SIG_OK; } + +void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]) +{ + image_header copy; + memcpy(©, hdr, sizeof(image_header)); + memzero(copy.sig1, sizeof(copy.sig1)); + memzero(copy.sig2, sizeof(copy.sig2)); + memzero(copy.sig3, sizeof(copy.sig3)); + copy.sigindex1 = 0; + copy.sigindex2 = 0; + copy.sigindex3 = 0; + sha256_Raw((const uint8_t *)©, sizeof(image_header), hash); +} + +bool firmware_present_new(void) +{ + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + if (hdr->magic != FIRMWARE_MAGIC_NEW) return false; + if (hdr->hdrlen != FLASH_FWHEADER_LEN) return false; + if (hdr->codelen > FLASH_APP_LEN) return false; + if (hdr->codelen < 4096) return false; + + return true; +} + +int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]) +{ + uint8_t hash[32]; + compute_firmware_fingerprint(hdr, hash); + + if (store_fingerprint) { + memcpy(store_fingerprint, hash, 32); + } + + if (hdr->sigindex1 < 1 || hdr->sigindex1 > PUBKEYS) return SIG_FAIL; // invalid index + if (hdr->sigindex2 < 1 || hdr->sigindex2 > PUBKEYS) return SIG_FAIL; // invalid index + if (hdr->sigindex3 < 1 || hdr->sigindex3 > PUBKEYS) return SIG_FAIL; // invalid index + + if (hdr->sigindex1 == hdr->sigindex2) return SIG_FAIL; // duplicate use + if (hdr->sigindex1 == hdr->sigindex3) return SIG_FAIL; // duplicate use + if (hdr->sigindex2 == hdr->sigindex3) return SIG_FAIL; // duplicate use + + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex1 - 1], hdr->sig1, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex2 - 1], hdr->sig2, hash)) { // failure + return SIG_FAIL; + } + if (0 != ecdsa_verify_digest(&secp256k1, pubkey[hdr->sigindex3 - 1], hdr->sig3, hash)) { // failure + return SIG_FAIL; + } + + return SIG_OK; +} + +int check_firmware_hashes(const image_header *hdr) +{ + uint8_t hash[32]; + // check hash of the first code chunk + sha256_Raw(FLASH_PTR(FLASH_APP_START), (64 - 1) * 1024, hash); + if (0 != memcmp(hash, hdr->hashes, 32)) return SIG_FAIL; + // check remaining used chunks + uint32_t total_len = FLASH_FWHEADER_LEN + hdr->codelen; + int used_chunks = total_len / FW_CHUNK_SIZE; + if (total_len % FW_CHUNK_SIZE > 0) { + used_chunks++; + } + for (int i = 1; i < used_chunks; i++) { + sha256_Raw(FLASH_PTR(FLASH_FWHEADER_START + (64 * i) * 1024), 64 * 1024, hash); + if (0 != memcmp(hdr->hashes + 32 * i, hash, 32)) return SIG_FAIL; + } + // check unused chunks + for (int i = used_chunks; i < 16; i++) { + if (0 != memcmp(hdr->hashes + 32 * i, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) return SIG_FAIL; + } + // all OK + return SIG_OK; +} diff --git a/bootloader/signatures.h b/bootloader/signatures.h index 01b5f308c..ea4f8c2ca 100644 --- a/bootloader/signatures.h +++ b/bootloader/signatures.h @@ -20,9 +20,48 @@ #ifndef __SIGNATURES_H__ #define __SIGNATURES_H__ +#include +#include + +extern const uint32_t FIRMWARE_MAGIC_OLD; // TRZR +extern const uint32_t FIRMWARE_MAGIC_NEW; // TRZF + #define SIG_OK 0x5A3CA5C3 #define SIG_FAIL 0x00000000 -int signatures_ok(uint8_t *store_hash); +bool firmware_present_old(void); +int signatures_old_ok(void); + +// we use the same structure as T2 firmware header +// but we don't use the field sig +// and rather introduce fields sig1, sig2, sig3 +// immediately following the chunk hashes + +typedef struct { + uint32_t magic; + uint32_t hdrlen; + uint32_t expiry; + uint32_t codelen; + uint32_t version; + uint32_t fix_version; + uint8_t __reserved1[8]; + uint8_t hashes[512]; + uint8_t sig1[64]; + uint8_t sig2[64]; + uint8_t sig3[64]; + uint8_t sigindex1; + uint8_t sigindex2; + uint8_t sigindex3; + uint8_t __reserved2[220]; + uint8_t __sigmask; + uint8_t __sig[64]; +} __attribute__((packed)) image_header; + +#define FW_CHUNK_SIZE 65536 + +bool firmware_present_new(void); +void compute_firmware_fingerprint(const image_header *hdr, uint8_t hash[32]); +int signatures_new_ok(const image_header *hdr, uint8_t store_fingerprint[32]); +int check_firmware_hashes(const image_header *hdr); #endif diff --git a/bootloader/usb.c b/bootloader/usb.c index 4532b6a1d..6af381606 100644 --- a/bootloader/usb.c +++ b/bootloader/usb.c @@ -34,91 +34,15 @@ #include "ecdsa.h" #include "secp256k1.h" #include "memzero.h" +#include "memory.h" #include "usb21_standard.h" #include "webusb.h" #include "winusb.h" -#define FIRMWARE_MAGIC "TRZR" - -#define USB_INTERFACE_INDEX_MAIN 0 - -#define ENDPOINT_ADDRESS_IN (0x81) -#define ENDPOINT_ADDRESS_OUT (0x01) - -static bool brand_new_firmware; -static bool old_was_unsigned; - -static const struct usb_device_descriptor dev_descr = { - .bLength = USB_DT_DEVICE_SIZE, - .bDescriptorType = USB_DT_DEVICE, - .bcdUSB = 0x0210, - .bDeviceClass = 0, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - .bMaxPacketSize0 = 64, - .idVendor = 0x1209, - .idProduct = 0x53c0, - .bcdDevice = 0x0100, - .iManufacturer = 1, - .iProduct = 2, - .iSerialNumber = 3, - .bNumConfigurations = 1, -}; - -static const struct usb_endpoint_descriptor endpoints[2] = {{ - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_IN, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}, { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = ENDPOINT_ADDRESS_OUT, - .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, - .wMaxPacketSize = 64, - .bInterval = 1, -}}; - -static const struct usb_interface_descriptor iface[] = {{ - .bLength = USB_DT_INTERFACE_SIZE, - .bDescriptorType = USB_DT_INTERFACE, - .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_VENDOR, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = 0, - .endpoint = endpoints, - .extra = NULL, - .extralen = 0, -}}; - -static const struct usb_interface ifaces[] = {{ - .num_altsetting = 1, - .altsetting = iface, -}}; - -static const struct usb_config_descriptor config = { - .bLength = USB_DT_CONFIGURATION_SIZE, - .bDescriptorType = USB_DT_CONFIGURATION, - .wTotalLength = 0, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 0, - .bmAttributes = 0x80, - .bMaxPower = 0x32, - .interface = ifaces, -}; - -static const char *usb_strings[] = { - "SatoshiLabs", - "TREZOR", - "000000000000000000000000", -}; +#include "usb_desc.h" +#include "usb_send.h" +#include "usb_erase.h" enum { STATE_READY, @@ -130,121 +54,77 @@ enum { }; static uint32_t flash_pos = 0, flash_len = 0; +static uint32_t chunk_idx = 0; static char flash_state = STATE_READY; -static uint8_t flash_anim = 0; -static uint16_t msg_id = 0xFFFF; -static uint32_t msg_size = 0; - -static uint8_t meta_backup[FLASH_META_LEN]; - -static void send_msg_success(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Success message (id 2), payload len 0 - memcpy(response, - // header - "?##" - // msg_id - "\x00\x02" - // msg_size - "\x00\x00\x00\x00", - 9); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} -static void send_msg_failure(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Failure message (id 3), payload len 2 - // - code = 99 (Failure_FirmwareError) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x03" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x63", - 11); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} - -static void send_msg_features(usbd_device *dev) -{ - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: Features message (id 17), payload len 25 - // - vendor = "trezor.io" - // - major_version = VERSION_MAJOR - // - minor_version = VERSION_MINOR - // - patch_version = VERSION_PATCH - // - bootloader_mode = True - // - firmware_present = True/False - // - model = "1" - memcpy(response, - // header - "?##" - // msg_id - "\x00\x11" - // msg_size - "\x00\x00\x00\x16" - // data - "\x0a" "\x09" "trezor.io" - "\x10" VERSION_MAJOR_CHAR - "\x18" VERSION_MINOR_CHAR - "\x20" VERSION_PATCH_CHAR - "\x28" "\x01" - "\x90\x01" "\x00" - "\xaa" "\x01" "1", - 34); - response[30] = brand_new_firmware ? 0x01 : 0x00; - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} +static uint32_t FW_HEADER[FLASH_FWHEADER_LEN/sizeof(uint32_t)]; +static uint32_t FW_CHUNK[FW_CHUNK_SIZE/sizeof(uint32_t)]; -static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) +static void check_and_write_chunk(void) { - uint8_t response[64]; - memzero(response, sizeof(response)); - // response: ButtonRequest message (id 26), payload len 2 - // - code = ButtonRequest_FirmwareCheck (9) - memcpy(response, - // header - "?##" - // msg_id - "\x00\x1a" - // msg_size - "\x00\x00\x00\x02" - // data - "\x08" "\x09", - 11 - ); - while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} -} + uint32_t offset = (chunk_idx == 0) ? FLASH_FWHEADER_LEN : 0; + uint32_t chunk_pos = flash_pos % FW_CHUNK_SIZE; + if (chunk_pos == 0) { + chunk_pos = FW_CHUNK_SIZE; + } + uint8_t hash[32]; + SHA256_CTX ctx; + sha256_Init(&ctx); + sha256_Update(&ctx, (const uint8_t *)FW_CHUNK + offset, chunk_pos - offset); + if (chunk_pos < 64 * 1024) { + // pad with FF + for (uint32_t i = chunk_pos; i < 64 * 1024; i += 4) { + sha256_Update(&ctx, (const uint8_t *)"\xFF\xFF\xFF\xFF", 4); + } + } + sha256_Final(&ctx, hash); -static void backup_metadata(uint8_t *backup) -{ - memcpy(backup, FLASH_PTR(FLASH_META_START), FLASH_META_LEN); -} + const image_header *hdr = (const image_header *)FW_HEADER; + // invalid chunk sent + if (0 != memcmp(hash, hdr->hashes + chunk_idx * 32, 32)) { + // erase storage + erase_storage(); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } -static void restore_metadata(const uint8_t *backup) -{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); flash_unlock(); - for (int i = 0; i < FLASH_META_LEN / 4; i++) { - const uint32_t *w = (const uint32_t *)(backup + i * 4); - flash_program_word(FLASH_META_START + i * 4, *w); + for (uint32_t i = offset/sizeof(uint32_t); i < chunk_pos/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + chunk_idx * FW_CHUNK_SIZE + i * sizeof(uint32_t), FW_CHUNK[i]); } + flash_wait_for_last_operation(); flash_lock(); + + // all done + if (flash_len == flash_pos) { + // check remaining chunks if any + for (uint32_t i = chunk_idx + 1; i < 16; i++) { + // hash should be empty if the chunk is unused + if (0 != memcmp(hdr->hashes + i * 32, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 32)) { + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } + } + } + + memzero(FW_CHUNK, sizeof(FW_CHUNK)); + chunk_idx++; } static void rx_callback(usbd_device *dev, uint8_t ep) { (void)ep; + static uint16_t msg_id = 0xFFFF; static uint8_t buf[64] __attribute__((aligned(4))); - static uint8_t towrite[4] __attribute__((aligned(4))); + static uint32_t w; static int wi; + static int old_was_signed; if ( usbd_ep_read_packet(dev, ENDPOINT_ADDRESS_OUT, buf, 64) != 64) return; @@ -258,7 +138,6 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } // struct.unpack(">HL") => msg, size msg_id = (buf[3] << 8) + buf[4]; - msg_size = ((uint32_t) buf[5] << 24) + (buf[6] << 16) + (buf[7] << 8) + buf[8]; } if (flash_state == STATE_READY || flash_state == STATE_OPEN) { @@ -277,26 +156,9 @@ static void rx_callback(usbd_device *dev, uint8_t ep) } if (msg_id == 0x0005) { // WipeDevice message (id 5) layoutDialog(&bmp_icon_question, "Cancel", "Confirm", NULL, "Do you really want to", "wipe the device?", NULL, "All data will be lost.", NULL, NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); - if (button.YesUp) { - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // erase metadata area - for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - // erase code area - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - flash_wait_for_last_operation(); - flash_lock(); + bool but = get_button_response(); + if (but) { + erase_storage_code_progress(); flash_state = STATE_END; layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "Device", "successfully wiped.", NULL, "You may now", "unplug your TREZOR.", NULL); send_msg_success(dev); @@ -311,59 +173,31 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_OPEN) { if (msg_id == 0x0006) { // FirmwareErase message (id 6) - if (!brand_new_firmware) { + bool proceed = false; + if (firmware_present_new()) { layoutDialog(&bmp_icon_question, "Abort", "Continue", NULL, "Install new", "firmware?", NULL, "Never do this without", "your recovery card!", NULL); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); + proceed = get_button_response(); + } else { + proceed = true; } - if (brand_new_firmware || button.YesUp) { - // check whether current firmware is signed - if (!brand_new_firmware && SIG_OK == signatures_ok(NULL)) { - old_was_unsigned = false; - // backup metadata - backup_metadata(meta_backup); + if (proceed) { + // check whether the current firmware is signed (old or new method) + if (firmware_present_new()) { + const image_header *hdr = (const image_header *)FLASH_PTR(FLASH_FWHEADER_START); + old_was_signed = (SIG_OK == signatures_new_ok(hdr, NULL)) && (SIG_OK == check_firmware_hashes(hdr)); + } else if (firmware_present_old()) { + old_was_signed = signatures_old_ok(); } else { - old_was_unsigned = true; - } - flash_wait_for_last_operation(); - flash_clear_status_flags(); - flash_unlock(); - // erase metadata area - for (int i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + old_was_signed = SIG_FAIL; } - // erase code area - for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { - layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_META_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_META_SECTOR_FIRST)); - flash_erase_sector(i, FLASH_CR_PROGRAM_X32); - } - layoutProgress("INSTALLING ... Please wait", 0); - flash_wait_for_last_operation(); - flash_lock(); - - // check that metadata was succesfully erased - // flash status register should show now error and - // the config block should contain only \xff. - uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_META_START), FLASH_META_LEN, hash); - if ((FLASH_SR & (FLASH_SR_PGAERR | FLASH_SR_PGPERR | FLASH_SR_PGSERR | FLASH_SR_WRPERR)) != 0 - || memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { - send_msg_failure(dev); - flash_state = STATE_END; - layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); - return; - } - + erase_code_progress(); send_msg_success(dev); flash_state = STATE_FLASHSTART; - return; + } else { + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); } - send_msg_failure(dev); - flash_state = STATE_END; - layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL); return; } return; @@ -375,41 +209,47 @@ static void rx_callback(usbd_device *dev, uint8_t ep) send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); return; } // read payload length const uint8_t *p = buf + 10; flash_len = readprotobufint(&p); - if (flash_len > FLASH_TOTAL_SIZE + FLASH_META_DESC_LEN - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware is too big + if (flash_len <= FLASH_FWHEADER_LEN) { // firmware is too small + send_msg_failure(dev); + flash_state = STATE_END; + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too small.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); + return; + } + if (flash_len > FLASH_FWHEADER_LEN + FLASH_APP_LEN) { // firmware is too big send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } // check firmware magic - if (memcmp(p, FIRMWARE_MAGIC, 4) != 0) { + if (memcmp(p, &FIRMWARE_MAGIC_NEW, 4) != 0) { send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Wrong firmware header.", NULL, "Get official firmware", "from trezor.io/start", NULL, NULL); return; } + memzero(FW_HEADER, sizeof(FW_HEADER)); + memzero(FW_CHUNK, sizeof(FW_CHUNK)); flash_state = STATE_FLASHING; - p += 4; // Don't flash firmware header yet. - flash_pos = 4; - wi = 0; - flash_unlock(); + flash_pos = 0; + chunk_idx = 0; + w = 0; while (p < buf + 64) { - towrite[wi] = *p; + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w wi++; if (wi == 4) { - const uint32_t *w = (uint32_t *)towrite; - flash_program_word(FLASH_META_START + flash_pos, *w); + FW_HEADER[flash_pos / 4] = w; flash_pos += 4; wi = 0; } p++; } - flash_lock(); return; } return; @@ -420,34 +260,44 @@ static void rx_callback(usbd_device *dev, uint8_t ep) send_msg_failure(dev); flash_state = STATE_END; layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); return; } - const uint8_t *p = buf + 1; + + static uint8_t flash_anim = 0; if (flash_anim % 32 == 4) { layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len); } flash_anim++; - flash_unlock(); + + const uint8_t *p = buf + 1; while (p < buf + 64 && flash_pos < flash_len) { - towrite[wi] = *p; + w = (w >> 8) | (*p << 24); // assign byte to first byte of uint32_t w wi++; if (wi == 4) { - const uint32_t *w = (const uint32_t *)towrite; - if (flash_pos < FLASH_META_DESC_LEN) { - flash_program_word(FLASH_META_START + flash_pos, *w); // the first 256 bytes of firmware is metadata descriptor + if (flash_pos < FLASH_FWHEADER_LEN) { + FW_HEADER[flash_pos / 4] = w; } else { - flash_program_word(FLASH_APP_START + (flash_pos - FLASH_META_DESC_LEN), *w); // the rest is code + FW_CHUNK[(flash_pos % FW_CHUNK_SIZE)/ 4] = w; } flash_pos += 4; wi = 0; + // finished the whole chunk + if (flash_pos % FW_CHUNK_SIZE == 0) { + check_and_write_chunk(); + } } p++; } - flash_lock(); // flashing done if (flash_pos == flash_len) { + // flush remaining data in the last chunk + if (flash_pos % FW_CHUNK_SIZE > 0) { + check_and_write_chunk(); + } flash_state = STATE_CHECK; - if (!brand_new_firmware) { + const image_header *hdr = (const image_header *)FW_HEADER; + if (SIG_OK != signatures_new_ok(hdr, NULL)) { send_msg_buttonrequest_firmwarecheck(dev); return; } @@ -458,55 +308,69 @@ static void rx_callback(usbd_device *dev, uint8_t ep) if (flash_state == STATE_CHECK) { - if (!brand_new_firmware) { + // use the firmware header from RAM + const image_header *hdr = (const image_header *)FW_HEADER; + + bool hash_check_ok; + // show fingerprint of unsigned firmware + if (SIG_OK != signatures_new_ok(hdr, NULL)) { if (msg_id != 0x001B) { // ButtonAck message (id 27) return; } uint8_t hash[32]; - sha256_Raw(FLASH_PTR(FLASH_APP_START), flash_len - FLASH_META_DESC_LEN, hash); - layoutFirmwareHash(hash); - do { - delay(100000); - buttonUpdate(); - } while (!button.YesUp && !button.NoUp); + compute_firmware_fingerprint(hdr, hash); + layoutFirmwareFingerprint(hash); + hash_check_ok = get_button_response(); + } else { + hash_check_ok = true; } - bool hash_check_ok = brand_new_firmware || button.YesUp; - layoutProgress("INSTALLING ... Please wait", 1000); - uint8_t flags = *FLASH_PTR(FLASH_META_FLAGS); // wipe storage if: - // 0) there was no firmware - // 1) old firmware was unsigned - // 2) firmware restore flag isn't set - // 3) signatures are not ok - if (brand_new_firmware || old_was_unsigned || (flags & 0x01) == 0 || SIG_OK != signatures_ok(NULL)) { - memzero(meta_backup, sizeof(meta_backup)); + // 1) old firmware was unsigned or not present + // 2) signatures are not OK + // 3) hashes are not OK + if (SIG_OK != old_was_signed || SIG_OK != signatures_new_ok(hdr, NULL) || SIG_OK != check_firmware_hashes(hdr)) { + // erase storage + erase_storage(); + // check erasure + uint8_t hash[32]; + sha256_Raw(FLASH_PTR(FLASH_STORAGE_START), FLASH_STORAGE_LEN, hash); + if (memcmp(hash, "\x2d\x86\x4c\x0b\x78\x9a\x43\x21\x4e\xee\x85\x24\xd3\x18\x20\x75\x12\x5e\x5c\xa2\xcd\x52\x7f\x35\x82\xec\x87\xff\xd9\x40\x76\xbc", 32) != 0) { + send_msg_failure(dev); + layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL); + shutdown(); + return; + } } - // copy new firmware header - memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN); - // write "TRZR" in header only when hash was confirmed + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // write firmware header only when hash was confirmed if (hash_check_ok) { - memcpy(meta_backup, FIRMWARE_MAGIC, 4); + for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), FW_HEADER[i]); + } } else { - memzero(meta_backup, 4); + for (size_t i = 0; i < FLASH_FWHEADER_LEN/sizeof(uint32_t); i++) { + flash_program_word(FLASH_FWHEADER_START + i * sizeof(uint32_t), 0); + } } - - // no need to erase, because we are not changing any already flashed byte. - restore_metadata(meta_backup); - memzero(meta_backup, sizeof(meta_backup)); + flash_wait_for_last_operation(); + flash_lock(); flash_state = STATE_END; if (hash_check_ok) { layoutDialog(&bmp_icon_ok, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL); send_msg_success(dev); + shutdown(); } else { layoutDialog(&bmp_icon_warning, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware."); send_msg_failure(dev); + shutdown(); } return; } - } static void set_config(usbd_device *dev, uint16_t wValue) @@ -531,7 +395,7 @@ static const struct usb_bos_descriptor bos_descriptor = { .capabilities = capabilities }; -void usbInit(void) +static void usbInit(void) { usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, sizeof(usb_strings)/sizeof(const char *), usbd_control_buffer, sizeof(usbd_control_buffer)); usbd_register_set_config_callback(usbd_dev, set_config); @@ -540,7 +404,7 @@ void usbInit(void) winusb_setup(usbd_dev, USB_INTERFACE_INDEX_MAIN); } -void checkButtons(void) +static void checkButtons(void) { static bool btn_left = false, btn_right = false, btn_final = false; if (btn_final) { @@ -569,13 +433,13 @@ void checkButtons(void) } } -void usbLoop(bool firmware_present) +void usbLoop(void) { - brand_new_firmware = !firmware_present; + bool firmware_present = firmware_present_new(); usbInit(); for (;;) { usbd_poll(usbd_dev); - if (brand_new_firmware && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { + if (!firmware_present && (flash_state == STATE_READY || flash_state == STATE_OPEN)) { checkButtons(); } } diff --git a/bootloader/usb.h b/bootloader/usb.h index fea6e680e..da506471a 100644 --- a/bootloader/usb.h +++ b/bootloader/usb.h @@ -20,6 +20,6 @@ #ifndef __USB_H__ #define __USB_H__ -void usbLoop(bool firmware_present); +void usbLoop(void); #endif diff --git a/bootloader/usb_desc.h b/bootloader/usb_desc.h new file mode 100644 index 000000000..d4044b930 --- /dev/null +++ b/bootloader/usb_desc.h @@ -0,0 +1,75 @@ +#define USB_INTERFACE_INDEX_MAIN 0 + +#define ENDPOINT_ADDRESS_IN (0x81) +#define ENDPOINT_ADDRESS_OUT (0x01) + +static const struct usb_device_descriptor dev_descr = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0210, + .bDeviceClass = 0, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = 0x1209, + .idProduct = 0x53c0, + .bcdDevice = 0x0100, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 3, + .bNumConfigurations = 1, +}; + +static const struct usb_endpoint_descriptor endpoints[2] = {{ + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_IN, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}, { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = ENDPOINT_ADDRESS_OUT, + .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT, + .wMaxPacketSize = 64, + .bInterval = 1, +}}; + +static const struct usb_interface_descriptor iface[] = {{ + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = USB_INTERFACE_INDEX_MAIN, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + .endpoint = endpoints, + .extra = NULL, + .extralen = 0, +}}; + +static const struct usb_interface ifaces[] = {{ + .num_altsetting = 1, + .altsetting = iface, +}}; + +static const struct usb_config_descriptor config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80, + .bMaxPower = 0x32, + .interface = ifaces, +}; + +static const char *usb_strings[] = { + "SatoshiLabs", + "TREZOR", + "000000000000000000000000", +}; diff --git a/bootloader/usb_erase.h b/bootloader/usb_erase.h new file mode 100644 index 000000000..cadcf4573 --- /dev/null +++ b/bootloader/usb_erase.h @@ -0,0 +1,44 @@ +static void erase_storage_code_progress(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + // erase storage area + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + // erase code area + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("WIPING ... Please wait", 1000 * (i - FLASH_STORAGE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_STORAGE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); +} + +static void erase_code_progress(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) { + layoutProgress("PREPARING ... Please wait", 1000 * (i - FLASH_CODE_SECTOR_FIRST) / (FLASH_CODE_SECTOR_LAST - FLASH_CODE_SECTOR_FIRST)); + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + layoutProgress("INSTALLING ... Please wait", 0); + flash_wait_for_last_operation(); + flash_lock(); +} + +static void erase_storage(void) +{ + flash_wait_for_last_operation(); + flash_clear_status_flags(); + flash_unlock(); + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } + flash_wait_for_last_operation(); + flash_lock(); +} diff --git a/bootloader/usb_send.h b/bootloader/usb_send.h new file mode 100644 index 000000000..ed73fbe08 --- /dev/null +++ b/bootloader/usb_send.h @@ -0,0 +1,86 @@ +static void send_msg_success(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Success message (id 2), payload len 0 + memcpy(response, + // header + "?##" + // msg_id + "\x00\x02" + // msg_size + "\x00\x00\x00\x00", + 9); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_failure(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Failure message (id 3), payload len 2 + // - code = 99 (Failure_FirmwareError) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x03" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x63", + 11); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_features(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: Features message (id 17), payload len 25 + // - vendor = "trezor.io" + // - major_version = VERSION_MAJOR + // - minor_version = VERSION_MINOR + // - patch_version = VERSION_PATCH + // - bootloader_mode = True + // - firmware_present = True/False + // - model = "1" + memcpy(response, + // header + "?##" + // msg_id + "\x00\x11" + // msg_size + "\x00\x00\x00\x16" + // data + "\x0a" "\x09" "trezor.io" + "\x10" VERSION_MAJOR_CHAR + "\x18" VERSION_MINOR_CHAR + "\x20" VERSION_PATCH_CHAR + "\x28" "\x01" + "\x90\x01" "\x00" + "\xaa" "\x01" "1", + 34); + response[30] = firmware_present_new() ? 0x01 : 0x00; + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} + +static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev) +{ + uint8_t response[64]; + memzero(response, sizeof(response)); + // response: ButtonRequest message (id 26), payload len 2 + // - code = ButtonRequest_FirmwareCheck (9) + memcpy(response, + // header + "?##" + // msg_id + "\x00\x1a" + // msg_size + "\x00\x00\x00\x02" + // data + "\x08" "\x09", + 11 + ); + while (usbd_ep_write_packet(dev, ENDPOINT_ADDRESS_IN, response, 64) != 64) {} +} diff --git a/emulator/memory.c b/emulator/memory.c index 02b2a4ec7..4bcda3886 100644 --- a/emulator/memory.c +++ b/emulator/memory.c @@ -128,8 +128,7 @@ void svc_flash_program(uint32_t size) { } void svc_flash_erase_sector(uint16_t sector) { assert (!flash_locked); - assert (sector >= FLASH_META_SECTOR_FIRST && - sector <= FLASH_META_SECTOR_LAST); + assert (sector >= FLASH_STORAGE_SECTOR_FIRST && sector <= FLASH_STORAGE_SECTOR_LAST); flash_erase_sector(sector, 3); } uint32_t svc_flash_lock(void) { diff --git a/firmware/Makefile b/firmware/Makefile index 91e84acad..a21f0cd26 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,4 +1,4 @@ -APPVER = 1.0.0 +APPVER = 1.8.0 NAME = trezor @@ -8,6 +8,7 @@ else OBJS += usb.o OBJS += bl_check.o OBJS += otp.o +OBJS += header.o endif OBJS += u2f.o diff --git a/firmware/config.c b/firmware/config.c index b2042acbf..6656b7f89 100644 --- a/firmware/config.c +++ b/firmware/config.c @@ -197,12 +197,15 @@ static secbool config_get_uint32(uint16_t key, uint32_t *value) return sectrue; } +#define FLASH_META_START 0x08008000 +#define FLASH_META_LEN 0x100 + static secbool config_upgrade_v10(void) { #define OLD_STORAGE_SIZE(last_member) (((offsetof(Storage, last_member) + pb_membersize(Storage, last_member)) + 3) & ~3) - if (memcmp(FLASH_PTR(FLASH_META_MAGIC), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || - memcmp(FLASH_PTR(FLASH_STORAGE_START), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { + if (memcmp(FLASH_PTR(FLASH_META_START), &META_MAGIC_V10, sizeof(META_MAGIC_V10)) != 0 || + memcmp(FLASH_PTR(FLASH_META_START + FLASH_META_LEN), &CONFIG_MAGIC_V10, sizeof(CONFIG_MAGIC_V10)) != 0) { // wrong magic return secfalse; } @@ -210,8 +213,8 @@ static secbool config_upgrade_v10(void) Storage config __attribute__((aligned(4))); _Static_assert((sizeof(config) & 3) == 0, "storage unaligned"); - memcpy(config_uuid, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); - memcpy(&config, FLASH_PTR(FLASH_STORAGE_START + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); + memcpy(config_uuid, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10)), sizeof(config_uuid)); + memcpy(&config, FLASH_PTR(FLASH_META_START + FLASH_META_LEN + sizeof(CONFIG_MAGIC_V10) + sizeof(config_uuid)), sizeof(config)); // version 1: since 1.0.0 // version 2: since 1.2.1 diff --git a/firmware/header.S b/firmware/header.S new file mode 100644 index 000000000..9333fb238 --- /dev/null +++ b/firmware/header.S @@ -0,0 +1,33 @@ + .syntax unified + +#include "version.h" + + .section .header, "a" + + .type g_header, %object + .size g_header, .-g_header + +g_header: + .byte 'T','R','Z','F' // magic + .word g_header_end - g_header // hdrlen + .word 0 // expiry + .word _codelen // codelen + .byte VERSION_MAJOR // vmajor + .byte VERSION_MINOR // vminor + .byte VERSION_PATCH // vpatch + .byte 0 // vbuild + .byte FIX_VERSION_MAJOR // fix_vmajor + .byte FIX_VERSION_MINOR // fix_vminor + .byte FIX_VERSION_PATCH // fix_vpatch + .byte 0 // fix_vbuild + . = . + 8 // reserved + . = . + 512 // hash1 ... hash16 + . = . + 64 // sig1 + . = . + 64 // sig2 + . = . + 64 // sig3 + .byte 0 // sigindex1 + .byte 0 // sigindex2 + .byte 0 // sigindex3 + . = . + 220 // reserved + . = . + 65 // reserved +g_header_end: diff --git a/firmware/trezor.h b/firmware/trezor.h index 65a515890..9975a997b 100644 --- a/firmware/trezor.h +++ b/firmware/trezor.h @@ -21,10 +21,7 @@ #define __TREZOR_H__ #include - -#define VERSION_MAJOR 1 -#define VERSION_MINOR 8 -#define VERSION_PATCH 0 +#include "version.h" #define STR(X) #X #define VERSTR(X) STR(X) diff --git a/firmware/version.h b/firmware/version.h new file mode 100644 index 000000000..1202e1b44 --- /dev/null +++ b/firmware/version.h @@ -0,0 +1,7 @@ +#define VERSION_MAJOR 1 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 + +#define FIX_VERSION_MAJOR 1 +#define FIX_VERSION_MINOR 8 +#define FIX_VERSION_PATCH 0 diff --git a/memory.c b/memory.c index 11c550b6e..b11e046b2 100644 --- a/memory.c +++ b/memory.c @@ -34,7 +34,9 @@ void memory_protect(void) if (((FLASH_OPTION_BYTES_1 & 0xFFEC) == 0xCCEC) && ((FLASH_OPTION_BYTES_2 & 0xFFF) == 0xFFC) && (FLASH_OPTCR == 0x0FFCCCED)) { return; // already set up correctly - bail out } - + for (int i = FLASH_STORAGE_SECTOR_FIRST; i <= FLASH_STORAGE_SECTOR_LAST; i++) { + flash_erase_sector(i, FLASH_CR_PROGRAM_X32); + } flash_unlock_option_bytes(); // Section 2.8.6 Flash option control register (FLASH_OPTCR) // Bits 31:28 Reserved, must be kept cleared. diff --git a/memory.h b/memory.h index eac09efa5..e47fc2917 100644 --- a/memory.h +++ b/memory.h @@ -24,43 +24,37 @@ /* - flash memory layout: + Flash memory layout: name | range | size | function -----------+-------------------------+---------+------------------ - Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader code - Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader code + Sector 0 | 0x08000000 - 0x08003FFF | 16 KiB | bootloader + Sector 1 | 0x08004000 - 0x08007FFF | 16 KiB | bootloader -----------+-------------------------+---------+------------------ - Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | metadata area - Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | metadata area + Sector 2 | 0x08008000 - 0x0800BFFF | 16 KiB | storage area + Sector 3 | 0x0800C000 - 0x0800FFFF | 16 KiB | storage area -----------+-------------------------+---------+------------------ - Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | application code - Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | application code - Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | application code - Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | application code -===========+=========================+============================ - Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | application code - Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | application code - Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | application code - Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | application code - - metadata area: - - offset | type/length | description ---------+-------------+------------------------------- - 0x0000 | 4 bytes | magic = 'TRZR' - 0x0004 | uint32 | length of the code (codelen) - 0x0008 | uint8 | signature index #1 - 0x0009 | uint8 | signature index #2 - 0x000A | uint8 | signature index #3 - 0x000B | uint8 | flags - 0x000C | 52 bytes | reserved - 0x0040 | 64 bytes | signature #1 - 0x0080 | 64 bytes | signature #2 - 0x00C0 | 64 bytes | signature #3 - 0x0100 | 32K-256 B | persistent storage - - flags & 0x01 -> restore storage after flashing (if signatures are ok) + Sector 4 | 0x08010000 - 0x0801FFFF | 64 KiB | firmware + Sector 5 | 0x08020000 - 0x0803FFFF | 128 KiB | firmware + Sector 6 | 0x08040000 - 0x0805FFFF | 128 KiB | firmware + Sector 7 | 0x08060000 - 0x0807FFFF | 128 KiB | firmware + Sector 8 | 0x08080000 - 0x0809FFFF | 128 KiB | firmware + Sector 9 | 0x080A0000 - 0x080BFFFF | 128 KiB | firmware + Sector 10 | 0x080C0000 - 0x080DFFFF | 128 KiB | firmware + Sector 11 | 0x080E0000 - 0x080FFFFF | 128 KiB | firmware + + firmware header (occupies first 1 KB of the firmware) + - very similar to trezor-core firmware header described in: + https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md#firmware-header + - differences: + * we don't use sigmask or sig field (these are reserved and set to zero) + * we introduce new fields immediately following the hash16 field: + - sig1[64], sig2[64], sig3[64] + - sigindex1[1], sigindex2[1], sigindex3[1] + * reserved[415] area is reduced to reserved[220] + - see signatures.c for more details + + We pad the firmware chunks with zeroes if they are shorted. */ @@ -78,31 +72,20 @@ extern uint8_t *emulator_flash_base; #define FLASH_BOOT_START (FLASH_ORIGIN) #define FLASH_BOOT_LEN (0x8000) -#define FLASH_META_START (FLASH_BOOT_START + FLASH_BOOT_LEN) -#define FLASH_META_LEN (0x8000) +#define FLASH_STORAGE_START (FLASH_BOOT_START + FLASH_BOOT_LEN) +#define FLASH_STORAGE_LEN (0x8000) -#define FLASH_APP_START (FLASH_META_START + FLASH_META_LEN) +#define FLASH_FWHEADER_START (FLASH_STORAGE_START + FLASH_STORAGE_LEN) +#define FLASH_FWHEADER_LEN (0x400) -#define FLASH_META_MAGIC (FLASH_META_START) -#define FLASH_META_CODELEN (FLASH_META_START + 0x0004) -#define FLASH_META_SIGINDEX1 (FLASH_META_START + 0x0008) -#define FLASH_META_SIGINDEX2 (FLASH_META_START + 0x0009) -#define FLASH_META_SIGINDEX3 (FLASH_META_START + 0x000A) -#define FLASH_META_FLAGS (FLASH_META_START + 0x000B) -#define FLASH_META_SIG1 (FLASH_META_START + 0x0040) -#define FLASH_META_SIG2 (FLASH_META_START + 0x0080) -#define FLASH_META_SIG3 (FLASH_META_START + 0x00C0) - -#define FLASH_META_DESC_LEN (0x100) - -#define FLASH_STORAGE_START (FLASH_META_START + FLASH_META_DESC_LEN) -#define FLASH_STORAGE_LEN (FLASH_APP_START - FLASH_STORAGE_START) +#define FLASH_APP_START (FLASH_FWHEADER_START + FLASH_FWHEADER_LEN) +#define FLASH_APP_LEN (FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) #define FLASH_BOOT_SECTOR_FIRST 0 #define FLASH_BOOT_SECTOR_LAST 1 -#define FLASH_META_SECTOR_FIRST 2 -#define FLASH_META_SECTOR_LAST 3 +#define FLASH_STORAGE_SECTOR_FIRST 2 +#define FLASH_STORAGE_SECTOR_LAST 3 #define FLASH_CODE_SECTOR_FIRST 4 #define FLASH_CODE_SECTOR_LAST 11 diff --git a/memory_app_1.8.0.ld b/memory_app_1.8.0.ld new file mode 100644 index 000000000..77a3ec2a0 --- /dev/null +++ b/memory_app_1.8.0.ld @@ -0,0 +1,31 @@ +/* STM32F205RG - 1024K Flash, 128K RAM */ +/* program starts at 0x08010100 */ +MEMORY +{ + rom (rx) : ORIGIN = 0x08010000, LENGTH = 1024K - 64K + ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K +} + +SECTIONS +{ + .confidential (NOLOAD) : { + *(confidential) + ASSERT ((SIZEOF(.confidential) <= 32K), "Error: Confidential section too big!"); + } >ram + + .header : ALIGN(4) { + KEEP(*(.header)); + } >rom AT>rom +} + +INCLUDE libopencm3_stm32f2.ld + +_codelen = SIZEOF(.text) + SIZEOF(.data) + SIZEOF(.ARM.exidx); + +_ram_start = ORIGIN(ram); +_ram_end = ORIGIN(ram) + LENGTH(ram); +_stack = _ram_end - 8; +__stack_chk_guard = _ram_end - 8; +system_millis = _ram_end - 4; + +_data_size = SIZEOF(.data); diff --git a/setup.c b/setup.c index e554ad17a..e1fab1020 100644 --- a/setup.c +++ b/setup.c @@ -33,7 +33,7 @@ uint32_t __stack_chk_guard; static inline void __attribute__((noreturn)) fault_handler(const char *line1) { layoutDialog(&bmp_icon_error, NULL, NULL, NULL, line1, "detected.", NULL, "Please unplug", "the device.", NULL); - for (;;) {} // loop forever + shutdown(); } void __attribute__((noreturn)) __stack_chk_fail(void) { diff --git a/supervise.c b/supervise.c index 7669cc5ed..5a86db884 100644 --- a/supervise.c +++ b/supervise.c @@ -45,9 +45,9 @@ static void svhandler_flash_program(uint32_t psize) { } static void svhandler_flash_erase_sector(uint16_t sector) { - /* we only allow erasing meta sectors 2 and 3. */ - if (sector < FLASH_META_SECTOR_FIRST || - sector > FLASH_META_SECTOR_LAST) { + /* we only allow erasing storage sectors 2 and 3. */ + if (sector < FLASH_STORAGE_SECTOR_FIRST || + sector > FLASH_STORAGE_SECTOR_LAST) { return; } flash_erase_sector(sector, FLASH_CR_PROGRAM_X32);