Skip to content

Conversation

@miyazakh
Copy link
Contributor

@miyazakh miyazakh commented Oct 18, 2025

Add crypto timeout to RNG and AES

The changes add timeout control logic to cryptographic and other operations under the wolfHSM framework. The modifications allow the client to enforce a maximum allowed time for operations.

Added new callback function pointers to the relevant configuration/context structures to support timeout handling. These callbacks allow the application to provide custom time-related functions, such as:

  • Getting the current time (GetCurrentTime)
  • Checking whether the timeout has expired (CheckTimeout)

When the crypt-timeout feature is enabled, the GetCurrentTime callback must be provided as a user-defined function. If the CheckTimeout callback is not defined, internal default implementation is used.

Added a new build-time configuration macro:

  • WOLFHSM_CFG_ENABLE_CLIENT_TIMEOUT

This macro enables the client-side timeout feature. When enabled, the wolfHSM client checks for timeout conditions during operations.

The feature has been added to RNG and AES. It will be extended to the remaining cryptographic algorithms once this PR is approved.

For testing, make CRYPTIMEOUT=1 enables the items in tests/ folder.

@douzzer
Copy link

douzzer commented Oct 31, 2025

@miyazakh conflicts to resolve

@miyazakh
Copy link
Contributor Author

miyazakh commented Nov 2, 2025

resolve conflicts and issues after rebase. Updated based on Copilot’s suggestions

@miyazakh
Copy link
Contributor Author

miyazakh commented Nov 5, 2025

Hi @billphipps and @bigbrett
Would a generic timeout framework be acceptable to you? If so, I will proceed with adding the feature to the remaining cryptographic algorithms.

Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

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

Hi Hide,

Thanks for this, and great work! Overall I think the architecture matches my expectations for the most part, however I have proposed some changes to hopefully allow this feature to scale beyond just crypto. I think we should get this all correct and working as desired before moving on to other algorithms.

Also, please remove all braceless if statements from this PR.

*/
uint64_t crypt_start_time;
/* cached conversion of crypt_timeout */
uint64_t crypt_timeout_ms;
Copy link
Contributor

Choose a reason for hiding this comment

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

do we want to hardcode the units into this? What if I want us level timeout?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Refactor to remove the "_ms" suffix from variable names. The time unit depends on the return value of GetTimeout().

whCommSetConnectedCb connect_cb;
uint8_t client_id;
#if defined(WOLFHSM_CFG_ENABLE_CLIENT_CRYPTIMEOUT)
uint8_t crypt_timeout_enabled;
Copy link
Contributor

Choose a reason for hiding this comment

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

why is the enable flag in the config struct? IMO we should be able to turn on/off dynamically. We should have an API function in this file to set the enable flag so that it can be turned on/off on a per-operation basis.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add wh_Client_timeoutEnable. user can enable / disable time out feature through the API.

* callback when the operation started.
* The actual unit depends on the GetCurrentTime() implementation.
*/
uint64_t crypt_start_time;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we have all timeout state stored in its own structure?

something like whClientTimeOutContext

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Add whClientTimeOutContext definition in wh_client.h

*/
int (*CheckTimeout)(uint64_t* start_time, uint64_t timeout_ms);
uint8_t WH_PAD[8];
} whCryptoClientTimeOutCb;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we want this feature to be generic and eventually scale beyond crypto so lets name it accordingly. We might want NVM or keystore operations to timeout, for exampe. No reason to box this into crypto from the start.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Remove crypt and be generic.

Comment on lines 171 to 178
#ifdef WOLFSSL_TIMEVAL
typedef WOLFSSL_TIMEVAL WOLFHSM_TIMEVAL;
#else
typedef struct {
uint64_t tv_sec; /* Seconds. */
uint64_t tv_usec; /* Microseconds. */
} WOLFHSM_TIMEVAL;
#endif
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't like the all-caps naming nor the dependency on the wolfSSL implementation of the structure. I think it is fine to just define our own whTimeVal structure, as we don't want it to hinge on the particular configuration of wolfSSL

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed WOLFHSM_TIMEVALP to wh_timeval

/* Enable client crypto timeout feature for testing */
#if defined(WOLFHSM_CFG_ENABLE_CLIENT_CRYPTIMEOUT) && \
defined(WOLFHSM_CFG_TEST_POSIX)
#define WOLFHSM_CFG_CLIENT_CRYPTIMEOUT_SEC (2)
Copy link
Contributor

Choose a reason for hiding this comment

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

2 seconds? seems long for a default value on a POSIX system

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed to WOLFHSM_CFG_CLIENT_TIMEOUT_USEC 500000 /* 500 ms */

.transport_context = (void*)tmcc,
.transport_config = (void*)tmcf,
#if defined(WOLFHSM_CFG_TEST_CLIENT_CRYPTIMEOUT)
.crypt_timeout_cb = (void*)tc_timeoutcb,
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned in another comment, we want all timeout state condensed to one structure in the client comm context. Same with in the config struct. That way if the config struct has a NULL element for the timeout substruct, those fields won't be populated in the context. The context struct should be allowed to be NULL (optionally set) and no operation should happen in this case (but it should be safe to leave uninitialized). All accesses should be gated on NULL checks.

That way, in a scenario like the wolfCrypt test runner here, where we don't care about using timeouts, we can just leave this as NULL In the config.


WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, config));
client->comm->client_id = ALT_CLIENT_ID_2;
ret = wh_Client_CommInit(client, NULL, NULL);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we changing the client ID here after initialization? I'm confused as to what you are trying to accomplish.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Remove whTest_CryptoClientConfig_Timeout() and integrate tests into the existing crypt test


if (ret == 0) {
/* expect to have TIMEOUT */
ret = whTest_CryptoRng(client, WH_DEV_ID, rng);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally we could do things like set the timeout for the operations done as part of the RNG tests, then clear it after. Theoretically we could test different timeouts for different algo tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the serverDelay logic here is confusing and hard to follow. Originally we used the serverDelay flag to block the server until released by the client (for CMAC cancellation tests). I think this is a good time to refactor this functionality to support both use cases in a cleaner manner. Instead of setting delay values from the client side, could we do all this by just keeping it as a binary pause/resume that the client thread can signal to the server? AFAICT the client doesn't really care about the "time" we delay the server for, but more that we "pause it" while we do something. In this case we would just "pause the server", send the request, hit our timeout and verify it works as expected, then can "resume" the server after. Or did you have a different intent?

Copy link
Contributor Author

@miyazakh miyazakh Nov 8, 2025

Choose a reason for hiding this comment

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

Agree with you. Refactored while(serverDelay) to use pthread_cond_wait if POSIX.

@bigbrett bigbrett removed their assignment Nov 5, 2025
@miyazakh miyazakh self-assigned this Nov 5, 2025
@miyazakh miyazakh changed the title Add crypto timeout - step 1 Add operation timeout - step 1 Nov 8, 2025
@miyazakh miyazakh removed their assignment Nov 8, 2025
Copy link
Contributor

@bigbrett bigbrett left a comment

Choose a reason for hiding this comment

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

Overall I'm still not happy with the test integration. It adds more boilerplate to the crypto tests than I am comfortable with and makes them difficult to read. I'd prefer timeout functionality to be tested in its own standalone test if this is the case.

*/
int (*CheckTimeout)(uint64_t* start_time, uint64_t timeout_val);
} whClientTimeOutCb;
typedef struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

add newline between definitions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

uint64_t tv_sec; /* Seconds. */
uint64_t tv_usec; /* Microseconds. */
} wh_timeval;
typedef struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

add newline between definitions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added newline

int (*Cleanup)(void* context);
} whTransportClientCb;


Copy link
Contributor

Choose a reason for hiding this comment

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

extra whitespace

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed

int wh_Client_CheckTimeout(whClientContext* context);
/* Register Client Timeout Callback */
int wh_Client_timeoutRegisterCb(whClientContext* client,
whClientTimeOutCb* cb);
Copy link
Contributor

Choose a reason for hiding this comment

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

formatting

whClientTimeOutCb* cb);
/* Enable Client Timeout */
int wh_Client_timeoutEnable(whClientContext* client,
wh_timeval* timeout_val);
Copy link
Contributor

Choose a reason for hiding this comment

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

formatting

src/wh_client.c Outdated
+ (uint64_t)((tv->tv_usec) / WH_BASE_TIMEOUT_UNIT);
}
/* 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()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed

src/wh_client.c Outdated
}

/* 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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed

src/wh_client.c Outdated
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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Capitalized

src/wh_client.c Outdated
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()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed


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()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed and included sends and Start

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed

Comment on lines 1533 to 1535
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);
}
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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

tv_usec * WH_BASE_TIMEOUT_UNIT / 1000000 is true. Fixed it.

I'm not sure we need microsecond accuracy here, so I'll leave it as milliseconds for now.

@miyazakh miyazakh removed their assignment Nov 14, 2025
@bigbrett
Copy link
Contributor

@miyazakh this is mostly good, however I am also working on a feature that needs a system time abstraction. Rather than each feature that needs it using callbacks, I think we need to generalize wolfHSM to have a built-in "get time" functionality. That way this can be used directly by benchmarks, timeouts, and other features like logging. I'm going to take a stab at this in my logging PR that I'm about to open then will ping you when it is time to integrate into the timeout feature. It should hopefully simplify the code you need to write. So putting this on hold for now.

@miyazakh miyazakh marked this pull request as draft November 19, 2025 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants