From d3dc8dce3590e448532299f49f33420d6447a4e8 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:38:30 -0700 Subject: [PATCH 1/4] WIP: CMAC state refactor. Passing tests and wolfCrypt tests. About to rip out cancellation --- src/wh_client_crypto.c | 53 ++++++--- src/wh_message_crypto.c | 22 +++- src/wh_server_crypto.c | 210 ++++++++++++++---------------------- test/wh_test_crypto.c | 20 ++-- wolfhsm/wh_message_crypto.h | 39 +++++-- 5 files changed, 174 insertions(+), 170 deletions(-) diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index c11b931ac..85e7a4891 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -3598,6 +3598,14 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, uint32_t mac_len = ((outMac == NULL) || (outMacLen == NULL)) ? 0 : *outMacLen; + /* For non-HSM keys on subsequent calls (no key provided), send the + * stored key bytes so the server can reconstruct the CMAC context */ + if (key == NULL && keyLen == 0 && WH_KEYID_ISERASED(key_id) && + (inLen != 0 || mac_len != 0)) { + key = (const uint8_t*)cmac->aes.devKey; + keyLen = cmac->aes.keylen; + } + /* Return success for a call with NULL params, or 0 len's */ if ((inLen == 0) && (keyLen == 0) && (mac_len == 0)) { /* Update the type */ @@ -3605,10 +3613,10 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, return WH_ERROR_OK; } - WH_DEBUG_CLIENT_VERBOSE("cmac key:%p key_len:%d in:%p in_len:%d out:%p out_len:%d " - "keyId:%x\n", - key, (int)keyLen, in, (int)inLen, outMac, (int)mac_len, key_id); - + WH_DEBUG_CLIENT_VERBOSE( + "cmac key:%p key_len:%d in:%p in_len:%d out:%p out_len:%d " + "keyId:%x\n", + key, (int)keyLen, in, (int)inLen, outMac, (int)mac_len, key_id); /* Get data pointer */ dataPtr = (uint8_t*)wh_CommClient_GetDataPtr(ctx->comm); @@ -3642,6 +3650,13 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, req->keyId = key_id; req->keySz = keyLen; req->outSz = mac_len; + + /* Pack non-sensitive CMAC state into request */ + memcpy(req->resumeState.buffer, cmac->buffer, AES_BLOCK_SIZE); + memcpy(req->resumeState.digest, cmac->digest, AES_BLOCK_SIZE); + req->resumeState.bufferSz = cmac->bufferSz; + req->resumeState.totalSz = cmac->totalSz; + /* multiple modes are possible so we need to set zero size if buffers * are NULL */ if ((in != NULL) && (inLen > 0)) { @@ -3656,6 +3671,13 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, if (ret == WH_ERROR_OK) { /* Update the local type since call succeeded */ cmac->type = type; + + /* Store key bytes locally for future calls (non-HSM keys) */ + if (key != NULL && keyLen > 0 && WH_KEYID_ISERASED(key_id)) { + memcpy((void*)cmac->aes.devKey, key, keyLen); + cmac->aes.keylen = keyLen; + } + #ifdef WOLFHSM_CFG_CANCEL_API /* if the client marked they may want to cancel, handle the * response in a separate call */ @@ -3671,16 +3693,17 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, } while (ret == WH_ERROR_NOTREADY); if (ret == WH_ERROR_OK) { /* Get response */ - ret = - _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); + ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, + (uint8_t**)&res); /* wolfCrypt allows positive error codes on success in some * scenarios */ if (ret >= 0) { - /* read keyId and res_out */ - if (key != NULL) { - WH_DEBUG_CLIENT_VERBOSE("got keyid %x\n", res->keyId); - cmac->devCtx = WH_KEYID_TO_DEVCTX(res->keyId); - } + /* Restore non-sensitive state from server response */ + memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); + memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); + cmac->bufferSz = res->resumeState.bufferSz; + cmac->totalSz = res->resumeState.totalSz; + if (outMac != NULL) { uint8_t* res_mac = (uint8_t*)(res + 1); memcpy(outMac, res_mac, res->outSz); @@ -3711,7 +3734,6 @@ int wh_Client_CmacCancelableResponse(whClientContext* c, Cmac* cmac, return WH_ERROR_BADARGS; } - /* Get data pointer */ dataPtr = (uint8_t*)wh_CommClient_GetDataPtr(c->comm); if (dataPtr == NULL) { @@ -3733,7 +3755,12 @@ int wh_Client_CmacCancelableResponse(whClientContext* c, Cmac* cmac, ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); /* wolfCrypt allows positive error codes on success in some scenarios */ if (ret >= 0) { - cmac->devCtx = (void*)((intptr_t)res->keyId); + /* Restore non-sensitive state from server response */ + memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); + memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); + cmac->bufferSz = res->resumeState.bufferSz; + cmac->totalSz = res->resumeState.totalSz; + if (out != NULL && outSz != NULL) { if (res->outSz > *outSz) { ret = WH_ERROR_BUFFER_SIZE; diff --git a/src/wh_message_crypto.c b/src/wh_message_crypto.c index 91a148948..514f2d0c4 100644 --- a/src/wh_message_crypto.c +++ b/src/wh_message_crypto.c @@ -695,6 +695,22 @@ int wh_MessageCrypto_TranslateSha2Response( } +/* CMAC State translation */ +int wh_MessageCrypto_TranslateCmacState( + uint16_t magic, const whMessageCrypto_CmacState* src, + whMessageCrypto_CmacState* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + /* buffer and digest are byte arrays - memcpy, no endian swap */ + memcpy(dest->buffer, src->buffer, sizeof(dest->buffer)); + memcpy(dest->digest, src->digest, sizeof(dest->digest)); + WH_T32(magic, dest, src, bufferSz); + WH_T32(magic, dest, src, totalSz); + return 0; +} + /* CMAC Request translation */ int wh_MessageCrypto_TranslateCmacRequest( uint16_t magic, const whMessageCrypto_CmacRequest* src, @@ -708,7 +724,8 @@ int wh_MessageCrypto_TranslateCmacRequest( WH_T32(magic, dest, src, inSz); WH_T32(magic, dest, src, keySz); WH_T16(magic, dest, src, keyId); - return 0; + return wh_MessageCrypto_TranslateCmacState( + magic, &src->resumeState, &dest->resumeState); } /* CMAC Response translation */ @@ -721,7 +738,8 @@ int wh_MessageCrypto_TranslateCmacResponse( } WH_T32(magic, dest, src, outSz); WH_T16(magic, dest, src, keyId); - return 0; + return wh_MessageCrypto_TranslateCmacState( + magic, &src->resumeState, &dest->resumeState); } /* ML-DSA Key Generation Request translation */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 282dab6cf..05ce59f5f 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -3019,7 +3019,6 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, uint32_t i; word32 len; - whKeyId keyId = WH_KEYID_ERASED; /* Setup fixed size fields */ uint8_t* in = @@ -3028,88 +3027,90 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, uint8_t* out = (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacResponse); + memset(&res, 0, sizeof(res)); + switch(req.type) { #if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) case WC_CMAC_AES: { - whNvmMetadata meta[1] = {{0}}; - uint8_t moveToBigCache = 0; word32 blockSz = AES_BLOCK_SIZE; - uint8_t tmpKey[AES_MAX_KEY_SIZE + AES_IV_SIZE]; + uint8_t tmpKey[AES_MAX_KEY_SIZE]; + word32 tmpKeyLen = 0; /* attempt oneshot if all fields are present */ if (req.inSz != 0 && req.keySz != 0 && req.outSz != 0) { len = req.outSz; WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); - ret = wc_AesCmacGenerate_ex(ctx->crypto->algoCtx.cmac, out, &len, in, - req.inSz, key, req.keySz, NULL, + ret = wc_AesCmacGenerate_ex(ctx->crypto->algoCtx.cmac, out, &len, + in, req.inSz, key, req.keySz, NULL, ctx->crypto->devId); res.outSz = len; - } else { - WH_DEBUG_SERVER_VERBOSE("cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", - req.keySz, req.inSz, req.outSz, req.keyId); - /* do each operation based on which fields are set */ + } + else { + WH_DEBUG_SERVER_VERBOSE( + "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", req.keySz, + req.inSz, req.outSz, req.keyId); + + /* Determine the key to use for initialization */ if (req.keySz != 0) { - /* initialize cmac with key and type */ - ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, key, req.keySz, - req.type, NULL, NULL, ctx->crypto->devId); - WH_DEBUG_SERVER_VERBOSE("cmac init with key:%p keylen:%d, type:%d ret:%d\n", - key, req.keySz, req.type, ret); - } else { - /* Key is not present, meaning client wants to use AES key from - * cache/nvm. In order to support multiple sequential CmacUpdate() - * calls, we need to cache the whole CMAC struct between invocations - * (which also holds the key). To do this we hijack the requested key's - * cache slot until CmacFinal() is called, at which point we evict the - * struct from the cache. TODO: client should hold CMAC state */ - len = sizeof(ctx->crypto->algoCtx.cmac); - keyId = wh_KeyId_TranslateFromClient( + /* Client provided the key directly in the request */ + memcpy(tmpKey, key, req.keySz); + tmpKeyLen = req.keySz; + } + else if (!WH_KEYID_ISERASED(req.keyId)) { + /* Load key from keystore by ID */ + whKeyId keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); /* Validate key usage policy - CMAC accepts sign or verify */ - if (!WH_KEYID_ISERASED(keyId)) { + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { + /* Sign not allowed, try verify */ ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - /* Sign not allowed, try verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } - if (ret != WH_ERROR_OK) { - return ret; - } + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); } - - ret = wh_Server_KeystoreReadKey( - ctx, keyId, meta, (uint8_t*)ctx->crypto->algoCtx.cmac, - (uint32_t*)&len); - if (ret == WH_ERROR_OK) { - /* if the key size is a multiple of aes, init the key and - * overwrite the existing key on exit */ - if (len == AES_128_KEY_SIZE || len == AES_192_KEY_SIZE || - len == AES_256_KEY_SIZE) { - WH_DEBUG_SERVER("cmac readkey got key len:%u\n", len); - moveToBigCache = 1; - memcpy(tmpKey, (uint8_t*)ctx->crypto->algoCtx.cmac, - len); - ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, tmpKey, len, - WC_CMAC_AES, NULL, NULL, ctx->crypto->devId); - } - else if (len != sizeof(ctx->crypto->algoCtx.cmac)) { - WH_DEBUG_SERVER("cmac bad readkey len:%u. sizeof(cmac):%lu\n", - len, sizeof(ctx->crypto->algoCtx.cmac)); - ret = BAD_FUNC_ARG; - } + if (ret != WH_ERROR_OK) { + return ret; } - else { - /* Initialize the cmac with a NULL key */ - /* initialize cmac with key and type */ - ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, NULL, - req.keySz, req.type, NULL, NULL, ctx->crypto->devId); - WH_DEBUG_SERVER("cmac init with NULL type:%d ret:%d\n", - req.type, ret); + + tmpKeyLen = sizeof(tmpKey); + ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, + &tmpKeyLen); + if (ret != WH_ERROR_OK) { + return ret; } } + else { + /* No key provided - error */ + return BAD_FUNC_ARG; + } + + /* Initialize CMAC context with key (re-derives k1/k2 subkeys) */ + if (ret == 0) { + ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, tmpKey, + tmpKeyLen, req.type, NULL, NULL, + ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE( + "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, + req.type, ret); + } + + /* Restore non-sensitive state from client. On the first call + * (init), the client sends zeroed state which is effectively a + * no-op since wc_InitCmac_ex already zeroed the struct. On + * subsequent calls (update/final), this restores the running + * intermediate state. */ + if (ret == 0) { + memcpy(ctx->crypto->algoCtx.cmac->buffer, + req.resumeState.buffer, AES_BLOCK_SIZE); + memcpy(ctx->crypto->algoCtx.cmac->digest, + req.resumeState.digest, AES_BLOCK_SIZE); + ctx->crypto->algoCtx.cmac->bufferSz = + req.resumeState.bufferSz; + ctx->crypto->algoCtx.cmac->totalSz = req.resumeState.totalSz; + } + /* Handle CMAC update, checking for cancellation */ if (ret == 0 && req.inSz != 0) { #ifndef WOLFHSM_CFG_CANCEL_API @@ -3120,7 +3121,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, blockSz = req.inSz - i; } ret = wc_CmacUpdate(ctx->crypto->algoCtx.cmac, in + i, - blockSz); + blockSz); #ifdef WOLFHSM_CFG_CANCEL_API if (ret == 0) { ret = _CheckCancellation(ctx, seq); @@ -3130,81 +3131,25 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); } - /* Check if we should finalize and evict, or cache for future calls - */ if (ret == 0 && req.outSz != 0) { /* Finalize CMAC operation */ - keyId = req.keyId; - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("cmac final keyId:%x len:%d\n", keyId, len); + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); ret = wc_CmacFinal(ctx->crypto->algoCtx.cmac, out, &len); res.outSz = len; res.keyId = WH_KEYID_ERASED; - - /* Evict the key from cache */ - if (!WH_KEYID_ISERASED(keyId)) { - /* Don't override return value except on failure */ - int tmpRet = wh_Server_KeystoreEvictKey( - ctx, wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - keyId)); - if (tmpRet != 0) { - ret = tmpRet; - } - } } -#ifdef WOLFHSM_CFG_CANCEL_API - else if (ret == WH_ERROR_CANCEL) { - /* Handle cancellation - evict key and abandon state */ - if (!WH_KEYID_ISERASED(req.keyId)) { - wh_Server_KeystoreEvictKey( - ctx, wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - req.keyId)); - } - } -#endif - /* Cache the CMAC struct for a future update call */ else if (ret == 0) { - /* cache/re-cache updated struct */ - if (req.keySz != 0) { - keyId = WH_MAKE_KEYID( WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - WH_KEYID_ERASED); - ret = wh_Server_KeystoreGetUniqueId(ctx, &keyId); - if (ret != WH_ERROR_OK) - return ret; - } - else { - keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - } - /* evict the aes sized key in the normal cache */ - if (moveToBigCache == 1) { - ret = wh_Server_KeystoreEvictKey(ctx, keyId); - } - if (ret == WH_ERROR_OK) { - meta->id = keyId; - meta->len = sizeof(ctx->crypto->algoCtx.cmac); - /* Nonzero key size means the client provided the key and - * wasn't able to provide flags, therefore we tag the key as - * useable for sign/verify operations. If the client instead - * wants to refer to the key by ID, meta->flags should - * already hold the flags set on the original AES key from - * the earlier read operation */ - if (req.keySz != 0) { - meta->flags = - WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY; - } - ret = wh_Server_KeystoreCacheKey( - ctx, meta, (uint8_t*)ctx->crypto->algoCtx.cmac); - if (ret == WH_ERROR_OK) { - res.keyId = wh_KeyId_TranslateToClient(keyId); - res.outSz = 0; - } - } - WH_DEBUG_SERVER_VERBOSE("cmac saved state in keyid:%x %x len:%u ret:%d type:%d\n", - keyId, WH_KEYID_ID(keyId), meta->len, ret, ctx->crypto->algoCtx.cmac->type); + /* Not finalizing - return updated state to client */ + memcpy(res.resumeState.buffer, + ctx->crypto->algoCtx.cmac->buffer, AES_BLOCK_SIZE); + memcpy(res.resumeState.digest, + ctx->crypto->algoCtx.cmac->digest, AES_BLOCK_SIZE); + res.resumeState.bufferSz = + ctx->crypto->algoCtx.cmac->bufferSz; + res.resumeState.totalSz = ctx->crypto->algoCtx.cmac->totalSz; + res.keyId = req.keyId; + res.outSz = 0; } } } break; @@ -3214,7 +3159,8 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, ret = CRYPTOCB_UNAVAILABLE; } if (ret == 0) { - ret = wh_MessageCrypto_TranslateCmacResponse(magic, &res, cryptoDataOut); + ret = wh_MessageCrypto_TranslateCmacResponse(magic, &res, + cryptoDataOut); if (ret == 0) { *outSize = sizeof(res) + res.outSz; } diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index e09f706a8..c838a9977 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -3606,8 +3606,6 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) uint8_t labelIn[WH_NVM_LABEL_LEN] = "CMAC Key Label"; - uint8_t keyEnd[sizeof(knownCmacKey)] = {0}; - uint8_t labelEnd[WH_NVM_LABEL_LEN] = {0}; uint16_t outLen = 0; uint8_t macOut[AES_BLOCK_SIZE] = {0}; word32 macLen; @@ -3697,21 +3695,14 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) else #endif /* WOLFHSM_CFG_DMA */ { - /* TODO: Eliminate this autoevict */ - /* verify the key was evicted after oneshot */ - outLen = sizeof(keyEnd); - ret = wh_Client_KeyExport(ctx, keyId, labelEnd, - sizeof(labelEnd), keyEnd, - &outLen); - if (ret != WH_ERROR_NOTFOUND) { + /* Key should still be present after oneshot since + * server no longer caches/evicts the Cmac struct */ + ret = wh_Client_KeyEvict(ctx, keyId); + if (ret != 0) { WH_ERROR_PRINT( - "Failed to not find evicted key: %d\n", - ret); + "Failed to wh_Client_KeyEvict %d\n", ret); ret = -1; } - else { - ret = 0; - } } } } @@ -3881,6 +3872,7 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) "Failed to wc_CmacFinal %d\n", ret); } else { + outLen = sizeof(macOut); ret = wh_Client_CmacCancelableResponse( ctx, cmac, macOut, &outLen); if (ret != 0) { diff --git a/wolfhsm/wh_message_crypto.h b/wolfhsm/wh_message_crypto.h index 96c84b242..a0572b438 100644 --- a/wolfhsm/wh_message_crypto.h +++ b/wolfhsm/wh_message_crypto.h @@ -797,14 +797,25 @@ int wh_MessageCrypto_TranslateSha2Response( * CMAC */ +/* CMAC intermediate state - non-sensitive fields only. + * k1/k2 subkeys are NOT included as they are key-derived material. + * Server re-derives them via wc_InitCmac_ex on each request. */ +typedef struct { + uint8_t buffer[16]; /* AES_BLOCK_SIZE: partial block buffer */ + uint8_t digest[16]; /* AES_BLOCK_SIZE: running CBC-MAC digest */ + uint32_t bufferSz; /* bytes in partial block buffer */ + uint32_t totalSz; /* total bytes processed */ +} whMessageCrypto_CmacState; + /* CMAC Request */ typedef struct { - uint32_t type; /* wolfCrypt CmacType enum */ - uint32_t outSz; - uint32_t inSz; - uint32_t keySz; - uint16_t keyId; - uint8_t WH_PAD[6]; + uint32_t type; /* wolfCrypt CmacType enum */ + uint32_t outSz; /* output MAC size (0 if not finalizing) */ + uint32_t inSz; /* input data size */ + uint32_t keySz; /* key size (0 if using keyId or already initialized) */ + uint16_t keyId; /* key ID for HSM-stored key */ + uint8_t WH_PAD[2]; + whMessageCrypto_CmacState resumeState; /* Data follows: * uint8_t in[inSz] * uint8_t key[keySz] @@ -813,14 +824,24 @@ typedef struct { /* CMAC Response */ typedef struct { - uint32_t outSz; - uint16_t keyId; + uint32_t outSz; /* actual output MAC size */ + uint16_t keyId; /* key ID (ERASED for non-HSM) */ uint8_t WH_PAD[2]; + whMessageCrypto_CmacState resumeState; + uint8_t WH_PAD2[12]; /* pad to match request size */ /* Data follows: - * uint8_t out[outSz]; + * uint8_t out[outSz] */ } whMessageCrypto_CmacResponse; +WH_UTILS_STATIC_ASSERT(sizeof(whMessageCrypto_CmacRequest) == + sizeof(whMessageCrypto_CmacResponse), + "CmacRequest and CmacResponse must be the same size"); + +int wh_MessageCrypto_TranslateCmacState( + uint16_t magic, const whMessageCrypto_CmacState* src, + whMessageCrypto_CmacState* dest); + int wh_MessageCrypto_TranslateCmacRequest( uint16_t magic, const whMessageCrypto_CmacRequest* src, whMessageCrypto_CmacRequest* dest); From 43fe6c7493e32b24ef107f3c6c636dd48ddda451 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:53:29 -0700 Subject: [PATCH 2/4] remove cancellation API --- src/wh_client.c | 71 ----------- src/wh_client_crypto.c | 64 ---------- src/wh_server.c | 29 ----- src/wh_server_crypto.c | 234 ++++++++++++++++--------------------- test/config/wolfhsm_cfg.h | 6 - test/wh_test_crypto.c | 167 -------------------------- wolfhsm/wh_client.h | 77 ------------ wolfhsm/wh_client_crypto.h | 18 --- wolfhsm/wh_error.h | 2 - wolfhsm/wh_message.h | 1 - wolfhsm/wh_server.h | 35 +----- wolfhsm/wh_settings.h | 6 - 12 files changed, 104 insertions(+), 606 deletions(-) diff --git a/src/wh_client.c b/src/wh_client.c index 927c4bf0e..132841b7b 100644 --- a/src/wh_client.c +++ b/src/wh_client.c @@ -76,10 +76,6 @@ int wh_Client_Init(whClientContext* c, const whClientConfig* config) } memset(c, 0, sizeof(*c)); -#ifdef WOLFHSM_CFG_CANCEL_API - /* register the cancel callback */ - c->cancelCb = config->cancelCb; -#endif rc = wh_CommClient_Init(c->comm, config->comm); @@ -472,73 +468,6 @@ int wh_Client_CommClose(whClientContext* c) return rc; } -#ifdef WOLFHSM_CFG_CANCEL_API -int wh_Client_EnableCancel(whClientContext* c) -{ - if (c == NULL) - return WH_ERROR_BADARGS; - c->cancelable = 1; - return 0; -} - -int wh_Client_DisableCancel(whClientContext* c) -{ - if (c == NULL) - return WH_ERROR_BADARGS; - c->cancelable = 0; - return 0; -} - -int wh_Client_CancelRequest(whClientContext* c) -{ - if (c == NULL) { - return WH_ERROR_BADARGS; - } - - if (c->cancelCb == NULL) { - return WH_ERROR_ABORTED; - } - - /* Since we aren't sending this request through the standard transport, we - * need to update the client context's last sent "kind" to prevent the Comm - * Client receive function from discarding the next response as an - * out-of-order/corrupted message. No need to update the sequence number/ID - * as it will not have been incremented by the cancel operation, as it is - * out-of-band */ - c->last_req_kind = WH_MESSAGE_KIND(WH_MESSAGE_GROUP_CANCEL, 0); - - return c->cancelCb(c->comm->seq); -} - -int wh_Client_CancelResponse(whClientContext* c) -{ - int ret = 0; - uint16_t group; - uint16_t action; - uint16_t size; - uint8_t* buf; - if (c == NULL) - return WH_ERROR_BADARGS; - /* check if the request was canceled */ - buf = wh_CommClient_GetDataPtr(c->comm); - ret = wh_Client_RecvResponse(c, &group, &action, &size, buf); - if (ret == 0 && group != WH_MESSAGE_GROUP_CANCEL) - return WH_ERROR_CANCEL_LATE; - return ret; -} - -int wh_Client_Cancel(whClientContext* c) -{ - int ret; - ret = wh_Client_CancelRequest(c); - if (ret == 0) { - do { - ret = wh_Client_CancelResponse(c); - } while (ret == WH_ERROR_NOTREADY); - } - return ret; -} -#endif /* WOLFHSM_CFG_CANCEL_API */ int wh_Client_EchoRequest(whClientContext* c, uint16_t size, const void* data) { diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index 85e7a4891..66fcb8672 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -3678,13 +3678,6 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, cmac->aes.keylen = keyLen; } -#ifdef WOLFHSM_CFG_CANCEL_API - /* if the client marked they may want to cancel, handle the - * response in a separate call */ - if (ctx->cancelable) { - return ret; - } -#endif uint16_t res_len = 0; do { @@ -3719,63 +3712,6 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, #endif /* !NO_AES */ -#ifdef WOLFHSM_CFG_CANCEL_API -int wh_Client_CmacCancelableResponse(whClientContext* c, Cmac* cmac, - uint8_t* out, uint16_t* outSz) -{ - whMessageCrypto_CmacResponse* res = NULL; - uint8_t* dataPtr = NULL; - int ret; - uint16_t group; - uint16_t action; - uint16_t dataSz; - - if (c == NULL || cmac == NULL) { - return WH_ERROR_BADARGS; - } - - /* Get data pointer */ - dataPtr = (uint8_t*)wh_CommClient_GetDataPtr(c->comm); - if (dataPtr == NULL) { - return WH_ERROR_BADARGS; - } - - do { - ret = wh_Client_RecvResponse(c, &group, &action, &dataSz, - (uint8_t*)dataPtr); - } while (ret == WH_ERROR_NOTREADY); - - /* check for out of sequence action */ - if (ret == 0 && - (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_CMAC)) { - ret = WH_ERROR_ABORTED; - } - if (ret == 0) { - /* Setup generic header and get pointer to response data */ - ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); - /* wolfCrypt allows positive error codes on success in some scenarios */ - if (ret >= 0) { - /* Restore non-sensitive state from server response */ - memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); - memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); - cmac->bufferSz = res->resumeState.bufferSz; - cmac->totalSz = res->resumeState.totalSz; - - if (out != NULL && outSz != NULL) { - if (res->outSz > *outSz) { - ret = WH_ERROR_BUFFER_SIZE; - } - else { - uint8_t* packOut = (uint8_t*)(res + 1); - memcpy(out, packOut, res->outSz); - *outSz = res->outSz; - } - } - } - } - return ret; -} -#endif /* WOLFHSM_CFG_CANCEL_API */ #ifdef WOLFHSM_CFG_DMA int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, diff --git a/src/wh_server.c b/src/wh_server.c index 83df8acbf..498fe3370 100644 --- a/src/wh_server.c +++ b/src/wh_server.c @@ -170,25 +170,6 @@ int wh_Server_GetConnected(whServerContext *server, return WH_ERROR_OK; } -#ifdef WOLFHSM_CFG_CANCEL_API -int wh_Server_GetCanceledSequence(whServerContext* server, uint16_t* outSeq) -{ - if (server == NULL || outSeq == NULL) - return WH_ERROR_BADARGS; - *outSeq = server->cancelSeq; - server->cancelSeq = 0; - return 0; -} - -int wh_Server_SetCanceledSequence(whServerContext* server, uint16_t cancelSeq) -{ - if (server == NULL) { - return WH_ERROR_BADARGS; - } - server->cancelSeq = cancelSeq; - return WH_ERROR_OK; -} -#endif /* WOLFHSM_CFG_CANCEL_API */ static int _wh_Server_HandleCommRequest(whServerContext* server, uint16_t magic, uint16_t action, uint16_t seq, @@ -418,16 +399,6 @@ int wh_Server_HandleRequestMessage(whServerContext* server) * contains the error code for the client in the resp.rc field. */ handlerRc = rc; - /* Handle cancellation by modifying response kind */ -#ifdef WOLFHSM_CFG_CANCEL_API - if (handlerRc == WH_ERROR_CANCEL) { - /* notify the client that their request was canceled */ - kind = WH_MESSAGE_KIND(WH_MESSAGE_GROUP_CANCEL, 0); - size = 0; - data = NULL; - } -#endif - /* Always send the response to the client, regardless of handler error. * The response packet contains the operational error code for the * client in the resp.rc field. */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 05ce59f5f..dccefc063 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -57,25 +57,6 @@ #include "wolfhsm/wh_message_crypto.h" -/** Helper functions */ -#ifdef WOLFHSM_CFG_CANCEL_API -/** - * Check if the current operation should be canceled - * @param ctx Server context - * @param seq Sequence number to check against - * @return WH_ERROR_CANCEL if canceled, 0 if not canceled, or error code - */ -static int _CheckCancellation(whServerContext* ctx, uint16_t seq) -{ - uint16_t cancelSeq; - int ret = wh_Server_GetCanceledSequence(ctx, &cancelSeq); - if (ret == 0 && cancelSeq == seq) { - return WH_ERROR_CANCEL; - } - return ret; -} -#endif - /** Forward declarations */ #ifndef NO_RSA #ifdef WOLFSSL_KEY_GEN @@ -3017,7 +2998,6 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, return WH_ERROR_BADARGS; } - uint32_t i; word32 len; /* Setup fixed size fields */ @@ -3031,128 +3011,120 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, switch(req.type) { #if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) - case WC_CMAC_AES: - { - word32 blockSz = AES_BLOCK_SIZE; - uint8_t tmpKey[AES_MAX_KEY_SIZE]; - word32 tmpKeyLen = 0; - - /* attempt oneshot if all fields are present */ - if (req.inSz != 0 && req.keySz != 0 && req.outSz != 0) { - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); - ret = wc_AesCmacGenerate_ex(ctx->crypto->algoCtx.cmac, out, &len, - in, req.inSz, key, req.keySz, NULL, - ctx->crypto->devId); - res.outSz = len; - } - else { - WH_DEBUG_SERVER_VERBOSE( - "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", req.keySz, - req.inSz, req.outSz, req.keyId); - - /* Determine the key to use for initialization */ - if (req.keySz != 0) { - /* Client provided the key directly in the request */ - memcpy(tmpKey, key, req.keySz); - tmpKeyLen = req.keySz; + case WC_CMAC_AES: { + uint8_t tmpKey[AES_MAX_KEY_SIZE]; + word32 tmpKeyLen = 0; + + /* attempt oneshot if all fields are present */ + if (req.inSz != 0 && req.keySz != 0 && req.outSz != 0) { + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); + + ret = wc_AesCmacGenerate_ex(ctx->crypto->algoCtx.cmac, out, + &len, in, req.inSz, key, req.keySz, + NULL, ctx->crypto->devId); + res.outSz = len; } - else if (!WH_KEYID_ISERASED(req.keyId)) { - /* Load key from keystore by ID */ - whKeyId keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - - /* Validate key usage policy - CMAC accepts sign or verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - /* Sign not allowed, try verify */ + else { + WH_DEBUG_SERVER_VERBOSE( + "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", + req.keySz, req.inSz, req.outSz, req.keyId); + + /* Determine the key to use for initialization */ + if (req.keySz != 0) { + /* Client provided the key directly in the request */ + memcpy(tmpKey, key, req.keySz); + tmpKeyLen = req.keySz; + } + else if (!WH_KEYID_ISERASED(req.keyId)) { + /* Load key from keystore by ID */ + whKeyId keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + + /* Validate key usage policy - CMAC accepts sign or verify + */ ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); + ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { + /* Sign not allowed, try verify */ + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); + } + if (ret != WH_ERROR_OK) { + return ret; + } + + tmpKeyLen = sizeof(tmpKey); + ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, + &tmpKeyLen); + if (ret != WH_ERROR_OK) { + return ret; + } } - if (ret != WH_ERROR_OK) { - return ret; + else { + /* No key provided - error */ + return BAD_FUNC_ARG; } - tmpKeyLen = sizeof(tmpKey); - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, - &tmpKeyLen); - if (ret != WH_ERROR_OK) { - return ret; - } - } - else { - /* No key provided - error */ - return BAD_FUNC_ARG; - } + /* Initialize CMAC context with key (re-derives k1/k2 subkeys) + */ + if (ret == 0) { - /* Initialize CMAC context with key (re-derives k1/k2 subkeys) */ - if (ret == 0) { - ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, tmpKey, - tmpKeyLen, req.type, NULL, NULL, - ctx->crypto->devId); - WH_DEBUG_SERVER_VERBOSE( - "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, - req.type, ret); - } + ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, tmpKey, + tmpKeyLen, req.type, NULL, NULL, + ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE( + "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, + req.type, ret); + } - /* Restore non-sensitive state from client. On the first call - * (init), the client sends zeroed state which is effectively a - * no-op since wc_InitCmac_ex already zeroed the struct. On - * subsequent calls (update/final), this restores the running - * intermediate state. */ - if (ret == 0) { - memcpy(ctx->crypto->algoCtx.cmac->buffer, - req.resumeState.buffer, AES_BLOCK_SIZE); - memcpy(ctx->crypto->algoCtx.cmac->digest, - req.resumeState.digest, AES_BLOCK_SIZE); - ctx->crypto->algoCtx.cmac->bufferSz = - req.resumeState.bufferSz; - ctx->crypto->algoCtx.cmac->totalSz = req.resumeState.totalSz; - } + /* Restore non-sensitive state from client. On the first call + * (init), the client sends zeroed state which is effectively a + * no-op since wc_InitCmac_ex already zeroed the struct. On + * subsequent calls (update/final), this restores the running + * intermediate state. */ + if (ret == 0) { + memcpy(ctx->crypto->algoCtx.cmac->buffer, + req.resumeState.buffer, AES_BLOCK_SIZE); + memcpy(ctx->crypto->algoCtx.cmac->digest, + req.resumeState.digest, AES_BLOCK_SIZE); + ctx->crypto->algoCtx.cmac->bufferSz = + req.resumeState.bufferSz; + ctx->crypto->algoCtx.cmac->totalSz = + req.resumeState.totalSz; + } - /* Handle CMAC update, checking for cancellation */ - if (ret == 0 && req.inSz != 0) { -#ifndef WOLFHSM_CFG_CANCEL_API - (void)seq; -#endif - for (i = 0; ret == 0 && i < req.inSz; i += AES_BLOCK_SIZE) { - if (i + AES_BLOCK_SIZE > req.inSz) { - blockSz = req.inSz - i; - } - ret = wc_CmacUpdate(ctx->crypto->algoCtx.cmac, in + i, - blockSz); -#ifdef WOLFHSM_CFG_CANCEL_API - if (ret == 0) { - ret = _CheckCancellation(ctx, seq); - } -#endif + /* Handle CMAC update */ + if (ret == 0 && req.inSz != 0) { + (void)seq; + ret = + wc_CmacUpdate(ctx->crypto->algoCtx.cmac, in, req.inSz); + WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); } - WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); - } - if (ret == 0 && req.outSz != 0) { - /* Finalize CMAC operation */ - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); - ret = wc_CmacFinal(ctx->crypto->algoCtx.cmac, out, &len); - res.outSz = len; - res.keyId = WH_KEYID_ERASED; - } - else if (ret == 0) { - /* Not finalizing - return updated state to client */ - memcpy(res.resumeState.buffer, - ctx->crypto->algoCtx.cmac->buffer, AES_BLOCK_SIZE); - memcpy(res.resumeState.digest, - ctx->crypto->algoCtx.cmac->digest, AES_BLOCK_SIZE); - res.resumeState.bufferSz = - ctx->crypto->algoCtx.cmac->bufferSz; - res.resumeState.totalSz = ctx->crypto->algoCtx.cmac->totalSz; - res.keyId = req.keyId; - res.outSz = 0; + if (ret == 0 && req.outSz != 0) { + /* Finalize CMAC operation */ + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); + ret = wc_CmacFinal(ctx->crypto->algoCtx.cmac, out, &len); + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + else if (ret == 0) { + /* Not finalizing - return updated state to client */ + memcpy(res.resumeState.buffer, + ctx->crypto->algoCtx.cmac->buffer, AES_BLOCK_SIZE); + memcpy(res.resumeState.digest, + ctx->crypto->algoCtx.cmac->digest, AES_BLOCK_SIZE); + res.resumeState.bufferSz = + ctx->crypto->algoCtx.cmac->bufferSz; + res.resumeState.totalSz = + ctx->crypto->algoCtx.cmac->totalSz; + res.keyId = req.keyId; + res.outSz = 0; + } } - } - } break; + } break; #endif /* !NO_AES && WOLFSSL_AES_DIRECT */ default: /* Type not supported */ diff --git a/test/config/wolfhsm_cfg.h b/test/config/wolfhsm_cfg.h index 940512a51..0a4bb8789 100644 --- a/test/config/wolfhsm_cfg.h +++ b/test/config/wolfhsm_cfg.h @@ -59,12 +59,6 @@ #define WOLFHSM_CFG_KEYWRAP #endif -/* Only enable cancellation tests in POSIX test harness if using the - * instrumented tests server. Otherwise CMAC is too fast to test cancellation */ -#ifdef WOLFHSM_CFG_IS_TEST_SERVER -#define WOLFHSM_CFG_CANCEL_API -#endif - /* Test log-based NVM flash backend */ #define WOLFHSM_CFG_SERVER_NVM_FLASH_LOG diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index c838a9977..78ad830b5 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -26,7 +26,6 @@ #ifndef WOLFHSM_CFG_NO_CRYPTO #include -#include /* For printf */ #include /* For memset, memcpy */ #include "wolfssl/wolfcrypt/settings.h" @@ -90,15 +89,6 @@ enum { #ifdef WOLFHSM_CFG_IS_TEST_SERVER /* Flag causing the server loop to sleep(1) */ int serverDelay = 0; - -#if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ - defined(WOLFHSM_CFG_ENABLE_SERVER) && defined(WOLFHSM_CFG_CANCEL_API) -/* pointer to expose server context cancel sequence to the client cancel - * callback */ -static uint16_t* cancelSeqP; - -#endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_CLIENT && \ - WOLFHSM_CFG_ENABLE_SERVER && WOLFHSM_CFG_CANCEL_API */ #endif /* WOLFHSM_CFG_IS_TEST_SERVER */ #if defined(WOLFHSM_CFG_DEBUG_VERBOSE) && defined(WOLFHSM_CFG_ENABLE_CLIENT) @@ -3606,7 +3596,6 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) uint8_t labelIn[WH_NVM_LABEL_LEN] = "CMAC Key Label"; - uint16_t outLen = 0; uint8_t macOut[AES_BLOCK_SIZE] = {0}; word32 macLen; whKeyId keyId; @@ -3769,145 +3758,6 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) } } -#if defined(WOLFHSM_CFG_CANCEL_API) && !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY) - /* test CMAC cancellation for supported devIds */ - if (ret == 0 -#ifdef WOLFHSM_CFG_DMA - && devId != WH_DEV_ID_DMA -#endif - ) { -#define WH_TEST_CMAC_TEXTSIZE 1000 - char cmacFodder[WH_TEST_CMAC_TEXTSIZE] = {0}; - - ret = wh_Client_EnableCancel(ctx); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wh_Client_EnableCancel %d\n", ret); - } - if (ret == 0) { - ret = wc_InitCmac_ex(cmac, knownCmacKey, sizeof(knownCmacKey), - WC_CMAC_AES, NULL, NULL, devId); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_InitCmac_ex %d\n", ret); - } - else { - ret = wh_Client_CmacCancelableResponse(ctx, cmac, NULL, 0); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wh_Client_CmacCancelableResponse %d\n", ret); - } - else { - -#if WOLFHSM_CFG_IS_TEST_SERVER - /* TODO: use hsm pause/resume functionality on real hardware - */ - /* delay the server so scheduling doesn't interfere with the - * timing */ - serverDelay = 1; -#endif - - ret = wc_CmacUpdate(cmac, (byte*)cmacFodder, - sizeof(cmacFodder)); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_CmacUpdate %d\n", ret); - } - else { - ret = wh_Client_CancelRequest(ctx); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wh_Client_CancelRequest %d\n", ret); - } - else { -#if WOLFHSM_CFG_IS_TEST_SERVER - serverDelay = 0; -#endif - do { - ret = wh_Client_CancelResponse(ctx); - } while (ret == WH_ERROR_NOTREADY); - if ((ret != 0) && - (ret != WH_ERROR_CANCEL_LATE)) { - WH_ERROR_PRINT( - "Failed to wh_Client_CancelResponse %d\n", - ret); - } - } - } - } - } - } - if (ret == 0) { - /* test cancelable request and response work for standard CMAC - * request with no cancellation */ - ret = wc_InitCmac_ex(cmac, knownCmacKey, sizeof(knownCmacKey), - WC_CMAC_AES, NULL, NULL, devId); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_InitCmac_ex %d\n", ret); - } - else { - ret = wh_Client_CmacCancelableResponse(ctx, cmac, NULL, 0); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wh_Client_CmacCancelableResponse %d\n", - ret); - } - else { - ret = wc_CmacUpdate(cmac, (byte*)knownCmacMessage, - sizeof(knownCmacMessage)); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_CmacUpdate %d\n", ret); - } - else { - ret = wh_Client_CmacCancelableResponse(ctx, cmac, - NULL, 0); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to " - "wh_Client_CmacCancelableResponse %d\n", - ret); - } - else { - macLen = sizeof(knownCmacTag); - ret = wc_CmacFinal(cmac, macOut, &macLen); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wc_CmacFinal %d\n", ret); - } - else { - outLen = sizeof(macOut); - ret = wh_Client_CmacCancelableResponse( - ctx, cmac, macOut, &outLen); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to " - "wh_Client_CmacCancelableResponse " - "%d\n", - ret); - } - else { - if (memcmp(knownCmacTag, macOut, - sizeof(knownCmacTag)) != 0) { - WH_ERROR_PRINT("CMAC FAILED KNOWN " - "ANSWER TEST\n"); - ret = -1; - } - else { - ret = wh_Client_DisableCancel(ctx); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to " - "wh_Client_DisableCancel " - "%d\n", - ret); - } - } - } - } - } - } - } - } - } - } -#endif /* WOLFHSM_CFG_CANCEL_API */ if (ret == 0) { WH_TEST_PRINT("CMAC DEVID=0x%X SUCCESS\n", devId); } @@ -5572,11 +5422,6 @@ int whTest_CryptoServerConfig(whServerConfig* config) return WH_ERROR_BADARGS; } -#if defined(WOLFHSM_CFG_IS_TEST_SERVER) && defined(WOLFHSM_CFG_TEST_POSIX) && \ - defined(WOLFHSM_CFG_CANCEL_API) - /* expose server ctx to client cancel callback */ - cancelSeqP = &server->cancelSeq; -#endif WH_TEST_RETURN_ON_FAIL(wh_Server_Init(server, config)); WH_TEST_RETURN_ON_FAIL(wh_Server_SetConnected(server, am_connected)); @@ -5648,15 +5493,6 @@ static void* _whServerTask(void* cf) #if defined(WOLFHSM_CFG_TEST_POSIX) && defined(WOLFHSM_CFG_ENABLE_CLIENT) && \ defined(WOLFHSM_CFG_ENABLE_SERVER) -#if defined(WOLFHSM_CFG_IS_TEST_SERVER) && defined(WOLFHSM_CFG_CANCEL_API) -/* Test client cancel callback that directly sets the sequence to cancel in the - * server context */ -static int _cancelCb(uint16_t seq) -{ - *cancelSeqP = seq; - return 0; -} -#endif static void _whClientServerThreadTest(whClientConfig* c_conf, whServerConfig* s_conf) @@ -5714,9 +5550,6 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) .comm = cc_conf, #ifdef WOLFHSM_CFG_DMA .dmaConfig = &clientDmaConfig, -#endif -#ifdef WOLFHSM_CFG_CANCEL_API - .cancelCb = _cancelCb, #endif }}; diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index f1b1b70a5..3f9097513 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -104,23 +104,10 @@ typedef struct { } whClientDmaContext; #endif /* WOLFHSM_CFG_DMA */ -/** - * Out of band callback function to inform the server to cancel a request, - * internal logic is provided by the port code. - * - * @param cancelSeq The sequence of the request to cancel. - * @return Returns 0 on success, or a negative value indicating an error. - */ -typedef int (*whClientCancelCb)(uint16_t cancelSeq); - /* Client context */ struct whClientContext_t { uint16_t last_req_id; uint16_t last_req_kind; -#ifdef WOLFHSM_CFG_CANCEL_API - uint8_t cancelable; - whClientCancelCb cancelCb; -#endif #ifdef WOLFHSM_CFG_DMA whClientDmaContext dma; #endif /* WOLFHSM_CFG_DMA */ @@ -129,9 +116,6 @@ struct whClientContext_t { struct whClientConfig_t { whCommClientConfig* comm; -#ifdef WOLFHSM_CFG_CANCEL_API - whClientCancelCb cancelCb; -#endif #ifdef WOLFHSM_CFG_DMA whClientDmaConfig* dmaConfig; #endif /* WOLFHSM_CFG_DMA */ @@ -364,67 +348,6 @@ int wh_Client_CommInfo(whClientContext* c, */ int wh_Client_CommCloseRequest(whClientContext* c); -#ifdef WOLFHSM_CFG_CANCEL_API -/** - * @brief Enables request cancellation. - * - * This function allows subsequent requests to be canceled, the responses that - * are normally handled by automatically by wolfCrypt must be handled with a - * wolfHSM specific function call. - * - * @param[in] c Pointer to the client context. - * @return int Returns 0 on success, or a negative error code on failure. - */ -int wh_Client_EnableCancel(whClientContext* c); - -/** - * @brief Disables request cancellation. - * - * This function disables request cancellation, making wolfCrypt automatically - * handle responses again. - * - * @param[in] c Pointer to the client context. - * @return int Returns 0 on success, or a negative error code on failure. - */ -int wh_Client_DisableCancel(whClientContext* c); - -/** - * @brief Cancels the previous request, currently only supports CMAC. Async - * Request - * - * This function sends a cancellation request to the server to cancel the - * previous request made. Does not wait for the response which must be handled - * separately - * - * @param[in] c Pointer to the client context. - * @return int Returns 0 on success, or a negative error code on failure. - */ -int wh_Client_CancelRequest(whClientContext* c); -/** - * @brief Handles the response for a cancellation the previous request, currently - * only supports CMAC. Async response handler. - * - * This function handles the response for a request cancellation previously sent - * to the server. Blocks to wait for the response. - * - * @param[in] c Pointer to the client context. - * @return int Returns 0 or WH_ERROR_CANCEL_LATE on success, or a negative - * error code on failure. - */ -int wh_Client_CancelResponse(whClientContext* c); -/** - * @brief Cancels the previous request, currently only supports CMAC. - * - * This function sends a cancellation request to the server and waits for the - * response to cancel the previous request made. - * - * @param[in] c Pointer to the client context. - * @return int Returns 0 or WH_ERROR_CANCEL_LATE on success, or a negative - * error code on failure. - */ -int wh_Client_Cancel(whClientContext* c); -#endif /* WOLFHSM_CFG_CANCEL_API */ - /** * @brief Receives a communication close response from the server. * diff --git a/wolfhsm/wh_client_crypto.h b/wolfhsm/wh_client_crypto.h index 856740b02..e031747ee 100644 --- a/wolfhsm/wh_client_crypto.h +++ b/wolfhsm/wh_client_crypto.h @@ -683,24 +683,6 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, const uint8_t* key, uint32_t keyLen, const uint8_t* in, uint32_t inLen, uint8_t* outMac, uint32_t* outMacLen); -/** - * @brief Handle cancelable CMAC response. - * - * This function handles a CMAC operation response from the server when - * cancellation has been enabled, since wolfCrypt won't automatically block and - * wait for the response. Note that DMA-based CMAC operations are NOT - * cancellable and if a cancel is requested, the cancellation will be aborted. - * - * @param[in] c Pointer to the client context structure. - * @param[in] cmac Pointer to the CMAC key structure. - * @param[out] out Buffer to store the CMAC result, only required after - * wc_CmacFinal. - * @param[in,out] outSz Pointer to the size of the out buffer in bytes, will be - * set to the size returned by the server on return. - * @return int Returns 0 on success, or a negative error code on failure. - */ -int wh_Client_CmacCancelableResponse(whClientContext* c, Cmac* cmac, - uint8_t* out, uint16_t* outSz); /** * @brief Associates a CMAC key with a specific key ID. diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h index d918fe616..2ad565973 100644 --- a/wolfhsm/wh_error.h +++ b/wolfhsm/wh_error.h @@ -35,8 +35,6 @@ enum WH_ERROR_ENUM { WH_ERROR_BADARGS = -2000, /* No side effects. Fix args. */ WH_ERROR_NOTREADY = -2001, /* Retry function. */ WH_ERROR_ABORTED = -2002, /* Function has fatally failed. Cleanup. */ - WH_ERROR_CANCEL = -2003, /* Operation was canceled */ - WH_ERROR_CANCEL_LATE = -2004, /* Cancel was processed too late */ WH_ERROR_CERT_VERIFY = -2005, /* Certificate verification failed */ WH_ERROR_BUFFER_SIZE = -2006, /* Generic buffer size mismatch. Buffer * length is not what was expected */ diff --git a/wolfhsm/wh_message.h b/wolfhsm/wh_message.h index 60167cbfe..37db1e5a7 100644 --- a/wolfhsm/wh_message.h +++ b/wolfhsm/wh_message.h @@ -43,7 +43,6 @@ enum WH_MESSAGE_ENUM { WH_MESSAGE_GROUP_PKCS11 = 0x0600, /* PKCS11 protocol */ WH_MESSAGE_GROUP_SHE = 0x0700, /* SHE protocol */ WH_MESSAGE_GROUP_COUNTER = 0x0800, /* monotonic counters */ - WH_MESSAGE_GROUP_CANCEL = 0x0900, /* request cancellation */ WH_MESSAGE_GROUP_CUSTOM = 0x0A00, /* User-specified features */ WH_MESSAGE_GROUP_CRYPTO_DMA = 0x0B00, /* DMA crypto operations */ WH_MESSAGE_GROUP_CERT = 0x0C00, /* Certificate operations */ diff --git a/wolfhsm/wh_server.h b/wolfhsm/wh_server.h index 4e9226583..f7b37da04 100644 --- a/wolfhsm/wh_server.h +++ b/wolfhsm/wh_server.h @@ -186,10 +186,7 @@ struct whServerContext_t { #ifdef WOLFHSM_CFG_DMA whServerDmaContext dma; #endif /* WOLFHSM_CFG_DMA */ - int connected; -#ifdef WOLFHSM_CFG_CANCEL_API - uint16_t cancelSeq; -#endif + int connected; #ifdef WOLFHSM_CFG_LOGGING whLogContext log; #endif /* WOLFHSM_CFG_LOGGING */ @@ -255,36 +252,6 @@ int wh_Server_SetConnectedCb(void* s, whCommConnected connected); int wh_Server_GetConnected(whServerContext* server, whCommConnected* out_connected); -#ifdef WOLFHSM_CFG_CANCEL_API -/** - * @brief Gets the canceled sequence number of the server. - * - * The canceled sequence number is the comms layer sequence number of the last - * canceled request. This number is set by the server port in response to an - * out-of-band signal from the client when the client wishes to cancel a - * request. - * - * @param[in] server Pointer to the server context. - * @param[out] outSeq Pointer to store the canceled sequence number. - * @return int Returns 0 on success, or WH_ERROR_BADARGS if the arguments are - * invalid - * - */ -int wh_Server_GetCanceledSequence(whServerContext* server, uint16_t* outSeq); - - -/** - * @brief Sets the canceled sequence number of the server. - * - * The canceled sequence number is the comms layer sequence number of the last - * canceled request. This function should be used by the server port to set the - * canceled sequence number in response to an out-of-band signal from the - * client. - * - */ -int wh_Server_SetCanceledSequence(whServerContext* server, uint16_t cancelSeq); -#endif /* WOLFHSM_CFG_CANCEL_API */ - /** * @brief Handles incoming request messages and dispatches them to the * appropriate handlers. diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index b33ecc9e9..23167c860 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -90,12 +90,6 @@ * test harness. * Default: Not defined * - * WOLFHSM_CFG_CANCEL_API - If defined, enables the cancellation API support - * allowing clients to cancel in-progress operations. This includes the client - * cancel functions and server-side cancellation handling. When not defined, - * all cancellation code is compiled out. - * Default: Not defined - * * WOLFHSM_CFG_DEBUG - If defined, enable basic debug output from wolfHSM * Default: Not defined * From 2dedb291c42af6990ee1d1e9a9c3e241f6e7a444 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Fri, 30 Jan 2026 17:10:04 -0700 Subject: [PATCH 3/4] - refactor non-dma oneshot cmac generate to support cached keys - refactor DMA CMAC to use client-supplied state vs state by reference - refactor to use stack allocated CMAC context - expand CMAC tests to mimic wolfCrypt tests but with cached keys - housekeeping, error checking --- src/wh_client_crypto.c | 242 +++++++------- src/wh_message_crypto.c | 53 ++- src/wh_server_crypto.c | 637 ++++++++++++++++-------------------- test/wh_test_crypto.c | 342 +++++++++++++------ wolfhsm/wh_message_crypto.h | 45 +-- wolfhsm/wh_server.h | 16 - 6 files changed, 676 insertions(+), 659 deletions(-) diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index 66fcb8672..e83a431b2 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -3594,19 +3594,24 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, whMessageCrypto_CmacResponse* res = NULL; uint8_t* dataPtr = NULL; + if (ctx == NULL || cmac == NULL) { + return WH_ERROR_BADARGS; + } + whKeyId key_id = WH_DEVCTX_TO_KEYID(cmac->devCtx); uint32_t mac_len = ((outMac == NULL) || (outMacLen == NULL)) ? 0 : *outMacLen; - /* For non-HSM keys on subsequent calls (no key provided), send the - * stored key bytes so the server can reconstruct the CMAC context */ + /* For non-HSM keys on incremental calls (update/final with no key argument + * provided), send the stored key bytes so the server can reconstruct the + * CMAC context */ if (key == NULL && keyLen == 0 && WH_KEYID_ISERASED(key_id) && (inLen != 0 || mac_len != 0)) { key = (const uint8_t*)cmac->aes.devKey; keyLen = cmac->aes.keylen; } - /* Return success for a call with NULL params, or 0 len's */ + /* Update type and return success for 0 length data, nothing else to do */ if ((inLen == 0) && (keyLen == 0) && (mac_len == 0)) { /* Update the type */ cmac->type = type; @@ -3630,19 +3635,14 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, uint8_t* req_in = (uint8_t*)(req + 1); uint8_t* req_key = req_in + inLen; - uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) + - sizeof(*req) + inLen + keyLen; + uint32_t hdr_sz = + sizeof(whMessageCrypto_GenericRequestHeader) + sizeof(*req); - /* TODO get rid of this logic, we should always fail */ - if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { - /* if we're using an HSM req_key return BAD_FUNC_ARG */ - if (!WH_KEYID_ISERASED(key_id)) { - return WH_ERROR_BADARGS; - } - else { - return CRYPTOCB_UNAVAILABLE; - } + if (inLen > WOLFHSM_CFG_COMM_DATA_LEN - hdr_sz || + keyLen > WOLFHSM_CFG_COMM_DATA_LEN - hdr_sz - inLen) { + return WH_ERROR_BADARGS; } + uint16_t req_len = hdr_sz + inLen + keyLen; /* Setup request packet */ req->type = type; @@ -3652,13 +3652,14 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, req->outSz = mac_len; /* Pack non-sensitive CMAC state into request */ - memcpy(req->resumeState.buffer, cmac->buffer, AES_BLOCK_SIZE); - memcpy(req->resumeState.digest, cmac->digest, AES_BLOCK_SIZE); + memcpy(req->resumeState.buffer, cmac->buffer, + sizeof(req->resumeState.buffer)); + memcpy(req->resumeState.digest, cmac->digest, + sizeof(req->resumeState.digest)); req->resumeState.bufferSz = cmac->bufferSz; req->resumeState.totalSz = cmac->totalSz; - /* multiple modes are possible so we need to set zero size if buffers - * are NULL */ + /* copy input data to request, if relevant */ if ((in != NULL) && (inLen > 0)) { memcpy(req_in, in, inLen); } @@ -3672,7 +3673,7 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, /* Update the local type since call succeeded */ cmac->type = type; - /* Store key bytes locally for future calls (non-HSM keys) */ + /* If using non-HSM keys, store key bytes locally for future calls */ if (key != NULL && keyLen > 0 && WH_KEYID_ISERASED(key_id)) { memcpy((void*)cmac->aes.devKey, key, keyLen); cmac->aes.keylen = keyLen; @@ -3686,23 +3687,26 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, } while (ret == WH_ERROR_NOTREADY); if (ret == WH_ERROR_OK) { /* Get response */ - ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, - (uint8_t**)&res); + ret = + _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); /* wolfCrypt allows positive error codes on success in some * scenarios */ if (ret >= 0) { /* Restore non-sensitive state from server response */ - memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); - memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); + memcpy(cmac->buffer, res->resumeState.buffer, + sizeof(cmac->buffer)); + memcpy(cmac->digest, res->resumeState.digest, + sizeof(cmac->digest)); cmac->bufferSz = res->resumeState.bufferSz; cmac->totalSz = res->resumeState.totalSz; - if (outMac != NULL) { - uint8_t* res_mac = (uint8_t*)(res + 1); - memcpy(outMac, res_mac, res->outSz); - if (outMacLen != NULL) { - *(outMacLen) = res->outSz; + /* Copy out finalized CMAC if present */ + if (outMac != NULL && outMacLen != NULL) { + if (res->outSz < *outMacLen) { + *outMacLen = res->outSz; } + uint8_t* res_mac = (uint8_t*)(res + 1); + memcpy(outMac, res_mac, *outMacLen); } } } @@ -3718,23 +3722,40 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, const uint8_t* key, uint32_t keyLen, const uint8_t* in, uint32_t inLen, uint8_t* outMac, uint32_t* outMacLen) { - int ret = WH_ERROR_OK; - whMessageCrypto_CmacDmaRequest* req = NULL; - whMessageCrypto_CmacDmaResponse* res = NULL; - uint8_t* dataPtr = NULL; - int finalize = 0; - uintptr_t inAddr = 0; /* The req->input.addr is reused elsewhere, this - local variable is to keep track of the resulting - DMA translation to pass back to the callback on - POST operations. */ - uintptr_t outAddr = 0; - uintptr_t keyAddr = 0; - uintptr_t stateAddr = 0; + int ret = WH_ERROR_OK; + whMessageCrypto_CmacDmaRequest* req = NULL; + whMessageCrypto_CmacDmaResponse* res = NULL; + uint8_t* dataPtr = NULL; + uintptr_t inAddr = 0; if (ctx == NULL || cmac == NULL) { return WH_ERROR_BADARGS; } + whKeyId key_id = WH_DEVCTX_TO_KEYID(cmac->devCtx); + uint32_t mac_len = + ((outMac == NULL) || (outMacLen == NULL)) ? 0 : *outMacLen; + + /* For non-HSM keys on subsequent calls (no key provided), send the + * stored key bytes so the server can reconstruct the CMAC context */ + if (key == NULL && keyLen == 0 && WH_KEYID_ISERASED(key_id) && + (inLen != 0 || mac_len != 0)) { + key = (const uint8_t*)cmac->aes.devKey; + keyLen = cmac->aes.keylen; + } + + /* Return success for a call with NULL params, or 0 len's */ + if ((inLen == 0) && (keyLen == 0) && (mac_len == 0)) { + /* Update the type */ + cmac->type = type; + return WH_ERROR_OK; + } + + WH_DEBUG_CLIENT_VERBOSE( + "cmac dma key:%p key_len:%d in:%p in_len:%d out:%p out_len:%d " + "keyId:%x\n", + key, (int)keyLen, in, (int)inLen, outMac, (int)mac_len, key_id); + /* Get data pointer from the context to use as request/response storage */ dataPtr = (uint8_t*)wh_CommClient_GetDataPtr(ctx->comm); if (dataPtr == NULL) { @@ -3745,37 +3766,37 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, req = (whMessageCrypto_CmacDmaRequest*)_createCryptoRequest( dataPtr, WC_ALGO_TYPE_CMAC); memset(req, 0, sizeof(*req)); - req->type = type; - /* Store devId and devCtx to restore after request */ - int devId = cmac->devId; - void* devCtx = cmac->devCtx; + uint8_t* req_key = (uint8_t*)(req + 1); + uint32_t hdr_sz = + sizeof(whMessageCrypto_GenericRequestHeader) + sizeof(*req); - /* Set up DMA state buffer in client address space */ - req->state.sz = sizeof(*cmac); - ret = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)cmac, (void**)&stateAddr, req->state.sz, - WH_DMA_OPER_CLIENT_WRITE_PRE, (whDmaFlags){0}); - if (ret == WH_ERROR_OK) { - req->state.addr = stateAddr; + if (keyLen > WOLFHSM_CFG_COMM_DATA_LEN - hdr_sz) { + return WH_ERROR_BADARGS; } + uint16_t req_len = hdr_sz + keyLen; - /* Handle different CMAC operations based on input parameters */ - if (ret == WH_ERROR_OK && key != NULL) { - /* Initialize with provided key */ - req->key.sz = keyLen; - ret = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key, (void**)&keyAddr, req->key.sz, - WH_DMA_OPER_CLIENT_READ_PRE, (whDmaFlags){0}); - if (ret == WH_ERROR_OK) { - req->key.addr = keyAddr; - } + /* Setup request fields */ + req->type = type; + req->outSz = mac_len; + req->keyId = key_id; + req->keySz = keyLen; + + /* Pack non-sensitive CMAC state into request */ + memcpy(req->resumeState.buffer, cmac->buffer, AES_BLOCK_SIZE); + memcpy(req->resumeState.digest, cmac->digest, AES_BLOCK_SIZE); + req->resumeState.bufferSz = cmac->bufferSz; + req->resumeState.totalSz = cmac->totalSz; + + /* Copy key bytes into trailing data */ + if ((key != NULL) && (keyLen > 0)) { + memcpy(req_key, key, keyLen); } - if (ret == WH_ERROR_OK && in != NULL) { - /* Update operation */ - req->input.sz = inLen; - ret = wh_Client_DmaProcessClientAddress( + /* DMA for input data only */ + if (ret == WH_ERROR_OK && in != NULL && inLen != 0) { + req->input.sz = inLen; + ret = wh_Client_DmaProcessClientAddress( ctx, (uintptr_t)in, (void**)&inAddr, req->input.sz, WH_DMA_OPER_CLIENT_READ_PRE, (whDmaFlags){0}); if (ret == WH_ERROR_OK) { @@ -3783,78 +3804,59 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, } } - if (ret == WH_ERROR_OK && outMac != NULL) { - /* Finalize operation */ - req->output.sz = (size_t)*outMacLen; - ret = wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)outMac, (void**)&outAddr, req->output.sz, - WH_DMA_OPER_CLIENT_WRITE_PRE, (whDmaFlags){0}); - if (ret == WH_ERROR_OK) { - req->output.addr = outAddr; - req->finalize = 1; - /* Also set local flag, as request will be trashed after a response - * is received */ - finalize = 1; - } - } - - /* If this is just a deferred initialization (NULL key, but keyId set), - * don't send a request - server will initialize on first update */ - if ((key == NULL) && (in == NULL) && (outMac == NULL)) { - /* Just a keyId set operation, nothing to do via DMA */ - return 0; - } - if (ret == WH_ERROR_OK) { /* Send the request */ - ret = wh_Client_SendRequest( - ctx, WH_MESSAGE_GROUP_CRYPTO_DMA, WC_ALGO_TYPE_CMAC, - sizeof(whMessageCrypto_GenericRequestHeader) + sizeof(*req), - (uint8_t*)dataPtr); + ret = wh_Client_SendRequest(ctx, WH_MESSAGE_GROUP_CRYPTO_DMA, + WC_ALGO_TYPE_CMAC, req_len, + (uint8_t*)dataPtr); } if (ret == WH_ERROR_OK) { + /* Update the local type since call succeeded */ + cmac->type = type; + + /* Store key bytes locally for future calls (non-HSM keys) */ + if (key != NULL && keyLen > 0 && WH_KEYID_ISERASED(key_id)) { + memcpy((void*)cmac->aes.devKey, key, keyLen); + cmac->aes.keylen = keyLen; + } + uint16_t respSz = 0; do { ret = wh_Client_RecvResponse(ctx, NULL, NULL, &respSz, (uint8_t*)dataPtr); } while (ret == WH_ERROR_NOTREADY); - } - if (ret == WH_ERROR_OK) { - /* Get response structure pointer, validates generic header - * rc */ - ret = _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); - if (ret == WH_ERROR_OK && finalize) { - /* Update outSz with actual size of CMAC output */ - *outMacLen = res->outSz; + if (ret == WH_ERROR_OK) { + ret = + _getCryptoResponse(dataPtr, WC_ALGO_TYPE_CMAC, (uint8_t**)&res); + /* wolfCrypt allows positive error codes on success */ + if (ret >= 0) { + /* Restore non-sensitive state from server response */ + memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); + memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); + cmac->bufferSz = res->resumeState.bufferSz; + cmac->totalSz = res->resumeState.totalSz; + + /* Copy out finalized CMAC if present */ + if (outMac != NULL && outMacLen != NULL) { + if (res->outSz < *outMacLen) { + *outMacLen = res->outSz; + } + uint8_t* res_mac = (uint8_t*)(res + 1); + memcpy(outMac, res_mac, *outMacLen); + } + } } } - /* Restore devId, devCtx, and type after DMA operation */ - cmac->devId = devId; - cmac->devCtx = devCtx; - cmac->type = type; - - /* post address translation callbacks (for cleanup) */ - if (key != NULL) { - (void)wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)key, (void**)&keyAddr, req->key.sz, - WH_DMA_OPER_CLIENT_READ_POST, (whDmaFlags){0}); - } - if (in != NULL) { + /* Post DMA cleanup for input address */ + if (in != NULL && inAddr != 0) { (void)wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)in, (void**)&inAddr, req->input.sz, + ctx, (uintptr_t)in, (void**)&inAddr, inLen, WH_DMA_OPER_CLIENT_READ_POST, (whDmaFlags){0}); } - if (outMac != NULL) { - (void)wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)outMac, (void**)&outAddr, req->output.sz, - WH_DMA_OPER_CLIENT_WRITE_POST, (whDmaFlags){0}); - } - (void)wh_Client_DmaProcessClientAddress( - ctx, (uintptr_t)cmac, (void**)&stateAddr, req->state.sz, - WH_DMA_OPER_CLIENT_WRITE_POST, (whDmaFlags){0}); + return ret; } #endif /* WOLFHSM_CFG_DMA */ diff --git a/src/wh_message_crypto.c b/src/wh_message_crypto.c index 514f2d0c4..54e1ddfbd 100644 --- a/src/wh_message_crypto.c +++ b/src/wh_message_crypto.c @@ -696,9 +696,9 @@ int wh_MessageCrypto_TranslateSha2Response( /* CMAC State translation */ -int wh_MessageCrypto_TranslateCmacState( - uint16_t magic, const whMessageCrypto_CmacState* src, - whMessageCrypto_CmacState* dest) +int wh_MessageCrypto_TranslateCmacState(uint16_t magic, + const whMessageCrypto_CmacState* src, + whMessageCrypto_CmacState* dest) { if ((src == NULL) || (dest == NULL)) { return WH_ERROR_BADARGS; @@ -724,8 +724,8 @@ int wh_MessageCrypto_TranslateCmacRequest( WH_T32(magic, dest, src, inSz); WH_T32(magic, dest, src, keySz); WH_T16(magic, dest, src, keyId); - return wh_MessageCrypto_TranslateCmacState( - magic, &src->resumeState, &dest->resumeState); + return wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, + &dest->resumeState); } /* CMAC Response translation */ @@ -738,8 +738,8 @@ int wh_MessageCrypto_TranslateCmacResponse( } WH_T32(magic, dest, src, outSz); WH_T16(magic, dest, src, keyId); - return wh_MessageCrypto_TranslateCmacState( - magic, &src->resumeState, &dest->resumeState); + return wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, + &dest->resumeState); } /* ML-DSA Key Generation Request translation */ @@ -835,9 +835,10 @@ int wh_MessageCrypto_TranslateMlDsaVerifyResponse( */ /* DMA Buffer translation */ -static int wh_MessageCrypto_TranslateDmaBuffer(uint16_t magic, - const whMessageCrypto_DmaBuffer* src, - whMessageCrypto_DmaBuffer* dest) +static int +wh_MessageCrypto_TranslateDmaBuffer(uint16_t magic, + const whMessageCrypto_DmaBuffer* src, + whMessageCrypto_DmaBuffer* dest) { if ((src == NULL) || (dest == NULL)) { return WH_ERROR_BADARGS; @@ -914,31 +915,19 @@ int wh_MessageCrypto_TranslateCmacDmaRequest( return WH_ERROR_BADARGS; } - WH_T32(magic, dest, src, type); - WH_T32(magic, dest, src, finalize); - - ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->state, &dest->state); - if (ret != 0) { - return ret; - } - - ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->key, &dest->key); - if (ret != 0) { - return ret; - } - ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->input, &dest->input); if (ret != 0) { return ret; } - ret = - wh_MessageCrypto_TranslateDmaBuffer(magic, &src->output, &dest->output); - if (ret != 0) { - return ret; - } + WH_T32(magic, dest, src, type); + WH_T32(magic, dest, src, outSz); + WH_T32(magic, dest, src, keySz); + WH_T16(magic, dest, src, keyId); - return 0; + ret = wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, + &dest->resumeState); + return ret; } /* CMAC DMA Response translation */ @@ -959,7 +948,11 @@ int wh_MessageCrypto_TranslateCmacDmaResponse( } WH_T32(magic, dest, src, outSz); - return 0; + WH_T16(magic, dest, src, keyId); + + ret = wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, + &dest->resumeState); + return ret; } /* ML-DSA DMA Key Generation Request translation */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index dccefc063..40a2fef6a 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -2976,6 +2976,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, int ret; whMessageCrypto_CmacRequest req; whMessageCrypto_CmacResponse res; + (void)seq; /* Validate minimum size */ if (inSize < sizeof(whMessageCrypto_CmacRequest)) { @@ -2997,8 +2998,11 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, if (req.keySz > available) { return WH_ERROR_BADARGS; } + if (req.keySz > AES_MAX_KEY_SIZE) { + return WH_ERROR_BADARGS; + } - word32 len; + word32 len; /* Setup fixed size fields */ uint8_t* in = @@ -3014,68 +3018,79 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, case WC_CMAC_AES: { uint8_t tmpKey[AES_MAX_KEY_SIZE]; word32 tmpKeyLen = 0; - - /* attempt oneshot if all fields are present */ - if (req.inSz != 0 && req.keySz != 0 && req.outSz != 0) { - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); - - ret = wc_AesCmacGenerate_ex(ctx->crypto->algoCtx.cmac, out, - &len, in, req.inSz, key, req.keySz, - NULL, ctx->crypto->devId); - res.outSz = len; + Cmac cmac[1]; + + /* Determine the key to use - shared across oneshot and + * multi-step paths */ + if (req.keySz != 0) { + /* Client provided the key directly in the request */ + memcpy(tmpKey, key, req.keySz); + tmpKeyLen = req.keySz; } - else { - WH_DEBUG_SERVER_VERBOSE( - "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", - req.keySz, req.inSz, req.outSz, req.keyId); - - /* Determine the key to use for initialization */ - if (req.keySz != 0) { - /* Client provided the key directly in the request */ - memcpy(tmpKey, key, req.keySz); - tmpKeyLen = req.keySz; - } - else if (!WH_KEYID_ISERASED(req.keyId)) { - /* Load key from keystore by ID */ - whKeyId keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - - /* Validate key usage policy - CMAC accepts sign or verify - */ + else if (!WH_KEYID_ISERASED(req.keyId)) { + /* Load key from keystore by ID */ + whKeyId keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + + /* Validate key usage policy - CMAC accepts sign or verify */ + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - /* Sign not allowed, try verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } - if (ret != WH_ERROR_OK) { - return ret; - } + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); + } + if (ret == WH_ERROR_OK) { tmpKeyLen = sizeof(tmpKey); ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, &tmpKeyLen); - if (ret != WH_ERROR_OK) { - return ret; - } } - else { - /* No key provided - error */ - return BAD_FUNC_ARG; + + if (ret == WH_ERROR_OK) { + /* Validate AES key size */ + if (tmpKeyLen != AES_128_KEY_SIZE && + tmpKeyLen != AES_192_KEY_SIZE && + tmpKeyLen != AES_256_KEY_SIZE) { + ret = WH_ERROR_ABORTED; + } } + } + else { + /* No key provided - error */ + ret = BAD_FUNC_ARG; + } + + /* Oneshot: input and output are both present */ + if (ret == 0 && req.inSz != 0 && req.outSz != 0) { + len = req.outSz; + + WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); + + ret = + wc_AesCmacGenerate_ex(cmac, out, &len, in, req.inSz, tmpKey, + tmpKeyLen, NULL, ctx->crypto->devId); - /* Initialize CMAC context with key (re-derives k1/k2 subkeys) - */ if (ret == 0) { + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + } + else if (ret == 0) { + /* Multi-step: init/update/final */ + WH_DEBUG_SERVER_VERBOSE( + "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", + req.keySz, req.inSz, req.outSz, req.keyId); - ret = wc_InitCmac_ex(ctx->crypto->algoCtx.cmac, tmpKey, - tmpKeyLen, req.type, NULL, NULL, - ctx->crypto->devId); - WH_DEBUG_SERVER_VERBOSE( - "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, - req.type, ret); + /* Initialize CMAC context with key (re-derives k1/k2 + * subkeys) */ + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, NULL, + NULL, ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE( + "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, + req.type, ret); + + if (ret == 0 && req.resumeState.bufferSz > AES_BLOCK_SIZE) { + ret = BAD_FUNC_ARG; } /* Restore non-sensitive state from client. On the first call @@ -3084,21 +3099,17 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, * subsequent calls (update/final), this restores the running * intermediate state. */ if (ret == 0) { - memcpy(ctx->crypto->algoCtx.cmac->buffer, - req.resumeState.buffer, AES_BLOCK_SIZE); - memcpy(ctx->crypto->algoCtx.cmac->digest, - req.resumeState.digest, AES_BLOCK_SIZE); - ctx->crypto->algoCtx.cmac->bufferSz = - req.resumeState.bufferSz; - ctx->crypto->algoCtx.cmac->totalSz = - req.resumeState.totalSz; + memcpy(cmac->buffer, req.resumeState.buffer, + AES_BLOCK_SIZE); + memcpy(cmac->digest, req.resumeState.digest, + AES_BLOCK_SIZE); + cmac->bufferSz = req.resumeState.bufferSz; + cmac->totalSz = req.resumeState.totalSz; } /* Handle CMAC update */ if (ret == 0 && req.inSz != 0) { - (void)seq; - ret = - wc_CmacUpdate(ctx->crypto->algoCtx.cmac, in, req.inSz); + ret = wc_CmacUpdate(cmac, in, req.inSz); WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); } @@ -3106,22 +3117,20 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Finalize CMAC operation */ len = req.outSz; WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); - ret = wc_CmacFinal(ctx->crypto->algoCtx.cmac, out, &len); + ret = wc_CmacFinal(cmac, out, &len); res.outSz = len; res.keyId = WH_KEYID_ERASED; } else if (ret == 0) { /* Not finalizing - return updated state to client */ - memcpy(res.resumeState.buffer, - ctx->crypto->algoCtx.cmac->buffer, AES_BLOCK_SIZE); - memcpy(res.resumeState.digest, - ctx->crypto->algoCtx.cmac->digest, AES_BLOCK_SIZE); - res.resumeState.bufferSz = - ctx->crypto->algoCtx.cmac->bufferSz; - res.resumeState.totalSz = - ctx->crypto->algoCtx.cmac->totalSz; - res.keyId = req.keyId; - res.outSz = 0; + memcpy(res.resumeState.buffer, cmac->buffer, + AES_BLOCK_SIZE); + memcpy(res.resumeState.digest, cmac->digest, + AES_BLOCK_SIZE); + res.resumeState.bufferSz = cmac->bufferSz; + res.resumeState.totalSz = cmac->totalSz; + res.keyId = req.keyId; + res.outSz = 0; } } } break; @@ -3131,8 +3140,8 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, ret = CRYPTOCB_UNAVAILABLE; } if (ret == 0) { - ret = wh_MessageCrypto_TranslateCmacResponse(magic, &res, - cryptoDataOut); + ret = + wh_MessageCrypto_TranslateCmacResponse(magic, &res, cryptoDataOut); if (ret == 0) { *outSize = sizeof(res) + res.outSz; } @@ -5091,278 +5100,215 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, return ret; } - Cmac* cmac = ctx->crypto->algoCtx.cmac; - int clientDevId = 0; - whKeyId keyId; - byte tmpKey[AES_256_KEY_SIZE]; - uint32_t keyLen; - /* Flag indicating if the CMAC context holds a local key that should not be - * returned to the client */ - int ctxHoldsLocalKey = 0; - /* Flag indicating if the CMAC operation has been finalized */ - int cmacFinalized = 0; - - /* DMA translated addresses */ - void* inAddr = NULL; - void* outAddr = NULL; - void* keyAddr = NULL; - word32 outSz = 0; - - /* Ensure state sizes are the same */ - if (req.state.sz != sizeof(*cmac)) { - res.dmaAddrStatus.badAddr = req.state; - ret = WH_ERROR_BADARGS; + /* Validate variable-length fields fit within inSize */ + uint32_t available = inSize - sizeof(whMessageCrypto_CmacDmaRequest); + if (req.keySz > available) { + return WH_ERROR_BADARGS; } - - if (ret == WH_ERROR_OK) { - /* Copy the CMAC context from client address space */ - ret = whServerDma_CopyFromClient(ctx, cmac, req.state.addr, - req.state.sz, (whServerDmaFlags){0}); - if (ret != WH_ERROR_OK) { - res.dmaAddrStatus.badAddr = req.state; - } + if (req.keySz > AES_MAX_KEY_SIZE) { + return WH_ERROR_BADARGS; } - if (ret == WH_ERROR_OK) { - /* Save the client devId to be restored later */ - clientDevId = cmac->devId; - /* overwrite the devId to that of the server for local crypto */ - cmac->devId = ctx->crypto->devId; - - /* Print out the state of req */ - WH_DEBUG_SERVER_VERBOSE("DMA CMAC req recv. type:%u keySz:%u inSz:%u outSz:%u " - "finalize:%u\n", - (unsigned int)req.type, (unsigned int)req.key.sz, - (unsigned int)req.input.sz, (unsigned int)req.output.sz, - (unsigned int)req.finalize); - - /* Translate all DMA addresses upfront */ - if (req.input.sz != 0) { - ret = wh_Server_DmaProcessClientAddress( - ctx, req.input.addr, &inAddr, req.input.sz, - WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); - if (ret == WH_ERROR_ACCESS) { - res.dmaAddrStatus.badAddr = req.input; - } - } + word32 len; - if (ret == WH_ERROR_OK && req.output.sz != 0) { - ret = wh_Server_DmaProcessClientAddress( - ctx, req.output.addr, &outAddr, req.output.sz, - WH_DMA_OPER_CLIENT_WRITE_PRE, (whServerDmaFlags){0}); - if (ret == WH_ERROR_ACCESS) { - res.dmaAddrStatus.badAddr = req.output; - } - } + /* Pointers to inline trailing data */ + uint8_t* key = + (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_CmacDmaRequest); + uint8_t* out = + (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacDmaResponse); - if (ret == WH_ERROR_OK && req.key.sz != 0) { - ret = wh_Server_DmaProcessClientAddress( - ctx, req.key.addr, &keyAddr, req.key.sz, - WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); - if (ret == WH_ERROR_ACCESS) { - res.dmaAddrStatus.badAddr = req.key; - } - } + memset(&res, 0, sizeof(res)); - if (ret == WH_ERROR_OK) { - /* Check for one-shot operation (both input and output are - * non-NULL). There are three distinct cases we need to handle for - * one-shots: - * 1. Direct one-shot operation with key provided in request - * 2. One-shot operation with key referenced by context that needs - * to be loaded from cache - * 3. One-shot operation with context already initialized with a key - */ - if (req.input.sz != 0 && req.output.sz != 0) { - WH_DEBUG_SERVER_VERBOSE("CMAC one-shot operation detected\n"); - - /* Case 1: Direct one-shot operation with key provided in - * request This is the simplest case - we have the key directly - * and can use it immediately for the CMAC operation */ - if (req.key.sz != 0) { - outSz = req.output.sz; - /* Perform one-shot CMAC operation with provided key */ - ret = wc_AesCmacGenerate_ex( - cmac, outAddr, &outSz, inAddr, req.input.sz, keyAddr, - req.key.sz, NULL, ctx->crypto->devId); - cmacFinalized = 1; - res.outSz = outSz; + /* DMA translated address for input */ + void* inAddr = NULL; + + switch (req.type) { +#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) + case WC_CMAC_AES: { + uint8_t tmpKey[AES_MAX_KEY_SIZE]; + word32 tmpKeyLen = 0; + Cmac cmac[1]; + + /* Attempt oneshot if input and output are both present */ + if (req.input.sz != 0 && req.outSz != 0) { + len = req.outSz; + + /* Translate DMA address for input */ + ret = wh_Server_DmaProcessClientAddress( + ctx, req.input.addr, &inAddr, req.input.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.input; } - /* Case 2 & 3: One-shot operation with key referenced by context - * We need to check if the context is already initialized or - * needs to be initialized with a key from cache */ - else { - /* Check if there's a keyID in the context that we need to - * load - */ - whKeyId clientKeyId = WH_DEVCTX_TO_KEYID(cmac->devCtx); - if (clientKeyId != WH_KEYID_ERASED) { - /* Case 2: Client-supplied context references a key ID - * that needs to be loaded from cache This happens when - * the client invokes the one-shot generate on a context - * that has been initialized to use a keyId by - * reference. We need to load the key from cache and - * initialize a new context with it */ - keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, - clientKeyId); - - /* Validate key usage policy - CMAC accepts sign or - * verify */ - if (!WH_KEYID_ISERASED(keyId)) { - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - /* Sign not allowed, try verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } - if (ret != WH_ERROR_OK) { - return ret; - } - } - keyLen = sizeof(tmpKey); - - /* Load key from cache */ - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, - tmpKey, &keyLen); - if (ret == WH_ERROR_OK) { - /* Verify key size is valid for AES */ - if (keyLen != AES_128_KEY_SIZE && - keyLen != AES_192_KEY_SIZE && - keyLen != AES_256_KEY_SIZE) { - ret = WH_ERROR_ABORTED; - } - else { - /* Initialize CMAC with loaded key */ - ctxHoldsLocalKey = 1; - ret = wc_InitCmac_ex(cmac, tmpKey, keyLen, - WC_CMAC_AES, NULL, NULL, - ctx->crypto->devId); - if (ret == WH_ERROR_OK) { - /* Perform one-shot CMAC operation */ - outSz = req.output.sz; - ret = wc_AesCmacGenerate_ex( - cmac, outAddr, &outSz, inAddr, - req.input.sz, NULL, 0, NULL, - ctx->crypto->devId); - res.outSz = outSz; - cmacFinalized = 1; - } - } + if (ret == WH_ERROR_OK && req.keySz != 0) { + /* Client-supplied key - direct one-shot */ + WH_DEBUG_SERVER_VERBOSE("dma cmac generate oneshot\n"); + + ret = wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, + req.input.sz, key, req.keySz, + NULL, ctx->crypto->devId); + } + else if (ret == WH_ERROR_OK && !WH_KEYID_ISERASED(req.keyId)) { + /* HSM-local key via keyId */ + whKeyId keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + + WH_DEBUG_SERVER_VERBOSE( + "dma cmac generate oneshot with keyId:%x\n", keyId); + + /* Enforce usage policy (sign or verify) */ + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); + } + + if (ret == WH_ERROR_OK) { + tmpKeyLen = sizeof(tmpKey); + ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, + tmpKey, &tmpKeyLen); + } + + if (ret == WH_ERROR_OK) { + /* Validate AES key size */ + if (tmpKeyLen != AES_128_KEY_SIZE && + tmpKeyLen != AES_192_KEY_SIZE && + tmpKeyLen != AES_256_KEY_SIZE) { + ret = WH_ERROR_ABORTED; } } - else { - /* Case 3: Context is already initialized with a key - * This happens when invoking the one-shot generate on a - * context that has been initialized with a previous - * wc_InitCmac_ex call where the key was already loaded - * into the context. We can use the context directly - * without needing to load or initialize anything */ - outSz = req.output.sz; - ret = wc_AesCmacGenerate_ex( - cmac, outAddr, &outSz, inAddr, req.input.sz, NULL, - 0, NULL, ctx->crypto->devId); - res.outSz = outSz; - cmacFinalized = 1; + + if (ret == WH_ERROR_OK) { + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, + NULL, NULL, ctx->crypto->devId); } + + if (ret == WH_ERROR_OK) { + ret = wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, + req.input.sz, NULL, 0, NULL, + ctx->crypto->devId); + } + } + else if (ret == WH_ERROR_OK) { + /* No key available */ + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + res.outSz = len; + res.keyId = WH_KEYID_ERASED; } } - /* Otherwise, process the request as an incremental operation */ else { - /* Incremental: Initialize CMAC with key if provided */ - if (req.key.sz != 0) { - ret = wc_InitCmac_ex(cmac, keyAddr, req.key.sz, req.type, - NULL, NULL, ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE( + "dma cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", + (int)req.keySz, (int)req.input.sz, (int)req.outSz, + req.keyId); + + /* Determine the key to use for initialization */ + if (req.keySz != 0) { + /* Client provided the key directly in the request */ + memcpy(tmpKey, key, req.keySz); + tmpKeyLen = req.keySz; } - /* Check for deferred initialization with cached key */ - else if (req.input.sz != 0 || req.finalize) { - /* Check if there's a key ID in the context that needs to be - * loaded - */ - whNvmId nvmId = WH_DEVCTX_TO_KEYID(cmac->devCtx); - if (nvmId != WH_KEYID_ERASED) { - /* Get key ID from CMAC context */ - keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, nvmId); - - /* Validate key usage policy - CMAC accepts sign or - * verify */ - if (!WH_KEYID_ISERASED(keyId)) { - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - /* Sign not allowed, try verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } - if (ret != WH_ERROR_OK) { - return ret; - } - } + else if (!WH_KEYID_ISERASED(req.keyId)) { + /* Load key from keystore by ID */ + whKeyId keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - keyLen = sizeof(tmpKey); - - /* Load key from cache */ - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, - tmpKey, &keyLen); - if (ret == WH_ERROR_OK) { - /* Verify key size is valid for AES */ - if (keyLen != AES_128_KEY_SIZE && - keyLen != AES_192_KEY_SIZE && - keyLen != AES_256_KEY_SIZE) { - ret = WH_ERROR_ABORTED; - } - else { - ctxHoldsLocalKey = 1; - - /* Save CMAC state so we can resume operation - * after initialization with key, as reinit will - * clear the state */ - byte savedBuffer[AES_BLOCK_SIZE]; - byte savedDigest[AES_BLOCK_SIZE]; - word32 savedBufferSz = cmac->bufferSz; - word32 savedTotalSz = cmac->totalSz; - memcpy(savedBuffer, cmac->buffer, - AES_BLOCK_SIZE); - memcpy(savedDigest, cmac->digest, - AES_BLOCK_SIZE); - - ret = wc_InitCmac_ex(cmac, tmpKey, keyLen, - WC_CMAC_AES, NULL, NULL, - ctx->crypto->devId); - - /* Restore CMAC state */ - memcpy(cmac->buffer, savedBuffer, - AES_BLOCK_SIZE); - memcpy(cmac->digest, savedDigest, - AES_BLOCK_SIZE); - cmac->bufferSz = savedBufferSz; - cmac->totalSz = savedTotalSz; - cmac->devCtx = (void*)(uintptr_t)nvmId; - } - } + /* Validate key usage policy */ + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); } + if (ret != WH_ERROR_OK) { + break; + } + + tmpKeyLen = sizeof(tmpKey); + ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, + &tmpKeyLen); + if (ret != WH_ERROR_OK) { + break; + } + } + else { + /* No key provided - error */ + ret = BAD_FUNC_ARG; + break; } - /* Process update if requested */ - if (ret == WH_ERROR_OK && req.input.sz != 0) { - ret = wc_CmacUpdate(cmac, inAddr, req.input.sz); + /* Initialize CMAC context with key (re-derives k1/k2 subkeys) + */ + if (ret == 0) { + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, + NULL, NULL, ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE( + "dma cmac init with keylen:%d, type:%d ret:%d\n", + tmpKeyLen, req.type, ret); } - /* Process finalize if requested */ - if (ret == WH_ERROR_OK && req.finalize) { - word32 len = (word32)req.output.sz; - ret = wc_CmacFinal(cmac, outAddr, &len); - cmacFinalized = 1; - res.outSz = len; + /* Restore non-sensitive state from client */ + if (ret == 0 && req.resumeState.bufferSz > AES_BLOCK_SIZE) { + ret = BAD_FUNC_ARG; + } + + if (ret == 0) { + memcpy(cmac->buffer, req.resumeState.buffer, + AES_BLOCK_SIZE); + memcpy(cmac->digest, req.resumeState.digest, + AES_BLOCK_SIZE); + cmac->bufferSz = req.resumeState.bufferSz; + cmac->totalSz = req.resumeState.totalSz; + } + + /* Handle CMAC update with DMA input */ + if (ret == 0 && req.input.sz != 0) { + ret = wh_Server_DmaProcessClientAddress( + ctx, req.input.addr, &inAddr, req.input.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.input; + } + if (ret == WH_ERROR_OK) { + ret = wc_CmacUpdate(cmac, inAddr, req.input.sz); + WH_DEBUG_SERVER_VERBOSE( + "dma cmac update done. ret:%d\n", ret); + } + } + + if (ret == 0 && req.outSz != 0) { + /* Finalize CMAC operation */ + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("dma cmac final len:%d\n", len); + ret = wc_CmacFinal(cmac, out, &len); + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + else if (ret == 0) { + /* Not finalizing - return updated state to client */ + memcpy(res.resumeState.buffer, cmac->buffer, + AES_BLOCK_SIZE); + memcpy(res.resumeState.digest, cmac->digest, + AES_BLOCK_SIZE); + res.resumeState.bufferSz = cmac->bufferSz; + res.resumeState.totalSz = cmac->totalSz; + res.keyId = req.keyId; + res.outSz = 0; } } - } + } break; +#endif /* !NO_AES && WOLFSSL_AES_DIRECT */ + default: + /* Type not supported */ + ret = CRYPTOCB_UNAVAILABLE; } - /* Clean up all DMA addresses */ + /* Clean up DMA input address */ if (inAddr != NULL) { if (wh_Server_DmaProcessClientAddress( ctx, req.input.addr, &inAddr, req.input.sz, @@ -5372,48 +5318,15 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, } } - if (outAddr != NULL) { - if (wh_Server_DmaProcessClientAddress( - ctx, req.output.addr, &outAddr, req.output.sz, - WH_DMA_OPER_CLIENT_WRITE_POST, - (whServerDmaFlags){0}) != WH_ERROR_OK) { - WH_DEBUG_SERVER_VERBOSE("Error cleaning up output DMA address\n"); - } - } - - if (keyAddr != NULL) { - if (wh_Server_DmaProcessClientAddress( - ctx, req.key.addr, &keyAddr, req.key.sz, - WH_DMA_OPER_CLIENT_READ_POST, - (whServerDmaFlags){0}) != WH_ERROR_OK) { - WH_DEBUG_SERVER_VERBOSE("Error cleaning up key DMA address\n"); - } - } - - /* Reset the devId and type in the local context */ - cmac->devId = clientDevId; - - /* If we are using HSM-local keys, sanitize the key material from the CMAC - * state before returning it to the client */ - if (ctxHoldsLocalKey) { - wc_AesFree(&cmac->aes); - } - - /* Copy CMAC context back into client memory */ - if (ret == WH_ERROR_OK && !cmacFinalized) { - ret = whServerDma_CopyToClient(ctx, req.state.addr, cmac, - req.state.sz, (whServerDmaFlags){0}); - if (ret != WH_ERROR_OK) { - res.dmaAddrStatus.badAddr = req.state; + if (ret == 0) { + ret = wh_MessageCrypto_TranslateCmacDmaResponse( + magic, &res, (whMessageCrypto_CmacDmaResponse*)cryptoDataOut); + if (ret == 0) { + *outSize = sizeof(res) + res.outSz; } } - /* Translate response */ - (void)wh_MessageCrypto_TranslateCmacDmaResponse( - magic, &res, (whMessageCrypto_CmacDmaResponse*)cryptoDataOut); - *outSize = sizeof(res); - - /* return value populates rc in response message */ + WH_DEBUG_SERVER_VERBOSE("dma cmac end ret:%d\n", ret); return ret; } #endif /* WOLFSSL_CMAC */ diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 78ad830b5..52ebfd8c8 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -3573,140 +3573,260 @@ static int whTestCrypto_Aes(whClientContext* ctx, int devId, WC_RNG* rng) #endif /* !NO_AES */ #if defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) +/* Direct copy of wolfCrypt tests, but using cached keys local to HSM instead */ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) { - (void)ctx; (void)rng; - int ret; - /* test cmac */ + int ret = 0; Cmac cmac[1]; - uint8_t knownCmacKey[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, - 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; - uint8_t knownCmacMessage[] = { + uint8_t tag[AES_BLOCK_SIZE] = {0}; + word32 tagSz; + whKeyId keyId; + uint8_t labelIn[WH_NVM_LABEL_LEN] = "CMAC Key Label"; + word32 i; + + /* NIST SP 800-38B test vectors */ +#ifdef WOLFSSL_AES_128 + const byte k128[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}; +#endif +#ifdef WOLFSSL_AES_192 + const byte k192[] = {0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b}; +#endif +#ifdef WOLFSSL_AES_256 + const byte k256[] = {0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4}; +#endif + + const byte m[] = { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; - uint8_t knownCmacTag[AES_BLOCK_SIZE] = {0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, - 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, - 0x79, 0x36, 0x3c, 0xfe}; - uint8_t labelIn[WH_NVM_LABEL_LEN] = "CMAC Key Label"; +#define CMAC_MLEN_0 0 +#define CMAC_MLEN_128 (128 / 8) +#define CMAC_MLEN_319 (320 / 8 - 1) +#define CMAC_MLEN_320 (320 / 8) +#define CMAC_MLEN_512 (512 / 8) + + /* Expected tags */ +#ifdef WOLFSSL_AES_128 + const byte t128_0[] = {0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46}; + const byte t128_128[] = {0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c}; + const byte t128_319[] = {0x2c, 0x17, 0x84, 0x4c, 0x93, 0x1c, 0x07, 0x95, + 0x15, 0x92, 0x73, 0x0a, 0x34, 0xd0, 0xd9, 0xd2}; + const byte t128_320[] = {0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, + 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27}; + const byte t128_512[] = {0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe}; +#endif +#ifdef WOLFSSL_AES_192 + const byte t192_0[] = {0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, + 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67}; + const byte t192_128[] = {0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, + 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84}; + const byte t192_320[] = {0x8a, 0x1d, 0xe5, 0xbe, 0x2e, 0xb3, 0x1a, 0xad, + 0x08, 0x9a, 0x82, 0xe6, 0xee, 0x90, 0x8b, 0x0e}; + const byte t192_512[] = {0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, + 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11}; +#endif +#ifdef WOLFSSL_AES_256 + const byte t256_0[] = {0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83}; + const byte t256_128[] = {0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c}; + const byte t256_320[] = {0xaa, 0xf3, 0xd8, 0xf1, 0xde, 0x56, 0x40, 0xc2, + 0x32, 0xf5, 0xb1, 0x69, 0xb9, 0xc9, 0x11, 0xe6}; + const byte t256_512[] = {0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10}; +#endif + + typedef struct { + const byte* k; + word32 kSz; + const byte* m; + word32 mSz; + const byte* t; + word32 tSz; + word32 partial; + } CmacTestCase; + + const CmacTestCase testCases[] = { +#ifdef WOLFSSL_AES_128 + {k128, sizeof(k128), m, CMAC_MLEN_0, t128_0, AES_BLOCK_SIZE, 0}, + {k128, sizeof(k128), m, CMAC_MLEN_128, t128_128, AES_BLOCK_SIZE, 0}, + {k128, sizeof(k128), m, CMAC_MLEN_319, t128_319, AES_BLOCK_SIZE, 0}, + {k128, sizeof(k128), m, CMAC_MLEN_320, t128_320, AES_BLOCK_SIZE, 0}, + {k128, sizeof(k128), m, CMAC_MLEN_512, t128_512, AES_BLOCK_SIZE, 0}, + {k128, sizeof(k128), m, CMAC_MLEN_512, t128_512, AES_BLOCK_SIZE, 5}, +#endif +#ifdef WOLFSSL_AES_192 + {k192, sizeof(k192), m, CMAC_MLEN_0, t192_0, AES_BLOCK_SIZE, 0}, + {k192, sizeof(k192), m, CMAC_MLEN_128, t192_128, AES_BLOCK_SIZE, 0}, + {k192, sizeof(k192), m, CMAC_MLEN_320, t192_320, AES_BLOCK_SIZE, 0}, + {k192, sizeof(k192), m, CMAC_MLEN_512, t192_512, AES_BLOCK_SIZE, 0}, +#endif +#ifdef WOLFSSL_AES_256 + {k256, sizeof(k256), m, CMAC_MLEN_0, t256_0, AES_BLOCK_SIZE, 0}, + {k256, sizeof(k256), m, CMAC_MLEN_128, t256_128, AES_BLOCK_SIZE, 0}, + {k256, sizeof(k256), m, CMAC_MLEN_320, t256_320, AES_BLOCK_SIZE, 0}, + {k256, sizeof(k256), m, CMAC_MLEN_512, t256_512, AES_BLOCK_SIZE, 0}, +#endif + }; + const word32 numCases = sizeof(testCases) / sizeof(testCases[0]); - uint8_t macOut[AES_BLOCK_SIZE] = {0}; - word32 macLen; - whKeyId keyId; + for (i = 0; i < numCases && ret == 0; i++) { + const CmacTestCase* tc = &testCases[i]; - ret = wc_InitCmac_ex(cmac, knownCmacKey, sizeof(knownCmacKey), WC_CMAC_AES, - NULL, NULL, devId); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_InitCmac_ex %d\n", ret); - } - else { - ret = wc_CmacUpdate(cmac, knownCmacMessage, sizeof(knownCmacMessage)); + /* (a) One-shot generate with cached key */ + keyId = WH_KEYID_ERASED; + ret = wh_Client_KeyCache(ctx, WH_NVM_FLAGS_USAGE_SIGN, labelIn, + sizeof(labelIn), (uint8_t*)tc->k, tc->kSz, + &keyId); if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_CmacUpdate %d\n", ret); + WH_ERROR_PRINT("Failed to wh_Client_KeyCache (gen) tc=%d %d\n", i, + ret); + break; } - else { - macLen = sizeof(macOut); - ret = wc_CmacFinal(cmac, macOut, &macLen); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_CmacFinal %d\n", ret); - } - else { - if (memcmp(knownCmacTag, macOut, sizeof(knownCmacTag)) != 0) { - WH_ERROR_PRINT("CMAC FAILED KNOWN ANSWER TEST\n"); - ret = -1; - } - } + ret = wh_Client_CmacSetKeyId(cmac, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_CmacSetKeyId (gen) tc=%d %d\n", + i, ret); + break; + } + memset(tag, 0, sizeof(tag)); + tagSz = sizeof(tag); + ret = wc_AesCmacGenerate_ex(cmac, tag, &tagSz, tc->m, tc->mSz, NULL, 0, + NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_AesCmacGenerate_ex tc=%d %d\n", i, ret); + break; + } + if (memcmp(tag, tc->t, AES_BLOCK_SIZE) != 0) { + WH_ERROR_PRINT("CMAC generate mismatch tc=%d\n", i); + ret = -1; + break; + } + ret = wh_Client_KeyEvict(ctx, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_KeyEvict (gen) tc=%d %d\n", i, + ret); + break; } - wc_CmacFree(cmac); - memset(macOut, 0, sizeof(macOut)); - } - if (ret == 0) { - /* test oneshot verify */ - ret = wc_AesCmacVerify_ex(cmac, knownCmacTag, sizeof(knownCmacTag), - knownCmacMessage, sizeof(knownCmacMessage), - knownCmacKey, sizeof(knownCmacKey), NULL, - devId); + /* (b) One-shot verify with cached key */ + keyId = WH_KEYID_ERASED; + ret = wh_Client_KeyCache(ctx, WH_NVM_FLAGS_USAGE_VERIFY, labelIn, + sizeof(labelIn), (uint8_t*)tc->k, tc->kSz, + &keyId); if (ret != 0) { - WH_ERROR_PRINT("Failed to wc_AesCmacVerify_ex %d\n", ret); + WH_ERROR_PRINT("Failed to wh_Client_KeyCache (ver) tc=%d %d\n", i, + ret); + break; + } + ret = wh_Client_CmacSetKeyId(cmac, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_CmacSetKeyId (ver) tc=%d %d\n", + i, ret); + break; + } + ret = wc_AesCmacVerify_ex(cmac, tc->t, tc->tSz, tc->m, tc->mSz, NULL, 0, + NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_AesCmacVerify_ex tc=%d %d\n", i, ret); + break; + } + ret = wh_Client_KeyEvict(ctx, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_KeyEvict (ver) tc=%d %d\n", i, + ret); + break; } - } - if (ret == 0) { - /* test oneshot generate with pre-cached key */ + /* (c) Incremental init/update/final with cached key */ keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(ctx, WH_NVM_FLAGS_USAGE_SIGN, labelIn, - sizeof(labelIn), knownCmacKey, - sizeof(knownCmacKey), &keyId); + sizeof(labelIn), (uint8_t*)tc->k, tc->kSz, + &keyId); if (ret != 0) { - WH_ERROR_PRINT("Failed to wh_Client_KeyCache %d\n", ret); + WH_ERROR_PRINT("Failed to wh_Client_KeyCache (inc) tc=%d %d\n", i, + ret); + break; } - else { - ret = wh_Client_CmacSetKeyId(cmac, keyId); + ret = wc_InitCmac_ex(cmac, NULL, 0, WC_CMAC_AES, NULL, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_InitCmac_ex (inc) tc=%d %d\n", i, ret); + break; + } + ret = wh_Client_CmacSetKeyId(cmac, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_CmacSetKeyId (inc) tc=%d %d\n", + i, ret); + break; + } + if (tc->partial > 0) { + word32 firstSz = tc->mSz / 2 - tc->partial; + word32 secondSz = tc->mSz / 2 + tc->partial; + ret = wc_CmacUpdate(cmac, tc->m, firstSz); if (ret != 0) { - WH_ERROR_PRINT("Failed to wh_Client_CmacSetKeyId %d\n", ret); + WH_ERROR_PRINT("Failed wc_CmacUpdate (inc1) tc=%d %d\n", i, + ret); + break; } - else { - macLen = sizeof(macOut); - ret = wc_AesCmacGenerate_ex( - cmac, macOut, &macLen, knownCmacMessage, - sizeof(knownCmacMessage), NULL, 0, NULL, devId); - if (ret != 0) { - WH_ERROR_PRINT("Failed to wh_Client_AesCmacGenerate %d\n", - ret); - } - else { - if (memcmp(knownCmacTag, macOut, sizeof(knownCmacTag)) != - 0) { - WH_ERROR_PRINT("CMAC FAILED KNOWN ANSWER TEST\n"); - ret = -1; - } - else { -#ifdef WOLFHSM_CFG_DMA - /* DMA doesn't autoevict keys after use */ - /* TODO: should we instead match autoevict behavior for - * DMA - */ - if (devId == WH_DEV_ID_DMA) { - ret = wh_Client_KeyEvict(ctx, keyId); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wh_Client_KeyEvict %d\n", ret); - ret = -1; - } - } - else -#endif /* WOLFHSM_CFG_DMA */ - { - /* Key should still be present after oneshot since - * server no longer caches/evicts the Cmac struct */ - ret = wh_Client_KeyEvict(ctx, keyId); - if (ret != 0) { - WH_ERROR_PRINT( - "Failed to wh_Client_KeyEvict %d\n", ret); - ret = -1; - } - } - } - } + ret = wc_CmacUpdate(cmac, tc->m + firstSz, secondSz); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_CmacUpdate (inc2) tc=%d %d\n", i, + ret); + break; } } + else { + ret = wc_CmacUpdate(cmac, tc->m, tc->mSz); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_CmacUpdate (inc) tc=%d %d\n", i, ret); + break; + } + } + memset(tag, 0, sizeof(tag)); + tagSz = sizeof(tag); + ret = wc_CmacFinal(cmac, tag, &tagSz); + if (ret != 0) { + WH_ERROR_PRINT("Failed wc_CmacFinal (inc) tc=%d %d\n", i, ret); + break; + } + if (memcmp(tag, tc->t, AES_BLOCK_SIZE) != 0) { + WH_ERROR_PRINT("CMAC incremental mismatch tc=%d\n", i); + ret = -1; + break; + } + wc_CmacFree(cmac); + ret = wh_Client_KeyEvict(ctx, keyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to wh_Client_KeyEvict (inc) tc=%d %d\n", i, + ret); + break; + } } + /* Test oneshot verify with committed (NVM) key using AES-128 */ if (ret == 0) { - /* test oneshot verify with committed key */ +#ifdef WOLFSSL_AES_128 keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(ctx, WH_NVM_FLAGS_USAGE_VERIFY, labelIn, - sizeof(labelIn), knownCmacKey, - sizeof(knownCmacKey), &keyId); + sizeof(labelIn), (uint8_t*)k128, sizeof(k128), + &keyId); if (ret != 0) { - WH_ERROR_PRINT("Failed to wh_Client_KeyCache %d\n", ret); + WH_ERROR_PRINT("Failed to wh_Client_KeyCache (commit) %d\n", ret); } else { ret = wh_Client_KeyCommit(ctx, keyId); @@ -3719,9 +3839,8 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) WH_ERROR_PRINT("Failed to wh_Client_KeyEvict %d\n", ret); } else { - ret = - wc_InitCmac_ex(cmac, knownCmacKey, sizeof(knownCmacKey), - WC_CMAC_AES, NULL, NULL, devId); + ret = wc_InitCmac_ex(cmac, k128, sizeof(k128), WC_CMAC_AES, + NULL, NULL, devId); if (ret != 0) { WH_ERROR_PRINT("Failed to wc_InitCmac_ex %d\n", ret); } @@ -3732,18 +3851,16 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) "Failed to wh_Client_CmacSetKeyId %d\n", ret); } else { - macLen = sizeof(macOut); - ret = wc_AesCmacVerify_ex( - cmac, knownCmacTag, sizeof(knownCmacTag), - (byte*)knownCmacMessage, - sizeof(knownCmacMessage), NULL, 0, NULL, devId); + tagSz = sizeof(tag); + ret = wc_AesCmacVerify_ex( + cmac, t128_512, sizeof(t128_512), m, + CMAC_MLEN_512, NULL, 0, NULL, devId); if (ret != 0) { WH_ERROR_PRINT( - "Failed to wh_Client_AesCmacVerify %d\n", + "Failed wc_AesCmacVerify_ex (commit) %d\n", ret); } else { - /* test finished, erase key */ ret = wh_Client_KeyErase(ctx, keyId); if (ret != 0) { WH_ERROR_PRINT( @@ -3756,8 +3873,15 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) } } } +#endif /* WOLFSSL_AES_128 */ } +#undef CMAC_MLEN_0 +#undef CMAC_MLEN_128 +#undef CMAC_MLEN_319 +#undef CMAC_MLEN_320 +#undef CMAC_MLEN_512 + if (ret == 0) { WH_TEST_PRINT("CMAC DEVID=0x%X SUCCESS\n", devId); } diff --git a/wolfhsm/wh_message_crypto.h b/wolfhsm/wh_message_crypto.h index a0572b438..c43fafacf 100644 --- a/wolfhsm/wh_message_crypto.h +++ b/wolfhsm/wh_message_crypto.h @@ -824,23 +824,18 @@ typedef struct { /* CMAC Response */ typedef struct { - uint32_t outSz; /* actual output MAC size */ - uint16_t keyId; /* key ID (ERASED for non-HSM) */ - uint8_t WH_PAD[2]; whMessageCrypto_CmacState resumeState; - uint8_t WH_PAD2[12]; /* pad to match request size */ + uint32_t outSz; /* actual output MAC size */ + uint16_t keyId; /* key ID (ERASED for non-HSM) */ + uint8_t WH_PAD[2]; /* Data follows: * uint8_t out[outSz] */ } whMessageCrypto_CmacResponse; -WH_UTILS_STATIC_ASSERT(sizeof(whMessageCrypto_CmacRequest) == - sizeof(whMessageCrypto_CmacResponse), - "CmacRequest and CmacResponse must be the same size"); - -int wh_MessageCrypto_TranslateCmacState( - uint16_t magic, const whMessageCrypto_CmacState* src, - whMessageCrypto_CmacState* dest); +int wh_MessageCrypto_TranslateCmacState(uint16_t magic, + const whMessageCrypto_CmacState* src, + whMessageCrypto_CmacState* dest); int wh_MessageCrypto_TranslateCmacRequest( uint16_t magic, const whMessageCrypto_CmacRequest* src, @@ -985,21 +980,27 @@ int wh_MessageCrypto_TranslateSha2DmaRequest( int wh_MessageCrypto_TranslateSha2DmaResponse( uint16_t magic, const whMessageCrypto_Sha2DmaResponse* src, whMessageCrypto_Sha2DmaResponse* dest); -/* CMAC DMA Request */ -typedef struct { - uint32_t type; /* enum wc_CmacType */ - uint32_t finalize; /* 1 if final, 0 if update */ - whMessageCrypto_DmaBuffer state; /* CMAC state buffer */ - whMessageCrypto_DmaBuffer key; /* Key buffer */ - whMessageCrypto_DmaBuffer input; /* Input buffer */ - whMessageCrypto_DmaBuffer output; /* Output buffer */ +/* CMAC DMA Request - only input data goes via DMA; state, key, and output + * are passed inline in the message for cross-architecture safety */ +typedef struct { + whMessageCrypto_CmacState resumeState; /* portable CMAC state */ + whMessageCrypto_DmaBuffer input; /* Input data via DMA */ + uint32_t type; /* enum wc_CmacType */ + uint32_t outSz; /* output MAC size (0 = not finalizing) */ + uint32_t keySz; /* inline key size (0 = use keyId) */ + uint16_t keyId; /* HSM key ID */ + uint8_t WH_PAD[2]; + /* Trailing data: uint8_t key[keySz] */ } whMessageCrypto_CmacDmaRequest; -/* CMAC DMA Response */ +/* CMAC DMA Response - state and output MAC returned inline */ typedef struct { + whMessageCrypto_CmacState resumeState; /* portable CMAC state */ whMessageCrypto_DmaAddrStatus dmaAddrStatus; - uint32_t outSz; - uint8_t WH_PAD[4]; /* Pad to 8-byte alignment */ + uint32_t outSz; /* actual output MAC size */ + uint16_t keyId; + uint8_t WH_PAD[2]; + /* Trailing data: uint8_t out[outSz] (max AES_BLOCK_SIZE = 16 bytes) */ } whMessageCrypto_CmacDmaResponse; /* CMAC DMA translation functions */ diff --git a/wolfhsm/wh_server.h b/wolfhsm/wh_server.h index f7b37da04..9361a8535 100644 --- a/wolfhsm/wh_server.h +++ b/wolfhsm/wh_server.h @@ -70,22 +70,6 @@ typedef struct whServerCryptoContext { #ifndef WC_NO_RNG WC_RNG rng[1]; #endif - union { -#if 0 -#ifndef NO_AES - Aes aes[1]; -#endif -#ifndef NO_RSA - RsaKey rsa[1]; -#endif -#ifdef HAVE_CURVE25519 - curve25519_key curve25519Private[1]; -#endif -#endif /* 0 */ -#ifdef WOLFSSL_CMAC - Cmac cmac[1]; -#endif - } algoCtx; } whServerCryptoContext; From 8d89392e7e09229adb3a40ddd10be3c56c5866e5 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 4 Feb 2026 15:43:57 -0700 Subject: [PATCH 4/4] =?UTF-8?q?Review=20feedback:=20-=20Reserve=20removed?= =?UTF-8?q?=20error=20codes=20(wh=5Ferror.h):=20WH=5FERROR=5FRESERVED{1,2}?= =?UTF-8?q?=20-=20Reserve=20removed=20message=20group=20(wh=5Fmessage.h):?= =?UTF-8?q?=20WH=5FMESSAGE=5FGROUP=5FRESERVED=20-=20Rename=20CMAC=20?= =?UTF-8?q?=E2=86=92=20CmacAes=20(wh=5Fmessage=5Fcrypto.h,=20all=20consume?= =?UTF-8?q?rs):=20All=20structs=20and=20translation=20functions=20renamed?= =?UTF-8?q?=20to=20indicate=20AES-specific=20-=20Remove=20`type`=20field?= =?UTF-8?q?=20from=20request=20structs=20and=20translation;=20use=20WC=5FC?= =?UTF-8?q?MAC=5FAES=20literal=20on=20server=20-=20Remove=20switch(req.typ?= =?UTF-8?q?e)=20in=20server=20handlers;=20guard=20with=20#if=20defined(WOL?= =?UTF-8?q?FSSL=5FCMAC)=20&&=20!defined(NO=5FAES)=20&&=20defined(WOLFSSL?= =?UTF-8?q?=5FAES=5FDIRECT)=20instead=20-=20Extract=20=5FCmacResolveKey()?= =?UTF-8?q?=20static=20helper=20for=20shared=20key=20resolution=20(inline?= =?UTF-8?q?=20key=20or=20keystore=20+=20usage=20policy=20+=20size=20valida?= =?UTF-8?q?tion)=20-=20Extract=20wh=5FCrypto=5FCmacAesSaveStateToMsg()=20/?= =?UTF-8?q?=20RestoreStateFromMsg()=20to=20deduplicate=20state=20pack/unpa?= =?UTF-8?q?ck=20across=20client=20+=20server=20+=20DMA=20-=20BAD=5FFUNC=5F?= =?UTF-8?q?ARG=20=E2=86=92=20WH=5FERROR=5FBADARGS=20for=20bufferSz=20valid?= =?UTF-8?q?ation=20(now=20inside=20RestoreStateFromMsg)=20-=20Don't=20read?= =?UTF-8?q?=20req.*=20after=20response=20may=20overlap=20=E2=80=94=20use?= =?UTF-8?q?=20WC=5FCMAC=5FAES=20literal=20instead=20of=20req.type=20-=20#d?= =?UTF-8?q?efine/#undef=20=E2=86=92=20enum=20for=20CMAC=5FMLEN=5F*=20test?= =?UTF-8?q?=20constants?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/wh_client_crypto.c | 60 ++-- src/wh_crypto.c | 27 ++ src/wh_message_crypto.c | 58 ++- src/wh_server_crypto.c | 526 ++++++++++++---------------- test/wh_test_check_struct_padding.c | 8 +- test/wh_test_crypto.c | 17 +- wolfhsm/wh_crypto.h | 13 + wolfhsm/wh_error.h | 2 + wolfhsm/wh_message.h | 1 + wolfhsm/wh_message_crypto.h | 80 +++-- 10 files changed, 358 insertions(+), 434 deletions(-) diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index e83a431b2..3672eac48 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -3587,12 +3587,12 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, const uint8_t* key, uint32_t keyLen, const uint8_t* in, uint32_t inLen, uint8_t* outMac, uint32_t* outMacLen) { - int ret = WH_ERROR_OK; - uint16_t group = WH_MESSAGE_GROUP_CRYPTO; - uint16_t action = WC_ALGO_TYPE_CMAC; - whMessageCrypto_CmacRequest* req = NULL; - whMessageCrypto_CmacResponse* res = NULL; - uint8_t* dataPtr = NULL; + int ret = WH_ERROR_OK; + uint16_t group = WH_MESSAGE_GROUP_CRYPTO; + uint16_t action = WC_ALGO_TYPE_CMAC; + whMessageCrypto_CmacAesRequest* req = NULL; + whMessageCrypto_CmacAesResponse* res = NULL; + uint8_t* dataPtr = NULL; if (ctx == NULL || cmac == NULL) { return WH_ERROR_BADARGS; @@ -3630,8 +3630,8 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, } /* Setup generic header and get pointer to request data */ - req = (whMessageCrypto_CmacRequest*)_createCryptoRequest(dataPtr, - WC_ALGO_TYPE_CMAC); + req = (whMessageCrypto_CmacAesRequest*)_createCryptoRequest( + dataPtr, WC_ALGO_TYPE_CMAC); uint8_t* req_in = (uint8_t*)(req + 1); uint8_t* req_key = req_in + inLen; @@ -3645,19 +3645,13 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, uint16_t req_len = hdr_sz + inLen + keyLen; /* Setup request packet */ - req->type = type; req->inSz = inLen; req->keyId = key_id; req->keySz = keyLen; req->outSz = mac_len; /* Pack non-sensitive CMAC state into request */ - memcpy(req->resumeState.buffer, cmac->buffer, - sizeof(req->resumeState.buffer)); - memcpy(req->resumeState.digest, cmac->digest, - sizeof(req->resumeState.digest)); - req->resumeState.bufferSz = cmac->bufferSz; - req->resumeState.totalSz = cmac->totalSz; + wh_Crypto_CmacAesSaveStateToMsg(&req->resumeState, cmac); /* copy input data to request, if relevant */ if ((in != NULL) && (inLen > 0)) { @@ -3693,15 +3687,11 @@ int wh_Client_Cmac(whClientContext* ctx, Cmac* cmac, CmacType type, * scenarios */ if (ret >= 0) { /* Restore non-sensitive state from server response */ - memcpy(cmac->buffer, res->resumeState.buffer, - sizeof(cmac->buffer)); - memcpy(cmac->digest, res->resumeState.digest, - sizeof(cmac->digest)); - cmac->bufferSz = res->resumeState.bufferSz; - cmac->totalSz = res->resumeState.totalSz; + ret = wh_Crypto_CmacAesRestoreStateFromMsg(cmac, + &res->resumeState); /* Copy out finalized CMAC if present */ - if (outMac != NULL && outMacLen != NULL) { + if (ret == 0 && outMac != NULL && outMacLen != NULL) { if (res->outSz < *outMacLen) { *outMacLen = res->outSz; } @@ -3722,11 +3712,11 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, const uint8_t* key, uint32_t keyLen, const uint8_t* in, uint32_t inLen, uint8_t* outMac, uint32_t* outMacLen) { - int ret = WH_ERROR_OK; - whMessageCrypto_CmacDmaRequest* req = NULL; - whMessageCrypto_CmacDmaResponse* res = NULL; - uint8_t* dataPtr = NULL; - uintptr_t inAddr = 0; + int ret = WH_ERROR_OK; + whMessageCrypto_CmacAesDmaRequest* req = NULL; + whMessageCrypto_CmacAesDmaResponse* res = NULL; + uint8_t* dataPtr = NULL; + uintptr_t inAddr = 0; if (ctx == NULL || cmac == NULL) { return WH_ERROR_BADARGS; @@ -3763,7 +3753,7 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, } /* Setup generic header and get pointer to request data */ - req = (whMessageCrypto_CmacDmaRequest*)_createCryptoRequest( + req = (whMessageCrypto_CmacAesDmaRequest*)_createCryptoRequest( dataPtr, WC_ALGO_TYPE_CMAC); memset(req, 0, sizeof(*req)); @@ -3777,16 +3767,12 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, uint16_t req_len = hdr_sz + keyLen; /* Setup request fields */ - req->type = type; req->outSz = mac_len; req->keyId = key_id; req->keySz = keyLen; /* Pack non-sensitive CMAC state into request */ - memcpy(req->resumeState.buffer, cmac->buffer, AES_BLOCK_SIZE); - memcpy(req->resumeState.digest, cmac->digest, AES_BLOCK_SIZE); - req->resumeState.bufferSz = cmac->bufferSz; - req->resumeState.totalSz = cmac->totalSz; + wh_Crypto_CmacAesSaveStateToMsg(&req->resumeState, cmac); /* Copy key bytes into trailing data */ if ((key != NULL) && (keyLen > 0)) { @@ -3833,13 +3819,11 @@ int wh_Client_CmacDma(whClientContext* ctx, Cmac* cmac, CmacType type, /* wolfCrypt allows positive error codes on success */ if (ret >= 0) { /* Restore non-sensitive state from server response */ - memcpy(cmac->buffer, res->resumeState.buffer, AES_BLOCK_SIZE); - memcpy(cmac->digest, res->resumeState.digest, AES_BLOCK_SIZE); - cmac->bufferSz = res->resumeState.bufferSz; - cmac->totalSz = res->resumeState.totalSz; + ret = wh_Crypto_CmacAesRestoreStateFromMsg(cmac, + &res->resumeState); /* Copy out finalized CMAC if present */ - if (outMac != NULL && outMacLen != NULL) { + if (ret == 0 && outMac != NULL && outMacLen != NULL) { if (res->outSz < *outMacLen) { *outMacLen = res->outSz; } diff --git a/src/wh_crypto.c b/src/wh_crypto.c index 878a6df2b..d43c73ff8 100644 --- a/src/wh_crypto.c +++ b/src/wh_crypto.c @@ -32,10 +32,13 @@ #include #include /* For NULL */ +#include + #include "wolfssl/wolfcrypt/settings.h" #include "wolfssl/wolfcrypt/types.h" #include "wolfssl/wolfcrypt/error-crypt.h" #include "wolfssl/wolfcrypt/asn.h" +#include "wolfssl/wolfcrypt/cmac.h" #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" @@ -376,4 +379,28 @@ int wh_Crypto_MlDsaDeserializeKeyDer(const uint8_t* buffer, uint16_t size, } #endif /* HAVE_DILITHIUM */ +#ifdef WOLFSSL_CMAC +void wh_Crypto_CmacAesSaveStateToMsg(whMessageCrypto_CmacAesState* state, + const Cmac* cmac) +{ + memcpy(state->buffer, cmac->buffer, AES_BLOCK_SIZE); + memcpy(state->digest, cmac->digest, AES_BLOCK_SIZE); + state->bufferSz = cmac->bufferSz; + state->totalSz = cmac->totalSz; +} + +int wh_Crypto_CmacAesRestoreStateFromMsg( + Cmac* cmac, const whMessageCrypto_CmacAesState* state) +{ + if (state->bufferSz > AES_BLOCK_SIZE) { + return WH_ERROR_BADARGS; + } + memcpy(cmac->buffer, state->buffer, AES_BLOCK_SIZE); + memcpy(cmac->digest, state->digest, AES_BLOCK_SIZE); + cmac->bufferSz = state->bufferSz; + cmac->totalSz = state->totalSz; + return 0; +} +#endif /* WOLFSSL_CMAC */ + #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/src/wh_message_crypto.c b/src/wh_message_crypto.c index 54e1ddfbd..085fd34de 100644 --- a/src/wh_message_crypto.c +++ b/src/wh_message_crypto.c @@ -695,10 +695,10 @@ int wh_MessageCrypto_TranslateSha2Response( } -/* CMAC State translation */ -int wh_MessageCrypto_TranslateCmacState(uint16_t magic, - const whMessageCrypto_CmacState* src, - whMessageCrypto_CmacState* dest) +/* CMAC-AES State translation */ +int wh_MessageCrypto_TranslateCmacAesState( + uint16_t magic, const whMessageCrypto_CmacAesState* src, + whMessageCrypto_CmacAesState* dest) { if ((src == NULL) || (dest == NULL)) { return WH_ERROR_BADARGS; @@ -711,35 +711,34 @@ int wh_MessageCrypto_TranslateCmacState(uint16_t magic, return 0; } -/* CMAC Request translation */ -int wh_MessageCrypto_TranslateCmacRequest( - uint16_t magic, const whMessageCrypto_CmacRequest* src, - whMessageCrypto_CmacRequest* dest) +/* CMAC-AES Request translation */ +int wh_MessageCrypto_TranslateCmacAesRequest( + uint16_t magic, const whMessageCrypto_CmacAesRequest* src, + whMessageCrypto_CmacAesRequest* dest) { if ((src == NULL) || (dest == NULL)) { return WH_ERROR_BADARGS; } - WH_T32(magic, dest, src, type); WH_T32(magic, dest, src, outSz); WH_T32(magic, dest, src, inSz); WH_T32(magic, dest, src, keySz); WH_T16(magic, dest, src, keyId); - return wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, - &dest->resumeState); + return wh_MessageCrypto_TranslateCmacAesState(magic, &src->resumeState, + &dest->resumeState); } -/* CMAC Response translation */ -int wh_MessageCrypto_TranslateCmacResponse( - uint16_t magic, const whMessageCrypto_CmacResponse* src, - whMessageCrypto_CmacResponse* dest) +/* CMAC-AES Response translation */ +int wh_MessageCrypto_TranslateCmacAesResponse( + uint16_t magic, const whMessageCrypto_CmacAesResponse* src, + whMessageCrypto_CmacAesResponse* dest) { if ((src == NULL) || (dest == NULL)) { return WH_ERROR_BADARGS; } WH_T32(magic, dest, src, outSz); WH_T16(magic, dest, src, keyId); - return wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, - &dest->resumeState); + return wh_MessageCrypto_TranslateCmacAesState(magic, &src->resumeState, + &dest->resumeState); } /* ML-DSA Key Generation Request translation */ @@ -904,10 +903,10 @@ int wh_MessageCrypto_TranslateSha2DmaResponse( &dest->dmaAddrStatus); } -/* CMAC DMA Request translation */ -int wh_MessageCrypto_TranslateCmacDmaRequest( - uint16_t magic, const whMessageCrypto_CmacDmaRequest* src, - whMessageCrypto_CmacDmaRequest* dest) +/* CMAC-AES DMA Request translation */ +int wh_MessageCrypto_TranslateCmacAesDmaRequest( + uint16_t magic, const whMessageCrypto_CmacAesDmaRequest* src, + whMessageCrypto_CmacAesDmaRequest* dest) { int ret; @@ -920,20 +919,19 @@ int wh_MessageCrypto_TranslateCmacDmaRequest( return ret; } - WH_T32(magic, dest, src, type); WH_T32(magic, dest, src, outSz); WH_T32(magic, dest, src, keySz); WH_T16(magic, dest, src, keyId); - ret = wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, - &dest->resumeState); + ret = wh_MessageCrypto_TranslateCmacAesState(magic, &src->resumeState, + &dest->resumeState); return ret; } -/* CMAC DMA Response translation */ -int wh_MessageCrypto_TranslateCmacDmaResponse( - uint16_t magic, const whMessageCrypto_CmacDmaResponse* src, - whMessageCrypto_CmacDmaResponse* dest) +/* CMAC-AES DMA Response translation */ +int wh_MessageCrypto_TranslateCmacAesDmaResponse( + uint16_t magic, const whMessageCrypto_CmacAesDmaResponse* src, + whMessageCrypto_CmacAesDmaResponse* dest) { int ret; @@ -950,8 +948,8 @@ int wh_MessageCrypto_TranslateCmacDmaResponse( WH_T32(magic, dest, src, outSz); WH_T16(magic, dest, src, keyId); - ret = wh_MessageCrypto_TranslateCmacState(magic, &src->resumeState, - &dest->resumeState); + ret = wh_MessageCrypto_TranslateCmacAesState(magic, &src->resumeState, + &dest->resumeState); return ret; } diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 40a2fef6a..282f0d0eb 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -2968,29 +2968,79 @@ static int _HandleAesGcmDma(whServerContext* ctx, uint16_t magic, uint16_t seq, #endif /* HAVE_AESGCM */ #endif /* !NO_AES */ -#ifdef WOLFSSL_CMAC +#if defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) + +/* Resolve CMAC key from request (inline key or keystore ID). + * outKey must be at least AES_MAX_KEY_SIZE bytes. */ +static int _CmacResolveKey(whServerContext* ctx, const uint8_t* requestKey, + uint32_t requestKeySz, whKeyId clientKeyId, + uint8_t* outKey, word32* outKeyLen) +{ + int ret = WH_ERROR_OK; + + if (requestKeySz != 0) { + /* Client provided the key directly in the request */ + memcpy(outKey, requestKey, requestKeySz); + *outKeyLen = requestKeySz; + } + else if (!WH_KEYID_ISERASED(clientKeyId)) { + /* Load key from keystore by ID */ + whKeyId keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, clientKeyId); + + /* Validate key usage policy - CMAC accepts sign or verify */ + ret = wh_Server_KeystoreFindEnforceKeyUsage(ctx, keyId, + WH_NVM_FLAGS_USAGE_SIGN); + if (ret == WH_ERROR_USAGE) { + ret = wh_Server_KeystoreFindEnforceKeyUsage( + ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); + } + + if (ret == WH_ERROR_OK) { + ret = + wh_Server_KeystoreReadKey(ctx, keyId, NULL, outKey, outKeyLen); + } + + if (ret == WH_ERROR_OK) { + /* Validate AES key size */ + if (*outKeyLen != AES_128_KEY_SIZE && + *outKeyLen != AES_192_KEY_SIZE && + *outKeyLen != AES_256_KEY_SIZE) { + ret = WH_ERROR_ABORTED; + } + } + } + else { + /* No key provided - error */ + ret = WH_ERROR_BADARGS; + } + + return ret; +} + static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, const void* cryptoDataIn, uint16_t inSize, void* cryptoDataOut, uint16_t* outSize) { - int ret; - whMessageCrypto_CmacRequest req; - whMessageCrypto_CmacResponse res; (void)seq; + int ret; + whMessageCrypto_CmacAesRequest req; + whMessageCrypto_CmacAesResponse res; + /* Validate minimum size */ - if (inSize < sizeof(whMessageCrypto_CmacRequest)) { + if (inSize < sizeof(whMessageCrypto_CmacAesRequest)) { return WH_ERROR_BADARGS; } /* Translate request */ - ret = wh_MessageCrypto_TranslateCmacRequest(magic, cryptoDataIn, &req); + ret = wh_MessageCrypto_TranslateCmacAesRequest(magic, cryptoDataIn, &req); if (ret != 0) { return ret; } /* Validate variable-length fields fit within inSize */ - uint32_t available = inSize - sizeof(whMessageCrypto_CmacRequest); + uint32_t available = inSize - sizeof(whMessageCrypto_CmacAesRequest); if (req.inSz > available) { return WH_ERROR_BADARGS; } @@ -3006,142 +3056,80 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Setup fixed size fields */ uint8_t* in = - (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_CmacRequest); + (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_CmacAesRequest); uint8_t* key = in + req.inSz; uint8_t* out = - (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacResponse); + (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacAesResponse); memset(&res, 0, sizeof(res)); - switch(req.type) { -#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) - case WC_CMAC_AES: { - uint8_t tmpKey[AES_MAX_KEY_SIZE]; - word32 tmpKeyLen = 0; - Cmac cmac[1]; - - /* Determine the key to use - shared across oneshot and - * multi-step paths */ - if (req.keySz != 0) { - /* Client provided the key directly in the request */ - memcpy(tmpKey, key, req.keySz); - tmpKeyLen = req.keySz; - } - else if (!WH_KEYID_ISERASED(req.keyId)) { - /* Load key from keystore by ID */ - whKeyId keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - - /* Validate key usage policy - CMAC accepts sign or verify */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } + uint8_t tmpKey[AES_MAX_KEY_SIZE]; + word32 tmpKeyLen = sizeof(tmpKey); + Cmac cmac[1]; - if (ret == WH_ERROR_OK) { - tmpKeyLen = sizeof(tmpKey); - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, - &tmpKeyLen); - } + /* Resolve the key to use */ + ret = _CmacResolveKey(ctx, key, req.keySz, req.keyId, tmpKey, &tmpKeyLen); - if (ret == WH_ERROR_OK) { - /* Validate AES key size */ - if (tmpKeyLen != AES_128_KEY_SIZE && - tmpKeyLen != AES_192_KEY_SIZE && - tmpKeyLen != AES_256_KEY_SIZE) { - ret = WH_ERROR_ABORTED; - } - } - } - else { - /* No key provided - error */ - ret = BAD_FUNC_ARG; - } + /* Oneshot: input and output are both present */ + if (ret == 0 && req.inSz != 0 && req.outSz != 0) { + len = req.outSz; - /* Oneshot: input and output are both present */ - if (ret == 0 && req.inSz != 0 && req.outSz != 0) { - len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); - WH_DEBUG_SERVER_VERBOSE("cmac generate oneshot\n"); + ret = wc_AesCmacGenerate_ex(cmac, out, &len, in, req.inSz, tmpKey, + tmpKeyLen, NULL, ctx->crypto->devId); - ret = - wc_AesCmacGenerate_ex(cmac, out, &len, in, req.inSz, tmpKey, - tmpKeyLen, NULL, ctx->crypto->devId); + if (ret == 0) { + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + } + else if (ret == 0) { + /* Multi-step: init/update/final */ + WH_DEBUG_SERVER_VERBOSE( + "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", req.keySz, + req.inSz, req.outSz, req.keyId); - if (ret == 0) { - res.outSz = len; - res.keyId = WH_KEYID_ERASED; - } - } - else if (ret == 0) { - /* Multi-step: init/update/final */ - WH_DEBUG_SERVER_VERBOSE( - "cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", - req.keySz, req.inSz, req.outSz, req.keyId); - - /* Initialize CMAC context with key (re-derives k1/k2 - * subkeys) */ - ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, NULL, - NULL, ctx->crypto->devId); - WH_DEBUG_SERVER_VERBOSE( - "cmac init with keylen:%d, type:%d ret:%d\n", tmpKeyLen, - req.type, ret); - - if (ret == 0 && req.resumeState.bufferSz > AES_BLOCK_SIZE) { - ret = BAD_FUNC_ARG; - } + /* Initialize CMAC context with key (re-derives k1/k2 subkeys) */ + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, WC_CMAC_AES, NULL, NULL, + ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE("cmac init with keylen:%d ret:%d\n", tmpKeyLen, + ret); - /* Restore non-sensitive state from client. On the first call - * (init), the client sends zeroed state which is effectively a - * no-op since wc_InitCmac_ex already zeroed the struct. On - * subsequent calls (update/final), this restores the running - * intermediate state. */ - if (ret == 0) { - memcpy(cmac->buffer, req.resumeState.buffer, - AES_BLOCK_SIZE); - memcpy(cmac->digest, req.resumeState.digest, - AES_BLOCK_SIZE); - cmac->bufferSz = req.resumeState.bufferSz; - cmac->totalSz = req.resumeState.totalSz; - } + /* Restore non-sensitive state from client. On the first call + * (init), the client sends zeroed state which is effectively a + * no-op since wc_InitCmac_ex already zeroed the struct. On + * subsequent calls (update/final), this restores the running + * intermediate state. */ + if (ret == 0) { + ret = wh_Crypto_CmacAesRestoreStateFromMsg(cmac, &req.resumeState); + } - /* Handle CMAC update */ - if (ret == 0 && req.inSz != 0) { - ret = wc_CmacUpdate(cmac, in, req.inSz); - WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); - } + /* Handle CMAC update */ + if (ret == 0 && req.inSz != 0) { + ret = wc_CmacUpdate(cmac, in, req.inSz); + WH_DEBUG_SERVER_VERBOSE("cmac update done. ret:%d\n", ret); + } - if (ret == 0 && req.outSz != 0) { - /* Finalize CMAC operation */ - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); - ret = wc_CmacFinal(cmac, out, &len); - res.outSz = len; - res.keyId = WH_KEYID_ERASED; - } - else if (ret == 0) { - /* Not finalizing - return updated state to client */ - memcpy(res.resumeState.buffer, cmac->buffer, - AES_BLOCK_SIZE); - memcpy(res.resumeState.digest, cmac->digest, - AES_BLOCK_SIZE); - res.resumeState.bufferSz = cmac->bufferSz; - res.resumeState.totalSz = cmac->totalSz; - res.keyId = req.keyId; - res.outSz = 0; - } - } - } break; -#endif /* !NO_AES && WOLFSSL_AES_DIRECT */ - default: - /* Type not supported */ - ret = CRYPTOCB_UNAVAILABLE; + if (ret == 0 && req.outSz != 0) { + /* Finalize CMAC operation */ + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("cmac final len:%d\n", len); + ret = wc_CmacFinal(cmac, out, &len); + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + else if (ret == 0) { + /* Not finalizing - return updated state to client */ + wh_Crypto_CmacAesSaveStateToMsg(&res.resumeState, cmac); + res.keyId = req.keyId; + res.outSz = 0; + } } + if (ret == 0) { - ret = - wh_MessageCrypto_TranslateCmacResponse(magic, &res, cryptoDataOut); + ret = wh_MessageCrypto_TranslateCmacAesResponse(magic, &res, + cryptoDataOut); if (ret == 0) { *outSize = sizeof(res) + res.outSz; } @@ -3149,7 +3137,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, WH_DEBUG_SERVER_VERBOSE("cmac end ret:%d\n", ret); return ret; } -#endif /* WOLFSSL_CMAC */ +#endif /* WOLFSSL_CMAC && !NO_AES && WOLFSSL_AES_DIRECT */ #ifndef NO_SHA256 static int _HandleSha256(whServerContext* ctx, uint16_t magic, @@ -4082,7 +4070,7 @@ int wh_Server_HandleCryptoRequest(whServerContext* ctx, uint16_t magic, break; #endif /* HAVE_HKDF || HAVE_CMAC_KDF */ -#ifdef WOLFSSL_CMAC +#if defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) case WC_ALGO_TYPE_CMAC: ret = _HandleCmac(ctx, magic, seq, cryptoDataIn, cryptoInSize, cryptoDataOut, &cryptoOutSize); @@ -5078,7 +5066,7 @@ static int _HandlePqcSigAlgorithmDma(whServerContext* ctx, uint16_t magic, } #endif /* HAVE_DILITHIUM || HAVE_FALCON */ -#ifdef WOLFSSL_CMAC +#if defined(WOLFSSL_CMAC) && !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, const void* cryptoDataIn, uint16_t inSize, void* cryptoDataOut, uint16_t* outSize) @@ -5086,22 +5074,22 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, (void)seq; int ret = 0; - whMessageCrypto_CmacDmaRequest req; - whMessageCrypto_CmacDmaResponse res; + whMessageCrypto_CmacAesDmaRequest req; + whMessageCrypto_CmacAesDmaResponse res; - if (inSize < sizeof(whMessageCrypto_CmacDmaRequest)) { + if (inSize < sizeof(whMessageCrypto_CmacAesDmaRequest)) { return WH_ERROR_BADARGS; } /* Translate request */ - ret = wh_MessageCrypto_TranslateCmacDmaRequest( - magic, (whMessageCrypto_CmacDmaRequest*)cryptoDataIn, &req); + ret = wh_MessageCrypto_TranslateCmacAesDmaRequest( + magic, (whMessageCrypto_CmacAesDmaRequest*)cryptoDataIn, &req); if (ret != WH_ERROR_OK) { return ret; } /* Validate variable-length fields fit within inSize */ - uint32_t available = inSize - sizeof(whMessageCrypto_CmacDmaRequest); + uint32_t available = inSize - sizeof(whMessageCrypto_CmacAesDmaRequest); if (req.keySz > available) { return WH_ERROR_BADARGS; } @@ -5113,199 +5101,115 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Pointers to inline trailing data */ uint8_t* key = - (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_CmacDmaRequest); + (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_CmacAesDmaRequest); uint8_t* out = - (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacDmaResponse); + (uint8_t*)(cryptoDataOut) + sizeof(whMessageCrypto_CmacAesDmaResponse); memset(&res, 0, sizeof(res)); /* DMA translated address for input */ void* inAddr = NULL; - switch (req.type) { -#if !defined(NO_AES) && defined(WOLFSSL_AES_DIRECT) - case WC_CMAC_AES: { - uint8_t tmpKey[AES_MAX_KEY_SIZE]; - word32 tmpKeyLen = 0; - Cmac cmac[1]; - - /* Attempt oneshot if input and output are both present */ - if (req.input.sz != 0 && req.outSz != 0) { - len = req.outSz; - - /* Translate DMA address for input */ - ret = wh_Server_DmaProcessClientAddress( - ctx, req.input.addr, &inAddr, req.input.sz, - WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); - if (ret == WH_ERROR_ACCESS) { - res.dmaAddrStatus.badAddr = req.input; - } - - if (ret == WH_ERROR_OK && req.keySz != 0) { - /* Client-supplied key - direct one-shot */ - WH_DEBUG_SERVER_VERBOSE("dma cmac generate oneshot\n"); - - ret = wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, - req.input.sz, key, req.keySz, - NULL, ctx->crypto->devId); - } - else if (ret == WH_ERROR_OK && !WH_KEYID_ISERASED(req.keyId)) { - /* HSM-local key via keyId */ - whKeyId keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + uint8_t tmpKey[AES_MAX_KEY_SIZE]; + word32 tmpKeyLen = sizeof(tmpKey); + Cmac cmac[1]; - WH_DEBUG_SERVER_VERBOSE( - "dma cmac generate oneshot with keyId:%x\n", keyId); + /* Attempt oneshot if input and output are both present */ + if (req.input.sz != 0 && req.outSz != 0) { + len = req.outSz; - /* Enforce usage policy (sign or verify) */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } + /* Translate DMA address for input */ + ret = wh_Server_DmaProcessClientAddress( + ctx, req.input.addr, &inAddr, req.input.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.input; + } - if (ret == WH_ERROR_OK) { - tmpKeyLen = sizeof(tmpKey); - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, - tmpKey, &tmpKeyLen); - } + /* Resolve key */ + if (ret == WH_ERROR_OK) { + ret = _CmacResolveKey(ctx, key, req.keySz, req.keyId, tmpKey, + &tmpKeyLen); + } - if (ret == WH_ERROR_OK) { - /* Validate AES key size */ - if (tmpKeyLen != AES_128_KEY_SIZE && - tmpKeyLen != AES_192_KEY_SIZE && - tmpKeyLen != AES_256_KEY_SIZE) { - ret = WH_ERROR_ABORTED; - } - } + if (ret == WH_ERROR_OK && req.keySz != 0) { + /* Client-supplied key - direct one-shot */ + WH_DEBUG_SERVER_VERBOSE("dma cmac generate oneshot\n"); - if (ret == WH_ERROR_OK) { - ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, - NULL, NULL, ctx->crypto->devId); - } + ret = wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, req.input.sz, + tmpKey, tmpKeyLen, NULL, + ctx->crypto->devId); + } + else if (ret == WH_ERROR_OK) { + /* HSM-local key via keyId - init then generate */ + WH_DEBUG_SERVER_VERBOSE("dma cmac generate oneshot with keyId:%x\n", + req.keyId); - if (ret == WH_ERROR_OK) { - ret = wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, - req.input.sz, NULL, 0, NULL, - ctx->crypto->devId); - } - } - else if (ret == WH_ERROR_OK) { - /* No key available */ - ret = BAD_FUNC_ARG; - } + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, WC_CMAC_AES, NULL, + NULL, ctx->crypto->devId); - if (ret == 0) { - res.outSz = len; - res.keyId = WH_KEYID_ERASED; - } + if (ret == WH_ERROR_OK) { + ret = + wc_AesCmacGenerate_ex(cmac, out, &len, inAddr, req.input.sz, + NULL, 0, NULL, ctx->crypto->devId); } - else { - WH_DEBUG_SERVER_VERBOSE( - "dma cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", - (int)req.keySz, (int)req.input.sz, (int)req.outSz, - req.keyId); - - /* Determine the key to use for initialization */ - if (req.keySz != 0) { - /* Client provided the key directly in the request */ - memcpy(tmpKey, key, req.keySz); - tmpKeyLen = req.keySz; - } - else if (!WH_KEYID_ISERASED(req.keyId)) { - /* Load key from keystore by ID */ - whKeyId keyId = wh_KeyId_TranslateFromClient( - WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); - - /* Validate key usage policy */ - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_SIGN); - if (ret == WH_ERROR_USAGE) { - ret = wh_Server_KeystoreFindEnforceKeyUsage( - ctx, keyId, WH_NVM_FLAGS_USAGE_VERIFY); - } - if (ret != WH_ERROR_OK) { - break; - } - - tmpKeyLen = sizeof(tmpKey); - ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, - &tmpKeyLen); - if (ret != WH_ERROR_OK) { - break; - } - } - else { - /* No key provided - error */ - ret = BAD_FUNC_ARG; - break; - } + } - /* Initialize CMAC context with key (re-derives k1/k2 subkeys) - */ - if (ret == 0) { - ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, req.type, - NULL, NULL, ctx->crypto->devId); - WH_DEBUG_SERVER_VERBOSE( - "dma cmac init with keylen:%d, type:%d ret:%d\n", - tmpKeyLen, req.type, ret); - } + if (ret == 0) { + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + } + else { + WH_DEBUG_SERVER_VERBOSE( + "dma cmac begin keySz:%d inSz:%d outSz:%d keyId:%x\n", + (int)req.keySz, (int)req.input.sz, (int)req.outSz, req.keyId); - /* Restore non-sensitive state from client */ - if (ret == 0 && req.resumeState.bufferSz > AES_BLOCK_SIZE) { - ret = BAD_FUNC_ARG; - } + /* Resolve key */ + ret = + _CmacResolveKey(ctx, key, req.keySz, req.keyId, tmpKey, &tmpKeyLen); - if (ret == 0) { - memcpy(cmac->buffer, req.resumeState.buffer, - AES_BLOCK_SIZE); - memcpy(cmac->digest, req.resumeState.digest, - AES_BLOCK_SIZE); - cmac->bufferSz = req.resumeState.bufferSz; - cmac->totalSz = req.resumeState.totalSz; - } + /* Initialize CMAC context with key (re-derives k1/k2 subkeys) */ + if (ret == 0) { + ret = wc_InitCmac_ex(cmac, tmpKey, tmpKeyLen, WC_CMAC_AES, NULL, + NULL, ctx->crypto->devId); + WH_DEBUG_SERVER_VERBOSE("dma cmac init with keylen:%d ret:%d\n", + tmpKeyLen, ret); + } - /* Handle CMAC update with DMA input */ - if (ret == 0 && req.input.sz != 0) { - ret = wh_Server_DmaProcessClientAddress( - ctx, req.input.addr, &inAddr, req.input.sz, - WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); - if (ret == WH_ERROR_ACCESS) { - res.dmaAddrStatus.badAddr = req.input; - } - if (ret == WH_ERROR_OK) { - ret = wc_CmacUpdate(cmac, inAddr, req.input.sz); - WH_DEBUG_SERVER_VERBOSE( - "dma cmac update done. ret:%d\n", ret); - } - } + /* Restore non-sensitive state from client */ + if (ret == 0) { + ret = wh_Crypto_CmacAesRestoreStateFromMsg(cmac, &req.resumeState); + } - if (ret == 0 && req.outSz != 0) { - /* Finalize CMAC operation */ - len = req.outSz; - WH_DEBUG_SERVER_VERBOSE("dma cmac final len:%d\n", len); - ret = wc_CmacFinal(cmac, out, &len); - res.outSz = len; - res.keyId = WH_KEYID_ERASED; - } - else if (ret == 0) { - /* Not finalizing - return updated state to client */ - memcpy(res.resumeState.buffer, cmac->buffer, - AES_BLOCK_SIZE); - memcpy(res.resumeState.digest, cmac->digest, - AES_BLOCK_SIZE); - res.resumeState.bufferSz = cmac->bufferSz; - res.resumeState.totalSz = cmac->totalSz; - res.keyId = req.keyId; - res.outSz = 0; - } + /* Handle CMAC update with DMA input */ + if (ret == 0 && req.input.sz != 0) { + ret = wh_Server_DmaProcessClientAddress( + ctx, req.input.addr, &inAddr, req.input.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.input; } - } break; -#endif /* !NO_AES && WOLFSSL_AES_DIRECT */ - default: - /* Type not supported */ - ret = CRYPTOCB_UNAVAILABLE; + if (ret == WH_ERROR_OK) { + ret = wc_CmacUpdate(cmac, inAddr, req.input.sz); + WH_DEBUG_SERVER_VERBOSE("dma cmac update done. ret:%d\n", ret); + } + } + + if (ret == 0 && req.outSz != 0) { + /* Finalize CMAC operation */ + len = req.outSz; + WH_DEBUG_SERVER_VERBOSE("dma cmac final len:%d\n", len); + ret = wc_CmacFinal(cmac, out, &len); + res.outSz = len; + res.keyId = WH_KEYID_ERASED; + } + else if (ret == 0) { + /* Not finalizing - return updated state to client */ + wh_Crypto_CmacAesSaveStateToMsg(&res.resumeState, cmac); + res.keyId = req.keyId; + res.outSz = 0; + } } /* Clean up DMA input address */ @@ -5319,8 +5223,8 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, } if (ret == 0) { - ret = wh_MessageCrypto_TranslateCmacDmaResponse( - magic, &res, (whMessageCrypto_CmacDmaResponse*)cryptoDataOut); + ret = wh_MessageCrypto_TranslateCmacAesDmaResponse( + magic, &res, (whMessageCrypto_CmacAesDmaResponse*)cryptoDataOut); if (ret == 0) { *outSize = sizeof(res) + res.outSz; } @@ -5329,7 +5233,7 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, WH_DEBUG_SERVER_VERBOSE("dma cmac end ret:%d\n", ret); return ret; } -#endif /* WOLFSSL_CMAC */ +#endif /* WOLFSSL_CMAC && !NO_AES && WOLFSSL_AES_DIRECT */ #ifndef WC_NO_RNG static int _HandleRngDma(whServerContext* ctx, uint16_t magic, uint16_t seq, diff --git a/test/wh_test_check_struct_padding.c b/test/wh_test_check_struct_padding.c index 7163a4ff0..530b3e7ef 100644 --- a/test/wh_test_check_struct_padding.c +++ b/test/wh_test_check_struct_padding.c @@ -101,7 +101,7 @@ whMessageCrypto_EccSignRequest pkEccSignReq; whMessageCrypto_EccVerifyRequest pkEccVerifyReq; whMessageCrypto_EccCheckRequest pkEccCheckReq; whMessageCrypto_RngRequest rngReq; -whMessageCrypto_CmacRequest cmacReq; +whMessageCrypto_CmacAesRequest cmacReq; whMessageCrypto_AesCbcResponse cipherAesCbcRes; whMessageCrypto_AesGcmResponse cipherAesGcmRes; whMessageCrypto_RsaKeyGenResponse pkRsakgRes; @@ -113,7 +113,7 @@ whMessageCrypto_EccSignResponse pkEccSignRes; whMessageCrypto_EccVerifyResponse pkEccVerifyRes; whMessageCrypto_EccCheckResponse pkEccCheckRes; whMessageCrypto_RngResponse rngRes; -whMessageCrypto_CmacResponse cmacRes; +whMessageCrypto_CmacAesResponse cmacRes; whMessageCrypto_Sha256Request hashSha256Req; whMessageCrypto_Sha512Request hashSha512Req; whMessageCrypto_Sha2Response hashSha2Res; @@ -130,8 +130,8 @@ whMessageCrypto_MlDsaSignDmaRequest pqMldsaSignDmaReq; whMessageCrypto_MlDsaSignDmaResponse pqMldsaSignDmaRes; whMessageCrypto_MlDsaVerifyDmaRequest pqMldsaVerifyDmaReq; whMessageCrypto_MlDsaVerifyDmaResponse pqMldsaVerifyDmaRes; -whMessageCrypto_CmacDmaRequest cmacDmaReq; -whMessageCrypto_CmacDmaResponse cmacDmaRes; +whMessageCrypto_CmacAesDmaRequest cmacDmaReq; +whMessageCrypto_CmacAesDmaResponse cmacDmaRes; #endif /* WOLFHSM_CFG_DMA */ #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 52ebfd8c8..2e835fe72 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -3611,11 +3611,13 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) 0x1a, 0x0a, 0x52, 0xef, 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10}; -#define CMAC_MLEN_0 0 -#define CMAC_MLEN_128 (128 / 8) -#define CMAC_MLEN_319 (320 / 8 - 1) -#define CMAC_MLEN_320 (320 / 8) -#define CMAC_MLEN_512 (512 / 8) + enum { + CMAC_MLEN_0 = 0, + CMAC_MLEN_128 = 128 / 8, + CMAC_MLEN_319 = 320 / 8 - 1, + CMAC_MLEN_320 = 320 / 8, + CMAC_MLEN_512 = 512 / 8, + }; /* Expected tags */ #ifdef WOLFSSL_AES_128 @@ -3876,11 +3878,6 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) #endif /* WOLFSSL_AES_128 */ } -#undef CMAC_MLEN_0 -#undef CMAC_MLEN_128 -#undef CMAC_MLEN_319 -#undef CMAC_MLEN_320 -#undef CMAC_MLEN_512 if (ret == 0) { WH_TEST_PRINT("CMAC DEVID=0x%X SUCCESS\n", devId); diff --git a/wolfhsm/wh_crypto.h b/wolfhsm/wh_crypto.h index fd729edb4..8ce20fd17 100644 --- a/wolfhsm/wh_crypto.h +++ b/wolfhsm/wh_crypto.h @@ -37,12 +37,25 @@ #include "wolfssl/wolfcrypt/settings.h" #include "wolfssl/wolfcrypt/types.h" #include "wolfssl/wolfcrypt/aes.h" +#include "wolfssl/wolfcrypt/cmac.h" #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" #include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/dilithium.h" +#include "wolfhsm/wh_message_crypto.h" + +#ifdef WOLFSSL_CMAC +/* Save portable CMAC state from a Cmac context into a message state struct */ +void wh_Crypto_CmacAesSaveStateToMsg(whMessageCrypto_CmacAesState* state, + const Cmac* cmac); +/* Restore portable CMAC state from a message state struct into a Cmac context + */ +int wh_Crypto_CmacAesRestoreStateFromMsg( + Cmac* cmac, const whMessageCrypto_CmacAesState* state); +#endif /* WOLFSSL_CMAC */ + #ifndef NO_AES int wh_Crypto_SerializeAesKey(Aes* key, uint16_t max_size, uint8_t* buffer, uint16_t *out_size); diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h index 2ad565973..5ce75cdde 100644 --- a/wolfhsm/wh_error.h +++ b/wolfhsm/wh_error.h @@ -35,6 +35,8 @@ enum WH_ERROR_ENUM { WH_ERROR_BADARGS = -2000, /* No side effects. Fix args. */ WH_ERROR_NOTREADY = -2001, /* Retry function. */ WH_ERROR_ABORTED = -2002, /* Function has fatally failed. Cleanup. */ + WH_ERROR_RESERVED1 = -2003, /* Reserved for future use */ + WH_ERROR_RESERVED2 = -2004, /* Reserved for future use */ WH_ERROR_CERT_VERIFY = -2005, /* Certificate verification failed */ WH_ERROR_BUFFER_SIZE = -2006, /* Generic buffer size mismatch. Buffer * length is not what was expected */ diff --git a/wolfhsm/wh_message.h b/wolfhsm/wh_message.h index 37db1e5a7..7ae54c249 100644 --- a/wolfhsm/wh_message.h +++ b/wolfhsm/wh_message.h @@ -43,6 +43,7 @@ enum WH_MESSAGE_ENUM { WH_MESSAGE_GROUP_PKCS11 = 0x0600, /* PKCS11 protocol */ WH_MESSAGE_GROUP_SHE = 0x0700, /* SHE protocol */ WH_MESSAGE_GROUP_COUNTER = 0x0800, /* monotonic counters */ + WH_MESSAGE_GROUP_RESERVED = 0x0900, /* Reserved for future use */ WH_MESSAGE_GROUP_CUSTOM = 0x0A00, /* User-specified features */ WH_MESSAGE_GROUP_CRYPTO_DMA = 0x0B00, /* DMA crypto operations */ WH_MESSAGE_GROUP_CERT = 0x0C00, /* Certificate operations */ diff --git a/wolfhsm/wh_message_crypto.h b/wolfhsm/wh_message_crypto.h index c43fafacf..d6992a63e 100644 --- a/wolfhsm/wh_message_crypto.h +++ b/wolfhsm/wh_message_crypto.h @@ -794,10 +794,10 @@ int wh_MessageCrypto_TranslateSha2Response( whMessageCrypto_Sha2Response* dest); /* - * CMAC + * CMAC (AES) */ -/* CMAC intermediate state - non-sensitive fields only. +/* CMAC-AES intermediate state - non-sensitive fields only. * k1/k2 subkeys are NOT included as they are key-derived material. * Server re-derives them via wc_InitCmac_ex on each request. */ typedef struct { @@ -805,45 +805,44 @@ typedef struct { uint8_t digest[16]; /* AES_BLOCK_SIZE: running CBC-MAC digest */ uint32_t bufferSz; /* bytes in partial block buffer */ uint32_t totalSz; /* total bytes processed */ -} whMessageCrypto_CmacState; +} whMessageCrypto_CmacAesState; -/* CMAC Request */ +/* CMAC-AES Request */ typedef struct { - uint32_t type; /* wolfCrypt CmacType enum */ uint32_t outSz; /* output MAC size (0 if not finalizing) */ uint32_t inSz; /* input data size */ uint32_t keySz; /* key size (0 if using keyId or already initialized) */ uint16_t keyId; /* key ID for HSM-stored key */ uint8_t WH_PAD[2]; - whMessageCrypto_CmacState resumeState; + whMessageCrypto_CmacAesState resumeState; /* Data follows: * uint8_t in[inSz] * uint8_t key[keySz] */ -} whMessageCrypto_CmacRequest; +} whMessageCrypto_CmacAesRequest; -/* CMAC Response */ +/* CMAC-AES Response */ typedef struct { - whMessageCrypto_CmacState resumeState; - uint32_t outSz; /* actual output MAC size */ - uint16_t keyId; /* key ID (ERASED for non-HSM) */ - uint8_t WH_PAD[2]; + whMessageCrypto_CmacAesState resumeState; + uint32_t outSz; /* actual output MAC size */ + uint16_t keyId; /* key ID (ERASED for non-HSM) */ + uint8_t WH_PAD[2]; /* Data follows: * uint8_t out[outSz] */ -} whMessageCrypto_CmacResponse; +} whMessageCrypto_CmacAesResponse; -int wh_MessageCrypto_TranslateCmacState(uint16_t magic, - const whMessageCrypto_CmacState* src, - whMessageCrypto_CmacState* dest); +int wh_MessageCrypto_TranslateCmacAesState( + uint16_t magic, const whMessageCrypto_CmacAesState* src, + whMessageCrypto_CmacAesState* dest); -int wh_MessageCrypto_TranslateCmacRequest( - uint16_t magic, const whMessageCrypto_CmacRequest* src, - whMessageCrypto_CmacRequest* dest); +int wh_MessageCrypto_TranslateCmacAesRequest( + uint16_t magic, const whMessageCrypto_CmacAesRequest* src, + whMessageCrypto_CmacAesRequest* dest); -int wh_MessageCrypto_TranslateCmacResponse( - uint16_t magic, const whMessageCrypto_CmacResponse* src, - whMessageCrypto_CmacResponse* dest); +int wh_MessageCrypto_TranslateCmacAesResponse( + uint16_t magic, const whMessageCrypto_CmacAesResponse* src, + whMessageCrypto_CmacAesResponse* dest); /* @@ -980,37 +979,36 @@ int wh_MessageCrypto_TranslateSha2DmaRequest( int wh_MessageCrypto_TranslateSha2DmaResponse( uint16_t magic, const whMessageCrypto_Sha2DmaResponse* src, whMessageCrypto_Sha2DmaResponse* dest); -/* CMAC DMA Request - only input data goes via DMA; state, key, and output +/* CMAC-AES DMA Request - only input data goes via DMA; state, key, and output * are passed inline in the message for cross-architecture safety */ typedef struct { - whMessageCrypto_CmacState resumeState; /* portable CMAC state */ - whMessageCrypto_DmaBuffer input; /* Input data via DMA */ - uint32_t type; /* enum wc_CmacType */ - uint32_t outSz; /* output MAC size (0 = not finalizing) */ - uint32_t keySz; /* inline key size (0 = use keyId) */ - uint16_t keyId; /* HSM key ID */ - uint8_t WH_PAD[2]; + whMessageCrypto_CmacAesState resumeState; /* portable CMAC state */ + whMessageCrypto_DmaBuffer input; /* Input data via DMA */ + uint32_t outSz; /* output MAC size (0 = not finalizing) */ + uint32_t keySz; /* inline key size (0 = use keyId) */ + uint16_t keyId; /* HSM key ID */ + uint8_t WH_PAD[2]; /* Trailing data: uint8_t key[keySz] */ -} whMessageCrypto_CmacDmaRequest; +} whMessageCrypto_CmacAesDmaRequest; -/* CMAC DMA Response - state and output MAC returned inline */ +/* CMAC-AES DMA Response - state and output MAC returned inline */ typedef struct { - whMessageCrypto_CmacState resumeState; /* portable CMAC state */ + whMessageCrypto_CmacAesState resumeState; /* portable CMAC state */ whMessageCrypto_DmaAddrStatus dmaAddrStatus; uint32_t outSz; /* actual output MAC size */ uint16_t keyId; uint8_t WH_PAD[2]; /* Trailing data: uint8_t out[outSz] (max AES_BLOCK_SIZE = 16 bytes) */ -} whMessageCrypto_CmacDmaResponse; +} whMessageCrypto_CmacAesDmaResponse; -/* CMAC DMA translation functions */ -int wh_MessageCrypto_TranslateCmacDmaRequest( - uint16_t magic, const whMessageCrypto_CmacDmaRequest* src, - whMessageCrypto_CmacDmaRequest* dest); +/* CMAC-AES DMA translation functions */ +int wh_MessageCrypto_TranslateCmacAesDmaRequest( + uint16_t magic, const whMessageCrypto_CmacAesDmaRequest* src, + whMessageCrypto_CmacAesDmaRequest* dest); -int wh_MessageCrypto_TranslateCmacDmaResponse( - uint16_t magic, const whMessageCrypto_CmacDmaResponse* src, - whMessageCrypto_CmacDmaResponse* dest); +int wh_MessageCrypto_TranslateCmacAesDmaResponse( + uint16_t magic, const whMessageCrypto_CmacAesDmaResponse* src, + whMessageCrypto_CmacAesDmaResponse* dest); /* AES DMA Request [CTR / CBC / GCM / ECB]*/ typedef struct {