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)
pull/7/head
Daniele Lacamera 2019-04-24 00:15:04 +02:00
parent 937e9d46fb
commit fc547e4a25
11 changed files with 249 additions and 29 deletions

View File

@ -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)

View File

@ -19,6 +19,7 @@ SECTIONS
KEEP(*(.isr_vector))
*(.text*)
*(.rodata*)
*(.srodata*)
. = ALIGN(4);
_end_text = .;
} > FLASH

View File

@ -4,6 +4,13 @@
#include <inttypes.h>
#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);

View File

@ -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

View File

@ -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);

View File

@ -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 <loader.h>
#include "image.h"
#include "loader.h"
#include <stdint.h>
#include <wolfboot/wolfboot.h>
#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

View File

@ -20,6 +20,7 @@
*/
#include <stdint.h>
#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

View File

@ -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 <image.h>
#include <hal.h>
#include "loader.h"
#include "image.h"
#include "hal.h"
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/ssl.h>
#include <loader.h>
#ifdef WOLFBOOT_SIGN_ED25519
#include <wolfssl/wolfcrypt/ed25519.h>
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)

View File

@ -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)) {

View File

@ -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('<Q', int(os.path.getmtime(image_file)))
# Image type field
header += struct.pack('BB', HDR_IMG_TYPE, HDR_IMG_TYPE_LEN)
if (sign == 'ed25519'):
img_type = HDR_IMG_TYPE_AUTH_ED25519
if (sign == 'ecc256'):
img_type = HDR_IMG_TYPE_AUTH_ECC256
if (not self_update):
img_type |= HDR_IMG_TYPE_APP
header += struct.pack('<H', img_type)
sha = hashes.Sha256.new()
# Sha calculation
sha.update(header)

View File

@ -1,7 +1,7 @@
TEST_UPDATE_VERSION?=2
WOLFBOOT_VERSION?=0
EXPVER=tools/test-expect-version/test-expect-version
SPI_CHIP=SST25VF080B
SIGN_TOOL=/bin/false
ifeq ($(SIGN),ED25519)
@ -40,7 +40,6 @@ test-spi-off: FORCE
@echo "in" >/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)