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..a086bd01
--- /dev/null
+++ b/wolfhsm/wh_timeout.h
@@ -0,0 +1,97 @@
+/*
+ * 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(usec) (usec * 1000ULL)
+#define WH_SEC_TO_USEC(sec) (sec * 1000000ULL)
+#define WH_MIN_TO_USEC(min) (min * 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.
+ *
+ * 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.
+ */
+int wh_Timeout_Expired(const whTimeoutCtx* timeout);
+
+#endif /* !WOLFHSM_WH_TIMEOUT_H_ */