mirror of https://github.com/wolfSSL/wolfBoot.git
F-7969: validate boot-side digest before delta base hash compare
wolfBoot_delta_update() compared the boot partition digest against the delta base hash using base_hash_sz, the length returned by wolfBoot_find_header() for the boot header's hash TLV, without ever checking it. When the tag is absent, find_header() sets base_hash to NULL and returns 0, so wolfBoot_hardened_CT_compare(NULL, ..., 0) compared zero bytes and reported a match: the base image digest gate silently succeeded instead of rejecting the patch. A short or oversized TLV length would likewise truncate the comparison or read past the delta base hash in the update header. The gate is reachable because wolfBoot_update() runs before the boot partition is verified, so the boot header contents are not guaranteed to carry a well-formed digest TLV at that point. Reject the patch when the base image has no usable digest, and compare a fixed WOLFBOOT_SHA_DIGEST_SIZE. The inverse and resume paths are unaffected, as they do not use this gate. Add unit-update-flash-delta coverage for a boot header without a digest TLV.pull/851/head
parent
7608e333a8
commit
e200579d36
|
|
@ -710,9 +710,11 @@ static int wolfBoot_delta_update(struct wolfBoot_image *boot,
|
|||
cur_v, delta_base_v);
|
||||
ret = -1;
|
||||
} else if (!resume && delta_base_hash &&
|
||||
wolfBoot_hardened_CT_compare(base_hash, delta_base_hash,
|
||||
base_hash_sz) != 0) {
|
||||
/* Wrong base image digest, cannot apply delta patch */
|
||||
((base_hash == NULL) ||
|
||||
(base_hash_sz != WOLFBOOT_SHA_DIGEST_SIZE) ||
|
||||
(wolfBoot_hardened_CT_compare(base_hash, delta_base_hash,
|
||||
WOLFBOOT_SHA_DIGEST_SIZE) != 0))) {
|
||||
/* Wrong or missing base image digest, cannot apply delta patch */
|
||||
wolfBoot_printf("Delta Base hash mismatch\n");
|
||||
ret = -1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1358,6 +1358,67 @@ START_TEST (test_delta_base_version_match_accepts)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_delta_base_hash_missing_in_boot_header_rejected)
|
||||
{
|
||||
struct wolfBoot_image boot, update, swap;
|
||||
uint32_t word;
|
||||
uint32_t delta_sz = 0x00001020;
|
||||
uint32_t delta_base = 1;
|
||||
uint8_t base_hash[SHA256_DIGEST_SIZE];
|
||||
uint8_t *boot_base = (uint8_t *)(uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS;
|
||||
int ret;
|
||||
|
||||
reset_mock_stats();
|
||||
prepare_flash();
|
||||
|
||||
add_payload(PART_BOOT, 1, TEST_SIZE_SMALL);
|
||||
add_payload(PART_UPDATE, 2, TEST_SIZE_SMALL);
|
||||
|
||||
/* Remove the digest TLV from the boot header, keeping the TLV chain
|
||||
* well-formed by retagging it to an unused custom type */
|
||||
hal_flash_unlock();
|
||||
word = SHA256_DIGEST_SIZE << 16 | 0x0031;
|
||||
hal_flash_write((uintptr_t)boot_base + DIGEST_TLV_OFF_IN_HDR,
|
||||
(void *)&word, 4);
|
||||
hal_flash_lock();
|
||||
|
||||
/* The delta patch declares a base digest that cannot match */
|
||||
memset(base_hash, 0xA5, sizeof(base_hash));
|
||||
|
||||
ext_flash_unlock();
|
||||
word = (4u << 16) | HDR_IMG_DELTA_SIZE;
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 64,
|
||||
(const uint8_t *)&word, sizeof(word));
|
||||
word = host_to_img_u32(delta_sz);
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 68,
|
||||
(const uint8_t *)&word, sizeof(word));
|
||||
word = (4u << 16) | HDR_IMG_DELTA_BASE;
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 72,
|
||||
(const uint8_t *)&word, sizeof(word));
|
||||
word = host_to_img_u32(delta_base);
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 76,
|
||||
(const uint8_t *)&word, sizeof(word));
|
||||
word = (SHA256_DIGEST_SIZE << 16) | HDR_IMG_DELTA_BASE_HASH;
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 80,
|
||||
(const uint8_t *)&word, sizeof(word));
|
||||
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS + 84,
|
||||
base_hash, sizeof(base_hash));
|
||||
ext_flash_lock();
|
||||
|
||||
ck_assert_int_eq(wolfBoot_open_image(&boot, PART_BOOT), 0);
|
||||
ck_assert_int_eq(wolfBoot_open_image(&update, PART_UPDATE), 0);
|
||||
memset(&swap, 0, sizeof(swap));
|
||||
swap.part = PART_SWAP;
|
||||
swap.hdr = (void *)(uintptr_t)WOLFBOOT_PARTITION_SWAP_ADDRESS;
|
||||
|
||||
ret = wolfBoot_delta_update(&boot, &update, &swap, 0, 0);
|
||||
ck_assert_int_eq(ret, -1);
|
||||
ck_assert_int_eq(mock_wb_patch_init_calls, 0);
|
||||
|
||||
cleanup_flash();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST (test_delta_inverse_values_passed_with_native_endian)
|
||||
{
|
||||
struct wolfBoot_image boot, update, swap;
|
||||
|
|
@ -1567,6 +1628,7 @@ Suite *wolfboot_suite(void)
|
|||
tcase_add_test(delta_zero_size, test_delta_zero_size_erased_header_uses_recovery_heuristic);
|
||||
tcase_add_test(delta_base_version, test_delta_base_version_mismatch_rejected);
|
||||
tcase_add_test(delta_base_version, test_delta_base_version_match_accepts);
|
||||
tcase_add_test(delta_base_version, test_delta_base_hash_missing_in_boot_header_rejected);
|
||||
tcase_add_test(delta_base_version, test_delta_inverse_values_passed_with_native_endian);
|
||||
tcase_add_test(delta_base_version, test_delta_inverse_accepts_when_current_matches_update);
|
||||
tcase_add_test(delta_base_version, test_delta_inverse_accepts_when_current_matches_delta_base);
|
||||
|
|
|
|||
Loading…
Reference in New Issue