Skip to content

Commit 8f0b38b

Browse files
committed
image: check integrity in wolfBoot_verify_authenticity()
1 parent 880c0a7 commit 8f0b38b

3 files changed

Lines changed: 161 additions & 6 deletions

File tree

src/image.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,10 +2305,9 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
23052305
image_type = (uint16_t)(image_type_buf[0] + (image_type_buf[1] << 8));
23062306
if ((image_type & HDR_IMG_TYPE_AUTH_MASK) != HDR_IMG_TYPE_AUTH)
23072307
return -1;
2308-
if (img->sha_hash == NULL) {
2309-
if (image_hash(img, digest) != 0)
2308+
if ((img->sha_hash == NULL) || (img->sha_ok != 1U)) {
2309+
if (wolfBoot_verify_integrity(img) != 0)
23102310
return -1;
2311-
img->sha_hash = digest;
23122311
}
23132312
image_part = image_type & HDR_IMG_TYPE_PART_MASK;
23142313
#ifdef WOLFBOOT_NO_KEYSTORE

tools/unit-tests/Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
5252
unit-uart-flash \
5353
unit-aes256 unit-chacha20 unit-pci unit-mock-state unit-sectorflags \
5454
unit-max-space \
55-
unit-image unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \
55+
unit-image unit-image-hybrid unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \
5656
unit-enc-nvm-flagshome unit-delta unit-gzip unit-update-flash unit-update-flash-delta \
5757
unit-update-flash-hook \
5858
unit-update-flash-self-update \
@@ -417,6 +417,12 @@ unit-sectorflags: ../../include/target.h unit-sectorflags.c
417417
unit-image: unit-image.c unit-common.c $(WOLFCRYPT_SRC)
418418
gcc -o $@ $^ $(CFLAGS) $(WOLFCRYPT_CFLAGS) $(LDFLAGS)
419419

420+
unit-image-hybrid: ../../include/target.h unit-image.c unit-common.c $(WOLFCRYPT_SRC)
421+
gcc -o $@ unit-image.c unit-common.c $(WOLFCRYPT_SRC) \
422+
$(CFLAGS) $(WOLFCRYPT_CFLAGS) -DUNIT_IMAGE_HYBRID_ONLY \
423+
-DSIGN_HYBRID -DWOLFBOOT_SIGN_SECONDARY_ECC256 \
424+
-DIMAGE_HEADER_SIZE=512 $(LDFLAGS)
425+
420426
unit-image-nopart: ../../include/target.h unit-image.c unit-common.c $(WOLFCRYPT_SRC)
421427
gcc -o $@ unit-image.c unit-common.c $(WOLFCRYPT_SRC) \
422428
$(CFLAGS) $(WOLFCRYPT_CFLAGS) -DWOLFBOOT_NO_PARTITIONS -DMOCK_PARTITIONS \

tools/unit-tests/unit-image.c

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ static int ecc_init_fail = 1;
7979
static int ecc_import_fail = 1;
8080

8181
static int verify_called = 0;
82+
static int verify_hash_count = 0;
83+
static int verify_capture_hashes = 0;
84+
static int verify_reject_hash_mismatch = 0;
85+
static uint8_t verify_hashes[2][WOLFBOOT_SHA_DIGEST_SIZE];
8286

8387
static int find_header_fail = 0;
8488
static int find_header_called = 0;
@@ -263,6 +267,48 @@ static void patch_image_type_part(uint8_t *img, uint32_t img_len, uint16_t part)
263267
ptr[0] = (uint8_t)(type & 0xFF);
264268
ptr[1] = (uint8_t)(type >> 8);
265269
}
270+
271+
static void patch_stored_hash(uint8_t *img, uint32_t img_len)
272+
{
273+
struct wolfBoot_image tmp_img;
274+
uint8_t hash[WOLFBOOT_SHA_DIGEST_SIZE];
275+
uint8_t *stored_sha = NULL;
276+
uint16_t stored_sha_len;
277+
int saved_find_header_mocked = find_header_mocked;
278+
279+
(void)img_len;
280+
find_header_mocked = 0;
281+
memset(&tmp_img, 0, sizeof(tmp_img));
282+
tmp_img.part = PART_BOOT;
283+
tmp_img.hdr = img;
284+
tmp_img.fw_base = img + IMAGE_HEADER_SIZE;
285+
tmp_img.fw_size = wolfBoot_image_size(img);
286+
287+
ck_assert_int_eq(image_hash(&tmp_img, hash), 0);
288+
stored_sha_len = _find_header(img + IMAGE_HEADER_OFFSET, WOLFBOOT_SHA_HDR,
289+
&stored_sha);
290+
ck_assert_uint_eq(stored_sha_len, WOLFBOOT_SHA_DIGEST_SIZE);
291+
memcpy(stored_sha, hash, WOLFBOOT_SHA_DIGEST_SIZE);
292+
find_header_mocked = saved_find_header_mocked;
293+
}
294+
295+
static void append_header_tag(uint8_t *img, uint32_t img_len, uint32_t *idx,
296+
uint16_t type, uint16_t len, const uint8_t *data)
297+
{
298+
ck_assert_ptr_nonnull(img);
299+
ck_assert_ptr_nonnull(idx);
300+
ck_assert_ptr_nonnull(data);
301+
ck_assert_uint_le(*idx + 4U + len, img_len);
302+
ck_assert_uint_le(*idx + 4U + len, IMAGE_HEADER_SIZE);
303+
304+
img[*idx] = (uint8_t)(type & 0xFF);
305+
img[*idx + 1U] = (uint8_t)(type >> 8);
306+
img[*idx + 2U] = (uint8_t)(len & 0xFF);
307+
img[*idx + 3U] = (uint8_t)(len >> 8);
308+
memcpy(img + *idx + 4U, data, len);
309+
*idx += 4U + len;
310+
}
311+
266312
static const unsigned int test_img_len = 275;
267313

268314

@@ -293,6 +339,37 @@ unsigned char test_img_v123_signed_bin[] = {
293339
};
294340
unsigned int test_img_v123_signed_bin_len = 275;
295341

342+
#if defined(UNIT_IMAGE_HYBRID_ONLY)
343+
static void build_hybrid_test_image(uint8_t *img, uint32_t img_len)
344+
{
345+
uint8_t secondary_pubkey_hint[WOLFBOOT_SHA_DIGEST_SIZE];
346+
uint8_t secondary_signature[ECC_IMAGE_SIGNATURE_SIZE];
347+
uint32_t idx = 256U;
348+
uint32_t fixture_payload_len;
349+
350+
ck_assert_uint_ge(IMAGE_HEADER_SIZE, 512U);
351+
ck_assert_uint_ge(img_len, IMAGE_HEADER_SIZE +
352+
wolfBoot_image_size(test_img_v123_signed_bin));
353+
354+
memset(img, 0xFF, img_len);
355+
memcpy(img, test_img_v123_signed_bin, 256U);
356+
357+
fixture_payload_len = test_img_v123_signed_bin_len - 256U;
358+
memcpy(img + IMAGE_HEADER_SIZE, test_img_v123_signed_bin + 256U,
359+
fixture_payload_len);
360+
361+
patch_image_type_auth(img, img_len);
362+
patch_pubkey_hint_slot(img, img_len, 0);
363+
364+
key_hash(2, secondary_pubkey_hint);
365+
memset(secondary_signature, 0, sizeof(secondary_signature));
366+
append_header_tag(img, img_len, &idx, HDR_SECONDARY_PUBKEY,
367+
sizeof(secondary_pubkey_hint), secondary_pubkey_hint);
368+
append_header_tag(img, img_len, &idx, HDR_SECONDARY_SIGNATURE,
369+
sizeof(secondary_signature), secondary_signature);
370+
}
371+
#endif
372+
296373

297374
static uint16_t _find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
298375
{
@@ -388,8 +465,21 @@ int wc_ecc_import_unsigned(ecc_key* key, const byte* qx, const byte* qy,
388465
int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
389466
word32 hashlen, int* res, ecc_key* key)
390467
{
468+
int call_idx = verify_hash_count;
469+
int valid_hash = (hash != NULL && hashlen == WOLFBOOT_SHA_DIGEST_SIZE);
470+
471+
if (verify_capture_hashes && call_idx < 2 && valid_hash) {
472+
memcpy(verify_hashes[call_idx], hash, WOLFBOOT_SHA_DIGEST_SIZE);
473+
}
474+
verify_hash_count++;
391475
verify_called++;
392-
*res = 1;
476+
if (verify_capture_hashes && verify_reject_hash_mismatch &&
477+
call_idx > 0 && valid_hash &&
478+
memcmp(hash, verify_hashes[0], WOLFBOOT_SHA_DIGEST_SIZE) != 0) {
479+
*res = 0;
480+
} else {
481+
*res = 1;
482+
}
393483
return 0;
394484
}
395485
#endif
@@ -685,6 +775,9 @@ START_TEST(test_verify_authenticity)
685775
ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
686776
ext_flash_write(0, test_img_v123_signed_bin,
687777
test_img_v123_signed_bin_len);
778+
memset(&test_img, 0, sizeof(struct wolfBoot_image));
779+
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
780+
ck_assert_int_eq(ret, 0);
688781
test_img.signature_ok = 1; /* mock for VERIFY_FN */
689782
ret = wolfBoot_verify_authenticity(&test_img);
690783
ck_assert_int_eq(ret, 0);
@@ -772,6 +865,7 @@ START_TEST(test_verify_authenticity_allows_permitted_key_mask)
772865
patch_image_type_auth(buf, sizeof(buf));
773866
patch_pubkey_hint_slot(buf, sizeof(buf), 1);
774867
patch_image_type_part(buf, sizeof(buf), HDR_IMG_TYPE_APP);
868+
patch_stored_hash(buf, sizeof(buf));
775869

776870
find_header_mocked = 0;
777871
find_header_fail = 0;
@@ -782,12 +876,59 @@ START_TEST(test_verify_authenticity_allows_permitted_key_mask)
782876
ext_flash_write(0, buf, sizeof(buf));
783877

784878
memset(&test_img, 0, sizeof(struct wolfBoot_image));
785-
test_img.part = PART_UPDATE;
879+
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
880+
ck_assert_int_eq(ret, 0);
786881
test_img.signature_ok = 1;
787882
ret = wolfBoot_verify_authenticity(&test_img);
788883
ck_assert_int_eq(ret, 0);
789884
}
790885
END_TEST
886+
887+
#if defined(UNIT_IMAGE_HYBRID_ONLY) && defined(SIGN_HYBRID) && \
888+
defined(WOLFBOOT_SIGN_SECONDARY_ECC256)
889+
START_TEST(test_verify_authenticity_hybrid_direct_call_uses_verified_sha)
890+
{
891+
struct wolfBoot_image test_img;
892+
uint8_t *stored_sha = NULL;
893+
uint16_t stored_sha_len;
894+
uint32_t image_len;
895+
uint8_t image[IMAGE_HEADER_SIZE + 123U];
896+
int ret;
897+
898+
find_header_mocked = 0;
899+
find_header_fail = 0;
900+
hdr_cpy_done = 0;
901+
ecc_import_fail = 0;
902+
ecc_init_fail = 0;
903+
verify_hash_count = 0;
904+
verify_capture_hashes = 1;
905+
verify_reject_hash_mismatch = 1;
906+
verify_called = 0;
907+
908+
build_hybrid_test_image(image, sizeof(image));
909+
image_len = IMAGE_HEADER_SIZE + wolfBoot_image_size(image);
910+
911+
ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_SECTOR_SIZE);
912+
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS, image, image_len);
913+
914+
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
915+
ck_assert_int_eq(ret, 0);
916+
ck_assert_ptr_null(test_img.sha_hash);
917+
ck_assert_uint_eq(test_img.sha_ok, 0);
918+
919+
ret = wolfBoot_verify_authenticity(&test_img);
920+
ck_assert_int_eq(ret, 0);
921+
922+
stored_sha_len = get_header(&test_img, WOLFBOOT_SHA_HDR, &stored_sha);
923+
ck_assert_uint_eq(stored_sha_len, WOLFBOOT_SHA_DIGEST_SIZE);
924+
ck_assert_uint_eq(test_img.sha_ok, 1);
925+
ck_assert_ptr_eq(test_img.sha_hash, stored_sha);
926+
ck_assert_int_eq(verify_hash_count, 2);
927+
ck_assert_mem_eq(verify_hashes[0], verify_hashes[1],
928+
WOLFBOOT_SHA_DIGEST_SIZE);
929+
}
930+
END_TEST
931+
#endif
791932
#endif
792933

793934
#ifdef WOLFBOOT_FIXED_PARTITIONS
@@ -938,6 +1079,15 @@ Suite *wolfboot_suite(void)
9381079
return s;
9391080
#endif
9401081

1082+
#ifdef UNIT_IMAGE_HYBRID_ONLY
1083+
TCase* tcase_hybrid_auth = tcase_create("hybrid_auth");
1084+
tcase_set_timeout(tcase_hybrid_auth, 20);
1085+
tcase_add_test(tcase_hybrid_auth,
1086+
test_verify_authenticity_hybrid_direct_call_uses_verified_sha);
1087+
suite_add_tcase(s, tcase_hybrid_auth);
1088+
return s;
1089+
#endif
1090+
9411091
#if defined(WOLFBOOT_SIGN_ECC256)
9421092
TCase* tcase_verify_signature = tcase_create("verify_signature");
9431093
tcase_set_timeout(tcase_verify_signature, 20);

0 commit comments

Comments
 (0)