mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-13 02:58:57 +00:00
bootloader source code
This commit is contained in:
parent
8f1c40a933
commit
938e8a5966
1
.gitignore
vendored
1
.gitignore
vendored
@ -7,4 +7,3 @@
|
||||
*.list
|
||||
*.srec
|
||||
*.log
|
||||
bootloader
|
||||
|
9
bootloader/.gitignore
vendored
Normal file
9
bootloader/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.o
|
||||
*.a
|
||||
*.d
|
||||
*.bin
|
||||
*.elf
|
||||
*.hex
|
||||
*.list
|
||||
*.srec
|
||||
*.log
|
23
bootloader/Makefile
Normal file
23
bootloader/Makefile
Normal file
@ -0,0 +1,23 @@
|
||||
NAME = bootloader
|
||||
|
||||
MCU_DIR=$(subst /bootloader,,$(PWD))
|
||||
|
||||
OBJS += bootloader.o
|
||||
OBJS += signatures.o
|
||||
OBJS += usb.o
|
||||
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/bignum.small.o
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/ecdsa.small.o
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/hmac.o
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/ripemd160.o
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/secp256k1.small.o
|
||||
OBJS += $(MCU_DIR)/trezor-crypto/sha2.o
|
||||
|
||||
CFLAGS += -DUSE_PRECOMPUTED_IV=0
|
||||
CFLAGS += -DUSE_PRECOMPUTED_CP=0
|
||||
CFLAGS += -DUSE_PUBKEY_VALIDATE=0
|
||||
|
||||
include $(MCU_DIR)/Makefile.include
|
||||
|
||||
align:
|
||||
./firmware_align.py $(NAME).bin
|
132
bootloader/bootloader.c
Normal file
132
bootloader/bootloader.c
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <libopencm3/stm32/rcc.h>
|
||||
#include <libopencm3/stm32/gpio.h>
|
||||
#include <libopencm3/cm3/scb.h>
|
||||
|
||||
#include "bootloader.h"
|
||||
#include "buttons.h"
|
||||
#include "setup.h"
|
||||
#include "usb.h"
|
||||
#include "oled.h"
|
||||
#include "util.h"
|
||||
#include "signatures.h"
|
||||
#include "layout.h"
|
||||
#include "serialno.h"
|
||||
|
||||
#ifdef APPVER
|
||||
#error Bootloader cannot be used in app mode
|
||||
#endif
|
||||
|
||||
void show_unofficial_warning(void)
|
||||
{
|
||||
layoutDialog(DIALOG_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.YesUp) {
|
||||
return; // yes button was pressed -> return
|
||||
}
|
||||
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Unofficial firmware", "aborted.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
}
|
||||
|
||||
void load_app(void)
|
||||
{
|
||||
// jump to app
|
||||
SCB_VTOR = FLASH_APP_START; // & 0xFFFF;
|
||||
asm volatile("msr msp, %0"::"g" (*(volatile uint32_t *)FLASH_APP_START));
|
||||
(*(void (**)())(FLASH_APP_START + 4))();
|
||||
}
|
||||
|
||||
void bootloader_loop(void)
|
||||
{
|
||||
static char serial[25];
|
||||
|
||||
fill_serialno_fixed(serial);
|
||||
|
||||
oledDrawBitmap(0, 0, &bmp_logo64);
|
||||
oledDrawString(52, 0, "TREZOR");
|
||||
|
||||
oledDrawString(52, 20, "Serial No.");
|
||||
oledDrawString(52, 40, serial + 12); // second part of serial
|
||||
serial[12] = 0;
|
||||
oledDrawString(52, 30, serial); // first part of serial
|
||||
|
||||
oledDrawStringRight(OLED_WIDTH - 1, OLED_HEIGHT - 8, "BLv" VERSTR(VERSION_MAJOR) "." VERSTR(VERSION_MINOR) "." VERSTR(VERSION_PATCH));
|
||||
|
||||
oledRefresh();
|
||||
|
||||
usbInit();
|
||||
usbLoop();
|
||||
}
|
||||
|
||||
void check_firmware_sanity(void)
|
||||
{
|
||||
int broken = 0;
|
||||
if (memcmp((void *)FLASH_META_MAGIC, "TRZR", 4)) { // magic does not match
|
||||
broken++;
|
||||
}
|
||||
if (*((uint32_t *)FLASH_META_CODELEN) < 4096) { // firmware reports smaller size than 4kB
|
||||
broken++;
|
||||
}
|
||||
if (*((uint32_t *)FLASH_META_CODELEN) > FLASH_TOTAL_SIZE - (FLASH_APP_START - FLASH_ORIGIN)) { // firmware reports bigger size than flash size
|
||||
broken++;
|
||||
}
|
||||
if (broken) {
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware appears", "to be broken.", NULL, "Unplug your TREZOR", "and see our support", "page at mytrezor.com");
|
||||
system_halt();
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
setup();
|
||||
memory_protect();
|
||||
oledInit();
|
||||
|
||||
// at least one button is unpressed
|
||||
uint16_t state = gpio_port_read(BTN_PORT);
|
||||
if ((state & BTN_PIN_YES) == BTN_PIN_YES || (state & BTN_PIN_NO) == BTN_PIN_NO) {
|
||||
|
||||
check_firmware_sanity();
|
||||
|
||||
oledClear();
|
||||
oledDrawBitmap(40, 0, &bmp_logo64_empty);
|
||||
oledRefresh();
|
||||
|
||||
if (!signatures_ok()) {
|
||||
show_unofficial_warning();
|
||||
}
|
||||
|
||||
load_app();
|
||||
|
||||
}
|
||||
|
||||
bootloader_loop();
|
||||
|
||||
return 0;
|
||||
}
|
36
bootloader/bootloader.h
Normal file
36
bootloader/bootloader.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __BOOTLOADER_H__
|
||||
#define __BOOTLOADER_H__
|
||||
|
||||
#define VERSION_MAJOR 1
|
||||
#define VERSION_MINOR 2
|
||||
#define VERSION_PATCH 5
|
||||
|
||||
#define STR(X) #X
|
||||
#define VERSTR(X) STR(X)
|
||||
|
||||
#define VERSION_MAJOR_CHAR "\x01"
|
||||
#define VERSION_MINOR_CHAR "\x02"
|
||||
#define VERSION_PATCH_CHAR "\x05"
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
#endif
|
10
bootloader/combine/prepare.py
Executable file
10
bootloader/combine/prepare.py
Executable file
@ -0,0 +1,10 @@
|
||||
#!/usr/bin/python
|
||||
bl = open('bl.bin').read()
|
||||
fw = open('fw.bin').read()
|
||||
combined = bl + fw[:256] + (32768-256)*'\x00' + fw[256:]
|
||||
|
||||
open('combined.bin', 'w').write(combined)
|
||||
|
||||
print 'bootloader : %d bytes' % len(bl)
|
||||
print 'firmware : %d bytes' % len(fw)
|
||||
print 'combined : %d bytes' % len(combined)
|
2
bootloader/combine/write.sh
Executable file
2
bootloader/combine/write.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/bash
|
||||
st-flash write combined.bin 0x8000000
|
11
bootloader/firmware_align.py
Executable file
11
bootloader/firmware_align.py
Executable file
@ -0,0 +1,11 @@
|
||||
#!/usr/bin/python
|
||||
import sys
|
||||
import os
|
||||
|
||||
fn = sys.argv[1]
|
||||
fs = os.stat(fn).st_size
|
||||
if fs > 32768:
|
||||
raise Exception('bootloader has to be smaller than 32768 bytes')
|
||||
with open(fn, 'ab') as f:
|
||||
f.write(os.urandom(32768 - fs))
|
||||
f.close()
|
189
bootloader/firmware_sign.py
Executable file
189
bootloader/firmware_sign.py
Executable file
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/python
|
||||
import argparse
|
||||
import hashlib
|
||||
import struct
|
||||
import binascii
|
||||
import ecdsa
|
||||
|
||||
SLOTS = 3
|
||||
|
||||
pubkeys = {
|
||||
1: '04d571b7f148c5e4232c3814f777d8faeaf1a84216c78d569b71041ffc768a5b2d810fc3bb134dd026b57e65005275aedef43e155f48fc11a32ec790a93312bd58',
|
||||
2: '0463279c0c0866e50c05c799d32bd6bab0188b6de06536d1109d2ed9ce76cb335c490e55aee10cc901215132e853097d5432eda06b792073bd7740c94ce4516cb1',
|
||||
3: '0443aedbb6f7e71c563f8ed2ef64ec9981482519e7ef4f4aa98b27854e8c49126d4956d300ab45fdc34cd26bc8710de0a31dbdf6de7435fd0b492be70ac75fde58',
|
||||
4: '04877c39fd7c62237e038235e9c075dab261630f78eeb8edb92487159fffedfdf6046c6f8b881fa407c4a4ce6c28de0b19c1f4e29f1fcbc5a58ffd1432a3e0938a',
|
||||
5: '047384c51ae81add0a523adbb186c91b906ffb64c2c765802bf26dbd13bdf12c319e80c2213a136c8ee03d7874fd22b70d68e7dee469decfbbb510ee9a460cda45',
|
||||
}
|
||||
|
||||
INDEXES_START = len('TRZR') + struct.calcsize('<I')
|
||||
SIG_START = INDEXES_START + SLOTS + 1 + 52
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description='Commandline tool for signing Trezor firmware.')
|
||||
parser.add_argument('-f', '--file', dest='path', help="Firmware file to modify")
|
||||
parser.add_argument('-s', '--sign', dest='sign', action='store_true', help="Add signature to firmware slot")
|
||||
parser.add_argument('-p', '--pem', dest='pem', action='store_true', help="Use PEM instead of SECEXP")
|
||||
parser.add_argument('-g', '--generate', dest='generate', action='store_true', help='Generate new ECDSA keypair')
|
||||
|
||||
return parser.parse_args()
|
||||
|
||||
def prepare(data):
|
||||
# Takes raw OR signed firmware and clean out metadata structure
|
||||
# This produces 'clean' data for signing
|
||||
|
||||
meta = 'TRZR' # magic
|
||||
if data[:4] == 'TRZR':
|
||||
meta += data[4:4 + struct.calcsize('<I')]
|
||||
else:
|
||||
meta += struct.pack('<I', len(data)) # length of the code
|
||||
meta += '\x00' * SLOTS # signature index #1-#3
|
||||
meta += '\x01' # flags
|
||||
meta += '\x00' * 52 # reserved
|
||||
meta += '\x00' * 64 * SLOTS # signature #1-#3
|
||||
|
||||
if data[:4] == 'TRZR':
|
||||
# Replace existing header
|
||||
out = meta + data[len(meta):]
|
||||
else:
|
||||
# create data from meta + code
|
||||
out = meta + data
|
||||
|
||||
return out
|
||||
|
||||
def check_signatures(data):
|
||||
# Analyses given firmware and prints out
|
||||
# status of included signatures
|
||||
|
||||
indexes = [ ord(x) for x in data[INDEXES_START:INDEXES_START + SLOTS] ]
|
||||
|
||||
to_sign = prepare(data)[256:] # without meta
|
||||
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]
|
||||
|
||||
if indexes[x] == 0:
|
||||
print "Slot #%d" % (x + 1), 'is empty'
|
||||
else:
|
||||
pk = pubkeys[indexes[x]]
|
||||
verify = ecdsa.VerifyingKey.from_string(binascii.unhexlify(pk)[1:],
|
||||
curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
|
||||
|
||||
try:
|
||||
verify.verify(signature, to_sign, hashfunc=hashlib.sha256)
|
||||
|
||||
if indexes[x] in used:
|
||||
print "Slot #%d signature: DUPLICATE" % (x + 1), binascii.hexlify(signature)
|
||||
else:
|
||||
used.append(indexes[x])
|
||||
print "Slot #%d signature: VALID" % (x + 1), binascii.hexlify(signature)
|
||||
|
||||
except:
|
||||
print "Slot #%d signature: INVALID" % (x + 1), binascii.hexlify(signature)
|
||||
|
||||
|
||||
def modify(data, slot, index, signature):
|
||||
# Replace signature in data
|
||||
|
||||
# Put index to data
|
||||
data = data[:INDEXES_START + slot - 1 ] + chr(index) + data[INDEXES_START + slot:]
|
||||
|
||||
# Put signature to data
|
||||
data = data[:SIG_START + 64 * (slot - 1) ] + signature + data[SIG_START + 64 * slot:]
|
||||
|
||||
return 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))
|
||||
if slot < 1 or slot > SLOTS:
|
||||
raise Exception("Invalid slot")
|
||||
|
||||
if is_pem:
|
||||
print "Paste ECDSA private key in PEM format and press Enter:"
|
||||
print "(blank private key removes the signature on given index)"
|
||||
pem_key = ''
|
||||
while True:
|
||||
key = raw_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)
|
||||
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()
|
||||
if secexp.strip() == '':
|
||||
# Blank key,let's remove existing signature from slot
|
||||
return modify(data, slot, 0, '\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
|
||||
|
||||
# Locate proper index of current signing key
|
||||
pubkey = '04' + binascii.hexlify(key.get_verifying_key().to_string())
|
||||
index = None
|
||||
for i, pk in pubkeys.iteritems():
|
||||
if pk == pubkey:
|
||||
index = i
|
||||
break
|
||||
|
||||
if index == None:
|
||||
raise Exception("Unable to find private key index. Unknown private key?")
|
||||
|
||||
signature = key.sign_deterministic(to_sign, hashfunc=hashlib.sha256)
|
||||
|
||||
return modify(data, slot, index, signature)
|
||||
|
||||
def main(args):
|
||||
if args.generate:
|
||||
key = ecdsa.SigningKey.generate(
|
||||
curve=ecdsa.curves.SECP256k1,
|
||||
hashfunc=hashlib.sha256)
|
||||
|
||||
print "PRIVATE KEY (SECEXP):"
|
||||
print binascii.hexlify(key.to_string())
|
||||
print
|
||||
|
||||
print "PRIVATE KEY (PEM):"
|
||||
print key.to_pem()
|
||||
|
||||
print "PUBLIC KEY:"
|
||||
print '04' + binascii.hexlify(key.get_verifying_key().to_string())
|
||||
return
|
||||
|
||||
if not args.path:
|
||||
raise Exception("-f/--file is required")
|
||||
|
||||
data = open(args.path, 'rb').read()
|
||||
assert len(data) % 4 == 0
|
||||
|
||||
if data[:4] != 'TRZR':
|
||||
print "Metadata has been added..."
|
||||
data = prepare(data)
|
||||
|
||||
if data[:4] != 'TRZR':
|
||||
raise Exception("Firmware header expected")
|
||||
|
||||
print "Firmware size %d bytes" % len(data)
|
||||
|
||||
check_signatures(data)
|
||||
|
||||
if args.sign:
|
||||
data = sign(data, args.pem)
|
||||
check_signatures(data)
|
||||
|
||||
fp = open(args.path, 'w')
|
||||
fp.write(data)
|
||||
fp.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parse_args()
|
||||
main(args)
|
31
bootloader/firmware_sign_split.py
Executable file
31
bootloader/firmware_sign_split.py
Executable file
@ -0,0 +1,31 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import subprocess
|
||||
import ecdsa
|
||||
from binascii import hexlify, unhexlify
|
||||
|
||||
print 'master secret:',
|
||||
h = raw_input()
|
||||
if h:
|
||||
h = unhexlify(h)
|
||||
else:
|
||||
h = hashlib.sha256(os.urandom(1024)).digest()
|
||||
|
||||
print
|
||||
print 'master secret:', hexlify(h)
|
||||
print
|
||||
|
||||
for i in range(1, 6):
|
||||
se = hashlib.sha256(h + chr(i)).hexdigest()
|
||||
print 'seckey', i, ':', se
|
||||
sk = ecdsa.SigningKey.from_secret_exponent(secexp = int(se, 16), curve=ecdsa.curves.SECP256k1, hashfunc=hashlib.sha256)
|
||||
print 'pubkey', i, ':', '04' + hexlify(sk.get_verifying_key().to_string())
|
||||
print sk.to_pem()
|
||||
|
||||
p = subprocess.Popen('ssss-split -t 3 -n 5 -x'.split(' '), stdin = subprocess.PIPE)
|
||||
p.communicate(input = hexlify(h) + '\n')
|
||||
|
||||
# to recover use:
|
||||
# $ ssss-combine -t 3 -x
|
66
bootloader/signatures.c
Normal file
66
bootloader/signatures.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "signatures.h"
|
||||
#include "ecdsa.h"
|
||||
#include "bootloader.h"
|
||||
|
||||
#define PUBKEYS 5
|
||||
|
||||
static const uint8_t *pubkey[PUBKEYS] = {
|
||||
(uint8_t *)"\x04\xd5\x71\xb7\xf1\x48\xc5\xe4\x23\x2c\x38\x14\xf7\x77\xd8\xfa\xea\xf1\xa8\x42\x16\xc7\x8d\x56\x9b\x71\x04\x1f\xfc\x76\x8a\x5b\x2d\x81\x0f\xc3\xbb\x13\x4d\xd0\x26\xb5\x7e\x65\x00\x52\x75\xae\xde\xf4\x3e\x15\x5f\x48\xfc\x11\xa3\x2e\xc7\x90\xa9\x33\x12\xbd\x58",
|
||||
(uint8_t *)"\x04\x63\x27\x9c\x0c\x08\x66\xe5\x0c\x05\xc7\x99\xd3\x2b\xd6\xba\xb0\x18\x8b\x6d\xe0\x65\x36\xd1\x10\x9d\x2e\xd9\xce\x76\xcb\x33\x5c\x49\x0e\x55\xae\xe1\x0c\xc9\x01\x21\x51\x32\xe8\x53\x09\x7d\x54\x32\xed\xa0\x6b\x79\x20\x73\xbd\x77\x40\xc9\x4c\xe4\x51\x6c\xb1",
|
||||
(uint8_t *)"\x04\x43\xae\xdb\xb6\xf7\xe7\x1c\x56\x3f\x8e\xd2\xef\x64\xec\x99\x81\x48\x25\x19\xe7\xef\x4f\x4a\xa9\x8b\x27\x85\x4e\x8c\x49\x12\x6d\x49\x56\xd3\x00\xab\x45\xfd\xc3\x4c\xd2\x6b\xc8\x71\x0d\xe0\xa3\x1d\xbd\xf6\xde\x74\x35\xfd\x0b\x49\x2b\xe7\x0a\xc7\x5f\xde\x58",
|
||||
(uint8_t *)"\x04\x87\x7c\x39\xfd\x7c\x62\x23\x7e\x03\x82\x35\xe9\xc0\x75\xda\xb2\x61\x63\x0f\x78\xee\xb8\xed\xb9\x24\x87\x15\x9f\xff\xed\xfd\xf6\x04\x6c\x6f\x8b\x88\x1f\xa4\x07\xc4\xa4\xce\x6c\x28\xde\x0b\x19\xc1\xf4\xe2\x9f\x1f\xcb\xc5\xa5\x8f\xfd\x14\x32\xa3\xe0\x93\x8a",
|
||||
(uint8_t *)"\x04\x73\x84\xc5\x1a\xe8\x1a\xdd\x0a\x52\x3a\xdb\xb1\x86\xc9\x1b\x90\x6f\xfb\x64\xc2\xc7\x65\x80\x2b\xf2\x6d\xbd\x13\xbd\xf1\x2c\x31\x9e\x80\xc2\x21\x3a\x13\x6c\x8e\xe0\x3d\x78\x74\xfd\x22\xb7\x0d\x68\xe7\xde\xe4\x69\xde\xcf\xbb\xb5\x10\xee\x9a\x46\x0c\xda\x45",
|
||||
};
|
||||
|
||||
#define SIGNATURES 3
|
||||
|
||||
int signatures_ok(void)
|
||||
{
|
||||
uint32_t codelen = *((uint32_t *)FLASH_META_CODELEN);
|
||||
uint8_t sigindex1, sigindex2, sigindex3;
|
||||
|
||||
sigindex1 = *((uint8_t *)FLASH_META_SIGINDEX1);
|
||||
sigindex2 = *((uint8_t *)FLASH_META_SIGINDEX2);
|
||||
sigindex3 = *((uint8_t *)FLASH_META_SIGINDEX3);
|
||||
|
||||
if (sigindex1 < 1 || sigindex1 > PUBKEYS) return 0; // invalid index
|
||||
if (sigindex2 < 1 || sigindex2 > PUBKEYS) return 0; // invalid index
|
||||
if (sigindex3 < 1 || sigindex3 > PUBKEYS) return 0; // invalid index
|
||||
|
||||
if (sigindex1 == sigindex2) return 0; // duplicate use
|
||||
if (sigindex1 == sigindex3) return 0; // duplicate use
|
||||
if (sigindex2 == sigindex3) return 0; // duplicate use
|
||||
|
||||
if (ecdsa_verify(pubkey[sigindex1 - 1], (uint8_t *)FLASH_META_SIG1, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure
|
||||
return 0;
|
||||
}
|
||||
if (ecdsa_verify(pubkey[sigindex2 - 1], (uint8_t *)FLASH_META_SIG2, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failure
|
||||
return 0;
|
||||
}
|
||||
if (ecdsa_verify(pubkey[sigindex3 - 1], (uint8_t *)FLASH_META_SIG3, (uint8_t *)FLASH_APP_START, codelen) != 0) { // failture
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
25
bootloader/signatures.h
Normal file
25
bootloader/signatures.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __SIGNATURES_H__
|
||||
#define __SIGNATURES_H__
|
||||
|
||||
int signatures_ok(void);
|
||||
|
||||
#endif
|
518
bootloader/usb.c
Normal file
518
bootloader/usb.c
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <libopencm3/usb/usbd.h>
|
||||
#include <libopencm3/usb/hid.h>
|
||||
#include <libopencm3/stm32/flash.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "buttons.h"
|
||||
#include "bootloader.h"
|
||||
#include "oled.h"
|
||||
#include "rng.h"
|
||||
#include "usb.h"
|
||||
#include "serialno.h"
|
||||
#include "layout.h"
|
||||
#include "util.h"
|
||||
#include "signatures.h"
|
||||
#include "sha2.h"
|
||||
|
||||
static const struct usb_device_descriptor dev_descr = {
|
||||
.bLength = USB_DT_DEVICE_SIZE,
|
||||
.bDescriptorType = USB_DT_DEVICE,
|
||||
.bcdUSB = 0x0200,
|
||||
.bDeviceClass = 0,
|
||||
.bDeviceSubClass = 0,
|
||||
.bDeviceProtocol = 0,
|
||||
.bMaxPacketSize0 = 64,
|
||||
.idVendor = 0x534c,
|
||||
.idProduct = 0x0001,
|
||||
.bcdDevice = 0x0100,
|
||||
.iManufacturer = 1,
|
||||
.iProduct = 2,
|
||||
.iSerialNumber = 3,
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
/* got via usbhid-dump from CP2110 */
|
||||
static const uint8_t hid_report_descriptor[] = {
|
||||
0x06, 0x00, 0xFF, 0x09, 0x01, 0xA1, 0x01, 0x09, 0x01, 0x75, 0x08, 0x95, 0x40, 0x26, 0xFF, 0x00,
|
||||
0x15, 0x00, 0x85, 0x01, 0x95, 0x01, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x02,
|
||||
0x95, 0x02, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x03, 0x95, 0x03, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x04, 0x95, 0x04, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x05, 0x95, 0x05, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x06,
|
||||
0x95, 0x06, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x07, 0x95, 0x07, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x08, 0x95, 0x08, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x09, 0x95, 0x09, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0A,
|
||||
0x95, 0x0A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0B, 0x95, 0x0B, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0C, 0x95, 0x0C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x0D, 0x95, 0x0D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0E,
|
||||
0x95, 0x0E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x0F, 0x95, 0x0F, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x10, 0x95, 0x10, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x11, 0x95, 0x11, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x12,
|
||||
0x95, 0x12, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x13, 0x95, 0x13, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x14, 0x95, 0x14, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x15, 0x95, 0x15, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x16,
|
||||
0x95, 0x16, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x17, 0x95, 0x17, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x18, 0x95, 0x18, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x19, 0x95, 0x19, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1A,
|
||||
0x95, 0x1A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1B, 0x95, 0x1B, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1C, 0x95, 0x1C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x1D, 0x95, 0x1D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1E,
|
||||
0x95, 0x1E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x1F, 0x95, 0x1F, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x20, 0x95, 0x20, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x21, 0x95, 0x21, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x22,
|
||||
0x95, 0x22, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x23, 0x95, 0x23, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x24, 0x95, 0x24, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x25, 0x95, 0x25, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x26,
|
||||
0x95, 0x26, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x27, 0x95, 0x27, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x28, 0x95, 0x28, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x29, 0x95, 0x29, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2A,
|
||||
0x95, 0x2A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2B, 0x95, 0x2B, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2C, 0x95, 0x2C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x2D, 0x95, 0x2D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2E,
|
||||
0x95, 0x2E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x2F, 0x95, 0x2F, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x30, 0x95, 0x30, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x31, 0x95, 0x31, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x32,
|
||||
0x95, 0x32, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x33, 0x95, 0x33, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x34, 0x95, 0x34, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x35, 0x95, 0x35, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x36,
|
||||
0x95, 0x36, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x37, 0x95, 0x37, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x38, 0x95, 0x38, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x39, 0x95, 0x39, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3A,
|
||||
0x95, 0x3A, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3B, 0x95, 0x3B, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3C, 0x95, 0x3C, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01,
|
||||
0x91, 0x02, 0x85, 0x3D, 0x95, 0x3D, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3E,
|
||||
0x95, 0x3E, 0x09, 0x01, 0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x3F, 0x95, 0x3F, 0x09, 0x01,
|
||||
0x81, 0x02, 0x09, 0x01, 0x91, 0x02, 0x85, 0x40, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x41,
|
||||
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x42, 0x95, 0x06, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x43,
|
||||
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x44, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x45,
|
||||
0x95, 0x04, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x46, 0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x47,
|
||||
0x95, 0x02, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x50, 0x95, 0x08, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x51,
|
||||
0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x52, 0x95, 0x01, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x60,
|
||||
0x95, 0x0A, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x61, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x62,
|
||||
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x63, 0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x64,
|
||||
0x95, 0x3F, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x65, 0x95, 0x3E, 0x09, 0x01, 0xB1, 0x02, 0x85, 0x66,
|
||||
0x95, 0x13, 0x09, 0x01, 0xB1, 0x02, 0xC0,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
struct usb_hid_descriptor hid_descriptor;
|
||||
struct {
|
||||
uint8_t bReportDescriptorType;
|
||||
uint16_t wDescriptorLength;
|
||||
} __attribute__((packed)) hid_report;
|
||||
} __attribute__((packed)) hid_function = {
|
||||
.hid_descriptor = {
|
||||
.bLength = sizeof(hid_function),
|
||||
.bDescriptorType = USB_DT_HID,
|
||||
.bcdHID = 0x0111,
|
||||
.bCountryCode = 0,
|
||||
.bNumDescriptors = 1,
|
||||
},
|
||||
.hid_report = {
|
||||
.bReportDescriptorType = USB_DT_REPORT,
|
||||
.wDescriptorLength = sizeof(hid_report_descriptor),
|
||||
}
|
||||
};
|
||||
|
||||
static const struct usb_endpoint_descriptor hid_endpoints[2] = {{
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0x81,
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 1,
|
||||
}, {
|
||||
.bLength = USB_DT_ENDPOINT_SIZE,
|
||||
.bDescriptorType = USB_DT_ENDPOINT,
|
||||
.bEndpointAddress = 0x02,
|
||||
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
|
||||
.wMaxPacketSize = 64,
|
||||
.bInterval = 1,
|
||||
}};
|
||||
|
||||
static const struct usb_interface_descriptor hid_iface[] = {{
|
||||
.bLength = USB_DT_INTERFACE_SIZE,
|
||||
.bDescriptorType = USB_DT_INTERFACE,
|
||||
.bInterfaceNumber = 0,
|
||||
.bAlternateSetting = 0,
|
||||
.bNumEndpoints = 2,
|
||||
.bInterfaceClass = USB_CLASS_HID,
|
||||
.bInterfaceSubClass = 0,
|
||||
.bInterfaceProtocol = 0,
|
||||
.iInterface = 0,
|
||||
.endpoint = hid_endpoints,
|
||||
.extra = &hid_function,
|
||||
.extralen = sizeof(hid_function),
|
||||
}};
|
||||
|
||||
static const struct usb_interface ifaces[] = {{
|
||||
.num_altsetting = 1,
|
||||
.altsetting = hid_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",
|
||||
"", // empty serial
|
||||
};
|
||||
|
||||
static int hid_control_request(usbd_device *dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
|
||||
void (**complete)(usbd_device *, struct usb_setup_data *))
|
||||
{
|
||||
(void)complete;
|
||||
(void)dev;
|
||||
|
||||
if ((req->bmRequestType != 0x81) ||
|
||||
(req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
|
||||
(req->wValue != 0x2200)) return 0;
|
||||
|
||||
*buf = (uint8_t *)hid_report_descriptor;
|
||||
*len = sizeof(hid_report_descriptor);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
enum {
|
||||
STATE_READY,
|
||||
STATE_OPEN,
|
||||
STATE_FLASHSTART,
|
||||
STATE_FLASHING,
|
||||
STATE_CHECK,
|
||||
STATE_END,
|
||||
};
|
||||
|
||||
static uint32_t flash_pos = 0, flash_len = 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)
|
||||
{
|
||||
// send response: Success message (id 2), payload len 0
|
||||
while ( usbd_ep_write_packet(dev, 0x81,
|
||||
"?##" // header
|
||||
"\x00\x02" // msg_id
|
||||
"\x00\x00\x00\x00" // payload_len
|
||||
"\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
, 64) != 64) {}
|
||||
}
|
||||
|
||||
static void send_msg_failure(usbd_device *dev)
|
||||
{
|
||||
// send response: Failure message (id 3), payload len 2
|
||||
// code = 99 (Failure_FirmwareError)
|
||||
while ( usbd_ep_write_packet(dev, 0x81,
|
||||
"?##" // header
|
||||
"\x00\x03" // msg_id
|
||||
"\x00\x00\x00\x02" // payload_len
|
||||
"\x08\x63" // data
|
||||
"\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
, 64) != 64) {}
|
||||
}
|
||||
|
||||
static void send_msg_features(usbd_device *dev)
|
||||
{
|
||||
// send response: Features message (id 17), payload len 27
|
||||
// vendor = "bitcointrezor.com"
|
||||
// major_version = VERSION_MAJOR
|
||||
// minor_version = VERSION_MINOR
|
||||
// patch_version = VERSION_PATCH
|
||||
// bootloader_mode = True
|
||||
while ( usbd_ep_write_packet(dev, 0x81,
|
||||
"?##" // header
|
||||
"\x00\x11" // msg_id
|
||||
"\x00\x00\x00\x1b" // payload_len
|
||||
"\x0a\x11" "bitcointrezor.com\x10" VERSION_MAJOR_CHAR "\x18" VERSION_MINOR_CHAR " " VERSION_PATCH_CHAR "(\x01" // data
|
||||
"\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"
|
||||
, 64) != 64) {}
|
||||
}
|
||||
|
||||
static void send_msg_buttonrequest_firmwarecheck(usbd_device *dev)
|
||||
{
|
||||
// send response: ButtonRequest message (id 26), payload len 2
|
||||
// code = ButtonRequest_FirmwareCheck (9)
|
||||
while ( usbd_ep_write_packet(dev, 0x81,
|
||||
"?##" // header
|
||||
"\x00\x1a" // msg_id
|
||||
"\x00\x00\x00\x02" // payload_len
|
||||
"\x08\x09" // data
|
||||
"\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
, 64) != 64) {}
|
||||
}
|
||||
|
||||
static void hid_rx_callback(usbd_device *dev, uint8_t ep)
|
||||
{
|
||||
(void)ep;
|
||||
static uint8_t buf[64] __attribute__((aligned(4)));
|
||||
uint8_t *p;
|
||||
static uint8_t towrite[4] __attribute__((aligned(4)));
|
||||
static int wi;
|
||||
int i;
|
||||
uint32_t *w;
|
||||
static SHA256_CTX ctx;
|
||||
|
||||
if ( usbd_ep_read_packet(dev, 0x02, buf, 64) != 64) return;
|
||||
|
||||
if (flash_state == STATE_END) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flash_state == STATE_READY || flash_state == STATE_OPEN || flash_state == STATE_FLASHSTART || flash_state == STATE_CHECK) {
|
||||
if (buf[0] != '?' || buf[1] != '#' || buf[2] != '#') { // invalid start - discard
|
||||
return;
|
||||
}
|
||||
// struct.unpack(">HL") => msg, size
|
||||
msg_id = (buf[3] << 8) + buf[4];
|
||||
msg_size = (buf[5] << 24)+ (buf[6] << 16) + (buf[7] << 8) + buf[8];
|
||||
}
|
||||
|
||||
if (flash_state == STATE_READY || flash_state == STATE_OPEN) {
|
||||
if (msg_id == 0x0000) { // Initialize message (id 0)
|
||||
send_msg_features(dev);
|
||||
flash_state = STATE_OPEN;
|
||||
return;
|
||||
}
|
||||
if (msg_id == 0x0001) { // Ping message (id 1)
|
||||
send_msg_success(dev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (flash_state == STATE_OPEN) {
|
||||
if (msg_id == 0x0006) { // FirmwareErase message (id 6)
|
||||
layoutDialog(DIALOG_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);
|
||||
if (button.YesUp) {
|
||||
layoutProgress("INSTALLING ... Please wait", 0, 0);
|
||||
// backup metadata
|
||||
memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_LEN);
|
||||
flash_unlock();
|
||||
// erase metadata area
|
||||
for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) {
|
||||
flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
|
||||
}
|
||||
// erase code area
|
||||
for (i = FLASH_CODE_SECTOR_FIRST; i <= FLASH_CODE_SECTOR_LAST; i++) {
|
||||
flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
|
||||
}
|
||||
flash_lock();
|
||||
send_msg_success(dev);
|
||||
flash_state = STATE_FLASHSTART;
|
||||
return;
|
||||
}
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (flash_state == STATE_FLASHSTART) {
|
||||
if (msg_id == 0x0007) { // FirmwareUpload message (id 7)
|
||||
if (buf[9] != 0x0a) { // invalid contents
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
return;
|
||||
}
|
||||
// read payload length
|
||||
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
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Firmware is too big.", NULL, "Get official firmware", "from mytrezor.com", NULL, NULL);
|
||||
return;
|
||||
}
|
||||
sha256_Init(&ctx);
|
||||
flash_state = STATE_FLASHING;
|
||||
flash_pos = 0;
|
||||
wi = 0;
|
||||
flash_unlock();
|
||||
while (p < buf + 64) {
|
||||
towrite[wi] = *p;
|
||||
wi++;
|
||||
if (wi == 4) {
|
||||
w = (uint32_t *)towrite;
|
||||
flash_program_word(FLASH_META_START + flash_pos, *w);
|
||||
flash_pos += 4;
|
||||
wi = 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
flash_lock();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (flash_state == STATE_FLASHING) {
|
||||
if (buf[0] != '?') { // invalid contents
|
||||
send_msg_failure(dev);
|
||||
flash_state = STATE_END;
|
||||
layoutDialog(DIALOG_ICON_ERROR, NULL, NULL, NULL, "Error installing ", "firmware.", NULL, "Unplug your TREZOR", "and try again.", NULL);
|
||||
return;
|
||||
}
|
||||
p = buf + 1;
|
||||
layoutProgress("INSTALLING ... Please wait", 1000 * flash_pos / flash_len, flash_anim / 8);
|
||||
flash_anim++;
|
||||
flash_unlock();
|
||||
while (p < buf + 64 && flash_pos < flash_len) {
|
||||
towrite[wi] = *p;
|
||||
wi++;
|
||||
if (wi == 4) {
|
||||
w = (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
|
||||
} else {
|
||||
flash_program_word(FLASH_APP_START + (flash_pos - FLASH_META_DESC_LEN), *w); // the rest is code
|
||||
sha256_Update(&ctx, towrite, 4);
|
||||
}
|
||||
flash_pos += 4;
|
||||
wi = 0;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
flash_lock();
|
||||
// flashing done
|
||||
if (flash_pos == flash_len) {
|
||||
flash_state = STATE_CHECK;
|
||||
send_msg_buttonrequest_firmwarecheck(dev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (flash_state == STATE_CHECK) {
|
||||
if (msg_id != 0x001B) { // ButtonAck message (id 27)
|
||||
return;
|
||||
}
|
||||
char digest[64];
|
||||
sha256_End(&ctx, digest);
|
||||
char str[4][17];
|
||||
strlcpy(str[0], digest, 17);
|
||||
strlcpy(str[1], digest + 16, 17);
|
||||
strlcpy(str[2], digest + 32, 17);
|
||||
strlcpy(str[3], digest + 48, 17);
|
||||
layoutDialog(DIALOG_ICON_QUESTION, "Abort", "Continue", "Compare fingerprints", str[0], str[1], str[2], str[3], NULL, NULL);
|
||||
|
||||
do {
|
||||
delay(100000);
|
||||
buttonUpdate();
|
||||
} while (!button.YesUp && !button.NoUp);
|
||||
|
||||
bool hash_check_ok = button.YesUp;
|
||||
|
||||
layoutProgress("INSTALLING ... Please wait", 1000, 0);
|
||||
uint8_t flags = *((uint8_t *)FLASH_META_FLAGS);
|
||||
// check if to restore old storage area but only if signatures are ok
|
||||
if ((flags & 0x01) && signatures_ok()) {
|
||||
// copy new stuff
|
||||
memcpy(meta_backup, (void *)FLASH_META_START, FLASH_META_DESC_LEN);
|
||||
// replace "TRZR" in header with 0000 when hash not confirmed
|
||||
if (!hash_check_ok) {
|
||||
meta_backup[0] = 0;
|
||||
meta_backup[1] = 0;
|
||||
meta_backup[2] = 0;
|
||||
meta_backup[3] = 0;
|
||||
}
|
||||
flash_unlock();
|
||||
// erase storage
|
||||
for (i = FLASH_META_SECTOR_FIRST; i <= FLASH_META_SECTOR_LAST; i++) {
|
||||
flash_erase_sector(i, FLASH_CR_PROGRAM_X32);
|
||||
}
|
||||
// copy it back
|
||||
for (i = 0; i < FLASH_META_LEN / 4; i++) {
|
||||
w = (uint32_t *)(meta_backup + i * 4);
|
||||
flash_program_word(FLASH_META_START + i * 4, *w);
|
||||
}
|
||||
flash_lock();
|
||||
} else {
|
||||
// replace "TRZR" in header with 0000 when hash not confirmed
|
||||
if (!hash_check_ok) {
|
||||
// no need to erase, because we are just erasing bits
|
||||
flash_unlock();
|
||||
flash_program_word(FLASH_META_START, 0x00000000);
|
||||
flash_lock();
|
||||
}
|
||||
}
|
||||
flash_state = STATE_END;
|
||||
if (hash_check_ok) {
|
||||
layoutDialog(DIALOG_ICON_OK, NULL, NULL, NULL, "New firmware", "successfully installed.", NULL, "You may now", "unplug your TREZOR.", NULL);
|
||||
send_msg_success(dev);
|
||||
} else {
|
||||
layoutDialog(DIALOG_ICON_WARNING, NULL, NULL, NULL, "Firmware installation", "aborted.", NULL, "You need to repeat", "the procedure with", "the correct firmware.");
|
||||
send_msg_failure(dev);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void hid_set_config(usbd_device *dev, uint16_t wValue)
|
||||
{
|
||||
(void)wValue;
|
||||
|
||||
usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_INTERRUPT, 64, 0);
|
||||
usbd_ep_setup(dev, 0x02, USB_ENDPOINT_ATTR_INTERRUPT, 64, hid_rx_callback);
|
||||
|
||||
usbd_register_control_callback(
|
||||
dev,
|
||||
USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
|
||||
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
|
||||
hid_control_request
|
||||
);
|
||||
}
|
||||
|
||||
static usbd_device *usbd_dev;
|
||||
static uint8_t usbd_control_buffer[128];
|
||||
|
||||
void usbInit(void)
|
||||
{
|
||||
usbd_dev = usbd_init(&otgfs_usb_driver, &dev_descr, &config, usb_strings, 3, usbd_control_buffer, sizeof(usbd_control_buffer));
|
||||
usbd_register_set_config_callback(usbd_dev, hid_set_config);
|
||||
}
|
||||
|
||||
void usbLoop(void)
|
||||
{
|
||||
for (;;) {
|
||||
usbd_poll(usbd_dev);
|
||||
}
|
||||
}
|
26
bootloader/usb.h
Normal file
26
bootloader/usb.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the TREZOR project.
|
||||
*
|
||||
* Copyright (C) 2014 Pavol Rusnak <stick@satoshilabs.com>
|
||||
*
|
||||
* This library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __USB_H__
|
||||
#define __USB_H__
|
||||
|
||||
void usbInit(void);
|
||||
void usbLoop(void);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user