diff --git a/core/Makefile b/core/Makefile index 6a7a98cf4..7c1ca0e8c 100644 --- a/core/Makefile +++ b/core/Makefile @@ -214,8 +214,8 @@ gdb_firmware: $(FIRMWARE_BUILD_DIR)/firmware.elf ## start remote gdb session to ## misc commands: binctl: ## print info about binary files - ./tools/binctl $(BOOTLOADER_BUILD_DIR)/bootloader.bin - ./tools/binctl $(FIRMWARE_BUILD_DIR)/firmware.bin + ./tools/headertool.py $(BOOTLOADER_BUILD_DIR)/bootloader.bin + ./tools/headertool.py $(FIRMWARE_BUILD_DIR)/firmware.bin bloaty: ## run bloaty size profiler bloaty -d symbols -n 0 -s file $(FIRMWARE_BUILD_DIR)/firmware.elf | less diff --git a/core/SConscript.bootloader b/core/SConscript.bootloader index 092c351a2..1310a1df6 100644 --- a/core/SConscript.bootloader +++ b/core/SConscript.bootloader @@ -160,8 +160,7 @@ env.Replace( ASPPFLAGS='$CFLAGS $CCFLAGS', ) env.Replace( - BINCTL='tools/binctl', - KEYCTL='tools/keyctl', + HEADERTOOL='tools/headertool.py', ) # @@ -186,6 +185,5 @@ program_bin = env.Command( source=program_elf, action=[ '$OBJCOPY -O binary -j .header -j .flash -j .data $SOURCE $TARGET', - '$BINCTL $TARGET -h', - '$BINCTL $TARGET -s 1:2 `$KEYCTL sign bootloader $TARGET 4141414141414141414141414141414141414141414141414141414141414141 4242424242424242424242424242424242424242424242424242424242424242`' if ARGUMENTS.get('PRODUCTION', '0') == '0' else '', + '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), ], ) diff --git a/core/SConscript.firmware b/core/SConscript.firmware index e83c765d5..be45c9b21 100644 --- a/core/SConscript.firmware +++ b/core/SConscript.firmware @@ -397,8 +397,7 @@ env.Replace( ASPPFLAGS='$CFLAGS $CCFLAGS', ) env.Replace( - BINCTL='tools/binctl', - KEYCTL='tools/keyctl', + HEADERTOOL='tools/headertool.py', PYTHON='python', MAKEQSTRDATA='$PYTHON vendor/micropython/py/makeqstrdata.py', MAKEVERSIONHDR='$PYTHON vendor/micropython/py/makeversionhdr.py', @@ -613,8 +612,7 @@ if env.get('TREZOR_MODEL') == 'T': '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data --pad-to 0x08100000 $SOURCE ${TARGET}.p1', '$OBJCOPY -O binary -j .flash2 $SOURCE ${TARGET}.p2', '$CAT ${TARGET}.p1 ${TARGET}.p2 > $TARGET', - '$BINCTL $TARGET -h', - '$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`' if ARGUMENTS.get('PRODUCTION', '0') == '0' else '', + '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), '$DD if=$TARGET of=${TARGET}.p1 skip=0 bs=128k count=6', ] else: diff --git a/core/SConscript.prodtest b/core/SConscript.prodtest index 2307c42a2..77695ac4a 100644 --- a/core/SConscript.prodtest +++ b/core/SConscript.prodtest @@ -136,8 +136,7 @@ env.Replace( ASPPFLAGS='$CFLAGS $CCFLAGS', ) env.Replace( - BINCTL='tools/binctl', - KEYCTL='tools/keyctl', + HEADERTOOL='tools/headertool.py', ) # @@ -172,6 +171,5 @@ program_bin = env.Command( source=program_elf, action=[ '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', - '$BINCTL $TARGET -h', - '$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`' if ARGUMENTS.get('PRODUCTION', '0') == '0' else '', + '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), ], ) diff --git a/core/SConscript.reflash b/core/SConscript.reflash index 51c2c0e9b..0369b9a8d 100644 --- a/core/SConscript.reflash +++ b/core/SConscript.reflash @@ -130,8 +130,7 @@ env.Replace( ASPPFLAGS='$CFLAGS $CCFLAGS', ) env.Replace( - BINCTL='tools/binctl', - KEYCTL='tools/keyctl', + HEADERTOOL='tools/headertool.py', ) # @@ -166,6 +165,5 @@ program_bin = env.Command( source=program_elf, action=[ '$OBJCOPY -O binary -j .vendorheader -j .header -j .flash -j .data $SOURCE $TARGET', - '$BINCTL $TARGET -h', - '$BINCTL $TARGET -s 1:2 `$KEYCTL sign firmware $TARGET 4747474747474747474747474747474747474747474747474747474747474747 4848484848484848484848484848484848484848484848484848484848484848`' if ARGUMENTS.get('PRODUCTION', '0') == '0' else '', + '$HEADERTOOL $TARGET ' + ('-D' if ARGUMENTS.get('PRODUCTION', '0') == '0' else ''), ], ) diff --git a/core/tools/binctl b/core/tools/binctl deleted file mode 100755 index 9685fa3dd..000000000 --- a/core/tools/binctl +++ /dev/null @@ -1,363 +0,0 @@ -#!/usr/bin/env python3 - -from __future__ import print_function - -import sys -import struct -import binascii - -import pyblake2 - -from trezorlib import cosi - - -def format_sigmask(sigmask): - bits = [str(b + 1) if sigmask & (1 << b) else "." for b in range(8)] - return "0x%02x = [%s]" % (sigmask, " ".join(bits)) - - -def format_vtrust(vtrust): - bits = [str(b) if vtrust & (1 << b) == 0 else "." for b in range(16)] - # see docs/bootloader.md for vtrust constants - desc = "" - wait = (vtrust & 0x000F) ^ 0x000F - if wait > 0: - desc = "WAIT_%d" % wait - if vtrust & 0x0010 == 0: - desc += " RED" - if vtrust & 0x0020 == 0: - desc += " CLICK" - if vtrust & 0x0040 == 0: - desc += " STRING" - return "%d = [%s] = [%s]" % (vtrust, " ".join(bits), desc) - - -# bootloader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md - -IMAGE_HEADER_SIZE = 1024 -IMAGE_SIG_SIZE = 65 -IMAGE_CHUNK_SIZE = 128 * 1024 -BOOTLOADER_SECTORS_COUNT = 1 -FIRMWARE_SECTORS_COUNT = 6 + 7 - - -class BinImage(object): - def __init__(self, data, magic, max_size): - header = struct.unpack("<4sIIIBBBBBBBB8s512s415sB64s", data[:IMAGE_HEADER_SIZE]) - self.magic, self.hdrlen, self.expiry, self.codelen, self.vmajor, self.vminor, self.vpatch, self.vbuild, self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild, self.reserved1, self.hashes, self.reserved2, self.sigmask, self.sig = ( - header - ) - assert self.magic == magic - assert self.hdrlen == IMAGE_HEADER_SIZE - total_len = self.hdrlen + self.codelen - assert total_len % 512 == 0 - assert total_len >= 4 * 1024 - assert total_len <= max_size - assert self.reserved1 == 8 * b"\x00" - assert self.reserved2 == 415 * b"\x00" - self.code = data[self.hdrlen :] - assert len(self.code) == self.codelen - - def print(self): - if self.magic == b"TRZF": - print("Trezor Firmware Image") - total_len = self.vhdrlen + self.hdrlen + self.codelen - elif self.magic == b"TRZB": - print("Trezor Bootloader Image") - total_len = self.hdrlen + self.codelen - else: - print("Trezor Unknown Image") - print(" * magic :", self.magic.decode()) - print(" * hdrlen :", self.hdrlen) - print(" * expiry :", self.expiry) - print(" * codelen :", self.codelen) - print( - " * version : %d.%d.%d.%d" - % (self.vmajor, self.vminor, self.vpatch, self.vbuild) - ) - print( - " * fixver : %d.%d.%d.%d" - % (self.fix_vmajor, self.fix_vminor, self.fix_vpatch, self.fix_vbuild) - ) - print(" * hashes: %s" % ("OK" if self.check_hashes() else "INCORRECT")) - for i in range(16): - print( - " - %02d : %s" - % (i, binascii.hexlify(self.hashes[i * 32 : i * 32 + 32]).decode()) - ) - print(" * sigmask :", format_sigmask(self.sigmask)) - print(" * sig :", binascii.hexlify(self.sig).decode()) - print(" * total : %d bytes" % total_len) - print(" * fngprnt :", self.fingerprint()) - print() - - def compute_hashes(self): - if self.magic == b"TRZF": - hdrlen = self.vhdrlen + self.hdrlen - else: - hdrlen = self.hdrlen - hashes = b"" - for i in range(16): - if i == 0: - d = self.code[: IMAGE_CHUNK_SIZE - hdrlen] - else: - s = IMAGE_CHUNK_SIZE - hdrlen + (i - 1) * IMAGE_CHUNK_SIZE - d = self.code[s : s + IMAGE_CHUNK_SIZE] - if len(d) > 0: - h = pyblake2.blake2s(d).digest() - else: - h = 32 * b"\x00" - hashes += h - return hashes - - def check_hashes(self): - return self.hashes == self.compute_hashes() - - def update_hashes(self): - self.hashes = self.compute_hashes() - - def serialize_header(self, sig=True): - header = struct.pack( - "<4sIIIBBBBBBBB8s512s415s", - self.magic, - self.hdrlen, - self.expiry, - self.codelen, - self.vmajor, - self.vminor, - self.vpatch, - self.vbuild, - self.fix_vmajor, - self.fix_vminor, - self.fix_vpatch, - self.fix_vbuild, - self.reserved1, - self.hashes, - self.reserved2, - ) - if sig: - header += struct.pack(" 0 and self.vsig_m <= self.vsig_n - assert self.vsig_n > 0 and self.vsig_n <= 8 - p = 32 - self.vpub = [] - for _ in range(self.vsig_n): - self.vpub.append(data[p : p + 32]) - p += 32 - self.vstr_len = data[p] - p += 1 - self.vstr = data[p : p + self.vstr_len] - p += self.vstr_len - vstr_pad = -p & 3 - p += vstr_pad - self.vimg_len = len(data) - IMAGE_SIG_SIZE - p - self.vimg = data[p : p + self.vimg_len] - p += self.vimg_len - self.sigmask = data[p] - p += 1 - self.sig = data[p : p + 64] - assert ( - len(data) - == 4 - + 4 - + 4 - + 1 - + 1 - + 1 - + 1 - + 1 - + 15 - + 32 * len(self.vpub) - + 1 - + self.vstr_len - + vstr_pad - + self.vimg_len - + IMAGE_SIG_SIZE - ) - assert len(data) % 512 == 0 - - def print(self): - print("Trezor Vendor Header") - print(" * magic :", self.magic.decode()) - print(" * hdrlen :", self.hdrlen) - print(" * expiry :", self.expiry) - print(" * version : %d.%d" % (self.vmajor, self.vminor)) - print(" * scheme : %d out of %d" % (self.vsig_m, self.vsig_n)) - print(" * trust :", format_vtrust(self.vtrust)) - for i in range(self.vsig_n): - print(" * vpub #%d :" % (i + 1), binascii.hexlify(self.vpub[i]).decode()) - print(" * vstr :", self.vstr.decode()) - print(" * vhash :", binascii.hexlify(self.vhash()).decode()) - print(" * vimg : (%d bytes)" % len(self.vimg)) - print(" * sigmask :", format_sigmask(self.sigmask)) - print(" * sig :", binascii.hexlify(self.sig).decode()) - print(" * fngprnt :", self.fingerprint()) - print() - - def serialize_header(self, sig=True): - header = struct.pack( - "<4sIIBBBBH", - self.magic, - self.hdrlen, - self.expiry, - self.vmajor, - self.vminor, - self.vsig_m, - self.vsig_n, - self.vtrust, - ) - header += 14 * b"\x00" - for i in range(self.vsig_n): - header += self.vpub[i] - header += struct.pack(" 0: - hdr = ( - subdata[: IMAGE_HEADER_SIZE - IMAGE_SIG_SIZE] - + IMAGE_SIG_SIZE * b"\x00" - ) - digest = pyblake2.blake2s(hdr).digest() - try: - cosi.verify( - firmware.sig, - digest, - vheader.vsig_m, - vheader.vpub, - firmware.sigmask, - ) - print("Firmware signature OK") - except ValueError: - print("Firmware signature INCORRECT") - else: - print("No firmware signature") - return firmware - if magic == b"TRZF": - return FirmwareImage(data, 0) - raise Exception("Unknown file format") - - -def main(): - if len(sys.argv) < 2: - print("Usage: binctl file.bin [-s sigmask signature] [-h]") - return 1 - fn = sys.argv[1] - sign = len(sys.argv) > 2 and sys.argv[2] == "-s" - rehash = len(sys.argv) == 3 and sys.argv[2] == "-h" - b = binopen(fn) - if sign: - sigmask = 0 - if ":" in sys.argv[3]: - for idx in sys.argv[3].split(":"): - sigmask |= 1 << (int(idx) - 1) - else: - sigmask = 1 << (int(sys.argv[3]) - 1) - signature = binascii.unhexlify(sys.argv[4]) - b.sign(sigmask, signature) - b.write(fn) - if rehash: - b.update_hashes() - b.write(fn) - b.print() - - -if __name__ == "__main__": - main() diff --git a/core/tools/keyctl b/core/tools/keyctl deleted file mode 100755 index d1c9aaf0c..000000000 --- a/core/tools/keyctl +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env python3 -import binascii -import struct -import click -import pyblake2 -from trezorlib import cosi - -indexmap = {"bootloader": 0, "vendorheader": 1, "firmware": 2} - - -def header_digest(index, filename): - data = open(filename, "rb").read() - z = bytes(65 * [0x00]) - if index == "bootloader": - header = data[:0x03BF] + z - elif index == "vendorheader": - header = data[:-65] + z - elif index == "firmware": - vhdrlen = struct.unpack("