From 648d1f9c8b7b117ffb4d73ae53ce7be94d9340ff Mon Sep 17 00:00:00 2001 From: Yosuke Shimizu Date: Fri, 17 Jul 2026 11:14:51 +0900 Subject: [PATCH] Validate SHE client response payload size before use --- src/wh_client_she.c | 102 ++++++-- test-refactor/misc/wh_test_she_client.c | 313 ++++++++++++++++++++++++ test-refactor/wh_test_list.c | 2 + 3 files changed, 398 insertions(+), 19 deletions(-) create mode 100644 test-refactor/misc/wh_test_she_client.c diff --git a/src/wh_client_she.c b/src/wh_client_she.c index 716934f83..455fe0674 100644 --- a/src/wh_client_she.c +++ b/src/wh_client_she.c @@ -86,7 +86,7 @@ int wh_Client_SheSetUidResponse(whClientContext* c) { uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; int ret; whMessageShe_SetUidResponse *resp = NULL; @@ -96,6 +96,9 @@ int wh_Client_SheSetUidResponse(whClientContext* c) resp = (whMessageShe_SetUidResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == WH_ERROR_OK) { ret = resp->rc; } @@ -121,7 +124,7 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, uint32_t bootloaderSent = 0; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; uint8_t* respBuf; whMessageShe_SecureBootInitRequest* initReq = NULL; @@ -149,6 +152,9 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, respBuf); initResp = (whMessageShe_SecureBootInitResponse*)respBuf; } while (ret == WH_ERROR_NOTREADY); + if (ret == WH_ERROR_OK && dataSz < sizeof(*initResp)) { + ret = WH_ERROR_ABORTED; + } } /* send update sub command until we've sent the entire bootloader */ @@ -185,6 +191,10 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, respBuf); } while (ret == WH_ERROR_NOTREADY); + if (ret == WH_ERROR_OK && + dataSz < sizeof(whMessageShe_SecureBootUpdateResponse)) { + ret = WH_ERROR_ABORTED; + } } /* increment sent */ @@ -204,6 +214,9 @@ int wh_Client_SheSecureBoot(whClientContext* c, uint8_t* bootloader, ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, respBuf); finishResp = (whMessageShe_SecureBootFinishResponse*)respBuf; } while (ret == WH_ERROR_NOTREADY); + if (ret == WH_ERROR_OK && dataSz < sizeof(*finishResp)) { + ret = WH_ERROR_ABORTED; + } } if (ret == 0) { @@ -231,7 +244,7 @@ int wh_Client_SheGetStatusResponse(whClientContext* c, uint8_t* sreg) { uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; int ret; whMessageShe_GetStatusResponse *resp = NULL; @@ -242,6 +255,9 @@ int wh_Client_SheGetStatusResponse(whClientContext* c, uint8_t* sreg) resp = (whMessageShe_GetStatusResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } /* return error or set sreg */ if (ret == 0) { @@ -296,7 +312,7 @@ int wh_Client_SheLoadKeyResponse(whClientContext* c, uint8_t* messageFour, int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_LoadKeyResponse* resp = NULL; if (c == NULL || messageFour == NULL || messageFive == NULL) { @@ -306,6 +322,9 @@ int wh_Client_SheLoadKeyResponse(whClientContext* c, uint8_t* messageFour, resp = (whMessageShe_LoadKeyResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; @@ -355,7 +374,7 @@ int wh_Client_SheLoadPlainKeyResponse(whClientContext* c) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_LoadPlainKeyResponse* resp = NULL; if (c == NULL) { @@ -366,6 +385,9 @@ int wh_Client_SheLoadPlainKeyResponse(whClientContext* c) (whMessageShe_LoadPlainKeyResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { ret = resp->rc; } @@ -404,7 +426,7 @@ int wh_Client_SheExportRamKeyResponse(whClientContext* c, uint8_t* messageOne, int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_ExportRamKeyResponse* resp = NULL; if (c == NULL || messageOne == NULL || messageTwo == NULL || @@ -416,6 +438,9 @@ int wh_Client_SheExportRamKeyResponse(whClientContext* c, uint8_t* messageOne, (whMessageShe_ExportRamKeyResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; @@ -464,7 +489,7 @@ int wh_Client_SheInitRndResponse(whClientContext* c) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_InitRngResponse* resp = NULL; if (c == NULL) { @@ -473,6 +498,9 @@ int wh_Client_SheInitRndResponse(whClientContext* c) resp = (whMessageShe_InitRngResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { ret = resp->rc; } @@ -506,7 +534,7 @@ int wh_Client_SheRndResponse(whClientContext* c, uint8_t* out, uint32_t* outSz) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_RndResponse* resp = NULL; if (c == NULL || out == NULL || outSz == NULL || *outSz < WH_SHE_KEY_SZ) { @@ -516,6 +544,9 @@ int wh_Client_SheRndResponse(whClientContext* c, uint8_t* out, uint32_t* outSz) resp = (whMessageShe_RndResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { if (resp->rc != WH_SHE_ERC_NO_ERROR) @@ -567,7 +598,7 @@ int wh_Client_SheExtendSeedResponse(whClientContext* c) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_ExtendSeedResponse* resp = NULL; if (c == NULL) { @@ -576,6 +607,9 @@ int wh_Client_SheExtendSeedResponse(whClientContext* c) resp = (whMessageShe_ExtendSeedResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { ret = resp->rc; @@ -625,7 +659,7 @@ int wh_Client_SheEncEcbResponse(whClientContext* c, uint8_t* out, uint32_t sz) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; uint8_t* packOut; whMessageShe_EncEcbResponse* resp = NULL; @@ -640,9 +674,15 @@ int wh_Client_SheEncEcbResponse(whClientContext* c, uint8_t* out, uint32_t sz) ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); if (ret == 0) { - if (resp->rc != WH_SHE_ERC_NO_ERROR) { + if (dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } + else if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; } + else if (resp->sz > (dataSz - sizeof(*resp))) { + ret = WH_ERROR_ABORTED; + } else if (sz < resp->sz) { ret = WH_ERROR_BADARGS; } @@ -698,7 +738,7 @@ int wh_Client_SheEncCbcResponse(whClientContext* c, uint8_t* out, uint32_t sz) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; uint8_t* packOut; whMessageShe_EncCbcResponse* resp = NULL; @@ -712,9 +752,15 @@ int wh_Client_SheEncCbcResponse(whClientContext* c, uint8_t* out, uint32_t sz) ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); if (ret == 0) { - if (resp->rc != WH_SHE_ERC_NO_ERROR) { + if (dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } + else if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; } + else if (resp->sz > (dataSz - sizeof(*resp))) { + ret = WH_ERROR_ABORTED; + } else if (sz < resp->sz) { ret = WH_ERROR_BADARGS; } @@ -766,7 +812,7 @@ int wh_Client_SheDecEcbResponse(whClientContext* c, uint8_t* out, uint32_t sz) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; uint8_t* packOut; whMessageShe_DecEcbResponse* resp = NULL; @@ -780,9 +826,15 @@ int wh_Client_SheDecEcbResponse(whClientContext* c, uint8_t* out, uint32_t sz) ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); if (ret == 0) { - if (resp->rc != WH_SHE_ERC_NO_ERROR) { + if (dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } + else if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; } + else if (resp->sz > (dataSz - sizeof(*resp))) { + ret = WH_ERROR_ABORTED; + } else if (sz < resp->sz) { ret = WH_ERROR_BADARGS; } @@ -838,7 +890,7 @@ int wh_Client_SheDecCbcResponse(whClientContext* c, uint8_t* out, uint32_t sz) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; uint8_t* packOut; whMessageShe_DecCbcResponse* resp = NULL; @@ -852,9 +904,15 @@ int wh_Client_SheDecCbcResponse(whClientContext* c, uint8_t* out, uint32_t sz) ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); if (ret == 0) { - if (resp->rc != WH_SHE_ERC_NO_ERROR) { + if (dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } + else if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; } + else if (resp->sz > (dataSz - sizeof(*resp))) { + ret = WH_ERROR_ABORTED; + } else if (sz < resp->sz) { ret = WH_ERROR_BADARGS; } @@ -908,7 +966,7 @@ int wh_Client_SheGenerateMacResponse(whClientContext* c, uint8_t* out, int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_GenMacResponse* resp = NULL; if (c == NULL || out == NULL || sz < WH_SHE_KEY_SZ) { @@ -918,6 +976,9 @@ int wh_Client_SheGenerateMacResponse(whClientContext* c, uint8_t* out, resp = (whMessageShe_GenMacResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; @@ -981,7 +1042,7 @@ int wh_Client_SheVerifyMacResponse(whClientContext* c, uint8_t* outStatus) int ret; uint16_t group; uint16_t action; - uint16_t dataSz; + uint16_t dataSz = 0; whMessageShe_VerifyMacResponse* resp = NULL; if (c == NULL || outStatus == NULL) { @@ -990,6 +1051,9 @@ int wh_Client_SheVerifyMacResponse(whClientContext* c, uint8_t* outStatus) resp = (whMessageShe_VerifyMacResponse*)wh_CommClient_GetDataPtr(c->comm); ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, (uint8_t*)resp); + if (ret == WH_ERROR_OK && dataSz < sizeof(*resp)) { + ret = WH_ERROR_ABORTED; + } if (ret == 0) { if (resp->rc != WH_SHE_ERC_NO_ERROR) { ret = resp->rc; diff --git a/test-refactor/misc/wh_test_she_client.c b/test-refactor/misc/wh_test_she_client.c new file mode 100644 index 000000000..b80ad4965 --- /dev/null +++ b/test-refactor/misc/wh_test_she_client.c @@ -0,0 +1,313 @@ +/* + * 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_she_client.c + * + * SHE client tests needing raw control of both transport ends, so they cannot + * use the client-server group's live server: a raw comm server returns the + * expected kind and seq with a malformed payload size. Counterpart to + * server/wh_test_she_server.c. + */ + +#include "wolfhsm/wh_settings.h" + +#if defined(WOLFHSM_CFG_SHE_EXTENSION) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ + defined(WOLFHSM_CFG_ENABLE_SERVER) + +#include +#include + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_message.h" +#include "wolfhsm/wh_message_she.h" +#include "wolfhsm/wh_she_common.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_client_she.h" +#include "wolfhsm/wh_transport_mem.h" + +#include "wh_test_common.h" +#include "wh_test_list.h" + +#define BUFFER_SIZE 4096 + +/* The four variable-length SHE crypt helpers share a response signature */ +typedef int (*whSheCryptRespFn)(whClientContext* c, uint8_t* out, uint32_t sz); + +typedef struct { + uint16_t action; + whSheCryptRespFn respFn; +} whSheCryptCase; + +typedef struct { + whClientContext client[1]; + whCommServer server[1]; + /* Mem transport shared by the client and the raw comm server */ + uint8_t reqBuf[BUFFER_SIZE]; + uint8_t respBuf[BUFFER_SIZE]; + whTransportMemConfig tmcf[1]; + whTransportClientCb tccb[1]; + whTransportMemClientContext tmcc[1]; + whCommClientConfig cc_conf[1]; + whClientConfig c_conf[1]; + whTransportServerCb tscb[1]; + whTransportMemServerContext tmsc[1]; + whCommServerConfig cs_conf[1]; +} TestCtx; + +static const whSheCryptCase _cryptCase[] = { + {WH_SHE_ENC_ECB, wh_Client_SheEncEcbResponse}, + {WH_SHE_ENC_CBC, wh_Client_SheEncCbcResponse}, + {WH_SHE_DEC_ECB, wh_Client_SheDecEcbResponse}, + {WH_SHE_DEC_CBC, wh_Client_SheDecCbcResponse}, +}; + +static int _SetupClientServer(TestCtx* t) +{ + memset(t, 0, sizeof(*t)); + + t->tmcf[0] = (whTransportMemConfig){ + .req = (whTransportMemCsr*)t->reqBuf, + .req_size = sizeof(t->reqBuf), + .resp = (whTransportMemCsr*)t->respBuf, + .resp_size = sizeof(t->respBuf), + }; + + t->tccb[0] = (whTransportClientCb)WH_TRANSPORT_MEM_CLIENT_CB; + t->cc_conf[0] = (whCommClientConfig){ + .transport_cb = t->tccb, + .transport_context = (void*)t->tmcc, + .transport_config = (void*)t->tmcf, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, + }; + t->c_conf[0] = (whClientConfig){ + .comm = t->cc_conf, + }; + + t->tscb[0] = (whTransportServerCb)WH_TRANSPORT_MEM_SERVER_CB; + t->cs_conf[0] = (whCommServerConfig){ + .transport_cb = t->tscb, + .transport_context = (void*)t->tmsc, + .transport_config = (void*)t->tmcf, + .server_id = 124, + }; + + WH_TEST_RETURN_ON_FAIL(wh_Client_Init(t->client, t->c_conf)); + WH_TEST_RETURN_ON_FAIL( + wh_CommServer_Init(t->server, t->cs_conf, NULL, NULL)); + return WH_ERROR_OK; +} + +static void _CleanupClientServer(TestCtx* t) +{ + (void)wh_CommServer_Cleanup(t->server); + (void)wh_Client_Cleanup(t->client); +} + +/* Issue the request for action so the reply's kind and seq line up */ +static int _SheCryptRequest(whClientContext* c, uint16_t action, uint8_t* iv, + uint8_t* in, uint32_t sz) +{ + int ret; + + switch (action) { + case WH_SHE_ENC_ECB: + ret = wh_Client_SheEncEcbRequest(c, 0, in, sz); + break; + case WH_SHE_ENC_CBC: + ret = wh_Client_SheEncCbcRequest(c, 0, iv, WH_SHE_KEY_SZ, in, sz); + break; + case WH_SHE_DEC_ECB: + ret = wh_Client_SheDecEcbRequest(c, 0, in, sz); + break; + case WH_SHE_DEC_CBC: + ret = wh_Client_SheDecCbcRequest(c, 0, iv, WH_SHE_KEY_SZ, in, sz); + break; + default: + ret = WH_ERROR_BADARGS; + break; + } + return ret; +} + +/* A fixed-size response one byte short of its own struct must be rejected + * rather than read out of the stale tail of the shared comm buffer. */ +static int _whTest_SheRespSizeFixed(TestCtx* t) +{ + int ret = 0; + uint16_t magic = 0; + uint16_t kind = 0; + uint16_t seq = 0; + uint16_t len = 0; + + uint8_t in[WH_SHE_KEY_SZ * 2]; + uint8_t out[WH_SHE_KEY_SZ * 4]; + uint8_t rxReq[WOLFHSM_CFG_COMM_DATA_LEN]; + uint8_t txResp[WOLFHSM_CFG_COMM_DATA_LEN]; + + whMessageShe_GenMacResponse* macResp = NULL; + + memset(in, 0xA5, sizeof(in)); + memset(out, 0, sizeof(out)); + + WH_TEST_RETURN_ON_FAIL( + wh_Client_SheGenerateMacRequest(t->client, 0, in, sizeof(in))); + WH_TEST_RETURN_ON_FAIL(wh_CommServer_RecvRequest( + t->server, &magic, &kind, &seq, &len, sizeof(rxReq), rxReq)); + + memset(txResp, 0, sizeof(txResp)); + macResp = (whMessageShe_GenMacResponse*)txResp; + macResp->rc = WH_SHE_ERC_NO_ERROR; + WH_TEST_RETURN_ON_FAIL(wh_CommServer_SendResponse( + t->server, magic, kind, seq, (uint16_t)(sizeof(*macResp) - 1), txResp)); + + ret = wh_Client_SheGenerateMacResponse(t->client, out, sizeof(out)); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_ABORTED); + + return WH_ERROR_OK; +} + +/* Every variable-length helper, at the exact bound: reject a declared sz one + * past the payload received, accept one sitting exactly on it. */ +static int _whTest_SheRespSizeCryptBound(TestCtx* t) +{ + int ret = 0; + int i = 0; + int j = 0; + int caseCount = 0; + uint16_t magic = 0; + uint16_t kind = 0; + uint16_t seq = 0; + uint16_t len = 0; + uint32_t payloadSz = 0; + uint32_t claimSz = 0; + + uint8_t in[WH_SHE_KEY_SZ * 2]; + uint8_t iv[WH_SHE_KEY_SZ]; + uint8_t out[WH_SHE_KEY_SZ * 4]; + uint8_t rxReq[WOLFHSM_CFG_COMM_DATA_LEN]; + uint8_t txResp[WOLFHSM_CFG_COMM_DATA_LEN]; + + /* All four crypt responses share the rc/sz layout, so one type covers + * them. Asserted below. */ + whMessageShe_EncEcbResponse* cryptResp = NULL; + + memset(in, 0xA5, sizeof(in)); + memset(iv, 0x5A, sizeof(iv)); + memset(out, 0, sizeof(out)); + + WH_TEST_ASSERT_RETURN(sizeof(whMessageShe_EncEcbResponse) == + sizeof(whMessageShe_EncCbcResponse)); + WH_TEST_ASSERT_RETURN(sizeof(whMessageShe_EncEcbResponse) == + sizeof(whMessageShe_DecEcbResponse)); + WH_TEST_ASSERT_RETURN(sizeof(whMessageShe_EncEcbResponse) == + sizeof(whMessageShe_DecCbcResponse)); + + caseCount = (int)(sizeof(_cryptCase) / sizeof(_cryptCase[0])); + payloadSz = WH_SHE_KEY_SZ; + + for (i = 0; i < caseCount; i++) { + for (j = 0; j < 2; j++) { + claimSz = (j == 0) ? (payloadSz + 1) : payloadSz; + + WH_TEST_RETURN_ON_FAIL(_SheCryptRequest( + t->client, _cryptCase[i].action, iv, in, sizeof(in))); + WH_TEST_RETURN_ON_FAIL(wh_CommServer_RecvRequest( + t->server, &magic, &kind, &seq, &len, sizeof(rxReq), rxReq)); + + /* Row's request and response helper must be the same action */ + WH_TEST_ASSERT_RETURN(WH_MESSAGE_ACTION(kind) == + _cryptCase[i].action); + + memset(txResp, 0, sizeof(txResp)); + cryptResp = (whMessageShe_EncEcbResponse*)txResp; + cryptResp->rc = WH_SHE_ERC_NO_ERROR; + cryptResp->sz = claimSz; + WH_TEST_RETURN_ON_FAIL(wh_CommServer_SendResponse( + t->server, magic, kind, seq, + (uint16_t)(sizeof(*cryptResp) + payloadSz), txResp)); + + ret = _cryptCase[i].respFn(t->client, out, sizeof(out)); + if (j == 0) { + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_ABORTED); + } + else { + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + } + } + } + + return WH_ERROR_OK; +} + +/* A crypt reply too short for even its fixed fields. All-ones payload makes rc + * read nonzero, so a missing size gate surfaces as a stale rc. */ +static int _whTest_SheRespSizeCryptShort(TestCtx* t) +{ + int ret = 0; + uint16_t magic = 0; + uint16_t kind = 0; + uint16_t seq = 0; + uint16_t len = 0; + + uint8_t in[WH_SHE_KEY_SZ * 2]; + uint8_t iv[WH_SHE_KEY_SZ]; + uint8_t out[WH_SHE_KEY_SZ * 4]; + uint8_t rxReq[WOLFHSM_CFG_COMM_DATA_LEN]; + uint8_t txResp[WOLFHSM_CFG_COMM_DATA_LEN]; + + memset(in, 0xA5, sizeof(in)); + memset(iv, 0x5A, sizeof(iv)); + memset(out, 0, sizeof(out)); + + WH_TEST_RETURN_ON_FAIL( + _SheCryptRequest(t->client, WH_SHE_ENC_ECB, iv, in, sizeof(in))); + WH_TEST_RETURN_ON_FAIL(wh_CommServer_RecvRequest( + t->server, &magic, &kind, &seq, &len, sizeof(rxReq), rxReq)); + + memset(txResp, 0xFF, sizeof(txResp)); + WH_TEST_RETURN_ON_FAIL( + wh_CommServer_SendResponse(t->server, magic, kind, seq, 2, txResp)); + + ret = wh_Client_SheEncEcbResponse(t->client, out, sizeof(out)); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_ABORTED); + + return WH_ERROR_OK; +} + +int whTest_SheClient(void* ctx) +{ + TestCtx t[1]; + + (void)ctx; + + WH_TEST_RETURN_ON_FAIL(_SetupClientServer(t)); + + WH_TEST_PRINT("Testing SHE client response size validation...\n"); + WH_TEST_RETURN_ON_FAIL(_whTest_SheRespSizeFixed(t)); + WH_TEST_RETURN_ON_FAIL(_whTest_SheRespSizeCryptBound(t)); + WH_TEST_RETURN_ON_FAIL(_whTest_SheRespSizeCryptShort(t)); + + _CleanupClientServer(t); + + return WH_ERROR_OK; +} + +#endif /* WOLFHSM_CFG_SHE_EXTENSION && WOLFHSM_CFG_ENABLE_CLIENT && \ + WOLFHSM_CFG_ENABLE_SERVER */ diff --git a/test-refactor/wh_test_list.c b/test-refactor/wh_test_list.c index 70f7d0396..c34f995da 100644 --- a/test-refactor/wh_test_list.c +++ b/test-refactor/wh_test_list.c @@ -47,6 +47,7 @@ WH_TEST_DECL(whTest_HwKeystore); WH_TEST_DECL(whTest_KeystoreReqSize); WH_TEST_DECL(whTest_MultiClient); WH_TEST_DECL(whTest_Lock); +WH_TEST_DECL(whTest_SheClient); WH_TEST_DECL(whTest_CertVerify); WH_TEST_DECL(whTest_CertNvmPolicy); WH_TEST_DECL(whTest_CertReadRejectsServerOnly); @@ -107,6 +108,7 @@ const whTestCase whTestsMisc[] = { { "whTest_Lock", whTest_Lock }, { "whTest_SheKeywrapInterop", whTest_SheKeywrapInterop }, { "whTest_SheNoNvm", whTest_SheNoNvm }, + { "whTest_SheClient", whTest_SheClient }, }; const size_t whTestsMiscCount = ARRAY_SIZE(whTestsMisc);