diff --git a/Makefile.bootloader b/Makefile.bootloader index 903317922..393e24644 100644 --- a/Makefile.bootloader +++ b/Makefile.bootloader @@ -56,11 +56,11 @@ OBJ_HAL += $(addprefix $(BUILD_MP)/,\ # OBJ micropython/ OBJ_FW += $(addprefix $(BUILD_FW)/, \ - bootloader/crypto.o \ bootloader/main.o \ extmod/modtrezorui/display.o \ extmod/modtrezorui/font_bitmap.o \ trezorhal/common.o \ + trezorhal/image.o \ trezorhal/sdcard.o \ trezorhal/stm32_it.o \ trezorhal/stm32_system.o \ @@ -94,8 +94,8 @@ SRC_MOD = $(patsubst $(BUILD_FW)%.o, $(SRCDIR_FW)%.c, $(OBJ_MOD)) CROSS_COMPILE = arm-none-eabi- INC += -I. +INC += -I$(SRCDIR_FW)/bootloader INC += -I$(SRCDIR_FW)/extmod/modtrezorui -INC += -I$(SRCDIR_FW)/firmware INC += -I$(SRCDIR_FW)/trezorhal INC += -I$(SRCDIR_FW)/trezorhal/hal INC += -I$(SRCDIR_MP) diff --git a/Makefile.firmware b/Makefile.firmware index bad67bbfb..293becf87 100644 --- a/Makefile.firmware +++ b/Makefile.firmware @@ -341,8 +341,8 @@ SRC_MOD = $(patsubst $(BUILD_FW)%.o, $(SRCDIR_FW)%.c, $(OBJ_MOD)) CROSS_COMPILE = arm-none-eabi- INC += -I. -INC += -I$(SRCDIR_FW)/extmod/modtrezorui INC += -I$(SRCDIR_FW)/firmware +INC += -I$(SRCDIR_FW)/extmod/modtrezorui INC += -I$(SRCDIR_FW)/trezorhal INC += -I$(SRCDIR_FW)/trezorhal/hal INC += -I$(SRCDIR_MP) diff --git a/Makefile.loader b/Makefile.loader index f8b07f6f1..969ff863a 100644 --- a/Makefile.loader +++ b/Makefile.loader @@ -56,12 +56,12 @@ 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 \ extmod/modtrezorui/font_bitmap.o \ trezorhal/common.o \ + trezorhal/image.o \ trezorhal/stm32_it.o \ trezorhal/stm32_system.o \ trezorhal/hal/stm32f4xx_hal_sram.o \ @@ -94,8 +94,8 @@ SRC_MOD = $(patsubst $(BUILD_FW)%.o, $(SRCDIR_FW)%.c, $(OBJ_MOD)) CROSS_COMPILE = arm-none-eabi- INC += -I. +INC += -I$(SRCDIR_FW)/loader INC += -I$(SRCDIR_FW)/extmod/modtrezorui -INC += -I$(SRCDIR_FW)/firmware INC += -I$(SRCDIR_FW)/trezorhal INC += -I$(SRCDIR_FW)/trezorhal/hal INC += -I$(SRCDIR_MP) diff --git a/micropython/bootloader/crypto.c b/micropython/bootloader/crypto.c deleted file mode 100644 index fe8339c38..000000000 --- a/micropython/bootloader/crypto.c +++ /dev/null @@ -1,105 +0,0 @@ -#include - -#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 != 0x4C5A5254) return false; // TRZL - - 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 > 64 * 1024 + 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)); -} diff --git a/micropython/bootloader/crypto.h b/micropython/bootloader/crypto.h deleted file mode 100644 index 59f80ff4e..000000000 --- a/micropython/bootloader/crypto.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __BOOTLOADER_CRYPTO_H__ -#define __BOOTLOADER_CRYPTO_H__ - -#include -#include - -bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8_t *sig); - -bool check_signature(const uint8_t *start); - -#endif diff --git a/micropython/bootloader/image_options.h b/micropython/bootloader/image_options.h new file mode 100644 index 000000000..135c4f699 --- /dev/null +++ b/micropython/bootloader/image_options.h @@ -0,0 +1,2 @@ +#define IMAGE_MAGIC 0x4C5A5254 // TRZL +#define IMAGE_MAXSIZE (1 * 64 * 1024 + 7 * 128 + 1024) diff --git a/micropython/bootloader/main.c b/micropython/bootloader/main.c index e72f764f7..8c7470118 100644 --- a/micropython/bootloader/main.c +++ b/micropython/bootloader/main.c @@ -2,10 +2,9 @@ #include -#include "crypto.h" - #include "common.h" #include "display.h" +#include "image.h" #include "sdcard.h" #define BOOTLOADER_FGCOLOR 0xFFFF @@ -38,13 +37,13 @@ bool check_sdcard(void) return false; } - uint8_t buf[SDCARD_BLOCK_SIZE] __attribute__((aligned(4))); + uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; sdcard_read_blocks(buf, 0, 1); sdcard_power_off(); - if (parse_header(buf, NULL, NULL, NULL)) { + if (image_parse_header((const uint8_t *)buf, NULL)) { BOOTLOADER_PRINTLN("SD card header is valid"); return true; } else { @@ -86,13 +85,13 @@ bool copy_sdcard(void) uint32_t buf[SDCARD_BLOCK_SIZE / sizeof(uint32_t)]; sdcard_read_blocks((uint8_t *)buf, 0, 1); - uint32_t codelen; - if (!parse_header((uint8_t *)buf, &codelen, NULL, NULL)) { + image_header hdr; + if (!image_parse_header((const uint8_t *)buf, &hdr)) { BOOTLOADER_PRINTLN("wrong header"); return false; } - for (int i = 0; i < codelen / SDCARD_BLOCK_SIZE; i++) { + for (int i = 0; i < (HEADER_SIZE + hdr.codelen) / SDCARD_BLOCK_SIZE; i++) { sdcard_read_blocks((uint8_t *)buf, i, 1); for (int j = 0; j < SDCARD_BLOCK_SIZE / sizeof(uint32_t); j++) { if (HAL_FLASH_Program(TYPEPROGRAM_WORD, LOADER_START + i * SDCARD_BLOCK_SIZE + j * sizeof(uint32_t), buf[j]) != HAL_OK) { @@ -115,21 +114,16 @@ bool copy_sdcard(void) 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"); - } + if (image_check_signature((const uint8_t *)LOADER_START)) { + BOOTLOADER_PRINTLN("valid loader image"); + // 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 header"); + BOOTLOADER_PRINTLN("invalid loader image"); } } diff --git a/micropython/loader/crypto.h b/micropython/loader/crypto.h deleted file mode 100644 index 9d618cdfb..000000000 --- a/micropython/loader/crypto.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __LOADER_CRYPTO_H__ -#define __LOADER_CRYPTO_H__ - -#include -#include - -bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigidx, uint8_t *sig); - -bool check_signature(const uint8_t *start); - -#endif diff --git a/micropython/loader/image_options.h b/micropython/loader/image_options.h new file mode 100644 index 000000000..10afda967 --- /dev/null +++ b/micropython/loader/image_options.h @@ -0,0 +1,2 @@ +#define IMAGE_MAGIC 0x465A5254 // TRZF +#define IMAGE_MAXSIZE (7 * 128 + 1024) diff --git a/micropython/loader/main.c b/micropython/loader/main.c index 479fed92d..7d3ef9158 100644 --- a/micropython/loader/main.c +++ b/micropython/loader/main.c @@ -2,7 +2,7 @@ #include "common.h" #include "display.h" -#include "crypto.h" +#include "image.h" #define LOADER_FGCOLOR 0xFFFF #define LOADER_BGCOLOR 0x0000 @@ -17,21 +17,16 @@ void pendsv_isr_handler(void) { 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"); - } + if (image_check_signature((const uint8_t *)FIRMWARE_START)) { + 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); } else { - LOADER_PRINTLN("invalid firmware header"); + LOADER_PRINTLN("invalid firmware image"); } } diff --git a/micropython/loader/crypto.c b/micropython/trezorhal/image.c similarity index 60% rename from micropython/loader/crypto.c rename to micropython/trezorhal/image.c index a26a11806..c609120ef 100644 --- a/micropython/loader/crypto.c +++ b/micropython/trezorhal/image.c @@ -4,51 +4,43 @@ #include "ed25519-donna/ed25519.h" #include "common.h" -#include "crypto.h" +#include "image.h" -bool parse_header(const uint8_t *data, uint32_t *codelen, uint8_t *sigmask, uint8_t *sig) +bool image_parse_header(const uint8_t *data, image_header *header) { - 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; + if (!header) { + image_header h; + header = &h; } - uint32_t version; - memcpy(&version, data + 16, 4); + memcpy(&header->magic, data, 4); + if (header->magic != IMAGE_MAGIC) return false; + + memcpy(&header->hdrlen, data + 4, 4); + if (header->hdrlen != HEADER_SIZE) return false; + + memcpy(&header->expiry, data + 8, 4); + if (header->expiry != 0) return false; + + memcpy(&header->codelen, data + 12, 4); + if (header->hdrlen + header->codelen < 4 * 1024) return false; + if (header->hdrlen + header->codelen > IMAGE_MAXSIZE) return false; + if ((header->hdrlen + header->codelen) % 512 != 0) return false; + + memcpy(&header->version, data + 16, 4); // uint8_t reserved[427]; - if (sigmask) { - memcpy(sigmask, data + 0x01BF, 1); - } + memcpy(&header->sigmask, data + 0x01BF, 1); - if (sig) { - memcpy(sig, data + 0x01C0, 64); - } + memcpy(header->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) +static const uint8_t *get_pubkey(uint8_t index) { switch (index) { case KEYMASK(1, 2, 3): @@ -76,30 +68,28 @@ const uint8_t *get_pubkey(uint8_t index) } } -bool check_signature(const uint8_t *start) +bool image_check_signature(const uint8_t *data) { - uint32_t codelen; - uint8_t sigmask; - uint8_t sig[64]; - if (!parse_header(start, &codelen, &sigmask, sig)) { + image_header hdr; + if (!image_parse_header(data, &hdr)) { return false; } uint8_t hash[BLAKE2S_DIGEST_LENGTH]; BLAKE2S_CTX ctx; blake2s_Init(&ctx, BLAKE2S_DIGEST_LENGTH); - blake2s_Update(&ctx, start, 256 - 65); + blake2s_Update(&ctx, data, HEADER_SIZE - 65); for (int i = 0; i < 65; i++) { blake2s_Update(&ctx, (const uint8_t *)"\x00", 1); } - blake2s_Update(&ctx, start + 256, codelen); + blake2s_Update(&ctx, data + HEADER_SIZE, hdr.codelen); blake2s_Final(&ctx, hash, BLAKE2S_DIGEST_LENGTH); - const uint8_t *pub = get_pubkey(sigmask); + const uint8_t *pub = get_pubkey(hdr.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)); + return pub && (0 == ed25519_sign_open(hash, BLAKE2S_DIGEST_LENGTH, *(const ed25519_public_key *)pub, *(const ed25519_signature *)hdr.sig)); } diff --git a/micropython/trezorhal/image.h b/micropython/trezorhal/image.h new file mode 100644 index 000000000..e7b480882 --- /dev/null +++ b/micropython/trezorhal/image.h @@ -0,0 +1,24 @@ +#ifndef __TREZORHAL_IMAGE_H__ +#define __TREZORHAL_IMAGE_H__ + +#include +#include + +#include "image_options.h" + +typedef struct { + uint32_t magic; + uint32_t hdrlen; + uint32_t expiry; + uint32_t codelen; + uint32_t version; + // uint8_t reserved[427]; + uint8_t sigmask; + uint8_t sig[64]; +} image_header; + +bool image_parse_header(const uint8_t *data, image_header *header); + +bool image_check_signature(const uint8_t *data); + +#endif