mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-27 00:28:10 +00:00
build: refactor binctl and firmware/loader image stuff
This commit is contained in:
parent
e37619899e
commit
435e96e1b3
@ -56,6 +56,7 @@ OBJ_HAL += $(addprefix $(BUILD_MP)/,\
|
||||
|
||||
# OBJ micropython/
|
||||
OBJ_FW += $(addprefix $(BUILD_FW)/, \
|
||||
loader/crypto.o \
|
||||
loader/header.o \
|
||||
loader/main.o \
|
||||
extmod/modtrezorui/display.o \
|
||||
|
@ -48,8 +48,8 @@ Total length of loader header is always 512 bytes.
|
||||
| 0x0012 | 1 | vpatch | version (patch) |
|
||||
| 0x0013 | 1 | vbuild | version (build) |
|
||||
| 0x0014 | 427 | reserved | not used yet (zeroed) |
|
||||
| 0x01BF | 1 | sigidx | SatoshiLabs signature indexes (bitmap) |
|
||||
| 0x01C0 | 64 | sig | SatoshiLabs signature |
|
||||
| 0x01BF | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
|
||||
| 0x01C0 | 64 | sig | SatoshiLabs aggregated signature |
|
||||
|
||||
## Firmware Format
|
||||
|
||||
@ -79,8 +79,8 @@ Total length of vendor header is 84 + 32 * (number of pubkeys) + (length of vend
|
||||
| ? | ? | vstr | vendor string |
|
||||
| ? | 2 | vimg_len | vendor image length |
|
||||
| ? | ? | vimg | vendor image (in [TOIf format](toif.md)) |
|
||||
| ? | 1 | sigidx | SatoshiLabs signature indexes (bitmap) |
|
||||
| ? | 64 | sig | SatoshiLabs signature |
|
||||
| ? | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
|
||||
| ? | 64 | sig | SatoshiLabs aggregated signature |
|
||||
|
||||
### Firmware Header
|
||||
|
||||
@ -97,8 +97,8 @@ Total length of firmware header is always 512 bytes.
|
||||
| 0x0012 | 1 | vpatch | version (patch) |
|
||||
| 0x0013 | 1 | vbuild | version (build) |
|
||||
| 0x0014 | 427 | reserved | not used yet (zeroed) |
|
||||
| 0x01BF | 1 | sigidx | vendor signature indexes (bitmap) |
|
||||
| 0x01C0 | 64 | sig | vendor signature |
|
||||
| 0x01BF | 1 | sigmask | vendor signature indexes (bitmap) |
|
||||
| 0x01C0 | 64 | sig | vendor aggregated signature |
|
||||
|
||||
## Various ideas
|
||||
|
||||
|
@ -3,9 +3,10 @@
|
||||
#include "blake2s.h"
|
||||
#include "ed25519-donna/ed25519.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8_t *sig)
|
||||
bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigmask, uint8_t *sig)
|
||||
{
|
||||
uint32_t magic;
|
||||
memcpy(&magic, data, 4);
|
||||
@ -13,7 +14,7 @@ bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8
|
||||
|
||||
uint32_t hdrlen;
|
||||
memcpy(&hdrlen, data + 4, 4);
|
||||
if (hdrlen != 256) return false;
|
||||
if (hdrlen != HEADER_SIZE) return false;
|
||||
|
||||
uint32_t expiry;
|
||||
memcpy(&expiry, data + 8, 4);
|
||||
@ -21,7 +22,6 @@ bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8
|
||||
|
||||
uint32_t clen;
|
||||
memcpy(&clen, data + 12, 4);
|
||||
// stage 2 (+header) must fit into sectors 4...11 - see docs/memory.md for more info
|
||||
if (clen + hdrlen < 4 * 1024) return false;
|
||||
if (clen + hdrlen > 64 * 1024 + 7 * 128 * 1024) return false;
|
||||
if ((clen + hdrlen) % 512 != 0) return false;
|
||||
@ -33,14 +33,14 @@ bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8
|
||||
uint32_t version;
|
||||
memcpy(&version, data + 16, 4);
|
||||
|
||||
// uint8_t reserved[171];
|
||||
// uint8_t reserved[427];
|
||||
|
||||
if (sigidx) {
|
||||
memcpy(sigidx, data + 0x00BF, 1);
|
||||
if (sigmask) {
|
||||
memcpy(sigmask, data + 0x01BF, 1);
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
memcpy(sig, data + 0x00C0, 64);
|
||||
memcpy(sig, data + 0x01C0, 64);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -79,9 +79,9 @@ const uint8_t *get_pubkey(uint8_t index)
|
||||
bool check_signature(const uint8_t *start)
|
||||
{
|
||||
uint32_t codelen;
|
||||
uint8_t sigidx;
|
||||
uint8_t sigmask;
|
||||
uint8_t sig[64];
|
||||
if (!parse_header(start, &codelen, &sigidx, sig)) {
|
||||
if (!parse_header(start, &codelen, &sigmask, sig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -95,7 +95,11 @@ bool check_signature(const uint8_t *start)
|
||||
blake2s_Update(&ctx, start + 256, codelen);
|
||||
blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH);
|
||||
|
||||
const uint8_t *pub = get_pubkey(sigidx);
|
||||
const uint8_t *pub = get_pubkey(sigmask);
|
||||
|
||||
// TODO: remove debug skip of unsigned
|
||||
if (!pub) return true;
|
||||
// end
|
||||
|
||||
return pub && (0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, *(const ed25519_public_key *)pub, *(const ed25519_signature *)sig));
|
||||
}
|
||||
|
@ -112,6 +112,27 @@ bool copy_sdcard(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
void check_and_jump(void)
|
||||
{
|
||||
BOOTLOADER_PRINTLN("checking loader");
|
||||
if (parse_header((const uint8_t *)LOADER_START, NULL, NULL, NULL)) {
|
||||
BOOTLOADER_PRINTLN("valid loader header");
|
||||
if (check_signature((const uint8_t *)LOADER_START)) {
|
||||
BOOTLOADER_PRINTLN("valid loader signature");
|
||||
// TODO: remove debug wait
|
||||
BOOTLOADER_PRINTLN("waiting 1 second");
|
||||
HAL_Delay(1000);
|
||||
// end
|
||||
BOOTLOADER_PRINTLN("JUMP!");
|
||||
jump_to(LOADER_START + HEADER_SIZE);
|
||||
} else {
|
||||
BOOTLOADER_PRINTLN("invalid loader signature");
|
||||
}
|
||||
} else {
|
||||
BOOTLOADER_PRINTLN("invalid loader header");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SCB->VTOR = BOOTLOADER_START;
|
||||
@ -127,32 +148,13 @@ int main(void)
|
||||
BOOTLOADER_PRINTLN("=================");
|
||||
BOOTLOADER_PRINTLN("starting bootloader");
|
||||
|
||||
// TODO: remove debug
|
||||
BOOTLOADER_PRINTLN("waiting 1 second");
|
||||
HAL_Delay(1000);
|
||||
BOOTLOADER_PRINTLN("jumping to loader");
|
||||
jump_to(LOADER_START + HEADER_SIZE);
|
||||
// end
|
||||
|
||||
if (check_sdcard()) {
|
||||
if (!copy_sdcard()) {
|
||||
__fatal_error("halt");
|
||||
}
|
||||
}
|
||||
|
||||
BOOTLOADER_PRINTLN("checking loader");
|
||||
if (parse_header((const uint8_t *)LOADER_START, NULL, NULL, NULL)) {
|
||||
BOOTLOADER_PRINTLN("valid loader header");
|
||||
if (check_signature((const uint8_t *)LOADER_START)) {
|
||||
BOOTLOADER_PRINTLN("valid loader signature");
|
||||
BOOTLOADER_PRINTLN("JUMP!");
|
||||
jump_to(LOADER_START + HEADER_SIZE);
|
||||
} else {
|
||||
BOOTLOADER_PRINTLN("invalid loader signature");
|
||||
}
|
||||
} else {
|
||||
BOOTLOADER_PRINTLN("invalid loader header");
|
||||
}
|
||||
check_and_jump();
|
||||
|
||||
__fatal_error("halt");
|
||||
|
||||
|
@ -1,20 +1,20 @@
|
||||
#include "version.h"
|
||||
|
||||
.section .header,"a",%progbits
|
||||
.section .header,"a",%progbits
|
||||
|
||||
.type g_header, %object
|
||||
.size g_header, .-g_header
|
||||
.type g_header, %object
|
||||
.size g_header, .-g_header
|
||||
|
||||
g_header:
|
||||
.byte 'T','R','Z','F'
|
||||
.word g_header_end - g_header
|
||||
.word 0 /* valid until */
|
||||
.word _codelen
|
||||
.byte VERSION_MAJOR
|
||||
.byte VERSION_MINOR
|
||||
.byte VERSION_PATCH
|
||||
.byte VERSION_BUILD
|
||||
. = . + 427 /* reserved */
|
||||
.byte 0 /* sigindex */
|
||||
. = . + 64 /* signatures */
|
||||
.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 VERSION_BUILD // vbuild
|
||||
. = . + 427 // reserved
|
||||
.byte 0 // sigmask
|
||||
. = . + 64 // sig
|
||||
g_header_end:
|
||||
|
@ -34,7 +34,7 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
. = ALIGN(512);
|
||||
_etext = .; /* define a global symbol at end of code */
|
||||
} >FLASH
|
||||
|
||||
@ -51,7 +51,7 @@ SECTIONS
|
||||
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
|
||||
*(.data*) /* .data* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
. = ALIGN(512);
|
||||
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
|
||||
} >RAM AT> FLASH
|
||||
|
||||
@ -87,7 +87,7 @@ SECTIONS
|
||||
}
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data);
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data) - 512;
|
||||
_ram_start = ORIGIN(RAM);
|
||||
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_heap_start = _ebss; /* heap starts just after statically allocated memory */
|
||||
|
105
micropython/loader/crypto.c
Normal file
105
micropython/loader/crypto.c
Normal file
@ -0,0 +1,105 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "blake2s.h"
|
||||
#include "ed25519-donna/ed25519.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigmask, uint8_t *sig)
|
||||
{
|
||||
uint32_t magic;
|
||||
memcpy(&magic, data, 4);
|
||||
if (magic != 0x465A5254) return false; // TRZF
|
||||
|
||||
uint32_t hdrlen;
|
||||
memcpy(&hdrlen, data + 4, 4);
|
||||
if (hdrlen != HEADER_SIZE) return false;
|
||||
|
||||
uint32_t expiry;
|
||||
memcpy(&expiry, data + 8, 4);
|
||||
if (expiry != 0) return false;
|
||||
|
||||
uint32_t clen;
|
||||
memcpy(&clen, data + 12, 4);
|
||||
if (clen + hdrlen < 4 * 1024) return false;
|
||||
if (clen + hdrlen > 7 * 128 * 1024) return false;
|
||||
if ((clen + hdrlen) % 512 != 0) return false;
|
||||
|
||||
if (codelen) {
|
||||
*codelen = clen;
|
||||
}
|
||||
|
||||
uint32_t version;
|
||||
memcpy(&version, data + 16, 4);
|
||||
|
||||
// uint8_t reserved[427];
|
||||
|
||||
if (sigmask) {
|
||||
memcpy(sigmask, data + 0x01BF, 1);
|
||||
}
|
||||
|
||||
if (sig) {
|
||||
memcpy(sig, data + 0x01C0, 64);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define KEYMASK(A, B, C) ((1 << (A - 1)) | (1 << (B - 1)) | (1 << (C - 1)))
|
||||
|
||||
const uint8_t *get_pubkey(uint8_t index)
|
||||
{
|
||||
switch (index) {
|
||||
case KEYMASK(1, 2, 3):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(1, 2, 4):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(1, 2, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(1, 3, 4):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(1, 3, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(1, 4, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(2, 3, 4):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(2, 3, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(2, 4, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
case KEYMASK(3, 4, 5):
|
||||
return (const uint8_t *)"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool check_signature(const uint8_t *start)
|
||||
{
|
||||
uint32_t codelen;
|
||||
uint8_t sigmask;
|
||||
uint8_t sig[64];
|
||||
if (!parse_header(start, &codelen, &sigmask, sig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t hash[BLAKE2S_DIGEST_LENGTH];
|
||||
BLAKE2S_CTX ctx;
|
||||
blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH);
|
||||
blake2s_Update(&ctx, start, 256 - 65);
|
||||
for (int i = 0; i < 65; i++) {
|
||||
blake2s_Update(&ctx, (const uint8_t *)"\x00", 1);
|
||||
}
|
||||
blake2s_Update(&ctx, start + 256, codelen);
|
||||
blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH);
|
||||
|
||||
const uint8_t *pub = get_pubkey(sigmask);
|
||||
|
||||
// TODO: remove debug skip of unsigned
|
||||
if (!pub) return true;
|
||||
// end
|
||||
|
||||
return pub && (0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, *(const ed25519_public_key *)pub, *(const ed25519_signature *)sig));
|
||||
}
|
11
micropython/loader/crypto.h
Normal file
11
micropython/loader/crypto.h
Normal file
@ -0,0 +1,11 @@
|
||||
#ifndef __LOADER_CRYPTO_H__
|
||||
#define __LOADER_CRYPTO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8_t *sig);
|
||||
|
||||
bool check_signature(const uint8_t *start);
|
||||
|
||||
#endif
|
@ -1,20 +1,20 @@
|
||||
#include "version.h"
|
||||
|
||||
.section .header,"a",%progbits
|
||||
.section .header,"a",%progbits
|
||||
|
||||
.type g_header, %object
|
||||
.size g_header, .-g_header
|
||||
.type g_header, %object
|
||||
.size g_header, .-g_header
|
||||
|
||||
g_header:
|
||||
.byte 'T','R','Z','L'
|
||||
.word g_header_end - g_header
|
||||
.word 0 /* valid until */
|
||||
.word _codelen
|
||||
.byte VERSION_MAJOR
|
||||
.byte VERSION_MINOR
|
||||
.byte VERSION_PATCH
|
||||
.byte VERSION_BUILD
|
||||
. = . + 427 /* reserved */
|
||||
.byte 0 /* sigindex */
|
||||
. = . + 64 /* signatures */
|
||||
.byte 'T','R','Z','L' // 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 VERSION_BUILD // vbuild
|
||||
. = . + 427 // reserved
|
||||
.byte 0 // sigmask
|
||||
. = . + 64 // sig
|
||||
g_header_end:
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "display.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#define LOADER_FGCOLOR 0xFFFF
|
||||
#define LOADER_BGCOLOR 0x0000
|
||||
@ -13,6 +14,27 @@ void pendsv_isr_handler(void) {
|
||||
__fatal_error("pendsv");
|
||||
}
|
||||
|
||||
void check_and_jump(void)
|
||||
{
|
||||
LOADER_PRINTLN("checking firmware");
|
||||
if (parse_header((const uint8_t *)FIRMWARE_START, NULL, NULL, NULL)) {
|
||||
LOADER_PRINTLN("valid firmware header");
|
||||
if (check_signature((const uint8_t *)FIRMWARE_START)) {
|
||||
LOADER_PRINTLN("valid firmware signature");
|
||||
LOADER_PRINTLN("JUMP!");
|
||||
// TODO: remove debug wait
|
||||
LOADER_PRINTLN("waiting 1 second");
|
||||
HAL_Delay(1000);
|
||||
// end
|
||||
jump_to(FIRMWARE_START + HEADER_SIZE);
|
||||
} else {
|
||||
LOADER_PRINTLN("invalid firmware signature");
|
||||
}
|
||||
} else {
|
||||
LOADER_PRINTLN("invalid firmware header");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SCB->VTOR = LOADER_START + HEADER_SIZE;
|
||||
@ -22,12 +44,13 @@ int main(void)
|
||||
display_clear();
|
||||
display_backlight(255);
|
||||
|
||||
LOADER_PRINTLN("reached loader");
|
||||
LOADER_PRINTLN("waiting 1 second");
|
||||
HAL_Delay(1000);
|
||||
LOADER_PRINTLN("jumping to firmware");
|
||||
LOADER_PRINTLN("TREZOR Loader");
|
||||
LOADER_PRINTLN("=============");
|
||||
LOADER_PRINTLN("starting loader");
|
||||
|
||||
jump_to(FIRMWARE_START + HEADER_SIZE);
|
||||
check_and_jump();
|
||||
|
||||
__fatal_error("halt");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -29,12 +29,12 @@ SECTIONS
|
||||
.flash :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
KEEP(*(.header))
|
||||
KEEP(*(.header)) /* Firmware Header */
|
||||
KEEP(*(.isr_vector)) /* Startup code */
|
||||
. = ALIGN(4);
|
||||
*(.text*) /* .text* sections (code) */
|
||||
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
|
||||
. = ALIGN(4);
|
||||
. = ALIGN(512);
|
||||
_etext = .; /* define a global symbol at end of code */
|
||||
} >FLASH
|
||||
|
||||
@ -51,9 +51,8 @@ SECTIONS
|
||||
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
|
||||
*(.data*) /* .data* sections */
|
||||
|
||||
. = ALIGN(4);
|
||||
. = ALIGN(512);
|
||||
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
|
||||
_datalen = . - _sdata;
|
||||
} >RAM AT> FLASH
|
||||
|
||||
/* Uninitialized data section */
|
||||
@ -88,7 +87,7 @@ SECTIONS
|
||||
}
|
||||
|
||||
/* RAM extents for the garbage collector */
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data);
|
||||
_codelen = SIZEOF(.flash) + SIZEOF(.data) - 512;
|
||||
_ram_start = ORIGIN(RAM);
|
||||
_ram_end = ORIGIN(RAM) + LENGTH(RAM);
|
||||
_heap_start = _ebss; /* heap starts just after statically allocated memory */
|
||||
|
122
tools/binctl
122
tools/binctl
@ -6,22 +6,22 @@ import ed25519
|
||||
import pyblake2
|
||||
|
||||
|
||||
# loader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md
|
||||
|
||||
|
||||
def get_sig(data):
|
||||
print('Enter privkey: ', end='')
|
||||
seckey = binascii.unhexlify(input())
|
||||
signkey = ed25519.SigningKey(seckey)
|
||||
digest = pyblake2.blake2s(data).digest()
|
||||
sigidx = 0x01 # (1 _ _ _ _)
|
||||
sigmask = 0x01 # (1 _ _ _ _)
|
||||
sig = signkey.sign(digest)
|
||||
return sigidx, sig
|
||||
return sigmask, sig
|
||||
|
||||
|
||||
class LoaderImage:
|
||||
# loader/firmware headers specification: https://github.com/trezor/trezor-core/blob/master/docs/bootloader.md
|
||||
|
||||
def __init__(self, data):
|
||||
|
||||
class BinImage:
|
||||
|
||||
def __init__(self, data, magic, max_size):
|
||||
header = struct.unpack('<4sIIIBBBB427sB64s', data[:512])
|
||||
self.magic, \
|
||||
self.hdrlen, \
|
||||
@ -32,25 +32,31 @@ class LoaderImage:
|
||||
self.vpatch, \
|
||||
self.vbuild, \
|
||||
self.reserved, \
|
||||
self.sigidx, \
|
||||
self.sigmask, \
|
||||
self.sig = header
|
||||
assert self.magic == b'TRZL'
|
||||
assert self.magic == magic
|
||||
assert self.hdrlen == 512
|
||||
assert self.codelen + self.hdrlen >= 4 * 1024
|
||||
assert self.codelen + self.hdrlen <= 64 * 1024 + 7 * 128 * 1024
|
||||
assert (self.codelen + self.hdrlen) % 512 == 0
|
||||
total_len = self.hdrlen + self.codelen
|
||||
assert total_len % 512 == 0
|
||||
assert total_len >= 4 * 1024
|
||||
assert total_len <= max_size
|
||||
assert self.reserved == 427 * b'\x00'
|
||||
self.code = data[self.hdrlen:]
|
||||
assert len(self.code) == self.codelen
|
||||
|
||||
def print(self):
|
||||
print('TREZOR Loader Image')
|
||||
if self.magic == b'TRZF':
|
||||
print('TREZOR Firmware Image')
|
||||
elif self.magic == b'TRZL':
|
||||
print('TREZOR Loader Image')
|
||||
else:
|
||||
print('TREZOR Unknown Image')
|
||||
print(' * magic :', self.magic.decode('ascii'))
|
||||
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(' * sigidx :', self.sigidx)
|
||||
print(' * sigmask :', self.sigmask)
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode('ascii'))
|
||||
|
||||
def serialize_header(self, sig=True):
|
||||
@ -59,7 +65,7 @@ class LoaderImage:
|
||||
self.vmajor, self.vminor, self.vpatch, self.vbuild, \
|
||||
self.reserved)
|
||||
if sig:
|
||||
header += struct.pack('<B64s', self.sigidx, self.sig)
|
||||
header += struct.pack('<B64s', self.sigmask, self.sig)
|
||||
else:
|
||||
header += 65 * b'\x00'
|
||||
assert len(header) == self.hdrlen
|
||||
@ -69,7 +75,7 @@ class LoaderImage:
|
||||
header = self.serialize_header(sig=False)
|
||||
data = header + self.code
|
||||
assert len(data) == self.hdrlen + self.codelen
|
||||
self.sigidx, self.sig = get_sig(data)
|
||||
self.sigmask, self.sig = get_sig(data)
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
@ -77,6 +83,19 @@ class LoaderImage:
|
||||
f.write(self.code)
|
||||
|
||||
|
||||
class FirmwareImage(BinImage):
|
||||
|
||||
def __init__(self, data):
|
||||
super().__init__(data, magic=b'TRZF', max_size=7*128*1024)
|
||||
|
||||
|
||||
class LoaderImage(BinImage):
|
||||
|
||||
def __init__(self, data):
|
||||
super().__init__(data, magic=b'TRZL', max_size=64*1024 + 7*128*1024)
|
||||
|
||||
|
||||
"""
|
||||
class VendorHeader:
|
||||
|
||||
def __init__(self, data):
|
||||
@ -104,7 +123,7 @@ class VendorHeader:
|
||||
p += 2
|
||||
self.vimg = data[p:p + self.vimg_len]
|
||||
p += self.vimg_len
|
||||
self.sigidx = data[p]
|
||||
self.sigmask = data[p]
|
||||
p += 1
|
||||
self.sig = data[p:p+64]
|
||||
assert len(data) == 4 + 4 + 4 + 1 + 1 + 1 + 1 + \
|
||||
@ -124,8 +143,8 @@ class VendorHeader:
|
||||
print(' * vpub #%d :' % (i + 1), binascii.hexlify(self.vpub[i]).decode('ascii'))
|
||||
print(' * vstr :', self.vstr.decode('ascii'))
|
||||
print(' * vimg : (%d bytes)', len(self.vimg))
|
||||
print(' * sigidx :', self.sigidx)
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode('ascii'))
|
||||
print(' * sigmask :', self.sigmask)
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode('ascii'))
|
||||
|
||||
def serialize_header(self, sig=True):
|
||||
header = struct.pack('<4sIIBBBB', \
|
||||
@ -137,7 +156,7 @@ class VendorHeader:
|
||||
header += struct.pack('<B', self.vstr_len) + self.vstr
|
||||
header += struct.pack('<H', self.vimg_len) + self.vimg
|
||||
if sig:
|
||||
header += struct.pack('<B64s', self.sigidx, self.sig)
|
||||
header += struct.pack('<B64s', self.sigmask, self.sig)
|
||||
else:
|
||||
header += 65 * b'\x00'
|
||||
assert len(header) == self.hdrlen
|
||||
@ -145,67 +164,12 @@ class VendorHeader:
|
||||
|
||||
def sign(self):
|
||||
header = self.serialize_header(sig=False)
|
||||
self.sigidx, self.sig = get_sig(header)
|
||||
self.sigmask, self.sig = get_sig(header)
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(self.serialize_header())
|
||||
|
||||
|
||||
class FirmwareImage:
|
||||
|
||||
def __init__(self, data):
|
||||
header = struct.unpack('<4sIIIBBBB427sB64s', data[:512])
|
||||
self.magic, \
|
||||
self.hdrlen, \
|
||||
self.expiry, \
|
||||
self.codelen, \
|
||||
self.vmajor, \
|
||||
self.vminor, \
|
||||
self.vpatch, \
|
||||
self.vbuild, \
|
||||
self.reserved, \
|
||||
self.sigidx, \
|
||||
self.sig = header
|
||||
assert self.magic == b'TRZF'
|
||||
assert self.hdrlen == 512
|
||||
assert self.codelen % 4 == 0
|
||||
assert self.reserved == 427 * b'\x00'
|
||||
self.code = data[self.hdrlen:]
|
||||
assert len(self.code) == self.codelen
|
||||
|
||||
def print(self):
|
||||
print('TREZOR Firmware Image')
|
||||
print(' * magic :', self.magic.decode('ascii'))
|
||||
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(' * sigidx :', self.sigidx)
|
||||
print(' * sig :', binascii.hexlify(self.sig).decode('ascii'))
|
||||
|
||||
def serialize_header(self, sig=True):
|
||||
header = struct.pack('<4sIIIBBBB427s', \
|
||||
self.magic, self.hdrlen, self.expiry, self.codelen, \
|
||||
self.vmajor, self.vminor, self.vpatch, self.vbuild, \
|
||||
self.reserved)
|
||||
if sig:
|
||||
header += struct.pack('<B64s', self.sigidx, self.sig)
|
||||
else:
|
||||
header += 65 * b'\x00'
|
||||
assert len(header) == self.hdrlen
|
||||
return header
|
||||
|
||||
def sign(self):
|
||||
header = self.serialize_header(sig=False)
|
||||
data = header + self.code
|
||||
assert len(data) == self.hdrlen + self.codelen
|
||||
self.sigidx, self.sig = get_sig(data)
|
||||
|
||||
def write(self, filename):
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(self.serialize_header())
|
||||
f.write(self.code)
|
||||
"""
|
||||
|
||||
|
||||
def binopen(filename):
|
||||
@ -216,10 +180,10 @@ def binopen(filename):
|
||||
magic = data[:4]
|
||||
if magic == b'TRZL':
|
||||
return LoaderImage(data)
|
||||
if magic == b'TRZV':
|
||||
return VendorHeader(data)
|
||||
if magic == b'TRZF':
|
||||
return FirmwareImage(data)
|
||||
# if magic == b'TRZV':
|
||||
# return VendorHeader(data)
|
||||
raise Exception('Unknown file format')
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user