Fix sign header TLV overflow sizing

F/2266
pull/745/head
Daniele Lacamera 2026-04-08 16:35:20 +02:00
parent 0bcc49ab3c
commit 153ad2b0af
2 changed files with 184 additions and 9 deletions

View File

@ -221,9 +221,23 @@ static void header_append_u16(uint8_t* header, uint32_t* idx, uint16_t tmp16)
memcpy(&header[*idx], &tmp16, sizeof(tmp16));
*idx += sizeof(tmp16);
}
static uint32_t header_append_limit(void);
static void header_append_tag(uint8_t* header, uint32_t* idx, uint16_t tag,
uint16_t len, void* data)
uint16_t len, const void* data)
{
const uint32_t append_sz = (uint32_t)(sizeof(tag) + sizeof(len)) + len;
const uint32_t header_sz = header_append_limit();
if ((*idx > header_sz) || (append_sz > (header_sz - *idx))) {
fprintf(stderr,
"Header overflow while appending tag 0x%04x "
"(offset=%u, size=%u, header=%u)\n",
tag, *idx, append_sz, header_sz);
exit(1);
}
header_append_u16(header, idx, tag);
header_append_u16(header, idx, len);
memcpy(&header[*idx], data, len);
@ -296,6 +310,11 @@ static struct cmd_options CMD = {
.hybrid = 0
};
static uint32_t header_append_limit(void)
{
return CMD.header_sz;
}
static void zero_and_free(uint8_t *buf, uint32_t len)
{
volatile uint8_t *p;
@ -1124,6 +1143,114 @@ static int sign_digest(int sign, int hash_algo,
#define ALIGN_8(x) while ((x % 8) != 4) { x++; }
#define ALIGN_4(x) while ((x % 4) != 0) { x++; }
static void header_size_align_8(uint32_t *idx)
{
while ((*idx % 8U) != 4U) {
(*idx)++;
}
}
static void header_size_align_4(uint32_t *idx)
{
while ((*idx % 4U) != 0U) {
(*idx)++;
}
}
static void header_size_append_tag(uint32_t *idx, uint32_t len)
{
*idx += 4U + len;
}
static uint32_t header_digest_size(int hash_algo)
{
switch (hash_algo) {
case HASH_SHA256:
return HDR_SHA256_LEN;
case HASH_SHA384:
return HDR_SHA384_LEN;
case HASH_SHA3:
return HDR_SHA3_384_LEN;
default:
return 0;
}
}
static uint32_t header_required_size(int is_diff, uint32_t cert_chain_sz,
uint32_t secondary_key_sz)
{
uint32_t idx = 0;
uint32_t digest_sz = header_digest_size(CMD.hash_algo);
uint32_t i;
idx += 2U * sizeof(uint32_t);
header_size_append_tag(&idx, HDR_VERSION_LEN);
header_size_align_8(&idx);
if (!CMD.no_ts) {
header_size_append_tag(&idx, HDR_TIMESTAMP_LEN);
}
header_size_append_tag(&idx, HDR_IMG_TYPE_LEN);
if (is_diff) {
header_size_align_4(&idx);
header_size_append_tag(&idx, 4);
header_size_append_tag(&idx, 4);
header_size_align_4(&idx);
header_size_append_tag(&idx, 4);
header_size_append_tag(&idx, 4);
if (!CMD.no_base_sha && digest_sz > 0U) {
header_size_align_8(&idx);
header_size_append_tag(&idx, digest_sz);
}
}
for (i = 0; i < CMD.custom_tlvs; i++) {
header_size_align_8(&idx);
header_size_append_tag(&idx, CMD.custom_tlv[i].len);
}
if (cert_chain_sz > 0U) {
header_size_align_8(&idx);
header_size_append_tag(&idx, cert_chain_sz);
}
if (digest_sz > 0U) {
header_size_align_8(&idx);
header_size_append_tag(&idx, digest_sz);
header_size_align_8(&idx);
if (CMD.hybrid && secondary_key_sz > 0U) {
header_size_append_tag(&idx, 2);
header_size_align_8(&idx);
header_size_append_tag(&idx, digest_sz);
header_size_align_8(&idx);
}
header_size_append_tag(&idx, digest_sz);
}
if (CMD.sign != NO_SIGN) {
header_size_align_8(&idx);
header_size_append_tag(&idx, CMD.signature_sz);
if (CMD.hybrid) {
header_size_align_8(&idx);
header_size_append_tag(&idx, CMD.secondary_signature_sz);
}
if (CMD.policy_sign) {
header_size_align_8(&idx);
header_size_append_tag(&idx,
CMD.policy_sz + (uint32_t)sizeof(uint32_t));
}
}
return idx;
}
static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
const char *image_file, const char *outfile,
uint32_t delta_base_version, uint32_t patch_len, uint32_t patch_inv_off,
@ -1157,14 +1284,8 @@ static int make_header_ex(int is_diff, uint8_t *pubkey, uint32_t pubkey_sz,
/* Get the file size */
if (stat(CMD.cert_chain_file, &file_stat) == 0) {
/* 2 bytes for tag + 2 bytes for length field */
const uint32_t tag_len_size = 4;
/* Maximum alignment padding that might be needed */
const uint32_t max_alignment = 8;
/* Required space = tag(2) + length(2) + data + potential alignment
* * padding */
const uint32_t required_space =
tag_len_size + file_stat.st_size + max_alignment;
const uint32_t required_space = header_required_size(is_diff,
(uint32_t)file_stat.st_size, secondary_key_sz);
/* If the current header size is too small, increase it */
if (CMD.header_sz < required_space) {

View File

@ -220,6 +220,58 @@ START_TEST(test_make_header_ex_fails_when_image_reopen_fails)
}
END_TEST
START_TEST(test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs)
{
char tempdir[] = "/tmp/wolfboot-sign-XXXXXX";
char image_path[PATH_MAX];
char output_path[PATH_MAX];
char cert_chain_path[PATH_MAX];
uint8_t image_buf[] = { 0x01, 0x02, 0x03, 0x04 };
uint8_t cert_chain_buf[200];
uint8_t pubkey[] = { 0xA5 };
struct stat st;
int ret;
ck_assert_ptr_nonnull(mkdtemp(tempdir));
snprintf(image_path, sizeof(image_path), "%s/image.bin", tempdir);
snprintf(output_path, sizeof(output_path), "%s/output.bin", tempdir);
snprintf(cert_chain_path, sizeof(cert_chain_path), "%s/cert-chain.bin",
tempdir);
memset(cert_chain_buf, 0xC3, sizeof(cert_chain_buf));
ck_assert_int_eq(write_file(image_path, image_buf, sizeof(image_buf)), 0);
ck_assert_int_eq(write_file(cert_chain_path, cert_chain_buf,
sizeof(cert_chain_buf)), 0);
memset(&CMD, 0, sizeof(CMD));
CMD.sign = NO_SIGN;
CMD.hash_algo = HASH_SHA256;
CMD.partition_id = HDR_IMG_TYPE_APP;
CMD.header_sz = 256;
CMD.fw_version = "7";
CMD.no_ts = 1;
CMD.cert_chain_file = cert_chain_path;
reset_mocks(NULL, 0);
ret = make_header_ex(0, pubkey, sizeof(pubkey), image_path, output_path,
0, 0, 0, 0, NULL, 0, NULL, 0);
ck_assert_int_eq(ret, 0);
ck_assert_uint_eq(CMD.header_sz, 512);
ck_assert_int_eq(stat(output_path, &st), 0);
ck_assert_uint_eq((uint32_t)st.st_size, CMD.header_sz + sizeof(image_buf));
ck_assert_int_eq(mock_null_fwrite_calls, 0);
ck_assert_int_eq(mock_null_fread_calls, 0);
ck_assert_int_eq(mock_null_fclose_calls, 0);
unlink(output_path);
unlink(cert_chain_path);
unlink(image_path);
rmdir(tempdir);
}
END_TEST
Suite *wolfboot_suite(void)
{
Suite *s = suite_create("sign-encrypted-output");
@ -227,6 +279,8 @@ Suite *wolfboot_suite(void)
tcase_add_test(tcase, test_make_header_ex_fails_when_encrypted_output_open_fails);
tcase_add_test(tcase, test_make_header_ex_fails_when_image_reopen_fails);
tcase_add_test(tcase,
test_make_header_ex_grows_header_for_cert_chain_and_digest_tlvs);
suite_add_tcase(s, tcase);
return s;