4.9 KiB
TREZOR Core Bootloader
TREZOR initialization in split into two stages. See Memory Layout for info about in which sectors each stage is stored.
First stage (boardloader) is stored in write-protected area, which means it is non-upgradable. Only second stage (bootloader) update is allowed.
First Stage - Boardloader
First stage checks the integrity and signatures of the second stage and runs it if everything is OK.
If first stage boardloader finds a valid second stage bootloader image on the SD card (in raw format, no filesystem), it will replace the internal second stage, allowing a second stage update via SD card.
Second Stage - Bootloader
Second stage checks the integrity and signatures of the firmware and runs it if everything is OK.
If second stage bootloader detects a pressed finger on the display or there is no firmware loaded in the device, it will start in a firmware update mode, allowing a firmware update via USB.
Common notes
- Hash function used for computing data digest for signatures is BLAKE2s.
- Signature system is Ed25519 (allows combining signatures by multiple keys into one).
- All multibyte integer values are little endian.
- There is a tool called binctl which checks validity of the bootloader/firmware images including their headers.
Bootloader Format
TREZOR Core (second stage) bootloader consists of 2 parts:
- bootloader header
- bootloader code
Bootloader Header
Total length of bootloader header is always 512 bytes.
offset | length | name | description |
---|---|---|---|
0x0000 | 4 | magic | firmware magic TRZB |
0x0004 | 4 | hdrlen | length of the bootloader header |
0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
0x000C | 4 | codelen | length of the bootloader code (without the header) |
0x0010 | 1 | vmajor | version (major) |
0x0011 | 1 | vminor | version (minor) |
0x0012 | 1 | vpatch | version (patch) |
0x0013 | 1 | vbuild | version (build) |
0x0014 | 427 | reserved | not used yet (zeroed) |
0x01BF | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
0x01C0 | 64 | sig | SatoshiLabs aggregated signature |
Firmware Format
TREZOR Core firmware consists of 3 parts:
- vendor header
- firmware header
- firmware code
Vendor Header
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 (multiple of 512) |
0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
0x000C | 1 | vmajor | version (major) |
0x000D | 1 | vminor | version (minor) |
0x000E | 1 | vsig_m | number of signatures needed to run the firmware from this vendor |
0x000F | 1 | vsig_n | number of different pubkeys vendor provides for signing |
0x0010 | 32 | vpub1 | vendor pubkey 1 |
... | ... | ... | ... |
? | 32 | vpubn | vendor pubkey n |
? | 1 | vstr_len | vendor string length |
? | ? | vstr | vendor string |
? | ? | vstrpad | padding to a multiple of 4 bytes |
? | ? | vimg | vendor image (in TOIf format) |
? | ? | reserved | padding to an address that is -65 modulo 512 |
? | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
? | 64 | sig | SatoshiLabs aggregated signature |
Firmware Header
Total length of firmware header is always 512 bytes.
offset | length | name | description |
---|---|---|---|
0x0000 | 4 | magic | firmware magic TRZF |
0x0004 | 4 | hdrlen | length of the firmware header |
0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
0x000C | 4 | codelen | length of the firmware code (without the header) |
0x0010 | 1 | vmajor | version (major) |
0x0011 | 1 | vminor | version (minor) |
0x0012 | 1 | vpatch | version (patch) |
0x0013 | 1 | vbuild | version (build) |
0x0014 | 427 | reserved | not used yet (zeroed) |
0x01BF | 1 | sigmask | vendor signature indexes (bitmap) |
0x01C0 | 64 | sig | vendor aggregated signature |
Various ideas
- Bootloader should be able to read vendor + firmware header and send info about FW to client in features message.
- Bootloader should not try to run firmware if there is not any.
- Storage wiping rule: Don't erase storage when old FW and new FW are signed using the same key set. Otherwise erase.
- Bootloader should send error to client when firmware update fails and allow client to try one more time. This prevents storage area erasure by accident.