mirror of https://github.com/wolfSSL/wolfBoot.git
1356 lines
46 KiB
C
1356 lines
46 KiB
C
/* unit-image.c
|
|
*
|
|
* Unit test for parser functions in image.c
|
|
*
|
|
*
|
|
* Copyright (C) 2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfBoot.
|
|
*
|
|
* wolfBoot is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfBoot is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
/* Option to enable sign tool debugging */
|
|
/* Must also define DEBUG_WOLFSSL in user_settings.h */
|
|
#if !defined(WOLFBOOT_HASH_SHA256) && !defined(WOLFBOOT_HASH_SHA384) && \
|
|
!defined(WOLFBOOT_HASH_SHA3_384)
|
|
#define WOLFBOOT_HASH_SHA256
|
|
#endif
|
|
#define EXT_FLASH
|
|
#define PART_UPDATE_EXT
|
|
#define NVM_FLASH_WRITEONCE
|
|
#define WOLFBOOT_SELF_HEADER
|
|
|
|
#if defined(ENCRYPT_WITH_AES256) || defined(ENCRYPT_WITH_AES128)
|
|
#define WOLFSSL_AES_COUNTER
|
|
#define WOLFSSL_AES_DIRECT
|
|
#endif
|
|
#if defined(ENCRYPT_WITH_AES256)
|
|
#define WOLFSSL_AES_256
|
|
#endif
|
|
#if defined(ENCRYPT_WITH_CHACHA)
|
|
#define HAVE_CHACHA
|
|
#endif
|
|
#define ECC_TIMING_RESISTANT
|
|
|
|
#define ENCRYPT_KEY "123456789abcdef0123456789abcdef0123456789abcdef"
|
|
#if !defined(WOLFBOOT_SIGN_ED25519) && !defined(WOLFBOOT_SIGN_ED448) && \
|
|
!defined(WOLFBOOT_SIGN_RSA2048) && !defined(WOLFBOOT_SIGN_RSA3072) && \
|
|
!defined(WOLFBOOT_SIGN_RSA4096) && !defined(WOLFBOOT_SIGN_RSA2048ENC) && \
|
|
!defined(WOLFBOOT_SIGN_RSA3072ENC) && !defined(WOLFBOOT_SIGN_RSA4096ENC) && \
|
|
!defined(WOLFBOOT_SIGN_ECC256) && !defined(WOLFBOOT_SIGN_ECC384) && \
|
|
!defined(WOLFBOOT_SIGN_ECC521) && !defined(WOLFBOOT_SIGN_LMS) && \
|
|
!defined(WOLFBOOT_SIGN_XMSS) && !defined(WOLFBOOT_SIGN_ML_DSA)
|
|
#define WOLFBOOT_SIGN_ECC256
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <check.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include "user_settings.h"
|
|
#include "wolfssl/wolfcrypt/sha.h"
|
|
#include "wolfboot/wolfboot.h"
|
|
|
|
#ifndef ARCH_FLASH_OFFSET
|
|
#define ARCH_FLASH_OFFSET WOLFBOOT_PARTITION_BOOT_ADDRESS
|
|
#endif
|
|
|
|
#include "unit-keystore.c"
|
|
|
|
#include "image.c"
|
|
|
|
const uint8_t a;
|
|
|
|
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;
|
|
static int find_header_mocked = 1;
|
|
|
|
uint8_t *wolfBoot_get_self_header(void)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
#if defined(WOLFBOOT_SIGN_ECC256) && defined(WOLFBOOT_HASH_SHA256)
|
|
static const unsigned char pubkey_digest[SHA256_DIGEST_SIZE] = {
|
|
0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
|
|
0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
|
|
0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68
|
|
};
|
|
#endif
|
|
|
|
|
|
uint32_t wolfBoot_get_blob_version(uint8_t *blob)
|
|
{
|
|
(void)blob;
|
|
return 1;
|
|
}
|
|
|
|
|
|
static unsigned char test_img_v200000000_signed_bin[] = {
|
|
0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
|
|
0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
|
|
0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
|
|
0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
|
|
0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x23,
|
|
0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
|
|
0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
|
|
0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
|
|
0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
|
|
0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
|
|
0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2e,
|
|
0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
|
|
0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
|
|
0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
|
|
0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
|
|
0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
|
|
0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
|
|
};
|
|
|
|
|
|
static const unsigned char test_img_v200000000_wrong_signature_bin[] = {
|
|
0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
|
|
0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
|
|
0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
|
|
0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
|
|
0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x23,
|
|
0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
|
|
0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
|
|
0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
|
|
0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
|
|
0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
|
|
0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2f,
|
|
0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
|
|
0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
|
|
0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
|
|
0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
|
|
0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
|
|
0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
|
|
};
|
|
|
|
static const unsigned char test_img_v200000000_wrong_pubkey_bin[] = {
|
|
0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
|
|
0x00, 0xc2, 0xeb, 0x0b, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
|
|
0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
|
|
0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
|
|
0xda, 0x9c, 0xee, 0x7e, 0x12, 0xcf, 0xa0, 0xe1, 0xda, 0xa1, 0xb4, 0x24,
|
|
0xbf, 0x31, 0xe5, 0xdd, 0x6f, 0x58, 0xfe, 0xd9, 0x8d, 0xb7, 0x7b, 0x31,
|
|
0x6f, 0x7b, 0x01, 0x84, 0xe0, 0x63, 0x5e, 0xe9, 0x10, 0x00, 0x20, 0x00,
|
|
0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
|
|
0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
|
|
0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
|
|
0xb0, 0x22, 0xb3, 0x91, 0xf7, 0x4e, 0xe1, 0x37, 0x6c, 0xb5, 0x64, 0x2e,
|
|
0xe6, 0x80, 0x4b, 0xcb, 0xa7, 0x1d, 0xa1, 0xa7, 0x16, 0x2e, 0x4b, 0xa5,
|
|
0xee, 0x67, 0xd2, 0x02, 0xff, 0x1b, 0xd3, 0x4c, 0xc6, 0x09, 0x62, 0x66,
|
|
0x08, 0x4c, 0xfc, 0x32, 0x4b, 0x47, 0x56, 0xe0, 0x9b, 0x98, 0xd9, 0xa4,
|
|
0x2a, 0x5e, 0x53, 0xd3, 0xb4, 0xde, 0x80, 0xe1, 0x9a, 0x95, 0x2a, 0x58,
|
|
0xc9, 0xd6, 0x9a, 0x2a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
|
|
0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
|
|
};
|
|
|
|
static uint16_t _find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr);
|
|
|
|
static void patch_pubkey_hint_slot(uint8_t *img, uint32_t img_len, uint8_t slot)
|
|
{
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len;
|
|
uint8_t hash[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
|
|
(void)img_len;
|
|
len = _find_header(img + IMAGE_HEADER_OFFSET, HDR_PUBKEY, &ptr);
|
|
ck_assert_int_eq(len, WOLFBOOT_SHA_DIGEST_SIZE);
|
|
key_hash(slot, hash);
|
|
memcpy(ptr, hash, WOLFBOOT_SHA_DIGEST_SIZE);
|
|
}
|
|
|
|
static void patch_pubkey_hint(uint8_t *img, uint32_t img_len)
|
|
{
|
|
patch_pubkey_hint_slot(img, img_len, 0);
|
|
}
|
|
|
|
static void patch_signature_len(uint8_t *img, uint32_t img_len, uint16_t new_len)
|
|
{
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len;
|
|
|
|
(void)img_len;
|
|
len = _find_header(img + IMAGE_HEADER_OFFSET, HDR_SIGNATURE, &ptr);
|
|
ck_assert_int_ne(len, 0);
|
|
ptr[-2] = (uint8_t)(new_len & 0xFF);
|
|
ptr[-1] = (uint8_t)(new_len >> 8);
|
|
}
|
|
|
|
static void patch_image_type_auth(uint8_t *img, uint32_t img_len)
|
|
{
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len;
|
|
uint16_t type;
|
|
|
|
(void)img_len;
|
|
len = _find_header(img + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, &ptr);
|
|
ck_assert_int_eq(len, sizeof(uint16_t));
|
|
type = (uint16_t)(ptr[0] | (ptr[1] << 8));
|
|
type = (uint16_t)((type & ~HDR_IMG_TYPE_AUTH_MASK) | HDR_IMG_TYPE_AUTH);
|
|
ptr[0] = (uint8_t)(type & 0xFF);
|
|
ptr[1] = (uint8_t)(type >> 8);
|
|
}
|
|
|
|
static void patch_image_type_auth_value(uint8_t *img, uint32_t img_len,
|
|
uint16_t auth)
|
|
{
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len;
|
|
uint16_t type;
|
|
|
|
(void)img_len;
|
|
len = _find_header(img + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, &ptr);
|
|
ck_assert_int_eq(len, sizeof(uint16_t));
|
|
type = (uint16_t)(ptr[0] | (ptr[1] << 8));
|
|
type = (uint16_t)((type & ~HDR_IMG_TYPE_AUTH_MASK) |
|
|
(auth & HDR_IMG_TYPE_AUTH_MASK));
|
|
ptr[0] = (uint8_t)(type & 0xFF);
|
|
ptr[1] = (uint8_t)(type >> 8);
|
|
}
|
|
|
|
static void patch_image_type_part(uint8_t *img, uint32_t img_len, uint16_t part)
|
|
{
|
|
uint8_t *ptr = NULL;
|
|
uint16_t len;
|
|
uint16_t type;
|
|
|
|
(void)img_len;
|
|
len = _find_header(img + IMAGE_HEADER_OFFSET, HDR_IMG_TYPE, &ptr);
|
|
ck_assert_int_eq(len, sizeof(uint16_t));
|
|
type = (uint16_t)(ptr[0] | (ptr[1] << 8));
|
|
type = (uint16_t)((type & ~HDR_IMG_TYPE_PART_MASK) |
|
|
(part & HDR_IMG_TYPE_PART_MASK));
|
|
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;
|
|
|
|
|
|
unsigned char test_img_v123_signed_bin[] = {
|
|
0x57, 0x4f, 0x4c, 0x46, 0x13, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00,
|
|
0x7b, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0x00, 0x08, 0x00,
|
|
0x77, 0x33, 0x29, 0x65, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00,
|
|
0x01, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x20, 0x00,
|
|
0x89, 0xbd, 0x89, 0x01, 0xb9, 0xaf, 0xa9, 0xbd, 0x78, 0x88, 0xba, 0xd1,
|
|
0x97, 0xc1, 0x6f, 0xd0, 0x7f, 0x11, 0xbd, 0x29, 0x97, 0x4a, 0x10, 0x27,
|
|
0xa0, 0x53, 0x8c, 0x32, 0x3d, 0xfc, 0xc9, 0x9b, 0x10, 0x00, 0x20, 0x00,
|
|
0x17, 0x20, 0xa5, 0x9b, 0xe0, 0x9b, 0x80, 0x0c, 0xaa, 0xc4, 0xf5, 0x3f,
|
|
0xae, 0xe5, 0x72, 0x4f, 0xf2, 0x1f, 0x33, 0x53, 0xd1, 0xd4, 0xcd, 0x8b,
|
|
0x5c, 0xc3, 0x4e, 0xda, 0xea, 0xc8, 0x4a, 0x68, 0x20, 0x00, 0x40, 0x00,
|
|
0xfc, 0x1d, 0x02, 0x10, 0xb7, 0x60, 0x63, 0x7b, 0x55, 0xe0, 0x0e, 0xd5,
|
|
0xb0, 0x64, 0xcd, 0x14, 0x9c, 0x1c, 0x80, 0x5f, 0x02, 0xb5, 0x54, 0x67,
|
|
0x54, 0x93, 0x6d, 0xaf, 0x72, 0x74, 0x7b, 0x96, 0x94, 0x5c, 0x62, 0xb2,
|
|
0x6d, 0x0f, 0xc9, 0xf4, 0x9f, 0x82, 0xa7, 0xd4, 0x28, 0xb9, 0x4c, 0x64,
|
|
0x01, 0x5d, 0x03, 0x0f, 0x81, 0x05, 0x13, 0xf1, 0xe0, 0xbd, 0xdc, 0xe2,
|
|
0x17, 0x84, 0xa3, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
0xff, 0xff, 0xff, 0xff, 0x54, 0x65, 0x73, 0x74, 0x20, 0x69, 0x6d, 0x61,
|
|
0x67, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x0a
|
|
};
|
|
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)
|
|
{
|
|
uint8_t *p = haystack;
|
|
uint16_t len;
|
|
const volatile uint8_t *max_p = (haystack - IMAGE_HEADER_OFFSET) +
|
|
IMAGE_HEADER_SIZE;
|
|
*ptr = NULL;
|
|
if (p > max_p) {
|
|
printf("Illegal address (too high)\n");
|
|
return 0;
|
|
}
|
|
while ((p + 4) < max_p) {
|
|
if ((p[0] == 0) && (p[1] == 0)) {
|
|
printf("Explicit end of options reached\n");
|
|
break;
|
|
}
|
|
if (*p == HDR_PADDING) {
|
|
/* Padding byte (skip one position) */
|
|
p++;
|
|
continue;
|
|
}
|
|
/* Sanity check to prevent dereferencing unaligned half-words */
|
|
if ((((unsigned long)p) & 0x01) != 0) {
|
|
p++;
|
|
continue;
|
|
}
|
|
len = p[2] | (p[3] << 8);
|
|
if ((4 + len) > (uint16_t)(IMAGE_HEADER_SIZE - IMAGE_HEADER_OFFSET)) {
|
|
printf("This field is too large (bigger than the space available "
|
|
"in the current header)\n");
|
|
printf("%d %d %d\n", len, IMAGE_HEADER_SIZE, IMAGE_HEADER_OFFSET);
|
|
break;
|
|
}
|
|
if (p + 4 + len > max_p) {
|
|
printf("This field is too large and would overflow the image "
|
|
"header\n");
|
|
break;
|
|
}
|
|
if ((p[0] | (p[1] << 8)) == type) {
|
|
*ptr = (p + 4);
|
|
return len;
|
|
}
|
|
p += 4 + len;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint16_t wolfBoot_get_blob_type(uint8_t *addr)
|
|
{
|
|
return HDR_IMG_TYPE_APP;
|
|
}
|
|
|
|
uint16_t wolfBoot_find_header(uint8_t *haystack, uint16_t type, uint8_t **ptr)
|
|
{
|
|
find_header_called++;
|
|
if (find_header_mocked) {
|
|
if (find_header_fail) {
|
|
return -1;
|
|
} else {
|
|
return sizeof(uint16_t);
|
|
}
|
|
} else {
|
|
return _find_header(haystack, type, ptr);
|
|
}
|
|
}
|
|
|
|
#if defined(WOLFBOOT_SIGN_ECC256) || defined(WOLFBOOT_SIGN_ECC384) || \
|
|
defined(WOLFBOOT_SIGN_ECC521)
|
|
int wc_ecc_init_ex(ecc_key* key, void* heap, int devId) {
|
|
(void)heap;
|
|
(void)devId;
|
|
if (ecc_init_fail)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
int wc_ecc_free(ecc_key *key) {
|
|
return 0;
|
|
}
|
|
|
|
int wc_ecc_import_unsigned(ecc_key* key, const byte* qx, const byte* qy,
|
|
const byte* d, int curve_id)
|
|
{
|
|
if (ecc_import_fail)
|
|
return -1;
|
|
|
|
key->type = ECC_PUBLICKEY;
|
|
return 0;
|
|
}
|
|
|
|
|
|
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++;
|
|
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
|
|
|
|
#if defined(WOLFBOOT_SIGN_ECC256)
|
|
START_TEST(test_verify_signature)
|
|
{
|
|
uint8_t pubkey[32];
|
|
struct wolfBoot_image test_img;
|
|
|
|
test_img.part = PART_UPDATE;
|
|
test_img.fw_size = test_img_len;
|
|
test_img.fw_base = 0;
|
|
|
|
wolfBoot_verify_signature_ecc(0, NULL, NULL);
|
|
ck_assert_int_eq(verify_called, 0);
|
|
|
|
ecc_init_fail = 1;
|
|
wolfBoot_verify_signature_ecc(0, NULL, pubkey);
|
|
ck_assert_int_eq(verify_called, 0);
|
|
|
|
ecc_init_fail = 0;
|
|
verify_called = 0;
|
|
ecc_import_fail = 1;
|
|
wolfBoot_verify_signature_ecc(0, NULL, pubkey);
|
|
ck_assert_int_eq(verify_called, 0);
|
|
|
|
ecc_init_fail = 0;
|
|
ecc_import_fail = 0;
|
|
verify_called = 0;
|
|
find_header_mocked = 0;
|
|
ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
|
|
ext_flash_write(0, test_img_v200000000_signed_bin,
|
|
test_img_len);
|
|
wolfBoot_verify_signature_ecc(0, &test_img, pubkey);
|
|
ck_assert_int_eq(verify_called, 1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_keyslot_id_by_sha_scans_all_slots)
|
|
{
|
|
int id;
|
|
uint8_t digest[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
|
|
key_hash(0, digest);
|
|
unit_keystore_reset_counters();
|
|
id = keyslot_id_by_sha(digest);
|
|
|
|
ck_assert_int_eq(id, 0);
|
|
ck_assert_int_eq(unit_keystore_get_buffer_calls(), keystore_num_pubkeys());
|
|
ck_assert_int_eq(unit_keystore_get_size_calls(), keystore_num_pubkeys());
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_key_hash_zeroes_output_on_invalid_slot)
|
|
{
|
|
uint8_t hash[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
size_t i;
|
|
|
|
memset(hash, 0xA5, sizeof(hash));
|
|
key_hash(0xFF, hash);
|
|
|
|
for (i = 0; i < sizeof(hash); i++) {
|
|
ck_assert_uint_eq(hash[i], 0);
|
|
}
|
|
}
|
|
END_TEST
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_RSA3072) || \
|
|
defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \
|
|
defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \
|
|
defined(WOLFBOOT_SIGN_SECONDARY_RSA4096)
|
|
int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId)
|
|
{
|
|
(void)key;
|
|
(void)heap;
|
|
(void)devId;
|
|
return 0;
|
|
}
|
|
|
|
int wc_FreeRsaKey(RsaKey* key)
|
|
{
|
|
(void)key;
|
|
return 0;
|
|
}
|
|
|
|
int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
|
|
word32 inSz)
|
|
{
|
|
(void)input;
|
|
(void)inOutIdx;
|
|
(void)key;
|
|
(void)inSz;
|
|
return 0;
|
|
}
|
|
|
|
int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
|
|
{
|
|
(void)in;
|
|
(void)inLen;
|
|
(void)out;
|
|
(void)key;
|
|
return 0;
|
|
}
|
|
|
|
START_TEST(test_decode_asn1_tag_start_bounds)
|
|
{
|
|
uint8_t *input = malloc(1);
|
|
int idx = 0;
|
|
volatile int input_sz = 1;
|
|
int tag_len = -1;
|
|
|
|
ck_assert_ptr_nonnull(input);
|
|
input[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
|
|
ck_assert_int_eq(DecodeAsn1Tag(input, input_sz, &idx, &tag_len,
|
|
ASN_SEQUENCE | ASN_CONSTRUCTED), -1);
|
|
free(input);
|
|
}
|
|
END_TEST
|
|
#endif
|
|
|
|
|
|
START_TEST(test_sha_ops)
|
|
{
|
|
uint8_t hash[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
static uint8_t FlashImg[32 * 1024];
|
|
uint8_t *retp = NULL;
|
|
struct wolfBoot_image test_img;
|
|
uint32_t offset;
|
|
uint32_t sz = 0;
|
|
find_header_mocked = 1;
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
test_img.part = PART_BOOT;
|
|
test_img.fw_size = 0x1000;
|
|
test_img.fw_base = FlashImg;
|
|
|
|
/* Test get_sha_block */
|
|
offset = 0x2000;
|
|
retp = get_sha_block(&test_img, offset);
|
|
ck_assert_ptr_null(retp);
|
|
|
|
offset = 0x100;
|
|
retp = get_sha_block(&test_img, offset);
|
|
ck_assert_ptr_eq(retp, FlashImg + offset);
|
|
|
|
test_img.part = PART_UPDATE;
|
|
test_img.fw_size = 0x1000;
|
|
test_img.fw_base = 0x0000;
|
|
|
|
offset = 0x2000;
|
|
retp = get_sha_block(&test_img, offset);
|
|
ck_assert_ptr_null(retp);
|
|
|
|
offset = 0x100;
|
|
retp = get_sha_block(&test_img, offset);
|
|
ck_assert_ptr_eq(retp, ext_hash_block);
|
|
|
|
/* Test wolfBoot_peek_image */
|
|
hdr_cpy_done = 0;
|
|
offset = 0x100;
|
|
retp = get_sha_block(&test_img, offset);
|
|
ck_assert_ptr_eq(retp, ext_hash_block);
|
|
retp = wolfBoot_peek_image(&test_img, offset, NULL);
|
|
ck_assert_ptr_eq(retp, ext_hash_block);
|
|
retp = wolfBoot_peek_image(&test_img, offset, &sz);
|
|
ck_assert_ptr_eq(retp, ext_hash_block);
|
|
/* Full block fits in this image (fw_size 0x1000): the reported
|
|
* size stays the block size. The clamped tail case is covered by
|
|
* test_peek_image_bounds. */
|
|
ck_assert_uint_eq(sz, WOLFBOOT_SHA_BLOCK_SIZE);
|
|
|
|
/* Test image hash */
|
|
|
|
/* NULL img */
|
|
ck_assert_int_lt(image_hash(NULL, hash), 0);
|
|
|
|
/* Too short, internal partition field */
|
|
test_img.part = PART_BOOT;
|
|
test_img.fw_size = 0x1000;
|
|
ck_assert_int_lt(image_hash(&test_img, hash), 0);
|
|
|
|
/* Ext partition with a valid SHA */
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, test_img_v200000000_signed_bin,
|
|
test_img_len);
|
|
test_img.part = PART_UPDATE;
|
|
test_img.fw_base = 0;
|
|
test_img.fw_size = test_img_len;
|
|
ck_assert_int_eq(image_hash(&test_img, hash), 0);
|
|
|
|
/* key hash */
|
|
key_hash(0, hash);
|
|
#if defined(WOLFBOOT_SIGN_ECC256) && defined(WOLFBOOT_HASH_SHA256)
|
|
ck_assert_mem_eq(hash, pubkey_digest, SHA256_DIGEST_SIZE);
|
|
#else
|
|
/* Only the SHA-256 ECC256 fixture has a fixed expected digest here. */
|
|
(void)hash;
|
|
#endif
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_peek_image_bounds)
|
|
{
|
|
static uint8_t FlashImg[0x1000];
|
|
struct wolfBoot_image test_img;
|
|
uint32_t sz;
|
|
uint8_t *retp;
|
|
|
|
/* Internal image: a peek at offset == fw_size must be rejected
|
|
* (no bytes remain) and the reported size must be clamped to the
|
|
* bytes that remain in the image. */
|
|
memset(&test_img, 0, sizeof(test_img));
|
|
test_img.part = PART_BOOT;
|
|
test_img.fw_size = 0x100;
|
|
test_img.fw_base = FlashImg;
|
|
|
|
sz = 0xFFFF;
|
|
retp = wolfBoot_peek_image(&test_img, 0x100, &sz);
|
|
ck_assert_ptr_null(retp);
|
|
ck_assert_uint_eq(sz, 0);
|
|
|
|
sz = 0xFFFF;
|
|
retp = wolfBoot_peek_image(&test_img, 0xF0, &sz);
|
|
ck_assert_ptr_nonnull(retp);
|
|
ck_assert_uint_eq(sz, 0x10);
|
|
|
|
/* A block that fits fully must still report the full block size. */
|
|
memset(&test_img, 0, sizeof(test_img));
|
|
test_img.part = PART_BOOT;
|
|
test_img.fw_size = 0x1000;
|
|
test_img.fw_base = FlashImg;
|
|
|
|
sz = 0xFFFF;
|
|
retp = wolfBoot_peek_image(&test_img, 0, &sz);
|
|
ck_assert_ptr_nonnull(retp);
|
|
ck_assert_uint_eq(sz, WOLFBOOT_SHA_BLOCK_SIZE);
|
|
|
|
/* External image: same contract through the ext flash reader. */
|
|
memset(&test_img, 0, sizeof(test_img));
|
|
test_img.part = PART_UPDATE;
|
|
test_img.fw_base = 0;
|
|
test_img.fw_size = test_img_len;
|
|
ext_flash_write(0, test_img_v200000000_signed_bin, test_img_len);
|
|
|
|
sz = 0xFFFF;
|
|
retp = wolfBoot_peek_image(&test_img, test_img_len, &sz);
|
|
ck_assert_ptr_null(retp);
|
|
ck_assert_uint_eq(sz, 0);
|
|
|
|
sz = 0xFFFF;
|
|
retp = wolfBoot_peek_image(&test_img, test_img_len - 10, &sz);
|
|
ck_assert_ptr_nonnull(retp);
|
|
ck_assert_uint_eq(sz, 10);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_headers)
|
|
{
|
|
struct wolfBoot_image img;
|
|
uint16_t type;
|
|
void *ptr;
|
|
uint16_t ret;
|
|
uint32_t sz;
|
|
memset(&img, 0, sizeof(struct wolfBoot_image));
|
|
|
|
|
|
/* Test get_header() */
|
|
img.part = PART_BOOT;
|
|
find_header_fail = 1;
|
|
find_header_called = 0;
|
|
ret = get_header(&img, type, (void *)&ptr);
|
|
ck_assert_uint_eq(ret, 0xFFFF);
|
|
ck_assert_int_eq(find_header_called, 1);
|
|
|
|
img.part = PART_BOOT;
|
|
find_header_fail = 0;
|
|
find_header_called = 0;
|
|
ret = get_header(&img, type, (void *)&ptr);
|
|
ck_assert_uint_ne(ret, 0xFFFF);
|
|
ck_assert_int_eq(find_header_called, 1);
|
|
|
|
img.part = PART_UPDATE;
|
|
find_header_fail = 1;
|
|
find_header_called = 0;
|
|
ret = get_header(&img, type, (void *)&ptr);
|
|
ck_assert_uint_eq(ret, 0xFFFF);
|
|
ck_assert_int_eq(find_header_called, 1);
|
|
|
|
img.part = PART_UPDATE;
|
|
find_header_fail = 0;
|
|
find_header_called = 0;
|
|
ret = get_header(&img, type, (void *)&ptr);
|
|
ck_assert_uint_ne(ret, 0xFFFF);
|
|
ck_assert_int_eq(find_header_called, 1);
|
|
|
|
/* Test get_img_hdr */
|
|
img.part = PART_BOOT;
|
|
img.hdr = (void *)0xAABBCCDD;
|
|
ptr = get_img_hdr(&img);
|
|
ck_assert_ptr_eq(ptr, img.hdr);
|
|
|
|
img.part = PART_UPDATE;
|
|
img.hdr = 0;
|
|
ptr = get_img_hdr(&img);
|
|
ck_assert_ptr_eq(ptr, hdr_cpy);
|
|
|
|
/* Test image_size */
|
|
sz = wolfBoot_image_size((void *)(uintptr_t)test_img_v200000000_signed_bin);
|
|
ck_assert_uint_eq(sz, test_img_len - 256);
|
|
}
|
|
|
|
#if defined(WOLFBOOT_SIGN_ECC256)
|
|
#ifdef WOLFBOOT_FIXED_PARTITIONS
|
|
START_TEST(test_verify_authenticity)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
int ret;
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
test_img.part = PART_UPDATE;
|
|
|
|
/* Wrong sha field */
|
|
find_header_mocked = 1;
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_eq(ret, -1);
|
|
|
|
/* Wrong pubkey */
|
|
find_header_mocked = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, test_img_v200000000_wrong_pubkey_bin,
|
|
test_img_len);
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_lt(ret, 0);
|
|
|
|
/* Wrong signature */
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, test_img_v200000000_wrong_signature_bin,
|
|
test_img_len);
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_lt(ret, 0);
|
|
|
|
/* Correct image */
|
|
find_header_mocked = 0;
|
|
ecc_import_fail = 0;
|
|
ecc_init_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
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)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
uint8_t buf[sizeof(test_img_v200000000_signed_bin)];
|
|
int ret;
|
|
|
|
memcpy(buf, test_img_v200000000_signed_bin, sizeof(buf));
|
|
patch_image_type_auth(buf, sizeof(buf));
|
|
patch_pubkey_hint(buf, sizeof(buf));
|
|
patch_signature_len(buf, sizeof(buf), 1);
|
|
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, buf, sizeof(buf));
|
|
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
test_img.part = PART_UPDATE;
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_eq(ret, -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_verify_authenticity_rejects_mismatched_auth_type)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
uint8_t buf[sizeof(test_img_v200000000_signed_bin)];
|
|
int ret;
|
|
|
|
memcpy(buf, test_img_v200000000_signed_bin, sizeof(buf));
|
|
patch_image_type_auth_value(buf, sizeof(buf), HDR_IMG_TYPE_AUTH_RSA2048);
|
|
patch_pubkey_hint(buf, sizeof(buf));
|
|
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, buf, sizeof(buf));
|
|
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
test_img.part = PART_UPDATE;
|
|
test_img.signature_ok = 1;
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_eq(ret, -1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(test_verify_authenticity_rejects_disallowed_key_mask)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
uint8_t buf[sizeof(test_img_v200000000_signed_bin)];
|
|
int ret;
|
|
|
|
memcpy(buf, test_img_v200000000_signed_bin, sizeof(buf));
|
|
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_WOLFBOOT);
|
|
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, buf, sizeof(buf));
|
|
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
test_img.part = PART_UPDATE;
|
|
test_img.signature_ok = 1;
|
|
ret = wolfBoot_verify_authenticity(&test_img);
|
|
ck_assert_int_eq(ret, -1);
|
|
}
|
|
END_TEST
|
|
|
|
#ifdef WOLFBOOT_FIXED_PARTITIONS
|
|
START_TEST(test_verify_authenticity_allows_permitted_key_mask)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
uint8_t buf[sizeof(test_img_v200000000_signed_bin)];
|
|
int ret;
|
|
|
|
memcpy(buf, test_img_v200000000_signed_bin, sizeof(buf));
|
|
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;
|
|
hdr_cpy_done = 0;
|
|
ecc_import_fail = 0;
|
|
ecc_init_fail = 0;
|
|
ext_flash_erase(0, 2 * WOLFBOOT_SECTOR_SIZE);
|
|
ext_flash_write(0, buf, sizeof(buf));
|
|
|
|
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;
|
|
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
|
|
START_TEST(test_verify_integrity)
|
|
{
|
|
struct wolfBoot_image test_img;
|
|
int ret;
|
|
/* Wrong sha field */
|
|
find_header_mocked = 1;
|
|
ret = wolfBoot_verify_integrity(&test_img);
|
|
ck_assert_int_eq(ret, -1);
|
|
|
|
/* Correct image */
|
|
find_header_mocked = 0;
|
|
find_header_fail = 0;
|
|
hdr_cpy_done = 0;
|
|
ecc_import_fail = 0;
|
|
ecc_init_fail = 0;
|
|
memset(&test_img, 0, sizeof(struct wolfBoot_image));
|
|
ext_flash_erase(WOLFBOOT_PARTITION_UPDATE_ADDRESS, WOLFBOOT_SECTOR_SIZE);
|
|
ext_flash_write(WOLFBOOT_PARTITION_UPDATE_ADDRESS,
|
|
test_img_v123_signed_bin,
|
|
test_img_v123_signed_bin_len);
|
|
ret = wolfBoot_open_image(&test_img, PART_UPDATE);
|
|
ck_assert_int_eq(ret, 0);
|
|
ck_assert_ptr_eq(test_img.hdr, (void*)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ret = wolfBoot_verify_integrity(&test_img);
|
|
ck_assert_int_eq(ret, 0);
|
|
}
|
|
END_TEST
|
|
#endif
|
|
|
|
#ifdef WOLFBOOT_FIXED_PARTITIONS
|
|
START_TEST(test_open_image)
|
|
{
|
|
struct wolfBoot_image img;
|
|
int ret;
|
|
uint8_t self_hdr[IMAGE_HEADER_SIZE];
|
|
uint32_t oversize;
|
|
|
|
|
|
/* invalid argument */
|
|
ret = wolfBoot_open_image(NULL, PART_UPDATE);
|
|
ck_assert_int_eq(ret, -1);
|
|
|
|
/* Empty flash */
|
|
find_header_mocked = 0;
|
|
hdr_cpy_done = 0;
|
|
ext_flash_erase(0, WOLFBOOT_SECTOR_SIZE);
|
|
ret = wolfBoot_open_image(&img, PART_UPDATE);
|
|
ck_assert_int_eq(ret, -1);
|
|
ck_assert_uint_eq(img.hdr_ok, 0);
|
|
|
|
/* Swap partition */
|
|
ret = wolfBoot_open_image(&img, PART_SWAP);
|
|
ck_assert_uint_eq(img.hdr_ok, 1);
|
|
ck_assert_ptr_eq(img.hdr, (void *)WOLFBOOT_PARTITION_SWAP_ADDRESS);
|
|
ck_assert_ptr_eq(img.hdr, img.fw_base);
|
|
ck_assert_uint_eq(img.fw_size, WOLFBOOT_SECTOR_SIZE);
|
|
|
|
/* Valid image */
|
|
hdr_cpy_done = 0;
|
|
ext_flash_write(0, test_img_v200000000_signed_bin,
|
|
test_img_len);
|
|
ret = wolfBoot_open_image(&img, PART_UPDATE);
|
|
ck_assert_int_eq(ret, 0);
|
|
ck_assert_uint_eq(img.hdr_ok, 1);
|
|
ck_assert_ptr_eq(img.hdr, WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ck_assert_ptr_eq(img.fw_base, (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
|
+ 256);
|
|
|
|
/* External helper should accept the same mapped header pointer */
|
|
ret = wolfBoot_open_image_external(NULL, PART_UPDATE,
|
|
(uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ck_assert_int_eq(ret, -1);
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
hdr_cpy_done = 0;
|
|
ret = wolfBoot_open_image_external(&img, PART_UPDATE,
|
|
(uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ck_assert_int_eq(ret, 0);
|
|
ck_assert_uint_eq(img.hdr_ok, 1);
|
|
ck_assert_ptr_eq(img.hdr, (void *)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ck_assert_ptr_eq(img.fw_base, (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
|
+ 256);
|
|
|
|
/* Invalid external header must keep hdr_ok cleared on failure */
|
|
ext_flash_erase(0, WOLFBOOT_SECTOR_SIZE);
|
|
memset(&img, 0, sizeof(img));
|
|
hdr_cpy_done = 0;
|
|
ret = wolfBoot_open_image_external(&img, PART_UPDATE,
|
|
(uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS);
|
|
ck_assert_int_eq(ret, -1);
|
|
ck_assert_uint_eq(img.hdr_ok, 0);
|
|
|
|
/* A firmware payload that exactly fills the partition payload budget
|
|
* (fw_size == WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE) must be
|
|
* accepted by the partition-fit check in wolfBoot_open_image_address(),
|
|
* with fw_base/trailer positioned right after the header / at the end
|
|
* of the partition. */
|
|
memset(self_hdr, 0xFF, sizeof(self_hdr));
|
|
((uint32_t *)self_hdr)[0] = WOLFBOOT_MAGIC;
|
|
((uint32_t *)self_hdr)[1] = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE;
|
|
|
|
ext_flash_erase(0, WOLFBOOT_SECTOR_SIZE);
|
|
ext_flash_write(0, self_hdr, IMAGE_HEADER_SIZE);
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
hdr_cpy_done = 0;
|
|
ret = wolfBoot_open_image(&img, PART_UPDATE);
|
|
ck_assert_int_eq(ret, 0);
|
|
ck_assert_uint_eq(img.hdr_ok, 1);
|
|
ck_assert_uint_eq(img.fw_size, WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE);
|
|
ck_assert_ptr_eq(img.fw_base, (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
|
+ IMAGE_HEADER_SIZE);
|
|
ck_assert_ptr_eq(img.trailer, (uint8_t *)WOLFBOOT_PARTITION_UPDATE_ADDRESS
|
|
+ WOLFBOOT_PARTITION_SIZE);
|
|
|
|
/* Self header must reject bad magic and leave hdr_ok cleared */
|
|
memset(self_hdr, 0xFF, sizeof(self_hdr));
|
|
((uint32_t *)self_hdr)[0] = ~WOLFBOOT_MAGIC;
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
ret = wolfBoot_open_self_address(&img, self_hdr,
|
|
(uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS);
|
|
ck_assert_int_eq(ret, -1);
|
|
ck_assert_uint_eq(img.hdr_ok, 0);
|
|
|
|
/* Self header must accept sizes that exactly fill the partition
|
|
* payload budget (accept side of the same boundary checked below) */
|
|
memset(self_hdr, 0xFF, sizeof(self_hdr));
|
|
((uint32_t *)self_hdr)[0] = WOLFBOOT_MAGIC;
|
|
((uint32_t *)self_hdr)[1] = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE;
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
ret = wolfBoot_open_self_address(&img, self_hdr,
|
|
(uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS);
|
|
ck_assert_int_eq(ret, 0);
|
|
ck_assert_uint_eq(img.hdr_ok, 1);
|
|
ck_assert_uint_eq(img.fw_size, WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE);
|
|
|
|
/* Self header must reject sizes beyond the partition payload budget */
|
|
memset(self_hdr, 0xFF, sizeof(self_hdr));
|
|
((uint32_t *)self_hdr)[0] = WOLFBOOT_MAGIC;
|
|
oversize = WOLFBOOT_PARTITION_SIZE - IMAGE_HEADER_SIZE + 1;
|
|
((uint32_t *)self_hdr)[1] = oversize;
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
ret = wolfBoot_open_self_address(&img, self_hdr,
|
|
(uint8_t *)WOLFBOOT_PARTITION_BOOT_ADDRESS);
|
|
ck_assert_int_eq(ret, -1);
|
|
}
|
|
END_TEST
|
|
#else
|
|
START_TEST(test_open_image_address_without_partitions_rejects_oversized_fw_size)
|
|
{
|
|
struct wolfBoot_image img;
|
|
uint8_t image[IMAGE_HEADER_SIZE] = {0};
|
|
int ret;
|
|
|
|
memset(&img, 0, sizeof(img));
|
|
((uint32_t *)image)[0] = WOLFBOOT_MAGIC;
|
|
((uint32_t *)image)[1] = WOLFBOOT_RAMBOOT_MAX_SIZE + 1;
|
|
|
|
ret = wolfBoot_open_image_address(&img, image);
|
|
|
|
ck_assert_int_eq(ret, -1);
|
|
ck_assert_uint_eq(img.hdr_ok, 0);
|
|
}
|
|
END_TEST
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_FDT) || defined(MMU)
|
|
/* Exercises wolfBoot_verify_dts_digest(), the raw-DTB authentication used by
|
|
* the non-FIT MMU boot path in src/update_ram.c (Fenrir #7998). The reference
|
|
* digest is computed with whichever WOLFBOOT_HASH the build selected, so the
|
|
* SHA256, SHA384 and SHA3-384 variants of wolfBoot_hash_buffer() are all
|
|
* covered (see the unit-image-dts* Makefile targets). */
|
|
START_TEST(test_verify_dts_digest)
|
|
{
|
|
uint8_t dtb[256];
|
|
uint8_t tampered[256];
|
|
uint8_t good[WOLFBOOT_SHA_DIGEST_SIZE];
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < sizeof(dtb); i++)
|
|
dtb[i] = (uint8_t)(i * 7U + 1U);
|
|
|
|
/* Reference digest computed the same way the signer does (image hash over
|
|
* the DTB bytes), using the configured hash algorithm. */
|
|
#if defined(WOLFBOOT_HASH_SHA256)
|
|
{
|
|
wc_Sha256 sha;
|
|
ck_assert_int_eq(wc_InitSha256_ex(&sha, NULL, INVALID_DEVID), 0);
|
|
ck_assert_int_eq(wc_Sha256Update(&sha, dtb, sizeof(dtb)), 0);
|
|
ck_assert_int_eq(wc_Sha256Final(&sha, good), 0);
|
|
wc_Sha256Free(&sha);
|
|
}
|
|
#elif defined(WOLFBOOT_HASH_SHA384)
|
|
{
|
|
wc_Sha384 sha;
|
|
ck_assert_int_eq(wc_InitSha384_ex(&sha, NULL, INVALID_DEVID), 0);
|
|
ck_assert_int_eq(wc_Sha384Update(&sha, dtb, sizeof(dtb)), 0);
|
|
ck_assert_int_eq(wc_Sha384Final(&sha, good), 0);
|
|
wc_Sha384Free(&sha);
|
|
}
|
|
#elif defined(WOLFBOOT_HASH_SHA3_384)
|
|
{
|
|
wc_Sha3 sha;
|
|
ck_assert_int_eq(wc_InitSha3_384(&sha, NULL, INVALID_DEVID), 0);
|
|
ck_assert_int_eq(wc_Sha3_384_Update(&sha, dtb, sizeof(dtb)), 0);
|
|
ck_assert_int_eq(wc_Sha3_384_Final(&sha, good), 0);
|
|
wc_Sha3_384_Free(&sha);
|
|
}
|
|
#else
|
|
#error "test_verify_dts_digest: no supported WOLFBOOT_HASH selected"
|
|
#endif
|
|
|
|
/* Matching digest -> accept. */
|
|
ck_assert_int_eq(wolfBoot_verify_dts_digest(good, dtb, sizeof(dtb)), 0);
|
|
|
|
/* Tampered DTB (single flipped byte) -> reject. */
|
|
memcpy(tampered, dtb, sizeof(dtb));
|
|
tampered[100] ^= 0xFFU;
|
|
ck_assert_int_eq(
|
|
wolfBoot_verify_dts_digest(good, tampered, sizeof(tampered)), -1);
|
|
|
|
/* Wrong expected digest -> reject. */
|
|
good[0] ^= 0xFFU;
|
|
ck_assert_int_eq(wolfBoot_verify_dts_digest(good, dtb, sizeof(dtb)), -1);
|
|
good[0] ^= 0xFFU;
|
|
|
|
/* Bad arguments -> reject. */
|
|
ck_assert_int_eq(wolfBoot_verify_dts_digest(NULL, dtb, sizeof(dtb)), -1);
|
|
ck_assert_int_eq(wolfBoot_verify_dts_digest(good, NULL, sizeof(dtb)), -1);
|
|
ck_assert_int_eq(wolfBoot_verify_dts_digest(good, dtb, 0), -1);
|
|
}
|
|
END_TEST
|
|
#endif /* WOLFBOOT_FDT || MMU */
|
|
|
|
|
|
Suite *wolfboot_suite(void)
|
|
{
|
|
/* Suite initialization */
|
|
Suite *s = suite_create("wolfBoot");
|
|
|
|
#ifdef UNIT_IMAGE_KEYHASH_ONLY
|
|
TCase* tcase_key_hash = tcase_create("key_hash");
|
|
tcase_set_timeout(tcase_key_hash, 20);
|
|
tcase_add_test(tcase_key_hash, test_key_hash_zeroes_output_on_invalid_slot);
|
|
suite_add_tcase(s, tcase_key_hash);
|
|
return s;
|
|
#endif
|
|
|
|
#if defined(UNIT_IMAGE_DTS_ONLY) && (defined(WOLFBOOT_FDT) || defined(MMU))
|
|
/* Only the raw-DTB digest test. Used by the sha384/sha3-384 variants,
|
|
* whose non-SHA256 hash config would break the other unit-image tests. */
|
|
TCase* tcase_dts_only = tcase_create("dts_digest");
|
|
tcase_set_timeout(tcase_dts_only, 20);
|
|
tcase_add_test(tcase_dts_only, test_verify_dts_digest);
|
|
suite_add_tcase(s, tcase_dts_only);
|
|
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);
|
|
tcase_add_test(tcase_verify_signature, test_verify_signature);
|
|
tcase_add_test(tcase_verify_signature, test_keyslot_id_by_sha_scans_all_slots);
|
|
tcase_add_test(tcase_verify_signature, test_key_hash_zeroes_output_on_invalid_slot);
|
|
suite_add_tcase(s, tcase_verify_signature);
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_SIGN_RSA2048) || defined(WOLFBOOT_SIGN_RSA3072) || \
|
|
defined(WOLFBOOT_SIGN_RSA4096) || defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) || \
|
|
defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) || \
|
|
defined(WOLFBOOT_SIGN_SECONDARY_RSA4096)
|
|
TCase* tcase_rsa_asn1 = tcase_create("rsa_asn1");
|
|
tcase_set_timeout(tcase_rsa_asn1, 20);
|
|
tcase_add_test(tcase_rsa_asn1, test_decode_asn1_tag_start_bounds);
|
|
suite_add_tcase(s, tcase_rsa_asn1);
|
|
#endif
|
|
|
|
#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
|
|
|
|
#if !defined(WOLFBOOT_SIGN_RSA2048) && !defined(WOLFBOOT_SIGN_RSA3072) && \
|
|
!defined(WOLFBOOT_SIGN_RSA4096) && !defined(WOLFBOOT_SIGN_SECONDARY_RSA2048) && \
|
|
!defined(WOLFBOOT_SIGN_SECONDARY_RSA3072) && \
|
|
!defined(WOLFBOOT_SIGN_SECONDARY_RSA4096)
|
|
TCase* tcase_sha_ops = tcase_create("sha_ops");
|
|
tcase_set_timeout(tcase_sha_ops, 20);
|
|
tcase_add_test(tcase_sha_ops, test_sha_ops);
|
|
tcase_add_test(tcase_sha_ops, test_peek_image_bounds);
|
|
suite_add_tcase(s, tcase_sha_ops);
|
|
|
|
TCase* tcase_headers = tcase_create("headers");
|
|
tcase_set_timeout(tcase_headers, 20);
|
|
tcase_add_test(tcase_headers, test_headers);
|
|
suite_add_tcase(s, tcase_headers);
|
|
|
|
#ifdef WOLFBOOT_FIXED_PARTITIONS
|
|
TCase* tcase_verify_integrity = tcase_create("verify_integrity");
|
|
tcase_set_timeout(tcase_verify_integrity, 20);
|
|
tcase_add_test(tcase_verify_integrity, test_verify_integrity);
|
|
suite_add_tcase(s, tcase_verify_integrity);
|
|
#endif
|
|
|
|
TCase* tcase_open_image = tcase_create("open_image");
|
|
tcase_set_timeout(tcase_open_image, 20);
|
|
#ifdef WOLFBOOT_FIXED_PARTITIONS
|
|
tcase_add_test(tcase_open_image, test_open_image);
|
|
#else
|
|
tcase_add_test(tcase_open_image,
|
|
test_open_image_address_without_partitions_rejects_oversized_fw_size);
|
|
#endif
|
|
suite_add_tcase(s, tcase_open_image);
|
|
#endif
|
|
|
|
#if defined(WOLFBOOT_FDT) || defined(MMU)
|
|
TCase* tcase_dts_digest = tcase_create("dts_digest");
|
|
tcase_set_timeout(tcase_dts_digest, 20);
|
|
tcase_add_test(tcase_dts_digest, test_verify_dts_digest);
|
|
suite_add_tcase(s, tcase_dts_digest);
|
|
#endif
|
|
return s;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
int fails;
|
|
Suite *s = wolfboot_suite();
|
|
SRunner *sr = srunner_create(s);
|
|
srunner_run_all(sr, CK_NORMAL);
|
|
fails = srunner_ntests_failed(sr);
|
|
srunner_free(sr);
|
|
return fails;
|
|
}
|