mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-11-29 10:58:21 +00:00
Implemented vendor header.
Header is generated with ./tools/build_vendorheader 'key1,key2,key3' 2 1.1 SatoshiLabs assets/satoshilabs.png micropython/firmware/vendorheader.bin where - keyN is a 64 character hex string encoding the public key - 2 encodes 2/3 key scheme - 1.1 is the version number (major, minor) - SatoshiLabs is the vendor name - satoshilabs.png is the vendor image Updated the firmware compilation that it adds vendor header and updated loader that it handles vendor header to be present.
This commit is contained in:
parent
300daa4513
commit
e0fd890661
@ -311,6 +311,7 @@ OBJ_HAL += $(addprefix $(BUILD_MP)/,\
|
||||
|
||||
# OBJ micropython/
|
||||
OBJ_FW += $(addprefix $(BUILD_FW)/, \
|
||||
firmware/vendorheader.o \
|
||||
firmware/header.o \
|
||||
firmware/main.o \
|
||||
firmware/mphalport.o \
|
||||
@ -399,6 +400,11 @@ QSTR_GEN_EXTRA_CFLAGS += -DNO_QSTR -DN_X64 -DN_X86 -DN_THUMB -DN_ARM -DN_XTENSA
|
||||
|
||||
all: $(BUILD)/$(TARGET).bin
|
||||
|
||||
$(BUILD_FW)/firmware/vendorheader.o: $(SRCDIR_FW)/firmware/vendorheader.bin
|
||||
$(Q)$(OBJCOPY) -I binary -O elf32-littlearm -B arm \
|
||||
--rename-section .data=.vendorheader,alloc,load,readonly,contents \
|
||||
$< $@
|
||||
|
||||
$(BUILD)/$(TARGET).elf: $(OBJ)
|
||||
$(ECHO) "LINK $@"
|
||||
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
|
||||
|
@ -61,12 +61,12 @@ TREZOR Core firmware consists of 3 parts:
|
||||
|
||||
### Vendor Header
|
||||
|
||||
Total length of vendor header is 84 + 32 * (number of pubkeys) + (length of vendor string) + (length of vendor image) bytes rounded up to the closest multiply of 512 bytes.
|
||||
Total length of vendor header is 84 + 32 * (number of pubkeys) + (length of vendor string rounded up to multiple of 4) + (length of vendor image) bytes rounded up to the closest multiple of 512 bytes.
|
||||
|
||||
| offset | length | name | description |
|
||||
|-------:|-------:|------|-------------|
|
||||
| 0x0000 | 4 | magic | firmware magic `TRZV` |
|
||||
| 0x0004 | 4 | hdrlen | length of the vendor header |
|
||||
| 0x0004 | 4 | hdrlen | length of the vendor header (multiple of 512) |
|
||||
| 0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
|
||||
| 0x000C | 1 | vmajor | version (major) |
|
||||
| 0x000D | 1 | vminor | version (minor) |
|
||||
@ -77,8 +77,9 @@ Total length of vendor header is 84 + 32 * (number of pubkeys) + (length of vend
|
||||
| ? | 32 | vpubn | vendor pubkey n |
|
||||
| ? | 1 | vstr_len | vendor string length |
|
||||
| ? | ? | vstr | vendor string |
|
||||
| ? | 2 | vimg_len | vendor image length |
|
||||
| ? | ? | vstrpad | padding to a multiple of 4 bytes |
|
||||
| ? | ? | vimg | vendor image (in [TOIf format](toif.md)) |
|
||||
| ? | ? | reserved | padding to an address that is -65 modulo 512 |
|
||||
| ? | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
|
||||
| ? | 64 | sig | SatoshiLabs aggregated signature |
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
#define IMAGE_MAGIC 0x4C5A5254 // TRZL
|
||||
#define IMAGE_MAXSIZE (1 * 64 * 1024 + 7 * 128 + 1024)
|
||||
#define IMAGE_MAXSIZE (1 * 64 * 1024 + 7 * 128 * 1024)
|
||||
|
@ -24,7 +24,6 @@
|
||||
|
||||
int main(void) {
|
||||
|
||||
SCB->VTOR = FIRMWARE_START + HEADER_SIZE;
|
||||
periph_init();
|
||||
|
||||
pendsv_init();
|
||||
|
@ -28,6 +28,7 @@ SECTIONS
|
||||
/* Firmware Header */
|
||||
.header :
|
||||
{
|
||||
KEEP(*(.vendorheader))
|
||||
KEEP(*(.header))
|
||||
} > FLASH
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
#define IMAGE_MAGIC 0x465A5254 // TRZF
|
||||
#define IMAGE_MAXSIZE (7 * 128 + 1024)
|
||||
#define IMAGE_MAXSIZE (7 * 128 * 1024)
|
||||
|
@ -17,14 +17,16 @@ void pendsv_isr_handler(void) {
|
||||
void check_and_jump(void)
|
||||
{
|
||||
LOADER_PRINTLN("checking firmware");
|
||||
if (image_check_signature((const uint8_t *)FIRMWARE_START)) {
|
||||
// TODO: check vendor header and its signature
|
||||
uint32_t vhdrlen = *((const uint32_t *) (FIRMWARE_START + 4));
|
||||
if (image_check_signature((const uint8_t *) (FIRMWARE_START + vhdrlen))) {
|
||||
LOADER_PRINTLN("valid firmware image");
|
||||
// TODO: remove debug wait
|
||||
LOADER_PRINTLN("waiting 1 second");
|
||||
HAL_Delay(1000);
|
||||
// end
|
||||
LOADER_PRINTLN("JUMP!");
|
||||
jump_to(FIRMWARE_START + HEADER_SIZE);
|
||||
jump_to(FIRMWARE_START + vhdrlen + HEADER_SIZE);
|
||||
} else {
|
||||
LOADER_PRINTLN("invalid firmware image");
|
||||
}
|
||||
|
35
tools/binctl
35
tools/binctl
@ -85,9 +85,15 @@ class BinImage:
|
||||
|
||||
class FirmwareImage(BinImage):
|
||||
|
||||
def __init__(self, data):
|
||||
super().__init__(data, magic=b'TRZF', max_size=7*128*1024)
|
||||
def __init__(self, data, vhdrlen):
|
||||
super().__init__(data[vhdrlen:], magic=b'TRZF', max_size=7*128*1024)
|
||||
self.vheader = data[0:vhdrlen]
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(self.vheader)
|
||||
f.write(self.serialize_header())
|
||||
f.write(self.code)
|
||||
|
||||
class LoaderImage(BinImage):
|
||||
|
||||
@ -95,7 +101,6 @@ class LoaderImage(BinImage):
|
||||
super().__init__(data, magic=b'TRZL', max_size=64*1024 + 7*128*1024)
|
||||
|
||||
|
||||
"""
|
||||
class VendorHeader:
|
||||
|
||||
def __init__(self, data):
|
||||
@ -107,7 +112,7 @@ class VendorHeader:
|
||||
self.vminor, \
|
||||
self.vsig_m, \
|
||||
self.vsig_n = header
|
||||
assert self.magic == b'TRZF'
|
||||
assert self.magic == b'TRZV'
|
||||
assert self.vsig_m > 0 and self.vsig_m <= self.vsig_n
|
||||
assert self.vsig_n > 0 and self.vsig_n <= 8
|
||||
p = 16
|
||||
@ -119,8 +124,9 @@ class VendorHeader:
|
||||
p += 1
|
||||
self.vstr = data[p:p + self.vstr_len]
|
||||
p += self.vstr_len
|
||||
self.vimg_len, _ = struct.unpack('<H', data[p: p + 2])
|
||||
p += 2
|
||||
vstr_pad = -p & 3
|
||||
p += vstr_pad
|
||||
self.vimg_len = len(data) - 65 - p
|
||||
self.vimg = data[p:p + self.vimg_len]
|
||||
p += self.vimg_len
|
||||
self.sigmask = data[p]
|
||||
@ -128,8 +134,8 @@ class VendorHeader:
|
||||
self.sig = data[p:p+64]
|
||||
assert len(data) == 4 + 4 + 4 + 1 + 1 + 1 + 1 + \
|
||||
32 * len(self.vpub) + \
|
||||
1 + self.vstr_len + \
|
||||
2 + self.vimg_len + \
|
||||
1 + self.vstr_len + vstr_pad + \
|
||||
self.vimg_len + \
|
||||
1 + 64
|
||||
|
||||
def print(self):
|
||||
@ -169,7 +175,6 @@ class VendorHeader:
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(self.serialize_header())
|
||||
"""
|
||||
|
||||
|
||||
def binopen(filename):
|
||||
@ -180,13 +185,17 @@ def binopen(filename):
|
||||
magic = data[:4]
|
||||
if magic == b'TRZL':
|
||||
return LoaderImage(data)
|
||||
if magic == b'TRZV':
|
||||
vheader = VendorHeader(data)
|
||||
if len(data) == vheader.hdrlen:
|
||||
return vheader
|
||||
subdata = data[vheader.hdrlen:]
|
||||
if subdata[:4] == b'TRZF':
|
||||
return FirmwareImage(data, vheader.hdrlen)
|
||||
if magic == b'TRZF':
|
||||
return FirmwareImage(data)
|
||||
# if magic == b'TRZV':
|
||||
# return VendorHeader(data)
|
||||
return FirmwareImage(data, 0)
|
||||
raise Exception('Unknown file format')
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage: binctl file.bin [-s]')
|
||||
|
109
tools/build_vendorheader
Executable file
109
tools/build_vendorheader
Executable file
@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
from PIL import Image
|
||||
import sys
|
||||
import re
|
||||
import struct
|
||||
import zlib
|
||||
import binascii
|
||||
|
||||
def process_rgb(w, h, pix):
|
||||
data = bytes()
|
||||
for j in range(h):
|
||||
for i in range(w):
|
||||
r, g, b = pix[i, j]
|
||||
c = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3)
|
||||
data += struct.pack('>H', c)
|
||||
return data
|
||||
|
||||
|
||||
def process_grayscale(w, h, pix):
|
||||
data = bytes()
|
||||
for j in range(h):
|
||||
for i in range(w // 2):
|
||||
l1, l2 = pix[i * 2, j], pix[i * 2 + 1, j]
|
||||
c = (l1 & 0xF0) | (l2 >> 4)
|
||||
data += struct.pack('>B', c)
|
||||
return data
|
||||
|
||||
|
||||
def process_image(ifn):
|
||||
im = Image.open(ifn)
|
||||
w, h = im.size
|
||||
print('Opened %s ... %d x %d @ %s' % (ifn, w, h, im.mode))
|
||||
|
||||
if im.mode == 'RGB':
|
||||
print('Detected RGB mode')
|
||||
elif im.mode == 'L':
|
||||
if w % 2 > 0:
|
||||
print('PNG file must have width divisible by 2')
|
||||
return 3
|
||||
print('Detected GRAYSCALE mode')
|
||||
else:
|
||||
print('Unknown mode:', im.mode)
|
||||
return 4
|
||||
|
||||
pix = im.load()
|
||||
|
||||
if im.mode == 'RGB':
|
||||
ofn = '%s.toif' % ifn[:-4]
|
||||
pixeldata = process_rgb(w, h, pix)
|
||||
else:
|
||||
ofn = '%s.toig' % ifn[:-4]
|
||||
pixeldata = process_grayscale(w, h, pix)
|
||||
z = zlib.compressobj(level=9, wbits=10)
|
||||
zdata = z.compress(pixeldata) + z.flush()
|
||||
zdata = zdata[2:-4] # strip header and checksum
|
||||
|
||||
toif = b''
|
||||
if im.mode == 'RGB':
|
||||
toif += b'TOIf'
|
||||
else:
|
||||
toif += b'TOIg'
|
||||
toif += struct.pack('<HH', w, h)
|
||||
toif += struct.pack('<I', len(zdata))
|
||||
toif += zdata
|
||||
return toif
|
||||
|
||||
# encode vendor name, add length byte and padding to multiple of 4
|
||||
def vendorencode(vname):
|
||||
vbin = vname.encode('utf-8')
|
||||
vbin = struct.pack('<B',len(vbin)) + vbin
|
||||
vbin += b'\0' * (-len(vbin) & 3)
|
||||
return vbin
|
||||
|
||||
def encodekey(key):
|
||||
if len(key) != 64:
|
||||
raise Exception("Wrong key length")
|
||||
return binascii.unhexlify(key)
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 7:
|
||||
print('Usage build_vendorheader key1hex,... m version vendorname vendorimage.png vendorimage.bin')
|
||||
return 1
|
||||
|
||||
keys = list(map(encodekey, sys.argv[1].split(',')))
|
||||
m = int(sys.argv[2])
|
||||
(major,minor) = map(lambda x: int(x),
|
||||
re.search('^(\d+)\.(\d+)$', sys.argv[3]).groups())
|
||||
vname = sys.argv[4]
|
||||
ifn = sys.argv[5]
|
||||
ofn = sys.argv[6]
|
||||
if not ifn.endswith('.png'):
|
||||
print('Must provide PNG file')
|
||||
return 2
|
||||
|
||||
timeout = 0
|
||||
vheader = b'TRZV' + struct.pack('<IIBBBB', 0, timeout, major, minor, m, len(keys))
|
||||
for k in keys:
|
||||
vheader += k
|
||||
vheader += vendorencode(vname) + process_image(ifn)
|
||||
padding = 65 + (-len(vheader) - 65) & 511
|
||||
vheader += b'\0' * padding
|
||||
|
||||
# put in length
|
||||
vheader = vheader[0:4] + struct.pack('<I', len(vheader)) + vheader[8:]
|
||||
|
||||
with open(ofn, 'wb') as f:
|
||||
f.write(vheader)
|
||||
|
||||
main()
|
Loading…
Reference in New Issue
Block a user