From fc547e4a25a413f79802d25a3c1948405e42952a Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Wed, 24 Apr 2019 00:15:04 +0200 Subject: [PATCH] wolfBoot can update itself when compiled with RAM_CODE=1 - Added wolfBoot version - Added extra 16bit header tag to identify the image type and authentication - Implemented optional in-ram self-update of the bootloader, with version control and authentication mechanism (not fail-safe) --- Makefile | 6 ++- hal/hifive1.ld | 1 + include/hal.h | 7 +++ include/image.h | 3 ++ include/wolfboot/wolfboot.h | 19 ++++++++ src/boot_arm.c | 25 ++++++++-- src/boot_riscv.c | 34 ++++++++++++++ src/image.c | 20 ++++++-- src/loader.c | 93 ++++++++++++++++++++++++++++++++++++- tools/keytools/sign.py | 56 ++++++++++++++++------ tools/test.mk | 14 +++++- 11 files changed, 249 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 32c45adb..48332d59 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,7 @@ EXT_FLASH?=0 SPI_FLASH?=0 ALLOW_DOWNGRADE?=0 NVM_FLASH_WRITEONCE?=0 +WOLFBOOT_VERSION?=0 V?=0 SPMATH?=1 RAM_CODE?=0 @@ -28,7 +29,7 @@ RAM_CODE?=0 ## Initializers -CFLAGS:=-D__WOLFBOOT +CFLAGS:=-D__WOLFBOOT -DWOLFBOOT_VERSION=$(WOLFBOOT_VERSION)UL LSCRIPT:=hal/$(TARGET).ld LDFLAGS:=-T $(LSCRIPT) -Wl,-gc-sections -Wl,-Map=wolfboot.map -ffreestanding -nostartfiles OBJS:= \ @@ -147,7 +148,8 @@ wolfboot-align.bin: wolfboot.bin @echo test-app/image.bin: - @make -C test-app TARGET=$(TARGET) EXT_FLASH=$(EXT_FLASH) SPI_FLASH=$(SPI_FLASH) ARCH=$(ARCH) V=$(V) \ + @make -C test-app TARGET=$(TARGET) EXT_FLASH=$(EXT_FLASH) SPI_FLASH=$(SPI_FLASH) ARCH=$(ARCH) \ + V=$(V) RAM_CODE=$(RAM_CODE) WOLFBOOT_VERSION=$(WOLFBOOT_VERSION)\ KINETIS=$(KINETIS) KINETIS_CPU=$(KINETIS_CPU) KINETIS_DRIVERS=$(KINETIS_DRIVERS) \ KINETIS_CMSIS=$(KINETIS_CMSIS) NVM_FLASH_WRITEONCE=$(NVM_FLASH_WRITEONCE) \ FREEDOM_E_SDK=$(FREEDOM_E_SDK) diff --git a/hal/hifive1.ld b/hal/hifive1.ld index b33ea6c0..0707554b 100644 --- a/hal/hifive1.ld +++ b/hal/hifive1.ld @@ -19,6 +19,7 @@ SECTIONS KEEP(*(.isr_vector)) *(.text*) *(.rodata*) + *(.srodata*) . = ALIGN(4); _end_text = .; } > FLASH diff --git a/include/hal.h b/include/hal.h index 359c7c98..6ec61d3f 100644 --- a/include/hal.h +++ b/include/hal.h @@ -4,6 +4,13 @@ #include #include "target.h" + +/* Architecture specific calls */ +extern void do_boot(const uint32_t *app_offset); +extern void arch_reboot(void); + + + void hal_init(void); int hal_flash_write(uint32_t address, const uint8_t *data, int len); int hal_flash_erase(uint32_t address, int len); diff --git a/include/image.h b/include/image.h index 652334e7..3428b341 100644 --- a/include/image.h +++ b/include/image.h @@ -41,6 +41,9 @@ int wolfBoot_set_sector_flag(uint8_t part, uint8_t sector, uint8_t newflag); int wolfBoot_get_partition_state(uint8_t part, uint8_t *st); int wolfBoot_get_sector_flag(uint8_t part, uint8_t sector, uint8_t *flag); +/* Defined in libwolfboot */ +uint8_t wolfBoot_find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr); + #ifdef EXT_FLASH # ifdef PART_UPDATE_EXT # define UPDATE_EXT 1 diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index dd682a6f..a26ab562 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -13,10 +13,27 @@ #define HDR_VERSION 0x01 #define HDR_TIMESTAMP 0x02 #define HDR_SHA256 0x03 +#define HDR_IMG_TYPE 0x04 #define HDR_PUBKEY 0x10 #define HDR_SIGNATURE 0x20 #define HDR_PADDING 0xFF +#define HDR_IMG_TYPE_AUTH_ED25519 0x0100 +#define HDR_IMG_TYPE_AUTH_ECC256 0x0200 +#define HDR_IMG_TYPE_WOLFBOOT 0x0000 +#define HDR_IMG_TYPE_APP 0x0001 + + +#ifdef __WOLFBOOT + #if defined(WOLFBOOT_SIGN_ED25519) + # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ED25519 + #elif defined(WOLFBOOT_SIGN_ECC256) + # define HDR_IMG_TYPE_AUTH HDR_IMG_TYPE_AUTH_ECC256 + #else + # error "no valid authentication mechanism selected. Please define WOLFBOOT_SIGN_ED25519 or WOLFBOOT_SIGN_ECC256" + #endif /* defined WOLFBOOT_SIGN_ECC256 || WOLFBOOT_SIGN_ED25519 */ +#endif /* defined WOLFBOOT */ + #define PART_BOOT 0 #define PART_UPDATE 1 #define PART_SWAP 2 @@ -26,6 +43,8 @@ #define IMG_STATE_TESTING 0x10 #define IMG_STATE_SUCCESS 0x00 + + void wolfBoot_erase_partition(uint8_t part); void wolfBoot_update_trigger(void); void wolfBoot_success(void); diff --git a/src/boot_arm.c b/src/boot_arm.c index de1ab6a7..54e85d90 100644 --- a/src/boot_arm.c +++ b/src/boot_arm.c @@ -1,4 +1,4 @@ -/* boot_arm.c +/* boot_arm.c * * Copyright (C) 2018 wolfSSL Inc. * @@ -18,9 +18,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#include +#include "image.h" +#include "loader.h" #include -#include +#include "wolfboot/wolfboot.h" extern unsigned int _stored_data; extern unsigned int _start_data; extern unsigned int _end_data; @@ -33,7 +34,7 @@ extern void main(void); void isr_reset(void) { register unsigned int *src, *dst; -#ifdef PLATFORM_kinetis +#ifdef PLATFORM_kinetis /* Immediately disable Watchdog after boot */ /* Write Keys to unlock register */ *((volatile unsigned short *)0x4005200E) = 0xC520; @@ -86,6 +87,7 @@ void isr_empty(void) static void *app_entry; static uint32_t app_end_stack; + void do_boot(const uint32_t *app_offset) { @@ -171,3 +173,18 @@ void (* const IV[])(void) = isr_empty, isr_empty, }; + +#ifdef RAM_CODE + +#define AIRCR *(volatile uint32_t *)(0xE000ED0C) +#define AIRCR_VKEY (0x05FA << 16) +# define AIRCR_SYSRESETREQ (1 << 2) + +void RAMFUNCTION arch_reboot(void) +{ + AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY; + while(1) + ; + +} +#endif diff --git a/src/boot_riscv.c b/src/boot_riscv.c index e1b83795..d991d7a4 100644 --- a/src/boot_riscv.c +++ b/src/boot_riscv.c @@ -20,6 +20,7 @@ */ #include +#include "image.h" extern void trap_entry(void); extern void trap_exit(void); @@ -36,6 +37,12 @@ extern uint32_t _global_pointer; extern void (* const IV[])(void); extern void main(void); +void RAMFUNCTION reloc_iv(uint32_t *address) +{ + asm volatile("csrw mtvec, %0":: "r"(address + 1)); +} + + void __attribute__((naked,section(".init"))) _reset(void) { register uint32_t *src, *dst; asm volatile("la gp, _global_pointer"); @@ -83,4 +90,31 @@ void isr_empty(void) } +#ifdef RAM_CODE + +#define AON_WDOGCFG *(volatile uint32_t *)(0x10000000UL) +#define AON_WDOGKEY *(volatile uint32_t *)(0x1000001CUL) +#define AON_WDOGFEED *(volatile uint32_t *)(0x10000018UL) +#define AON_WDOGCMP *(volatile uint32_t *)(0x10000020UL) + +#define AON_WDOGKEY_VALUE 0x0051F15E +#define AON_WDOGCFG_SCALE 0x0000000F +#define AON_WDOGCFG_RSTEN 0x00000100 +#define AON_WDOGCFG_ZEROCMP 0x00000200 +#define AON_WDOGCFG_ENALWAYS 0x00001000 + + +void RAMFUNCTION arch_reboot(void) +{ + AON_WDOGKEY = AON_WDOGKEY_VALUE; + AON_WDOGCMP = 0; + //wdogconfig: : wdogrsten | enablealways | reset to 0 | max scale + AON_WDOGKEY = AON_WDOGKEY_VALUE; + AON_WDOGCFG |= (AON_WDOGCFG_RSTEN | AON_WDOGCFG_ENALWAYS | AON_WDOGCFG_ZEROCMP | AON_WDOGCFG_SCALE) ; + AON_WDOGKEY = AON_WDOGKEY_VALUE; + AON_WDOGFEED = 1; + while(1) + ; +} +#endif diff --git a/src/image.c b/src/image.c index 8388ec8c..c3ca1bae 100644 --- a/src/image.c +++ b/src/image.c @@ -18,18 +18,16 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ -#include -#include +#include "loader.h" +#include "image.h" +#include "hal.h" #include #include -#include #ifdef WOLFBOOT_SIGN_ED25519 #include -extern uint8_t wolfBoot_find_header(uint8_t *haystack, uint8_t type, uint8_t **ptr); - static int wolfBoot_verify_signature(uint8_t *hash, uint8_t *sig) { int ret, res; @@ -266,6 +264,9 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) uint8_t stored_signature_size; uint8_t *pubkey_hint; uint8_t pubkey_hint_size; + uint8_t *image_type_buf; + uint16_t image_type; + uint8_t image_type_size; stored_signature_size = get_header(img, HDR_SIGNATURE, &stored_signature); if (stored_signature_size != IMAGE_SIGNATURE_SIZE) @@ -276,6 +277,15 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img) if (memcmp(digest, pubkey_hint, SHA256_DIGEST_SIZE) != 0) return -1; } + image_type_size = get_header(img, HDR_IMG_TYPE, &image_type_buf); + if (image_type_size != sizeof(uint16_t)) + return -1; + image_type = (uint16_t)(image_type_buf[0] + (image_type_buf[1] << 8)); + + if ((image_type & 0xFF00) != HDR_IMG_TYPE_AUTH) + return -1; + + if (image_hash(img, digest) != 0) return -1; if (wolfBoot_verify_signature(digest, stored_signature) != 0) diff --git a/src/loader.c b/src/loader.c index 6bdffc46..ab5da108 100644 --- a/src/loader.c +++ b/src/loader.c @@ -22,8 +22,13 @@ #include "image.h" #include "hal.h" #include "spi_flash.h" +#include "wolfboot/wolfboot.h" -extern void do_boot(const uint32_t *app_offset); +#ifdef RAM_CODE +extern unsigned int _start_text; +static volatile const uint32_t wolfboot_version = WOLFBOOT_VERSION; +extern void (** const IV_RAM)(void); +#endif #define FLASHBUFFER_SIZE 256 static int wolfBoot_copy_sector(struct wolfBoot_image *src, struct wolfBoot_image *dst, uint32_t sector) @@ -87,10 +92,16 @@ static int wolfBoot_update(int fallback_allowed) /* Check the first sector to detect interrupted update */ if ((wolfBoot_get_sector_flag(PART_UPDATE, 0, &flag) < 0) || (flag == SECT_FLAG_NEW)) { + uint8_t *update_type; /* In case this is a new update, do the required * checks on the firmware update * before starting the swap */ + + if (wolfBoot_find_header(update.hdr + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, &update_type) == sizeof(uint16_t)) { + if ((update_type[0] != HDR_IMG_TYPE_APP) || update_type[1] != (HDR_IMG_TYPE_AUTH >> 8)) + return -1; + } if (!update.hdr_ok || (wolfBoot_verify_integrity(&update) < 0) || (wolfBoot_verify_authenticity(&update) < 0)) { return -1; @@ -153,11 +164,89 @@ static int wolfBoot_update(int fallback_allowed) return 0; } + +#ifdef RAM_CODE + +static void RAMFUNCTION wolfBoot_erase_bootloader(void) +{ + uint32_t *start = (uint32_t *)&_start_text; + uint32_t len = WOLFBOOT_PARTITION_BOOT_ADDRESS - (uint32_t)start; + hal_flash_erase((uint32_t)start, len); + +} + +static void RAMFUNCTION wolfBoot_self_update(struct wolfBoot_image *src) +{ + uint32_t pos = 0; + uint32_t src_offset = IMAGE_HEADER_SIZE; + + hal_flash_unlock(); + wolfBoot_erase_bootloader(); +#ifdef EXT_FLASH + while (pos < src->fw_size) { + if (PART_IS_EXT(src)) { + uint8_t buffer[FLASHBUFFER_SIZE]; + if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + ext_flash_read((uint32_t)(src->hdr) + src_offset + pos, (void *)buffer, FLASHBUFFER_SIZE); + hal_flash_write(pos + (uint32_t)&_start_text, buffer, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + goto lock_and_reset; + } +#endif + while (pos < src->fw_size) { + if (src_offset + pos < (src->fw_size + IMAGE_HEADER_SIZE + FLASHBUFFER_SIZE)) { + uint8_t *orig = (uint8_t*)(src->hdr + src_offset + pos); + hal_flash_write(pos + (uint32_t)&_start_text, orig, FLASHBUFFER_SIZE); + } + pos += FLASHBUFFER_SIZE; + } + +lock_and_reset: + hal_flash_lock(); + arch_reboot(); +} + +static void wolfBoot_check_self_update(void) +{ + uint8_t st; + struct wolfBoot_image update; + uint8_t *update_type; + uint32_t update_version; + + /* Check for self update in the UPDATE partition */ + if ((wolfBoot_get_partition_state(PART_UPDATE, &st) == 0) && (st == IMG_STATE_UPDATING) && + (wolfBoot_open_image(&update, PART_UPDATE) == 0) && + (wolfBoot_find_header(update.hdr + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, &update_type) == sizeof(uint16_t)) && + update_type[0] == HDR_IMG_TYPE_WOLFBOOT && + update_type[1] == (HDR_IMG_TYPE_AUTH >> 8)) { + uint32_t update_version = wolfBoot_update_firmware_version(); + if (update_version <= wolfboot_version) { + hal_flash_unlock(); + wolfBoot_erase_partition(PART_UPDATE); + hal_flash_lock(); + return; + } + if (wolfBoot_verify_integrity(&update) < 0) + return; + if (wolfBoot_verify_authenticity(&update) < 0) + return; + wolfBoot_self_update(&update); + } +} +#endif /* RAM_CODE for self_update */ + static void wolfBoot_start(void) { uint8_t st; struct wolfBoot_image boot, update; - /* First, check if the BOOT partition is still in TESTING, + +#ifdef RAM_CODE + wolfBoot_check_self_update(); +#endif + + /* Check if the BOOT partition is still in TESTING, * to trigger fallback. */ if ((wolfBoot_get_partition_state(PART_BOOT, &st) == 0) && (st == IMG_STATE_TESTING)) { diff --git a/tools/keytools/sign.py b/tools/keytools/sign.py index 71d83ba7..d34f0d0f 100755 --- a/tools/keytools/sign.py +++ b/tools/keytools/sign.py @@ -30,37 +30,48 @@ HDR_END = 0x00 HDR_VERSION = 0x01 HDR_TIMESTAMP = 0x02 HDR_SHA256 = 0x03 +HDR_IMG_TYPE = 0x04 HDR_PUBKEY = 0x10 HDR_SIGNATURE = 0x20 HDR_PADDING = 0xFF + HDR_VERSION_LEN = 4 HDR_TIMESTAMP_LEN = 8 HDR_SHA256_LEN = 32 +HDR_IMG_TYPE_LEN = 2 HDR_PUBKEY_LEN = 32 HDR_SIGNATURE_LEN = 64 +HDR_IMG_TYPE_AUTH_ED25519 = 0x0100 +HDR_IMG_TYPE_AUTH_ECC256 = 0x0200 + +HDR_IMG_TYPE_WOLFBOOT = 0x0000 +HDR_IMG_TYPE_APP = 0x0001 + sign="auto" +self_update=False argc = len(sys.argv) argv = sys.argv -if (argc < 4) or (argc > 5): - print("Usage: %s [--ed25519 | --ecc256 ] image key.der fw_version\n" % sys.argv[0]) +if (argc < 4) or (argc > 6): + print("Usage: %s [--ed25519 | --ecc256 ] [--wolfboot-update] image key.der fw_version\n" % sys.argv[0]) sys.exit(1) +for i in range(1, len(argv)): + if (argv[i] == '--ed25519'): + sign='ed25519' + elif (argv[i] == '--ecc256'): + sign='ecc256' + elif (argv[i] == '--wolfboot-update'): + self_update = True + else: + i-=1 + break -if argc == 5: - if argv[1] != '--ed25519' and argv[1] != '--ecc256': - print("Usage: %s [--ed25519 | --ecc256 ] image key.der fw_version\n" % sys.argv[0]) - sys.exit(1) - sign=argv[1][2:] - image_file = argv[2] - key_file = argv[3] - fw_version = int(argv[4]) -else: - image_file = argv[1] - key_file = argv[2] - fw_version = int(argv[3]) +image_file = argv[i+1] +key_file = argv[i+2] +fw_version = int(argv[i+3]) if '.' in image_file: tokens = image_file.split('.') @@ -69,6 +80,11 @@ if '.' in image_file: else: output_image_file = image_file + "_v" + str(fw_version) + "_signed.bin" +if (self_update): + print("Update type: wolfBoot") +else: + print("Update type: Firmware") + print ("Selected cipher: " + sign) print ("Private key: " + key_file) print ("Input image: " + image_file) @@ -130,6 +146,18 @@ header += struct.pack('BB', 0xFF, 0xFF) header += struct.pack('BB', HDR_TIMESTAMP, HDR_TIMESTAMP_LEN) header += struct.pack('/sys/class/gpio/gpio10/direction @echo "in" >/sys/class/gpio/gpio11/direction - test-update: test-app/image.bin FORCE @dd if=/dev/zero bs=131067 count=1 2>/dev/null | tr "\000" "\377" > test-update.bin @python3 $(SIGN_TOOL) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION) @@ -52,6 +51,17 @@ test-update: test-app/image.bin FORCE (make test-reset && sleep 1 && st-flash --reset write test-update.bin 0x08040000) || \ (make test-reset && sleep 1 && st-flash --reset write test-update.bin 0x08040000) +test-self-update: wolfboot.bin test-app/image.bin FORCE + @dd if=/dev/zero bs=131067 count=1 2>/dev/null | tr "\000" "\377" > test-self-update.bin + @$(SIGN_TOOL) --wolfboot-update wolfboot.bin $(PRIVATE_KEY) $(WOLFBOOT_VERSION) + @dd if=wolfboot_v$(WOLFBOOT_VERSION)_signed.bin of=test-self-update.bin bs=1 conv=notrunc + @printf "pBOOT" >> test-self-update.bin + @make test-reset + @sleep 2 + @st-flash --reset write test-self-update.bin 0x08040000 || \ + (make test-reset && sleep 1 && st-flash --reset write test-self-update.bin 0x08040000) || \ + (make test-reset && sleep 1 && st-flash --reset write test-self-update.bin 0x08040000) + test-update-ext: test-app/image.bin FORCE @python3 $(SIGN_TOOL) test-app/image.bin $(PRIVATE_KEY) $(TEST_UPDATE_VERSION) @$$(dd if=/dev/zero bs=1M count=1 | tr '\000' '\377' > test-update.rom)