diff --git a/.github/workflows/test-elf-scattered.yml b/.github/workflows/test-elf-scattered.yml index 4445016985..868560acd7 100644 --- a/.github/workflows/test-elf-scattered.yml +++ b/.github/workflows/test-elf-scattered.yml @@ -35,3 +35,11 @@ jobs: - name: Run bootloader with no arguments run: | ./wolfboot.elf + + - name: Build wolfboot.elf (ELF_SCATTERED, ONESHOT_HASH) + run: | + make clean && make test-sim-internal-flash-with-update ELF=1 ELF_SCATTERED=1 WOLFBOOT_IMG_HASH_ONESHOT=1 + + - name: Run bootloader with no arguments (ONESHOT_HASH) + run: | + ./wolfboot.elf diff --git a/.github/workflows/test-sunnyday-simulator.yml b/.github/workflows/test-sunnyday-simulator.yml index b537b51e14..d02eae4bb8 100644 --- a/.github/workflows/test-sunnyday-simulator.yml +++ b/.github/workflows/test-sunnyday-simulator.yml @@ -379,6 +379,30 @@ jobs: run: | tools/scripts/sim-sunnyday-update.sh + - name: Build wolfboot.elf (ECC256, ONESHOT_HASH, SHA256) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=ECC256 SPMATH=1 WOLFBOOT_IMG_HASH_ONESHOT=1 + + - name: Run sunny day update test (ONESHOT_HASH, SHA256) + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (ECC256, ONESHOT_HASH, SHA384) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=ECC256 SPMATH=1 HASH=SHA384 WOLFBOOT_IMG_HASH_ONESHOT=1 + + - name: Run sunny day update test (ONESHOT_HASH, SHA384) + run: | + tools/scripts/sim-sunnyday-update.sh + + - name: Build wolfboot.elf (ECC256, ONESHOT_HASH, SHA3) + run: | + make clean && make test-sim-internal-flash-with-update SIGN=ECC256 SPMATH=1 HASH=SHA3 WOLFBOOT_IMG_HASH_ONESHOT=1 + + - name: Run sunny day update test (ONESHOT_HASH, SHA3) + run: | + tools/scripts/sim-sunnyday-update.sh + - name: Cleanup to change key type run: | make keysclean diff --git a/docs/compile.md b/docs/compile.md index cf0d566ac0..7a11e0748c 100644 --- a/docs/compile.md +++ b/docs/compile.md @@ -189,6 +189,22 @@ falls in one of these cases, wolfBoot compilation will terminate with an explici In some cases you might have enough memory available to allow large stack allocations. To circumvent the compile-time checks on the maximum allowed stack size, use `WOLFBOOT_HUGE_STACK=1`. +### One-shot hash verification + +By default, wolfBoot hashes firmware images in blocks of `WOLFBOOT_SHA_BLOCK_SIZE` bytes during +verification. This block-by-block approach is required when firmware resides in external flash or +other non-memory-mapped storage, where data must be read through intermediate buffers. + +When firmware images are stored in directly memory-mapped flash (e.g. internal flash with +execute-in-place support), the block-by-block overhead can be eliminated by enabling +`WOLFBOOT_IMG_HASH_ONESHOT=1`. With this option, the entire image buffer is passed to the wolfCrypt +hash function in a single call, which can improve verification performance. + +**warning** This option assumes that `fw_base` pointers are directly dereferenceable for the full +firmware size. It is incompatible with `EXT_FLASH=1` configurations where partitions reside on +external SPI or UART flash. Only use `WOLFBOOT_IMG_HASH_ONESHOT=1` when all firmware partitions are +in directly addressable, memory-mapped flash. + ### Disable Backup of current running firmware Optionally, it is possible to disable the backup copy of the current running firmware upon the installation of the diff --git a/options.mk b/options.mk index 814e1d9987..5cb35bac32 100644 --- a/options.mk +++ b/options.mk @@ -779,6 +779,10 @@ ifeq ($(ARMORED),1) CFLAGS+=-DWOLFBOOT_ARMORED endif +ifeq ($(WOLFBOOT_IMG_HASH_ONESHOT),1) + CFLAGS+=-DWOLFBOOT_IMG_HASH_ONESHOT +endif + ifeq ($(WOLFBOOT_HUGE_STACK),1) CFLAGS+=-DWOLFBOOT_HUGE_STACK endif diff --git a/src/image.c b/src/image.c index 6d87db1616..d5598fcba9 100644 --- a/src/image.c +++ b/src/image.c @@ -973,8 +973,7 @@ static int header_sha256(wc_Sha256 *sha256_ctx, struct wolfBoot_image *img) { uint8_t *stored_sha, *end_sha; uint16_t stored_sha_len; - uint8_t *p; - int blksz; + uint8_t* p; if (!img) return -1; @@ -988,13 +987,22 @@ static int header_sha256(wc_Sha256 *sha256_ctx, struct wolfBoot_image *img) wc_InitSha256(sha256_ctx); #endif end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ - while (p < end_sha) { - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (end_sha - p < blksz) - blksz = end_sha - p; - wc_Sha256Update(sha256_ctx, p, blksz); - p += blksz; +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (end_sha <= p) + return -1; + wc_Sha256Update(sha256_ctx, p, (word32)(end_sha - p)); +#else + { + int blksz; + while (p < end_sha) { + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (end_sha - p < blksz) + blksz = end_sha - p; + wc_Sha256Update(sha256_ctx, p, blksz); + p += blksz; + } } +#endif return 0; } @@ -1007,23 +1015,31 @@ static int header_sha256(wc_Sha256 *sha256_ctx, struct wolfBoot_image *img) */ static int image_sha256(struct wolfBoot_image *img, uint8_t *hash) { - uint32_t position = 0; - uint8_t *p; - int blksz; wc_Sha256 sha256_ctx; if (header_sha256(&sha256_ctx, img) != 0) return -1; - do { - p = get_sha_block(img, position); - if (p == NULL) - break; - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (position + blksz > img->fw_size) - blksz = img->fw_size - position; - wc_Sha256Update(&sha256_ctx, p, blksz); - position += blksz; - } while(position < img->fw_size); +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (img->fw_base == NULL) + return -1; + wc_Sha256Update(&sha256_ctx, img->fw_base, img->fw_size); +#else + { + uint32_t position = 0; + uint8_t* p; + int blksz; + do { + p = get_sha_block(img, position); + if (p == NULL) + break; + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (position + blksz > img->fw_size) + blksz = img->fw_size - position; + wc_Sha256Update(&sha256_ctx, p, blksz); + position += blksz; + } while (position < img->fw_size); + } +#endif wc_Sha256Final(&sha256_ctx, hash); wc_Sha256Free(&sha256_ctx); @@ -1064,8 +1080,7 @@ static int header_sha384(wc_Sha384 *sha384_ctx, struct wolfBoot_image *img) { uint16_t stored_sha_len; uint8_t *stored_sha, *end_sha; - uint8_t *p; - int blksz; + uint8_t* p; if (!img) return -1; @@ -1079,13 +1094,22 @@ static int header_sha384(wc_Sha384 *sha384_ctx, struct wolfBoot_image *img) wc_InitSha384(sha384_ctx); #endif end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ - while (p < end_sha) { - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (end_sha - p < blksz) - blksz = end_sha - p; - wc_Sha384Update(sha384_ctx, p, blksz); - p += blksz; +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (end_sha <= p) + return -1; + wc_Sha384Update(sha384_ctx, p, (word32)(end_sha - p)); +#else + { + int blksz; + while (p < end_sha) { + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (end_sha - p < blksz) + blksz = end_sha - p; + wc_Sha384Update(sha384_ctx, p, blksz); + p += blksz; + } } +#endif return 0; } @@ -1101,23 +1125,31 @@ static int header_sha384(wc_Sha384 *sha384_ctx, struct wolfBoot_image *img) */ static int image_sha384(struct wolfBoot_image *img, uint8_t *hash) { - uint32_t position = 0; - uint8_t *p; - int blksz; wc_Sha384 sha384_ctx; if (header_sha384(&sha384_ctx, img) != 0) return -1; - do { - p = get_sha_block(img, position); - if (p == NULL) - break; - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (position + blksz > img->fw_size) - blksz = img->fw_size - position; - wc_Sha384Update(&sha384_ctx, p, blksz); - position += blksz; - } while(position < img->fw_size); +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (img->fw_base == NULL) + return -1; + wc_Sha384Update(&sha384_ctx, img->fw_base, img->fw_size); +#else + { + uint32_t position = 0; + uint8_t* p; + int blksz; + do { + p = get_sha_block(img, position); + if (p == NULL) + break; + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (position + blksz > img->fw_size) + blksz = img->fw_size - position; + wc_Sha384Update(&sha384_ctx, p, blksz); + position += blksz; + } while (position < img->fw_size); + } +#endif wc_Sha384Final(&sha384_ctx, hash); wc_Sha384Free(&sha384_ctx); @@ -1164,8 +1196,7 @@ static int header_sha3_384(wc_Sha3 *sha3_ctx, struct wolfBoot_image *img) { uint16_t stored_sha_len; uint8_t *stored_sha, *end_sha; - uint8_t *p; - int blksz; + uint8_t* p; if (!img) return -1; @@ -1176,13 +1207,22 @@ static int header_sha3_384(wc_Sha3 *sha3_ctx, struct wolfBoot_image *img) return -1; wc_InitSha3_384(sha3_ctx, NULL, INVALID_DEVID); end_sha = stored_sha - (2 * sizeof(uint16_t)); /* Subtract 2 Type + 2 Len */ - while (p < end_sha) { - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (end_sha - p < blksz) - blksz = end_sha - p; - wc_Sha3_384_Update(sha3_ctx, p, blksz); - p += blksz; +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (end_sha <= p) + return -1; + wc_Sha3_384_Update(sha3_ctx, p, (word32)(end_sha - p)); +#else + { + int blksz; + while (p < end_sha) { + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (end_sha - p < blksz) + blksz = end_sha - p; + wc_Sha3_384_Update(sha3_ctx, p, blksz); + p += blksz; + } } +#endif return 0; } @@ -1197,23 +1237,31 @@ static int header_sha3_384(wc_Sha3 *sha3_ctx, struct wolfBoot_image *img) */ static int image_sha3_384(struct wolfBoot_image *img, uint8_t *hash) { - uint8_t *p; - int blksz; - uint32_t position = 0; wc_Sha3 sha3_ctx; if (header_sha3_384(&sha3_ctx, img) != 0) return -1; - do { - p = get_sha_block(img, position); - if (p == NULL) - break; - blksz = WOLFBOOT_SHA_BLOCK_SIZE; - if (position + blksz > img->fw_size) - blksz = img->fw_size - position; - wc_Sha3_384_Update(&sha3_ctx, p, blksz); - position += blksz; - } while(position < img->fw_size); +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + if (img->fw_base == NULL) + return -1; + wc_Sha3_384_Update(&sha3_ctx, img->fw_base, img->fw_size); +#else + { + uint8_t* p; + int blksz; + uint32_t position = 0; + do { + p = get_sha_block(img, position); + if (p == NULL) + break; + blksz = WOLFBOOT_SHA_BLOCK_SIZE; + if (position + blksz > img->fw_size) + blksz = img->fw_size - position; + wc_Sha3_384_Update(&sha3_ctx, p, blksz); + position += blksz; + } while (position < img->fw_size); + } +#endif wc_Sha3_384_Final(&sha3_ctx, hash); wc_Sha3_384_Free(&sha3_ctx); @@ -1728,6 +1776,10 @@ static int update_hash_flash_fwimg(wolfBoot_hash_t* ctx, struct wolfBoot_image* img, uint32_t offset, uint32_t size) { +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + update_hash(ctx, img->fw_base + offset, size); + return 0; +#else uint32_t current_offset = offset; uint32_t remaining_size = size; uint8_t read_buf[WOLFBOOT_SHA_BLOCK_SIZE] XALIGNED_STACK(4); /* Use local buffer */ @@ -1750,6 +1802,7 @@ static int update_hash_flash_fwimg(wolfBoot_hash_t* ctx, current_offset += read_size; } return 0; +#endif } /* @@ -1759,6 +1812,11 @@ static int update_hash_flash_fwimg(wolfBoot_hash_t* ctx, static int update_hash_flash_addr(wolfBoot_hash_t* ctx, uintptr_t addr, uint32_t size, int src_ext) { +#ifdef WOLFBOOT_IMG_HASH_ONESHOT + (void)src_ext; + update_hash(ctx, (uint8_t*)addr, size); + return 0; +#else uint8_t buffer[WOLFBOOT_SHA_BLOCK_SIZE] XALIGNED_STACK(4); uint32_t remaining_size = size; uintptr_t current_addr = addr; @@ -1783,6 +1841,7 @@ static int update_hash_flash_addr(wolfBoot_hash_t* ctx, uintptr_t addr, } return 0; +#endif } int wolfBoot_check_flash_image_elf(uint8_t part, unsigned long* entry_out) diff --git a/tools/config.mk b/tools/config.mk index 034ac550c6..2d158ee3ff 100644 --- a/tools/config.mk +++ b/tools/config.mk @@ -78,6 +78,7 @@ ifeq ($(ARCH),) WOLFBOOT_SMALL_STACK?=0 DELTA_UPDATES?=0 DELTA_BLOCK_SIZE?=256 + WOLFBOOT_IMG_HASH_ONESHOT?=0 WOLFBOOT_HUGE_STACK?=0 ARMORED?=0 ELF?=0 @@ -107,7 +108,7 @@ CONFIG_VARS:= ARCH TARGET SIGN HASH MCUXSDK MCUXPRESSO MCUXPRESSO_CPU MCUXPRESSO WOLFBOOT_PARTITION_BOOT_ADDRESS WOLFBOOT_PARTITION_UPDATE_ADDRESS \ WOLFBOOT_PARTITION_SWAP_ADDRESS WOLFBOOT_LOAD_ADDRESS \ WOLFBOOT_LOAD_DTS_ADDRESS WOLFBOOT_DTS_BOOT_ADDRESS WOLFBOOT_DTS_UPDATE_ADDRESS \ - WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE \ + WOLFBOOT_SMALL_STACK DELTA_UPDATES DELTA_BLOCK_SIZE WOLFBOOT_IMG_HASH_ONESHOT \ WOLFBOOT_HUGE_STACK FORCE_32BIT\ ENCRYPT_WITH_CHACHA ENCRYPT_WITH_AES128 ENCRYPT_WITH_AES256 ARMORED \ LMS_LEVELS LMS_HEIGHT LMS_WINTERNITZ \