diff --git a/test-refactor/README.md b/test-refactor/README.md
index 88e068270..74e832d66 100644
--- a/test-refactor/README.md
+++ b/test-refactor/README.md
@@ -93,6 +93,7 @@ Translated tests:
| `wh_test_auth.c` (`whTest_AuthMEM` / `whTest_AuthTest` sub-tests) | `client-server/wh_test_auth.c::{whTest_AuthBadArgs, whTest_AuthLogin, whTest_AuthLogout, whTest_AuthAddUser, whTest_AuthDeleteUser, whTest_AuthSetPermissions, whTest_AuthSetCredentials, whTest_AuthRequestAuthorization}` | Client | Under `WOLFHSM_CFG_ENABLE_AUTHENTICATION` the POSIX server installs an auth context + admin user and the client logs in as admin at connect, so the ordinary client tests run authorized; each auth test brackets its own session (logout to start clean, restore admin on exit). Uses the blocking client API; the legacy own-server setup and single-thread manual-pump are dropped. Build with `make AUTH=1`. The TCP/client-only variant (`whTest_AuthTCP`) is not ported |
| `wh_test_she.c` (`whTest_SheMasterEcuKeyFallback`, `whTest_SheReqSizeChecking`) | `server/wh_test_she_server.c::{whTest_SheMasterEcuKeyFallback, whTest_SheReqSizeChecking}` | Server | server-internal checks reworked to use the shared server context; the POSIX server config gains a `whServerSheContext` under `WOLFHSM_CFG_SHE_EXTENSION` |
| `wh_test_she.c::whTest_She` (client flows) | `client-server/wh_test_she.c::whTest_She` | Client | SHE UID/secure-boot state is one-shot per server lifetime, so the three legacy client flows are folded into one test that does `SetUid` plus a single comm-boundary-sized secure boot, then the load-key vectors, UID handling, RND, ECB/CBC/MAC, and write-protect rejection -- all of which only need UID set and secure boot complete. Build with `make SHE=1` |
+| `wh_test_server_img_mgr.c::whTest_ServerImgMgr` | `server/wh_test_server_img_mgr.c::whTest_ServerImgMgr` | Server | Per-method subtests (ECC P256, AES-CMAC, RSA2048, wolfBoot RSA4096, and -- under `WOLFHSM_CFG_CERTIFICATE_MANAGER` -- wolfBoot cert chain) run against the shared server context instead of each building its own server/NVM/transport. Each subtest scrubs the NVM objects and key-cache entries it creates so the group's shared NVM stays clean. Legacy ran FLASH and FLASH_LOG backends; the port runs the plain flash backend only -- FLASH_LOG re-run pending (see Known coverage gaps) |
Not yet migrated (still live in `wolfHSM/test/`):
@@ -108,7 +109,6 @@ Not yet migrated (still live in `wolfHSM/test/`):
| `wh_test_lock.c::whTest_LockConfig`, `whTest_LockPosix` | `whTest_LockConfig` to be reworked to fit the Misc group, likely with a context param. |
| `wh_test_log.c::whTest_Log`, `whTest_LogBackend_RunAll` | `whTest_LogBackend_RunAll` to be reworked to fit the Misc group, likely with a context param. |
| `wh_test_timeout.c::whTest_TimeoutPosix` | |
-| `wh_test_server_img_mgr.c::whTest_ServerImgMgr` | |
| `wh_test_nvmflags.c::whTest_NvmFlags` | |
| `wh_test_flash_fault_inject.c` | |
| `wh_test_check_struct_padding.c` | |
diff --git a/test-refactor/server/wh_test_server_img_mgr.c b/test-refactor/server/wh_test_server_img_mgr.c
new file mode 100644
index 000000000..7355bb7d9
--- /dev/null
+++ b/test-refactor/server/wh_test_server_img_mgr.c
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2026 wolfSSL Inc.
+ *
+ * This file is part of wolfHSM.
+ *
+ * wolfHSM 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.
+ *
+ * wolfHSM 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 wolfHSM. If not, see .
+ */
+/*
+ * test-refactor/server/wh_test_server_img_mgr.c
+ *
+ * Server-side image manager test suite. Exercises the built-in
+ * verify methods (ECC, AES-CMAC, RSA, wolfBoot) through direct
+ * server API calls against the shared server context.
+ */
+
+#include "wolfhsm/wh_settings.h"
+
+#if defined(WOLFHSM_CFG_SERVER_IMG_MGR) && \
+ defined(WOLFHSM_CFG_ENABLE_SERVER) && !defined(WOLFHSM_CFG_NO_CRYPTO)
+
+#include
+#include
+#include
+
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_nvm.h"
+#include "wolfhsm/wh_server.h"
+#include "wolfhsm/wh_server_img_mgr.h"
+#include "wolfhsm/wh_server_keystore.h"
+
+#include "wolfssl/wolfcrypt/settings.h"
+#include "wolfssl/wolfcrypt/types.h"
+#include "wolfssl/wolfcrypt/ecc.h"
+#include "wolfssl/wolfcrypt/sha256.h"
+#include "wolfssl/wolfcrypt/asn.h"
+#include "wolfssl/wolfcrypt/random.h"
+#include "wolfssl/wolfcrypt/cmac.h"
+#include "wolfssl/wolfcrypt/aes.h"
+#include "wolfssl/wolfcrypt/rsa.h"
+
+#include "wh_test_common.h"
+#include "wh_test_list.h"
+
+#ifndef NO_RSA
+#include "gen/wh_test_wolfboot_img_data.h"
+#endif
+
+/* Test data to be "verified" */
+static const uint8_t testData[] = {
+ 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64,
+ 0x21, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61,
+ 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6D, 0x65, 0x73, 0x73, 0x61,
+ 0x67, 0x65, 0x20, 0x66, 0x6F, 0x72, 0x20, 0x45, 0x43, 0x43, 0x20,
+ 0x73, 0x69, 0x67, 0x6E, 0x61, 0x74, 0x75, 0x72, 0x65, 0x20, 0x76,
+ 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69};
+
+#ifdef HAVE_ECC
+/* Hardcoded ECC P256 private key for testing (DER format) */
+/* ./certs/ecc-key.der, ECC */
+static const unsigned char testEccPrivKey[] = {
+ 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x45, 0xB6, 0x69, 0x02,
+ 0x73, 0x9C, 0x6C, 0x85, 0xA1, 0x38, 0x5B, 0x72, 0xE8, 0xE8, 0xC7,
+ 0xAC, 0xC4, 0x03, 0x8D, 0x53, 0x35, 0x04, 0xFA, 0x6C, 0x28, 0xDC,
+ 0x34, 0x8D, 0xE1, 0xA8, 0x09, 0x8C, 0xA0, 0x0A, 0x06, 0x08, 0x2A,
+ 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0xA1, 0x44, 0x03, 0x42,
+ 0x00, 0x04, 0xBB, 0x33, 0xAC, 0x4C, 0x27, 0x50, 0x4A, 0xC6, 0x4A,
+ 0xA5, 0x04, 0xC3, 0x3C, 0xDE, 0x9F, 0x36, 0xDB, 0x72, 0x2D, 0xCE,
+ 0x94, 0xEA, 0x2B, 0xFA, 0xCB, 0x20, 0x09, 0x39, 0x2C, 0x16, 0xE8,
+ 0x61, 0x02, 0xE9, 0xAF, 0x4D, 0xD3, 0x02, 0x93, 0x9A, 0x31, 0x5B,
+ 0x97, 0x92, 0x21, 0x7F, 0xF0, 0xCF, 0x18, 0xDA, 0x91, 0x11, 0x02,
+ 0x34, 0x86, 0xE8, 0x20, 0x58, 0x33, 0x0B, 0x80, 0x34, 0x89, 0xD8};
+#endif /* HAVE_ECC */
+
+#ifdef WOLFSSL_CMAC
+/* Hardcoded AES128 key for testing */
+static const uint8_t testAes128Key[AES_128_KEY_SIZE] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+#endif /* WOLFSSL_CMAC */
+
+#ifndef NO_RSA
+/* Hardcoded RSA2048 private key for testing (DER format) */
+static const unsigned char testRsa2048PrivKey[] = {
+ 0x30, 0x82, 0x04, 0xA4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00,
+ 0xC3, 0x03, 0xD1, 0x2B, 0xFE, 0x39, 0xA4, 0x32, 0x45, 0x3B, 0x53, 0xC8,
+ 0x84, 0x2B, 0x2A, 0x7C, 0x74, 0x9A, 0xBD, 0xAA, 0x2A, 0x52, 0x07, 0x47,
+ 0xD6, 0xA6, 0x36, 0xB2, 0x07, 0x32, 0x8E, 0xD0, 0xBA, 0x69, 0x7B, 0xC6,
+ 0xC3, 0x44, 0x9E, 0xD4, 0x81, 0x48, 0xFD, 0x2D, 0x68, 0xA2, 0x8B, 0x67,
+ 0xBB, 0xA1, 0x75, 0xC8, 0x36, 0x2C, 0x4A, 0xD2, 0x1B, 0xF7, 0x8B, 0xBA,
+ 0xCF, 0x0D, 0xF9, 0xEF, 0xEC, 0xF1, 0x81, 0x1E, 0x7B, 0x9B, 0x03, 0x47,
+ 0x9A, 0xBF, 0x65, 0xCC, 0x7F, 0x65, 0x24, 0x69, 0xA6, 0xE8, 0x14, 0x89,
+ 0x5B, 0xE4, 0x34, 0xF7, 0xC5, 0xB0, 0x14, 0x93, 0xF5, 0x67, 0x7B, 0x3A,
+ 0x7A, 0x78, 0xE1, 0x01, 0x56, 0x56, 0x91, 0xA6, 0x13, 0x42, 0x8D, 0xD2,
+ 0x3C, 0x40, 0x9C, 0x4C, 0xEF, 0xD1, 0x86, 0xDF, 0x37, 0x51, 0x1B, 0x0C,
+ 0xA1, 0x3B, 0xF5, 0xF1, 0xA3, 0x4A, 0x35, 0xE4, 0xE1, 0xCE, 0x96, 0xDF,
+ 0x1B, 0x7E, 0xBF, 0x4E, 0x97, 0xD0, 0x10, 0xE8, 0xA8, 0x08, 0x30, 0x81,
+ 0xAF, 0x20, 0x0B, 0x43, 0x14, 0xC5, 0x74, 0x67, 0xB4, 0x32, 0x82, 0x6F,
+ 0x8D, 0x86, 0xC2, 0x88, 0x40, 0x99, 0x36, 0x83, 0xBA, 0x1E, 0x40, 0x72,
+ 0x22, 0x17, 0xD7, 0x52, 0x65, 0x24, 0x73, 0xB0, 0xCE, 0xEF, 0x19, 0xCD,
+ 0xAE, 0xFF, 0x78, 0x6C, 0x7B, 0xC0, 0x12, 0x03, 0xD4, 0x4E, 0x72, 0x0D,
+ 0x50, 0x6D, 0x3B, 0xA3, 0x3B, 0xA3, 0x99, 0x5E, 0x9D, 0xC8, 0xD9, 0x0C,
+ 0x85, 0xB3, 0xD9, 0x8A, 0xD9, 0x54, 0x26, 0xDB, 0x6D, 0xFA, 0xAC, 0xBB,
+ 0xFF, 0x25, 0x4C, 0xC4, 0xD1, 0x79, 0xF4, 0x71, 0xD3, 0x86, 0x40, 0x18,
+ 0x13, 0xB0, 0x63, 0xB5, 0x72, 0x4E, 0x30, 0xC4, 0x97, 0x84, 0x86, 0x2D,
+ 0x56, 0x2F, 0xD7, 0x15, 0xF7, 0x7F, 0xC0, 0xAE, 0xF5, 0xFC, 0x5B, 0xE5,
+ 0xFB, 0xA1, 0xBA, 0xD3, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x82, 0x01,
+ 0x01, 0x00, 0xA2, 0xE6, 0xD8, 0x5F, 0x10, 0x71, 0x64, 0x08, 0x9E, 0x2E,
+ 0x6D, 0xD1, 0x6D, 0x1E, 0x85, 0xD2, 0x0A, 0xB1, 0x8C, 0x47, 0xCE, 0x2C,
+ 0x51, 0x6A, 0xA0, 0x12, 0x9E, 0x53, 0xDE, 0x91, 0x4C, 0x1D, 0x6D, 0xEA,
+ 0x59, 0x7B, 0xF2, 0x77, 0xAA, 0xD9, 0xC6, 0xD9, 0x8A, 0xAB, 0xD8, 0xE1,
+ 0x16, 0xE4, 0x63, 0x26, 0xFF, 0xB5, 0x6C, 0x13, 0x59, 0xB8, 0xE3, 0xA5,
+ 0xC8, 0x72, 0x17, 0x2E, 0x0C, 0x9F, 0x6F, 0xE5, 0x59, 0x3F, 0x76, 0x6F,
+ 0x49, 0xB1, 0x11, 0xC2, 0x5A, 0x2E, 0x16, 0x29, 0x0D, 0xDE, 0xB7, 0x8E,
+ 0xDC, 0x40, 0xD5, 0xA2, 0xEE, 0xE0, 0x1E, 0xA1, 0xF4, 0xBE, 0x97, 0xDB,
+ 0x86, 0x63, 0x96, 0x14, 0xCD, 0x98, 0x09, 0x60, 0x2D, 0x30, 0x76, 0x9C,
+ 0x3C, 0xCD, 0xE6, 0x88, 0xEE, 0x47, 0x92, 0x79, 0x0B, 0x5A, 0x00, 0xE2,
+ 0x5E, 0x5F, 0x11, 0x7C, 0x7D, 0xF9, 0x08, 0xB7, 0x20, 0x06, 0x89, 0x2A,
+ 0x5D, 0xFD, 0x00, 0xAB, 0x22, 0xE1, 0xF0, 0xB3, 0xBC, 0x24, 0xA9, 0x5E,
+ 0x26, 0x0E, 0x1F, 0x00, 0x2D, 0xFE, 0x21, 0x9A, 0x53, 0x5B, 0x6D, 0xD3,
+ 0x2B, 0xAB, 0x94, 0x82, 0x68, 0x43, 0x36, 0xD8, 0xF6, 0x2F, 0xC6, 0x22,
+ 0xFC, 0xB5, 0x41, 0x5D, 0x0D, 0x33, 0x60, 0xEA, 0xA4, 0x7D, 0x7E, 0xE8,
+ 0x4B, 0x55, 0x91, 0x56, 0xD3, 0x5C, 0x57, 0x8F, 0x1F, 0x94, 0x17, 0x2F,
+ 0xAA, 0xDE, 0xE9, 0x9E, 0xA8, 0xF4, 0xCF, 0x8A, 0x4C, 0x8E, 0xA0, 0xE4,
+ 0x56, 0x73, 0xB2, 0xCF, 0x4F, 0x86, 0xC5, 0x69, 0x3C, 0xF3, 0x24, 0x20,
+ 0x8B, 0x5C, 0x96, 0x0C, 0xFA, 0x6B, 0x12, 0x3B, 0x9A, 0x67, 0xC1, 0xDF,
+ 0xC6, 0x96, 0xB2, 0xA5, 0xD5, 0x92, 0x0D, 0x9B, 0x09, 0x42, 0x68, 0x24,
+ 0x10, 0x45, 0xD4, 0x50, 0xE4, 0x17, 0x39, 0x48, 0xD0, 0x35, 0x8B, 0x94,
+ 0x6D, 0x11, 0xDE, 0x8F, 0xCA, 0x59, 0x02, 0x81, 0x81, 0x00, 0xEA, 0x24,
+ 0xA7, 0xF9, 0x69, 0x33, 0xE9, 0x71, 0xDC, 0x52, 0x7D, 0x88, 0x21, 0x28,
+ 0x2F, 0x49, 0xDE, 0xBA, 0x72, 0x16, 0xE9, 0xCC, 0x47, 0x7A, 0x88, 0x0D,
+ 0x94, 0x57, 0x84, 0x58, 0x16, 0x3A, 0x81, 0xB0, 0x3F, 0xA2, 0xCF, 0xA6,
+ 0x6C, 0x1E, 0xB0, 0x06, 0x29, 0x00, 0x8F, 0xE7, 0x77, 0x76, 0xAC, 0xDB,
+ 0xCA, 0xC7, 0xD9, 0x5E, 0x9B, 0x3F, 0x26, 0x90, 0x52, 0xAE, 0xFC, 0x38,
+ 0x90, 0x00, 0x14, 0xBB, 0xB4, 0x0F, 0x58, 0x94, 0xE7, 0x2F, 0x6A, 0x7E,
+ 0x1C, 0x4F, 0x41, 0x21, 0xD4, 0x31, 0x59, 0x1F, 0x4E, 0x8A, 0x1A, 0x8D,
+ 0xA7, 0x57, 0x6C, 0x22, 0xD8, 0xE5, 0xF4, 0x7E, 0x32, 0xA6, 0x10, 0xCB,
+ 0x64, 0xA5, 0x55, 0x03, 0x87, 0xA6, 0x27, 0x05, 0x8C, 0xC3, 0xD7, 0xB6,
+ 0x27, 0xB2, 0x4D, 0xBA, 0x30, 0xDA, 0x47, 0x8F, 0x54, 0xD3, 0x3D, 0x8B,
+ 0x84, 0x8D, 0x94, 0x98, 0x58, 0xA5, 0x02, 0x81, 0x81, 0x00, 0xD5, 0x38,
+ 0x1B, 0xC3, 0x8F, 0xC5, 0x93, 0x0C, 0x47, 0x0B, 0x6F, 0x35, 0x92, 0xC5,
+ 0xB0, 0x8D, 0x46, 0xC8, 0x92, 0x18, 0x8F, 0xF5, 0x80, 0x0A, 0xF7, 0xEF,
+ 0xA1, 0xFE, 0x80, 0xB9, 0xB5, 0x2A, 0xBA, 0xCA, 0x18, 0xB0, 0x5D, 0xA5,
+ 0x07, 0xD0, 0x93, 0x8D, 0xD8, 0x9C, 0x04, 0x1C, 0xD4, 0x62, 0x8E, 0xA6,
+ 0x26, 0x81, 0x01, 0xFF, 0xCE, 0x8A, 0x2A, 0x63, 0x34, 0x35, 0x40, 0xAA,
+ 0x6D, 0x80, 0xDE, 0x89, 0x23, 0x6A, 0x57, 0x4D, 0x9E, 0x6E, 0xAD, 0x93,
+ 0x4E, 0x56, 0x90, 0x0B, 0x6D, 0x9D, 0x73, 0x8B, 0x0C, 0xAE, 0x27, 0x3D,
+ 0xDE, 0x4E, 0xF0, 0xAA, 0xC5, 0x6C, 0x78, 0x67, 0x6C, 0x94, 0x52, 0x9C,
+ 0x37, 0x67, 0x6C, 0x2D, 0xEF, 0xBB, 0xAF, 0xDF, 0xA6, 0x90, 0x3C, 0xC4,
+ 0x47, 0xCF, 0x8D, 0x96, 0x9E, 0x98, 0xA9, 0xB4, 0x9F, 0xC5, 0xA6, 0x50,
+ 0xDC, 0xB3, 0xF0, 0xFB, 0x74, 0x17, 0x02, 0x81, 0x80, 0x5E, 0x83, 0x09,
+ 0x62, 0xBD, 0xBA, 0x7C, 0xA2, 0xBF, 0x42, 0x74, 0xF5, 0x7C, 0x1C, 0xD2,
+ 0x69, 0xC9, 0x04, 0x0D, 0x85, 0x7E, 0x3E, 0x3D, 0x24, 0x12, 0xC3, 0x18,
+ 0x7B, 0xF3, 0x29, 0xF3, 0x5F, 0x0E, 0x76, 0x6C, 0x59, 0x75, 0xE4, 0x41,
+ 0x84, 0x69, 0x9D, 0x32, 0xF3, 0xCD, 0x22, 0xAB, 0xB0, 0x35, 0xBA, 0x4A,
+ 0xB2, 0x3C, 0xE5, 0xD9, 0x58, 0xB6, 0x62, 0x4F, 0x5D, 0xDE, 0xE5, 0x9E,
+ 0x0A, 0xCA, 0x53, 0xB2, 0x2C, 0xF7, 0x9E, 0xB3, 0x6B, 0x0A, 0x5B, 0x79,
+ 0x65, 0xEC, 0x6E, 0x91, 0x4E, 0x92, 0x20, 0xF6, 0xFC, 0xFC, 0x16, 0xED,
+ 0xD3, 0x76, 0x0C, 0xE2, 0xEC, 0x7F, 0xB2, 0x69, 0x13, 0x6B, 0x78, 0x0E,
+ 0x5A, 0x46, 0x64, 0xB4, 0x5E, 0xB7, 0x25, 0xA0, 0x5A, 0x75, 0x3A, 0x4B,
+ 0xEF, 0xC7, 0x3C, 0x3E, 0xF7, 0xFD, 0x26, 0xB8, 0x20, 0xC4, 0x99, 0x0A,
+ 0x9A, 0x73, 0xBE, 0xC3, 0x19, 0x02, 0x81, 0x81, 0x00, 0xBA, 0x44, 0x93,
+ 0x14, 0xAC, 0x34, 0x19, 0x3B, 0x5F, 0x91, 0x60, 0xAC, 0xF7, 0xB4, 0xD6,
+ 0x81, 0x05, 0x36, 0x51, 0x53, 0x3D, 0xE8, 0x65, 0xDC, 0xAF, 0x2E, 0xDC,
+ 0x61, 0x3E, 0xC9, 0x7D, 0xB8, 0x7F, 0x87, 0xF0, 0x3B, 0x9B, 0x03, 0x82,
+ 0x29, 0x37, 0xCE, 0x72, 0x4E, 0x11, 0xD5, 0xB1, 0xC1, 0x0C, 0x07, 0xA0,
+ 0x99, 0x91, 0x4A, 0x8D, 0x7F, 0xEC, 0x79, 0xCF, 0xF1, 0x39, 0xB5, 0xE9,
+ 0x85, 0xEC, 0x62, 0xF7, 0xDA, 0x7D, 0xBC, 0x64, 0x4D, 0x22, 0x3C, 0x0E,
+ 0xF2, 0xD6, 0x51, 0xF5, 0x87, 0xD8, 0x99, 0xC0, 0x11, 0x20, 0x5D, 0x0F,
+ 0x29, 0xFD, 0x5B, 0xE2, 0xAE, 0xD9, 0x1C, 0xD9, 0x21, 0x56, 0x6D, 0xFC,
+ 0x84, 0xD0, 0x5F, 0xED, 0x10, 0x15, 0x1C, 0x18, 0x21, 0xE7, 0xC4, 0x3D,
+ 0x4B, 0xD7, 0xD0, 0x9E, 0x6A, 0x95, 0xCF, 0x22, 0xC9, 0x03, 0x7B, 0x9E,
+ 0xE3, 0x60, 0x01, 0xFC, 0x2F, 0x02, 0x81, 0x80, 0x11, 0xD0, 0x4B, 0xCF,
+ 0x1B, 0x67, 0xB9, 0x9F, 0x10, 0x75, 0x47, 0x86, 0x65, 0xAE, 0x31, 0xC2,
+ 0xC6, 0x30, 0xAC, 0x59, 0x06, 0x50, 0xD9, 0x0F, 0xB5, 0x70, 0x06, 0xF7,
+ 0xF0, 0xD3, 0xC8, 0x62, 0x7C, 0xA8, 0xDA, 0x6E, 0xF6, 0x21, 0x3F, 0xD3,
+ 0x7F, 0x5F, 0xEA, 0x8A, 0xAB, 0x3F, 0xD9, 0x2A, 0x5E, 0xF3, 0x51, 0xD2,
+ 0xC2, 0x30, 0x37, 0xE3, 0x2D, 0xA3, 0x75, 0x0D, 0x1E, 0x4D, 0x21, 0x34,
+ 0xD5, 0x57, 0x70, 0x5C, 0x89, 0xBF, 0x72, 0xEC, 0x4A, 0x6E, 0x68, 0xD5,
+ 0xCD, 0x18, 0x74, 0x33, 0x4E, 0x8C, 0x3A, 0x45, 0x8F, 0xE6, 0x96, 0x40,
+ 0xEB, 0x63, 0xF9, 0x19, 0x86, 0x3A, 0x51, 0xDD, 0x89, 0x4B, 0xB0, 0xF3,
+ 0xF9, 0x9F, 0x5D, 0x28, 0x95, 0x38, 0xBE, 0x35, 0xAB, 0xCA, 0x5C, 0xE7,
+ 0x93, 0x53, 0x34, 0xA1, 0x45, 0x5D, 0x13, 0x39, 0x65, 0x42, 0x46, 0xA1,
+ 0x9F, 0xCD, 0xF5, 0xBF};
+#endif /* !NO_RSA */
+
+/*
+ * Shared signature-based verify flow used by the ECC, AES-CMAC and
+ * RSA subtests. Stores the signature in NVM, caches+commits the
+ * verification key, then runs the positive checks (by image, by
+ * index, and verify-all) followed by a corrupted-signature negative
+ * check. Leaves NVM and the key cache clean on success.
+ */
+static int _imgMgrRunSigVerify(whServerContext* server,
+ whServerImgMgrImg* testImage, whNvmId keyId,
+ const uint8_t* keyDer, word32 keyDerLen,
+ const char* keyLabel, whNvmId sigId,
+ const uint8_t* sig, word32 sigLen,
+ const char* sigLabel)
+{
+ whServerImgMgrConfig imgMgrConfig = {0};
+ whServerImgMgrContext imgMgr = {0};
+ whServerImgMgrVerifyResult result;
+ whServerImgMgrVerifyResult results[1];
+ whNvmMetadata sigMeta = {0};
+ whNvmMetadata keyMeta = {0};
+ uint8_t corrupt[256];
+
+ WH_TEST_ASSERT_RETURN(sigLen <= sizeof(corrupt));
+
+ /* Store signature in NVM */
+ sigMeta.id = sigId;
+ sigMeta.access = WH_NVM_ACCESS_ANY;
+ sigMeta.flags = WH_NVM_FLAGS_NONE;
+ sigMeta.len = sigLen;
+ snprintf((char*)sigMeta.label, WH_NVM_LABEL_LEN, "%s", sigLabel);
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Nvm_AddObject(server->nvm, &sigMeta, sigLen, sig));
+
+ /* Wire the image manager to the shared server */
+ imgMgrConfig.images = testImage;
+ imgMgrConfig.imageCount = 1;
+ imgMgrConfig.server = server;
+ WH_TEST_RETURN_ON_FAIL(wh_Server_ImgMgrInit(&imgMgr, &imgMgrConfig));
+
+ /* Cache and commit the verification key */
+ keyMeta.id = keyId;
+ keyMeta.access = WH_NVM_ACCESS_ANY;
+ keyMeta.flags = WH_NVM_FLAGS_NONE;
+ keyMeta.len = keyDerLen;
+ snprintf((char*)keyMeta.label, WH_NVM_LABEL_LEN, "%s", keyLabel);
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_KeystoreCacheKey(server, &keyMeta, (uint8_t*)keyDer));
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreCommitKey(server, keyId));
+
+ /* Positive: verify by image */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, testImage, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult == WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(result.verifyActionResult == WH_ERROR_OK);
+
+ /* Positive: verify by index */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImgIdx(&imgMgr, 0, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult == WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(result.verifyActionResult == WH_ERROR_OK);
+
+ /* Positive: verify all */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyAll(&imgMgr, results, 1, NULL));
+ WH_TEST_ASSERT_RETURN(results[0].verifyMethodResult == WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(results[0].verifyActionResult == WH_ERROR_OK);
+
+ /* Negative: corrupt the stored signature and confirm failure */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Nvm_Read(server->nvm, sigId, 0, sigLen, corrupt));
+ corrupt[0] ^= 0x01;
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Nvm_AddObject(server->nvm, &sigMeta, sigLen, corrupt));
+
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, testImage, &result));
+ /* Method must reject; the default action just relays that result */
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult != WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(
+ result.verifyActionResult == result.verifyMethodResult);
+
+ /* Leave NVM and key cache clean for the next suite */
+ WH_TEST_RETURN_ON_FAIL(wh_Nvm_DestroyObjects(server->nvm, 1, &sigId));
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreEraseKey(server, keyId));
+
+ return WH_TEST_SUCCESS;
+}
+
+#ifdef HAVE_ECC
+/* Sign testData with the test ECC key and export its public DER. */
+static int _imgMgrEccSign(uint8_t* sig, word32* sigLen, uint8_t* pubDer,
+ word32* pubDerLen)
+{
+ int ret;
+ int verifyResult = 0;
+ ecc_key eccKey;
+ WC_RNG rng;
+ wc_Sha256 sha;
+ uint8_t hash[WC_SHA256_DIGEST_SIZE];
+ word32 inOutIdx = 0;
+
+ ret = wc_InitRng(&rng);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = wc_ecc_init(&eccKey);
+ if (ret != 0) {
+ wc_FreeRng(&rng);
+ return ret;
+ }
+
+ ret = wc_EccPrivateKeyDecode(testEccPrivKey, &inOutIdx, &eccKey,
+ sizeof(testEccPrivKey));
+ if (ret == 0) {
+ ret = wc_EccPublicKeyToDer(&eccKey, pubDer, *pubDerLen, 1);
+ if (ret > 0) {
+ *pubDerLen = (word32)ret;
+ ret = 0;
+ }
+ }
+ if (ret == 0) {
+ ret = wc_InitSha256(&sha);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&sha, testData, sizeof(testData));
+ if (ret == 0) {
+ ret = wc_Sha256Final(&sha, hash);
+ }
+ wc_Sha256Free(&sha);
+ }
+ }
+ if (ret == 0) {
+ ret = wc_ecc_sign_hash(hash, sizeof(hash), sig, sigLen, &rng, &eccKey);
+ }
+ if (ret == 0) {
+ /* Sanity check the signature directly before handing it off */
+ ret = wc_ecc_verify_hash(sig, *sigLen, hash, sizeof(hash),
+ &verifyResult, &eccKey);
+ if (ret == 0 && verifyResult != 1) {
+ ret = WH_ERROR_ABORTED;
+ }
+ }
+
+ wc_ecc_free(&eccKey);
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+static int _whTest_ServerImgMgrEcc256(whServerContext* server)
+{
+ whServerImgMgrImg testImage = {0};
+ const whNvmId keyId = 1;
+ const whNvmId sigId = 2;
+ uint8_t signature[ECC_MAX_SIG_SIZE];
+ word32 sigLen = sizeof(signature);
+ uint8_t pubKeyDer[ECC_BUFSIZE];
+ word32 pubKeyDerLen = sizeof(pubKeyDer);
+
+ WH_TEST_RETURN_ON_FAIL(
+ _imgMgrEccSign(signature, &sigLen, pubKeyDer, &pubKeyDerLen));
+
+ testImage.addr = (uintptr_t)testData;
+ testImage.size = sizeof(testData);
+ testImage.keyId = keyId;
+ testImage.sigNvmId = sigId;
+ testImage.verifyMethod = wh_Server_ImgMgrVerifyMethodEccWithSha256;
+ testImage.verifyAction = wh_Server_ImgMgrVerifyActionDefault;
+
+ WH_TEST_RETURN_ON_FAIL(_imgMgrRunSigVerify(
+ server, &testImage, keyId, pubKeyDer, pubKeyDerLen, "TestKey", sigId,
+ signature, sigLen, "TestSig"));
+
+ WH_TEST_PRINT("IMG_MGR ECC P256 Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+#endif /* HAVE_ECC */
+
+#ifdef WOLFSSL_CMAC
+static int _whTest_ServerImgMgrAes128Cmac(whServerContext* server)
+{
+ int rc;
+ whServerImgMgrImg testImage = {0};
+ const whNvmId keyId = 1;
+ const whNvmId sigId = 2;
+ Cmac cmac;
+ uint8_t computed_cmac[AES_BLOCK_SIZE];
+ word32 cmac_size = sizeof(computed_cmac);
+
+ /* Compute the expected CMAC over the test data */
+ rc = wc_InitCmac(&cmac, testAes128Key, sizeof(testAes128Key), WC_CMAC_AES,
+ NULL);
+ if (rc == 0) {
+ rc = wc_CmacUpdate(&cmac, testData, sizeof(testData));
+ }
+ if (rc == 0) {
+ rc = wc_CmacFinal(&cmac, computed_cmac, &cmac_size);
+ }
+ WH_TEST_RETURN_ON_FAIL(rc);
+
+ testImage.addr = (uintptr_t)testData;
+ testImage.size = sizeof(testData);
+ testImage.keyId = keyId;
+ testImage.sigNvmId = sigId;
+ testImage.verifyMethod = wh_Server_ImgMgrVerifyMethodAesCmac;
+ testImage.verifyAction = wh_Server_ImgMgrVerifyActionDefault;
+
+ WH_TEST_RETURN_ON_FAIL(_imgMgrRunSigVerify(
+ server, &testImage, keyId, testAes128Key, sizeof(testAes128Key),
+ "TestAes128Key", sigId, computed_cmac, cmac_size, "TestCmacSig"));
+
+ WH_TEST_PRINT("IMG_MGR AES128 CMAC Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+#endif /* WOLFSSL_CMAC */
+
+#ifndef NO_RSA
+/* Sign testData with the test RSA key and export its public DER. */
+static int _imgMgrRsaSign(uint8_t* sig, word32* sigLen, uint8_t* pubDer,
+ word32* pubDerLen)
+{
+ int ret;
+ RsaKey rsaKey;
+ WC_RNG rng;
+ wc_Sha256 sha;
+ uint8_t hash[WC_SHA256_DIGEST_SIZE];
+ uint8_t decrypted[256];
+ word32 decryptedLen = sizeof(decrypted);
+ word32 inOutIdx = 0;
+
+ ret = wc_InitRng(&rng);
+ if (ret != 0) {
+ return ret;
+ }
+ ret = wc_InitRsaKey(&rsaKey, NULL);
+ if (ret != 0) {
+ wc_FreeRng(&rng);
+ return ret;
+ }
+
+ ret = wc_RsaPrivateKeyDecode(testRsa2048PrivKey, &inOutIdx, &rsaKey,
+ sizeof(testRsa2048PrivKey));
+ if (ret == 0) {
+ ret = wc_RsaKeyToPublicDer(&rsaKey, pubDer, *pubDerLen);
+ if (ret > 0) {
+ *pubDerLen = (word32)ret;
+ ret = 0;
+ }
+ }
+ if (ret == 0) {
+ ret = wc_InitSha256(&sha);
+ if (ret == 0) {
+ ret = wc_Sha256Update(&sha, testData, sizeof(testData));
+ if (ret == 0) {
+ ret = wc_Sha256Final(&sha, hash);
+ }
+ wc_Sha256Free(&sha);
+ }
+ }
+ if (ret == 0) {
+ ret = wc_RsaSSL_Sign(hash, sizeof(hash), sig, *sigLen, &rsaKey, &rng);
+ if (ret > 0) {
+ *sigLen = (word32)ret;
+ ret = 0;
+ }
+ }
+ if (ret == 0) {
+ /* Sanity check the signature directly before handing it off */
+ ret = wc_RsaSSL_Verify(sig, *sigLen, decrypted, decryptedLen, &rsaKey);
+ if (ret > 0) {
+ decryptedLen = (word32)ret;
+ if (decryptedLen != sizeof(hash) ||
+ XMEMCMP(decrypted, hash, sizeof(hash)) != 0) {
+ ret = WH_ERROR_ABORTED;
+ }
+ else {
+ ret = 0;
+ }
+ }
+ }
+
+ wc_FreeRsaKey(&rsaKey);
+ wc_FreeRng(&rng);
+ return ret;
+}
+
+static int _whTest_ServerImgMgrRsa2048(whServerContext* server)
+{
+ whServerImgMgrImg testImage = {0};
+ const whNvmId keyId = 1;
+ const whNvmId sigId = 2;
+ uint8_t signature[256]; /* raw RSA signature is the key size */
+ word32 sigLen = sizeof(signature);
+ uint8_t pubKeyDer[512];
+ word32 pubKeyDerLen = sizeof(pubKeyDer);
+
+ WH_TEST_RETURN_ON_FAIL(
+ _imgMgrRsaSign(signature, &sigLen, pubKeyDer, &pubKeyDerLen));
+
+ testImage.addr = (uintptr_t)testData;
+ testImage.size = sizeof(testData);
+ testImage.keyId = keyId;
+ testImage.sigNvmId = sigId;
+ testImage.verifyMethod = wh_Server_ImgMgrVerifyMethodRsaSslWithSha256;
+ testImage.verifyAction = wh_Server_ImgMgrVerifyActionDefault;
+
+ WH_TEST_RETURN_ON_FAIL(_imgMgrRunSigVerify(
+ server, &testImage, keyId, pubKeyDer, pubKeyDerLen, "TestRsaKey", sigId,
+ signature, sigLen, "TestRsaSig"));
+
+ WH_TEST_PRINT("IMG_MGR RSA2048 Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+
+static int _whTest_ServerImgMgrWolfBootRsa4096(whServerContext* server)
+{
+ whServerImgMgrConfig imgMgrConfig = {0};
+ whServerImgMgrContext imgMgr = {0};
+ whServerImgMgrImg testImage = {0};
+ const whNvmId keyId = 1;
+ whServerImgMgrVerifyResult result;
+ whNvmMetadata keyMeta = {0};
+ uint8_t corrupt_fw[sizeof(wolfboot_test_firmware)];
+ whServerImgMgrImg corruptImage;
+
+ testImage.addr = (uintptr_t)wolfboot_test_firmware;
+ testImage.size = sizeof(wolfboot_test_firmware);
+ testImage.hdrAddr = (uintptr_t)wolfboot_test_header;
+ testImage.hdrSize = sizeof(wolfboot_test_header);
+ testImage.keyId = keyId;
+ testImage.imgType = WH_IMG_MGR_IMG_TYPE_WOLFBOOT;
+ testImage.verifyMethod =
+ wh_Server_ImgMgrVerifyMethodWolfBootRsa4096WithSha256;
+ testImage.verifyAction = wh_Server_ImgMgrVerifyActionDefault;
+
+ imgMgrConfig.images = &testImage;
+ imgMgrConfig.imageCount = 1;
+ imgMgrConfig.server = server;
+ WH_TEST_RETURN_ON_FAIL(wh_Server_ImgMgrInit(&imgMgr, &imgMgrConfig));
+
+ /* Cache and commit the wolfBoot public key */
+ keyMeta.id = keyId;
+ keyMeta.access = WH_NVM_ACCESS_ANY;
+ keyMeta.flags = WH_NVM_FLAGS_NONE;
+ keyMeta.len = sizeof(wolfboot_test_pubkey_der);
+ snprintf((char*)keyMeta.label, WH_NVM_LABEL_LEN, "WBPubKey");
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreCacheKey(
+ server, &keyMeta, (uint8_t*)wolfboot_test_pubkey_der));
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreCommitKey(server, keyId));
+
+ /* Positive: verify wolfBoot image with correct key */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &testImage, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult == WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(result.verifyActionResult == WH_ERROR_OK);
+
+ /* Negative: flip a bit in a firmware copy and confirm failure */
+ corruptImage = testImage;
+ memcpy(corrupt_fw, wolfboot_test_firmware, sizeof(corrupt_fw));
+ corrupt_fw[0] ^= 0x01;
+ corruptImage.addr = (uintptr_t)corrupt_fw;
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &corruptImage, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult != WH_ERROR_OK);
+
+ /* Leave the key cache clean for the next suite */
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreEraseKey(server, keyId));
+
+ WH_TEST_PRINT("IMG_MGR wolfBoot RSA4096 Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+
+#ifdef WOLFHSM_CFG_CERTIFICATE_MANAGER
+static int _whTest_ServerImgMgrWolfBootCertChainRsa4096(whServerContext* server)
+{
+ whServerImgMgrConfig imgMgrConfig = {0};
+ whServerImgMgrContext imgMgr = {0};
+ whServerImgMgrImg testImage = {0};
+ const whNvmId rootCaNvmId = 10;
+ whServerImgMgrVerifyResult result;
+ whNvmMetadata rootCaMeta = {0};
+ uint8_t corrupt_fw[sizeof(wolfboot_test_firmware)];
+ whServerImgMgrImg corruptImage;
+
+ /* Store the root CA cert in NVM */
+ rootCaMeta.id = rootCaNvmId;
+ rootCaMeta.access = WH_NVM_ACCESS_ANY;
+ rootCaMeta.flags = WH_NVM_FLAGS_NONE;
+ rootCaMeta.len = sizeof(wolfboot_test_root_ca_cert_der);
+ snprintf((char*)rootCaMeta.label, WH_NVM_LABEL_LEN, "RootCA");
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Nvm_AddObject(server->nvm, &rootCaMeta,
+ sizeof(wolfboot_test_root_ca_cert_der),
+ wolfboot_test_root_ca_cert_der));
+
+ testImage.addr = (uintptr_t)wolfboot_test_firmware;
+ testImage.size = sizeof(wolfboot_test_firmware);
+ testImage.hdrAddr = (uintptr_t)wolfboot_test_cert_chain_header;
+ testImage.hdrSize = sizeof(wolfboot_test_cert_chain_header);
+ testImage.sigNvmId = rootCaNvmId;
+ testImage.imgType = WH_IMG_MGR_IMG_TYPE_WOLFBOOT_CERT;
+ testImage.verifyMethod =
+ wh_Server_ImgMgrVerifyMethodWolfBootCertChainRsa4096WithSha256;
+ testImage.verifyAction = wh_Server_ImgMgrVerifyActionDefault;
+
+ imgMgrConfig.images = &testImage;
+ imgMgrConfig.imageCount = 1;
+ imgMgrConfig.server = server;
+ WH_TEST_RETURN_ON_FAIL(wh_Server_ImgMgrInit(&imgMgr, &imgMgrConfig));
+
+ /* Positive: verify wolfBoot image against the cert chain */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &testImage, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult == WH_ERROR_OK);
+ WH_TEST_ASSERT_RETURN(result.verifyActionResult == WH_ERROR_OK);
+
+ /* Negative: flip a bit in a firmware copy and confirm failure */
+ corruptImage = testImage;
+ memcpy(corrupt_fw, wolfboot_test_firmware, sizeof(corrupt_fw));
+ corrupt_fw[0] ^= 0x01;
+ corruptImage.addr = (uintptr_t)corrupt_fw;
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &corruptImage, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult != WH_ERROR_OK);
+
+ /* Leave NVM clean for the next suite */
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Nvm_DestroyObjects(server->nvm, 1, &rootCaNvmId));
+
+ WH_TEST_PRINT(
+ "IMG_MGR wolfBoot Cert Chain RSA4096 Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+#endif /* WOLFHSM_CFG_CERTIFICATE_MANAGER */
+#endif /* !NO_RSA */
+
+/*
+ * Argument-validation and dispatch guards. No signing needed, so this is
+ * cheap coverage of the error/reject paths the positive subtests never
+ * reach (bad args, unknown image type, missing key/signature, and the
+ * per-method NULL/size guards).
+ */
+static int _whTest_ServerImgMgrBadArgs(whServerContext* server)
+{
+ whServerImgMgrConfig cfg = {0};
+ whServerImgMgrContext imgMgr = {0};
+ whServerImgMgrContext nullCtx = {0}; /* context with no server */
+ whServerImgMgrImg img = {0};
+ whServerImgMgrImg images[1];
+ whServerImgMgrVerifyResult result;
+ whServerImgMgrVerifyResult results[1];
+ size_t errIdx = 0;
+ const whNvmId dummyKeyId = 5;
+ uint8_t dummyKey[AES_128_KEY_SIZE] = {0};
+ uint8_t dummySig[WC_AES_BLOCK_SIZE] = {0};
+ whNvmMetadata keyMeta = {0};
+
+ (void)dummySig;
+
+ /* Init: NULL args, NULL server, and over-count */
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrInit(NULL, &cfg));
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrInit(&imgMgr, NULL));
+ cfg.server = NULL;
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrInit(&imgMgr, &cfg));
+ cfg.server = server;
+ cfg.imageCount = WOLFHSM_CFG_SERVER_IMG_MGR_MAX_IMG_COUNT + 1;
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrInit(&imgMgr, &cfg));
+
+ /* A valid single-image context to drive the Verify* guards */
+ memset(images, 0, sizeof(images));
+ cfg.images = images;
+ cfg.imageCount = 1;
+ WH_TEST_RETURN_ON_FAIL(wh_Server_ImgMgrInit(&imgMgr, &cfg));
+
+ /* VerifyImg: NULL args */
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImg(NULL, &img, &result));
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImg(&imgMgr, NULL, &result));
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &img, NULL));
+
+ /* VerifyImg: context with no server */
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImg(&nullCtx, &img, &result));
+
+ /* VerifyImg: unknown image type -> default reject */
+ img.imgType = (whServerImgMgrImgType)0x7F;
+ WH_TEST_ASSERT_RETURN(WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &img, &result));
+
+ /* VerifyImg: cert-chain type skips key/sig loads, so NULL method and
+ * action surface as NOHANDLER without any NVM setup */
+ memset(&img, 0, sizeof(img));
+ img.imgType = WH_IMG_MGR_IMG_TYPE_WOLFBOOT_CERT;
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &img, &result));
+ WH_TEST_ASSERT_RETURN(result.verifyMethodResult == WH_ERROR_NOHANDLER);
+ WH_TEST_ASSERT_RETURN(result.verifyActionResult == WH_ERROR_NOHANDLER);
+
+ /* VerifyImgIdx: index past the end */
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyImgIdx(&imgMgr, 99, &result));
+
+ /* VerifyAll: NULL results and undersized count */
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyAll(&imgMgr, NULL, 1, NULL));
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyAll(&imgMgr, results, 0, NULL));
+
+ /* VerifyAll: an image whose key is missing makes the sub-verify return
+ * non-OK, exercising the error-index reporting path */
+ memset(images, 0, sizeof(images));
+ images[0].imgType = WH_IMG_MGR_IMG_TYPE_RAW;
+ images[0].keyId = 0xBEEF; /* not in keystore */
+ cfg.images = images;
+ cfg.imageCount = 1;
+ WH_TEST_RETURN_ON_FAIL(wh_Server_ImgMgrInit(&imgMgr, &cfg));
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_OK !=
+ wh_Server_ImgMgrVerifyAll(&imgMgr, results, 1, &errIdx));
+ WH_TEST_ASSERT_RETURN(errIdx == 0);
+
+ /* RAW path: key present but signature object missing. Cache a dummy
+ * key (no crypto -- just bytes) and point at a non-existent sig id. */
+ keyMeta.id = dummyKeyId;
+ keyMeta.access = WH_NVM_ACCESS_ANY;
+ keyMeta.flags = WH_NVM_FLAGS_NONE;
+ keyMeta.len = sizeof(dummyKey);
+ snprintf((char*)keyMeta.label, WH_NVM_LABEL_LEN, "BadArgsKey");
+ WH_TEST_RETURN_ON_FAIL(
+ wh_Server_KeystoreCacheKey(server, &keyMeta, dummyKey));
+ memset(&img, 0, sizeof(img));
+ img.imgType = WH_IMG_MGR_IMG_TYPE_RAW;
+ img.keyId = dummyKeyId;
+ img.sigNvmId = 0xBEEF; /* not in NVM */
+ WH_TEST_ASSERT_RETURN(WH_ERROR_OK !=
+ wh_Server_ImgMgrVerifyImg(&imgMgr, &img, &result));
+ WH_TEST_RETURN_ON_FAIL(wh_Server_KeystoreEvictKey(server, dummyKeyId));
+
+ /* Per-method NULL/size guards, called directly */
+#ifdef HAVE_ECC
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS == wh_Server_ImgMgrVerifyMethodEccWithSha256(
+ &imgMgr, &img, NULL, 0, NULL, 0));
+#endif
+#ifdef WOLFSSL_CMAC
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS == wh_Server_ImgMgrVerifyMethodAesCmac(
+ &imgMgr, &img, NULL, 0, NULL, 0));
+ /* wrong key size, then wrong signature size */
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS == wh_Server_ImgMgrVerifyMethodAesCmac(
+ &imgMgr, &img, dummyKey, 1, dummySig,
+ sizeof(dummySig)));
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS == wh_Server_ImgMgrVerifyMethodAesCmac(
+ &imgMgr, &img, dummyKey, sizeof(dummyKey),
+ dummySig, 1));
+#endif
+#ifndef NO_RSA
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS == wh_Server_ImgMgrVerifyMethodRsaSslWithSha256(
+ &imgMgr, &img, NULL, 0, NULL, 0));
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyMethodWolfBootRsa4096WithSha256(
+ &imgMgr, &img, NULL, 0, NULL, 0));
+#ifdef WOLFHSM_CFG_CERTIFICATE_MANAGER
+ /* NULL image, then a context with no server */
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyMethodWolfBootCertChainRsa4096WithSha256(
+ &imgMgr, NULL, NULL, 0, NULL, 0));
+ WH_TEST_ASSERT_RETURN(
+ WH_ERROR_BADARGS ==
+ wh_Server_ImgMgrVerifyMethodWolfBootCertChainRsa4096WithSha256(
+ &nullCtx, &img, NULL, 0, NULL, 0));
+#endif
+#endif
+
+ WH_TEST_PRINT("IMG_MGR BadArgs Test completed successfully!\n");
+ return WH_TEST_SUCCESS;
+}
+
+int whTest_ServerImgMgr(whServerContext* server)
+{
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrBadArgs(server));
+#ifdef HAVE_ECC
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrEcc256(server));
+#endif
+#ifdef WOLFSSL_CMAC
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrAes128Cmac(server));
+#endif
+#ifndef NO_RSA
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrRsa2048(server));
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrWolfBootRsa4096(server));
+#ifdef WOLFHSM_CFG_CERTIFICATE_MANAGER
+ WH_TEST_RETURN_ON_FAIL(_whTest_ServerImgMgrWolfBootCertChainRsa4096(server));
+#endif
+#endif
+ return WH_TEST_SUCCESS;
+}
+
+#endif /* WOLFHSM_CFG_SERVER_IMG_MGR && WOLFHSM_CFG_ENABLE_SERVER &&
+ !WOLFHSM_CFG_NO_CRYPTO */
diff --git a/test-refactor/wh_test_list.c b/test-refactor/wh_test_list.c
index 109536f2b..eb794ff6d 100644
--- a/test-refactor/wh_test_list.c
+++ b/test-refactor/wh_test_list.c
@@ -45,6 +45,7 @@ WH_TEST_DECL(whTest_Comm);
WH_TEST_DECL(whTest_Dma);
WH_TEST_DECL(whTest_KeystoreReqSize);
WH_TEST_DECL(whTest_CertVerify);
+WH_TEST_DECL(whTest_ServerImgMgr);
WH_TEST_DECL(whTest_NvmOptional);
WH_TEST_DECL(whTest_ClientCerts);
WH_TEST_DECL(whTest_Crypto_Aes);
@@ -89,6 +90,7 @@ const size_t whTestsMiscCount = ARRAY_SIZE(whTestsMisc);
const whTestCase whTestsServer[] = {
{"whTest_CertVerify", whTest_CertVerify},
+ {"whTest_ServerImgMgr", whTest_ServerImgMgr},
{"whTest_NvmOptional", whTest_NvmOptional},
{ "whTest_CertVerify", whTest_CertVerify },
{ "whTest_SheMasterEcuKeyFallback", whTest_SheMasterEcuKeyFallback },