-
Notifications
You must be signed in to change notification settings - Fork 22
Add operation timeout - step 1 #220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@miyazakh conflicts to resolve |
|
resolve conflicts and issues after rebase. Updated based on Copilot’s suggestions |
|
Hi @billphipps and @bigbrett |
There was a problem hiding this 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.
wolfhsm/wh_comm.h
Outdated
| */ | ||
| uint64_t crypt_start_time; | ||
| /* cached conversion of crypt_timeout */ | ||
| uint64_t crypt_timeout_ms; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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().
wolfhsm/wh_comm.h
Outdated
| whCommSetConnectedCb connect_cb; | ||
| uint8_t client_id; | ||
| #if defined(WOLFHSM_CFG_ENABLE_CLIENT_CRYPTIMEOUT) | ||
| uint8_t crypt_timeout_enabled; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
wolfhsm/wh_comm.h
Outdated
| * callback when the operation started. | ||
| * The actual unit depends on the GetCurrentTime() implementation. | ||
| */ | ||
| uint64_t crypt_start_time; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
wolfhsm/wh_comm.h
Outdated
| */ | ||
| int (*CheckTimeout)(uint64_t* start_time, uint64_t timeout_ms); | ||
| uint8_t WH_PAD[8]; | ||
| } whCryptoClientTimeOutCb; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
wolfhsm/wh_comm.h
Outdated
| #ifdef WOLFSSL_TIMEVAL | ||
| typedef WOLFSSL_TIMEVAL WOLFHSM_TIMEVAL; | ||
| #else | ||
| typedef struct { | ||
| uint64_t tv_sec; /* Seconds. */ | ||
| uint64_t tv_usec; /* Microseconds. */ | ||
| } WOLFHSM_TIMEVAL; | ||
| #endif |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
test/config/wolfhsm_cfg.h
Outdated
| /* 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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 */
test/wh_test_wolfcrypt_test.c
Outdated
| .transport_context = (void*)tmcc, | ||
| .transport_config = (void*)tmcf, | ||
| #if defined(WOLFHSM_CFG_TEST_CLIENT_CRYPTIMEOUT) | ||
| .crypt_timeout_cb = (void*)tc_timeoutcb, |
There was a problem hiding this comment.
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.
test/wh_test_crypto.c
Outdated
|
|
||
| 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); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
test/wh_test_crypto.c
Outdated
|
|
||
| if (ret == 0) { | ||
| /* expect to have TIMEOUT */ | ||
| ret = whTest_CryptoRng(client, WH_DEV_ID, rng); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
left a comment
There was a problem hiding this 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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add newline between definitions
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add newline between definitions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added newline
wolfhsm/wh_comm.h
Outdated
| int (*Cleanup)(void* context); | ||
| } whTransportClientCb; | ||
|
|
||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extra whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed
wolfhsm/wh_client.h
Outdated
| int wh_Client_CheckTimeout(whClientContext* context); | ||
| /* Register Client Timeout Callback */ | ||
| int wh_Client_timeoutRegisterCb(whClientContext* client, | ||
| whClientTimeOutCb* cb); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
formatting
wolfhsm/wh_client.h
Outdated
| whClientTimeOutCb* cb); | ||
| /* Enable Client Timeout */ | ||
| int wh_Client_timeoutEnable(whClientContext* client, | ||
| wh_timeval* timeout_val); |
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed
src/wh_client_crypto.c
Outdated
|
|
||
| return header->rc; | ||
| } | ||
| static int _wait_response_with_crypttimeout(whClientContext *ctx, |
There was a problem hiding this comment.
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()
There was a problem hiding this comment.
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
src/wh_client_crypto.c
Outdated
| 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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
broken macro
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
| 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); | ||
| } |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Updated based on Copilot's suggestions
|
@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. |
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:
GetCurrentTime)CheckTimeout)When the crypt-timeout feature is enabled, the
GetCurrentTimecallback must be provided as a user-defined function. If theCheckTimeoutcallback is not defined, internal default implementation is used.Added a new build-time configuration macro:
WOLFHSM_CFG_ENABLE_CLIENT_TIMEOUTThis 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=1enables the items in tests/ folder.