Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 2 additions & 3 deletions src/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -2305,10 +2305,9 @@ int wolfBoot_verify_authenticity(struct wolfBoot_image *img)
image_type = (uint16_t)(image_type_buf[0] + (image_type_buf[1] << 8));
if ((image_type & HDR_IMG_TYPE_AUTH_MASK) != HDR_IMG_TYPE_AUTH)
return -1;
if (img->sha_hash == NULL) {
if (image_hash(img, digest) != 0)
if ((img->sha_hash == NULL) || (img->sha_ok != 1U)) {
if (wolfBoot_verify_integrity(img) != 0)
return -1;
img->sha_hash = digest;
}
Comment thread
mattia-moffa marked this conversation as resolved.
image_part = image_type & HDR_IMG_TYPE_PART_MASK;
#ifdef WOLFBOOT_NO_KEYSTORE
Expand Down
8 changes: 7 additions & 1 deletion tools/unit-tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128
unit-uart-flash \
unit-aes256 unit-chacha20 unit-pci unit-mock-state unit-sectorflags \
unit-max-space \
unit-image unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \
unit-image unit-image-hybrid unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \
unit-enc-nvm-flagshome unit-delta unit-gzip unit-update-flash unit-update-flash-delta \
unit-update-flash-hook \
unit-update-flash-self-update \
Expand Down Expand Up @@ -417,6 +417,12 @@ unit-sectorflags: ../../include/target.h unit-sectorflags.c
unit-image: unit-image.c unit-common.c $(WOLFCRYPT_SRC)
gcc -o $@ $^ $(CFLAGS) $(WOLFCRYPT_CFLAGS) $(LDFLAGS)

unit-image-hybrid: ../../include/target.h unit-image.c unit-common.c $(WOLFCRYPT_SRC)
gcc -o $@ unit-image.c unit-common.c $(WOLFCRYPT_SRC) \
$(CFLAGS) $(WOLFCRYPT_CFLAGS) -DUNIT_IMAGE_HYBRID_ONLY \
-DSIGN_HYBRID -DWOLFBOOT_SIGN_SECONDARY_ECC256 \
-DIMAGE_HEADER_SIZE=512 $(LDFLAGS)

unit-image-nopart: ../../include/target.h unit-image.c unit-common.c $(WOLFCRYPT_SRC)
gcc -o $@ unit-image.c unit-common.c $(WOLFCRYPT_SRC) \
$(CFLAGS) $(WOLFCRYPT_CFLAGS) -DWOLFBOOT_NO_PARTITIONS -DMOCK_PARTITIONS \
Expand Down
162 changes: 160 additions & 2 deletions tools/unit-tests/unit-image.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ static int ecc_init_fail = 1;
static int ecc_import_fail = 1;

static int verify_called = 0;
static int verify_hash_count = 0;
static int verify_capture_hashes = 0;
static int verify_reject_hash_mismatch = 0;
static uint8_t verify_hashes[2][WOLFBOOT_SHA_DIGEST_SIZE];

static int find_header_fail = 0;
static int find_header_called = 0;
Expand Down Expand Up @@ -263,6 +267,48 @@ static void patch_image_type_part(uint8_t *img, uint32_t img_len, uint16_t part)
ptr[0] = (uint8_t)(type & 0xFF);
ptr[1] = (uint8_t)(type >> 8);
}

static void patch_stored_hash(uint8_t *img, uint32_t img_len)
{
struct wolfBoot_image tmp_img;
uint8_t hash[WOLFBOOT_SHA_DIGEST_SIZE];
uint8_t *stored_sha = NULL;
uint16_t stored_sha_len;
int saved_find_header_mocked = find_header_mocked;

(void)img_len;
find_header_mocked = 0;
memset(&tmp_img, 0, sizeof(tmp_img));
tmp_img.part = PART_BOOT;
tmp_img.hdr = img;
tmp_img.fw_base = img + IMAGE_HEADER_SIZE;
tmp_img.fw_size = wolfBoot_image_size(img);

ck_assert_int_eq(image_hash(&tmp_img, hash), 0);
stored_sha_len = _find_header(img + IMAGE_HEADER_OFFSET, WOLFBOOT_SHA_HDR,
&stored_sha);
ck_assert_uint_eq(stored_sha_len, WOLFBOOT_SHA_DIGEST_SIZE);
memcpy(stored_sha, hash, WOLFBOOT_SHA_DIGEST_SIZE);
find_header_mocked = saved_find_header_mocked;
}

static void append_header_tag(uint8_t *img, uint32_t img_len, uint32_t *idx,
uint16_t type, uint16_t len, const uint8_t *data)
{
ck_assert_ptr_nonnull(img);
ck_assert_ptr_nonnull(idx);
ck_assert_ptr_nonnull(data);
ck_assert_uint_le(*idx + 4U + len, img_len);
ck_assert_uint_le(*idx + 4U + len, IMAGE_HEADER_SIZE);

img[*idx] = (uint8_t)(type & 0xFF);
img[*idx + 1U] = (uint8_t)(type >> 8);
img[*idx + 2U] = (uint8_t)(len & 0xFF);
img[*idx + 3U] = (uint8_t)(len >> 8);
memcpy(img + *idx + 4U, data, len);
*idx += 4U + len;
}

static const unsigned int test_img_len = 275;


Expand Down Expand Up @@ -293,6 +339,37 @@ unsigned char test_img_v123_signed_bin[] = {
};
unsigned int test_img_v123_signed_bin_len = 275;

#if defined(UNIT_IMAGE_HYBRID_ONLY)
static void build_hybrid_test_image(uint8_t *img, uint32_t img_len)
{
uint8_t secondary_pubkey_hint[WOLFBOOT_SHA_DIGEST_SIZE];
uint8_t secondary_signature[ECC_IMAGE_SIGNATURE_SIZE];
uint32_t idx = 256U;
uint32_t fixture_payload_len;

ck_assert_uint_ge(IMAGE_HEADER_SIZE, 512U);
ck_assert_uint_ge(img_len, IMAGE_HEADER_SIZE +
wolfBoot_image_size(test_img_v123_signed_bin));

memset(img, 0xFF, img_len);
memcpy(img, test_img_v123_signed_bin, 256U);

fixture_payload_len = test_img_v123_signed_bin_len - 256U;
memcpy(img + IMAGE_HEADER_SIZE, test_img_v123_signed_bin + 256U,
fixture_payload_len);

patch_image_type_auth(img, img_len);
patch_pubkey_hint_slot(img, img_len, 0);

key_hash(2, secondary_pubkey_hint);
memset(secondary_signature, 0, sizeof(secondary_signature));
append_header_tag(img, img_len, &idx, HDR_SECONDARY_PUBKEY,
sizeof(secondary_pubkey_hint), secondary_pubkey_hint);
append_header_tag(img, img_len, &idx, HDR_SECONDARY_SIGNATURE,
sizeof(secondary_signature), secondary_signature);
}
#endif


static uint16_t _find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
{
Expand Down Expand Up @@ -388,8 +465,21 @@ int wc_ecc_import_unsigned(ecc_key* key, const byte* qx, const byte* qy,
int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
word32 hashlen, int* res, ecc_key* key)
{
int call_idx = verify_hash_count;
int valid_hash = (hash != NULL && hashlen == WOLFBOOT_SHA_DIGEST_SIZE);

if (verify_capture_hashes && call_idx < 2 && valid_hash) {
memcpy(verify_hashes[call_idx], hash, WOLFBOOT_SHA_DIGEST_SIZE);
}
verify_hash_count++;
verify_called++;
*res = 1;
if (verify_capture_hashes && verify_reject_hash_mismatch &&
call_idx > 0 && valid_hash &&
memcmp(hash, verify_hashes[0], WOLFBOOT_SHA_DIGEST_SIZE) != 0) {
*res = 0;
} else {
*res = 1;
}
return 0;
}
#endif
Expand Down Expand Up @@ -648,6 +738,7 @@ START_TEST(test_headers)
}

#if defined(WOLFBOOT_SIGN_ECC256)
#ifdef WOLFBOOT_FIXED_PARTITIONS
START_TEST(test_verify_authenticity)
{
struct wolfBoot_image test_img;
Expand Down Expand Up @@ -685,12 +776,16 @@ START_TEST(test_verify_authenticity)
ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
ext_flash_write(0, test_img_v123_signed_bin,
test_img_v123_signed_bin_len);
memset(&test_img, 0, sizeof(struct wolfBoot_image));
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
ck_assert_int_eq(ret, 0);
test_img.signature_ok = 1; /* mock for VERIFY_FN */
ret = wolfBoot_verify_authenticity(&test_img);
ck_assert_int_eq(ret, 0);

}
END_TEST
#endif /* WOLFBOOT_FIXED_PARTITIONS */

START_TEST(test_verify_authenticity_bad_siglen)
{
Expand Down Expand Up @@ -762,6 +857,7 @@ START_TEST(test_verify_authenticity_rejects_disallowed_key_mask)
}
END_TEST

#ifdef WOLFBOOT_FIXED_PARTITIONS
START_TEST(test_verify_authenticity_allows_permitted_key_mask)
{
struct wolfBoot_image test_img;
Expand All @@ -772,6 +868,7 @@ START_TEST(test_verify_authenticity_allows_permitted_key_mask)
patch_image_type_auth(buf, sizeof(buf));
patch_pubkey_hint_slot(buf, sizeof(buf), 1);
patch_image_type_part(buf, sizeof(buf), HDR_IMG_TYPE_APP);
patch_stored_hash(buf, sizeof(buf));

find_header_mocked = 0;
find_header_fail = 0;
Expand All @@ -782,12 +879,60 @@ START_TEST(test_verify_authenticity_allows_permitted_key_mask)
ext_flash_write(0, buf, sizeof(buf));

memset(&test_img, 0, sizeof(struct wolfBoot_image));
test_img.part = PART_UPDATE;
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
ck_assert_int_eq(ret, 0);
test_img.signature_ok = 1;
ret = wolfBoot_verify_authenticity(&test_img);
ck_assert_int_eq(ret, 0);
}
END_TEST
#endif /* WOLFBOOT_FIXED_PARTITIONS */

#if defined(UNIT_IMAGE_HYBRID_ONLY) && defined(SIGN_HYBRID) && \
defined(WOLFBOOT_SIGN_SECONDARY_ECC256)
START_TEST(test_verify_authenticity_hybrid_direct_call_uses_verified_sha)
{
struct wolfBoot_image test_img;
uint8_t *stored_sha = NULL;
uint16_t stored_sha_len;
uint32_t image_len;
uint8_t image[IMAGE_HEADER_SIZE + 123U];
int ret;

find_header_mocked = 0;
find_header_fail = 0;
hdr_cpy_done = 0;
ecc_import_fail = 0;
ecc_init_fail = 0;
verify_hash_count = 0;
verify_capture_hashes = 1;
verify_reject_hash_mismatch = 1;
verify_called = 0;

build_hybrid_test_image(image, sizeof(image));
image_len = IMAGE_HEADER_SIZE + wolfBoot_image_size(image);

ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_SECTOR_SIZE);
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS, image, image_len);

ret = wolfBoot_open_image(&test_img, PART_UPDATE);
ck_assert_int_eq(ret, 0);
ck_assert_ptr_null(test_img.sha_hash);
ck_assert_uint_eq(test_img.sha_ok, 0);

ret = wolfBoot_verify_authenticity(&test_img);
ck_assert_int_eq(ret, 0);

stored_sha_len = get_header(&test_img, WOLFBOOT_SHA_HDR, &stored_sha);
ck_assert_uint_eq(stored_sha_len, WOLFBOOT_SHA_DIGEST_SIZE);
ck_assert_uint_eq(test_img.sha_ok, 1);
ck_assert_ptr_eq(test_img.sha_hash, stored_sha);
ck_assert_int_eq(verify_hash_count, 2);
ck_assert_mem_eq(verify_hashes[0], verify_hashes[1],
WOLFBOOT_SHA_DIGEST_SIZE);
}
END_TEST
#endif
#endif

#ifdef WOLFBOOT_FIXED_PARTITIONS
Expand Down Expand Up @@ -938,6 +1083,15 @@ Suite *wolfboot_suite(void)
return s;
#endif

#ifdef UNIT_IMAGE_HYBRID_ONLY
TCase* tcase_hybrid_auth = tcase_create("hybrid_auth");
tcase_set_timeout(tcase_hybrid_auth, 20);
tcase_add_test(tcase_hybrid_auth,
test_verify_authenticity_hybrid_direct_call_uses_verified_sha);
suite_add_tcase(s, tcase_hybrid_auth);
return s;
#endif

#if defined(WOLFBOOT_SIGN_ECC256)
TCase* tcase_verify_signature = tcase_create("verify_signature");
tcase_set_timeout(tcase_verify_signature, 20);
Expand All @@ -960,14 +1114,18 @@ Suite *wolfboot_suite(void)
#if defined(WOLFBOOT_SIGN_ECC256)
TCase* tcase_verify_authenticity = tcase_create("verify_authenticity");
tcase_set_timeout(tcase_verify_authenticity, 20);
#ifdef WOLFBOOT_FIXED_PARTITIONS
tcase_add_test(tcase_verify_authenticity, test_verify_authenticity);
#endif /* WOLFBOOT_FIXED_PARTITIONS */
tcase_add_test(tcase_verify_authenticity, test_verify_authenticity_bad_siglen);
tcase_add_test(tcase_verify_authenticity,
test_verify_authenticity_rejects_mismatched_auth_type);
tcase_add_test(tcase_verify_authenticity,
test_verify_authenticity_rejects_disallowed_key_mask);
#ifdef WOLFBOOT_FIXED_PARTITIONS
tcase_add_test(tcase_verify_authenticity,
test_verify_authenticity_allows_permitted_key_mask);
#endif /* WOLFBOOT_FIXED_PARTITIONS */
suite_add_tcase(s, tcase_verify_authenticity);
#endif

Expand Down
Loading