1212#include <sys/stat.h>
1313#include <unistd.h>
1414
15+ #define WOLFBOOT_HASH_SHA256
16+ #define IMAGE_HEADER_SIZE 512
17+
1518static const char * mock_fail_open_path ;
1619static int mock_fail_open_on_call ;
1720static int mock_open_call_count ;
@@ -40,6 +43,45 @@ static int mock_fprintf(FILE *stream, const char *format, ...);
4043#undef fopen
4144#undef main
4245
46+ #include "../../src/libwolfboot.c"
47+
48+ static int locked ;
49+
50+ void hal_init (void )
51+ {
52+ }
53+
54+ int hal_flash_write (haladdr_t address , const uint8_t * data , int len )
55+ {
56+ (void )address ;
57+ (void )data ;
58+ (void )len ;
59+ return 0 ;
60+ }
61+
62+ int hal_flash_erase (haladdr_t address , int len )
63+ {
64+ (void )address ;
65+ (void )len ;
66+ return 0 ;
67+ }
68+
69+ void hal_flash_unlock (void )
70+ {
71+ ck_assert_msg (locked , "Double unlock detected\n" );
72+ locked -- ;
73+ }
74+
75+ void hal_flash_lock (void )
76+ {
77+ ck_assert_msg (!locked , "Double lock detected\n" );
78+ locked ++ ;
79+ }
80+
81+ void hal_prepare_boot (void )
82+ {
83+ }
84+
4385static void reset_mocks (const char * fail_open_path , int fail_open_on_call )
4486{
4587 mock_fail_open_path = fail_open_path ;
@@ -127,6 +169,89 @@ static int write_file(const char *path, const void *buf, size_t len)
127169 return written == len ? 0 : -1 ;
128170}
129171
172+ static int read_file (const char * path , uint8_t * * buf , size_t * len )
173+ {
174+ FILE * f ;
175+ struct stat st ;
176+ size_t read_len ;
177+
178+ if (stat (path , & st ) != 0 ) {
179+ return -1 ;
180+ }
181+
182+ * buf = malloc ((size_t )st .st_size );
183+ if (* buf == NULL ) {
184+ return -1 ;
185+ }
186+
187+ f = fopen (path , "rb" );
188+ if (f == NULL ) {
189+ free (* buf );
190+ * buf = NULL ;
191+ return -1 ;
192+ }
193+
194+ read_len = fread (* buf , 1 , (size_t )st .st_size , f );
195+ fclose (f );
196+ if (read_len != (size_t )st .st_size ) {
197+ free (* buf );
198+ * buf = NULL ;
199+ return -1 ;
200+ }
201+
202+ * len = read_len ;
203+ return 0 ;
204+ }
205+
206+ static void reset_cmd_defaults (void )
207+ {
208+ memset (& CMD , 0 , sizeof (CMD ));
209+ CMD .sign = NO_SIGN ;
210+ CMD .hash_algo = HASH_SHA256 ;
211+ CMD .partition_id = HDR_IMG_TYPE_APP ;
212+ CMD .header_sz = IMAGE_HEADER_SIZE ;
213+ CMD .fw_version = "7" ;
214+ CMD .no_ts = 1 ;
215+ }
216+
217+ static void free_custom_tlv_buffers (void )
218+ {
219+ uint32_t i ;
220+
221+ for (i = 0 ; i < MAX_CUSTOM_TLVS ; i ++ ) {
222+ free (CMD .custom_tlv [i ].buffer );
223+ CMD .custom_tlv [i ].buffer = NULL ;
224+ }
225+ }
226+
227+ static void assert_header_bytes (const uint8_t * image , uint16_t tag ,
228+ const uint8_t * expected , uint16_t expected_len )
229+ {
230+ uint8_t * value = NULL ;
231+ uint16_t len = wolfBoot_find_header ((uint8_t * )image + IMAGE_HEADER_OFFSET ,
232+ tag , & value );
233+
234+ ck_assert_uint_eq (len , expected_len );
235+ ck_assert_ptr_nonnull (value );
236+ ck_assert_msg (memcmp (value , expected , expected_len ) == 0 ,
237+ "Tag 0x%04x mismatch" , tag );
238+ }
239+
240+ static uint16_t find_exact_fill_custom_len (void )
241+ {
242+ uint16_t len ;
243+
244+ for (len = 1 ; len < IMAGE_HEADER_SIZE ; len ++ ) {
245+ CMD .custom_tlvs = 1 ;
246+ CMD .custom_tlv [0 ].len = len ;
247+ if (header_required_size (0 , 0 , 0 ) == CMD .header_sz ) {
248+ return len ;
249+ }
250+ }
251+
252+ return 0 ;
253+ }
254+
130255START_TEST (test_make_header_ex_fails_when_encrypted_output_open_fails )
131256{
132257 char tempdir [] = "/tmp/wolfboot-sign-XXXXXX" ;
@@ -151,14 +276,9 @@ START_TEST(test_make_header_ex_fails_when_encrypted_output_open_fails)
151276 ck_assert_int_eq (write_file (image_path , image_buf , sizeof (image_buf )), 0 );
152277 ck_assert_int_eq (write_file (key_path , key_buf , sizeof (key_buf )), 0 );
153278
154- memset (& CMD , 0 , sizeof (CMD ));
155- CMD .sign = NO_SIGN ;
279+ reset_cmd_defaults ();
156280 CMD .encrypt = ENC_AES128 ;
157- CMD .hash_algo = HASH_SHA256 ;
158- CMD .partition_id = HDR_IMG_TYPE_APP ;
159281 CMD .header_sz = 256 ;
160- CMD .fw_version = "7" ;
161- CMD .no_ts = 1 ;
162282 CMD .encrypt_key_file = key_path ;
163283 snprintf (CMD .output_encrypted_image_file ,
164284 sizeof (CMD .output_encrypted_image_file ), "%s" , encrypted_output_path );
@@ -197,13 +317,8 @@ START_TEST(test_make_header_ex_fails_when_image_reopen_fails)
197317
198318 ck_assert_int_eq (write_file (image_path , image_buf , sizeof (image_buf )), 0 );
199319
200- memset (& CMD , 0 , sizeof (CMD ));
201- CMD .sign = NO_SIGN ;
202- CMD .hash_algo = HASH_SHA256 ;
203- CMD .partition_id = HDR_IMG_TYPE_APP ;
320+ reset_cmd_defaults ();
204321 CMD .header_sz = 256 ;
205- CMD .fw_version = "7" ;
206- CMD .no_ts = 1 ;
207322
208323 reset_mocks (image_path , 2 );
209324 ret = make_header_ex (0 , pubkey , sizeof (pubkey ), image_path , output_path ,
@@ -226,10 +341,13 @@ START_TEST(test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs)
226341 char image_path [PATH_MAX ];
227342 char output_path [PATH_MAX ];
228343 char cert_chain_path [PATH_MAX ];
344+ uint8_t * output_buf = NULL ;
345+ uint8_t * value = NULL ;
229346 uint8_t image_buf [] = { 0x01 , 0x02 , 0x03 , 0x04 };
230347 uint8_t cert_chain_buf [200 ];
231348 uint8_t pubkey [] = { 0xA5 };
232349 struct stat st ;
350+ size_t output_len ;
233351 int ret ;
234352
235353 ck_assert_ptr_nonnull (mkdtemp (tempdir ));
@@ -244,13 +362,8 @@ START_TEST(test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs)
244362 ck_assert_int_eq (write_file (cert_chain_path , cert_chain_buf ,
245363 sizeof (cert_chain_buf )), 0 );
246364
247- memset (& CMD , 0 , sizeof (CMD ));
248- CMD .sign = NO_SIGN ;
249- CMD .hash_algo = HASH_SHA256 ;
250- CMD .partition_id = HDR_IMG_TYPE_APP ;
365+ reset_cmd_defaults ();
251366 CMD .header_sz = 256 ;
252- CMD .fw_version = "7" ;
253- CMD .no_ts = 1 ;
254367 CMD .cert_chain_file = cert_chain_path ;
255368
256369 reset_mocks (NULL , 0 );
@@ -264,14 +377,155 @@ START_TEST(test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs)
264377 ck_assert_int_eq (mock_null_fwrite_calls , 0 );
265378 ck_assert_int_eq (mock_null_fread_calls , 0 );
266379 ck_assert_int_eq (mock_null_fclose_calls , 0 );
267-
380+ ck_assert_int_eq (read_file (output_path , & output_buf , & output_len ), 0 );
381+ ck_assert_uint_eq (output_len , CMD .header_sz + sizeof (image_buf ));
382+ assert_header_bytes (output_buf , HDR_CERT_CHAIN , cert_chain_buf ,
383+ sizeof (cert_chain_buf ));
384+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
385+ HDR_PUBKEY , & value ), HDR_SHA256_LEN );
386+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
387+ HDR_SHA256 , & value ), HDR_SHA256_LEN );
388+
389+ free (output_buf );
268390 unlink (output_path );
269391 unlink (cert_chain_path );
270392 unlink (image_path );
271393 rmdir (tempdir );
272394}
273395END_TEST
274396
397+ START_TEST (test_make_header_ex_roundtrip_custom_tlvs_via_wolfboot_parser )
398+ {
399+ char tempdir [] = "/tmp/wolfboot-sign-XXXXXX" ;
400+ char image_path [PATH_MAX ];
401+ char output_path [PATH_MAX ];
402+ uint8_t * output_buf = NULL ;
403+ uint8_t * value = NULL ;
404+ uint8_t image_buf [] = { 0x10 , 0x20 , 0x30 , 0x40 , 0x50 };
405+ uint8_t pubkey [] = { 0xA5 , 0x5A , 0x33 , 0xCC };
406+ uint8_t tlv_one [] = { 0xAB };
407+ uint8_t tlv_two [] = { 0x10 , 0x11 , 0x12 , 0x13 , 0x14 };
408+ uint8_t tlv_three [] = { 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 , 0x27 , 0x28 };
409+ uint16_t image_type ;
410+ uint32_t version = 7 ;
411+ size_t output_len ;
412+ int ret ;
413+
414+ ck_assert_ptr_nonnull (mkdtemp (tempdir ));
415+
416+ snprintf (image_path , sizeof (image_path ), "%s/image.bin" , tempdir );
417+ snprintf (output_path , sizeof (output_path ), "%s/output.bin" , tempdir );
418+ ck_assert_int_eq (write_file (image_path , image_buf , sizeof (image_buf )), 0 );
419+
420+ reset_cmd_defaults ();
421+ image_type = (uint16_t )((CMD .sign & HDR_IMG_TYPE_AUTH_MASK ) |
422+ CMD .partition_id );
423+ CMD .custom_tlvs = 3 ;
424+ CMD .custom_tlv [0 ].tag = 0x30 ;
425+ CMD .custom_tlv [0 ].len = sizeof (tlv_one );
426+ CMD .custom_tlv [0 ].buffer = malloc (sizeof (tlv_one ));
427+ memcpy (CMD .custom_tlv [0 ].buffer , tlv_one , sizeof (tlv_one ));
428+ CMD .custom_tlv [1 ].tag = 0x31 ;
429+ CMD .custom_tlv [1 ].len = sizeof (tlv_two );
430+ CMD .custom_tlv [1 ].buffer = malloc (sizeof (tlv_two ));
431+ memcpy (CMD .custom_tlv [1 ].buffer , tlv_two , sizeof (tlv_two ));
432+ CMD .custom_tlv [2 ].tag = 0x32 ;
433+ CMD .custom_tlv [2 ].len = sizeof (tlv_three );
434+ CMD .custom_tlv [2 ].buffer = malloc (sizeof (tlv_three ));
435+ memcpy (CMD .custom_tlv [2 ].buffer , tlv_three , sizeof (tlv_three ));
436+
437+ reset_mocks (NULL , 0 );
438+ ret = make_header_ex (0 , pubkey , sizeof (pubkey ), image_path , output_path ,
439+ 0 , 0 , 0 , 0 , NULL , 0 , NULL , 0 );
440+
441+ ck_assert_int_eq (ret , 0 );
442+ ck_assert_int_eq (read_file (output_path , & output_buf , & output_len ), 0 );
443+ ck_assert_uint_eq (output_len , CMD .header_sz + sizeof (image_buf ));
444+ assert_header_bytes (output_buf , HDR_VERSION , (uint8_t * )& version ,
445+ sizeof (version ));
446+ assert_header_bytes (output_buf , HDR_IMG_TYPE , (uint8_t * )& image_type ,
447+ sizeof (image_type ));
448+ assert_header_bytes (output_buf , 0x30 , tlv_one , sizeof (tlv_one ));
449+ assert_header_bytes (output_buf , 0x31 , tlv_two , sizeof (tlv_two ));
450+ assert_header_bytes (output_buf , 0x32 , tlv_three , sizeof (tlv_three ));
451+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
452+ HDR_PUBKEY , & value ), HDR_SHA256_LEN );
453+ ck_assert_ptr_nonnull (value );
454+ ck_assert_uint_eq ((uintptr_t )value % 8U , 0 );
455+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
456+ 0x30 , & value ), sizeof (tlv_one ));
457+ ck_assert_uint_eq ((uintptr_t )value % 8U , 0 );
458+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
459+ 0x31 , & value ), sizeof (tlv_two ));
460+ ck_assert_uint_eq ((uintptr_t )value % 8U , 0 );
461+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
462+ 0x32 , & value ), sizeof (tlv_three ));
463+ ck_assert_uint_eq ((uintptr_t )value % 8U , 0 );
464+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
465+ HDR_SHA256 , & value ), HDR_SHA256_LEN );
466+
467+ free (output_buf );
468+ free_custom_tlv_buffers ();
469+ unlink (output_path );
470+ unlink (image_path );
471+ rmdir (tempdir );
472+ }
473+ END_TEST
474+
475+ START_TEST (test_make_header_ex_roundtrip_finds_tlv_that_exactly_fills_header )
476+ {
477+ char tempdir [] = "/tmp/wolfboot-sign-XXXXXX" ;
478+ char image_path [PATH_MAX ];
479+ char output_path [PATH_MAX ];
480+ uint8_t * output_buf = NULL ;
481+ uint8_t image_buf [] = { 0x61 , 0x62 , 0x63 , 0x64 };
482+ uint8_t pubkey [] = { 0x01 , 0x02 };
483+ uint8_t * custom_buf = NULL ;
484+ uint8_t * value = NULL ;
485+ size_t output_len ;
486+ uint16_t exact_len ;
487+ int ret ;
488+
489+ ck_assert_ptr_nonnull (mkdtemp (tempdir ));
490+
491+ snprintf (image_path , sizeof (image_path ), "%s/image.bin" , tempdir );
492+ snprintf (output_path , sizeof (output_path ), "%s/output.bin" , tempdir );
493+ ck_assert_int_eq (write_file (image_path , image_buf , sizeof (image_buf )), 0 );
494+
495+ reset_cmd_defaults ();
496+ exact_len = find_exact_fill_custom_len ();
497+ ck_assert_uint_ne (exact_len , 0 );
498+ custom_buf = malloc (exact_len );
499+ ck_assert_ptr_nonnull (custom_buf );
500+ memset (custom_buf , 0x6C , exact_len );
501+
502+ CMD .custom_tlvs = 1 ;
503+ CMD .custom_tlv [0 ].tag = 0x40 ;
504+ CMD .custom_tlv [0 ].len = exact_len ;
505+ CMD .custom_tlv [0 ].buffer = custom_buf ;
506+ ck_assert_uint_eq (header_required_size (0 , 0 , 0 ), CMD .header_sz );
507+
508+ reset_mocks (NULL , 0 );
509+ ret = make_header_ex (0 , pubkey , sizeof (pubkey ), image_path , output_path ,
510+ 0 , 0 , 0 , 0 , NULL , 0 , NULL , 0 );
511+
512+ ck_assert_int_eq (ret , 0 );
513+ ck_assert_int_eq (read_file (output_path , & output_buf , & output_len ), 0 );
514+ ck_assert_uint_eq (output_len , CMD .header_sz + sizeof (image_buf ));
515+ ck_assert_uint_eq (wolfBoot_find_header (output_buf + IMAGE_HEADER_OFFSET ,
516+ 0x40 , & value ), exact_len );
517+ ck_assert_ptr_nonnull (value );
518+ ck_assert_msg (memcmp (value , custom_buf , exact_len ) == 0 ,
519+ "Exact-fit TLV did not roundtrip" );
520+
521+ free (output_buf );
522+ free_custom_tlv_buffers ();
523+ unlink (output_path );
524+ unlink (image_path );
525+ rmdir (tempdir );
526+ }
527+ END_TEST
528+
275529Suite * wolfboot_suite (void )
276530{
277531 Suite * s = suite_create ("sign-encrypted-output" );
@@ -281,6 +535,10 @@ Suite *wolfboot_suite(void)
281535 tcase_add_test (tcase , test_make_header_ex_fails_when_image_reopen_fails );
282536 tcase_add_test (tcase ,
283537 test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs );
538+ tcase_add_test (tcase ,
539+ test_make_header_ex_roundtrip_custom_tlvs_via_wolfboot_parser );
540+ tcase_add_test (tcase ,
541+ test_make_header_ex_roundtrip_finds_tlv_that_exactly_fills_header );
284542 suite_add_tcase (s , tcase );
285543
286544 return s ;
0 commit comments