diff --git a/src/wh_client.c b/src/wh_client.c index 605fedbb..7e5151c4 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -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 @@ -1516,4 +1522,102 @@ 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) / 1000000ULL); +} +/* Start Timeout */ +int wh_Client_TimeoutStart(whClientContext* c) +{ + 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 Timeout */ +int wh_Client_TimeoutCheck(whClientContext* c) +{ + 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, 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_TimeoutSet(whClientContext* client, 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 */ diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index c11b931a..fd42d802 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -181,6 +181,38 @@ static int _getCryptoResponse(uint8_t* respBuf, uint16_t type, return header->rc; } +static int _SendRecieveWithTimeout(whClientContext* ctx, uint16_t* group, + uint16_t* action, uint16_t req_len, + uint16_t* res_len, void* data) +{ + + int ret = WH_ERROR_OK; + + ret = wh_Client_SendRequest(ctx, *group, *action, req_len, data); +#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) + if (ret == WH_ERROR_OK) { + ret = wh_Client_TimeoutStart(ctx); + } +#endif + if (ret == WH_ERROR_OK) { + do { + ret = wh_Client_RecvResponse(ctx, group, action, res_len, data); + #if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) + if (ret == WH_ERROR_NOTREADY) { + /* Check for crypto timeout */ + int chk = wh_Client_TimeoutCheck(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) @@ -230,12 +262,11 @@ int wh_Client_RngGenerate(whClientContext* ctx, uint8_t* out, uint32_t size) (unsigned int)size); WH_DEBUG_CLIENT_VERBOSE("RNG: req:%p\n", req); - /* Send request and get response */ - ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); + /* Send request and get response with Timeout */ if (ret == 0) { do { - ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, - dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, req_len, + &res_len, dataPtr); } while (ret == WH_ERROR_NOTREADY); } if (ret == WH_ERROR_OK) { @@ -409,15 +440,16 @@ int wh_Client_AesCtr(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, WH_DEBUG_VERBOSE_HEXDUMP("[client] iv: \n", req_iv, iv_len); WH_DEBUG_VERBOSE_HEXDUMP("[client] tmp: \n", req_tmp, AES_BLOCK_SIZE); WH_DEBUG_VERBOSE_HEXDUMP("[client] req packet: \n", (uint8_t*)req, req_len); - ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); - /* read response */ + + /* Send and get response with Timeout */ if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, req_len, + &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) { @@ -521,15 +553,16 @@ int wh_Client_AesEcb(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, WH_DEBUG_VERBOSE_HEXDUMP("[client] key: \n", req_key, key_len); WH_DEBUG_VERBOSE_HEXDUMP("[client] iv: \n", req_iv, iv_len); WH_DEBUG_VERBOSE_HEXDUMP("[client] req packet: \n", (uint8_t*)req, req_len); - ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); - /* read response */ + + /* Send and get response with Timeout */ if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, req_len, + &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) { @@ -630,15 +663,15 @@ int wh_Client_AesCbc(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, WH_DEBUG_VERBOSE_HEXDUMP("[client] key: \n", req_key, key_len); WH_DEBUG_VERBOSE_HEXDUMP("[client] iv: \n", req_iv, iv_len); WH_DEBUG_VERBOSE_HEXDUMP("[client] req packet: \n", (uint8_t*)req, req_len); - ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); - /* read response */ + /* Send and get response with Timeout */ if (ret == WH_ERROR_OK) { /* Response packet */ uint16_t res_len = 0; do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, req_len, + &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) { @@ -752,13 +785,12 @@ int wh_Client_AesGcm(whClientContext* ctx, Aes* aes, int enc, const uint8_t* in, WH_DEBUG_VERBOSE_HEXDUMP("[client] AESGCM req packet: \n", dataPtr, req_len); - /* Send request and receive response */ - ret = wh_Client_SendRequest(ctx, group, action, req_len, dataPtr); + /* Send and get response with Timeout */ if (ret == 0) { uint16_t res_len = 0; do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &res_len, dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, req_len, + &res_len, dataPtr); } while (ret == WH_ERROR_NOTREADY); if (ret == WH_ERROR_OK) { @@ -951,14 +983,12 @@ int wh_Client_AesGcmDma(whClientContext* ctx, Aes* aes, int enc, /* Send request and receive response */ reqLen = sizeof(whMessageCrypto_GenericRequestHeader) + sizeof(*req); WH_DEBUG_VERBOSE_HEXDUMP("[client] AESGCM DMA req packet: \n", dataPtr, reqLen); - if (ret == WH_ERROR_OK) { - ret = wh_Client_SendRequest(ctx, group, action, reqLen, dataPtr); - } + /* Send and get response with Timeout */ if (ret == 0) { uint16_t resLen = 0; do { - ret = - wh_Client_RecvResponse(ctx, &group, &action, &resLen, dataPtr); + ret = _SendRecieveWithTimeout(ctx, &group, &action, reqLen, &resLen, + dataPtr); } while (ret == WH_ERROR_NOTREADY); if (ret == WH_ERROR_OK) { diff --git a/src/wh_comm.c b/src/wh_comm.c index b8e4f647..3409287d 100644 --- a/src/wh_comm.c +++ b/src/wh_comm.c @@ -211,6 +211,7 @@ int wh_CommClient_Cleanup(whCommClient* context) return rc; } + #endif /* WOLFHSM_CFG_ENABLE_CLIENT */ /** Server Functions */ diff --git a/test/Makefile b/test/Makefile index d35ac286..8301355e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -136,6 +136,9 @@ else DEF += -DWOLFHSM_CFG_IS_TEST_SERVER endif +ifeq ($(CRYPTIMEOUT),1) + DEF += -DWOLFHSM_CFG_CLIENT_TIMEOUT +endif ## Source files # Assembly source files diff --git a/test/config/wolfhsm_cfg.h b/test/config/wolfhsm_cfg.h index 6c8b926f..db09fa1a 100644 --- a/test/config/wolfhsm_cfg.h +++ b/test/config/wolfhsm_cfg.h @@ -68,4 +68,10 @@ /* Test log-based NVM flash backend */ #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_ */ diff --git a/test/wh_test_common.c b/test/wh_test_common.c index 2cac0aeb..4e618d54 100644 --- a/test/wh_test_common.c +++ b/test/wh_test_common.c @@ -26,7 +26,9 @@ #include #include "wh_test_common.h" - +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) +#include /* For gettimeofday */ +#endif /** * Helper function to configure and select an NVM backend for testing. @@ -90,3 +92,56 @@ int whTest_NvmCfgBackend(whTestNvmBackendType type, return 0; } + +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) +#include +#include /* 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 */ diff --git a/test/wh_test_common.h b/test/wh_test_common.h index ab563025..53b04026 100644 --- a/test/wh_test_common.h +++ b/test/wh_test_common.h @@ -144,4 +144,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_ */ diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 8534d4e9..642b2c91 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -73,6 +73,7 @@ #define FLASH_PAGE_SIZE (8) /* 8B */ #define ALT_CLIENT_ID (2) +#define ALT_CLIENT_ID_2 (3) enum { /* Total size needs to fit: @@ -88,8 +89,36 @@ enum { #define PLAINTEXT "mytextisbigplain" #ifdef WOLFHSM_CFG_IS_TEST_SERVER -/* Flag causing the server loop to sleep(1) */ -int serverDelay = 0; +int server_pause = 0; + +#if defined(WOLFHSM_CFG_TEST_POSIX) +pthread_mutex_t lock; +pthread_cond_t cond; + +static void pause_server() +{ + pthread_mutex_lock(&lock); + server_pause = 1; + pthread_mutex_unlock(&lock); +} + +static void resume_server() +{ + pthread_mutex_lock(&lock); + server_pause = 0; + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +} +#else +static void pause_server() +{ + server_pause = 1; +} +static void resume_server() +{ + server_pause = 0; +} +#endif /* WOLFHSM_CFG_TEST_POSIX */ #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ defined(WOLFHSM_CFG_ENABLE_SERVER) && defined(WOLFHSM_CFG_CANCEL_API) @@ -127,7 +156,42 @@ static int whTest_ShowNvmAvailable(whClientContext* ctx) } #endif /* WOLFHSM_CFG_DEBUG_VERBOSE && WOLFHSM_CFG_ENABLE_CLIENT */ + #ifdef WOLFHSM_CFG_ENABLE_CLIENT +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) +static int whTest_CryptoRngTimeout(whClientContext* ctx, int devId) +{ + byte block[32]; + int ret; + WC_RNG rng; + + ret = wc_InitRng_ex(&rng, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_InitRng_ex %d\n", ret); + } + else { + pause_server(); + ret = wc_RNG_GenerateBlock(&rng, block, sizeof(block)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + printf("RNG DEVID=0x%X TIMEOUT TEST SUCCESS\n", devId); + ret = wh_Client_CommInit(ctx, NULL, NULL); + if (ret != WH_ERROR_OK) { + WH_ERROR_PRINT("Failed to re-init comms %d\n", ret); + } + } + else { + WH_ERROR_PRINT("Failed to timeout wc_InitRng_ex %d\n", ret); + } + } + ret = wc_FreeRng(&rng); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_FreeRng %d\n", ret); + } + return ret; +} +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ + static int whTest_CryptoRng(whClientContext* ctx, int devId, WC_RNG* rng) { (void)ctx; /* Unused */ @@ -2807,10 +2871,216 @@ static int whTest_NonExportableKeystore(whClientContext* ctx, int devId, } #ifndef NO_AES -static int whTestCrypto_Aes(whClientContext* ctx, int devId, WC_RNG* rng) -{ #define WH_TEST_AES_KEYSIZE 16 #define WH_TEST_AES_TEXTSIZE 16 +#define WH_TEST_AES_AUTHSIZE 16 +#define WH_TEST_AES_TAGSIZE 16 +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) +static int whTestCryptoTimeout_Aes(whClientContext* ctx, int devId) +{ + int ret; + Aes aes[1]; + uint8_t iv[AES_BLOCK_SIZE] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, + 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F}; + uint8_t key[WH_TEST_AES_KEYSIZE] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, + 0x77, 0x88, 0x99, 0x00, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF}; + + uint8_t plainIn[WH_TEST_AES_TEXTSIZE] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, + 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF}; + uint8_t cipher[WH_TEST_AES_TEXTSIZE] = {0}; + uint8_t plainOut[WH_TEST_AES_TEXTSIZE] = {0}; +#ifdef HAVE_AESGCM + uint8_t authTag[WH_TEST_AES_TAGSIZE] = {0}; + uint8_t authIn[WH_TEST_AES_TAGSIZE] = {0}; +#endif /* HAVE_AESGCM */ + +#ifdef WOLFSSL_AES_COUNTER +#ifdef WOLFHSM_CFG_DMA + if (devId != WH_DEV_ID_DMA) { +#endif + ret = wc_AesInit(aes, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret); + } + if (ret == 0) { + ret = wc_AesSetKeyDirect(aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesSetKeyDirect %d\n", ret); + } + else { + pause_server(); + ret = wc_AesCtrEncrypt(aes, cipher, plainIn, sizeof(plainIn)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + printf("AES CTR DEVID=0x%X TIMEOUT TEST SUCCESS\n", devId); + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesCtrEncrypt %d\n", ret); + } + } + (void)wc_AesFree(aes); + } +#ifdef WOLFHSM_CFG_DMA + } +#endif /* WOLFHSM_CFG_DMA */ +#endif /* WOLFSSL_AES_COUNTER */ + +#ifdef HAVE_AES_ECB + if (ret == 0 +#ifdef WOLFHSM_CFG_DMA + && devId != WH_DEV_ID_DMA +#endif + ) { + /* test aes ECB with client side key */ + ret = wc_AesInit(aes, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret); + } + else { + ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesSetKey %d\n", ret); + } + else { + pause_server(); + ret = wc_AesEcbEncrypt(aes, cipher, plainIn, sizeof(plainIn)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesEcbEncrypt %d\n", ret); + } + } + if (ret == 0) { + ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_DECRYPTION); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesSetKey %d\n", ret); + } + else { + pause_server(); + ret = + wc_AesEcbDecrypt(aes, plainOut, cipher, sizeof(cipher)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + printf("AES ECB DEVID=0x%X TIMEOUT TEST SUCCESS\n", + devId); + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesEcbDecrypt %d\n", ret); + } + } + } + (void)wc_AesFree(aes); + } + } +#endif /* HAVE_AES_ECB */ +#ifdef HAVE_AES_CBC + if (ret == 0 +#ifdef WOLFHSM_CFG_DMA + && devId != WH_DEV_ID_DMA +#endif + ) { + /* test aes CBC with client side key */ + ret = wc_AesInit(aes, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret); + } + else { + ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_ENCRYPTION); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesSetKey %d\n", ret); + } + else { + pause_server(); + ret = wc_AesCbcEncrypt(aes, cipher, plainIn, sizeof(plainIn)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesCbcEncrypt %d\n", ret); + } + } + if (ret == 0) { + ret = wc_AesSetKey(aes, key, sizeof(key), iv, AES_DECRYPTION); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesSetKey %d\n", ret); + } + else { + pause_server(); + ret = + wc_AesCbcDecrypt(aes, plainOut, cipher, sizeof(cipher)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + printf("AES CBC DEVID=0x%X TIMEOUT TEST SUCCESS\n", + devId); + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesCbcDecrypt %d\n", ret); + } + } + } + (void)wc_AesFree(aes); + } + } +#endif /* HAVE_AES_CBC */ +#ifdef HAVE_AESGCM + if (ret == 0) { + /* test aes GCM with client side key */ + ret = wc_AesInit(aes, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesInit %d\n", ret); + } + else { + ret = wc_AesGcmSetKey(aes, key, sizeof(key)); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wc_AesGcmSetKey %d\n", ret); + } + else { + pause_server(); + ret = wc_AesGcmEncrypt(aes, cipher, plainIn, sizeof(plainIn), + iv, sizeof(iv), authTag, sizeof(authTag), + authIn, sizeof(authIn)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesGcmEncrypt %d\n", ret); + } + } + if (ret == 0) { + pause_server(); + ret = wc_AesGcmDecrypt(aes, plainOut, cipher, sizeof(cipher), + iv, sizeof(iv), authTag, sizeof(authTag), + authIn, sizeof(authIn)); + resume_server(); + if (ret == WH_ERROR_TIMEOUT) { + printf("AES GCM DEVID=0x%X TIMEOUT TEST SUCCESS\n", devId); + ret = wh_Client_CommInit(ctx, NULL, NULL); + } + else { + WH_ERROR_PRINT("Failed to wc_AesGcmDecrypt %d\n", ret); + } + } + (void)wc_AesFree(aes); + } + } +#endif /* HAVE_AESGCM */ + + return ret; +} +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ + +static int whTestCrypto_Aes(whClientContext* ctx, int devId, WC_RNG* rng) +{ int ret = 0; Aes aes[1]; uint8_t iv[AES_BLOCK_SIZE]; @@ -2949,8 +3219,7 @@ static int whTestCrypto_Aes(whClientContext* ctx, int devId, WC_RNG* rng) WH_TEST_PRINT("AES CTR DEVID=0x%X SUCCESS\n", devId); } } -#endif - +#endif /* WOLFSSL_AES_COUNTER */ #ifdef HAVE_AES_ECB if (ret == 0) { @@ -3176,8 +3445,6 @@ static int whTestCrypto_Aes(whClientContext* ctx, int devId, WC_RNG* rng) #endif /* HAVE_AES_CBC */ #ifdef HAVE_AESGCM -#define WH_TEST_AES_AUTHSIZE 16 -#define WH_TEST_AES_TAGSIZE 16 uint8_t authIn[WH_TEST_AES_AUTHSIZE]; uint8_t authTag[WH_TEST_AES_TAGSIZE] = { 0 }; @@ -3511,7 +3778,7 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) */ /* delay the server so scheduling doesn't interfere with the * timing */ - serverDelay = 1; + pause_server(); #endif ret = wc_CmacUpdate(cmac, (byte*)cmacFodder, @@ -3527,7 +3794,7 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) } else { #if WOLFHSM_CFG_IS_TEST_SERVER - serverDelay = 0; + resume_server(); #endif do { ret = wh_Client_CancelResponse(ctx); @@ -4808,6 +5075,32 @@ int whTest_CryptoKeyUsagePolicies(whClientContext* client, WC_RNG* rng) return 0; } +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) +static int EnableTimeout(whClientContext* client, wh_timeval* timeout_val) +{ + int ret = 0; + + /* configure timeout */ + ret = wh_Client_TimeoutSet(client, timeout_val); + if (ret != 0) { + WH_ERROR_PRINT("Failed to enable timeout:%d\n", ret); + } + return ret; +} + +static int DisableTimeout(whClientContext* client) +{ + int ret = 0; + + /* disable timeout */ + ret = wh_Client_TimeoutSet(client, NULL); + if (ret != 0) { + WH_ERROR_PRINT("Failed to disable timeout:%d\n", ret); + } + return ret; +} + +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ int whTest_CryptoClientConfig(whClientConfig* config) { @@ -4817,6 +5110,10 @@ int whTest_CryptoClientConfig(whClientConfig* config) int ret = 0; /* wolfcrypt */ WC_RNG rng[1]; +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) + whClientTimeOutCb timeOutCb[1] = {WH_CLIENT_TIMEOUT_CB}; + wh_timeval timeout_val = {0, WOLFHSM_CFG_CLIENT_TIMEOUT_USEC}; /* 500 ms */ +#endif if (config == NULL) { return WH_ERROR_BADARGS; @@ -4828,6 +5125,13 @@ int whTest_CryptoClientConfig(whClientConfig* config) if (ret != 0) { WH_ERROR_PRINT("Failed to comm init:%d\n", ret); } +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) + /* configure timeout */ + ret = wh_Client_TimeoutRegisterCb(client, timeOutCb); + if (ret != 0) { + WH_ERROR_PRINT("Failed to register timeout cb:%d\n", ret); + } +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ #ifdef WOLFHSM_CFG_DEBUG_VERBOSE if (ret == 0) { @@ -4845,6 +5149,17 @@ int whTest_CryptoClientConfig(whClientConfig* config) i++; } } +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) + ret = EnableTimeout(client, &timeout_val); + if (ret != 0) { + WH_ERROR_PRINT("Failed to enable timeout:%d\n", ret); + } + if (ret == 0) { + /* expect to have TIMEOUT */ + ret = whTest_CryptoRngTimeout(client, WH_DEV_ID); + } + DisableTimeout(client); +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ /* Now that we have tested all RNG devIds, reinitialize the default RNG * devId (non-DMA) that will be used by the remainder of the tests for @@ -4889,6 +5204,20 @@ int whTest_CryptoClientConfig(whClientConfig* config) i++; } } +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) + ret = EnableTimeout(client, &timeout_val); + if (ret != 0) { + WH_ERROR_PRINT("Failed to enable timeout:%d\n", ret); + } + i = 0; + while ((ret == WH_ERROR_OK) && (i < WH_NUM_DEVIDS)) { + ret = whTestCryptoTimeout_Aes(client, WH_DEV_IDS_ARRAY[i]); + if (ret == WH_ERROR_OK) { + i++; + } + } + DisableTimeout(client); +#endif /* WOLFHSM_CFG_TEST_CLIENT_TIMEOUT */ #endif /* !NO_AES */ #if defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) @@ -5072,6 +5401,7 @@ int whTest_CryptoServerConfig(whServerConfig* config) int ret = 0; #ifdef WOLFHSM_CFG_IS_TEST_SERVER int userChange = 0; + int numofChanges = 2; #endif if (config == NULL) { @@ -5090,11 +5420,18 @@ int whTest_CryptoServerConfig(whServerConfig* config) while(am_connected == WH_COMM_CONNECTED) { #ifdef WOLFHSM_CFG_IS_TEST_SERVER - while (serverDelay == 1) { #ifdef WOLFHSM_CFG_TEST_POSIX - sleep(1); + pthread_mutex_lock(&lock); +#endif + while (server_pause) { +#ifdef WOLFHSM_CFG_TEST_POSIX + pthread_cond_wait(&cond, &lock); #endif } + server_pause = 0; +#ifdef WOLFHSM_CFG_TEST_POSIX + pthread_mutex_unlock(&lock); +#endif #endif ret = wh_Server_HandleRequestMessage(server); if ((ret != WH_ERROR_NOTREADY) && @@ -5107,7 +5444,7 @@ int whTest_CryptoServerConfig(whServerConfig* config) #ifdef WOLFHSM_CFG_IS_TEST_SERVER /* keep alive for 2 user changes */ - if (am_connected != WH_COMM_CONNECTED && userChange < 2) { + if (am_connected != WH_COMM_CONNECTED && userChange < numofChanges) { if (userChange == 0) server->comm->client_id = ALT_CLIENT_ID; else if (userChange == 1) @@ -5139,6 +5476,9 @@ static void* _whClientTask(void *cf) WH_ERROR_PRINT("whTest_CryptoClientConfig returned %d\n", rc); } WH_TEST_ASSERT(0 == rc); +#if defined(WOLFHSM_CFG_TEST_CLIENT_CRYPTIMEOUT) + WH_TEST_ASSERT(0 == whTest_CryptoClientConfig_Timeout(cf)); +#endif return NULL; } #endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_CLIENT */ @@ -5173,6 +5513,11 @@ static void _whClientServerThreadTest(whClientConfig* c_conf, void* retval; int rc = 0; +#if defined(WOLFHSM_CFG_TEST_POSIX) + pthread_mutex_init(&lock, NULL); + pthread_cond_init(&cond, NULL); +#endif + rc = pthread_create(&sthread, NULL, _whServerTask, s_conf); if (rc == 0) { rc = pthread_create(&cthread, NULL, _whClientTask, c_conf); @@ -5206,15 +5551,19 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) /* Client configuration/contexts */ whTransportClientCb tccb[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; whTransportMemClientContext tmcc[1] = {0}; - whCommClientConfig cc_conf[1] = {{ - .transport_cb = tccb, - .transport_context = (void*)tmcc, - .transport_config = (void*)tmcf, - .client_id = WH_TEST_DEFAULT_CLIENT_ID, + + whCommClientConfig cc_conf[1] = {{ + .transport_cb = tccb, + .transport_context = (void*)tmcc, + .transport_config = (void*)tmcf, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; #ifdef WOLFHSM_CFG_DMA whClientDmaConfig clientDmaConfig = {0}; +#endif +#if defined(WOLFHSM_CFG_TEST_CLIENT_TIMEOUT) + whClientTimeOutConfig timeoutcfg[1] = {0}; #endif whClientConfig c_conf[1] = {{ .comm = cc_conf, @@ -5223,6 +5572,9 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) #endif #ifdef WOLFHSM_CFG_CANCEL_API .cancelCb = _cancelCb, +#endif +#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) + .timeoutConfig = &timeoutcfg[0], #endif }}; diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index 4a5a7b92..0cacaf09 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -113,6 +113,61 @@ typedef struct { */ typedef int (*whClientCancelCb)(uint16_t cancelSeq); + +typedef struct { + uint64_t tv_sec; /* Seconds. */ + uint64_t tv_usec; /* Microseconds. */ +} wh_timeval; + +typedef struct { + /* Get current time callback. + * This callback is mandatory when using the timeout feature. + * + * Parameters: + * reset - If non-zero, reset internal time tracking to zero. + * + * Returns: + * Current time. Time units are user-defined. + */ + uint64_t (*GetCurrentTime)(int reset); + /* Timeout check callback (Optional). + * If not defined, an internal implementation is used for timeout checking. + * The internal implementation assumes that time units returned by + * GetCurrentTime() are consistent with those used in timeout value. + * For example, if timeout_value is specified in milliseconds, it expects + * GetCurrentTime() to return time in milliseconds as well. + * + * Parameters: + * start_time - Pointer to the start time value as returned by + * GetCurrentTime(). timeout_value - Timeout value conversion in defined + * time units. The default is in milliseconds, but it can be customized by + * WH_BASE_TIMEOUT_UNIT. + * + * Returns: + * WH_ERROR_OK - Not timed out, + * WH_ERROR_TIMEOUT - Timed out. + */ + int (*CheckTimeout)(uint64_t* start_time, uint64_t timeout_val); +} whClientTimeOutCb; + +typedef struct { + whClientTimeOutCb cb; + wh_timeval timeout_val; + /* start_time stores the time returned by the GetCurrentTime() + * callback when the operation started. + * The actual unit depends on the GetCurrentTime() implementation. + */ + uint64_t start_time; + uint8_t timeout_enabled; + uint8_t WH_PAD[7]; +} whClientTimeOutContext; + +typedef struct { + whClientTimeOutCb cb; + wh_timeval timeout_val; + uint8_t timeout_enabled; +} whClientTimeOutConfig; + /* Client context */ struct whClientContext_t { uint16_t last_req_id; @@ -124,6 +179,9 @@ struct whClientContext_t { #ifdef WOLFHSM_CFG_DMA whClientDmaContext dma; #endif /* WOLFHSM_CFG_DMA */ +#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) + whClientTimeOutContext timeout; +#endif whCommClient comm[1]; }; @@ -135,6 +193,9 @@ struct whClientConfig_t { #ifdef WOLFHSM_CFG_DMA whClientDmaConfig* dmaConfig; #endif /* WOLFHSM_CFG_DMA */ +#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) + whClientTimeOutConfig* timeoutConfig; +#endif }; typedef struct whClientConfig_t whClientConfig; @@ -2640,4 +2701,15 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, #define WH_CLIENT_KEYID_MAKE_WRAPPED_META(_clientId, _id) \ WH_MAKE_KEYID(WH_KEYTYPE_WRAPPED, (_clientId), (_id)) +#if defined(WOLFHSM_CFG_CLIENT_TIMEOUT) +/* Start Client Timeout */ +int wh_Client_TimeoutStart(whClientContext* context); +/* Check Client Timeout */ +int wh_Client_TimeoutCheck(whClientContext* context); +/* Register Client Timeout Callback */ +int wh_Client_TimeoutRegisterCb(whClientContext* client, whClientTimeOutCb* cb); +/* Set Client Timeout */ +int wh_Client_TimeoutSet(whClientContext* client, wh_timeval* timeout_val); +#endif /* WOLFHSM_CFG_CLIENT_TIMEOUT */ + #endif /* !WOLFHSM_WH_CLIENT_H_ */ diff --git a/wolfhsm/wh_comm.h b/wolfhsm/wh_comm.h index 4b77d58f..f68cd2cf 100644 --- a/wolfhsm/wh_comm.h +++ b/wolfhsm/wh_comm.h @@ -211,8 +211,6 @@ uint8_t* wh_CommClient_GetDataPtr(whCommClient* context); * unfinished requests can be ignored. */ int wh_CommClient_Cleanup(whCommClient* context); - - /** CommServer component types */ /* Server transport interface */ diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h index d918fe61..1df375da 100644 --- a/wolfhsm/wh_error.h +++ b/wolfhsm/wh_error.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2025 wolfSSL Inc. * * This file is part of wolfHSM. * @@ -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, /* operation timed out */ /* 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 f02dda5f..710506a6 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -527,4 +527,12 @@ #endif /* WOLFHSM_CFG_DMA */ +/* CLIENT TIMEOUT CONFIGURATION */ +#ifdef WOLFHSM_CFG_CLIENT_TIMEOUT +#if !defined(WH_BASE_TIMEOUT_UNIT) +/* Default time unit is milliseconds */ +#define WH_BASE_TIMEOUT_UNIT 1000ULL +#endif +#endif /* !WOLFHSM_CFG_CLIENT_TIMEOUT */ + #endif /* !WOLFHSM_WH_SETTINGS_H_ */