1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-11-12 18:49:07 +00:00
trezor-firmware/docs/bootloader.md

161 lines
7.0 KiB
Markdown
Raw Normal View History

2017-03-20 14:49:11 +00:00
# TREZOR Core Bootloader
2016-04-25 18:43:48 +00:00
TREZOR initialization is split into two stages.
See [Memory Layout](memory.md) for info about in which sectors each stage is stored.
2016-04-25 20:02:12 +00:00
2017-04-10 17:11:44 +00:00
First stage (boardloader) is stored in write-protected area, which means it is non-upgradable.
2017-04-10 17:24:21 +00:00
Only second stage (bootloader) update is allowed.
2016-04-25 18:43:48 +00:00
2017-04-10 17:11:44 +00:00
## 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.
The boardloader is special in that it is the device's write protected embedded code.
The primary purpose for write protecting the boardloader is to make it the
immutable portion that can defend against code-based attacks (e.g.- BadUSB)
and bugs that would reprogram any/all of the embedded code.
It assures that only verified signed embedded code is run on the device
(and that the intended code is run, and not skipped).
The write protection also provides some defense against attacks where the
attacker has physical control of the device.
The boardloader must include an update mechanism for later stage code because
if it did not, then a corruption/erasure of later stage flash memory would
leave the device unusable (only the boardloader could run and it would not
pass execution to a later stage that fails signature validation).
Developer note:
A microSD card can be prepared with the following. Note that the bootloader is allocated 128 KiB.
WARNING: Ensure that you want to overwrite and destroy the contents of `/dev/mmcblk0` before running these commands.
Likewise, `/dev/mmcblk0` may be replaced by your own specific destination.
1. `sudo dd if=/dev/zero of=/dev/mmcblk0 bs=512 count=256 conv=fsync`
1. `sudo dd if=build/bootloader/bootloader.bin of=/dev/mmcblk0 bs=512 conv=fsync`
2017-04-10 17:24:21 +00:00
## 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.
2017-02-08 14:42:52 +00:00
2017-03-20 14:49:11 +00:00
## Common notes
2017-02-08 14:42:52 +00:00
* Hash function used for computing data digest for signatures is BLAKE2s.
* Signature system is Ed25519 (allows combining signatures by multiple keys
into one).
2017-02-08 14:42:52 +00:00
* All multibyte integer values are little endian.
* There is a tool called [binctl](../tools/binctl) which checks validity
of the bootloader/firmware images including their headers.
2017-02-08 14:42:52 +00:00
2017-04-10 17:24:21 +00:00
## Bootloader Format
2017-02-08 14:42:52 +00:00
2017-04-10 17:24:21 +00:00
TREZOR Core (second stage) bootloader consists of 2 parts:
2017-02-08 14:42:52 +00:00
2017-04-10 17:24:21 +00:00
1. bootloader header
2. bootloader code
2017-02-08 14:42:52 +00:00
2017-04-10 17:24:21 +00:00
### Bootloader Header
2017-02-08 14:42:52 +00:00
Total length of bootloader header is always 1024 bytes.
2017-02-08 14:42:52 +00:00
| offset | length | name | description |
|-------:|-------:|------|-------------|
2017-04-10 17:24:21 +00:00
| 0x0000 | 4 | magic | firmware magic `TRZB` |
| 0x0004 | 4 | hdrlen | length of the bootloader header |
2017-02-08 14:42:52 +00:00
| 0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
2017-04-10 17:24:21 +00:00
| 0x000C | 4 | codelen | length of the bootloader code (without the header) |
2017-02-08 14:42:52 +00:00
| 0x0010 | 1 | vmajor | version (major) |
| 0x0011 | 1 | vminor | version (minor) |
| 0x0012 | 1 | vpatch | version (patch) |
| 0x0013 | 1 | vbuild | version (build) |
| 0x0014 | 12 | reserved | not used yet (zeroed) |
| 0x0020 | 32 | hash1 | hash of the first code chunk (128 - 1 KiB), this excludes the header |
| 0x0040 | 32 | hash2 | hash of the second code chunk (128 KiB), zeroed if unused |
| ... | ... | ... | ... |
| 0x0200 | 32 | hash16 | hash of the last possible code chunk (128 KiB), zeroed if unused |
| 0x0220 | 415 | reserved | not used yet (zeroed) |
| 0x03BF | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
| 0x03C0 | 64 | sig | SatoshiLabs aggregated signature of the bootloader header |
2017-02-08 14:42:52 +00:00
2017-03-20 14:49:11 +00:00
## Firmware Format
2017-02-08 14:42:52 +00:00
TREZOR Core firmware consists of 3 parts:
2016-04-25 18:43:48 +00:00
1. vendor header
2. firmware header
3. firmware code
2017-03-20 14:49:11 +00:00
### Vendor Header
2016-04-25 18:43:48 +00:00
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.
2016-05-10 14:42:20 +00:00
2016-04-25 18:43:48 +00:00
| offset | length | name | description |
|-------:|-------:|------|-------------|
| 0x0000 | 4 | magic | firmware magic `TRZV` |
| 0x0004 | 4 | hdrlen | length of the vendor header (multiple of 512) |
2017-02-08 14:42:52 +00:00
| 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 |
2017-10-05 15:31:05 +00:00
| 0x0010 | 1 | vtrust | level of vendor trust (0-100) |
| 0x0011 | 15 | reserved | not used yet (zeroed) |
| 0x0020 | 32 | vpub1 | vendor pubkey 1 |
2016-04-25 18:43:48 +00:00
| ... | ... | ... | ... |
| ? | 32 | vpubn | vendor pubkey n |
2016-05-10 14:42:20 +00:00
| ? | 1 | vstr_len | vendor string length |
| ? | ? | vstr | vendor string |
| ? | ? | vstrpad | padding to a multiple of 4 bytes |
2016-05-10 14:42:20 +00:00
| ? | ? | vimg | vendor image (in [TOIf format](toif.md)) |
2017-10-05 15:31:05 +00:00
| ? | ? | reserved | padding to an address that is -65 modulo 512 (zeroed) |
| ? | 1 | sigmask | SatoshiLabs signature indexes (bitmap) |
| ? | 64 | sig | SatoshiLabs aggregated signature of the vendor header |
2016-04-25 18:43:48 +00:00
2017-03-20 14:49:11 +00:00
### Firmware Header
2016-04-25 18:43:48 +00:00
Total length of firmware header is always 1024 bytes.
2016-05-10 14:42:20 +00:00
2016-04-25 18:43:48 +00:00
| offset | length | name | description |
|-------:|-------:|------|-------------|
| 0x0000 | 4 | magic | firmware magic `TRZF` |
| 0x0004 | 4 | hdrlen | length of the firmware header |
2017-02-08 14:42:52 +00:00
| 0x0008 | 4 | expiry | valid until timestamp (0=infinity) |
| 0x000C | 4 | codelen | length of the firmware code (without the header) |
2016-05-09 11:14:55 +00:00
| 0x0010 | 1 | vmajor | version (major) |
| 0x0011 | 1 | vminor | version (minor) |
| 0x0012 | 1 | vpatch | version (patch) |
| 0x0013 | 1 | vbuild | version (build) |
| 0x0014 | 12 | reserved | not used yet (zeroed) |
| 0x0020 | 32 | hash1 | hash of the first code chunk (128 - 1 KiB), this excludes the header |
| 0x0040 | 32 | hash2 | hash of the second code chunk (128 KiB), zeroed if unused |
| ... | ... | ... | ... |
| 0x0200 | 32 | hash16 | hash of the last possible code chunk (128 KiB), zeroed if unused |
| 0x0220 | 415 | reserved | not used yet (zeroed) |
| 0x03BF | 1 | sigmask | vendor signature indexes (bitmap) |
| 0x03C0 | 64 | sig | vendor aggregated signature of the firmware header |
2016-09-15 11:39:19 +00:00
2017-03-20 14:49:11 +00:00
## Various ideas
2016-09-15 11:39:19 +00:00
* Bootloader should be able to read vendor + firmware header and send info
about FW to client in features message.
2017-04-10 17:24:21 +00:00
* 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.