Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 107 additions & 1 deletion src/wh_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,13 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config)
/* register the cancel callback */
c->cancelCb = config->cancelCb;
#endif

#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (NULL != config->timeoutConfig) {
c->timeout.timeout_val = config->timeoutConfig->timeout_val;
c->timeout.timeout_enabled = config->timeoutConfig->timeout_enabled;
c->timeout.start_time = 0;
}
#endif
rc = wh_CommClient_Init(c->comm, config->comm);

#ifndef WOLFHSM_CFG_NO_CRYPTO
Expand Down Expand Up @@ -1523,4 +1529,104 @@ int wh_Client_KeyExportDma(whClientContext* c, uint16_t keyId,
}
#endif /* WOLFHSM_CFG_DMA */

#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
static uint64_t wh_timeval_to_64(const wh_timeval* tv)
{
if (tv == NULL) return 0;
return (uint64_t)tv->tv_sec * WH_BASE_TIMEOUT_UNIT
+ (uint64_t)((tv->tv_usec) / WH_BASE_TIMEOUT_UNIT);
}
Comment on lines +1533 to +1538
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this will result in a loss of precision. That only works for the default millisecond unit (1000). If a platform overrides WH_BASE_TIMEOUT_UNIT (e.g., 1 for seconds or 1'000'000 for microseconds) the microsecond field is either treated as seconds (tv_usec / 1) or dropped to zero (tv_usec / 1'000'000), so sub‑second timeouts are wildly wrong or become 0 (no timeout). I think the conversion should scale by the ratio of microseconds per base unit (e.g., tv_usec * WH_BASE_TIMEOUT_UNIT / 1000000) to keep behavior consistent when the base unit is customized.

All that said, I'm fine with the timeout being in us to simplify all of this.

/* Set Time Out if needed */
int wh_Client_InitCryptTimeout(whClientContext* c)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a confusing name - I would rename to wh_Client_TimeoutStart()

{
if (c == NULL) {
return WH_ERROR_BADARGS;
}

/* if feature not enabled, nothing to do */
if (c->timeout.timeout_enabled != 1) {
return WH_ERROR_OK;
}
if (c->timeout.cb.GetCurrentTime == NULL) {
return WH_ERROR_BADARGS;
}
/* initialize start time */
c->timeout.start_time = c->timeout.cb.GetCurrentTime(1);

return WH_ERROR_OK;
}

/* Check Crypto Timeout */
int wh_Client_CheckTimeout(whClientContext* c)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to wh_Client_TimeoutCheck

{
uint64_t current_ = 0;
uint64_t elapsed_ = 0;
uint64_t timeout_ = 0;

if (c == NULL) {
return WH_ERROR_BADARGS;
}

if (c->timeout.timeout_enabled != 1) {
return WH_ERROR_OK;
}

if (c->timeout.cb.GetCurrentTime == NULL) {
return WH_ERROR_BADARGS;
}

timeout_ = wh_timeval_to_64(&c->timeout.timeout_val);
if (timeout_ == 0) {
return WH_ERROR_OK;
}

/* check timeout by user cb if defined */
if (c->timeout.cb.CheckTimeout != NULL) {
return c->timeout.cb.CheckTimeout(
&c->timeout.start_time, timeout_);
}

/* Otherwise compute elapsed using user-provided GetCurrentTime */
current_ = c->timeout.cb.GetCurrentTime(0);
elapsed_ = current_ - c->timeout.start_time;
if (elapsed_ > timeout_) {
return WH_ERROR_TIMEOUT;
}

return WH_ERROR_OK;
}

int wh_Client_timeoutRegisterCb(whClientContext* client,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing capital T for consistency

whClientTimeOutCb* cb)
{
/* No NULL check for cb, since it is optional and always NULL checked before
* it is called */
if (NULL == client) {
return WH_ERROR_BADARGS;
}

client->timeout.cb.GetCurrentTime = cb->GetCurrentTime;
client->timeout.cb.CheckTimeout = cb->CheckTimeout;

return WH_ERROR_OK;
}

int wh_Client_timeoutEnable(whClientContext* client,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rename to wh_Client_TimeoutSet()

wh_timeval* timeout_val)
{
if (NULL == client) {
return WH_ERROR_BADARGS;
}

if (timeout_val != NULL) {
client->timeout.timeout_enabled = 1;
memcpy(&client->timeout.timeout_val, timeout_val,
sizeof(wh_timeval));
} else {
client->timeout.timeout_enabled = 0;
memset(&client->timeout.timeout_val, 0, sizeof(wh_timeval));
}
return WH_ERROR_OK;
}
#endif /* WOLFHSM_CFG_CLIENT_TIMEOUT */
#endif /* WOLFHSM_CFG_ENABLE_CLIENT */
71 changes: 65 additions & 6 deletions src/wh_client_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,27 @@ static int _getCryptoResponse(uint8_t* respBuf, uint16_t type,

return header->rc;
}
static int _wait_response_with_crypttimeout(whClientContext *ctx,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be able to refactor this to include the send too, right? That way we have one function that sets up the timeout and sends a request and blocks on the response?

I'd name this new function _SendRecieveWithTimeout()

uint16_t *out_group, uint16_t *out_action,
uint16_t *out_size, void* data)
{
int ret = WH_ERROR_OK;
do {
ret = wh_Client_RecvResponse(ctx, out_group, out_action, out_size, data);
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_NOTREADY) {
/* Check for crypto timeout */
int chk = wh_Client_CheckTimeout(ctx);
if (chk == WH_ERROR_TIMEOUT) {
return WH_ERROR_TIMEOUT;
} else if (chk < 0 && chk != WH_ERROR_OK) {
return chk;
}
}
#endif
} while (ret == WH_ERROR_NOTREADY);
return ret;
}

/** Implementations */
int wh_Client_RngGenerate(whClientContext* ctx, uint8_t* out, uint32_t size)
Expand Down Expand Up @@ -233,9 +254,14 @@ 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 defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
if (ret == 0) {
do {
ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len,
ret = _wait_response_with_crypttimeout(ctx, &group, &action, &res_len,
dataPtr);
} while (ret == WH_ERROR_NOTREADY);
}
Expand Down Expand Up @@ -420,14 +446,21 @@ int wh_Client_AesCtr(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in,
wh_Utils_Hexdump("[client] req packet: \n", (uint8_t*)req, req_len);
#endif
ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr);
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
/* read response */
if (ret == WH_ERROR_OK) {
/* Response packet */
uint16_t res_len = 0;
do {
ret =
wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr);
_wait_response_with_crypttimeout(ctx, &group, &action,
&res_len, dataPtr);
} while (ret == WH_ERROR_NOTREADY);

if (ret == WH_ERROR_OK) {
ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res);
if (ret == WH_ERROR_OK) {
Expand Down Expand Up @@ -542,14 +575,21 @@ int wh_Client_AesEcb(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in,
wh_Utils_Hexdump("[client] req packet: \n", (uint8_t*)req, req_len);
#endif
ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr);
#if defined(WOLFHSM_CFG_ENABLE_CWOLFHSM_CFG_CLIENT_TIMEOUTLIENT_TIMEOUT)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

broken macro

if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
/* read response */
if (ret == WH_ERROR_OK) {
/* Response packet */
uint16_t res_len = 0;
do {
ret =
wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr);
_wait_response_with_crypttimeout(ctx, &group, &action,
&res_len, dataPtr);
} while (ret == WH_ERROR_NOTREADY);

if (ret == WH_ERROR_OK) {
ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res);
if (ret == WH_ERROR_OK) {
Expand Down Expand Up @@ -661,14 +701,21 @@ int wh_Client_AesCbc(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in,
wh_Utils_Hexdump("[client] req packet: \n", (uint8_t*)req, req_len);
#endif
ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr);
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
/* read response */
if (ret == WH_ERROR_OK) {
/* Response packet */
uint16_t res_len = 0;
do {
ret =
wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr);
_wait_response_with_crypttimeout(ctx, &group, &action,
&res_len, dataPtr);
} while (ret == WH_ERROR_NOTREADY);

if (ret == WH_ERROR_OK) {
ret = _getCryptoResponse(dataPtr, type, (uint8_t**)&res);
if (ret == WH_ERROR_OK) {
Expand Down Expand Up @@ -795,11 +842,17 @@ int wh_Client_AesGcm(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in,

/* Send request and receive response */
ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr);
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
if (ret == 0) {
uint16_t res_len = 0;
do {
ret =
wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr);
_wait_response_with_crypttimeout(ctx, &group, &action,
&res_len, dataPtr);
} while (ret == WH_ERROR_NOTREADY);

if (ret == WH_ERROR_OK) {
Expand Down Expand Up @@ -1005,11 +1058,17 @@ int wh_Client_AesGcmDma(whClientContext* ctx, Aes* aes, int enc,
if (ret == WH_ERROR_OK) {
ret = wh_Client_SendRequest(ctx, group, action, reqLen, dataPtr);
}
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT)
if (ret == WH_ERROR_OK) {
ret = wh_Client_InitCryptTimeout(ctx);
}
#endif
if (ret == 0) {
uint16_t resLen = 0;
do {
ret =
wh_Client_RecvResponse(ctx, &group, &action, &resLen, dataPtr);
_wait_response_with_crypttimeout(ctx, &group, &action,
&resLen, dataPtr);
} while (ret == WH_ERROR_NOTREADY);

if (ret == WH_ERROR_OK) {
Expand Down
1 change: 1 addition & 0 deletions src/wh_comm.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ int wh_CommClient_Cleanup(whCommClient* context)
return rc;
}


#endif /* WOLFHSM_CFG_ENABLE_CLIENT */

/** Server Functions */
Expand Down
3 changes: 3 additions & 0 deletions test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ else
DEF += -DWOLFHSM_CFG_IS_TEST_SERVER
endif

ifeq ($(CRYPTIMEOUT),1)
DEF += -DWOLFHSM_CFG_CLIENT_TIMEOUT
endif

## Source files
# Assembly source files
Expand Down
7 changes: 7 additions & 0 deletions test/config/wolfhsm_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,11 @@

#define WOLFHSM_CFG_SERVER_NVM_FLASH_LOG

/* Enable client crypto timeout feature for testing */
#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) && \
defined(WOLFHSM_CFG_TEST_POSIX)
#define WOLFHSM_CFG_CLIENT_TIMEOUT_USEC (500000) /* 500ms */
#define WOLFHSM_CFG_TEST_CLIENT_TIMEOUT
#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */

#endif /* WOLFHSM_CFG_H_ */
58 changes: 57 additions & 1 deletion test/wh_test_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@
#include <wolfhsm/wh_error.h>

#include "wh_test_common.h"

#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT)
#include <sys/time.h> /* For gettimeofday */
#endif

/**
* Helper function to configure and select an NVM backend for testing.
Expand Down Expand Up @@ -90,3 +92,57 @@ int whTest_NvmCfgBackend(whTestNvmBackendType type,

return 0;
}

#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT)
#include <time.h>
#include <sys/time.h> /* For gettimeofday */

uint64_t whTest_GetCurrentTime(int reset)
{
(void)reset;
#if defined(CLOCK_MONOTONIC)
struct timespec ts;

if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
return 0;

/* Convert to milliseconds number. */
return (uint64_t)ts.tv_sec * 1000ULL +
(uint64_t)ts.tv_nsec / 1000000ULL;
#else
struct timeval tv;
if (gettimeofday(&tv, 0) < 0)
return 0;
/* Convert to milliseconds number. */
return (uint64_t)(tv.tv_sec * 1000ULL + tv.tv_usec / 1000ULL);
#endif
}
/* start_time stores the time (in milliseconds) returned by the GetCurrentTime()
* callback when the operation started.
* The actual unit depends on the GetCurrentTime() implementation.
* timeout_val represents the timeout in milliseconds(default),
* which is derived from the timeout value in whCommClientConfig.
*/
int whTest_CheckTimeout(uint64_t* start_time, uint64_t timeout_val)
{
uint64_t current_time;
uint64_t elapsed_time;

if (start_time == NULL) {
return WH_ERROR_BADARGS;
}

if (timeout_val == 0) {
return WH_ERROR_OK;
}

current_time = whTest_GetCurrentTime(0);
elapsed_time = current_time - *start_time;

if (elapsed_time > timeout_val) {
return WH_ERROR_TIMEOUT;
}

return WH_ERROR_OK;
}
#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */
9 changes: 9 additions & 0 deletions test/wh_test_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,13 @@ int whTest_NvmCfgBackend(whTestNvmBackendType type,
whTestNvmBackendUnion* nvmSetup, whNvmConfig* nvmCfg,
whFlashRamsimCfg* fCfg, whFlashRamsimCtx* fCtx,
const whFlashCb* fCb);
uint64_t whTest_GetCurrentTime(int reset);
int whTest_CheckTimeout(uint64_t* start_time, uint64_t timeout_val);

#define WH_CLIENT_TIMEOUT_CB \
{ \
.GetCurrentTime = whTest_GetCurrentTime, \
.CheckTimeout = whTest_CheckTimeout, \
}

#endif /* WH_TEST_COMMON_H_ */
Loading