1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-26 16:18:22 +00:00

introduce new memory layout

firmware header is now stored with code, not within the storage sectors
This commit is contained in:
Pavol Rusnak 2019-01-27 11:58:30 +01:00
parent fe39d10211
commit 07231d936e
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
24 changed files with 774 additions and 483 deletions

View File

@ -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

View File

@ -24,6 +24,7 @@
#include <libopencm3/cm3/scb.h>
#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)
{
layoutDialog(&bmp_icon_error, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "contact our support.", NULL);
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,", "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);
}

View File

@ -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 <stdint.h>
#include <stdbool.h>
#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

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python
#!/usr/bin/env python3
import sys
import os

View File

@ -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("<I")
SIG_START = INDEXES_START + SLOTS + 1 + 52
FWHEADER_SIZE = 1024
SIGNATURES_START = 6 * 4 + 8 + 512
INDEXES_START = SIGNATURES_START + 3 * 64
def parse_args():
@ -52,47 +49,83 @@ def parse_args():
return parser.parse_args()
def prepare(data):
# Takes raw OR signed firmware and clean out metadata structure
# This produces 'clean' data for signing
def pad_to_size(data, size):
if len(data) > 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("<I")]
# see memory.h for details
def prepare_hashes(data):
# process chunks
start = 0
end = (64 - 1) * 1024
hashes = []
for i in range(16):
sector = data[start:end]
if len(sector) > 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("<I", len(data)) # length of the code
meta += b"\x00" * SLOTS # signature index #1-#3
meta += b"\x01" # flags
meta += b"\x00" * 52 # reserved
meta += b"\x00" * 64 * SLOTS # signature #1-#3
print("HASHES NOT OK")
if data[:4] == b"TRZR":
# Replace existing header
out = meta + data[len(meta) :]
def update_hashes_in_header(data):
# Store hashes in the firmware header
data = bytearray(data)
o = 0
for h in prepare_hashes(data[FWHEADER_SIZE:]):
data[0x20 + o:0x20 + o + 32] = h
o += 32
return bytes(data)
def get_header(data, zero_signatures=False):
if not zero_signatures:
return data[:FWHEADER_SIZE]
else:
# create data from meta + code
out = meta + data
data = bytearray(data[:FWHEADER_SIZE])
data[SIGNATURES_START : SIGNATURES_START + 3 * 64 + 3] = b"\x00" * (3 * 64 + 3)
return bytes(data)
return out
def check_size(data):
size = struct.unpack("<L", data[12:16])[0]
assert size == len(data) - 1024
def check_signatures(data):
# Analyses given firmware and prints out
# status of included signatures
try:
indexes = [ord(x) for x in data[INDEXES_START : INDEXES_START + SLOTS]]
except:
indexes = [x for x in data[INDEXES_START : INDEXES_START + SLOTS]]
indexes = [x for x in data[INDEXES_START : INDEXES_START + SLOTS]]
to_sign = prepare(data)[256:] # without meta
to_sign = get_header(data, zero_signatures=True)
fingerprint = hashlib.sha256(to_sign).hexdigest()
print("Firmware fingerprint:", fingerprint)
used = []
for x in range(SLOTS):
signature = data[SIG_START + 64 * x : SIG_START + 64 * x + 64]
signature = data[SIGNATURES_START + 64 * x : SIGNATURES_START + 64 * x + 64]
if indexes[x] == 0:
print("Slot #%d" % (x + 1), "is empty")
@ -118,25 +151,18 @@ def check_signatures(data):
def modify(data, slot, index, signature):
# Replace signature in data
# Put index to data
data = (
data[: INDEXES_START + slot - 1] + bytes([index]) + data[INDEXES_START + slot :]
)
# Put signature to data
data = (
data[: SIG_START + 64 * (slot - 1)] + signature + data[SIG_START + 64 * slot :]
)
return data
data = bytearray(data)
# put index to data
data[INDEXES_START + slot - 1] = index
# put signature to data
data[SIGNATURES_START + 64 * (slot - 1) : SIGNATURES_START + 64 * slot] = signature
return bytes(data)
def sign(data, is_pem):
# Ask for index and private key and signs the firmware
slot = int(raw_input("Enter signature slot (1-%d): " % SLOTS))
slot = int(input("Enter signature slot (1-%d): " % SLOTS))
if slot < 1 or slot > 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)

View File

@ -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:

View File

@ -17,7 +17,6 @@
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdint.h>
#include <string.h>
#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(&copy, 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 *)&copy, 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;
}

View File

@ -20,9 +20,48 @@
#ifndef __SIGNATURES_H__
#define __SIGNATURES_H__
#include <stdbool.h>
#include <stdint.h>
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

View File

@ -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 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_success(usbd_device *dev)
static void check_and_write_chunk(void)
{
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 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) {}
}
static void backup_metadata(uint8_t *backup)
{
memcpy(backup, FLASH_PTR(FLASH_META_START), FLASH_META_LEN);
}
static void restore_metadata(const uint8_t *backup)
{
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);
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);
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;
}
flash_wait_for_last_operation();
flash_clear_status_flags();
flash_unlock();
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;
old_was_signed = SIG_FAIL;
}
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);
}
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();
}
}

View File

@ -20,6 +20,6 @@
#ifndef __USB_H__
#define __USB_H__
void usbLoop(bool firmware_present);
void usbLoop(void);
#endif

75
bootloader/usb_desc.h Normal file
View File

@ -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",
};

44
bootloader/usb_erase.h Normal file
View File

@ -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();
}

86
bootloader/usb_send.h Normal file
View File

@ -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) {}
}

View File

@ -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) {

View File

@ -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

View File

@ -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

33
firmware/header.S Normal file
View File

@ -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:

View File

@ -21,10 +21,7 @@
#define __TREZOR_H__
#include <stdint.h>
#define VERSION_MAJOR 1
#define VERSION_MINOR 8
#define VERSION_PATCH 0
#include "version.h"
#define STR(X) #X
#define VERSTR(X) STR(X)

7
firmware/version.h Normal file
View File

@ -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

View File

@ -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.

View File

@ -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
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
metadata area:
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
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)
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

31
memory_app_1.8.0.ld Normal file
View File

@ -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);

View File

@ -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) {

View File

@ -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);