From 095c213a12af500f82d7bf31845a27a84a5721e3 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Tue, 23 Jun 2026 12:09:48 -0700 Subject: [PATCH 1/2] Add refactored crypto affinity tests, coverage roughly same --- test-refactor/README.md | 2 +- test-refactor/misc/wh_test_crypto_affinity.c | 534 +++++++++++++++++++ test-refactor/wh_test_list.c | 2 + 3 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 test-refactor/misc/wh_test_crypto_affinity.c diff --git a/test-refactor/README.md b/test-refactor/README.md index 6de6046f9..370d96438 100644 --- a/test-refactor/README.md +++ b/test-refactor/README.md @@ -90,6 +90,7 @@ Translated tests: | `wh_test_flash_fault_inject.c` | `posix/wh_test_flash_fault_inject.c` | helper (no test) | fault-injection flash wrapper used by the recovery test | | `wh_test_posix_threadsafe_stress.c::whTest_ThreadSafeStress` | called directly from `posix/wh_test_posix_main.c` | POSIX port-specific (direct call) | | | `wh_test_check_struct_padding.c` | `misc/wh_test_check_struct_padding.c` | Build-time (compile-only) | Wire-format `-Wpadded` audit; the POSIX Makefile compiles it with `-Wpadded -DWH_PADDING_CHECK`. Not a runtime test, so not registered in `wh_test_list.c` | +| `wh_test_crypto_affinity.c::whTest_CryptoAffinity` | `misc/wh_test_crypto_affinity.c::whTest_CryptoAffinity` | Misc | Self-contained sequential client+server pair so the subtests can set the server devId. The WithCb subtest configures a HW devId plus a registered cryptoCb to cover the server's HW affinity-to-devId routing; the NoCb subtest uses INVALID_DEVID for the SW fallback. Kept out of the client group because the shared port server is fixed at INVALID_DEVID and cannot exercise the HW routing branch | | `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 | Not yet migrated (still live in `wolfHSM/test/`): @@ -100,7 +101,6 @@ Not yet migrated (still live in `wolfHSM/test/`): | `wh_test_clientserver.c::whTest_ClientServer` | Pthread variant: remaining client-side coverage (NVM ops, etc.) still needs to be split out as new tests. The sequential test is dropped | | `wh_test_crypto.c::whTest_Crypto` | Remaining crypto coverage not yet split out: the AES async family (comm-buffer `whTest_CryptoAesAsync`/`AesAsyncKat` + DMA `whTest_CryptoAesDmaAsync`/`AesDmaAsyncKat`, round-trip & KAT). ECC DMA export-public and the ML-DSA wolfCrypt-API path are now migrated. | | `wh_test_crypto.c::whTest_KeyCache`, `whTest_NonExportableKeystore` | Keystore tests (key-cache lifecycle and non-exportable-flag enforcement) dispatched from the legacy `whTest_Crypto`. The per-algorithm suites use `wh_Client_KeyCache`, but these dedicated keystore tests are not yet split out. | -| `wh_test_crypto_affinity.c::whTest_CryptoAffinity` | | | `wh_test_keywrap.c::whTest_KeyWrapClientConfig` | | | `wh_test_multiclient.c::whTest_MultiClient` | | | `wh_test_lock.c::whTest_LockConfig`, `whTest_LockPosix` | `whTest_LockConfig` to be reworked to fit the Misc group, likely with a context param. | diff --git a/test-refactor/misc/wh_test_crypto_affinity.c b/test-refactor/misc/wh_test_crypto_affinity.c new file mode 100644 index 000000000..0d5f2ad86 --- /dev/null +++ b/test-refactor/misc/wh_test_crypto_affinity.c @@ -0,0 +1,534 @@ +/* + * 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/misc/wh_test_crypto_affinity.c + * + * Tests for the crypto affinity API. Affinity is client-local state + * transmitted per-message in the generic crypto header; no round-trip + * to the server is required to set or get it. The server uses the + * per-message affinity to pick its devId: HW affinity routes to the + * configured HW devId, anything else falls back to INVALID_DEVID (SW). + * + * Self-contained in the Misc group: each subtest stands up its own + * client/server pair and pumps requests sequentially so it can control + * the server's devId, which the shared port server (fixed at + * INVALID_DEVID) cannot provide. The WithCb subtest exercises the HW + * routing branch; the NoCb subtest exercises the SW fallback branch. + */ + +#include "wolfhsm/wh_settings.h" + +/* Only compile if we have crypto, client, server, and crypto callbacks */ +#if defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ + defined(WOLFHSM_CFG_ENABLE_SERVER) && \ + !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLF_CRYPTO_CB) + +#include +#include +#include + +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/types.h" +#include "wolfssl/wolfcrypt/cryptocb.h" +#include "wolfssl/wolfcrypt/random.h" + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_common.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_transport_mem.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_crypto.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_nvm.h" +#include "wolfhsm/wh_nvm_flash.h" +#include "wolfhsm/wh_flash_ramsim.h" + +#include "wh_test_common.h" +#include "wh_test_list.h" + +#define BUFFER_SIZE 4096 +#define FLASH_RAM_SIZE (1024 * 1024) +#define FLASH_SECTOR_SIZE (128 * 1024) +#define FLASH_PAGE_SIZE (8) +#define TEST_DEV_ID 0xCA + +/* Counter to track how many times the crypto callback is invoked */ +static int cryptoCbInvokeCount = 0; + +static whServerContext* cryptoAffinityTestServerCtx = NULL; + +/* Test crypto callback that just increments a counter and returns + * CRYPTOCB_UNAVAILABLE to fall back to software */ +static int _testCryptoCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + (void)devId; + (void)info; + (void)ctx; + + cryptoCbInvokeCount++; + + /* Return CRYPTOCB_UNAVAILABLE to indicate we don't handle this operation + * and wolfCrypt should fall back to software implementation */ + return CRYPTOCB_UNAVAILABLE; +} + +static int _cryptoAffinityTestConnectCb(void* context, + whCommConnected connected) +{ + (void)context; + + if (cryptoAffinityTestServerCtx == NULL) { + WH_ERROR_PRINT("Client connect callback server context is NULL\n"); + WH_TEST_ASSERT_RETURN(0); + } + + /* Set server connect flag. In a "real" system, this should signal the + * server via out-of-band mechanism. The server app is responsible for + * receiving this signal and calling wh_Server_SetConnected() */ + return wh_Server_SetConnected(cryptoAffinityTestServerCtx, connected); +} + + +static int _whTest_CryptoAffinityWithCb(void) +{ + int rc = 0; + uint32_t affinity = 0; + + /* Transport memory configuration */ + uint8_t req[BUFFER_SIZE] = {0}; + uint8_t resp[BUFFER_SIZE] = {0}; + whTransportMemConfig tmcf[1] = {{ + .req = (whTransportMemCsr*)req, + .req_size = sizeof(req), + .resp = (whTransportMemCsr*)resp, + .resp_size = sizeof(resp), + }}; + + /* Client configuration/contexts */ + whTransportClientCb tccb[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; + whTransportMemClientContext tmcc[1] = {0}; + whCommClientConfig cc_conf[1] = {{ + .transport_cb = tccb, + .transport_context = (void*)tmcc, + .transport_config = (void*)tmcf, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, + .connect_cb = _cryptoAffinityTestConnectCb, + }}; + whClientConfig c_conf[1] = {{ + .comm = cc_conf, + }}; + whClientContext client[1] = {0}; + + /* Server configuration/contexts */ + whTransportServerCb tscb[1] = {WH_TRANSPORT_MEM_SERVER_CB}; + whTransportMemServerContext tmsc[1] = {0}; + whCommServerConfig cs_conf[1] = {{ + .transport_cb = tscb, + .transport_context = (void*)tmsc, + .transport_config = (void*)tmcf, + .server_id = 123, + }}; + + /* Flash/NVM configuration */ + uint8_t flash_memory[FLASH_RAM_SIZE] = {0}; + whFlashRamsimCtx fc[1] = {0}; + whFlashRamsimCfg fc_conf[1] = {{ + .size = FLASH_RAM_SIZE, + .sectorSize = FLASH_SECTOR_SIZE, + .pageSize = FLASH_PAGE_SIZE, + .erasedByte = ~(uint8_t)0, + .memory = flash_memory, + }}; + const whFlashCb fcb[1] = {WH_FLASH_RAMSIM_CB}; + + whNvmFlashContext nfc[1] = {0}; + whNvmFlashConfig nf_conf[1] = {{ + .cb = fcb, + .context = fc, + .config = fc_conf, + }}; + + + whNvmCb nfcb[1] = {WH_NVM_FLASH_CB}; + whNvmConfig n_conf[1] = {{ + .cb = nfcb, + .context = nfc, + .config = nf_conf, + }}; + whNvmContext nvm[1] = {0}; + + /* Crypto context */ + whServerCryptoContext crypto[1] = {0}; + + whServerConfig s_conf[1] = {{ + .comm_config = cs_conf, + .nvm = nvm, + .crypto = crypto, + .devId = TEST_DEV_ID, + }}; + whServerContext server[1] = {0}; + + cryptoAffinityTestServerCtx = server; + + WH_TEST_PRINT(" whTest_CryptoAffinityWithCb..."); + + /* Initialize wolfCrypt and register our test crypto callback */ + WH_TEST_RETURN_ON_FAIL(wolfCrypt_Init()); + WH_TEST_RETURN_ON_FAIL( + wc_CryptoCb_RegisterDevice(TEST_DEV_ID, _testCryptoCb, NULL)); + + /* Initialize NVM */ + WH_TEST_RETURN_ON_FAIL(wh_Nvm_Init(nvm, n_conf)); + + /* Initialize RNG */ + WH_TEST_RETURN_ON_FAIL(wc_InitRng_ex(crypto->rng, NULL, INVALID_DEVID)); + + /* Initialize server and client */ + WH_TEST_RETURN_ON_FAIL(wh_Server_Init(server, s_conf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, c_conf)); + + /* Check that the server side is ready to recv */ + WH_TEST_ASSERT_RETURN(WH_ERROR_NOTREADY == + wh_Server_HandleRequestMessage(server)); + + /* Send comm init */ + WH_TEST_RETURN_ON_FAIL(wh_Client_CommInitRequest(client)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_CommInitResponse(client, NULL, NULL)); + + /* Verify server initial state - devId should be set */ + WH_TEST_ASSERT_RETURN(server->devId == TEST_DEV_ID); + + /* Test 1: Default affinity after init should be HW (0) */ + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_HW); + + /* Test 2: Set SW affinity - local only, no round-trip */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_SW); + + /* Test 3: Restore HW affinity */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_HW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_HW); + + /* Test 4: Invalid affinity returns WH_ERROR_BADARGS */ + rc = wh_Client_SetCryptoAffinity(client, 0xFF); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS); + /* Affinity should remain unchanged */ + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_HW); + + /* Test 5: With HW affinity, crypto op triggers HW callback. + * Set HW affinity, send an AES CBC request through the client-server path. + * The server should see affinity=HW in the message and use the HW devId, + * which triggers the registered crypto callback. */ + cryptoCbInvokeCount = 0; + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_HW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + uint32_t outSize = 0; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcRequest(client, aes, 1, plainIn, sizeof(plainIn))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcResponse(client, aes, cipherOut, &outSize)); + wc_AesFree(aes); + } + /* Crypto callback should have been invoked at least once */ + WH_TEST_ASSERT_RETURN(cryptoCbInvokeCount > 0); + + /* Test 6: With SW affinity, same request does NOT trigger HW callback */ + cryptoCbInvokeCount = 0; + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + uint32_t outSize = 0; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcRequest(client, aes, 1, plainIn, sizeof(plainIn))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcResponse(client, aes, cipherOut, &outSize)); + wc_AesFree(aes); + } + /* Crypto callback should NOT have been invoked */ + WH_TEST_ASSERT_RETURN(cryptoCbInvokeCount == 0); + + /* Test 7: NULL args validation */ + rc = wh_Client_SetCryptoAffinity(NULL, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS); + rc = wh_Client_GetCryptoAffinity(NULL, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS); + rc = wh_Client_GetCryptoAffinity(client, NULL); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS); + + /* Cleanup */ + WH_TEST_RETURN_ON_FAIL(wh_Client_CommCloseRequest(client)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_CommCloseResponse(client)); + + WH_TEST_RETURN_ON_FAIL(wh_Server_Cleanup(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_Cleanup(client)); + + wc_FreeRng(crypto->rng); + wh_Nvm_Cleanup(nvm); + wc_CryptoCb_UnRegisterDevice(TEST_DEV_ID); + wolfCrypt_Cleanup(); + + WH_TEST_PRINT("PASS\n"); + return WH_ERROR_OK; +} + + +static int _whTest_CryptoAffinityNoCb(void) +{ + int rc = 0; + uint32_t affinity = 0; + + /* Transport memory configuration */ + uint8_t req[BUFFER_SIZE] = {0}; + uint8_t resp[BUFFER_SIZE] = {0}; + whTransportMemConfig tmcf[1] = {{ + .req = (whTransportMemCsr*)req, + .req_size = sizeof(req), + .resp = (whTransportMemCsr*)resp, + .resp_size = sizeof(resp), + }}; + + /* Client configuration/contexts */ + whTransportClientCb tccb[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; + whTransportMemClientContext tmcc[1] = {0}; + whCommClientConfig cc_conf[1] = {{ + .transport_cb = tccb, + .transport_context = (void*)tmcc, + .transport_config = (void*)tmcf, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, + .connect_cb = _cryptoAffinityTestConnectCb, + }}; + whClientConfig c_conf[1] = {{ + .comm = cc_conf, + }}; + whClientContext client[1] = {0}; + + /* Server configuration/contexts */ + whTransportServerCb tscb[1] = {WH_TRANSPORT_MEM_SERVER_CB}; + whTransportMemServerContext tmsc[1] = {0}; + whCommServerConfig cs_conf[1] = {{ + .transport_cb = tscb, + .transport_context = (void*)tmsc, + .transport_config = (void*)tmcf, + .server_id = 123, + }}; + + /* Flash/NVM configuration */ + uint8_t flash_memory[FLASH_RAM_SIZE] = {0}; + whFlashRamsimCtx fc[1] = {0}; + whFlashRamsimCfg fc_conf[1] = {{ + .size = FLASH_RAM_SIZE, + .sectorSize = FLASH_SECTOR_SIZE, + .pageSize = FLASH_PAGE_SIZE, + .erasedByte = ~(uint8_t)0, + .memory = flash_memory, + }}; + const whFlashCb fcb[1] = {WH_FLASH_RAMSIM_CB}; + + whNvmFlashContext nfc[1] = {0}; + whNvmFlashConfig nf_conf[1] = {{ + .cb = fcb, + .context = fc, + .config = fc_conf, + }}; + + + whNvmCb nfcb[1] = {WH_NVM_FLASH_CB}; + whNvmConfig n_conf[1] = {{ + .cb = nfcb, + .context = nfc, + .config = nf_conf, + }}; + whNvmContext nvm[1] = {0}; + + /* Crypto context */ + whServerCryptoContext crypto[1] = {0}; + + whServerConfig s_conf[1] = {{ + .comm_config = cs_conf, + .nvm = nvm, + .crypto = crypto, + .devId = INVALID_DEVID, + }}; + whServerContext server[1] = {0}; + + cryptoAffinityTestServerCtx = server; + + WH_TEST_PRINT(" whTest_CryptoAffinityNoCb..."); + + /* Initialize wolfCrypt */ + WH_TEST_RETURN_ON_FAIL(wolfCrypt_Init()); + + /* Initialize NVM */ + WH_TEST_RETURN_ON_FAIL(wh_Nvm_Init(nvm, n_conf)); + + /* Initialize RNG */ + WH_TEST_RETURN_ON_FAIL(wc_InitRng_ex(crypto->rng, NULL, INVALID_DEVID)); + + /* Initialize server and client */ + WH_TEST_RETURN_ON_FAIL(wh_Server_Init(server, s_conf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, c_conf)); + + /* Check that the server side is ready to recv */ + WH_TEST_ASSERT_RETURN(WH_ERROR_NOTREADY == + wh_Server_HandleRequestMessage(server)); + + /* Send comm init */ + WH_TEST_RETURN_ON_FAIL(wh_Client_CommInitRequest(client)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_CommInitResponse(client, NULL, NULL)); + + /* Verify server configured with INVALID_DEVID */ + WH_TEST_ASSERT_RETURN(server->devId == INVALID_DEVID); + + /* Test 1: Default affinity should be HW */ + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_HW); + + /* Test 2: Set SW affinity - should succeed */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_SW); + + /* Test 3: Set HW affinity on client side succeeds (it's just local state). + * But when the server processes a request with HW affinity and no valid + * devId, it will use INVALID_DEVID (SW) anyway. */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_HW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + rc = wh_Client_GetCryptoAffinity(client, &affinity); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + WH_TEST_ASSERT_RETURN(affinity == WH_CRYPTO_AFFINITY_HW); + + /* Test 4: AES CBC request with HW affinity succeeds even without a HW + * crypto callback because the server falls back to INVALID_DEVID (SW). */ + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + uint32_t outSize = 0; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcRequest(client, aes, 1, plainIn, sizeof(plainIn))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcResponse(client, aes, cipherOut, &outSize)); + WH_TEST_ASSERT_RETURN(outSize == sizeof(plainIn)); + wc_AesFree(aes); + } + + /* Test 5: AES CBC request with SW affinity also succeeds */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + uint32_t outSize = 0; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcRequest(client, aes, 1, plainIn, sizeof(plainIn))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_AesCbcResponse(client, aes, cipherOut, &outSize)); + WH_TEST_ASSERT_RETURN(outSize == sizeof(plainIn)); + wc_AesFree(aes); + } + + /* Cleanup */ + WH_TEST_RETURN_ON_FAIL(wh_Client_CommCloseRequest(client)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_CommCloseResponse(client)); + + WH_TEST_RETURN_ON_FAIL(wh_Server_Cleanup(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_Cleanup(client)); + + wc_FreeRng(crypto->rng); + wh_Nvm_Cleanup(nvm); + wolfCrypt_Cleanup(); + + WH_TEST_PRINT("PASS\n"); + return WH_ERROR_OK; +} + + +int whTest_CryptoAffinity(void* ctx) +{ + (void)ctx; + + WH_TEST_PRINT("Testing Crypto Affinity...\n"); + WH_TEST_RETURN_ON_FAIL(_whTest_CryptoAffinityWithCb()); + WH_TEST_RETURN_ON_FAIL(_whTest_CryptoAffinityNoCb()); + + return WH_ERROR_OK; +} + +#endif /* WOLFHSM_CFG_ENABLE_CLIENT && WOLFHSM_CFG_ENABLE_SERVER && \ + * !WOLFHSM_CFG_NO_CRYPTO && WOLF_CRYPTO_CB */ diff --git a/test-refactor/wh_test_list.c b/test-refactor/wh_test_list.c index a7ff07128..d955c7eb0 100644 --- a/test-refactor/wh_test_list.c +++ b/test-refactor/wh_test_list.c @@ -38,6 +38,7 @@ /* Test declarations and weak skip implementations. */ WH_TEST_DECL(whTest_ClientDevId); WH_TEST_DECL(whTest_Comm); +WH_TEST_DECL(whTest_CryptoAffinity); WH_TEST_DECL(whTest_Dma); WH_TEST_DECL(whTest_KeystoreReqSize); WH_TEST_DECL(whTest_CertVerify); @@ -70,6 +71,7 @@ WH_TEST_DECL(whTest_AuthRequestAuthorization); const whTestCase whTestsMisc[] = { {"whTest_ClientDevId", whTest_ClientDevId}, {"whTest_Comm", whTest_Comm}, + {"whTest_CryptoAffinity", whTest_CryptoAffinity}, {"whTest_Dma", whTest_Dma}, {"whTest_KeystoreReqSize", whTest_KeystoreReqSize}, }; From 679a82d6047fa584ad9d83879110ec171cc7a2a7 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Tue, 23 Jun 2026 13:29:38 -0700 Subject: [PATCH 2/2] Add DMA tests, coverage roughly same --- test-refactor/README.md | 2 +- test-refactor/misc/wh_test_crypto_affinity.c | 80 +++++++++++++++++++- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/test-refactor/README.md b/test-refactor/README.md index 370d96438..e5adc4786 100644 --- a/test-refactor/README.md +++ b/test-refactor/README.md @@ -90,7 +90,7 @@ Translated tests: | `wh_test_flash_fault_inject.c` | `posix/wh_test_flash_fault_inject.c` | helper (no test) | fault-injection flash wrapper used by the recovery test | | `wh_test_posix_threadsafe_stress.c::whTest_ThreadSafeStress` | called directly from `posix/wh_test_posix_main.c` | POSIX port-specific (direct call) | | | `wh_test_check_struct_padding.c` | `misc/wh_test_check_struct_padding.c` | Build-time (compile-only) | Wire-format `-Wpadded` audit; the POSIX Makefile compiles it with `-Wpadded -DWH_PADDING_CHECK`. Not a runtime test, so not registered in `wh_test_list.c` | -| `wh_test_crypto_affinity.c::whTest_CryptoAffinity` | `misc/wh_test_crypto_affinity.c::whTest_CryptoAffinity` | Misc | Self-contained sequential client+server pair so the subtests can set the server devId. The WithCb subtest configures a HW devId plus a registered cryptoCb to cover the server's HW affinity-to-devId routing; the NoCb subtest uses INVALID_DEVID for the SW fallback. Kept out of the client group because the shared port server is fixed at INVALID_DEVID and cannot exercise the HW routing branch | +| `wh_test_crypto_affinity.c::whTest_CryptoAffinity` | `misc/wh_test_crypto_affinity.c::whTest_CryptoAffinity` | Misc | Self-contained sequential client+server pair so the subtests can set the server devId. The WithCb subtest configures a HW devId plus a registered cryptoCb to cover the server's HW affinity-to-devId routing; the NoCb subtest uses INVALID_DEVID for the SW fallback. Under WOLFHSM_CFG_DMA both subtests also issue an AES CBC DMA request so the DMA crypto dispatch's affinity routing is covered with the same HW/SW branch matrix as the non-DMA path. Kept out of the client group because the shared port server is fixed at INVALID_DEVID and cannot exercise the HW routing branch | | `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 | Not yet migrated (still live in `wolfHSM/test/`): diff --git a/test-refactor/misc/wh_test_crypto_affinity.c b/test-refactor/misc/wh_test_crypto_affinity.c index 0d5f2ad86..1a1a590f0 100644 --- a/test-refactor/misc/wh_test_crypto_affinity.c +++ b/test-refactor/misc/wh_test_crypto_affinity.c @@ -30,6 +30,8 @@ * the server's devId, which the shared port server (fixed at * INVALID_DEVID) cannot provide. The WithCb subtest exercises the HW * routing branch; the NoCb subtest exercises the SW fallback branch. + * Under WOLFHSM_CFG_DMA the WithCb subtest also drives an AES CBC DMA + * request so the DMA crypto dispatch's affinity routing is covered too. */ #include "wolfhsm/wh_settings.h" @@ -299,7 +301,58 @@ static int _whTest_CryptoAffinityWithCb(void) /* Crypto callback should NOT have been invoked */ WH_TEST_ASSERT_RETURN(cryptoCbInvokeCount == 0); - /* Test 7: NULL args validation */ +#ifdef WOLFHSM_CFG_DMA + /* Test 7: DMA path mirrors tests 5-6 but routes through the server's DMA + * crypto dispatch. HW affinity selects the HW devId (callback fires); SW + * affinity falls back to the SW devId (callback silent). */ + cryptoCbInvokeCount = 0; + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_HW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaRequest( + client, aes, 1, plainIn, sizeof(plainIn), cipherOut)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaResponse(client, aes)); + wc_AesFree(aes); + } + /* HW affinity DMA op triggers the HW callback */ + WH_TEST_ASSERT_RETURN(cryptoCbInvokeCount > 0); + + cryptoCbInvokeCount = 0; + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_SW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaRequest( + client, aes, 1, plainIn, sizeof(plainIn), cipherOut)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaResponse(client, aes)); + wc_AesFree(aes); + } + /* SW affinity DMA op does NOT trigger the HW callback */ + WH_TEST_ASSERT_RETURN(cryptoCbInvokeCount == 0); +#endif /* WOLFHSM_CFG_DMA */ + + /* Test 8: NULL args validation */ rc = wh_Client_SetCryptoAffinity(NULL, WH_CRYPTO_AFFINITY_SW); WH_TEST_ASSERT_RETURN(rc == WH_ERROR_BADARGS); rc = wh_Client_GetCryptoAffinity(NULL, &affinity); @@ -502,6 +555,31 @@ static int _whTest_CryptoAffinityNoCb(void) wc_AesFree(aes); } +#ifdef WOLFHSM_CFG_DMA + /* Test 6: AES CBC DMA request with HW affinity still succeeds without a HW + * crypto callback: with no valid server devId the DMA dispatch falls back + * to INVALID_DEVID (SW). Exercises the DMA routing's SW-fallback branch. */ + rc = wh_Client_SetCryptoAffinity(client, WH_CRYPTO_AFFINITY_HW); + WH_TEST_ASSERT_RETURN(rc == WH_ERROR_OK); + + { + Aes aes[1]; + uint8_t key[AES_BLOCK_SIZE] = {0x01}; + uint8_t iv[AES_BLOCK_SIZE] = {0x02}; + uint8_t plainIn[AES_BLOCK_SIZE] = {0x03}; + uint8_t cipherOut[AES_BLOCK_SIZE] = {0}; + + WH_TEST_RETURN_ON_FAIL(wc_AesInit(aes, NULL, INVALID_DEVID)); + WH_TEST_RETURN_ON_FAIL( + wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaRequest( + client, aes, 1, plainIn, sizeof(plainIn), cipherOut)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server)); + WH_TEST_RETURN_ON_FAIL(wh_Client_AesCbcDmaResponse(client, aes)); + wc_AesFree(aes); + } +#endif /* WOLFHSM_CFG_DMA */ + /* Cleanup */ WH_TEST_RETURN_ON_FAIL(wh_Client_CommCloseRequest(client)); WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server));