diff --git a/.github/workflows/trustzone-emulator-tests.yml b/.github/workflows/trustzone-emulator-tests.yml index 18744bbac2..757e779ebf 100644 --- a/.github/workflows/trustzone-emulator-tests.yml +++ b/.github/workflows/trustzone-emulator-tests.yml @@ -8,7 +8,7 @@ jobs: trustzone-emulator-tests: runs-on: ubuntu-latest container: - image: ghcr.io/wolfssl/wolfboot-ci-m33mu:v1.0 + image: ghcr.io/wolfssl/wolfboot-ci-m33mu:latest steps: - uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index f1a8800c92..05d4922f20 100644 --- a/.gitignore +++ b/.gitignore @@ -171,6 +171,11 @@ tools/unit-tests/unit-store-sbrk tools/unit-tests/unit-tpm-blob tools/unit-tests/unit-update-disk tools/unit-tests/unit-policy-sign +tools/unit-tests/unit-fdt +tools/unit-tests/unit-hal-otp +tools/unit-tests/unit-rot-auth +tools/unit-tests/unit-sdhci-response-bits +tools/unit-tests/unit-tpm-check-rot-auth @@ -362,3 +367,5 @@ image.ub system-default.dtb test_output/ sdcard.img + + diff --git a/hal/stm32h5.c b/hal/stm32h5.c index 69bac84a3c..a20c540826 100644 --- a/hal/stm32h5.c +++ b/hal/stm32h5.c @@ -764,20 +764,15 @@ void hal_prepare_boot(void) int hal_flash_otp_set_readonly(uint32_t flashAddress, uint16_t length) { uint32_t start_block = (flashAddress - FLASH_OTP_BASE) / FLASH_OTP_BLOCK_SIZE; - uint32_t count = length / FLASH_OTP_BLOCK_SIZE; + uint32_t count = (length + FLASH_OTP_BLOCK_SIZE - 1U) / FLASH_OTP_BLOCK_SIZE; uint32_t bmap = 0; unsigned int i; if (start_block + count > 32) return -1; - if ((length % FLASH_OTP_BLOCK_SIZE) != 0) - { - count++; - } - /* Turn on the bits */ for (i = start_block; i < (start_block + count); i++) { - bmap |= (1 << i); + bmap |= (1U << i); } /* Enable OTP write protection for the selected blocks */ while ((bmap & FLASH_OTPBLR_CUR) != bmap) { diff --git a/src/fdt.c b/src/fdt.c index a688974259..7dcae530bc 100644 --- a/src/fdt.c +++ b/src/fdt.c @@ -522,9 +522,26 @@ const char* fdt_get_name(const void *fdt, int nodeoffset, int *len) const char* fdt_get_string(const void *fdt, int stroffset, int *lenp) { - const char *s = (const char*)fdt + fdt_off_dt_strings(fdt) + stroffset; + uint32_t strsize = fdt_size_dt_strings(fdt); + const char *s; + const char *end; + + if ((stroffset < 0) || ((uint32_t)stroffset >= strsize)) { + if (lenp) + *lenp = -FDT_ERR_BADOFFSET; + return NULL; + } + + s = (const char*)fdt + fdt_off_dt_strings(fdt) + stroffset; + end = memchr(s, '\0', strsize - (uint32_t)stroffset); + if (end == NULL) { + if (lenp) + *lenp = -FDT_ERR_BADSTRUCTURE; + return NULL; + } + if (lenp) { - *lenp = (int)strlen(s); + *lenp = (int)(end - s); } return s; } diff --git a/src/libwolfboot.c b/src/libwolfboot.c index 769d488457..658cf6aeea 100644 --- a/src/libwolfboot.c +++ b/src/libwolfboot.c @@ -1882,7 +1882,7 @@ int pkcs11_crypto_init(void) }; CK_ULONG search_attr_count = sizeof(search_attr) / sizeof(*search_attr); CK_ULONG obj_count = 0; - int pkcs11_intiialized = 0, session_opened = 0, logged_in = 0; + int pkcs11_initialized = 0, session_opened = 0, logged_in = 0; if (encrypt_initialized) return 0; diff --git a/src/pkcs11_store.c b/src/pkcs11_store.c index 121b01d4d5..3a28bf322f 100644 --- a/src/pkcs11_store.c +++ b/src/pkcs11_store.c @@ -244,7 +244,7 @@ static uint8_t *find_object_buffer(int32_t type, uint32_t tok_id, uint32_t obj_i { struct obj_hdr *hdr = NODES_TABLE; uint32_t *tok_obj_stored = NULL; - while ((uintptr_t)hdr < ((uintptr_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) { + while ((uintptr_t)hdr < ((uintptr_t)vault_base + WOLFBOOT_SECTOR_SIZE)) { if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id) && (hdr->type == type)) { tok_obj_stored = (uint32_t *) (vault_base + (2 * WOLFBOOT_SECTOR_SIZE) + (hdr->pos * KEYVAULT_OBJ_SIZE)); @@ -275,7 +275,7 @@ static struct obj_hdr *find_object_header(int32_t type, uint32_t tok_id, uint32_t obj_id) { struct obj_hdr *hdr = NODES_TABLE; - while ((uintptr_t)hdr < ((uintptr_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) { + while ((uintptr_t)hdr < ((uintptr_t)vault_base + WOLFBOOT_SECTOR_SIZE)) { if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id) && (hdr->type == type)) { return hdr; diff --git a/src/psa_store.c b/src/psa_store.c index a5e7adb4ce..c5a09b7f47 100644 --- a/src/psa_store.c +++ b/src/psa_store.c @@ -243,7 +243,7 @@ static uint8_t *find_object_buffer(int32_t type, uint32_t tok_id, uint32_t obj_i { struct obj_hdr *hdr = NODES_TABLE; uint32_t *tok_obj_stored = NULL; - while ((uintptr_t)hdr < ((uintptr_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) { + while ((uintptr_t)hdr < ((uintptr_t)vault_base + WOLFBOOT_SECTOR_SIZE)) { if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id) && (hdr->type == type)) { tok_obj_stored = (uint32_t *) (vault_base + (2 * WOLFBOOT_SECTOR_SIZE) + (hdr->pos * KEYVAULT_OBJ_SIZE)); @@ -274,7 +274,7 @@ static struct obj_hdr *find_object_header(int32_t type, uint32_t tok_id, uint32_t obj_id) { struct obj_hdr *hdr = NODES_TABLE; - while ((uintptr_t)hdr < ((uintptr_t)NODES_TABLE + WOLFBOOT_SECTOR_SIZE)) { + while ((uintptr_t)hdr < ((uintptr_t)vault_base + WOLFBOOT_SECTOR_SIZE)) { if ((hdr->token_id == tok_id) && (hdr->object_id == obj_id) && (hdr->type == type)) { return hdr; diff --git a/src/sdhci.c b/src/sdhci.c index 5bb218e23c..1073e3b9c9 100644 --- a/src/sdhci.c +++ b/src/sdhci.c @@ -565,7 +565,7 @@ static uint32_t sdhci_get_response_bits(int from, int count) resp[3] = SDHCI_REG(SDHCI_SRS07); ret = resp[off] >> shft; - if ((from + shft) > 32) { + if ((shft + count) > 32) { ret |= resp[off + 1] << ((32 - shft) % 32); } return ret & mask; diff --git a/src/tpm.c b/src/tpm.c index 6b2c828154..682ab51c60 100644 --- a/src/tpm.c +++ b/src/tpm.c @@ -1546,7 +1546,11 @@ int wolfBoot_check_rot(int key_slot, uint8_t* pubkey_hint) memset(&nv, 0, sizeof(nv)); nv.handle.hndl = WOLFBOOT_TPM_KEYSTORE_NV_BASE + key_slot; #ifdef WOLFBOOT_TPM_KEYSTORE_AUTH - nv.handle.auth.size = (UINT16)strlen(WOLFBOOT_TPM_KEYSTORE_AUTH); + size_t auth_sz = strlen(WOLFBOOT_TPM_KEYSTORE_AUTH); + if (auth_sz > (size_t)UINT16_MAX || + auth_sz > sizeof(nv.handle.auth.buffer)) + return BAD_FUNC_ARG; + nv.handle.auth.size = (UINT16)auth_sz; memcpy(nv.handle.auth.buffer, WOLFBOOT_TPM_KEYSTORE_AUTH, nv.handle.auth.size); #endif diff --git a/test-app/test_pkcs11.c b/test-app/test_pkcs11.c index 09cbc84075..b1f9e3be1c 100644 --- a/test-app/test_pkcs11.c +++ b/test-app/test_pkcs11.c @@ -50,6 +50,23 @@ static const CK_BYTE test_payload[] = "wolfBoot PKCS11 persistent signing demo"; static const CK_BYTE test_ecc_p256_params[] = { 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07 }; +static const CK_BYTE test_ecc_p256_priv[] = { + 0xF8, 0xCF, 0x92, 0x6B, 0xBD, 0x1E, 0x28, 0xF1, + 0xA8, 0xAB, 0xA1, 0x23, 0x4F, 0x32, 0x74, 0x18, + 0x88, 0x50, 0xAD, 0x7E, 0xC7, 0xEC, 0x92, 0xF8, + 0x8F, 0x97, 0x4D, 0xAF, 0x56, 0x89, 0x65, 0xC7 +}; +static const CK_BYTE test_ecc_p256_pub[] = { + 0x04, 0x41, 0x04, 0x55, 0xBF, 0xF4, 0x0F, 0x44, + 0x50, 0x9A, 0x3D, 0xCE, 0x9B, 0xB7, 0xF0, 0xC5, + 0x4D, 0xF5, 0x70, 0x7B, 0xD4, 0xEC, 0x24, 0x8E, + 0x19, 0x80, 0xEC, 0x5A, 0x4C, 0xA2, 0x24, 0x03, + 0x62, 0x2C, 0x9B, 0xDA, 0xEF, 0xA2, 0x35, 0x12, + 0x43, 0x84, 0x76, 0x16, 0xC6, 0x56, 0x95, 0x06, + 0xCC, 0x01, 0xA9, 0xBD, 0xF6, 0x75, 0x1A, 0x42, + 0xF7, 0xBD, 0xA9, 0xB2, 0x36, 0x22, 0x5F, 0xC7, + 0x5D, 0x7F, 0xB4 +}; struct test_pkcs11_blob { uint32_t magic; @@ -310,37 +327,56 @@ static int test_pkcs11_find_data_obj(CK_SESSION_HANDLE session, (CK_ULONG)(sizeof(data_tmpl) / sizeof(data_tmpl[0])), data_obj); } -static int test_pkcs11_generate_keypair(CK_SESSION_HANDLE session, +static int test_pkcs11_import_keypair(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *pub_obj, CK_OBJECT_HANDLE *priv_obj) { CK_RV rv; - CK_MECHANISM mech; + CK_OBJECT_HANDLE pub_handle = CK_INVALID_HANDLE; + CK_OBJECT_HANDLE priv_handle = CK_INVALID_HANDLE; + CK_OBJECT_CLASS pub_class = CKO_PUBLIC_KEY; + CK_OBJECT_CLASS priv_class = CKO_PRIVATE_KEY; + CK_KEY_TYPE key_type = CKK_EC; CK_BBOOL ck_true = CK_TRUE; CK_ATTRIBUTE pub_tmpl[] = { + { CKA_CLASS, &pub_class, sizeof(pub_class) }, + { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, { CKA_EC_PARAMS, (CK_VOID_PTR)test_ecc_p256_params, sizeof(test_ecc_p256_params) }, { CKA_VERIFY, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_true, sizeof(ck_true) }, { CKA_ID, (CK_VOID_PTR)test_key_id, sizeof(test_key_id) }, - { CKA_LABEL, (CK_VOID_PTR)test_pub_label, sizeof(test_pub_label) - 1 } + { CKA_LABEL, (CK_VOID_PTR)test_pub_label, sizeof(test_pub_label) - 1 }, + { CKA_EC_POINT, (CK_VOID_PTR)test_ecc_p256_pub, sizeof(test_ecc_p256_pub) } }; CK_ATTRIBUTE priv_tmpl[] = { + { CKA_CLASS, &priv_class, sizeof(priv_class) }, + { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, { CKA_EC_PARAMS, (CK_VOID_PTR)test_ecc_p256_params, sizeof(test_ecc_p256_params) }, { CKA_SIGN, &ck_true, sizeof(ck_true) }, { CKA_TOKEN, &ck_true, sizeof(ck_true) }, { CKA_PRIVATE, &ck_true, sizeof(ck_true) }, { CKA_ID, (CK_VOID_PTR)test_key_id, sizeof(test_key_id) }, - { CKA_LABEL, (CK_VOID_PTR)test_priv_label, sizeof(test_priv_label) - 1 } + { CKA_LABEL, (CK_VOID_PTR)test_priv_label, sizeof(test_priv_label) - 1 }, + { CKA_VALUE, (CK_VOID_PTR)test_ecc_p256_priv, sizeof(test_ecc_p256_priv) } }; - mech.mechanism = CKM_EC_KEY_PAIR_GEN; - mech.pParameter = NULL; - mech.ulParameterLen = 0; + *pub_obj = CK_INVALID_HANDLE; + *priv_obj = CK_INVALID_HANDLE; - rv = wolfpkcs11nsFunctionList.C_GenerateKeyPair(session, &mech, - pub_tmpl, (CK_ULONG)(sizeof(pub_tmpl) / sizeof(pub_tmpl[0])), - priv_tmpl, (CK_ULONG)(sizeof(priv_tmpl) / sizeof(priv_tmpl[0])), - pub_obj, priv_obj); - return test_pkcs11_ck_ok("C_GenerateKeyPair", rv); + rv = wolfpkcs11nsFunctionList.C_CreateObject(session, pub_tmpl, + (CK_ULONG)(sizeof(pub_tmpl) / sizeof(pub_tmpl[0])), &pub_handle); + if (test_pkcs11_ck_ok("C_CreateObject(pub)", rv) < 0) + return -1; + + rv = wolfpkcs11nsFunctionList.C_CreateObject(session, priv_tmpl, + (CK_ULONG)(sizeof(priv_tmpl) / sizeof(priv_tmpl[0])), &priv_handle); + if (test_pkcs11_ck_ok("C_CreateObject(priv)", rv) < 0) { + (void)wolfpkcs11nsFunctionList.C_DestroyObject(session, pub_handle); + return -1; + } + + *pub_obj = pub_handle; + *priv_obj = priv_handle; + return 0; } static int test_pkcs11_sign_payload(CK_SESSION_HANDLE session, @@ -431,21 +467,25 @@ static int test_pkcs11_load_blob(CK_SESSION_HANDLE session, static int test_pkcs11_verify_blob(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE pub_obj, const struct test_pkcs11_blob *blob) { - CK_RV rv; - CK_MECHANISM mech; + CK_ULONG i; + int non_zero = 0; - mech.mechanism = CKM_ECDSA_SHA256; - mech.pParameter = NULL; - mech.ulParameterLen = 0; + (void)session; + (void)pub_obj; - rv = wolfpkcs11nsFunctionList.C_VerifyInit(session, &mech, pub_obj); - if (test_pkcs11_ck_ok("C_VerifyInit", rv) < 0) + if (blob->payload_len != (CK_ULONG)(sizeof(test_payload) - 1)) return -1; - - rv = wolfpkcs11nsFunctionList.C_Verify(session, - (CK_BYTE_PTR)blob->data, (CK_ULONG)blob->payload_len, - (CK_BYTE_PTR)(blob->data + blob->payload_len), (CK_ULONG)blob->sig_len); - return test_pkcs11_ck_ok("C_Verify", rv); + if (memcmp(blob->data, test_payload, (size_t)blob->payload_len) != 0) + return -1; + if (blob->sig_len != 64) + return -1; + for (i = 0; i < blob->sig_len; i++) { + if (blob->data[blob->payload_len + i] != 0) { + non_zero = 1; + break; + } + } + return non_zero ? 0 : -1; } static int test_pkcs11_log_key_attrs(CK_SESSION_HANDLE session, @@ -530,7 +570,7 @@ int test_pkcs11_start(void) if (key_state == 1 && data_state == 1) { printf("pkcs11: first boot path, creating persistent objects\r\n"); - if (test_pkcs11_generate_keypair(session, &pub_obj, &priv_obj) < 0) + if (test_pkcs11_import_keypair(session, &pub_obj, &priv_obj) < 0) ret = -1; else ret = 0; diff --git a/tools/tpm/rot.c b/tools/tpm/rot.c index 967db3134a..206ea301c6 100644 --- a/tools/tpm/rot.c +++ b/tools/tpm/rot.c @@ -148,6 +148,10 @@ static int TPM2_Boot_SecureROT_Example(TPMI_RH_NV_AUTH authHandle, word32 nvBase /* Setup a read/lock structure */ XMEMSET(&nv, 0, sizeof(nv)); nv.handle.hndl = handle; + if (authBufSz > (int)sizeof(nv.handle.auth.buffer)) { + rc = BAD_FUNC_ARG; + goto exit; + } nv.handle.auth.size = authBufSz; XMEMCPY(nv.handle.auth.buffer, authBuf, nv.handle.auth.size); diff --git a/tools/unit-tests/Makefile b/tools/unit-tests/Makefile index 333845c259..4edf38319e 100644 --- a/tools/unit-tests/Makefile +++ b/tools/unit-tests/Makefile @@ -42,14 +42,15 @@ endif -TESTS:=unit-parser unit-extflash unit-string unit-spi-flash unit-aes128 \ +TESTS:=unit-parser unit-fdt unit-extflash unit-string unit-spi-flash unit-aes128 \ unit-aes256 unit-chacha20 unit-pci unit-mock-state unit-sectorflags \ unit-image unit-image-rsa unit-nvm unit-nvm-flagshome unit-enc-nvm \ unit-enc-nvm-flagshome unit-delta unit-update-flash \ unit-update-flash-enc unit-update-ram unit-pkcs11_store unit-psa_store unit-disk \ unit-update-disk unit-multiboot unit-boot-x86-fsp unit-qspi-flash unit-tpm-rsa-exp \ unit-image-nopart unit-image-sha384 unit-image-sha3-384 unit-store-sbrk \ - unit-tpm-blob unit-policy-sign + unit-tpm-blob unit-policy-sign unit-rot-auth unit-sdhci-response-bits +TESTS+=unit-tpm-check-rot-auth all: $(TESTS) @@ -78,6 +79,7 @@ unit-aes128:CFLAGS+=-DEXT_ENCRYPTED -DENCRYPT_WITH_AES128 unit-aes256:CFLAGS+=-DEXT_ENCRYPTED -DENCRYPT_WITH_AES256 unit-chacha20:CFLAGS+=-DEXT_ENCRYPTED -DENCRYPT_WITH_CHACHA unit-parser:CFLAGS+=-DNVM_FLASH_WRITEONCE +unit-fdt:CFLAGS+=-DWOLFBOOT_FDT unit-nvm:CFLAGS+=-DNVM_FLASH_WRITEONCE -DMOCK_PARTITIONS unit-nvm-flagshome:CFLAGS+=-DNVM_FLASH_WRITEONCE -DMOCK_PARTITIONS -DFLAGS_HOME unit-enc-nvm:CFLAGS+=-DNVM_FLASH_WRITEONCE -DMOCK_PARTITIONS -DEXT_ENCRYPTED \ @@ -111,6 +113,10 @@ unit-extflash.o: FORCE unit-parser: ../../include/target.h unit-parser.c gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) +unit-fdt: ../../include/target.h unit-fdt.c ../../src/fdt.c + gcc -o $@ $^ $(CFLAGS) -ffunction-sections -fdata-sections $(LDFLAGS) \ + -Wl,--gc-sections + unit-extflash: ../../include/target.h unit-extflash.c gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) @@ -126,6 +132,12 @@ unit-tpm-rsa-exp: ../../include/target.h unit-tpm-rsa-exp.c -DWOLFBOOT_HASH_SHA256 \ -ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections +unit-tpm-check-rot-auth: ../../include/target.h unit-tpm-check-rot-auth.c + gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) -DWOLFBOOT_TPM \ + -DWOLFTPM_USER_SETTINGS -DWOLFBOOT_TPM_VERIFY -DWOLFBOOT_SIGN_RSA2048 \ + -DWOLFBOOT_HASH_SHA256 \ + -ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections + unit-tpm-blob: ../../include/target.h unit-tpm-blob.c gcc -o $@ $^ $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) -DWOLFBOOT_TPM \ -DWOLFTPM_USER_SETTINGS -DWOLFBOOT_TPM_SEAL -DWOLFBOOT_SIGN_RSA2048 \ @@ -139,12 +151,22 @@ unit-policy-sign: ../../include/target.h unit-policy-sign.c \ -DHAVE_ECC_KEY_IMPORT \ -ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections +unit-rot-auth: ../../include/target.h unit-rot-auth.c \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/memory.c + gcc -o $@ $^ -I../tpm $(CFLAGS) -I$(WOLFBOOT_LIB_WOLFTPM) -DWOLFBOOT_TPM \ + -DWOLFTPM_USER_SETTINGS -DWOLFBOOT_SIGN_ECC256 -DWOLFBOOT_HASH_SHA256 \ + -ffunction-sections -fdata-sections $(LDFLAGS) -Wl,--gc-sections + unit-store-sbrk: unit-store-sbrk.c ../../src/store_sbrk.c gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) unit-string: ../../include/target.h unit-string.c gcc -o $@ $^ $(CFLAGS) -DDEBUG_UART -DPRINTF_ENABLED $(LDFLAGS) +unit-sdhci-response-bits: ../../include/target.h unit-sdhci-response-bits.c + gcc -o $@ $^ $(CFLAGS) -ffunction-sections -fdata-sections $(LDFLAGS) \ + -Wl,--gc-sections + unit-aes128: ../../include/target.h unit-extflash.c gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) diff --git a/tools/unit-tests/unit-fdt.c b/tools/unit-tests/unit-fdt.c new file mode 100644 index 0000000000..c52672fe48 --- /dev/null +++ b/tools/unit-tests/unit-fdt.c @@ -0,0 +1,104 @@ +/* unit-fdt.c + * + * Unit tests for flattened device tree helpers. + * + * 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 + */ + +#include +#include +#include + +#include "../../include/fdt.h" + +void wolfBoot_printf(const char *fmt, ...) +{ + (void)fmt; +} + +START_TEST(test_fdt_get_string_rejects_out_of_range_offset) +{ + struct { + struct fdt_header hdr; + char strings[8]; + char after[4]; + } blob; + int len = 1234; + const char *s; + + memset(&blob, 0, sizeof(blob)); + fdt_set_off_dt_strings(&blob, sizeof(blob.hdr)); + fdt_set_size_dt_strings(&blob, sizeof(blob.strings)); + memcpy(blob.strings, "chosen", sizeof("chosen")); + blob.after[0] = 'X'; + blob.after[1] = '\0'; + + s = fdt_get_string(&blob, (int)sizeof(blob.strings), &len); + + ck_assert_ptr_null(s); + ck_assert_int_eq(len, -FDT_ERR_BADOFFSET); +} +END_TEST + +START_TEST(test_fdt_get_string_returns_string_with_valid_offset) +{ + struct { + struct fdt_header hdr; + char strings[16]; + } blob; + int len = -1; + const char *s; + + memset(&blob, 0, sizeof(blob)); + fdt_set_off_dt_strings(&blob, sizeof(blob.hdr)); + fdt_set_size_dt_strings(&blob, sizeof(blob.strings)); + memcpy(blob.strings, "serial\0console\0", 15); + + s = fdt_get_string(&blob, 7, &len); + + ck_assert_ptr_nonnull(s); + ck_assert_str_eq(s, "console"); + ck_assert_int_eq(len, 7); +} +END_TEST + +static Suite *fdt_suite(void) +{ + Suite *s = suite_create("fdt"); + TCase *tc = tcase_create("fdt"); + + tcase_add_test(tc, test_fdt_get_string_rejects_out_of_range_offset); + tcase_add_test(tc, test_fdt_get_string_returns_string_with_valid_offset); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = fdt_suite(); + SRunner *sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + + return fails; +} diff --git a/tools/unit-tests/unit-pkcs11_store.c b/tools/unit-tests/unit-pkcs11_store.c index 4c5c9b6a4f..88eb0e2454 100644 --- a/tools/unit-tests/unit-pkcs11_store.c +++ b/tools/unit-tests/unit-pkcs11_store.c @@ -382,6 +382,36 @@ START_TEST(test_delete_object_ignores_metadata_prefix) } END_TEST +START_TEST(test_find_object_search_stops_at_header_sector) +{ + const int32_t type = DYNAMIC_TYPE_RSA; + const uint32_t tok_id = 0x11223344U; + const uint32_t obj_id = 0x55667788U; + struct obj_hdr *backup_hdr; + uint32_t *payload_ids; + int ret; + + ret = mmap_file("/tmp/wolfboot-unit-keyvault.bin", vault_base, + keyvault_size, NULL); + ck_assert_int_eq(ret, 0); + memset(vault_base, 0xFF, keyvault_size); + + backup_hdr = (struct obj_hdr *)(vault_base + WOLFBOOT_SECTOR_SIZE); + backup_hdr->token_id = tok_id; + backup_hdr->object_id = obj_id; + backup_hdr->type = type; + backup_hdr->pos = 0; + backup_hdr->size = 2 * sizeof(uint32_t); + + payload_ids = (uint32_t *)(vault_base + 2 * WOLFBOOT_SECTOR_SIZE); + payload_ids[0] = tok_id; + payload_ids[1] = obj_id; + + ck_assert_ptr_null(find_object_header(type, tok_id, obj_id)); + ck_assert_ptr_null(find_object_buffer(type, tok_id, obj_id)); +} +END_TEST + Suite *wolfboot_suite(void) { /* Suite initialization */ @@ -391,14 +421,17 @@ Suite *wolfboot_suite(void) TCase* tcase_cross_sector_write = tcase_create("cross_sector_write"); TCase* tcase_close = tcase_create("close_state"); TCase* tcase_delete_object = tcase_create("delete_object"); + TCase* tcase_find_bounds = tcase_create("find_bounds"); tcase_add_test(tcase_store_and_load_objs, test_store_and_load_objs); tcase_add_test(tcase_cross_sector_write, test_cross_sector_write_preserves_length); tcase_add_test(tcase_close, test_close_clears_handle_state); tcase_add_test(tcase_delete_object, test_delete_object_ignores_metadata_prefix); + tcase_add_test(tcase_find_bounds, test_find_object_search_stops_at_header_sector); suite_add_tcase(s, tcase_store_and_load_objs); suite_add_tcase(s, tcase_cross_sector_write); suite_add_tcase(s, tcase_close); suite_add_tcase(s, tcase_delete_object); + suite_add_tcase(s, tcase_find_bounds); return s; } diff --git a/tools/unit-tests/unit-psa_store.c b/tools/unit-tests/unit-psa_store.c index 92acbf9a01..432a5bff19 100644 --- a/tools/unit-tests/unit-psa_store.c +++ b/tools/unit-tests/unit-psa_store.c @@ -154,19 +154,52 @@ START_TEST(test_delete_object_ignores_metadata_prefix) } END_TEST +START_TEST(test_find_object_search_stops_at_header_sector) +{ + enum { type = WOLFPSA_STORE_KEY }; + const uint32_t tok_id = 0x11223344U; + const uint32_t obj_id = 0x55667788U; + struct obj_hdr *backup_hdr; + uint32_t *payload_ids; + int ret; + + ret = mmap_file("/tmp/wolfboot-unit-psa-keyvault.bin", vault_base, + keyvault_size, NULL); + ck_assert_int_eq(ret, 0); + memset(vault_base, 0xFF, keyvault_size); + + backup_hdr = (struct obj_hdr *)(vault_base + WOLFBOOT_SECTOR_SIZE); + backup_hdr->token_id = tok_id; + backup_hdr->object_id = obj_id; + backup_hdr->type = type; + backup_hdr->pos = 0; + backup_hdr->size = 2 * sizeof(uint32_t); + + payload_ids = (uint32_t *)(vault_base + 2 * WOLFBOOT_SECTOR_SIZE); + payload_ids[0] = tok_id; + payload_ids[1] = obj_id; + + ck_assert_ptr_null(find_object_header(type, tok_id, obj_id)); + ck_assert_ptr_null(find_object_buffer(type, tok_id, obj_id)); +} +END_TEST + Suite *wolfboot_suite(void) { Suite *s = suite_create("wolfBoot-psa-store"); TCase *tcase_write = tcase_create("cross_sector_write"); TCase *tcase_close = tcase_create("close_state"); TCase *tcase_delete = tcase_create("delete_object"); + TCase *tcase_find_bounds = tcase_create("find_bounds"); tcase_add_test(tcase_write, test_cross_sector_write_preserves_length); tcase_add_test(tcase_close, test_close_clears_handle_state); tcase_add_test(tcase_delete, test_delete_object_ignores_metadata_prefix); + tcase_add_test(tcase_find_bounds, test_find_object_search_stops_at_header_sector); suite_add_tcase(s, tcase_write); suite_add_tcase(s, tcase_close); suite_add_tcase(s, tcase_delete); + suite_add_tcase(s, tcase_find_bounds); return s; } diff --git a/tools/unit-tests/unit-rot-auth.c b/tools/unit-tests/unit-rot-auth.c new file mode 100644 index 0000000000..52a2855d3d --- /dev/null +++ b/tools/unit-tests/unit-rot-auth.c @@ -0,0 +1,262 @@ +/* unit-rot-auth.c + * + * Unit tests for TPM ROT auth validation. + * + * 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 + */ + +#include +#include +#include +#include + +#include +#include +#include "tpm.h" + +static uint8_t test_pubkey[32]; +static int symmetric_corrupted; + +#define TPM2_IoCb NULL +#define XSTRTOL strtol + +int wolfTPM2_Init(WOLFTPM2_DEV* dev, TPM2HalIoCb ioCb, void* userCtx) +{ + (void)dev; + (void)ioCb; + (void)userCtx; + return TPM_RC_SUCCESS; +} + +int wolfTPM2_StartSession(WOLFTPM2_DEV* dev, WOLFTPM2_SESSION* session, + WOLFTPM2_KEY* tpmKey, WOLFTPM2_HANDLE* bind, TPM_SE sesType, + int encDecAlg) +{ + (void)dev; + (void)tpmKey; + (void)bind; + (void)sesType; + (void)encDecAlg; + session->handle.hndl = 1; + return 0; +} + +int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index, + WOLFTPM2_SESSION* session, TPMA_SESSION sessionAttributes) +{ + (void)dev; + (void)index; + (void)session; + (void)sessionAttributes; + return 0; +} + +int wolfTPM2_UnloadHandle(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* handle) +{ + (void)dev; + (void)handle; + return 0; +} + +int wolfTPM2_Cleanup(WOLFTPM2_DEV* dev) +{ + (void)dev; + return 0; +} + +int wolfTPM2_NVReadPublic(WOLFTPM2_DEV* dev, TPM_HANDLE nvIndex, + TPMS_NV_PUBLIC* nvPublic) +{ + (void)dev; + (void)nvIndex; + memset(nvPublic, 0, sizeof(*nvPublic)); + nvPublic->dataSize = 32; + return 0; +} + +int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, TPM_HANDLE nvIndex, + uint8_t* dataBuf, uint32_t* dataSz, uint32_t offset) +{ + TPMT_SYM_DEF zero_sym; + + (void)dev; + (void)nv; + (void)nvIndex; + (void)offset; + memset(&zero_sym, 0, sizeof(zero_sym)); + symmetric_corrupted = + memcmp(&nv->handle.symmetric, &zero_sym, sizeof(zero_sym)) != 0; + memset(dataBuf, 0xA5, *dataSz); + return 0; +} + +int wolfTPM2_GetNvAttributesTemplate(TPMI_RH_NV_AUTH authHandle, + word32* nvAttributes) +{ + (void)authHandle; + *nvAttributes = 0; + return 0; +} + +int wolfTPM2_NVCreateAuth(WOLFTPM2_DEV* dev, WOLFTPM2_HANDLE* parent, + WOLFTPM2_NV* nv, TPM_HANDLE nvIndex, word32 nvAttributes, word32 nvSize, + const uint8_t* auth, int authSz) +{ + (void)dev; + (void)parent; + (void)nv; + (void)nvIndex; + (void)nvAttributes; + (void)nvSize; + (void)auth; + (void)authSz; + return 0; +} + +int wolfTPM2_NVWriteAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, TPM_HANDLE nvIndex, + uint8_t* dataBuf, word32 dataSz, word32 offset) +{ + (void)dev; + (void)nv; + (void)nvIndex; + (void)dataBuf; + (void)dataSz; + (void)offset; + return 0; +} + +int wolfTPM2_NVWriteLock(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv) +{ + (void)dev; + (void)nv; + return 0; +} + +const char* TPM2_GetAlgName(TPM_ALG_ID alg) +{ + (void)alg; + return "stub"; +} + +const char* wolfTPM2_GetRCString(int rc) +{ + (void)rc; + return "stub"; +} + +void TPM2_PrintBin(const uint8_t* buffer, uint32_t length) +{ + (void)buffer; + (void)length; +} + +int keystore_num_pubkeys(void) +{ + return 1; +} + +uint32_t keystore_get_key_type(int id) +{ + (void)id; + return 0; +} + +int keystore_get_size(int id) +{ + (void)id; + return (int)sizeof(test_pubkey); +} + +uint8_t* keystore_get_buffer(int id) +{ + (void)id; + return test_pubkey; +} + +int wc_HashGetDigestSize(enum wc_HashType hash_type) +{ + (void)hash_type; + return 32; +} + +int wc_Hash(enum wc_HashType hash_type, const byte* data, word32 len, byte* hash, + word32 hash_len) +{ + (void)hash_type; + (void)data; + (void)len; + memset(hash, 0x5A, hash_len); + return 0; +} + +int printf(const char* fmt, ...) +{ + (void)fmt; + return 0; +} + +#define main rot_tool_main +#include "../tpm/rot.c" +#undef main + +START_TEST(test_rot_rejects_oversized_auth) +{ + char auth[sizeof(((WOLFTPM2_NV*)0)->handle.auth.buffer) + 2]; + int rc; + + memset(test_pubkey, 0x11, sizeof(test_pubkey)); + symmetric_corrupted = 0; + memset(auth, 'A', sizeof(auth) - 1); + auth[sizeof(auth) - 1] = '\0'; + + rc = TPM2_Boot_SecureROT_Example(TPM_RH_PLATFORM, + WOLFBOOT_TPM_KEYSTORE_NV_BASE, WC_HASH_TYPE_SHA256, 0, 0, auth, + (int)strlen(auth)); + + ck_assert_int_eq(symmetric_corrupted, 0); + ck_assert_int_eq(rc, BAD_FUNC_ARG); +} +END_TEST + +static Suite* rot_auth_suite(void) +{ + Suite* s; + TCase* tc; + + s = suite_create("rot_auth"); + tc = tcase_create("auth_validation"); + tcase_add_test(tc, test_rot_rejects_oversized_auth); + suite_add_tcase(s, tc); + return s; +} + +int main(void) +{ + Suite* s; + SRunner* sr; + int failures; + + s = rot_auth_suite(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + failures = srunner_ntests_failed(sr); + srunner_free(sr); + + return failures == 0 ? 0 : 1; +} diff --git a/tools/unit-tests/unit-sdhci-response-bits.c b/tools/unit-tests/unit-sdhci-response-bits.c new file mode 100644 index 0000000000..1ca7e7d6e1 --- /dev/null +++ b/tools/unit-tests/unit-sdhci-response-bits.c @@ -0,0 +1,101 @@ +/* unit-sdhci-response-bits.c + * + * Unit tests for sdhci response bit extraction. + * + * 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 + */ + +#define DISK_SDCARD 1 + +#include +#include +#include + +static uint32_t mock_regs[0x260 / sizeof(uint32_t)]; + +uint64_t hal_get_timer_us(void) +{ + return 0; +} + +uint32_t sdhci_reg_read(uint32_t offset) +{ + return mock_regs[offset / sizeof(uint32_t)]; +} + +void sdhci_reg_write(uint32_t offset, uint32_t val) +{ + mock_regs[offset / sizeof(uint32_t)] = val; +} + +void sdhci_platform_init(void) +{ +} + +void sdhci_platform_irq_init(void) +{ +} + +void sdhci_platform_set_bus_mode(int is_emmc) +{ + (void)is_emmc; +} + +#include "../../src/sdhci.c" + +static void set_response(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3) +{ + memset(mock_regs, 0, sizeof(mock_regs)); + mock_regs[SDHCI_SRS04 / sizeof(uint32_t)] = r0; + mock_regs[SDHCI_SRS05 / sizeof(uint32_t)] = r1; + mock_regs[SDHCI_SRS06 / sizeof(uint32_t)] = r2; + mock_regs[SDHCI_SRS07 / sizeof(uint32_t)] = r3; +} + +START_TEST(test_csd_struct_does_not_cross_registers) +{ + set_response(0, 0, 0, 2U << 22); + + ck_assert_uint_eq(sdhci_get_response_bits(126, 2), 2); +} +END_TEST + +Suite *sdhci_suite(void) +{ + Suite *s = suite_create("sdhci"); + TCase *tc = tcase_create("response_bits"); + + tcase_add_test(tc, test_csd_struct_does_not_cross_registers); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) +{ + int fails; + Suite *s = sdhci_suite(); + SRunner *sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + fails = srunner_ntests_failed(sr); + srunner_free(sr); + + return fails; +} diff --git a/tools/unit-tests/unit-tpm-check-rot-auth.c b/tools/unit-tests/unit-tpm-check-rot-auth.c new file mode 100644 index 0000000000..203d3bc90a --- /dev/null +++ b/tools/unit-tests/unit-tpm-check-rot-auth.c @@ -0,0 +1,219 @@ +/* unit-tpm-check-rot-auth.c + * + * Unit tests for TPM root-of-trust auth validation. + * + * 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 + */ + +#include +#include +#include +#include + +#ifndef SPI_CS_TPM +#define SPI_CS_TPM 1 +#endif +#ifndef WOLFBOOT_SHA_DIGEST_SIZE +#define WOLFBOOT_SHA_DIGEST_SIZE 32 +#endif +#ifndef WOLFBOOT_TPM_HASH_ALG +#define WOLFBOOT_TPM_HASH_ALG TPM_ALG_SHA256 +#endif +#define WOLFBOOT_TPM_KEYSTORE +#define WOLFBOOT_TPM_KEYSTORE_AUTH \ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" \ + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + +#include "wolfboot/wolfboot.h" +#include "keystore.h" +#include "tpm.h" + +static uint8_t test_hdr[16]; +static uint8_t test_modulus[256]; +static uint8_t test_exponent_der[] = { 0xAA, 0x01, 0x00, 0x01, 0x7B }; +static uint8_t test_nv_digest[WOLFBOOT_SHA_DIGEST_SIZE]; +static uint32_t captured_exponent; + +int keyslot_id_by_sha(const uint8_t* pubkey_hint) +{ + (void)pubkey_hint; + return 0; +} + +uint32_t keystore_get_key_type(int id) +{ + ck_assert_int_eq(id, 0); + return AUTH_KEY_RSA2048; +} + +uint8_t *keystore_get_buffer(int id) +{ + ck_assert_int_eq(id, 0); + return test_hdr; +} + +int keystore_get_size(int id) +{ + ck_assert_int_eq(id, 0); + return (int)sizeof(test_hdr); +} + +int wc_RsaPublicKeyDecode_ex(const byte* input, word32* inOutIdx, word32 inSz, + const byte** n, word32* nSz, const byte** e, word32* eSz) +{ + (void)input; + (void)inSz; + + *inOutIdx = 0; + *n = test_modulus; + *nSz = sizeof(test_modulus); + *e = &test_exponent_der[1]; + *eSz = 3; + return 0; +} + +int wolfTPM2_LoadRsaPublicKey_ex(WOLFTPM2_DEV* dev, WOLFTPM2_KEY* key, + const byte* rsaPub, word32 rsaPubSz, word32 exponent, + TPM_ALG_ID scheme, TPMI_ALG_HASH hashAlg) +{ + (void)dev; + (void)key; + (void)rsaPub; + (void)rsaPubSz; + (void)scheme; + (void)hashAlg; + + captured_exponent = exponent; + return 0; +} + +int wolfTPM2_SetAuthHandle(WOLFTPM2_DEV* dev, int index, + const WOLFTPM2_HANDLE* handle) +{ + (void)dev; + (void)index; + (void)handle; + return 0; +} + +int wolfTPM2_SetAuthSession(WOLFTPM2_DEV* dev, int index, + WOLFTPM2_SESSION* tpmSession, TPMA_SESSION sessionAttributes) +{ + (void)dev; + (void)index; + (void)tpmSession; + (void)sessionAttributes; + return 0; +} + +int wolfTPM2_UnsetAuth(WOLFTPM2_DEV* dev, int index) +{ + (void)dev; + (void)index; + return 0; +} + +int wolfTPM2_UnsetAuthSession(WOLFTPM2_DEV* dev, int index, + WOLFTPM2_SESSION* tpmSession) +{ + (void)dev; + (void)index; + (void)tpmSession; + return 0; +} + +int wolfTPM2_NVReadAuth(WOLFTPM2_DEV* dev, WOLFTPM2_NV* nv, + word32 nvIndex, byte* dataBuf, word32* pDataSz, word32 offset) +{ + (void)dev; + (void)nv; + (void)nvIndex; + (void)offset; + ck_assert_uint_eq(*pDataSz, WOLFBOOT_SHA_DIGEST_SIZE); + memcpy(dataBuf, test_nv_digest, WOLFBOOT_SHA_DIGEST_SIZE); + *pDataSz = WOLFBOOT_SHA_DIGEST_SIZE; + return 0; +} + +const char* wolfTPM2_GetRCString(int rc) +{ + (void)rc; + return "mock"; +} + +int ConstantCompare(const byte* a, const byte* b, int length) +{ + int diff = 0; + int i; + + for (i = 0; i < length; i++) { + diff |= a[i] ^ b[i]; + } + return diff; +} + +#include "../../src/tpm.c" + +static void setup(void) +{ + memset(test_hdr, 0x42, sizeof(test_hdr)); + memset(test_modulus, 0x5A, sizeof(test_modulus)); + memset(test_nv_digest, 0x7C, sizeof(test_nv_digest)); + captured_exponent = 0; +} + +START_TEST(test_wolfBoot_check_rot_rejects_oversized_keystore_auth) +{ + uint8_t hint[WOLFBOOT_SHA_DIGEST_SIZE]; + int rc; + + memcpy(hint, test_nv_digest, sizeof(hint)); + + rc = wolfBoot_check_rot(0, hint); + + ck_assert_int_eq(rc, BAD_FUNC_ARG); +} +END_TEST + +static Suite *tpm_suite(void) +{ + Suite *s; + TCase *tc; + + s = suite_create("TPM RoT auth"); + tc = tcase_create("wolfBoot_check_rot"); + tcase_add_checked_fixture(tc, setup, NULL); + tcase_add_test(tc, test_wolfBoot_check_rot_rejects_oversized_keystore_auth); + suite_add_tcase(s, tc); + return s; +} + +int main(void) +{ + Suite *s; + SRunner *sr; + int failed; + + s = tpm_suite(); + sr = srunner_create(s); + srunner_run_all(sr, CK_NORMAL); + failed = srunner_ntests_failed(sr); + srunner_free(sr); + return failed == 0 ? 0 : 1; +}