Skip to content

Commit 43f2273

Browse files
committed
Added extra verify step in encrypted fallback
Using the original IV
1 parent 9eca74d commit 43f2273

6 files changed

Lines changed: 242 additions & 13 deletions

File tree

include/encrypt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ int ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len);
8686

8787
#ifdef EXT_ENCRYPTED
8888
int wolfBoot_enable_fallback_iv(int enable);
89+
int wolfBoot_force_fallback_iv(int enable);
8990
void wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter);
9091
#endif
9192

src/libwolfboot.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static int encrypt_initialized = 0;
6868

6969
static uint8_t encrypt_iv_nonce[ENCRYPT_NONCE_SIZE] XALIGNED(4);
7070
static uint32_t encrypt_iv_offset = 0;
71+
static int fallback_iv_forced = 0;
7172

7273
#define FALLBACK_IV_OFFSET 0x00100000U
7374
#if !defined(XMEMSET)
@@ -1395,6 +1396,13 @@ int RAMFUNCTION wolfBoot_enable_fallback_iv(int enable)
13951396
return prev;
13961397
}
13971398

1399+
int RAMFUNCTION wolfBoot_force_fallback_iv(int enable)
1400+
{
1401+
int prev = fallback_iv_forced;
1402+
fallback_iv_forced = enable ? 1 : 0;
1403+
return prev;
1404+
}
1405+
13981406
void RAMFUNCTION wolfBoot_crypto_set_iv(const uint8_t *nonce, uint32_t iv_counter)
13991407
{
14001408
#if defined(ENCRYPT_WITH_CHACHA)
@@ -2174,6 +2182,8 @@ int RAMFUNCTION ext_flash_decrypt_read(uintptr_t address, uint8_t *data, int len
21742182
return -1;
21752183
}
21762184
}
2185+
if (fallback_iv_forced)
2186+
encrypt_iv_offset = FALLBACK_IV_OFFSET;
21772187
wolfBoot_crypto_set_iv(encrypt_iv_nonce, iv_counter);
21782188
break;
21792189
case PART_SWAP:

src/update_flash.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -774,14 +774,22 @@ static int RAMFUNCTION wolfBoot_update(int fallback_allowed)
774774
return -1;
775775
}
776776
} else {
777-
/*
778-
* When we recover an already-encrypted fallback image, the
779-
* manifest still contains hashes computed with the original IV
780-
* stream. Skip the redundant integrity/authenticity checks here
781-
* and let the bootloader verify the restored image after the swap.
782-
*/
783-
update.sha_ok = 1;
784-
update.signature_ok = 1;
777+
#ifdef EXT_ENCRYPTED
778+
int prev = wolfBoot_force_fallback_iv(1);
779+
#endif
780+
if (!update.hdr_ok
781+
|| (wolfBoot_verify_integrity(&update) < 0)
782+
|| (wolfBoot_verify_authenticity(&update) < 0)) {
783+
#ifdef EXT_ENCRYPTED
784+
wolfBoot_force_fallback_iv(prev);
785+
#endif
786+
wolfBoot_printf("Update verify failed: Hdr %d, Hash %d, Sig %d\n",
787+
update.hdr_ok, update.sha_ok, update.signature_ok);
788+
return -1;
789+
}
790+
#ifdef EXT_ENCRYPTED
791+
wolfBoot_force_fallback_iv(prev);
792+
#endif
785793
}
786794
PART_SANITY_CHECK(&update);
787795

tools/unit-tests/Makefile

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ LDFLAGS+=-ftest-coverage
2828
TESTS:=unit-parser unit-extflash unit-string unit-spi-flash unit-aes128 \
2929
unit-aes256 unit-chacha20 unit-pci unit-mock-state unit-sectorflags \
3030
unit-image unit-nvm unit-nvm-flagshome unit-enc-nvm \
31-
unit-enc-nvm-flagshome unit-delta unit-update-flash unit-update-ram \
32-
unit-pkcs11_store
31+
unit-enc-nvm-flagshome unit-delta unit-update-flash \
32+
unit-update-flash-enc unit-update-ram unit-pkcs11_store
3333

3434
all: $(TESTS)
3535

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

140+
unit-update-flash-enc:CFLAGS+=-DMOCK_PARTITIONS -DWOLFBOOT_NO_SIGN -DUNIT_TEST_AUTH \
141+
-DWOLFBOOT_HASH_SHA256 -DPRINTF_ENABLED -DEXT_FLASH -DPART_UPDATE_EXT \
142+
-DPART_SWAP_EXT -DEXT_ENCRYPTED -DENCRYPT_WITH_CHACHA -DHAVE_CHACHA \
143+
-DCUSTOM_ENCRYPT_KEY -DUNIT_TEST_FALLBACK_ONLY
144+
unit-update-flash-enc: ../../include/target.h unit-update-flash.c
145+
gcc -o $@ unit-update-flash.c ../../src/image.c \
146+
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c \
147+
$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/chacha.c \
148+
$(CFLAGS) $(LDFLAGS)
149+
140150
unit-update-ram: ../../include/target.h unit-update-ram.c
141151
gcc -o $@ unit-update-ram.c ../../src/image.c $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.c $(CFLAGS) $(LDFLAGS)
142152

tools/unit-tests/unit-mock-flash.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,18 @@ int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
163163
int i;
164164
uint8_t *a = (uint8_t *)address;
165165
ck_assert_msg(!ext_locked, "Attempting to write to a locked FLASH");
166+
ck_assert_msg(
167+
((address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) &&
168+
(address + (uintptr_t)len <=
169+
WOLFBOOT_PARTITION_BOOT_ADDRESS + WOLFBOOT_PARTITION_SIZE)) ||
170+
((address >= WOLFBOOT_PARTITION_UPDATE_ADDRESS) &&
171+
(address + (uintptr_t)len <=
172+
WOLFBOOT_PARTITION_UPDATE_ADDRESS + WOLFBOOT_PARTITION_SIZE)) ||
173+
((address >= WOLFBOOT_PARTITION_SWAP_ADDRESS) &&
174+
(address + (uintptr_t)len <=
175+
WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE)),
176+
"ext_flash_write address out of range: %p len %d",
177+
(void*)address, len);
166178
for (i = 0; i < len; i++) {
167179
a[i] = data[i];
168180
}
@@ -190,6 +202,11 @@ void ext_flash_lock(void)
190202
ext_locked++;
191203
}
192204

205+
void ext_flash_reset_lock(void)
206+
{
207+
ext_locked = 1;
208+
}
209+
193210

194211
/* A simple mock memory */
195212
static int mmap_file(const char *path, uint8_t *address, uint32_t len,

tools/unit-tests/unit-update-flash.c

Lines changed: 186 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,32 @@ static void reset_mock_stats(void);
5252
static void prepare_flash(void);
5353
static void cleanup_flash(void);
5454

55+
#ifdef CUSTOM_ENCRYPT_KEY
56+
int wolfBoot_get_encrypt_key(uint8_t *k, uint8_t *nonce)
57+
{
58+
int i;
59+
for (i = 0; i < ENCRYPT_KEY_SIZE; i++) {
60+
k[i] = (uint8_t)(i + 1);
61+
}
62+
for (i = 0; i < ENCRYPT_NONCE_SIZE; i++) {
63+
nonce[i] = (uint8_t)(0xA5 + i);
64+
}
65+
return 0;
66+
}
67+
68+
int wolfBoot_set_encrypt_key(const uint8_t *key, const uint8_t *nonce)
69+
{
70+
(void)key;
71+
(void)nonce;
72+
return 0;
73+
}
74+
75+
int wolfBoot_erase_encrypt_key(void)
76+
{
77+
return 0;
78+
}
79+
#endif
80+
5581
START_TEST (test_boot_success_sets_state)
5682
{
5783
uint8_t state = 0;
@@ -90,6 +116,7 @@ static void reset_mock_stats(void)
90116
{
91117
wolfBoot_staged_ok = 0;
92118
wolfBoot_panicked = 0;
119+
ext_flash_reset_lock();
93120
}
94121

95122

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

199226
}
200227

228+
#ifdef EXT_ENCRYPTED
229+
static int build_image_buffer(uint8_t part, uint32_t version, uint32_t size,
230+
uint8_t *buf, uint32_t buf_sz)
231+
{
232+
uint32_t word;
233+
uint16_t word16;
234+
uint32_t total = size + IMAGE_HEADER_SIZE;
235+
int i;
236+
int ret;
237+
wc_Sha256 sha;
238+
uint8_t digest[SHA256_DIGEST_SIZE];
239+
240+
if (buf_sz < total)
241+
return -1;
242+
243+
memset(buf, 0xFF, buf_sz);
244+
245+
ret = wc_InitSha256_ex(&sha, NULL, INVALID_DEVID);
246+
if (ret != 0)
247+
return ret;
248+
249+
memcpy(buf, "WOLF", 4);
250+
memcpy(buf + 4, &size, 4);
251+
252+
word = 4 << 16 | HDR_VERSION;
253+
memcpy(buf + 8, &word, 4);
254+
memcpy(buf + 12, &version, 4);
255+
256+
word = 2 << 16 | HDR_IMG_TYPE;
257+
memcpy(buf + 16, &word, 4);
258+
word16 = HDR_IMG_TYPE_AUTH_NONE | HDR_IMG_TYPE_APP;
259+
memcpy(buf + 20, &word16, 2);
260+
261+
ret = wc_Sha256Update(&sha, buf, DIGEST_TLV_OFF_IN_HDR);
262+
if (ret != 0)
263+
return ret;
264+
265+
srandom(part);
266+
for (i = IMAGE_HEADER_SIZE; i < (int)total; i += 4) {
267+
uint32_t rnd = (random() << 16) | random();
268+
memcpy(buf + i, &rnd, 4);
269+
}
270+
for (i = IMAGE_HEADER_SIZE; i < (int)total; i += WOLFBOOT_SHA_BLOCK_SIZE) {
271+
int len = WOLFBOOT_SHA_BLOCK_SIZE;
272+
if ((int)total - i < len)
273+
len = (int)total - i;
274+
ret = wc_Sha256Update(&sha, buf + i, len);
275+
if (ret != 0)
276+
return ret;
277+
}
278+
279+
ret = wc_Sha256Final(&sha, digest);
280+
if (ret != 0)
281+
return ret;
282+
wc_Sha256Free(&sha);
283+
284+
word = SHA256_DIGEST_SIZE << 16 | HDR_SHA256;
285+
memcpy(buf + DIGEST_TLV_OFF_IN_HDR, &word, 4);
286+
memcpy(buf + DIGEST_TLV_OFF_IN_HDR + 4, digest, SHA256_DIGEST_SIZE);
287+
288+
return 0;
289+
}
290+
291+
static int add_payload_encrypted(uint8_t part, uint32_t version, uint32_t size,
292+
int use_fallback_iv)
293+
{
294+
uint32_t total = size + IMAGE_HEADER_SIZE;
295+
uint8_t *buf = NULL;
296+
uintptr_t base = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
297+
int ret;
298+
int prev = 0;
299+
300+
if (part == PART_BOOT)
301+
base = (uintptr_t)WOLFBOOT_PARTITION_BOOT_ADDRESS;
302+
else if (part == PART_UPDATE)
303+
base = (uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS;
304+
else
305+
return -1;
306+
307+
buf = malloc(total);
308+
if (!buf)
309+
return -1;
310+
311+
ret = build_image_buffer(part, version, size, buf, total);
312+
if (ret != 0) {
313+
free(buf);
314+
return ret;
315+
}
316+
317+
if (use_fallback_iv)
318+
prev = wolfBoot_enable_fallback_iv(1);
319+
320+
ext_flash_unlock();
321+
{
322+
uint32_t off = 0;
323+
while (off < total) {
324+
uint32_t chunk = total - off;
325+
if (chunk > WOLFBOOT_SECTOR_SIZE)
326+
chunk = WOLFBOOT_SECTOR_SIZE;
327+
ret = ext_flash_encrypt_write(base + off, buf + off, chunk);
328+
if (ret != 0)
329+
break;
330+
off += chunk;
331+
}
332+
}
333+
ext_flash_lock();
334+
335+
if (use_fallback_iv)
336+
wolfBoot_enable_fallback_iv(prev);
337+
338+
free(buf);
339+
return ret;
340+
}
341+
#endif
342+
201343
START_TEST (test_empty_panic)
202344
{
203345
reset_mock_stats();
@@ -210,6 +352,31 @@ START_TEST (test_empty_panic)
210352
}
211353
END_TEST
212354

355+
#ifdef EXT_ENCRYPTED
356+
START_TEST (test_fallback_image_verification_rejects_corruption)
357+
{
358+
int ret;
359+
uint8_t bad = 0x00;
360+
361+
reset_mock_stats();
362+
prepare_flash();
363+
364+
add_payload(PART_BOOT, 1, TEST_SIZE_SMALL);
365+
ret = add_payload_encrypted(PART_UPDATE, 2, TEST_SIZE_SMALL, 1);
366+
ck_assert_int_eq(ret, 0);
367+
368+
ext_flash_unlock();
369+
ext_flash_write((uintptr_t)WOLFBOOT_PARTITION_UPDATE_ADDRESS +
370+
IMAGE_HEADER_SIZE + 16, &bad, 1);
371+
ext_flash_lock();
372+
373+
ret = wolfBoot_update(1);
374+
ck_assert_int_eq(ret, -1);
375+
376+
cleanup_flash();
377+
}
378+
END_TEST
379+
#endif
213380

214381
START_TEST (test_sunnyday_noupdate)
215382
{
@@ -498,6 +665,9 @@ Suite *wolfboot_suite(void)
498665
Suite *s = suite_create("wolfboot");
499666

500667
/* Test cases */
668+
#ifdef UNIT_TEST_FALLBACK_ONLY
669+
TCase *fallback_verify = tcase_create("Fallback verify");
670+
#else
501671
TCase *empty_panic = tcase_create("Empty partition panic test");
502672
TCase *sunnyday_noupdate =
503673
tcase_create("Sunny day test with no update available");
@@ -521,9 +691,17 @@ Suite *wolfboot_suite(void)
521691
TCase *swap_resume = tcase_create("Swap resume noop");
522692
TCase *diffbase_version = tcase_create("Diffbase version lookup");
523693
TCase *boot_success = tcase_create("Boot success state");
694+
#ifdef EXT_ENCRYPTED
695+
TCase *fallback_verify = tcase_create("Fallback verify");
696+
#endif
697+
#endif
524698

525699

526-
700+
#ifdef UNIT_TEST_FALLBACK_ONLY
701+
tcase_add_test(fallback_verify, test_fallback_image_verification_rejects_corruption);
702+
suite_add_tcase(s, fallback_verify);
703+
return s;
704+
#else
527705
tcase_add_test(empty_panic, test_empty_panic);
528706
tcase_add_test(sunnyday_noupdate, test_sunnyday_noupdate);
529707
tcase_add_test(forward_update_samesize, test_forward_update_samesize);
@@ -541,8 +719,9 @@ Suite *wolfboot_suite(void)
541719
tcase_add_test(swap_resume, test_swap_resume_noop);
542720
tcase_add_test(diffbase_version, test_diffbase_version_reads);
543721
tcase_add_test(boot_success, test_boot_success_sets_state);
544-
545-
722+
#ifdef EXT_ENCRYPTED
723+
tcase_add_test(fallback_verify, test_fallback_image_verification_rejects_corruption);
724+
#endif
546725

547726
suite_add_tcase(s, empty_panic);
548727
suite_add_tcase(s, sunnyday_noupdate);
@@ -561,6 +740,10 @@ Suite *wolfboot_suite(void)
561740
suite_add_tcase(s, swap_resume);
562741
suite_add_tcase(s, diffbase_version);
563742
suite_add_tcase(s, boot_success);
743+
#ifdef EXT_ENCRYPTED
744+
suite_add_tcase(s, fallback_verify);
745+
#endif
746+
#endif
564747

565748

566749

0 commit comments

Comments
 (0)