From 26d6d084d3ab7ed8f862c79abb4cfe48d6248a92 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Wed, 28 Jan 2026 17:27:25 -0500 Subject: [PATCH 1/2] Implement timeout capability. Apply timeout to crypto response --- src/wh_client.c | 34 +++++ src/wh_client_crypto.c | 279 ++++++++++++++------------------------ src/wh_timeout.c | 96 +++++++++++++ test/config/wolfhsm_cfg.h | 2 + test/wh_test.c | 4 + test/wh_test_timeout.c | 74 ++++++++++ test/wh_test_timeout.h | 34 +++++ wolfhsm/wh_client.h | 24 ++++ wolfhsm/wh_error.h | 1 + wolfhsm/wh_settings.h | 3 + wolfhsm/wh_timeout.h | 94 +++++++++++++ 11 files changed, 466 insertions(+), 179 deletions(-) create mode 100644 src/wh_timeout.c create mode 100644 test/wh_test_timeout.c create mode 100644 test/wh_test_timeout.h create mode 100644 wolfhsm/wh_timeout.h diff --git a/src/wh_client.c b/src/wh_client.c index 927c4bf0..4117efa3 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -81,6 +81,15 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) c->cancelCb = config->cancelCb; #endif +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT + if (config->respTimeoutConfig != NULL) { + rc = wh_Timeout_Init(c->respTimeout, config->respTimeoutConfig); + if (rc != 0) { + return rc; + } + } +#endif + rc = wh_CommClient_Init(c->comm, config->comm); #ifndef WOLFHSM_CFG_NO_CRYPTO @@ -199,6 +208,31 @@ int wh_Client_RecvResponse(whClientContext *c, return rc; } +int wh_Client_RecvResponseTimeout(whClientContext *c, + uint16_t *out_group, uint16_t *out_action, + uint16_t *out_size, void* data, whTimeoutCtx *timeout) +{ + int ret; + + if ((c == NULL) || (timeout == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = wh_Timeout_Start(timeout); + if (ret != WH_ERROR_OK) { + return ret; + } + + do { + ret = wh_Client_RecvResponse(c, out_group, out_action, out_size, data); + if ((ret == WH_ERROR_NOTREADY) && wh_Timeout_Expired(timeout)) { + return WH_ERROR_TIMEOUT; + } + } while (ret == WH_ERROR_NOTREADY); + + return ret; +} + int wh_Client_CommInitRequest(whClientContext* c) { whMessageCommInitRequest msg = {0}; diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index c11b931a..51928883 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -163,6 +163,24 @@ static uint8_t* _createCryptoRequestWithSubtype(uint8_t* reqBuf, uint16_t type, return reqBuf + sizeof(whMessageCrypto_GenericRequestHeader); } +static int _recvCryptoResponse(whClientContext* ctx, + uint16_t* group, uint16_t* action, + uint16_t* size, void *data) +{ + int ret; + +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT + ret = wh_Client_RecvResponseTimeout(ctx, group, action, size, data, + ctx->respTimeout); +#else + do { + ret = wh_Client_RecvResponse(ctx, group, action, size, data); + } while (ret == WH_ERROR_NOTREADY); +#endif /* WOLFHSM_CFG_ENABLE_TIMEOUT */ + + return ret; +} + /* Helper function to validate and extract crypto response */ /* TODO: add algoSubType checking */ static int _getCryptoResponse(uint8_t* respBuf, uint16_t type, @@ -233,10 +251,8 @@ int wh_Client_RngGenerate(whClientContext* ctx, uint8_t* out, uint32_t size) /* Send request and get response */ ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + dataPtr); } if (ret == WH_ERROR_OK) { /* Get response */ @@ -311,10 +327,8 @@ int wh_Client_RngGenerateDma(whClientContext* ctx, uint8_t* out, uint32_t size) if (ret == WH_ERROR_OK) { /* Wait for and receive the response */ - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -414,10 +428,7 @@ int wh_Client_AesCtr(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); if (ret == WH_ERROR_OK) { ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res); if (ret == WH_ERROR_OK) { @@ -526,10 +537,7 @@ int wh_Client_AesEcb(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); if (ret == WH_ERROR_OK) { ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res); if (ret == WH_ERROR_OK) { @@ -635,10 +643,7 @@ int wh_Client_AesCbc(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); if (ret == WH_ERROR_OK) { ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res); if (ret == WH_ERROR_OK) { @@ -756,10 +761,7 @@ int wh_Client_AesGcm(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); if (ret == 0) { uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); if (ret == WH_ERROR_OK) { /* Get response */ @@ -956,10 +958,7 @@ int wh_Client_AesGcmDma(whClientContext* ctx, Aes* aes, int enc, } if (ret == 0) { uint16_t resLen = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &resLen, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &resLen, dataPtr); if (ret == WH_ERROR_OK) { /* Get response */ @@ -1158,10 +1157,8 @@ static int _EccMakeKey(whClientContext* ctx, int size, int curveId, if (ret == WH_ERROR_OK) { /* Response Message */ uint16_t res_len; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -1322,10 +1319,8 @@ int wh_Client_EccSharedSecret(whClientContext* ctx, ecc_key* priv_key, uint16_t res_len; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); WH_DEBUG_CLIENT_VERBOSE("resp packet recv. ret:%d\n", ret); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -1458,10 +1453,8 @@ int wh_Client_EccSign(whClientContext* ctx, ecc_key* key, const uint8_t* hash, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -1612,10 +1605,8 @@ int wh_Client_EccVerify(whClientContext* ctx, ecc_key* key, const uint8_t* sig, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header * rc */ @@ -1690,10 +1681,8 @@ int wh_Client_EccCheckPubKey(whClientContext* ctx, ecc_key* key, (uint8_t*)packet); /* read response */ if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &dataSz, - (uint8_t*)packet); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &dataSz, + (uint8_t*)packet); } if (ret == 0) { if (packet->rc != 0) @@ -1835,10 +1824,8 @@ static int _Curve25519MakeKey(whClientContext* ctx, uint16_t size, WH_DEBUG_CLIENT_VERBOSE("Curve25519 KeyGen Req sent:size:%u, ret:%d\n", (unsigned int)req->sz, ret); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &data_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &data_len, + (uint8_t*)dataPtr); } @@ -1994,10 +1981,8 @@ int wh_Client_Curve25519SharedSecret(whClientContext* ctx, pub_evict = prv_evict = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); WH_DEBUG_CLIENT_VERBOSE("resp packet recv. ret:%d\n", ret); if (ret == WH_ERROR_OK) { @@ -2163,10 +2148,8 @@ static int _Ed25519MakeKey(whClientContext* ctx, whKeyId* inout_key_id, return ret; } uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret != WH_ERROR_OK) { return ret; @@ -2308,10 +2291,8 @@ int wh_Client_Ed25519Sign(whClientContext* ctx, ed25519_key* key, evict = 0; uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_PK) { ret = WH_ERROR_ABORTED; @@ -2446,10 +2427,8 @@ int wh_Client_Ed25519Verify(whClientContext* ctx, ed25519_key* key, evict = 0; uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_PK) { ret = WH_ERROR_ABORTED; @@ -2581,10 +2560,8 @@ int wh_Client_Ed25519SignDma(whClientContext* ctx, ed25519_key* key, evict = 0; uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (group != WH_MESSAGE_GROUP_CRYPTO_DMA || action != WC_ALGO_TYPE_PK) { @@ -2728,10 +2705,8 @@ int wh_Client_Ed25519VerifyDma(whClientContext* ctx, ed25519_key* key, evict = 0; uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (group != WH_MESSAGE_GROUP_CRYPTO_DMA || action != WC_ALGO_TYPE_PK) { @@ -2916,10 +2891,7 @@ static int _RsaMakeKey(whClientContext* ctx, uint32_t size, uint32_t e, (unsigned int)req->size, (unsigned int)req->e, ret); if (ret == 0) { uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); WH_DEBUG_CLIENT_VERBOSE("RSA KeyGen Res recv: ret:%d, res_len: %u\n", ret, (unsigned int)res_len); @@ -3080,10 +3052,8 @@ int wh_Client_RsaFunction(whClientContext* ctx, RsaKey* key, int rsa_type, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response */ @@ -3192,10 +3162,8 @@ int wh_Client_RsaGetSize(whClientContext* ctx, const RsaKey* key, int* out_size) uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response */ @@ -3316,10 +3284,7 @@ static int _HkdfMakeKey(whClientContext* ctx, int hashType, whKeyId keyIdIn, if (ret == 0) { uint16_t res_len = 0; - do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); WH_DEBUG_CLIENT_VERBOSE("HKDF Res recv: ret:%d, res_len: %u\n", ret, (unsigned int)res_len); @@ -3483,9 +3448,7 @@ static int _CmacKdfMakeKey(whClientContext* ctx, whKeyId saltKeyId, } uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, dataPtr); if (ret == WH_ERROR_OK) { ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_KDF, (uint8_t**)&res); @@ -3665,10 +3628,8 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, #endif uint16_t res_len = 0; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response */ ret = @@ -3718,10 +3679,8 @@ int wh_Client_CmacCancelableResponse(whClientContext* c, Cmac* cmac, return WH_ERROR_BADARGS; } - do { - ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(c, &group, &action, &dataSz, + (uint8_t*)dataPtr); /* check for out of sequence action */ if (ret == 0 && @@ -3852,10 +3811,8 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, if (ret == WH_ERROR_OK) { uint16_t respSz = 0; - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -3962,10 +3919,8 @@ static int _xferSha256BlockAndUpdateDigest(whClientContext* ctx, WH_DEBUG_CLIENT_VERBOSE(" ret = %d\n", ret); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &dataSz, + (uint8_t*)dataPtr); } if (ret == 0) { /* Get response */ @@ -4118,10 +4073,8 @@ int wh_Client_Sha256Dma(whClientContext* ctx, wc_Sha256* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -4147,10 +4100,8 @@ int wh_Client_Sha256Dma(whClientContext* ctx, wc_Sha256* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } /* Copy out the final hash value */ @@ -4248,10 +4199,8 @@ static int _xferSha224BlockAndUpdateDigest(whClientContext* ctx, WH_DEBUG_CLIENT_VERBOSE(" ret = %d\n", ret); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &dataSz, + (uint8_t*)dataPtr); } if (ret == 0) { /* Get response */ @@ -4403,10 +4352,8 @@ int wh_Client_Sha224Dma(whClientContext* ctx, wc_Sha224* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -4433,10 +4380,8 @@ int wh_Client_Sha224Dma(whClientContext* ctx, wc_Sha224* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } /* Copy out the final hash value */ @@ -4529,10 +4474,8 @@ static int _xferSha384BlockAndUpdateDigest(whClientContext* ctx, WH_DEBUG_CLIENT_VERBOSE(" ret = %d\n", ret); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &dataSz, + (uint8_t*)dataPtr); } if (ret == 0) { /* Get response */ @@ -4684,10 +4627,8 @@ int wh_Client_Sha384Dma(whClientContext* ctx, wc_Sha384* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -4714,10 +4655,8 @@ int wh_Client_Sha384Dma(whClientContext* ctx, wc_Sha384* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } /* Copy out the final hash value */ @@ -4811,10 +4750,8 @@ static int _xferSha512BlockAndUpdateDigest(whClientContext* ctx, WH_DEBUG_CLIENT_VERBOSE(" ret = %d\n", ret); if (ret == 0) { - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &dataSz, + (uint8_t*)dataPtr); } if (ret == 0) { /* Get response */ @@ -4977,10 +4914,8 @@ int wh_Client_Sha512Dma(whClientContext* ctx, wc_Sha512* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { @@ -5007,10 +4942,8 @@ int wh_Client_Sha512Dma(whClientContext* ctx, wc_Sha512* sha, const uint8_t* in, (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { - do { - ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, NULL, NULL, &respSz, + (uint8_t*)dataPtr); } /* Copy out the final hash value */ @@ -5184,10 +5117,8 @@ static int _MlDsaMakeKey(whClientContext* ctx, int size, int level, (unsigned int)req->sz, ret); if (ret == 0) { uint16_t res_len; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -5345,10 +5276,8 @@ int wh_Client_MlDsaSign(whClientContext* ctx, const byte* in, word32 in_len, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -5480,10 +5409,8 @@ int wh_Client_MlDsaVerify(whClientContext* ctx, const byte* sig, word32 sig_len, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == 0) { /* Get response structure pointer, validates generic header * rc */ @@ -5648,10 +5575,8 @@ static int _MlDsaMakeKeyDma(whClientContext* ctx, int level, } if (ret == WH_ERROR_OK) { uint16_t res_len; - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); } (void)wh_Client_DmaProcessClientAddress( @@ -5807,10 +5732,8 @@ int wh_Client_MlDsaSignDma(whClientContext* ctx, const byte* in, word32 in_len, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header @@ -5942,10 +5865,8 @@ int wh_Client_MlDsaVerifyDma(whClientContext* ctx, const byte* sig, uint16_t res_len = 0; /* Recv Response */ - do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); + ret = _recvCryptoResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); if (ret == WH_ERROR_OK) { /* Get response structure pointer, validates generic header diff --git a/src/wh_timeout.c b/src/wh_timeout.c new file mode 100644 index 00000000..3c92ab3a --- /dev/null +++ b/src/wh_timeout.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2025 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 . + */ +/* + * src/wh_timeout.c + */ + +/* Pick up compile-time configuration */ +#include "wolfhsm/wh_settings.h" + +#include "wolfhsm/wh_timeout.h" +#include "wolfhsm/wh_error.h" + +int wh_Timeout_Init(whTimeoutCtx* timeout, const whTimeoutConfig* config) +{ + if ((timeout == NULL) || (config == NULL)) { + return WH_ERROR_BADARGS; + } + + timeout->startUs = 0; + timeout->timeoutUs = config->timeoutUs; + timeout->expiredCb = config->expiredCb; + timeout->cbCtx = config->cbCtx; + + return WH_ERROR_OK; +} + +int wh_Timeout_Set(whTimeoutCtx* timeout, uint64_t timeoutUs) +{ + if (timeout == NULL) { + return WH_ERROR_BADARGS; + } + + timeout->timeoutUs = timeoutUs; + + return WH_ERROR_OK; +} + +int wh_Timeout_Start(whTimeoutCtx* timeout) +{ + if (timeout == NULL) { + return WH_ERROR_BADARGS; + } + + timeout->startUs = WH_GETTIME_US(); + + return WH_ERROR_OK; +} + +int wh_Timeout_Stop(whTimeoutCtx* timeout) +{ + if (timeout == NULL) { + return WH_ERROR_BADARGS; + } + + timeout->startUs = 0; + timeout->timeoutUs = 0; + + return WH_ERROR_OK; +} + +int wh_Timeout_Expired(const whTimeoutCtx* timeout) +{ + uint64_t nowUs = 0; + int expired = 0; + + if (timeout == NULL) { + return 0; + } + + if (timeout->timeoutUs == 0) { + return 0; + } + + nowUs = WH_GETTIME_US(); + expired = (nowUs - timeout->startUs) >= timeout->timeoutUs; + if (expired && (timeout->expiredCb != NULL)) { + timeout->expiredCb(timeout->cbCtx); + } + return expired; +} diff --git a/test/config/wolfhsm_cfg.h b/test/config/wolfhsm_cfg.h index 940512a5..8e1a8a42 100644 --- a/test/config/wolfhsm_cfg.h +++ b/test/config/wolfhsm_cfg.h @@ -71,4 +71,6 @@ /* Allow persistent NVM artifacts in tests */ #define WOLFHSM_CFG_TEST_ALLOW_PERSISTENT_NVM_ARTIFACTS +#define WOLFHSM_CFG_ENABLE_TIMEOUT + #endif /* WOLFHSM_CFG_H_ */ diff --git a/test/wh_test.c b/test/wh_test.c index 29ba86b8..e332382e 100644 --- a/test/wh_test.c +++ b/test/wh_test.c @@ -40,6 +40,7 @@ #include "wh_test_keywrap.h" #include "wh_test_multiclient.h" #include "wh_test_log.h" +#include "wh_test_timeout.h" #if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) #include "wh_test_cert.h" @@ -71,6 +72,9 @@ int whTest_Unit(void) /* Component Tests */ WH_TEST_ASSERT(0 == whTest_Flash_RamSim()); WH_TEST_ASSERT(0 == whTest_NvmFlash()); +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT + WH_TEST_ASSERT(0 == whTest_Timeout()); +#endif #ifdef WOLFHSM_CFG_LOGGING WH_TEST_ASSERT(0 == whTest_Log()); #endif diff --git a/test/wh_test_timeout.c b/test/wh_test_timeout.c new file mode 100644 index 00000000..7dff3c5e --- /dev/null +++ b/test/wh_test_timeout.c @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2024 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/wh_test_timeout.c + * + */ + +#include + +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_timeout.h" +#include "wolfhsm/wh_error.h" + +#include "wh_test_common.h" +#include "wh_test_timeout.h" + +static void whTest_TimeoutCb(void* ctx) +{ + int* counter = (int*)ctx; + if (counter != NULL) { + (*counter)++; + } +} + +int whTest_Timeout(void) +{ + int cb_count = 0; + whTimeoutConfig cfg; + whTimeoutCtx timeout[1]; + + cfg.timeoutUs = 1; + cfg.expiredCb = whTest_TimeoutCb; + cfg.cbCtx = &cb_count; + + wh_Timeout_Init(timeout, &cfg); + WH_TEST_ASSERT_RETURN(timeout->startUs == 0); + WH_TEST_ASSERT_RETURN(timeout->timeoutUs == cfg.timeoutUs); + WH_TEST_ASSERT_RETURN(timeout->expiredCb == cfg.expiredCb); + WH_TEST_ASSERT_RETURN(timeout->cbCtx == cfg.cbCtx); + + wh_Timeout_Start(timeout); + WH_TEST_ASSERT_RETURN(timeout->timeoutUs > 0); + + wh_Timeout_Stop(timeout); + WH_TEST_ASSERT_RETURN(timeout->startUs == 0); + WH_TEST_ASSERT_RETURN(timeout->timeoutUs == 0); + + /* No expiration when disabled */ + WH_TEST_ASSERT_RETURN(wh_Timeout_Expired(timeout) == 0); + + WH_TEST_ASSERT_RETURN(wh_Timeout_Init(0, 0) == WH_ERROR_BADARGS); + WH_TEST_ASSERT_RETURN(wh_Timeout_Set(0, 0) == WH_ERROR_BADARGS); + WH_TEST_ASSERT_RETURN(wh_Timeout_Start(0) == WH_ERROR_BADARGS); + WH_TEST_ASSERT_RETURN(wh_Timeout_Stop(0) == WH_ERROR_BADARGS); + WH_TEST_ASSERT_RETURN(wh_Timeout_Expired(0) == 0); + + return 0; +} diff --git a/test/wh_test_timeout.h b/test/wh_test_timeout.h new file mode 100644 index 00000000..a863887f --- /dev/null +++ b/test/wh_test_timeout.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 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/wh_test_timeout.h + * + */ + +#ifndef TEST_WH_TEST_TIMEOUT_H_ +#define TEST_WH_TEST_TIMEOUT_H_ + +/** + * Runs timeout module tests. + * + * @return 0 on success and a non-zero error code on failure. + */ +int whTest_Timeout(void); + +#endif /* TEST_WH_TEST_TIMEOUT_H_ */ diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index f1b1b70a..6240860f 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -48,6 +48,7 @@ /* Component includes */ #include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_timeout.h" #include "wolfhsm/wh_message_customcb.h" #ifdef WOLFHSM_CFG_DMA #include "wolfhsm/wh_dma.h" @@ -121,6 +122,9 @@ struct whClientContext_t { uint8_t cancelable; whClientCancelCb cancelCb; #endif +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT + whTimeoutCtx respTimeout[1]; +#endif #ifdef WOLFHSM_CFG_DMA whClientDmaContext dma; #endif /* WOLFHSM_CFG_DMA */ @@ -135,6 +139,9 @@ struct whClientConfig_t { #ifdef WOLFHSM_CFG_DMA whClientDmaConfig* dmaConfig; #endif /* WOLFHSM_CFG_DMA */ +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT + whTimeoutConfig* respTimeoutConfig; +#endif /* WOLFHSM_CFG_ENABLE_TIMEOUT*/ }; typedef struct whClientConfig_t whClientConfig; @@ -193,6 +200,23 @@ int wh_Client_SendRequest(whClientContext* c, uint16_t group, uint16_t action, int wh_Client_RecvResponse(whClientContext* c, uint16_t* out_group, uint16_t* out_action, uint16_t* out_size, void* data); +#ifdef WOLFHSM_CFG_ENABLE_TIMEOUT +/** + * Receives a response from the server with a timeout window. + * + * @param c The client context. + * @param out_group Pointer to store the received group value. + * @param out_action Pointer to store the received action value. + * @param out_size Pointer to store the received size value. + * @param data Pointer to store the received data. + * @param timeout The timeout context to use. + * @return 0 if successful, WH_ERROR_TIMEOUT on expiration, or a negative value + * if an error occurred. + */ +int wh_Client_RecvResponseTimeout(whClientContext* c, uint16_t* out_group, + uint16_t* out_action, uint16_t* out_size, + void* data, whTimeoutCtx* timeout); +#endif /* WOLFHSM_CFG_ENABLE_TIMEOUT */ /** Comm component functions */ diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h index d918fe61..ffb0cdc4 100644 --- a/wolfhsm/wh_error.h +++ b/wolfhsm/wh_error.h @@ -45,6 +45,7 @@ enum WH_ERROR_ENUM { compile-time configuration */ WH_ERROR_USAGE = -2009, /* Operation not permitted based on object/key usage flags */ + WH_ERROR_TIMEOUT = -2010, /* Timeout occurred. */ /* NVM and keystore specific status returns */ WH_ERROR_LOCKED = -2100, /* Unlock and retry if necessary */ diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index b33ecc9e..0466927b 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -57,6 +57,9 @@ * WOLFHSM_CFG_ENABLE_SERVER - If defined, include server-specific * functionality * + * WOLFHSM_CFG_ENABLE_TIMEOUT - If defined, include timeout helpers and + * client response timeout support. + * * WOLFHSM_CFG_NVM_OBJECT_COUNT - Number of objects in ram and disk directories * Default: 32 * diff --git a/wolfhsm/wh_timeout.h b/wolfhsm/wh_timeout.h new file mode 100644 index 00000000..fbbc946b --- /dev/null +++ b/wolfhsm/wh_timeout.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2025 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 . + */ +/* + * wolfhsm/wh_timeout.h + * + * Generic timeout helpers based on WH_GETTIME_US(). + */ + +#ifndef WOLFHSM_WH_TIMEOUT_H_ +#define WOLFHSM_WH_TIMEOUT_H_ + +/* Pick up compile-time configuration */ +#include "wolfhsm/wh_settings.h" + +#define WH_MSEC_TO_USEC(sec) (sec * 1000ULL) +#define WH_SEC_TO_USEC(sec) (sec * 1000000ULL) +#define WH_MIN_TO_USEC(sec) (sec * WH_SEC_TO_USEC(60)) + +#include + +typedef void (*whTimeoutExpiredCb)(void* ctx); + +typedef struct { + uint64_t startUs; + uint64_t timeoutUs; + whTimeoutExpiredCb expiredCb; + void* cbCtx; +} whTimeoutCtx; + +typedef struct { + uint64_t timeoutUs; + whTimeoutExpiredCb expiredCb; + void* cbCtx; +} whTimeoutConfig; + +/** + * Initialize a timeout context from a configuration. + * + * @param timeout The timeout context to initialize. + * @param config The timeout configuration to apply. + * @return 0 on success, WH_ERROR_BADARGS on invalid input. + */ +int wh_Timeout_Init(whTimeoutCtx* timeout, const whTimeoutConfig* config); + +/** + * Configure a timeout value. + * + * @param timeout The timeout context to update. + * @param timeoutUs Timeout duration in microseconds; 0 disables the timeout. + * @return 0 on success, WH_ERROR_BADARGS on invalid input. + */ +int wh_Timeout_Set(whTimeoutCtx* timeout, uint64_t timeoutUs); + +/** + * Start or reset a timeout window using the configured timeoutUs. + * + * @param timeout The timeout context to start. + * @return 0 on success, WH_ERROR_BADARGS on invalid input. + */ +int wh_Timeout_Start(whTimeoutCtx* timeout); + +/** + * Disable a timeout and clear its bookkeeping. + * + * @param timeout The timeout context to stop. + * @return 0 on success, WH_ERROR_BADARGS on invalid input. + */ +int wh_Timeout_Stop(whTimeoutCtx* timeout); + +/** + * Check whether a timeout has expired. + * + * @param timeout The timeout context to check. + * @return 1 if expired, 0 if not expired or disabled. + */ +int wh_Timeout_Expired(const whTimeoutCtx* timeout); + +#endif /* !WOLFHSM_WH_TIMEOUT_H_ */ From c36725782208bc131779a6c7f7aea09551ddaeb5 Mon Sep 17 00:00:00 2001 From: Alex Lanzano Date: Fri, 30 Jan 2026 15:19:47 -0500 Subject: [PATCH 2/2] Address comments on #278 --- wolfhsm/wh_timeout.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wolfhsm/wh_timeout.h b/wolfhsm/wh_timeout.h index fbbc946b..a086bd01 100644 --- a/wolfhsm/wh_timeout.h +++ b/wolfhsm/wh_timeout.h @@ -28,9 +28,9 @@ /* Pick up compile-time configuration */ #include "wolfhsm/wh_settings.h" -#define WH_MSEC_TO_USEC(sec) (sec * 1000ULL) +#define WH_MSEC_TO_USEC(usec) (usec * 1000ULL) #define WH_SEC_TO_USEC(sec) (sec * 1000000ULL) -#define WH_MIN_TO_USEC(sec) (sec * WH_SEC_TO_USEC(60)) +#define WH_MIN_TO_USEC(min) (min * WH_SEC_TO_USEC(60)) #include @@ -86,6 +86,9 @@ int wh_Timeout_Stop(whTimeoutCtx* timeout); /** * Check whether a timeout has expired. * + * If the timeout is expired and an expired callback is configured, the + * callback is invoked before returning. + * * @param timeout The timeout context to check. * @return 1 if expired, 0 if not expired or disabled. */