From 3ff7059dc540510888bd62e6a43d35be046a812f Mon Sep 17 00:00:00 2001 From: Daniele Lacamera Date: Tue, 13 Aug 2024 15:25:49 +0200 Subject: [PATCH] Unit tests for update_flash.c (#487) * Initial draft with two test cases * Added more unit tests. Found OOB access. * Fix potential OOB access with too-large update img * NO_FORK disabled by default * Cover more corner cases --- include/loader.h | 11 +- include/wolfboot/wolfboot.h | 4 +- src/image.c | 2 +- tools/unit-tests/Makefile | 7 +- tools/unit-tests/unit-mock-flash.c | 50 ++- tools/unit-tests/unit-update-flash.c | 496 +++++++++++++++++++++++++++ 6 files changed, 558 insertions(+), 12 deletions(-) create mode 100644 tools/unit-tests/unit-update-flash.c diff --git a/include/loader.h b/include/loader.h index ebde3579d..0c55f819e 100644 --- a/include/loader.h +++ b/include/loader.h @@ -88,9 +88,18 @@ void wolfBoot_start(void); #elif defined(ARCH_SIM) #include +#include static inline void wolfBoot_panic(void) { - exit(1); + fprintf(stderr, "wolfBoot: PANIC!\n"); + exit('P'); +} +#elif defined UNIT_TEST +static int wolfBoot_panicked = 0; +static inline void wolfBoot_panic(void) +{ + fprintf(stderr, "wolfBoot: PANIC!\n"); + wolfBoot_panicked++; } #else static inline void wolfBoot_panic(void) diff --git a/include/wolfboot/wolfboot.h b/include/wolfboot/wolfboot.h index bbd76542e..b8bcfda81 100644 --- a/include/wolfboot/wolfboot.h +++ b/include/wolfboot/wolfboot.h @@ -132,7 +132,7 @@ extern "C" { #define KEY_VERIFY_SELF_ONLY KEY_VERIFY_ONLY_ID(0) #define KEY_VERIFY_APP_ONLY KEY_VERIFY_ONLY_ID(1) -#ifdef __WOLFBOOT +#if defined(__WOLFBOOT) || defined(UNIT_TEST_AUTH) /* Hashing configuration */ #if defined(WOLFBOOT_HASH_SHA256) @@ -177,7 +177,7 @@ extern "C" { #endif -#if defined(__WOLFBOOT) || defined (__FLASH_OTP_PRIMER) +#if defined(__WOLFBOOT) || defined (__FLASH_OTP_PRIMER) || defined (UNIT_TEST_AUTH) /* Authentication configuration */ #if defined(WOLFBOOT_NO_SIGN) diff --git a/src/image.c b/src/image.c index 1c3cf19a4..bad8f926f 100644 --- a/src/image.c +++ b/src/image.c @@ -866,7 +866,7 @@ int wolfBoot_open_image_address(struct wolfBoot_image *img, uint8_t *image) wolfBoot_printf("Image size %d > max %d\n", (unsigned int)img->fw_size, (WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE)); - img->fw_size = 0; + img->fw_size = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE; return -1; } if (!img->hdr_ok) { diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index dd1ff21ca..2acb577b8 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -18,7 +18,7 @@ WOLFCRYPT=../../lib/wolfssl/ TESTS:=unit-parser unit-extflash unit-aes128 unit-aes256 unit-chacha20 unit-pci \ unit-mock-state unit-sectorflags unit-image unit-nvm unit-nvm-flagshome \ - unit-enc-nvm unit-enc-nvm-flagshome unit-delta + unit-enc-nvm unit-enc-nvm-flagshome unit-delta unit-update-flash all: $(TESTS) @@ -56,6 +56,8 @@ unit-enc-nvm-flagshome:CFLAGS+=-DNVM_FLASH_WRITEONCE -DMOCK_PARTITIONS \ -DEXT_ENCRYPTED -DENCRYPT_WITH_CHACHA -DEXT_FLASH -DHAVE_CHACHA -DFLAGS_HOME unit-enc-nvm-flagshome:WOLFCRYPT_SRC+=$(WOLFCRYPT)/wolfcrypt/src/chacha.c unit-delta:CFLAGS+=-DNVM_FLASH_WRITEONCE -DMOCK_PARTITIONS -DDELTA_UPDATES -DDELTA_BLOCK_SIZE=512 +unit-update-flash:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \ + -DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT -DPART_SWAP_EXT @@ -112,6 +114,9 @@ unit-enc-nvm-flagshome: ../../include/target.h unit-enc-nvm.c unit-delta: ../../include/target.h unit-delta.c gcc -o $@ unit-delta.c $(CFLAGS) $(LDFLAGS) +unit-update-flash: ../../include/target.h unit-update-flash.c + gcc -o $@ unit-update-flash.c ../../src/image.c ../../lib/wolfssl/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS) + %.o:%.c gcc -c -o $@ $^ $(CFLAGS) diff --git a/tools/unit-tests/unit-mock-flash.c b/tools/unit-tests/unit-mock-flash.c index fb352af75..0132fd857 100644 --- a/tools/unit-tests/unit-mock-flash.c +++ b/tools/unit-tests/unit-mock-flash.c @@ -1,5 +1,30 @@ +/* unit-mock-flash.c + * + * Mock flash access for unit tests + * usage: #include "unit-mock-flash.c" + * + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ static int locked = 1; +static int ext_locked = 1; static int erased_boot = 0; static int erased_update = 0; static int erased_swap = 0; @@ -18,20 +43,24 @@ int hal_flash_write(haladdr_t address, const uint8_t *data, int len) int i; uint8_t *a = (uint8_t *)address; fail_if(locked, "Attempting to write to a locked FLASH"); + if ((address >= WOLFBOOT_PARTITION_SWAP_ADDRESS) && + (address < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_SECTOR_SIZE)) { + for (i = 0; i < len; i++) { + a[i] = data[i]; + } + } if ((address >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) && (address < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) { for (i = 0; i < len; i++) { a[i] = data[i]; } } -#ifdef FLAGS_HOME if ((address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) && (address < WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE)) { for (i = 0; i < len; i++) { a[i] = data[i]; } } -#endif #ifdef MOCK_KEYVAULT if ((address >= vault_base) && (address < vault_base + keyvault_size)) { for (i = 0; i < len; i++) { @@ -47,14 +76,12 @@ int hal_flash_erase(haladdr_t address, int len) if ((address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) && (address < WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE)) { erased_boot++; -#ifdef FLAGS_HOME memset(address, 0xFF, len); if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - WOLFBOOT_SECTOR_SIZE) { erased_nvm_bank0++; } else if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 2 * WOLFBOOT_SECTOR_SIZE) { erased_nvm_bank1++; } -#endif } else if ((address >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) && (address < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) { erased_update++; @@ -96,7 +123,6 @@ void hal_prepare_boot(void) int ext_flash_erase(uintptr_t address, int len) { - printf("%s", __FUNCTION__); if ((address >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) && (address < WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) { erased_update++; @@ -121,8 +147,7 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len) { int i; uint8_t *a = (uint8_t *)address; - fail_if(locked, "Attempting to write to a locked FLASH"); - printf("%s", __FUNCTION__); + fail_if(ext_locked, "Attempting to write to a locked FLASH"); for (i = 0; i < len; i++) { a[i] = data[i]; } @@ -139,6 +164,17 @@ int ext_flash_read(uintptr_t address, uint8_t *data, int len) return 0; } +void ext_flash_unlock(void) +{ + fail_unless(ext_locked, "Double ext unlock detected\n"); + ext_locked--; +} +void ext_flash_lock(void) +{ + fail_if(ext_locked, "Double ext lock detected\n"); + ext_locked++; +} + /* A simple mock memory */ static int mmap_file(const char *path, uint8_t *address, uint32_t len, uint8_t** ret_address) diff --git a/tools/unit-tests/unit-update-flash.c b/tools/unit-tests/unit-update-flash.c new file mode 100644 index 000000000..877c99b3c --- /dev/null +++ b/tools/unit-tests/unit-update-flash.c @@ -0,0 +1,496 @@ +/* unit-update-flash.c + * + * unit tests for update procedures in update_flash.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#define WOLFBOOT_HASH_SHA256 +#define IMAGE_HEADER_SIZE 256 +#define UNIT_TEST +#define WC_NO_HARDEN +#define MOCK_ADDRESS_UPDATE 0xCC000000 +#define MOCK_ADDRESS_BOOT 0xCD000000 +#define MOCK_ADDRESS_SWAP 0xCE000000 + +#define TEST_SIZE_SMALL 5300 +#define TEST_SIZE_LARGE 9800 + +#define NO_FORK 0 /* Set to 1 to disable fork mode (e.g. for gdb debugging) */ + +#include +#include +#include "wolfboot/wolfboot.h" +#include "libwolfboot.c" +#include "update_flash.c" +#include +#include +#include +#include +#include "unit-mock-flash.c" +#include +#include + +const char *argv0; + +Suite *wolfboot_suite(void); + +int wolfBoot_staged_ok = 0; +uint32_t *wolfBoot_stage_address = (uint32_t *) 0xFFFFFFFF; + +void do_boot(const uint32_t *address) +{ + /* Mock of do_boot */ + if (wolfBoot_panicked) + return; + wolfBoot_staged_ok++; + wolfBoot_stage_address = address; + printf("Called do_boot with address %p\n", address); +} + +static void reset_mock_stats(void) +{ + wolfBoot_staged_ok = 0; + wolfBoot_panicked = 0; +} + + +static void prepare_flash(void) +{ + int ret; + ret = mmap_file("/tmp/wolfboot-unit-ext-file.bin", MOCK_ADDRESS_UPDATE, + WOLFBOOT_PARTITION_SIZE, NULL); + fail_if(ret < 0); + ret = mmap_file("/tmp/wolfboot-unit-int-file.bin", MOCK_ADDRESS_BOOT, + WOLFBOOT_PARTITION_SIZE, NULL); + fail_if(ret < 0); + ret = mmap_file("/tmp/wolfboot-unit-swap.bin", MOCK_ADDRESS_SWAP, + WOLFBOOT_SECTOR_SIZE, NULL); + fail_if(ret < 0); + hal_flash_unlock(); + hal_flash_erase(WOLFBOOT_PARTITION_BOOT_ADDRESS, WOLFBOOT_PARTITION_SIZE); + hal_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_PARTITION_SIZE); + hal_flash_lock(); +} + +static void cleanup_flash(void) +{ + munmap(MOCK_ADDRESS_UPDATE, WOLFBOOT_PARTITION_SIZE); + munmap(MOCK_ADDRESS_BOOT, WOLFBOOT_PARTITION_SIZE); + munmap(MOCK_ADDRESS_SWAP, WOLFBOOT_SECTOR_SIZE); +} + + +#define DIGEST_TLV_OFF_IN_HDR 28 +static int add_payload(uint8_t part, uint32_t version, uint32_t size) +{ + uint32_t word; + uint16_t word16; + int i; + uint8_t *base = WOLFBOOT_PARTITION_BOOT_ADDRESS; + int ret; + wc_Sha256 sha; + uint8_t digest[SHA256_DIGEST_SIZE]; + + ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID); + if (ret != 0) + return ret; + + + if (part == PART_UPDATE) + base = WOLFBOOT_PARTITION_UPDATE_ADDRESS; + srandom(part); /* Ensure reproducible "random" image */ + + + hal_flash_unlock(); + hal_flash_write(base, "WOLF", 4); + printf("Written magic: \"WOLF\"\n"); + + hal_flash_write(base + 4, &size, 4); + printf("Written size: %u\n", size); + + /* Headers */ + word = 4 << 16 | HDR_VERSION; + hal_flash_write(base + 8, &word, 4); + hal_flash_write(base + 12, &version, 4); + printf("Written version: %u\n", version); + + word = 2 << 16 | HDR_IMG_TYPE; + hal_flash_write(base + 16, &word, 4); + word16 = HDR_IMG_TYPE_AUTH_NONE | HDR_IMG_TYPE_APP; + hal_flash_write(base + 20, &word16, 2); + printf("Written img_type: %04X\n", word16); + + /* Add 28B header to sha calculation */ + ret = wc_Sha256Update(&sha, base, DIGEST_TLV_OFF_IN_HDR); + if (ret != 0) + return ret; + + /* Payload */ + size += IMAGE_HEADER_SIZE; + for (i = IMAGE_HEADER_SIZE; i < size; i+=4) { + uint32_t word = (random() << 16) | random(); + hal_flash_write(base + i, &word, 4); + } + for (i = IMAGE_HEADER_SIZE; i < size; i+= WOLFBOOT_SHA_BLOCK_SIZE) { + int len = WOLFBOOT_SHA_BLOCK_SIZE; + if ((size - i) < len) + len = size - i; + ret = wc_Sha256Update(&sha, base + i, len); + if (ret != 0) + return ret; + } + + /* Calculate final digest */ + ret = wc_Sha256Final(&sha, digest); + if (ret != 0) + return ret; + wc_Sha256Free(&sha); + + word = SHA256_DIGEST_SIZE << 16 | HDR_SHA256; + hal_flash_write(base + DIGEST_TLV_OFF_IN_HDR, &word, 4); + hal_flash_write(base + DIGEST_TLV_OFF_IN_HDR + 4, digest, + SHA256_DIGEST_SIZE); + printf("SHA digest written\n"); + for (i = 0; i < 32; i++) { + printf("%02x ", digest[i]); + } + printf("\n"); + hal_flash_lock(); + +} + +START_TEST (test_empty_panic) +{ + reset_mock_stats(); + prepare_flash(); + wolfBoot_start(); + fail_if(wolfBoot_staged_ok); + fail_unless(wolfBoot_panicked); + cleanup_flash(); + +} +END_TEST + + +START_TEST (test_sunnyday_noupdate) +{ + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); + +} +END_TEST + +START_TEST (test_forward_update_samesize_notrigger) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); +} +END_TEST + +START_TEST (test_forward_update_samesize) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 2); + cleanup_flash(); +} +END_TEST + +START_TEST (test_forward_update_tolarger) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_LARGE); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 2); + cleanup_flash(); +} +END_TEST + +START_TEST (test_forward_update_tosmaller) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_LARGE); + add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 2); + cleanup_flash(); +} +END_TEST + +START_TEST (test_forward_update_sameversion_denied) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 1, TEST_SIZE_LARGE); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + fail_if(*(uint32_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + 4) != TEST_SIZE_SMALL); + cleanup_flash(); +} +END_TEST + +START_TEST (test_update_oldversion_denied) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 2, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 1, TEST_SIZE_LARGE); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 2); + fail_if(*(uint32_t *)(WOLFBOOT_PARTITION_BOOT_ADDRESS + 4) != TEST_SIZE_SMALL); + cleanup_flash(); +} + +START_TEST (test_invalid_update_type) { + reset_mock_stats(); + prepare_flash(); + uint16_t word16 = 0xBAAD; + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL); + ext_flash_unlock(); + ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 20, &word16, 2); + ext_flash_lock(); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); +} + +START_TEST (test_update_toolarge) { + uint32_t very_large = WOLFBOOT_PARTITION_SIZE; + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_LARGE); + /* Change the size in the header to be larger than the actual size */ + ext_flash_unlock(); + ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 4, &very_large, 4); + ext_flash_lock(); + + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); +} + +START_TEST (test_invalid_sha) { + uint8_t bad_digest[SHA256_DIGEST_SIZE]; + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 1, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL); + + memset(bad_digest, 0xBA, SHA256_DIGEST_SIZE); + ext_flash_unlock(); + ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + DIGEST_TLV_OFF_IN_HDR + 4, bad_digest, SHA256_DIGEST_SIZE); + ext_flash_lock(); + wolfBoot_update_trigger(); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); +} + +START_TEST (test_emergency_rollback) { + uint8_t testing_flags[5] = { IMG_STATE_TESTING, 'B', 'O', 'O', 'T' }; + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 2, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 1, TEST_SIZE_SMALL); + /* Set the testing flag in the last five bytes of the BOOT partition */ + hal_flash_unlock(); + hal_flash_write(WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 5, + testing_flags, 5); + hal_flash_lock(); + + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 1); + cleanup_flash(); +} + +START_TEST (test_emergency_rollback_failure_due_to_bad_update) { + uint8_t testing_flags[5] = { IMG_STATE_TESTING, 'B', 'O', 'O', 'T' }; + uint8_t wrong_update_magic[4] = { 'G', 'O', 'L', 'F' }; + reset_mock_stats(); + prepare_flash(); + add_payload(PART_BOOT, 2, TEST_SIZE_SMALL); + add_payload(PART_UPDATE, 1, TEST_SIZE_SMALL); + /* Set the testing flag in the last five bytes of the BOOT partition */ + hal_flash_unlock(); + hal_flash_write(WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE - 5, + testing_flags, 5); + hal_flash_lock(); + + /* Corrupt the update */ + ext_flash_unlock(); + ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS, wrong_update_magic, 4); + ext_flash_lock(); + + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 2); + cleanup_flash(); +} + +START_TEST (test_empty_boot_partition_update) { + reset_mock_stats(); + prepare_flash(); + add_payload(PART_UPDATE, 5, TEST_SIZE_SMALL); + wolfBoot_start(); + fail_if(wolfBoot_panicked); + fail_unless(wolfBoot_staged_ok); + fail_if(wolfBoot_current_firmware_version() != 5); + cleanup_flash(); +} + +START_TEST (test_empty_boot_but_update_sha_corrupted_denied) { + uint8_t bad_digest[SHA256_DIGEST_SIZE]; + reset_mock_stats(); + prepare_flash(); + add_payload(PART_UPDATE, 5, TEST_SIZE_SMALL); + memset(bad_digest, 0xBA, SHA256_DIGEST_SIZE); + ext_flash_unlock(); + ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + DIGEST_TLV_OFF_IN_HDR + 4, bad_digest, SHA256_DIGEST_SIZE); + ext_flash_lock(); + wolfBoot_start(); + /* We expect to panic */ + fail_unless(wolfBoot_panicked); + fail_if(wolfBoot_staged_ok); + cleanup_flash(); +} + + +Suite *wolfboot_suite(void) +{ + /* Suite initialization */ + Suite *s = suite_create("wolfboot"); + + /* Test cases */ + TCase *empty_panic = tcase_create("Empty partition panic test"); + TCase *sunnyday_noupdate = + tcase_create("Sunny day test with no update available"); + TCase *forward_update_samesize = + tcase_create("Forward update with same size"); + TCase *forward_update_tolarger = + tcase_create("Forward update to larger size"); + TCase *forward_update_tosmaller = tcase_create("Forward update to smaller size"); + TCase *forward_update_sameversion_denied = + tcase_create("Forward update to same version denied"); + TCase *update_oldversion_denied = + tcase_create("Update to older version denied"); + TCase *invalid_update_type = + tcase_create("Invalid update type"); + TCase *update_toolarge = tcase_create("Update too large"); + TCase *invalid_sha = tcase_create("Invalid SHA digest"); + TCase *emergency_rollback = tcase_create("Emergency rollback"); + TCase *emergency_rollback_failure_due_to_bad_update = tcase_create("Emergency rollback failure due to bad update"); + TCase *empty_boot_partition_update = tcase_create("Empty boot partition update"); + TCase *empty_boot_but_update_sha_corrupted_denied = tcase_create("Empty boot partition but update SHA corrupted"); + + + + tcase_add_test(empty_panic, test_empty_panic); + tcase_add_test(sunnyday_noupdate, test_sunnyday_noupdate); + tcase_add_test(forward_update_samesize, test_forward_update_samesize); + tcase_add_test(forward_update_tolarger, test_forward_update_tolarger); + tcase_add_test(forward_update_tosmaller, test_forward_update_tosmaller); + tcase_add_test(forward_update_sameversion_denied, test_forward_update_sameversion_denied); + tcase_add_test(update_oldversion_denied, test_update_oldversion_denied); + tcase_add_test(invalid_update_type, test_invalid_update_type); + tcase_add_test(update_toolarge, test_update_toolarge); + tcase_add_test(invalid_sha, test_invalid_sha); + tcase_add_test(emergency_rollback, test_emergency_rollback); + tcase_add_test(emergency_rollback_failure_due_to_bad_update, test_emergency_rollback_failure_due_to_bad_update); + tcase_add_test(empty_boot_partition_update, test_empty_boot_partition_update); + tcase_add_test(empty_boot_but_update_sha_corrupted_denied, test_empty_boot_but_update_sha_corrupted_denied); + + + + suite_add_tcase(s, empty_panic); + suite_add_tcase(s, sunnyday_noupdate); + suite_add_tcase(s, forward_update_samesize); + suite_add_tcase(s, forward_update_tolarger); + suite_add_tcase(s, forward_update_tosmaller); + suite_add_tcase(s, forward_update_sameversion_denied); + suite_add_tcase(s, update_oldversion_denied); + suite_add_tcase(s, invalid_update_type); + suite_add_tcase(s, update_toolarge); + suite_add_tcase(s, invalid_sha); + suite_add_tcase(s, emergency_rollback); + suite_add_tcase(s, emergency_rollback_failure_due_to_bad_update); + suite_add_tcase(s, empty_boot_partition_update); + suite_add_tcase(s, empty_boot_but_update_sha_corrupted_denied); + + + + return s; +} + + +int main(int argc, char *argv[]) +{ + int fails; + argv0 = strdup(argv[0]); + Suite *s = wolfboot_suite(); + SRunner *sr = srunner_create(s); +#if (NO_FORK == 1) + srunner_set_fork_status(sr, CK_NOFORK); +#endif + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + return fails; +}