From 764a627aa79ee33e22f209645bc70eb1374813df Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 1 Jun 2026 08:37:25 +0000 Subject: [PATCH] Fix ML-DSA cache import buffer sizing and test all security levels The server ML-DSA cache-import buffer was sized with the private-key DER macro instead of the full-keypair macro (MLDSA_MAX_BOTH_KEY_DER_SIZE), so caching a generated keypair failed at ML-DSA-65/87. CI missed it because the ML-DSA tests only ran ML-DSA-44; the existing tests are now parameterized to run across all enabled levels (44/65/87). Also bump the POSIX example server's big key-cache buffer to hold the largest ML-DSA-87 keypair DER (7520 bytes), matching the other server configs, so the client-only example flow can cache keys at every level. --- examples/posix/wh_posix_server/wolfhsm_cfg.h | 2 +- src/wh_server_crypto.c | 20 ++- test/wh_test_crypto.c | 122 ++++++++++++------- 3 files changed, 84 insertions(+), 60 deletions(-) diff --git a/examples/posix/wh_posix_server/wolfhsm_cfg.h b/examples/posix/wh_posix_server/wolfhsm_cfg.h index 790d61779..83919109e 100644 --- a/examples/posix/wh_posix_server/wolfhsm_cfg.h +++ b/examples/posix/wh_posix_server/wolfhsm_cfg.h @@ -40,7 +40,7 @@ #define WOLFHSM_CFG_NVM_OBJECT_COUNT 30 #define WOLFHSM_CFG_SERVER_KEYCACHE_COUNT 9 #define WOLFHSM_CFG_SERVER_KEYCACHE_SIZE 1024 -#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE 5120 +#define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE WOLFHSM_CFG_COMM_DATA_LEN #define WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT 5 #define WOLFHSM_CFG_SERVER_DMAADDR_COUNT 8 diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 4240c4a97..4effc3806 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -768,25 +768,19 @@ int wh_Server_MlDsaKeyCacheImport(whServerContext* ctx, wc_MlDsaKey* key, whNvmMetadata* cacheMeta; uint16_t der_size; - const uint16_t MAX_MLDSA_DER_SIZE = -#if !defined(WOLFSSL_NO_ML_DSA_87) - WC_MLDSA_87_PRV_KEY_DER_SIZE; -#elif !defined(WOLFSSL_NO_ML_DSA_65) - WC_MLDSA_65_PRV_KEY_DER_SIZE; -#else - WC_MLDSA_44_PRV_KEY_DER_SIZE; -#endif - if ((ctx == NULL) || (key == NULL) || (WH_KEYID_ISERASED(keyId)) || ((label != NULL) && (label_len > sizeof(cacheMeta->label)))) { return WH_ERROR_BADARGS; } - ret = wh_Server_KeystoreGetCacheSlotChecked(ctx, keyId, MAX_MLDSA_DER_SIZE, - &cacheBuf, &cacheMeta); + /* The key may hold a full keypair, in which case + * wh_Crypto_MlDsaSerializeKeyDer() encodes both the public and private key + * (wc_MlDsaKey_KeyToDer()), so size for both keys, not just the private key. */ + ret = wh_Server_KeystoreGetCacheSlotChecked( + ctx, keyId, MLDSA_MAX_BOTH_KEY_DER_SIZE, &cacheBuf, &cacheMeta); if (ret == WH_ERROR_OK) { - ret = wh_Crypto_MlDsaSerializeKeyDer(key, MAX_MLDSA_DER_SIZE, cacheBuf, - &der_size); + ret = wh_Crypto_MlDsaSerializeKeyDer(key, MLDSA_MAX_BOTH_KEY_DER_SIZE, + cacheBuf, &der_size); WH_DEBUG_SERVER_VERBOSE("keyId:%u, ret:%d\n", keyId, ret); } diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 6b8d4ff6b..2acaf7a59 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -10348,7 +10348,7 @@ static int whTestCrypto_CmacDmaAsync(whClientContext* ctx, int devId, !defined(WOLFSSL_MLDSA_NO_SIGN) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && !defined(WOLFSSL_NO_ML_DSA_44) static int whTestCrypto_MlDsaWolfCrypt(whClientContext* ctx, int devId, - WC_RNG* rng) + WC_RNG* rng, int level) { (void)ctx; @@ -10358,7 +10358,7 @@ static int whTestCrypto_MlDsaWolfCrypt(whClientContext* ctx, int devId, /* Test ML DSA key generation, signing and verification */ wc_MlDsaKey key; byte msg[] = "Test message for ML DSA signing"; - byte sig[WC_MLDSA_44_SIG_SIZE]; + byte sig[MLDSA_MAX_SIG_SIZE]; word32 sigSz = sizeof(sig); /* Initialize key */ @@ -10368,8 +10368,8 @@ static int whTestCrypto_MlDsaWolfCrypt(whClientContext* ctx, int devId, return ret; } - /* Set security level to 44-bit */ - ret = wc_MlDsaKey_SetParams(&key, WC_ML_DSA_44); + /* Set the requested ML-DSA security level */ + ret = wc_MlDsaKey_SetParams(&key, level); if (ret != 0) { WH_ERROR_PRINT("Failed to set ML DSA params: %d\n", ret); wc_MlDsaKey_Free(&key); @@ -10439,7 +10439,7 @@ static int whTestCrypto_MlDsaWolfCrypt(whClientContext* ctx, int devId, } static int whTestCrypto_MlDsaClient(whClientContext* ctx, int devId, - WC_RNG* rng) + WC_RNG* rng, int level) { (void)devId; (void)rng; @@ -10456,7 +10456,7 @@ static int whTestCrypto_MlDsaClient(whClientContext* ctx, int devId, /* Generate ephemeral key using non-DMA client API */ if (ret == 0) { - ret = wh_Client_MlDsaMakeExportKey(ctx, WC_ML_DSA_44, 0, key); + ret = wh_Client_MlDsaMakeExportKey(ctx, level, 0, key); if (ret != 0) { WH_ERROR_PRINT("Failed to generate ML-DSA key: %d\n", ret); } @@ -10563,7 +10563,7 @@ static int whTestCrypto_MlDsaClient(whClientContext* ctx, int devId, #if defined(WOLFSSL_MLDSA_PUBLIC_KEY) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && !defined(WOLFSSL_NO_ML_DSA_44) static int whTestCrypto_MlDsaExportPublic(whClientContext* ctx, int devId, - WC_RNG* rng) + WC_RNG* rng, int level) { (void)rng; @@ -10576,9 +10576,9 @@ static int whTestCrypto_MlDsaExportPublic(whClientContext* ctx, int devId, uint16_t denyLen = sizeof(denyBuf); (void)devId; - /* MakeCacheKey at the smallest supported level, with NONEXPORTABLE. */ + /* MakeCacheKey at the requested security level, with NONEXPORTABLE. */ ret = wh_Client_MlDsaMakeCacheKey( - ctx, 0, WC_ML_DSA_44, &keyId, + ctx, 0, level, &keyId, WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY | WH_NVM_FLAGS_NONEXPORTABLE, 0, NULL); @@ -10605,7 +10605,7 @@ static int whTestCrypto_MlDsaExportPublic(whClientContext* ctx, int devId, ret = wc_MlDsaKey_Init(pub, NULL, INVALID_DEVID); if (ret == 0) { /* Must set params before the decoder can populate the key. */ - ret = wc_MlDsaKey_SetParams(pub, WC_ML_DSA_44); + ret = wc_MlDsaKey_SetParams(pub, level); } if (ret == 0) { ret = wh_Client_MlDsaExportPublicKey(ctx, keyId, pub, 0, NULL); @@ -10636,7 +10636,7 @@ static int whTestCrypto_MlDsaExportPublic(whClientContext* ctx, int devId, #ifdef WOLFHSM_CFG_DMA static int whTestCrypto_MlDsaDmaClient(whClientContext* ctx, int devId, - WC_RNG* rng) + WC_RNG* rng, int level) { (void)rng; @@ -10669,7 +10669,7 @@ static int whTestCrypto_MlDsaDmaClient(whClientContext* ctx, int devId, /* Generate ephemeral key using DMA */ if (ret == 0) { - ret = wh_Client_MlDsaMakeExportKeyDma(ctx, WC_ML_DSA_44, key); + ret = wh_Client_MlDsaMakeExportKeyDma(ctx, level, key); if (ret != 0) { WH_ERROR_PRINT("Failed to generate ML-DSA key using DMA: %d\n", ret); @@ -10854,7 +10854,7 @@ static int whTestCrypto_MlDsaDmaClient(whClientContext* ctx, int devId, #ifdef WOLFSSL_MLDSA_PUBLIC_KEY static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, - WC_RNG* rng) + WC_RNG* rng, int level) { (void)rng; (void)devId; @@ -10865,9 +10865,9 @@ static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, uint8_t denyBuf[1]; uint16_t denyLen = sizeof(denyBuf); - /* Cache an ML-DSA-44 keypair NONEXPORTABLE on the HSM. */ + /* Cache an ML-DSA keypair NONEXPORTABLE on the HSM at the given level. */ ret = wh_Client_MlDsaMakeCacheKey( - ctx, 0, WC_ML_DSA_44, &keyId, + ctx, 0, level, &keyId, WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY | WH_NVM_FLAGS_NONEXPORTABLE, 0, NULL); @@ -10896,7 +10896,7 @@ static int whTestCrypto_MlDsaExportPublicDma(whClientContext* ctx, int devId, if (ret == 0) { ret = wc_MlDsaKey_Init(pub, NULL, INVALID_DEVID); if (ret == 0) { - ret = wc_MlDsaKey_SetParams(pub, WC_ML_DSA_44); + ret = wc_MlDsaKey_SetParams(pub, level); } if (ret == 0) { ret = wh_Client_MlDsaExportPublicKeyDma(ctx, keyId, pub, 0, NULL); @@ -13448,47 +13448,77 @@ int whTest_CryptoClientConfig(whClientConfig* config) !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \ !defined(WOLFSSL_NO_ML_DSA_44) - i = 0; - while (ret == WH_ERROR_OK && i < WH_NUM_DEVIDS) { + /* Exercise the ML-DSA client/server tests at every enabled security + * level (44/65/87). */ + { + int mldsaLevels[3]; + int mldsaLevelCnt = 0; + int li; + +#ifndef WOLFSSL_NO_ML_DSA_44 + mldsaLevels[mldsaLevelCnt++] = WC_ML_DSA_44; +#endif +#ifndef WOLFSSL_NO_ML_DSA_65 + mldsaLevels[mldsaLevelCnt++] = WC_ML_DSA_65; +#endif +#ifndef WOLFSSL_NO_ML_DSA_87 + mldsaLevels[mldsaLevelCnt++] = WC_ML_DSA_87; +#endif + + for (li = 0; (ret == 0) && (li < mldsaLevelCnt); li++) { + int level = mldsaLevels[li]; + + i = 0; + while (ret == WH_ERROR_OK && i < WH_NUM_DEVIDS) { #ifdef WOLFHSM_CFG_TEST_CLIENT_LARGE_DATA_DMA_ONLY - if (WH_DEV_IDS_ARRAY[i] != WH_DEV_ID_DMA) { - i++; - continue; - } + if (WH_DEV_IDS_ARRAY[i] != WH_DEV_ID_DMA) { + i++; + continue; + } #endif /* WOLFHSM_CFG_TEST_CLIENT_LARGE_DATA_DMA_ONLY */ - ret = whTestCrypto_MlDsaWolfCrypt(client, WH_DEV_IDS_ARRAY[i], rng); - if (ret == WH_ERROR_OK) { - i++; - } - } + ret = whTestCrypto_MlDsaWolfCrypt(client, WH_DEV_IDS_ARRAY[i], + rng, level); + if (ret == WH_ERROR_OK) { + i++; + } + } - if (ret == 0) { - ret = whTestCrypto_MlDsaClient(client, WH_DEV_ID, rng); - } + if (ret == 0) { + ret = whTestCrypto_MlDsaClient(client, WH_DEV_ID, rng, level); + } #ifdef WOLFSSL_MLDSA_PUBLIC_KEY - if (ret == 0) { - ret = whTestCrypto_MlDsaExportPublic(client, WH_DEV_ID, rng); - if (ret != 0) { - WH_ERROR_PRINT("ML-DSA export-public test failed: %d\n", ret); - } - } + if (ret == 0) { + ret = whTestCrypto_MlDsaExportPublic(client, WH_DEV_ID, rng, + level); + if (ret != 0) { + WH_ERROR_PRINT( + "ML-DSA export-public test failed (level %d): %d\n", + level, ret); + } + } #endif #ifdef WOLFHSM_CFG_DMA - if (ret == 0) { - ret = whTestCrypto_MlDsaDmaClient(client, WH_DEV_ID_DMA, rng); - } + if (ret == 0) { + ret = whTestCrypto_MlDsaDmaClient(client, WH_DEV_ID_DMA, rng, + level); + } #ifdef WOLFSSL_MLDSA_PUBLIC_KEY - if (ret == 0) { - ret = whTestCrypto_MlDsaExportPublicDma(client, WH_DEV_ID_DMA, rng); - if (ret != 0) { - WH_ERROR_PRINT( - "ML-DSA export-public DMA test failed: %d\n", ret); - } - } + if (ret == 0) { + ret = whTestCrypto_MlDsaExportPublicDma(client, WH_DEV_ID_DMA, + rng, level); + if (ret != 0) { + WH_ERROR_PRINT( + "ML-DSA export-public DMA test failed (level %d): " + "%d\n", + level, ret); + } + } #endif #endif /* WOLFHSM_CFG_DMA*/ + } + } #endif /* !defined(WOLFSSL_MLDSA_NO_VERIFY) && \ !defined(WOLFSSL_MLDSA_NO_SIGN) && \ !defined(WOLFSSL_MLDSA_NO_MAKE_KEY) && \