Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/encrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len);

#ifdef EXT_ENCRYPTED
int wolfBoot_enable_fallback_iv(int enable);
Comment thread
danielinux marked this conversation as resolved.
int wolfBoot_force_fallback_iv(int enable);
void wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter);
#endif

Expand Down
10 changes: 10 additions & 0 deletions src/libwolfboot.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ static int encrypt_initialized = 0;

static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE] XALIGNED(4);
static uint32_t encrypt_iv_offset = 0;
static int fallback_iv_forced = 0;

#define FALLBACK_IV_OFFSET 0x00100000U
#if !defined(XMEMSET)
Expand Down Expand Up @@ -1395,6 +1396,13 @@ int RAMFUNCTION wolfBoot_enable_fallback_iv(int enable)
return prev;
}

int RAMFUNCTION wolfBoot_force_fallback_iv(int enable)
{
int prev = fallback_iv_forced;
fallback_iv_forced = enable ? 1 : 0;
return prev;
}

void RAMFUNCTION wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter)
{
#if defined(ENCRYPT_WITH_CHACHA)
Expand Down Expand Up @@ -2174,6 +2182,8 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
return -1;
}
}
if (fallback_iv_forced)
encrypt_iv_offset = FALLBACK_IV_OFFSET;
wolfBoot_crypto_set_iv(encrypt_iv_nonce, iv_counter);
break;
case PART_SWAP:
Expand Down
24 changes: 16 additions & 8 deletions src/update_flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,14 +774,22 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
return -1;
}
} else {
/*
* When we recover an already-encrypted fallback image, the
* manifest still contains hashes computed with the original IV
* stream. Skip the redundant integrity/authenticity checks here
* and let the bootloader verify the restored image after the swap.
*/
update.sha_ok = 1;
update.signature_ok = 1;
#ifdef EXT_ENCRYPTED
int prev = wolfBoot_force_fallback_iv(1);
#endif
if (!update.hdr_ok
|| (wolfBoot_verify_integrity(&update) < 0)
|| (wolfBoot_verify_authenticity(&update) < 0)) {
#ifdef EXT_ENCRYPTED
wolfBoot_force_fallback_iv(prev);
#endif
wolfBoot_printf("Update verify failed: Hdr %d, Hash %d, Sig %d\n",
update.hdr_ok, update.sha_ok, update.signature_ok);
return -1;
}
#ifdef EXT_ENCRYPTED
wolfBoot_force_fallback_iv(prev);
#endif
}
PART_SANITY_CHECK(&update);

Expand Down
14 changes: 12 additions & 2 deletions tools/unit-tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ LDFLAGS+=-ftest-coverage
TESTS:=unit-parser unit-extflash unit-string unit-spi-flash 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-update-flash unit-update-ram \
unit-pkcs11_store
unit-enc-nvm-flagshome unit-delta unit-update-flash \
unit-update-flash-enc unit-update-ram unit-pkcs11_store

all: $(TESTS)

Expand Down Expand Up @@ -137,6 +137,16 @@ unit-delta: ../../include/target.h unit-delta.c
unit-update-flash: ../../include/target.h unit-update-flash.c
gcc -o $@ unit-update-flash.c ../../src/image.c $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS)

unit-update-flash-enc:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \
-DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT \
-DPART_SWAP_EXT -DEXT_ENCRYPTED -DENCRYPT_WITH_CHACHA -DHAVE_CHACHA \
-DCUSTOM_ENCRYPT_KEY -DUNIT_TEST_FALLBACK_ONLY
unit-update-flash-enc: ../../include/target.h unit-update-flash.c
gcc -o $@ unit-update-flash.c ../../src/image.c \
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c \
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/chacha.c \
$(CFLAGS) $(LDFLAGS)

unit-update-ram: ../../include/target.h unit-update-ram.c
gcc -o $@ unit-update-ram.c ../../src/image.c $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS)

Expand Down
17 changes: 17 additions & 0 deletions tools/unit-tests/unit-mock-flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,18 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
int i;
uint8_t *a = (uint8_t *)address;
ck_assert_msg(!ext_locked, "Attempting to write to a locked FLASH");
ck_assert_msg(
((address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) &&
(address + (uintptr_t)len <=
WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE)) ||
((address >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) &&
(address + (uintptr_t)len <=
WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) ||
((address >= WOLFBOOT_PARTITION_SWAP_ADDRESS) &&
Comment thread
danielinux marked this conversation as resolved.
(address + (uintptr_t)len <=
WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE)),
"ext_flash_write address out of range: %p len %d",
(void*)address, len);
Comment thread
danielinux marked this conversation as resolved.
for (i = 0; i < len; i++) {
a[i] = data[i];
}
Expand Down Expand Up @@ -190,6 +202,11 @@ void ext_flash_lock(void)
ext_locked++;
}

void ext_flash_reset_lock(void)
{
ext_locked = 1;
}


/* A simple mock memory */
static int mmap_file(const char *path, uint8_t *address, uint32_t len,
Expand Down
189 changes: 186 additions & 3 deletions tools/unit-tests/unit-update-flash.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,32 @@ static void reset_mock_stats(void);
static void prepare_flash(void);
static void cleanup_flash(void);

#ifdef CUSTOM_ENCRYPT_KEY
int wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
{
int i;
for (i = 0; i < ENCRYPT_KEY_SIZE; i++) {
k[i] = (uint8_t)(i + 1);
}
for (i = 0; i < ENCRYPT_NONCE_SIZE; i++) {
nonce[i] = (uint8_t)(0xA5 + i);
}
return 0;
}

int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce)
{
(void)key;
(void)nonce;
return 0;
}

int wolfBoot_erase_encrypt_key(void)
{
return 0;
}
#endif

START_TEST (test_boot_success_sets_state)
{
uint8_t state = 0;
Expand Down Expand Up @@ -90,6 +116,7 @@ static void reset_mock_stats(void)
{
wolfBoot_staged_ok = 0;
wolfBoot_panicked = 0;
ext_flash_reset_lock();
Comment thread
danielinux marked this conversation as resolved.
}


Expand Down Expand Up @@ -198,6 +225,121 @@ static int add_payload(uint8_t part, uint32_t version, uint32_t size)

}

#ifdef EXT_ENCRYPTED
static int build_image_buffer(uint8_t part, uint32_t version, uint32_t size,
uint8_t *buf, uint32_t buf_sz)
{
uint32_t word;
uint16_t word16;
uint32_t total = size + IMAGE_HEADER_SIZE;
int i;
int ret;
wc_Sha256 sha;
uint8_t digest[SHA256_DIGEST_SIZE];

if (buf_sz < total)
return -1;

memset(buf, 0xFF, buf_sz);

ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID);
if (ret != 0)
return ret;
Comment thread
danielinux marked this conversation as resolved.

memcpy(buf, "WOLF", 4);
memcpy(buf + 4, &size, 4);

word = 4 << 16 | HDR_VERSION;
memcpy(buf + 8, &word, 4);
memcpy(buf + 12, &version, 4);

word = 2 << 16 | HDR_IMG_TYPE;
memcpy(buf + 16, &word, 4);
word16 = HDR_IMG_TYPE_AUTH_NONE | HDR_IMG_TYPE_APP;
memcpy(buf + 20, &word16, 2);

ret = wc_Sha256Update(&sha, buf, DIGEST_TLV_OFF_IN_HDR);
if (ret != 0)
return ret;
Comment thread
danielinux marked this conversation as resolved.

srandom(part);
for (i = IMAGE_HEADER_SIZE; i < (int)total; i += 4) {
uint32_t rnd = (random() << 16) | random();
memcpy(buf + i, &rnd, 4);
Comment thread
danielinux marked this conversation as resolved.
}
for (i = IMAGE_HEADER_SIZE; i < (int)total; i += WOLFBOOT_SHA_BLOCK_SIZE) {
int len = WOLFBOOT_SHA_BLOCK_SIZE;
if ((int)total - i < len)
len = (int)total - i;
ret = wc_Sha256Update(&sha, buf + i, len);
if (ret != 0)
return ret;
}
Comment thread
danielinux marked this conversation as resolved.

ret = wc_Sha256Final(&sha, digest);
if (ret != 0)
return ret;
wc_Sha256Free(&sha);

word = SHA256_DIGEST_SIZE << 16 | HDR_SHA256;
memcpy(buf + DIGEST_TLV_OFF_IN_HDR, &word, 4);
memcpy(buf + DIGEST_TLV_OFF_IN_HDR + 4, digest, SHA256_DIGEST_SIZE);

return 0;
}

static int add_payload_encrypted(uint8_t part, uint32_t version, uint32_t size,
int use_fallback_iv)
{
uint32_t total = size + IMAGE_HEADER_SIZE;
uint8_t *buf = NULL;
uintptr_t base = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
int ret;
int prev = 0;

if (part == PART_BOOT)
base = (uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS;
else if (part == PART_UPDATE)
base = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
else
return -1;

buf = malloc(total);
if (!buf)
return -1;

ret = build_image_buffer(part, version, size, buf, total);
if (ret != 0) {
free(buf);
return ret;
}

if (use_fallback_iv)
prev = wolfBoot_enable_fallback_iv(1);

ext_flash_unlock();
{
uint32_t off = 0;
while (off < total) {
uint32_t chunk = total - off;
if (chunk > WOLFBOOT_SECTOR_SIZE)
chunk = WOLFBOOT_SECTOR_SIZE;
ret = ext_flash_encrypt_write(base + off, buf + off, chunk);
if (ret != 0)
break;
off += chunk;
}
}
ext_flash_lock();

if (use_fallback_iv)
wolfBoot_enable_fallback_iv(prev);
Comment thread
danielinux marked this conversation as resolved.

free(buf);
return ret;
}
#endif

START_TEST (test_empty_panic)
{
reset_mock_stats();
Expand All @@ -210,6 +352,31 @@ START_TEST (test_empty_panic)
}
END_TEST

#ifdef EXT_ENCRYPTED
START_TEST (test_fallback_image_verification_rejects_corruption)
{
int ret;
uint8_t bad = 0x00;

reset_mock_stats();
prepare_flash();

add_payload(PART_BOOT, 1, TEST_SIZE_SMALL);
ret = add_payload_encrypted(PART_UPDATE, 2, TEST_SIZE_SMALL, 1);
ck_assert_int_eq(ret, 0);

ext_flash_unlock();
ext_flash_write((uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS +
IMAGE_HEADER_SIZE + 16, &bad, 1);
ext_flash_lock();

ret = wolfBoot_update(1);
ck_assert_int_eq(ret, -1);

cleanup_flash();
}
END_TEST
#endif

START_TEST (test_sunnyday_noupdate)
{
Expand Down Expand Up @@ -498,6 +665,9 @@ Suite *wolfboot_suite(void)
Suite *s = suite_create("wolfboot");

/* Test cases */
#ifdef UNIT_TEST_FALLBACK_ONLY
TCase *fallback_verify = tcase_create("Fallback verify");
#else
TCase *empty_panic = tcase_create("Empty partition panic test");
TCase *sunnyday_noupdate =
tcase_create("Sunny day test with no update available");
Expand All @@ -521,9 +691,17 @@ Suite *wolfboot_suite(void)
TCase *swap_resume = tcase_create("Swap resume noop");
TCase *diffbase_version = tcase_create("Diffbase version lookup");
TCase *boot_success = tcase_create("Boot success state");
#ifdef EXT_ENCRYPTED
TCase *fallback_verify = tcase_create("Fallback verify");
#endif
#endif



#ifdef UNIT_TEST_FALLBACK_ONLY
tcase_add_test(fallback_verify, test_fallback_image_verification_rejects_corruption);
suite_add_tcase(s, fallback_verify);
return s;
Comment thread
danielinux marked this conversation as resolved.
#else
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);
Expand All @@ -541,8 +719,9 @@ Suite *wolfboot_suite(void)
tcase_add_test(swap_resume, test_swap_resume_noop);
tcase_add_test(diffbase_version, test_diffbase_version_reads);
tcase_add_test(boot_success, test_boot_success_sets_state);


#ifdef EXT_ENCRYPTED
tcase_add_test(fallback_verify, test_fallback_image_verification_rejects_corruption);
#endif

suite_add_tcase(s, empty_panic);
suite_add_tcase(s, sunnyday_noupdate);
Expand All @@ -561,6 +740,10 @@ Suite *wolfboot_suite(void)
suite_add_tcase(s, swap_resume);
suite_add_tcase(s, diffbase_version);
suite_add_tcase(s, boot_success);
#ifdef EXT_ENCRYPTED
suite_add_tcase(s, fallback_verify);
#endif
#endif



Expand Down
Loading