From 0170b93d0417a39e9836abb17ea8d8702455a92a Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Sat, 11 Oct 2025 12:45:27 -0600 Subject: [PATCH 1/5] Add global keys feature with comprehensive multi-client testing and keywrap compatibility. Key changes: - Add WOLFHSM_CFG_GLOBAL_KEYS feature flag and configuration - Implement global key cache in NVM context separate from local caches - Add keyId translation layer between client flags and server encoding - Create unified cache routing infrastructure for local/global keys - Add comprehensive multi-client test suite with 15+ test cases - Update all crypto/keystore operations to support global keys - Major refactor to keywrap feature to add clientId-based access control and addiional test coverage for wrap/unwrap scenarios with global and local keys - Standardize client_id usage across benchmarks and tests - Add new wh_keyid module for keyId manipulation helpers --- benchmark/wh_bench.c | 9 +- examples/demo/client/wh_demo_client_keywrap.c | 62 +- examples/demo/client/wh_demo_client_keywrap.h | 3 + .../posix/wh_posix_client/wh_posix_client.c | 9 + examples/posix/wh_posix_client/wolfhsm_cfg.h | 1 + .../posix/wh_posix_server/wh_posix_server.c | 1 - examples/posix/wh_posix_server/wolfhsm_cfg.h | 4 +- src/wh_client_keywrap.c | 9 +- src/wh_keyid.c | 48 + src/wh_nvm.c | 10 + src/wh_server.c | 9 + src/wh_server_cert.c | 9 +- src/wh_server_crypto.c | 141 +- src/wh_server_keystore.c | 687 +++++--- test/config/wolfhsm_cfg.h | 3 + test/wh_test.c | 6 +- test/wh_test_cert.c | 2 +- test/wh_test_clientserver.c | 6 +- test/wh_test_comm.c | 8 +- test/wh_test_common.h | 1 + test/wh_test_crypto.c | 25 +- test/wh_test_keywrap.c | 43 +- test/wh_test_keywrap.h | 1 - test/wh_test_multiclient.c | 1531 +++++++++++++++++ test/wh_test_multiclient.h | 46 + test/wh_test_she.c | 2 +- test/wh_test_wolfcrypt_test.c | 2 +- wolfhsm/wh_client.h | 98 ++ wolfhsm/wh_common.h | 49 +- wolfhsm/wh_error.h | 4 +- wolfhsm/wh_keyid.h | 100 ++ wolfhsm/wh_nvm.h | 6 +- wolfhsm/wh_server.h | 16 +- wolfhsm/wh_server_cache.h | 63 + wolfhsm/wh_server_keystore.h | 21 +- wolfhsm/wh_settings.h | 4 + wolfhsm/wh_transport_mem.h | 4 +- 37 files changed, 2602 insertions(+), 441 deletions(-) create mode 100644 src/wh_keyid.c create mode 100644 test/wh_test_multiclient.c create mode 100644 test/wh_test_multiclient.h create mode 100644 wolfhsm/wh_keyid.h create mode 100644 wolfhsm/wh_server_cache.h diff --git a/benchmark/wh_bench.c b/benchmark/wh_bench.c index 2dc4eefef..66bddfed8 100644 --- a/benchmark/wh_bench.c +++ b/benchmark/wh_bench.c @@ -52,6 +52,9 @@ #if defined(WOLFHSM_CFG_BENCH_ENABLE) +/* Default client ID for benchmarks */ +#define WH_BENCH_CLIENT_ID (1) + /* Buffer sizes for transport */ /* Large enough to handle an RSA 4096 key */ #define BUFFER_SIZE \ @@ -815,7 +818,7 @@ static whCommClientConfig g_mem_cc_conf = { .transport_cb = &g_mem_tccb, .transport_context = (void*)&g_mem_tmcc, .transport_config = (void*)&g_mem_tmcf, - .client_id = 123, + .client_id = WH_BENCH_CLIENT_ID, }; static whTransportServerCb g_mem_tscb = WH_TRANSPORT_MEM_SERVER_CB; @@ -867,7 +870,7 @@ static int _configureClientTransport(whBenchTransportType transport, .transport_cb = pttcClientShmCb, .transport_context = (void*)&tccShm, .transport_config = (void*)&myshmconfig, - .client_id = 12, + .client_id = WH_BENCH_CLIENT_ID, }; memset(&tccShm, 0, sizeof(posixTransportShmClientContext)); @@ -887,7 +890,7 @@ static int _configureClientTransport(whBenchTransportType transport, .transport_cb = &pttcClientTcpCb, .transport_context = (void*)&tccTcp, .transport_config = (void*)&mytcpconfig, - .client_id = 12, + .client_id = WH_BENCH_CLIENT_ID, }; memset(&tccTcp, 0, sizeof(posixTransportTcpClientContext)); diff --git a/examples/demo/client/wh_demo_client_keywrap.c b/examples/demo/client/wh_demo_client_keywrap.c index 92e1fa251..eebb382c9 100644 --- a/examples/demo/client/wh_demo_client_keywrap.c +++ b/examples/demo/client/wh_demo_client_keywrap.c @@ -35,13 +35,13 @@ #ifdef WOLFHSM_CFG_KEYWRAP -#define WH_TEST_KEKID 1 +#define WH_DEMO_KEYWRAP_KEKID 1 static int _InitServerKek(whClientContext* ctx) { /* IMPORTANT NOTE: Server KEK is typically intrinsic or set during * provisioning. Uploading the KEK via the client is for testing purposes * only and not intended as a recommendation */ - whKeyId serverKeyId = WH_TEST_KEKID; + whKeyId serverKeyId = WH_DEMO_KEYWRAP_KEKID; whNvmFlags flags = WH_NVM_FLAGS_NONEXPORTABLE; uint8_t label[WH_NVM_LABEL_LEN] = "Server KEK key"; uint8_t kek[] = {0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e, @@ -55,43 +55,44 @@ static int _InitServerKek(whClientContext* ctx) static int _CleanupServerKek(whClientContext* ctx) { - return wh_Client_KeyErase(ctx, WH_TEST_KEKID); + return wh_Client_KeyErase(ctx, WH_DEMO_KEYWRAP_KEKID); } #ifndef NO_AES #ifdef HAVE_AESGCM -#define WH_TEST_AES_KEYSIZE 16 -#define WH_TEST_AES_TEXTSIZE 16 -#define WH_TEST_AES_IVSIZE 12 -#define WH_TEST_AES_TAGSIZE 16 -#define WH_TEST_AES_WRAPPED_KEYSIZE \ - (WH_TEST_AES_IVSIZE + WH_TEST_AES_TAGSIZE + WH_TEST_AES_KEYSIZE + \ - sizeof(whNvmMetadata)) -#define WH_TEST_AESGCM_WRAPKEY_ID 8 +#define WH_DEMO_KEYWRAP_AES_KEYSIZE 16 +#define WH_DEMO_KEYWRAP_AES_TEXTSIZE 16 +#define WH_DEMO_KEYWRAP_AES_IVSIZE 12 +#define WH_DEMO_KEYWRAP_AES_TAGSIZE 16 +#define WH_DEMO_KEYWRAP_AES_WRAPPED_KEYSIZE \ + (WH_DEMO_KEYWRAP_AES_IVSIZE + WH_DEMO_KEYWRAP_AES_TAGSIZE + \ + WH_DEMO_KEYWRAP_AES_KEYSIZE + sizeof(whNvmMetadata)) +#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8 int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) { int ret = 0; Aes aes[1]; WC_RNG rng[1]; - uint8_t key[WH_TEST_AES_KEYSIZE]; - uint8_t exportedKey[WH_TEST_AES_KEYSIZE]; + uint8_t key[WH_DEMO_KEYWRAP_AES_KEYSIZE]; + uint8_t exportedKey[WH_DEMO_KEYWRAP_AES_KEYSIZE]; whNvmMetadata metadata = { - .id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, 0, WH_TEST_AESGCM_WRAPKEY_ID), - .label = "AES Key Label", + .id = WH_CLIENT_KEYID_MAKE_WRAPPED_META( + client->comm->client_id, WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID), + .label = "AES Key Label", .access = WH_NVM_ACCESS_ANY, - .len = WH_TEST_AES_KEYSIZE}; + .len = WH_DEMO_KEYWRAP_AES_KEYSIZE}; whNvmMetadata exportedMetadata; - uint8_t wrappedKey[WH_TEST_AES_WRAPPED_KEYSIZE]; + uint8_t wrappedKey[WH_DEMO_KEYWRAP_AES_WRAPPED_KEYSIZE]; whKeyId wrappedKeyId; const uint8_t plaintext[] = "hello, wolfSSL AES-GCM!"; uint8_t ciphertext[sizeof(plaintext)]; uint8_t decrypted[sizeof(plaintext)]; - uint8_t tag[WH_TEST_AES_TAGSIZE]; - uint8_t iv[WH_TEST_AES_IVSIZE]; + uint8_t tag[WH_DEMO_KEYWRAP_AES_TAGSIZE]; + uint8_t iv[WH_DEMO_KEYWRAP_AES_IVSIZE]; const uint8_t aad[] = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2}; @@ -127,8 +128,8 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) /* Now we request the server to wrap the key using the KEK we * establish above in the first step. */ - ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, key, - sizeof(key), &metadata, wrappedKey, + ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEKID, + key, sizeof(key), &metadata, wrappedKey, sizeof(wrappedKey)); if (ret != 0) { printf("Failed to wh_Client_KeyWrap %d\n", ret); @@ -144,9 +145,9 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) /* Request the server to unwrap and cache the wrapped key we just created. * This will provide us back a key ID that the client can use to do crypto * operations */ - ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, - wrappedKey, sizeof(wrappedKey), - &wrappedKeyId); + ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, + WH_DEMO_KEYWRAP_KEKID, wrappedKey, + sizeof(wrappedKey), &wrappedKeyId); if (ret != 0) { printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret); goto cleanup_rng; @@ -161,7 +162,8 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) /* Set the key id for this AES context to the wrapped key ID that the server * provided us */ - ret = wh_Client_AesSetKeyId(aes, wrappedKeyId); + ret = + wh_Client_AesSetKeyId(aes, WH_CLIENT_KEYID_MAKE_WRAPPED(wrappedKeyId)); if (ret != 0) { printf("Failed to wh_Client_AesSetKeyId %d\n", ret); goto cleanup_aes; @@ -207,12 +209,12 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client) /* Exporting a wrapped key */ /* Request the server to unwrap and export the wrapped key we created */ - ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, - wrappedKey, sizeof(wrappedKey), - &exportedMetadata, exportedKey, - sizeof(exportedKey)); + ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, + WH_DEMO_KEYWRAP_KEKID, wrappedKey, + sizeof(wrappedKey), &exportedMetadata, + exportedKey, sizeof(exportedKey)); if (ret != 0) { - printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret); + printf("Failed to wh_Client_KeyUnwrapAndExport %d\n", ret); goto cleanup_aes; } diff --git a/examples/demo/client/wh_demo_client_keywrap.h b/examples/demo/client/wh_demo_client_keywrap.h index ec2475fac..84842302c 100644 --- a/examples/demo/client/wh_demo_client_keywrap.h +++ b/examples/demo/client/wh_demo_client_keywrap.h @@ -3,6 +3,9 @@ #include "wolfhsm/wh_client.h" +/* Exposed in header so the demo server can obtain the ID for registration */ +#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8 + int wh_DemoClient_KeyWrap(whClientContext* clientContext); #endif /* !DEMO_CLIENT_KEYWRAP_H_ */ diff --git a/examples/posix/wh_posix_client/wh_posix_client.c b/examples/posix/wh_posix_client/wh_posix_client.c index 9e98b5da0..15d0fced4 100644 --- a/examples/posix/wh_posix_client/wh_posix_client.c +++ b/examples/posix/wh_posix_client/wh_posix_client.c @@ -69,6 +69,14 @@ static int wh_ClientTask(void* cf, const char* type, int test) ret = wh_Client_Init(client, config); + if (ret == 0) { + ret = wh_Client_CommInit(client, NULL, NULL); + if (ret != 0) { + printf("Failed to initialize client communication\n"); + return -1; + } + } + if (strcmp(type, "dma") == 0) { #ifdef WOLFSSL_STATIC_MEMORY printf("Setting up DMA heap with static memory buckets\n"); @@ -85,6 +93,7 @@ static int wh_ClientTask(void* cf, const char* type, int test) printf("Client connecting to server...\n"); if (ret == 0 && test) { + printf("Running client demos...\n"); return wh_DemoClient_All(client); } diff --git a/examples/posix/wh_posix_client/wolfhsm_cfg.h b/examples/posix/wh_posix_client/wolfhsm_cfg.h index 35e01b274..4f5153a03 100644 --- a/examples/posix/wh_posix_client/wolfhsm_cfg.h +++ b/examples/posix/wh_posix_client/wolfhsm_cfg.h @@ -30,5 +30,6 @@ #define WOLFHSM_CFG_HEXDUMP #define WOLFHSM_CFG_COMM_DATA_LEN 5000 #define WOLFHSM_CFG_KEYWRAP +#define WOLFHSM_CFG_GLOBAL_KEYS #endif /* WOLFHSM_CFG_H_ */ diff --git a/examples/posix/wh_posix_server/wh_posix_server.c b/examples/posix/wh_posix_server/wh_posix_server.c index dc97c24cf..adc9a183f 100644 --- a/examples/posix/wh_posix_server/wh_posix_server.c +++ b/examples/posix/wh_posix_server/wh_posix_server.c @@ -118,7 +118,6 @@ static int loadAndStoreKeys(whServerContext* server, whKeyId* outKeyId, return ret; } - static int wh_ServerTask(void* cf, const char* keyFilePath, int keyId, int clientId) { diff --git a/examples/posix/wh_posix_server/wolfhsm_cfg.h b/examples/posix/wh_posix_server/wolfhsm_cfg.h index 6ff18ecac..fd4b33db1 100644 --- a/examples/posix/wh_posix_server/wolfhsm_cfg.h +++ b/examples/posix/wh_posix_server/wolfhsm_cfg.h @@ -44,9 +44,11 @@ #define WOLFHSM_CFG_CERTIFICATE_MANAGER #define WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT +#define WOLFHSM_CFG_KEYWRAP #define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 5000 +#define WOLFHSM_CFG_GLOBAL_KEYS + #define XMEMFENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST) -#define WOLFHSM_CFG_KEYWRAP #endif /* WOLFHSM_CFG_H_ */ diff --git a/src/wh_client_keywrap.c b/src/wh_client_keywrap.c index 0d126b8a1..8945c20fc 100644 --- a/src/wh_client_keywrap.c +++ b/src/wh_client_keywrap.c @@ -185,13 +185,16 @@ int wh_Client_KeyUnwrapAndExportResponse(whClientContext* ctx, if (group != WH_MESSAGE_GROUP_KEY || action != WH_KEY_UNWRAPEXPORT || size < sizeof(*resp) || size > sizeof(*resp) + sizeof(*metadataOut) + keySz || - resp->keySz != keySz || resp->cipherType != cipherType) { + resp->cipherType != cipherType) { return WH_ERROR_ABORTED; } - if (resp->rc != 0) { + if (resp->rc != WH_ERROR_OK) { return resp->rc; } + else if (resp->keySz != keySz) { + return WH_ERROR_BUFFER_SIZE; + } /* Copy the metadata and key from the response data into metadataOut and * keyOut */ @@ -298,6 +301,8 @@ int wh_Client_KeyUnwrapAndCacheResponse(whClientContext* ctx, return resp->rc; } + /* Server returns ID portion only. Client must track ownership + * and specify appropriate flags when later using the key. */ *keyIdOut = resp->keyId; return WH_ERROR_OK; diff --git a/src/wh_keyid.c b/src/wh_keyid.c new file mode 100644 index 000000000..c2427ced0 --- /dev/null +++ b/src/wh_keyid.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * src/wh_keyid.c + * + * KeyId helper function implementations for wolfHSM + */ + +#include "wolfhsm/wh_keyid.h" + +whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, + whKeyId reqId) +{ + uint16_t user = clientId; + whKeyId id = reqId & WH_KEYID_MASK; + +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + /* Check for global flag (bit 8: 0x0100) */ + if ((reqId & 0x0100) != 0) { + user = WH_KEYUSER_GLOBAL; + } +#endif + +#ifdef WOLFHSM_CFG_KEYWRAP + /* Check for wrapped flag (bit 9: 0x0200) */ + if ((reqId & 0x0200) != 0) { + type = WH_KEYTYPE_WRAPPED; + } +#endif + + return WH_MAKE_KEYID(type, user, id); +} diff --git a/src/wh_nvm.c b/src/wh_nvm.c index 2ea7d7c82..c91667562 100644 --- a/src/wh_nvm.c +++ b/src/wh_nvm.c @@ -46,6 +46,11 @@ int wh_Nvm_Init(whNvmContext* context, const whNvmConfig *config) context->cb = config->cb; context->context = config->context; +#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_GLOBAL_KEYS) + /* Initialize the global key cache */ + memset(&context->globalCache, 0, sizeof(context->globalCache)); +#endif + if (context->cb->Init != NULL) { rc = context->cb->Init(context->context, config->config); if (rc != 0) { @@ -64,6 +69,11 @@ int wh_Nvm_Cleanup(whNvmContext* context) return WH_ERROR_BADARGS; } +#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_GLOBAL_KEYS) + /* Clear the global key cache */ + memset(&context->globalCache, 0, sizeof(context->globalCache)); +#endif + /* No callback? Return ABORTED */ if (context->cb->Cleanup == NULL) { return WH_ERROR_ABORTED; diff --git a/src/wh_server.c b/src/wh_server.c index c2da38972..a21c48152 100644 --- a/src/wh_server.c +++ b/src/wh_server.c @@ -188,8 +188,17 @@ static int _wh_Server_HandleCommRequest(whServerContext* server, wh_MessageComm_TranslateInitRequest(magic, (whMessageCommInitRequest*)req_packet, &req); +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + /* USER=0 is reserved for global keys, client_id must be non-zero */ + if (req.client_id == WH_KEYUSER_GLOBAL) { + *out_resp_size = 0; + return WH_ERROR_BADARGS; + } +#endif + /* Process the init action */ server->comm->client_id = req.client_id; + resp.client_id = server->comm->client_id; resp.server_id = server->comm->server_id; diff --git a/src/wh_server_cert.c b/src/wh_server_cert.c index 583e8d10d..cc66a8842 100644 --- a/src/wh_server_cert.c +++ b/src/wh_server_cert.c @@ -122,8 +122,9 @@ static int _verifyChainAgainstCmStore(whServerContext* server, /* Grab the cache slot and dump the public key from the cert * into it */ - rc = wh_Server_KeystoreGetCacheSlot(server, cacheBufSize, - &cacheBuf, &cacheMeta); + rc = wh_Server_KeystoreGetCacheSlot(server, *inout_keyId, + cacheBufSize, &cacheBuf, + &cacheMeta); if (rc == WH_ERROR_OK) { rc = wc_GetSubjectPubKeyInfoDerFromCert( cert_ptr, cert_len + idx, cacheBuf, &cacheBufSize); @@ -488,7 +489,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, cert_data = (const uint8_t*)req_packet + sizeof(req); /* Map client keyId to server keyId space */ - whKeyId keyId = WH_MAKE_KEYID( + whKeyId keyId = wh_KeyId_TranslateClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.keyId); /* Process the verify action */ @@ -617,7 +618,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, } if (resp.rc == WH_ERROR_OK) { /* Map client keyId to server keyId space */ - whKeyId keyId = WH_MAKE_KEYID( + whKeyId keyId = wh_KeyId_TranslateClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.keyId); /* Process the verify action */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 80b386d6a..48a1626a3 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -221,7 +221,8 @@ int wh_Server_CacheImportRsaKey(whServerContext* ctx, RsaKey* key, } /* get a free slot */ - ret = wh_Server_KeystoreGetCacheSlot(ctx, max_size, &cacheBuf, &cacheMeta); + ret = wh_Server_KeystoreGetCacheSlot(ctx, keyId, max_size, &cacheBuf, + &cacheMeta); if (ret == 0) { ret = wh_Crypto_RsaSerializeKeyDer(key, max_size, cacheBuf, &der_size); } @@ -286,8 +287,8 @@ static int _HandleRsaKeyGen(whServerContext* ctx, uint16_t magic, long e = req.e; /* Force incoming key_id to have current user/type */ - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint32_t label_size = WH_NVM_LABEL_LEN; @@ -385,8 +386,8 @@ static int _HandleRsaFunction( whServerContext* ctx, uint16_t magic, int op_type = (int)(req.opType); uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_RSA_OPTIONS_EVICT); - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); word32 in_len = (word32)(req.inLen); word32 out_len = (word32)(req.outLen); /* in and out are after the fixed size fields */ @@ -470,8 +471,8 @@ static int _HandleRsaGetSize(whServerContext* ctx, uint16_t magic, } /* Extract parameters from translated request */ - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_RSA_GET_SIZE_OPTIONS_EVICT); @@ -533,7 +534,8 @@ int wh_Server_EccKeyCacheImport(whServerContext* ctx, ecc_key* key, return WH_ERROR_BADARGS; } /* get a free slot */ - ret = wh_Server_KeystoreGetCacheSlot(ctx, max_size, &cacheBuf, &cacheMeta); + ret = wh_Server_KeystoreGetCacheSlot(ctx, keyId, max_size, &cacheBuf, + &cacheMeta); if (ret == WH_ERROR_OK) { ret = wh_Crypto_EccSerializeKeyDer(key, max_size, cacheBuf, &der_size); } @@ -597,7 +599,7 @@ int wh_Server_CacheImportCurve25519Key(whServerContext* server, /* if successful, find a free cache slot and copy in the key data */ if (ret == 0) { - ret = wh_Server_KeystoreGetCacheSlot(server, keySz, &cacheBuf, + ret = wh_Server_KeystoreGetCacheSlot(server, keyId, keySz, &cacheBuf, &cacheMeta); if (ret == 0) { memcpy(cacheBuf, der_buf, keySz); @@ -664,8 +666,8 @@ int wh_Server_MlDsaKeyCacheImport(whServerContext* ctx, MlDsaKey* key, return WH_ERROR_BADARGS; } - ret = wh_Server_KeystoreGetCacheSlot(ctx, MAX_MLDSA_DER_SIZE, &cacheBuf, - &cacheMeta); + ret = wh_Server_KeystoreGetCacheSlot(ctx, keyId, MAX_MLDSA_DER_SIZE, + &cacheBuf, &cacheMeta); if (ret == WH_ERROR_OK) { ret = wh_Crypto_MlDsaSerializeKeyDer(key, MAX_MLDSA_DER_SIZE, cacheBuf, &der_size); @@ -736,8 +738,8 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; int curve_id = req.curveId; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint16_t label_size = WH_NVM_LABEL_LEN; @@ -839,10 +841,10 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic, uint32_t options = req.options; int evict_pub = !!(options & WH_MESSAGE_CRYPTO_ECDH_OPTIONS_EVICTPUB); int evict_prv = !!(options & WH_MESSAGE_CRYPTO_ECDH_OPTIONS_EVICTPRV); - whKeyId pub_key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId); - whKeyId prv_key_id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, - req.privateKeyId); + whKeyId pub_key_id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId); + whKeyId prv_key_id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId); /* Response message */ byte* res_out = @@ -917,8 +919,8 @@ static int _HandleEccSign(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_EccSignRequest); - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); word32 in_len = req.sz; uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_ECCSIGN_OPTIONS_EVICT); @@ -989,8 +991,8 @@ static int _HandleEccVerify(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint32_t options = req.options; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); uint32_t hash_len = req.hashSz; uint32_t sig_len = req.sigSz; uint8_t* req_sig = @@ -1166,7 +1168,8 @@ int wh_Server_HkdfKeyCacheImport(whServerContext* ctx, const uint8_t* keyData, } /* Get a free slot */ - ret = wh_Server_KeystoreGetCacheSlot(ctx, keySize, &cacheBuf, &cacheMeta); + ret = wh_Server_KeystoreGetCacheSlot(ctx, keyId, keySize, &cacheBuf, + &cacheMeta); if (ret == WH_ERROR_OK) { /* Copy the key data to cache buffer */ memcpy(cacheBuf, keyData, keySize); @@ -1210,10 +1213,10 @@ static int _HandleHkdf(whServerContext* ctx, uint16_t magic, uint32_t saltSz = req.saltSz; uint32_t infoSz = req.infoSz; uint32_t outSz = req.outSz; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdOut); - whKeyId keyIdIn = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdIn); + whKeyId key_id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdOut); + whKeyId keyIdIn = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdIn); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint16_t label_size = WH_NVM_LABEL_LEN; @@ -1332,8 +1335,8 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint16_t label_size = WH_NVM_LABEL_LEN; @@ -1426,12 +1429,10 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic, uint32_t options = req.options; int evict_pub = !!(options & WH_MESSAGE_CRYPTO_CURVE25519_OPTIONS_EVICTPUB); int evict_prv = !!(options & WH_MESSAGE_CRYPTO_CURVE25519_OPTIONS_EVICTPRV); - whKeyId pub_key_id = WH_MAKE_KEYID( WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - req.publicKeyId); - whKeyId prv_key_id = WH_MAKE_KEYID( WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - req.privateKeyId); + whKeyId pub_key_id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId); + whKeyId prv_key_id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId); int endian = req.endian; /* Response message */ @@ -1516,8 +1517,8 @@ static int _HandleAesCtr(whServerContext* ctx, uint16_t magic, if (needed_size > inSize) { return WH_ERROR_BADARGS; } - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_AesCtrRequest); @@ -1633,8 +1634,8 @@ static int _HandleAesEcb(whServerContext* ctx, uint16_t magic, return WH_ERROR_BADARGS; } - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = @@ -1741,8 +1742,8 @@ static int _HandleAesCbc(whServerContext* ctx, uint16_t magic, const void* crypt return WH_ERROR_BADARGS; } - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = @@ -1850,8 +1851,8 @@ static int _HandleAesGcm(whServerContext* ctx, uint16_t magic, uint32_t iv_len = req.ivSz; uint32_t authin_len = req.authInSz; uint32_t tag_len = req.authTagSz; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); /* in, key, iv, authin, tag, and out are after fixed size fields */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_AesGcmRequest); @@ -2074,8 +2075,8 @@ static int _HandleAesGcmDma(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Handle keyId-based keys if no direct key was provided */ if (ret == WH_ERROR_OK && req.key.sz == 0) { - keyId = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + keyId = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); keyLen = sizeof(tmpKey); ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, &keyLen); if (ret == WH_ERROR_OK) { @@ -2221,8 +2222,8 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, * 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_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, - req.keyId); + keyId = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); ret = wh_Server_KeystoreReadKey( ctx, keyId, NULL, (uint8_t*)ctx->crypto->algoCtx.cmac, (uint32_t*)&len); @@ -2298,8 +2299,9 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, if (!WH_KEYID_ISERASED(keyId)) { /* Don't override return value except on failure */ int tmpRet = wh_Server_KeystoreEvictKey( - ctx, WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, keyId)); + ctx, + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, keyId)); if (tmpRet != 0) { ret = tmpRet; } @@ -2310,8 +2312,9 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Handle cancellation - evict key and abandon state */ if (!WH_KEYID_ISERASED(req.keyId)) { wh_Server_KeystoreEvictKey( - ctx, WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId)); + ctx, wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, + req.keyId)); } } #endif @@ -2327,9 +2330,8 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, return ret; } else { - keyId = WH_MAKE_KEYID( WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - req.keyId); + keyId = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); } /* evict the aes sized key in the normal cache */ if (moveToBigCache == 1) { @@ -2714,8 +2716,8 @@ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); int level = req.level; whNvmFlags flags = req.flags; uint8_t* label = req.label; @@ -2828,8 +2830,8 @@ static int _HandleMlDsaSign(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ byte* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_MlDsaSignRequest); - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); word32 in_len = req.sz; uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_MLDSA_SIGN_OPTIONS_EVICT); @@ -2908,8 +2910,8 @@ static int _HandleMlDsaVerify(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint32_t options = req.options; - whKeyId key_id = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); uint32_t hash_len = req.hashSz; uint32_t sig_len = req.sigSz; byte* req_sig = @@ -3909,9 +3911,8 @@ static int _HandleMlDsaKeyGenDma(whServerContext* ctx, uint16_t magic, else { /* Must import the key into the cache and return keyid */ - whKeyId keyId = - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId keyId = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); if (WH_KEYID_ISERASED(keyId)) { /* Generate a new id */ @@ -3999,7 +4000,8 @@ static int _HandleMlDsaSignDma(whServerContext* ctx, uint16_t magic, /* Get key ID and evict flag */ - key_id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, + req.keyId); evict = !!(req.options & WH_MESSAGE_CRYPTO_MLDSA_SIGN_OPTIONS_EVICT); /* Initialize key */ @@ -4107,7 +4109,8 @@ static int _HandleMlDsaVerifyDma(whServerContext* ctx, uint16_t magic, int evict = 0; /* Get key ID and evict flag */ - key_id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, + req.keyId); evict = !!(req.options & WH_MESSAGE_CRYPTO_MLDSA_VERIFY_OPTIONS_EVICT); /* Initialize key */ @@ -4376,9 +4379,9 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, * 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_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, clientKeyId); + keyId = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, + clientKeyId); keyLen = sizeof(tmpKey); /* Load key from cache */ @@ -4441,8 +4444,8 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, whNvmId nvmId = WH_DEVCTX_TO_KEYID(cmac->devCtx); if (nvmId != WH_KEYID_ERASED) { /* Get key ID from CMAC context */ - keyId = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, nvmId); + keyId = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, nvmId); keyLen = sizeof(tmpKey); /* Load key from cache */ diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c index 51e7a45c2..941543573 100644 --- a/src/wh_server_keystore.c +++ b/src/wh_server_keystore.c @@ -52,121 +52,277 @@ static int _FindInCache(whServerContext* server, whKeyId keyId, int* out_index, int* out_big, uint8_t** out_buffer, whNvmMetadata** out_meta); +#ifdef WOLFHSM_CFG_GLOBAL_KEYS +/* + * @brief Check if keyId represents a global key (USER == 0) + */ +static int _IsGlobalKey(whKeyId keyId) +{ + return (WH_KEYID_USER(keyId) == WH_KEYUSER_GLOBAL); +} +#endif /* WOLFHSM_CFG_GLOBAL_KEYS */ -int wh_Server_KeystoreGetUniqueId(whServerContext* server, whNvmId* inout_id) +/* + * @brief Get the appropriate cache context based on keyId + * + * When WOLFHSM_CFG_GLOBAL_KEYS is enabled, routes to global cache if keyId + * has USER == 0, otherwise routes to local cache. When disabled, always + * routes to local cache. + */ +static whKeyCacheContext* _GetCacheContext(whServerContext* server, + whKeyId keyId) { - int i; - int ret = 0; - whNvmId id; - /* apply client_id and type which should be set by caller on outId */ - whKeyId key_id = *inout_id; - int type = WH_KEYID_TYPE(key_id); - int user = WH_KEYID_USER(key_id); - whNvmId buildId; - whNvmId nvmId = 0; - whNvmId keyCount; +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + if (_IsGlobalKey(keyId)) { + return &server->nvm->globalCache; + } +#else + (void)keyId; +#endif + return &server->localCache; +} - /* try every index until we find a unique one, don't worry about capacity */ - for (id = WH_KEYID_IDMAX; id > WH_KEYID_ERASED; id--) { - buildId = WH_MAKE_KEYID(type, user, id); - /* check against cache keys */ - for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (buildId == server->cache[i].meta->id) - break; +/** + * @brief Find a key in the specified cache context + */ +static int _FindInKeyCache(whKeyCacheContext* ctx, whKeyId keyId, + int* out_index, int* out_big, uint8_t** out_buffer, + whNvmMetadata** out_meta) +{ + int ret = WH_ERROR_NOTFOUND; + int i; + int index = -1; + int big = -1; + whNvmMetadata* meta = NULL; + uint8_t* buffer = NULL; + + /* Search regular cache */ + for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { + if (ctx->cache[i].meta->id == keyId) { + big = 0; + index = i; + meta = ctx->cache[i].meta; + buffer = ctx->cache[i].buffer; + break; } - /* try again if match */ - if (i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT) - continue; - /* check against big cache keys */ + } + + /* Search big cache if not found */ + if (index == -1) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (buildId == server->bigCache[i].meta->id) + if (ctx->bigCache[i].meta->id == keyId) { + big = 1; + index = i; + meta = ctx->bigCache[i].meta; + buffer = ctx->bigCache[i].buffer; break; + } } - /* try again if match */ - if (i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT) - continue; - /* if keyId exists */ - ret = wh_Nvm_List(server->nvm, WH_NVM_ACCESS_ANY, WH_NVM_FLAGS_ANY, - buildId, &keyCount, &nvmId); - /* break if we didn't find a match */ - if (ret == WH_ERROR_NOTFOUND || nvmId != buildId) - break; } - /* unlikely but cover the case where we've run out of ids */ - if (id > WH_KEYID_IDMAX) - ret = WH_ERROR_NOSPACE; - /* ultimately, return found id */ - if (ret == 0) - *inout_id = buildId; + + /* Set output parameters if found */ + if (index != -1) { + if (out_index != NULL) + *out_index = index; + if (out_big != NULL) + *out_big = big; + if (out_meta != NULL) + *out_meta = meta; + if (out_buffer != NULL) + *out_buffer = buffer; + ret = WH_ERROR_OK; + } + return ret; } -/* find an available slot for the size, return the slots buffer and meta */ -int wh_Server_KeystoreGetCacheSlot(whServerContext* server, uint16_t keySz, - uint8_t** outBuf, whNvmMetadata** outMeta) +/** + * @brief Get an available cache slot from the specified cache context + */ +static int _GetKeyCacheSlot(whKeyCacheContext* ctx, uint16_t keySz, + uint8_t** outBuf, whNvmMetadata** outMeta) { - int i; int foundIndex = -1; - if (server == NULL || (keySz > WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE && - keySz > WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE)) { + int i; + + if (ctx == NULL || outBuf == NULL || outMeta == NULL) { return WH_ERROR_BADARGS; } + /* Determine which cache to use based on key size */ if (keySz <= WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE) { + /* Search regular cache for empty slot */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - /* check for empty slot or rewrite slot */ - if (foundIndex == -1 && - server->cache[i].meta->id == WH_KEYID_ERASED) { + if (ctx->cache[i].meta->id == WH_KEYID_ERASED) { foundIndex = i; break; } } - /* if no empty slots, check for a commited key we can evict */ + + /* If no empty slots, find committed key to evict */ if (foundIndex == -1) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (server->cache[i].commited == 1) { + if (ctx->cache[i].committed == 1) { foundIndex = i; break; } } } - /* zero the cache slot and set the output buffers */ + /* Zero slot and return pointers */ if (foundIndex >= 0) { - memset(&server->cache[foundIndex], 0, sizeof(whServerCacheSlot)); - *outBuf = server->cache[foundIndex].buffer; - *outMeta = server->cache[foundIndex].meta; + memset(&ctx->cache[foundIndex], 0, sizeof(whServerCacheSlot)); + *outBuf = ctx->cache[foundIndex].buffer; + *outMeta = ctx->cache[foundIndex].meta; } } else { + /* Search big cache for empty slot */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - /* check for empty slot or rewrite slot */ - if (foundIndex == -1 && - server->bigCache[i].meta->id == WH_KEYID_ERASED) { + if (ctx->bigCache[i].meta->id == WH_KEYID_ERASED) { foundIndex = i; break; } } - /* if no empty slots, check for a commited key we can evict */ + + /* If no empty slots, find committed key to evict */ if (foundIndex == -1) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (server->bigCache[i].commited == 1) { + if (ctx->bigCache[i].committed == 1) { foundIndex = i; break; } } } + + /* Zero slot and return pointers */ if (foundIndex >= 0) { - memset(&server->bigCache[foundIndex], 0, - sizeof(whServerBigCacheSlot)); - *outBuf = server->bigCache[foundIndex].buffer; - *outMeta = server->bigCache[foundIndex].meta; + memset(&ctx->bigCache[foundIndex], 0, sizeof(whServerBigCacheSlot)); + *outBuf = ctx->bigCache[foundIndex].buffer; + *outMeta = ctx->bigCache[foundIndex].meta; } } - /* return error if we are out of cache slots */ - if (foundIndex == -1) + + if (foundIndex == -1) { return WH_ERROR_NOSPACE; - return 0; + } + + return WH_ERROR_OK; +} + +/** + * @brief Evict a key from the specified cache context + */ +static int _EvictKeyFromCache(whKeyCacheContext* ctx, whKeyId keyId) +{ + whNvmMetadata* meta = NULL; + int ret = _FindInKeyCache(ctx, keyId, NULL, NULL, NULL, &meta); + + if (ret == WH_ERROR_OK && meta != NULL) { + meta->id = WH_KEYID_ERASED; + } + + return ret; +} + +/** + * @brief Mark a cached key as committed + */ +static int _MarkKeyCommitted(whKeyCacheContext* ctx, whKeyId keyId, + int committed) +{ + int index = -1; + int big = -1; + int ret = _FindInKeyCache(ctx, keyId, &index, &big, NULL, NULL); + + if (ret == WH_ERROR_OK) { + if (big == 0) { + ctx->cache[index].committed = committed; + } + else { + ctx->bigCache[index].committed = committed; + } + } + + return ret; +} + +int wh_Server_KeystoreGetUniqueId(whServerContext* server, whNvmId* inout_id) +{ + int ret = WH_ERROR_OK; + int found = 0; + whNvmId id; + /* apply client_id and type which should be set by caller on outId */ + whKeyId key_id = *inout_id; + int type = WH_KEYID_TYPE(key_id); + int user = WH_KEYID_USER(key_id); + whNvmId buildId; + whNvmId nvmId = 0; + whNvmId keyCount; + + whKeyCacheContext* ctx = _GetCacheContext(server, key_id); + + /* Wrapped keys must be provisioned with explicit identifiers */ + if (type == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_BADARGS; + } + + /* try every index until we find a unique one, don't worry about capacity */ + for (id = WH_KEYID_IDMAX; id > WH_KEYID_ERASED; id--) { + /* id loop var is not an input client ID so we don't need to handle the + * global case */ + buildId = WH_MAKE_KEYID(type, user, id); + + /* Check against cache keys using unified cache functions */ + ret = _FindInKeyCache(ctx, buildId, NULL, NULL, NULL, NULL); + if (ret == WH_ERROR_OK) { + /* Found in cache, try next ID */ + continue; + } + else if (ret != WH_ERROR_NOTFOUND) { + return ret; + } + + /* Check if keyId exists in NVM */ + ret = wh_Nvm_List(server->nvm, WH_NVM_ACCESS_ANY, WH_NVM_FLAGS_ANY, + buildId, &keyCount, &nvmId); + if (ret == WH_ERROR_NOTFOUND || nvmId != buildId) { + /* key doesn't exist in NVM, we found a candidate ID */ + found = 1; + break; + } + + if (ret != WH_ERROR_OK) { + return ret; + } + } + + if (!found) { + return WH_ERROR_NOSPACE; + } + + /* Return found id */ + *inout_id = buildId; + return WH_ERROR_OK; +} + +/* find an available slot for the size, return the slots buffer and meta */ +int wh_Server_KeystoreGetCacheSlot(whServerContext* server, whKeyId keyId, + uint16_t keySz, uint8_t** outBuf, + whNvmMetadata** outMeta) +{ + whKeyCacheContext* ctx; + + if (server == NULL || (keySz > WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE && + keySz > WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE)) { + return WH_ERROR_BADARGS; + } + + /* Get the appropriate cache context for this key */ + ctx = _GetCacheContext(server, keyId); + + /* Use the unified cache slot function */ + return _GetKeyCacheSlot(ctx, keySz, outBuf, outMeta); } int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, @@ -174,6 +330,7 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, { int i; int foundIndex = -1; + whKeyCacheContext* ctx; /* make sure id is valid */ if ((server == NULL) || (meta == NULL) || (in == NULL) || @@ -183,13 +340,16 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, return WH_ERROR_BADARGS; } + /* Get the appropriate cache context for this key */ + ctx = _GetCacheContext(server, meta->id); + /* Check for cross-cache duplicates and evict from other cache if found */ if (meta->len <= WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE) { /* We're going to use regular cache, check if key exists in big cache */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (server->bigCache[i].meta->id == meta->id) { + if (ctx->bigCache[i].meta->id == meta->id) { /* Evict the key from big cache */ - server->bigCache[i].meta->id = WH_KEYID_ERASED; + ctx->bigCache[i].meta->id = WH_KEYID_ERASED; break; } } @@ -197,9 +357,9 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, else { /* We're going to use big cache, check if key exists in regular cache */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (server->cache[i].meta->id == meta->id) { + if (ctx->cache[i].meta->id == meta->id) { /* Evict the key from regular cache */ - server->cache[i].meta->id = WH_KEYID_ERASED; + ctx->cache[i].meta->id = WH_KEYID_ERASED; break; } } @@ -209,17 +369,17 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, if (meta->len <= WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { /* check for empty slot or rewrite slot */ - if (WH_KEYID_ISERASED(server->cache[i].meta->id) || - (server->cache[i].meta->id == meta->id)) { + if (WH_KEYID_ISERASED(ctx->cache[i].meta->id) || + (ctx->cache[i].meta->id == meta->id)) { foundIndex = i; break; } } - /* if no empty slots, check for a commited key we can evict */ + /* if no empty slots, check for a committed key we can evict */ if (foundIndex == -1) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (server->cache[i].commited == 1) { + if (ctx->cache[i].committed == 1) { foundIndex = i; break; } @@ -228,16 +388,16 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, /* write key if slot found */ if (foundIndex != -1) { - memcpy((uint8_t*)server->cache[foundIndex].buffer, in, meta->len); - memcpy((uint8_t*)server->cache[foundIndex].meta, (uint8_t*)meta, + memcpy((uint8_t*)ctx->cache[foundIndex].buffer, in, meta->len); + memcpy((uint8_t*)ctx->cache[foundIndex].meta, (uint8_t*)meta, sizeof(whNvmMetadata)); - /* check if the key is already commited */ + /* check if the key is already committed */ if (wh_Nvm_GetMetadata(server->nvm, meta->id, meta) == WH_ERROR_NOTFOUND) { - server->cache[foundIndex].commited = 0; + ctx->cache[foundIndex].committed = 0; } else { - server->cache[foundIndex].commited = 1; + ctx->cache[foundIndex].committed = 1; } #if defined(DEBUG_CRYPTOCB) && defined(DEBUG_CRYPTOCB_VERBOSE) printf("[server] cacheKey: caching keyid=%u\n", meta->id); @@ -249,17 +409,17 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, /* try big key cache, don't put small keys into big cache if full */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { /* check for empty slot or rewrite slot */ - if (WH_KEYID_ISERASED(server->bigCache[i].meta->id) || - (server->bigCache[i].meta->id == meta->id)) { + if (WH_KEYID_ISERASED(ctx->bigCache[i].meta->id) || + (ctx->bigCache[i].meta->id == meta->id)) { foundIndex = i; break; } } - /* if no empty slots, check for a commited key we can evict */ + /* if no empty slots, check for a committed key we can evict */ if (foundIndex == -1) { for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (server->bigCache[i].commited == 1) { + if (ctx->bigCache[i].committed == 1) { foundIndex = i; break; } @@ -268,17 +428,16 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta, /* write key if slot found */ if (foundIndex != -1) { - memcpy((uint8_t*)server->bigCache[foundIndex].buffer, in, - meta->len); - memcpy((uint8_t*)server->bigCache[foundIndex].meta, (uint8_t*)meta, + memcpy((uint8_t*)ctx->bigCache[foundIndex].buffer, in, meta->len); + memcpy((uint8_t*)ctx->bigCache[foundIndex].meta, (uint8_t*)meta, sizeof(whNvmMetadata)); - /* check if the key is already commited */ + /* check if the key is already committed */ if (wh_Nvm_GetMetadata(server->nvm, meta->id, meta) == WH_ERROR_NOTFOUND) { - server->bigCache[foundIndex].commited = 0; + ctx->bigCache[foundIndex].committed = 0; } else { - server->bigCache[foundIndex].commited = 1; + ctx->bigCache[foundIndex].committed = 1; } } } @@ -299,49 +458,9 @@ static int _FindInCache(whServerContext* server, whKeyId keyId, int* out_index, int* out_big, uint8_t** out_buffer, whNvmMetadata** out_meta) { - int ret = WH_ERROR_NOTFOUND; - int i; - int index = -1; - int big = -1; - whNvmMetadata* meta = NULL; - uint8_t* buffer = NULL; - - for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (server->cache[i].meta->id == keyId) { - big = 0; - index = i; - meta = server->cache[i].meta; - buffer = server->cache[i].buffer; - break; - } - } - if (index == -1) { - for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (server->bigCache[i].meta->id == keyId) { - big = 1; - index = i; - meta = server->bigCache[i].meta; - buffer = server->bigCache[i].buffer; - break; - } - } - } - if (index != -1) { - if (out_index != NULL) { - *out_index = index; - } - if (out_big != NULL) { - *out_big = big; - } - if (out_meta != NULL) { - *out_meta = meta; - } - if (out_buffer != NULL) { - *out_buffer = buffer; - } - ret = WH_ERROR_OK; - } - return ret; + whKeyCacheContext* ctx = _GetCacheContext(server, keyId); + return _FindInKeyCache(ctx, keyId, out_index, out_big, out_buffer, + out_meta); } #ifdef WOLFHSM_CFG_KEYWRAP @@ -364,7 +483,26 @@ static int _ExistsInCache(whServerContext* server, whKeyId keyId) /* Key exists in the cache */ return 1; } +#endif /* WOLFHSM_CFG_KEYWRAP */ +#ifdef WOLFHSM_CFG_KEYWRAP +int wh_Server_KeystoreIsWrappedKey(whServerContext* server, whKeyId keyId, + int* outIsWrapped) +{ + int isWrapped; + + if (server == NULL || WH_KEYID_ISERASED(keyId)) { + return WH_ERROR_BADARGS; + } + + (void)server; + isWrapped = (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED); + if (outIsWrapped != NULL) { + *outIsWrapped = isWrapped; + } + + return WH_ERROR_OK; +} #endif /* WOLFHSM_CFG_KEYWRAP */ /* try to put the specified key into cache if it isn't already, return pointers @@ -381,6 +519,11 @@ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId, return WH_ERROR_BADARGS; } + /* Reject attempts to freshen wrapped keys from NVM */ + if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_ABORTED; + } + ret = _FindInCache(server, keyId, &foundIndex, &foundBigIndex, outBuf, outMeta); if (ret != WH_ERROR_OK) { @@ -388,8 +531,8 @@ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId, ret = wh_Nvm_GetMetadata(server->nvm, keyId, tmpMeta); if (ret == WH_ERROR_OK) { /* Key found in NVM, get a free cache slot */ - ret = wh_Server_KeystoreGetCacheSlot(server, tmpMeta->len, outBuf, - outMeta); + ret = wh_Server_KeystoreGetCacheSlot(server, keyId, tmpMeta->len, + outBuf, outMeta); if (ret == WH_ERROR_OK) { /* Read the key from NVM into the cache slot */ ret = wh_Nvm_Read(server->nvm, keyId, 0, tmpMeta->len, *outBuf); @@ -405,13 +548,16 @@ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId, return ret; } +/* Reads key from cache or NVM. If keyId is a wrapped key will attempt to read + * from cache but NOT from NVM */ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId, whNvmMetadata* outMeta, uint8_t* out, uint32_t* outSz) { - int ret = 0; - int i; - whNvmMetadata meta[1]; + int ret = 0; + whNvmMetadata meta[1]; + whNvmMetadata* cacheMeta = NULL; + uint8_t* cacheBuffer = NULL; if ((server == NULL) || (outSz == NULL) || (WH_KEYID_ISERASED(keyId) && @@ -419,45 +565,29 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId, return WH_ERROR_BADARGS; } - /* check the cache */ - for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - /* copy the meta and key before returning */ - if (server->cache[i].meta->id == keyId) { - /* check outSz */ - if (server->cache[i].meta->len > *outSz) - return WH_ERROR_NOSPACE; - if (outMeta != NULL) { - memcpy((uint8_t*)outMeta, (uint8_t*)server->cache[i].meta, - sizeof(whNvmMetadata)); - } - if (out != NULL) { - memcpy(out, server->cache[i].buffer, - server->cache[i].meta->len); - } - *outSz = server->cache[i].meta->len; - return 0; + /* Check the cache using unified function */ + ret = _FindInCache(server, keyId, NULL, NULL, &cacheBuffer, &cacheMeta); + if (ret == WH_ERROR_OK) { + /* Found in cache */ + if (cacheMeta->len > *outSz) + return WH_ERROR_NOSPACE; + if (outMeta != NULL) { + memcpy((uint8_t*)outMeta, (uint8_t*)cacheMeta, + sizeof(whNvmMetadata)); } - } - /* check the big cache */ - for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - /* copy the meta and key before returning */ - if (server->bigCache[i].meta->id == keyId) { - /* check outSz */ - if (server->bigCache[i].meta->len > *outSz) - return WH_ERROR_NOSPACE; - if (outMeta != NULL) { - memcpy((uint8_t*)outMeta, (uint8_t*)server->bigCache[i].meta, - sizeof(whNvmMetadata)); - } - if (out != NULL) { - memcpy(out, server->bigCache[i].buffer, - server->bigCache[i].meta->len); - } - *outSz = server->bigCache[i].meta->len; - return 0; + if (out != NULL) { + memcpy(out, cacheBuffer, cacheMeta->len); } + *outSz = cacheMeta->len; + return 0; } - /* try to read the metadata */ + + /* Prevent exposing wrapped blobs through the unwrapped read path */ + if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_NOTFOUND; + } + + /* Not in cache, try to read the metadata from NVM */ ret = wh_Nvm_GetMetadata(server->nvm, keyId, meta); if (ret == 0) { /* set outSz */ @@ -469,7 +599,7 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId, if (out != NULL) ret = wh_Nvm_Read(server->nvm, keyId, 0, *outSz, out); } - /* cache key if free slot, will only kick out other commited keys */ + /* cache key if free slot, will only kick out other committed keys */ if (ret == 0 && out != NULL) { (void)wh_Server_KeystoreCacheKey(server, meta, out); } @@ -494,48 +624,56 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId, int wh_Server_KeystoreEvictKey(whServerContext* server, whNvmId keyId) { - int ret = 0; - whNvmMetadata* meta; + int ret = 0; + whKeyCacheContext* ctx; if ((server == NULL) || WH_KEYID_ISERASED(keyId)) { return WH_ERROR_BADARGS; } - ret = _FindInCache(server, keyId, NULL, NULL, NULL, &meta); - if (ret == 0) { + /* Get the appropriate cache context for this key */ + ctx = _GetCacheContext(server, keyId); + + /* Use the unified evict function */ + ret = _EvictKeyFromCache(ctx, keyId); + #if defined(DEBUG_CRYPTOCB) && defined(DEBUG_CRYPTOCB_VERBOSE) + if (ret == 0) { printf("[server] wh_Server_KeystoreEvictKey: evicted keyid=0x%X\n", keyId); -#endif - meta->id = WH_KEYID_ERASED; } +#endif + return ret; } int wh_Server_KeystoreCommitKey(whServerContext* server, whNvmId keyId) { - uint8_t* slotBuf; - whNvmMetadata* slotMeta; - whNvmSize size; - int ret; - int index; - int big; + uint8_t* slotBuf; + whNvmMetadata* slotMeta; + whNvmSize size; + int ret; + whKeyCacheContext* ctx; if ((server == NULL) || WH_KEYID_ISERASED(keyId)) { return WH_ERROR_BADARGS; } - ret = _FindInCache(server, keyId, &index, &big, &slotBuf, &slotMeta); + if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_ABORTED; + } + + /* Get the appropriate cache context for this key */ + ctx = _GetCacheContext(server, keyId); + + /* Find the key in the appropriate cache context obtained above. */ + ret = _FindInKeyCache(ctx, keyId, NULL, NULL, &slotBuf, &slotMeta); if (ret == WH_ERROR_OK) { size = slotMeta->len; ret = wh_Nvm_AddObjectWithReclaim(server->nvm, slotMeta, size, slotBuf); if (ret == 0) { - if (big == 0) { - server->cache[index].commited = 1; - } - else { - server->bigCache[index].commited = 1; - } + /* Mark key as committed using unified function */ + (void)_MarkKeyCommitted(ctx, keyId, 1); } } return ret; @@ -547,6 +685,10 @@ int wh_Server_KeystoreEraseKey(whServerContext* server, whNvmId keyId) return WH_ERROR_BADARGS; } + if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_ABORTED; + } + /* remove the key from the cache if present */ (void)wh_Server_KeystoreEvictKey(server, keyId); @@ -555,6 +697,7 @@ int wh_Server_KeystoreEraseKey(whServerContext* server, whNvmId keyId) } #ifdef WOLFHSM_CFG_KEYWRAP + #ifndef NO_AES #ifdef HAVE_AESGCM @@ -590,7 +733,8 @@ static int _AesGcmWrapKey(whServerContext* server, whKeyId serverKeyId, /* Get the server side key */ ret = wh_Server_KeystoreReadKey( server, - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, serverKeyId), + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, + serverKeyId), NULL, serverKey, &serverKeySz); if (ret != WH_ERROR_OK) { return ret; @@ -662,7 +806,8 @@ static int _AesGcmUnwrapKey(whServerContext* server, uint16_t serverKeyId, /* Get the server side key */ ret = wh_Server_KeystoreReadKey( server, - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, serverKeyId), + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, + serverKeyId), NULL, serverKey, &serverKeySz); if (ret != WH_ERROR_OK) { return ret; @@ -728,6 +873,11 @@ static int _HandleWrapKeyRequest(whServerContext* server, memcpy(&metadata, reqData, sizeof(metadata)); memcpy(key, reqData + sizeof(metadata), req->keySz); + /* Ensure the keyId in the wrapped metadata has the wrapped flag set */ + if (!WH_KEYID_ISWRAPPED(metadata.id)) { + return WH_ERROR_BADARGS; + } + /* Store the wrapped key in the response data */ wrappedKey = respData; @@ -804,6 +954,10 @@ static int _HandleUnwrapAndExportKeyRequest( req->wrappedKeySz - WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE - WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE - sizeof(*metadata); + resp->cipherType = WC_CIPHER_AES_GCM; + /* Key size is only passed back to the client on success */ + resp->keySz = 0; + /* Check if the response data can fit the metadata + key */ if (respDataSz < sizeof(*metadata) + keySz) { return WH_ERROR_BUFFER_SIZE; @@ -816,15 +970,36 @@ static int _HandleUnwrapAndExportKeyRequest( return ret; } + /* Ensure unwrapped metadata has the wrapped flag set */ + if (!WH_KEYID_ISWRAPPED(metadata->id)) { + return WH_ERROR_ABORTED; + } + /* Check if the key is exportable */ if (metadata->flags & WH_NVM_FLAGS_NONEXPORTABLE) { return WH_ERROR_ACCESS; } - /* Tell the client how big the key is */ - resp->keySz = keySz; - resp->cipherType = WC_CIPHER_AES_GCM; + /* Validate client ownership. + * The USER field in wrapped key metadata specifies the owner. + * Only the owning client can export wrapped keys. */ + uint16_t keyUser = WH_KEYID_USER(metadata->id); +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + /* Global keys (USER=0) can be exported by any client */ + if (keyUser != WH_KEYUSER_GLOBAL && + keyUser != server->comm->client_id) { + return WH_ERROR_ACCESS; + } +#else + /* Without global keys, USER must match requesting client */ + if (keyUser != server->comm->client_id) { + return WH_ERROR_ACCESS; + } +#endif /* WOLFHSM_CFG_GLOBAL_KEYS */ + + /* Tell the client how big the key is on success */ + resp->keySz = keySz; } break; #endif /* HAVE_AESGCM */ #endif /* !NO_AES */ @@ -854,7 +1029,7 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, int ret; uint8_t* wrappedKey; - whNvmMetadata metadata; + whNvmMetadata metadata = {0}; uint16_t keySz = 0; uint8_t key[WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE]; @@ -873,6 +1048,7 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, case WC_CIPHER_AES_GCM: { keySz = req->wrappedKeySz - WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE - WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE - sizeof(metadata); + resp->cipherType = WC_CIPHER_AES_GCM; ret = _AesGcmUnwrapKey(server, req->serverKeyId, wrappedKey, req->wrappedKeySz, &metadata, key, keySz); @@ -880,8 +1056,6 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, return ret; } - resp->cipherType = WC_CIPHER_AES_GCM; - resp->keyId = metadata.id; } break; #endif /* HAVE_AESGCM */ @@ -895,15 +1069,49 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, return WH_ERROR_BADARGS; } - /* Check if this key already exists in the cache */ + /* Dynamic keyId generation for wrapped keys is not allowed */ + if (WH_KEYID_ISERASED(metadata.id)) { + /* Wrapped keys must use explicit identifiers */ + return WH_ERROR_BADARGS; + } + + /* Extract ownership from unwrapped metadata (preserves original owner) */ + uint16_t wrappedKeyUser = WH_KEYID_USER(metadata.id); + uint16_t wrappedKeyType = WH_KEYID_TYPE(metadata.id); + + /* Require explicit wrapped-key encoding */ + if (wrappedKeyType != WH_KEYTYPE_WRAPPED) { + return WH_ERROR_ABORTED; + } + + /* Validate ownership: USER field must match requesting client. + * The USER field specifies who owns this wrapped key. */ +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + /* Global keys (USER=0): any client can unwrap and cache to global cache + * Local keys (USER!=0): only owning client can unwrap and cache */ + if (wrappedKeyUser != WH_KEYUSER_GLOBAL && + wrappedKeyUser != server->comm->client_id) { + return WH_ERROR_ACCESS; + } +#else + /* Without global keys, USER must match requesting client */ + if (wrappedKeyUser != server->comm->client_id) { + return WH_ERROR_ACCESS; + } +#endif /* WOLFHSM_CFG_GLOBAL_KEYS */ + + /* Ensure a key with the unwrapped ID does not already exist in cache */ if (_ExistsInCache(server, metadata.id)) { return WH_ERROR_ABORTED; } + /* Store the assigned key ID in the response (ID portion only). We should + * NOT return the upper bits back to the client */ + resp->keyId = WH_KEYID_ID(metadata.id); + /* Cache the key */ return wh_Server_KeystoreCacheKey(server, &metadata, key); } - #endif /* WOLFHSM_CFG_KEYWRAP */ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, @@ -937,8 +1145,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, in = (uint8_t*)req_packet + sizeof(req); /* set the metadata fields */ - meta->id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, - req.id); + meta->id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, server->comm->client_id, req.id); meta->access = WH_NVM_ACCESS_ANY; meta->flags = req.flags; meta->len = req.sz; @@ -986,8 +1194,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, magic, (whMessageKeystore_CacheDmaRequest*)req_packet, &req); /* set the metadata fields */ - meta->id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, - req.id); + meta->id = wh_KeyId_TranslateClient( + WH_KEYTYPE_CRYPTO, server->comm->client_id, req.id); meta->access = WH_NVM_ACCESS_ANY; meta->flags = req.flags; meta->len = req.key.sz; @@ -1038,8 +1246,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = wh_Server_KeystoreExportKeyDma( server, - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, - req.id), + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id), req.key.addr, req.key.sz, meta); resp.rc = ret; /* propagate bad address to client if DMA operation failed */ @@ -1071,8 +1279,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, magic, (whMessageKeystore_EvictRequest*)req_packet, &req); ret = wh_Server_KeystoreEvictKey( - server, WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + server, + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; @@ -1103,8 +1312,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, /* read the key */ ret = wh_Server_KeystoreReadKey( server, - WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, - req.id), + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id), meta, out, &keySz); /* Check if key is non-exportable */ @@ -1146,8 +1355,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, magic, (whMessageKeystore_CommitRequest*)req_packet, &req); ret = wh_Server_KeystoreCommitKey( - server, WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + server, + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; @@ -1172,8 +1382,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, magic, (whMessageKeystore_EraseRequest*)req_packet, &req); ret = wh_Server_KeystoreEraseKey( - server, WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + server, + wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; @@ -1216,10 +1427,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, respData = (uint8_t*)resp_packet + sizeof(whMessageKeystore_WrapResponse); - ret = _HandleWrapKeyRequest(server, &wrapReq, reqData, reqDataSz, - &wrapResp, respData, respDataSz); - wrapResp.rc = ret; - + wrapResp.rc = + _HandleWrapKeyRequest(server, &wrapReq, reqData, reqDataSz, + &wrapResp, respData, respDataSz); (void)wh_MessageKeystore_TranslateWrapResponse(magic, &wrapResp, resp_packet); *out_resp_size = sizeof(wrapResp) + wrapResp.wrappedKeySz; @@ -1252,10 +1462,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, respData = (uint8_t*)resp_packet + sizeof(whMessageKeystore_UnwrapAndExportResponse); - ret = _HandleUnwrapAndExportKeyRequest(server, &unwrapReq, reqData, - reqDataSz, &unwrapResp, - respData, respDataSz); - unwrapResp.rc = ret; + unwrapResp.rc = _HandleUnwrapAndExportKeyRequest( + server, &unwrapReq, reqData, reqDataSz, &unwrapResp, respData, + respDataSz); (void)wh_MessageKeystore_TranslateUnwrapAndExportResponse( magic, &unwrapResp, resp_packet); @@ -1289,10 +1498,9 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, respData = (uint8_t*)resp_packet + sizeof(whMessageKeystore_UnwrapAndCacheResponse); - ret = _HandleUnwrapAndCacheKeyRequest(server, &cacheReq, reqData, - reqDataSz, &cacheResp, - respData, respDataSz); - cacheResp.rc = ret; + cacheResp.rc = _HandleUnwrapAndCacheKeyRequest( + server, &cacheReq, reqData, reqDataSz, &cacheResp, respData, + respDataSz); (void)wh_MessageKeystore_TranslateUnwrapAndCacheResponse( magic, &cacheResp, resp_packet); @@ -1315,18 +1523,22 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, int wh_Server_KeystoreCacheKeyDma(whServerContext* server, whNvmMetadata* meta, uint64_t keyAddr) { - int ret; - uint8_t* buffer; - whNvmMetadata* slotMeta; - int i; + int ret; + uint8_t* buffer; + whNvmMetadata* slotMeta; + int i; + whKeyCacheContext* ctx; + + /* Get the appropriate cache context for this key */ + ctx = _GetCacheContext(server, meta->id); /* Check for cross-cache duplicates and evict from other cache if found */ if (meta->len <= WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE) { /* We're going to use regular cache, check if key exists in big cache */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT; i++) { - if (server->bigCache[i].meta->id == meta->id) { + if (ctx->bigCache[i].meta->id == meta->id) { /* Evict the key from big cache */ - server->bigCache[i].meta->id = WH_KEYID_ERASED; + ctx->bigCache[i].meta->id = WH_KEYID_ERASED; break; } } @@ -1334,16 +1546,17 @@ int wh_Server_KeystoreCacheKeyDma(whServerContext* server, whNvmMetadata* meta, else { /* We're going to use big cache, check if key exists in regular cache */ for (i = 0; i < WOLFHSM_CFG_SERVER_KEYCACHE_COUNT; i++) { - if (server->cache[i].meta->id == meta->id) { + if (ctx->cache[i].meta->id == meta->id) { /* Evict the key from regular cache */ - server->cache[i].meta->id = WH_KEYID_ERASED; + ctx->cache[i].meta->id = WH_KEYID_ERASED; break; } } } /* Get a cache slot */ - ret = wh_Server_KeystoreGetCacheSlot(server, meta->len, &buffer, &slotMeta); + ret = wh_Server_KeystoreGetCacheSlot(server, meta->id, meta->len, &buffer, + &slotMeta); if (ret != 0) { return ret; } diff --git a/test/config/wolfhsm_cfg.h b/test/config/wolfhsm_cfg.h index 4a0762140..9a0d19154 100644 --- a/test/config/wolfhsm_cfg.h +++ b/test/config/wolfhsm_cfg.h @@ -32,6 +32,9 @@ #define WOLFHSM_CFG_COMM_DATA_LEN (1280 * 4) +/* Enable global keys feature for testing */ +#define WOLFHSM_CFG_GLOBAL_KEYS + #define WOLFHSM_CFG_NVM_OBJECT_COUNT 30 #define WOLFHSM_CFG_SERVER_KEYCACHE_COUNT 9 #define WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE 300 diff --git a/test/wh_test.c b/test/wh_test.c index 31124a6e4..413077ab9 100644 --- a/test/wh_test.c +++ b/test/wh_test.c @@ -37,6 +37,7 @@ #include "wh_test_she.h" #include "wh_test_clientserver.h" #include "wh_test_keywrap.h" +#include "wh_test_multiclient.h" #if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER) #include "wh_test_cert.h" @@ -93,6 +94,9 @@ int whTest_Unit(void) #endif /* WOLFHSM_CFG_SERVER_IMG_MGR && !WOLFHSM_CFG_NO_CRYPTO */ + /* Multi-Client Tests (includes Global Keys when enabled) */ + WH_TEST_ASSERT(0 == whTest_MultiClient()); + #if defined(WOLFHSM_CFG_SHE_EXTENSION) WH_TEST_ASSERT(0 == whTest_She()); #endif /* WOLFHSM_SHE_EXTENTION */ @@ -158,7 +162,7 @@ int whTest_ClientTcp(void) .transport_cb = pttccb, .transport_context = (void*)tcc, .transport_config = (void*)mytcpconfig, - .client_id = 0, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whClientConfig c_conf[1] = {{ .comm = cc_conf, diff --git a/test/wh_test_cert.c b/test/wh_test_cert.c index b48cda9f9..cba107440 100644 --- a/test/wh_test_cert.c +++ b/test/wh_test_cert.c @@ -334,7 +334,7 @@ int whTest_CertClientDma_ClientServerTestInternal(whClientContext* client) int32_t out_rc; whNvmId rootCertA_id = 1; whNvmId rootCertB_id = 2; - whKeyId out_keyId; + whKeyId out_keyId = WH_KEYID_ERASED; uint8_t exportedPubKey[LEAF_A_PUBKEY_len]; uint16_t exportedPubKeyLen = sizeof(exportedPubKey); diff --git a/test/wh_test_clientserver.c b/test/wh_test_clientserver.c index 8c1a86151..3b946ed4e 100644 --- a/test/wh_test_clientserver.c +++ b/test/wh_test_clientserver.c @@ -747,7 +747,7 @@ int whTest_ClientServerSequential(whTestNvmBackendType nvmType) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 123, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, .connect_cb = _clientServerSequentialTestConnectCb, }}; @@ -1775,7 +1775,7 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 123, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whClientConfig c_conf[1] = {{ .comm = cc_conf, @@ -1860,7 +1860,7 @@ static int wh_ClientServer_PosixMemMapThreadTest(whTestNvmBackendType nvmType) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 123, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whClientConfig c_conf[1] = {{ .comm = cc_conf, diff --git a/test/wh_test_comm.c b/test/wh_test_comm.c index f3f3ebf29..d5678ed38 100644 --- a/test/wh_test_comm.c +++ b/test/wh_test_comm.c @@ -82,7 +82,7 @@ int whTest_CommMem(void) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 123, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whCommClient client[1] = {0}; @@ -405,7 +405,7 @@ void wh_CommClientServer_MemThreadTest(void) .transport_cb = tmccb, .transport_context = (void*)csc, .transport_config = (void*)tmcf, - .client_id = 0x1, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; /* Server configuration/contexts */ @@ -444,7 +444,7 @@ void wh_CommClientServer_ShMemThreadTest(void) .transport_cb = tmccb, .transport_context = (void*)csc, .transport_config = (void*)tmcf, - .client_id = 0x2, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; /* Server configuration/contexts */ @@ -475,7 +475,7 @@ void wh_CommClientServer_TcpThreadTest(void) .transport_cb = pttccb, .transport_context = (void*)tcc, .transport_config = (void*)mytcpconfig, - .client_id = 0x3, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; /* Server configuration/contexts */ diff --git a/test/wh_test_common.h b/test/wh_test_common.h index c1bc5a08f..792ec36be 100644 --- a/test/wh_test_common.h +++ b/test/wh_test_common.h @@ -33,6 +33,7 @@ #define WH_TEST_FAIL (-1) #define WH_TEST_SUCCESS (0) +#define WH_TEST_DEFAULT_CLIENT_ID (1) /* Helper macro to print a message with caller source file info */ #ifdef WOLFHSM_CFG_TEST_VERBOSE diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index eff6a6baa..1175e9e76 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -46,6 +46,8 @@ #ifdef WOLFHSM_CFG_ENABLE_CLIENT #include "wolfhsm/wh_client.h" #include "wolfhsm/wh_client_crypto.h" +/* Pull in client keywrap tests to run against server */ +#include "wh_test_keywrap.h" #endif #ifdef WOLFHSM_CFG_ENABLE_SERVER @@ -68,6 +70,8 @@ #define FLASH_SECTOR_SIZE (128 * 1024) /* 128KB */ #define FLASH_PAGE_SIZE (8) /* 8B */ +#define ALT_CLIENT_ID (2) + enum { /* Total size needs to fit: * - Transport CSR (whTransportMemCsr) @@ -1352,7 +1356,7 @@ static int whTest_KeyCache(whClientContext* ctx, int devId, WC_RNG* rng) if (ret != 0) { WH_ERROR_PRINT("Failed to CommClose:%d\n",ret); } else { - ctx->comm->client_id = 2; + ctx->comm->client_id = ALT_CLIENT_ID; ret = wh_Client_CommInit(ctx, NULL, NULL); if (ret != 0) { WH_ERROR_PRINT("Failed to CommInit:%d\n", ret); @@ -1376,7 +1380,7 @@ static int whTest_KeyCache(whClientContext* ctx, int devId, WC_RNG* rng) } /* switch back and verify original key */ (void)wh_Client_CommClose(ctx); - ctx->comm->client_id = 1; + ctx->comm->client_id = WH_TEST_DEFAULT_CLIENT_ID; ret = wh_Client_CommInit(ctx, NULL, NULL); if (ret != 0) { WH_ERROR_PRINT("Failed to reconnect: %d\n", ret); @@ -2620,7 +2624,7 @@ static int whTestCrypto_Cmac(whClientContext* ctx, int devId, WC_RNG* rng) } if (ret == 0) { - /* test oneshot verify with commited key */ + /* test oneshot verify with committed key */ keyId = WH_KEYID_ERASED; ret = wh_Client_KeyCache(ctx, 0, labelIn, sizeof(labelIn), knownCmacKey, sizeof(knownCmacKey), &keyId); @@ -3595,6 +3599,13 @@ int whTest_CryptoClientConfig(whClientConfig* config) ret = whTest_NonExportableKeystore(client, WH_DEV_ID, rng); } +#ifdef WOLFHSM_CFG_KEYWRAP + if (ret == 0) { + /* Test keywrap functionality */ + ret = whTest_Client_KeyWrap(client); + } +#endif + #ifndef NO_AES i = 0; while ((ret == WH_ERROR_OK) && (i < WH_NUM_DEVIDS)) { @@ -3761,7 +3772,7 @@ int whTest_CryptoServerConfig(whServerConfig* config) WH_TEST_RETURN_ON_FAIL(wh_Server_Init(server, config)); WH_TEST_RETURN_ON_FAIL(wh_Server_SetConnected(server, am_connected)); - server->comm->client_id = 1; + server->comm->client_id = WH_TEST_DEFAULT_CLIENT_ID; while(am_connected == WH_COMM_CONNECTED) { #ifdef WOLFHSM_CFG_IS_TEST_SERVER @@ -3784,9 +3795,9 @@ int whTest_CryptoServerConfig(whServerConfig* config) /* keep alive for 2 user changes */ if (am_connected != WH_COMM_CONNECTED && userChange < 2) { if (userChange == 0) - server->comm->client_id = 2; + server->comm->client_id = ALT_CLIENT_ID; else if (userChange == 1) - server->comm->client_id = 1; + server->comm->client_id = WH_TEST_DEFAULT_CLIENT_ID; userChange++; am_connected = WH_COMM_CONNECTED; WH_TEST_RETURN_ON_FAIL(wh_Server_SetConnected(server, am_connected)); @@ -3881,7 +3892,7 @@ static int wh_ClientServer_MemThreadTest(whTestNvmBackendType nvmType) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 1, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; #ifdef WOLFHSM_CFG_DMA diff --git a/test/wh_test_keywrap.c b/test/wh_test_keywrap.c index a492e980e..bca4e574f 100644 --- a/test/wh_test_keywrap.c +++ b/test/wh_test_keywrap.c @@ -85,14 +85,15 @@ static int _AesGcm_KeyWrap(whClientContext* client, WC_RNG* rng) uint8_t plainKey[WH_TEST_AES_KEYSIZE]; uint8_t tmpPlainKey[WH_TEST_AES_KEYSIZE]; uint8_t wrappedKey[WH_TEST_AES_WRAPPED_KEYSIZE]; - whKeyId wrappedKeyId; - whNvmMetadata metadata = { - .id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, client->comm->client_id, WH_TEST_AESGCM_KEYID), - .label = "AES Key Label", - .len = WH_TEST_AES_KEYSIZE, - .flags = WH_NVM_FLAGS_NONE, + whKeyId wrappedKeyId = WH_KEYID_ERASED; + whNvmMetadata metadata = { + .id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_TEST_DEFAULT_CLIENT_ID, + WH_TEST_AESGCM_KEYID), + .label = "AES Key Label", + .len = WH_TEST_AES_KEYSIZE, + .flags = WH_NVM_FLAGS_NONE, }; - whNvmMetadata tmpMetadata; + whNvmMetadata tmpMetadata = {0}; Aes aes[1]; const uint8_t plaintext[] = "hello, wolfSSL AES-GCM!"; @@ -135,7 +136,8 @@ static int _AesGcm_KeyWrap(whClientContext* client, WC_RNG* rng) return ret; } - ret = wh_Client_AesSetKeyId(aes, wrappedKeyId); + ret = + wh_Client_AesSetKeyId(aes, WH_CLIENT_KEYID_MAKE_WRAPPED(wrappedKeyId)); if (ret != 0) { WH_ERROR_PRINT("Failed to wh_Client_AesSetKeyId %d\n", ret); return ret; @@ -195,6 +197,28 @@ static int _AesGcm_KeyWrap(whClientContext* client, WC_RNG* rng) return ret; } + /* Cache a local key using the same numeric ID to confirm coexistence */ + { + whKeyId localKeyId = WH_TEST_AESGCM_KEYID; + uint8_t localLabel[WH_NVM_LABEL_LEN] = "LocalKeySameId"; + const uint8_t localKey[WH_TEST_AES_KEYSIZE] = {0}; + + ret = wh_Client_KeyCache(client, WH_NVM_FLAGS_NONE, localLabel, + (uint16_t)sizeof("LocalKeySameId"), + (uint8_t*)localKey, sizeof(localKey), + &localKeyId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to cache local key with shared ID %d\n", ret); + return ret; + } + if (localKeyId != WH_TEST_AESGCM_KEYID) { + WH_ERROR_PRINT("Local key ID mismatch (expected %u, got %u)\n", + WH_TEST_AESGCM_KEYID, localKeyId); + return WH_ERROR_ABORTED; + } + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyErase(client, localKeyId)); + } + wh_Client_KeyErase(client, wrappedKeyId); wc_AesFree(aes); @@ -254,6 +278,9 @@ int whTest_KeyWrapClientConfig(whClientConfig* clientCfg) if (ret != 0) { WH_ERROR_PRINT("Failed to whTest_Client_KeyWrap %d\n", ret); } + else { + printf("KEYWRAP TESTS SUCCESS\n"); + } /* Clean up used resources */ cleanup_and_exit: diff --git a/test/wh_test_keywrap.h b/test/wh_test_keywrap.h index 44262f293..94ed032e3 100644 --- a/test/wh_test_keywrap.h +++ b/test/wh_test_keywrap.h @@ -21,7 +21,6 @@ #include "wolfhsm/wh_server.h" #include "wolfhsm/wh_client.h" -#include "wolfhsm/wh_flash.h" int whTest_Client_KeyWrap(whClientContext* ctx); int whTest_KeyWrapClientConfig(whClientConfig* cf); diff --git a/test/wh_test_multiclient.c b/test/wh_test_multiclient.c new file mode 100644 index 000000000..c4de85943 --- /dev/null +++ b/test/wh_test_multiclient.c @@ -0,0 +1,1531 @@ +/* + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ + +/* + * test/wh_test_multiclient.c + * + * Multi-client test framework and test suites + * + * Provides reusable setup/teardown infrastructure for testing features that + * require multiple clients. Each client connects to its own server instance, + * but both servers share a common NVM context to enable testing of shared + * resources (global keys, shared counters, etc.). + */ + +#include "wolfhsm/wh_settings.h" + +#if defined(WOLFHSM_CFG_ENABLE_CLIENT) && defined(WOLFHSM_CFG_ENABLE_SERVER) + +#include +#include +#include + +#include "wolfssl/wolfcrypt/settings.h" +#include "wolfssl/wolfcrypt/types.h" +#include "wolfssl/wolfcrypt/rsa.h" +#include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/asn.h" + +#include "wolfhsm/wh_error.h" +#include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_message.h" +#include "wolfhsm/wh_transport_mem.h" +#include "wolfhsm/wh_client.h" +#include "wolfhsm/wh_server.h" +#include "wolfhsm/wh_server_keystore.h" +#include "wolfhsm/wh_nvm.h" +#include "wolfhsm/wh_nvm_flash.h" +#include "wolfhsm/wh_flash_ramsim.h" + +#include "wh_test_common.h" + +/* Test configuration */ +#define FLASH_RAM_SIZE (1024 * 1024) /* 1MB */ +#define FLASH_SECTOR_SIZE (128 * 1024) /* 128KB */ +#define FLASH_PAGE_SIZE (8) /* 8B */ +#define BUFFER_SIZE 4096 + +#ifdef WOLFHSM_CFG_GLOBAL_KEYS +/* Test key data */ +static const uint8_t TEST_KEY_DATA_1[] = "TestGlobalKey1Data"; +static const uint8_t TEST_KEY_DATA_2[] = "TestLocalKey2Data"; +static const uint8_t TEST_KEY_DATA_3[] = "TestGlobalKey3DataLonger"; +#endif + +/* ============================================================================ + * DUMMY KEY ID DEFINITIONS + * + * Generic key ID values for use in tests. Actual keyIds are defined locally + * within each test function and macros (WH_CLIENT_KEYID_MAKE_GLOBAL, etc.) are + * applied at assignment time. + * ========================================================================== */ + +#define DUMMY_KEYID_1 1 +#define DUMMY_KEYID_2 2 + +/* ============================================================================ + * MULTI-CLIENT TEST FRAMEWORK INFRASTRUCTURE + * ========================================================================== */ + +/* Server contexts for connect callbacks */ +static whServerContext* testServer1 = NULL; +static whServerContext* testServer2 = NULL; + +/* Connect callback for client 1 */ +static int _connectCb1(void* context, whCommConnected connected) +{ + (void)context; + if (testServer1 == NULL) { + return WH_ERROR_BADARGS; + } + return wh_Server_SetConnected(testServer1, connected); +} + +/* Connect callback for client 2 */ +static int _connectCb2(void* context, whCommConnected connected) +{ + (void)context; + if (testServer2 == NULL) { + return WH_ERROR_BADARGS; + } + return wh_Server_SetConnected(testServer2, connected); +} + +/* ============================================================================ + * GLOBAL KEYS TEST SUITE + * ========================================================================== */ + +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + +/* + * Test 1: Basic global key operations + * - Client 1 caches a global key + * - Client 2 reads the same global key and verifies the data matches + */ +static int _testGlobalKeyBasic(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint8_t outBuf[sizeof(TEST_KEY_DATA_1)] = {0}; + uint16_t outSz = sizeof(outBuf); + + printf("Test: Global key basic operations\n"); + + /* Client 1 caches a global key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"GlobalKey5", sizeof("GlobalKey5"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &keyId)); + + /* Client 2 reads the same global key */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + + /* Verify the key data matches */ + WH_TEST_ASSERT_RETURN(outSz == sizeof(TEST_KEY_DATA_1)); + WH_TEST_ASSERT_RETURN(0 == memcmp(outBuf, TEST_KEY_DATA_1, outSz)); + + printf(" PASS: Basic global key operations\n"); + + (void)ret; + return 0; +} + +/* + * Test 2: Local key isolation + * - Both clients cache local keys with the same ID but different data + * - Each client verifies they can only read their own local key data, not the + * other's + */ +static int _testLocalKeyIsolation(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId keyId1 = DUMMY_KEYID_1; /* Local key for client 1 */ + whKeyId keyId2 = + DUMMY_KEYID_1; /* Same ID for client 2 - should be different key */ + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint8_t outBuf[32] = {0}; + uint16_t outSz; + + printf("Test: Local key isolation\n"); + + /* Client 1 caches a local key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"LocalKey10_C1", sizeof("LocalKey10_C1"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), keyId1)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &keyId1)); + + /* Client 2 caches a different local key with same ID */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client2, 0, (uint8_t*)"LocalKey10_C2", sizeof("LocalKey10_C2"), + (uint8_t*)TEST_KEY_DATA_2, sizeof(TEST_KEY_DATA_2), keyId2)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client2, &keyId2)); + + /* Client 1 reads its own key */ + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client1, keyId1)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client1, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1))); + + /* Client 2 reads its own key (different data) */ + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, keyId2)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_2, sizeof(TEST_KEY_DATA_2))); + + printf(" PASS: Local key isolation\n"); + + (void)ret; + return 0; +} + +/* + * Test 3: Mixed global and local keys with no cross-cache interference + * - Client 1 caches both a global key and a local key with the same ID number + * - Client 2 caches a local key with the same ID (different data) + * - Client 1 can read both its global and local keys correctly + * - Client 2 can access the global key + * - Client 2 can read its own local key (different data than client 1's) + * - Client 2 correctly fails to access Client 1's local key + */ +static int _testMixedGlobalLocal(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId globalKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + whKeyId localKeyId = DUMMY_KEYID_1; /* Same ID number but local */ + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint8_t outBuf[32] = {0}; + uint16_t outSz; + + printf( + "Test: Mixed global and local keys with no cross-cache interference\n"); + + /* Client 1 caches global key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"Global15", sizeof("Global15"), + (uint8_t*)TEST_KEY_DATA_3, sizeof(TEST_KEY_DATA_3), globalKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &globalKeyId)); + + /* Client 1 caches local key with same ID number */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"Local15_C1", sizeof("Local15_C1"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), localKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &localKeyId)); + + /* Client 2 caches local key with same ID number (different data) */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client2, 0, (uint8_t*)"Local15_C2", sizeof("Local15_C2"), + (uint8_t*)TEST_KEY_DATA_2, sizeof(TEST_KEY_DATA_2), localKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client2, &localKeyId)); + + /* Client 1 reads its global key */ + globalKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client1, globalKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client1, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_3, sizeof(TEST_KEY_DATA_3))); + + /* Client 1 reads its local key */ + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client1, localKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client1, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1))); + + /* Client 2 accesses global key (should work) */ + globalKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, globalKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_3, sizeof(TEST_KEY_DATA_3))); + + /* Client 2 reads its own local key 15 (different data) */ + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, localKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_2, sizeof(TEST_KEY_DATA_2))); + + /* Client 1 tries to access Client 2's local key 15 - should fail */ + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client1, localKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + ret = wh_Client_KeyExportResponse(client1, label, labelSz, outBuf, &outSz); + /* Should get client 1's own local key, not client 2's */ + WH_TEST_ASSERT_RETURN(ret == 0); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1))); + + printf(" PASS: Mixed global and local keys with no cross-cache " + "interference\n"); + + (void)ret; + return 0; +} + +/* + * Test 4: NVM persistence of global keys + * - Client 1 caches a global key and commits it to NVM, then evicts it from + * cache + * - Client 2 successfully reloads the global key from NVM + */ +static int _testGlobalKeyNvmPersistence(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint8_t outBuf[sizeof(TEST_KEY_DATA_1)] = {0}; + uint16_t outSz; + + printf("Test: NVM persistence of global keys\n"); + + /* Client 1 caches and commits a global key to NVM */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"GlobalNVM20", sizeof("GlobalNVM20"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &keyId)); + + /* Commit to NVM */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCommitRequest(client1, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCommitResponse(client1)); + + /* Evict from cache on server1 */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + /* Client 2 reads from NVM (will reload to cache) */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1))); + + /* Clean up - erase the key */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEraseRequest(client1, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEraseResponse(client1)); + + printf(" PASS: NVM persistence of global keys\n"); + + (void)ret; + return 0; +} + +/* + * Test 5: Export protection on global keys + * - Client 1 caches a non-exportable global key + * - Client 2 correctly fails when attempting to export the protected key + */ +static int _testGlobalKeyExportProtection(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint8_t outBuf[sizeof(TEST_KEY_DATA_1)] = {0}; + uint16_t outSz; + + printf("Test: Export protection on global keys\n"); + + /* Client 1 caches a non-exportable global key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, WH_NVM_FLAGS_NONEXPORTABLE, (uint8_t*)"NoExport25", + sizeof("NoExport25"), (uint8_t*)TEST_KEY_DATA_1, + sizeof(TEST_KEY_DATA_1), keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &keyId)); + + /* Client 2 tries to export it - should fail */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + ret = wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz); + /* Should fail due to non-exportable flag */ + WH_TEST_ASSERT_RETURN(ret != 0); + + /* Clean up */ + keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Export protection on global keys\n"); + + return 0; +} + +#ifdef WOLFHSM_CFG_DMA +/* + * Test 6: DMA operations with global keys + * - Client 1 caches a global key using DMA transfer + * - Client 2 reads the DMA-cached global key via regular export + * - Client 1 caches another global key via regular method + * - Client 2 exports that global key via DMA transfer + */ +static int _testGlobalKeyDma(whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId keyId1 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + whKeyId keyId2 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_2); + uint8_t keyData1[32] = "GlobalDmaCacheTestKey123456!"; + uint8_t keyData2[32] = "GlobalDmaExportTestKey12345!"; + uint8_t outBuf[32] = {0}; + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint16_t outSz; + + printf("Test: DMA operations with global keys\n"); + + /* Part 1: Cache via DMA, export via regular */ + /* Client 1 caches a global key using DMA */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheDmaRequest( + client1, 0, (uint8_t*)"DmaGlobal35", sizeof("DmaGlobal35"), keyData1, + sizeof(keyData1), keyId1)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheDmaResponse(client1, &keyId1)); + + /* Client 2 reads the global key via regular export */ + keyId1 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest(client2, keyId1)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportResponse(client2, label, labelSz, outBuf, &outSz)); + + /* Verify the key data matches */ + WH_TEST_ASSERT_RETURN(outSz == sizeof(keyData1)); + WH_TEST_ASSERT_RETURN(0 == memcmp(outBuf, keyData1, outSz)); + + /* Part 2: Cache via regular, export via DMA */ + /* Client 1 caches a global key using regular method */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"DmaExport40", sizeof("DmaExport40"), keyData2, + sizeof(keyData2), keyId2)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &keyId2)); + + /* Client 2 exports the global key via DMA */ + keyId2 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_2); + outSz = sizeof(outBuf); + memset(outBuf, 0, sizeof(outBuf)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportDmaRequest(client2, keyId2, outBuf, sizeof(outBuf))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportDmaResponse(client2, label, labelSz, &outSz)); + + /* Verify the key data matches */ + WH_TEST_ASSERT_RETURN(outSz == sizeof(keyData2)); + WH_TEST_ASSERT_RETURN(0 == memcmp(outBuf, keyData2, outSz)); + + /* Clean up */ + keyId1 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, keyId1)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + keyId2 = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_2); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, keyId2)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: DMA operations with global keys\n"); + + (void)ret; + return 0; +} +#endif /* WOLFHSM_CFG_DMA */ + +#ifdef WOLFHSM_CFG_KEYWRAP +/* + * Test 7: Key wrap with global server key + * - Client 1 caches a global wrapping key + * - Client 2 wraps a key using that global server key + * - Client 1 unwraps the key using the same global server key + */ +static int _testGlobalKeyWrapExport(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalWrapKey123456789012345!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "PlainKeyToWrap1234567890123!"; + /* Wrapped key size = IV(12) + TAG(16) + KEYSIZE(32) + metadata */ +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test: Key wrap with global server key\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey45", sizeof("WrapKey45"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 2 wraps a global key using the global server key */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + meta.id = + WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client2, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 unwraps the key using the same global server key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportResponse( + client1, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey))); + + /* Verify the unwrapped key matches the original */ + WH_TEST_ASSERT_RETURN(0 == + memcmp(unwrappedKey, plainKey, sizeof(plainKey))); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Key wrap with global server key\n"); + + (void)ret; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 8: Key unwrap and cache with global server key + * - Client 1 caches a global wrapping key and wraps a key (also global) + * - Client 2 unwraps and caches the key using the global server key + * - Client 2 exports and verifies the cached key matches the original + */ +static int _testGlobalKeyUnwrapCache(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + whKeyId cachedKeyId = 0; + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalUnwrapKey123456789012!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "KeyToCacheViaUnwrap123456!!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t verifyBuf[AES_256_KEY_SIZE] = {0}; + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint16_t verifySz = sizeof(verifyBuf); + whNvmMetadata meta = {0}; + + printf("Test: Key unwrap and cache with global server key\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"UnwrapKey50", sizeof("UnwrapKey50"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 1 wraps a global key */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + /* key-TODO: client-facing helper macro? */ + meta.id = + WH_MAKE_KEYID(WH_KEYTYPE_WRAPPED, WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client1, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client1, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 2 unwraps and caches the key using the global server key */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + ret = wh_Client_KeyUnwrapAndCacheRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, wrappedKey, + sizeof(wrappedKey)); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + + ret = wh_Server_HandleRequestMessage(server2); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + + ret = wh_Client_KeyUnwrapAndCacheResponse(client2, WC_CIPHER_AES_GCM, + &cachedKeyId); + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_OK); + + /* Verify the cached key by exporting it */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest( + client2, WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(cachedKeyId))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportResponse(client2, label, labelSz, + verifyBuf, &verifySz)); + + /* Verify the exported key matches the original */ + WH_TEST_ASSERT_RETURN(0 == memcmp(verifyBuf, plainKey, sizeof(plainKey))); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest( + client2, WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(cachedKeyId))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client2)); + + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Key unwrap and cache with global server key\n"); + + (void)ret; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 7a: Global wrapping key + Global wrapped key (Positive) + * - Client 1 caches a global wrapping key + * - Client 2 wraps a global key using it + * - Client 1 unwraps and exports successfully + */ +static int _testWrappedKey_GlobalWrap_GlobalKey_Positive( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalWrapKey2Test7aXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "GlobalPlainKey2Test7aXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test 7a: Global wrap key + Global wrapped key (Positive)\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_7a", sizeof("WrapKey_7a"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 2 wraps a GLOBAL key using the global server key */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + meta.id = + WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client2, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 unwraps and exports the global key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportResponse( + client1, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey))); + + /* Verify the unwrapped key matches the original */ + WH_TEST_ASSERT_RETURN(0 == + memcmp(unwrappedKey, plainKey, sizeof(plainKey))); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Global wrap key + Global wrapped key (Positive)\n"); + + (void)ret; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 7b: Global wrapping key + Global wrapped key (Negative - NONEXPORTABLE) + * - Client 1 caches a global wrapping key + * - Client 2 wraps a global key with NONEXPORTABLE flag + * - Client 1 unwrap-and-export fails with WH_ERROR_ACCESS + */ +static int _testWrappedKey_GlobalWrap_GlobalKey_NonExportable( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalWrapKey2Test7bXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "GlobalPlainKey2Test7bXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test 7b: Global wrap key + Global wrapped key (Non-exportable)\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_7b", sizeof("WrapKey_7b"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 2 wraps a GLOBAL key with NONEXPORTABLE flag */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + meta.id = + WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + meta.flags = WH_NVM_FLAGS_NONEXPORTABLE; + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client2, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 tries to unwrap and export - should fail */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + ret = wh_Client_KeyUnwrapAndExportResponse( + client1, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey)); + + /* Should fail due to non-exportable flag */ + WH_TEST_ASSERT_RETURN(ret != 0); + + /* Clean up */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Global wrap key + Global wrapped key (Non-exportable)\n"); + + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 8a: Global wrapping key + Local wrapped key (Positive - Owner) + * - Client 1 caches a global wrapping key + * - Client 2 wraps a LOCAL key (USER=client2_id) using global wrapping key + * - Client 2 unwraps and exports successfully (owner) + */ +static int _testWrappedKey_GlobalWrap_LocalKey_OwnerExport( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint16_t client2Id = WH_TEST_DEFAULT_CLIENT_ID + 1; + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalWrapKey2Test8aXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "LocalPlainKey2Test8aXXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test 8a: Global wrap key + Local wrapped key (Owner export)\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_8a", sizeof("WrapKey_8a"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 2 wraps a LOCAL key (USER=client2_id) */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + meta.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(client2Id, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client2, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 2 (owner) unwraps and exports the local key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client2, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportResponse( + client2, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey))); + + /* Verify the unwrapped key matches the original */ + WH_TEST_ASSERT_RETURN(0 == + memcmp(unwrappedKey, plainKey, sizeof(plainKey))); + + /* Clean up */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Global wrap key + Local wrapped key (Owner export)\n"); + + (void)ret; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 8b: Global wrapping key + Local wrapped key (Negative - Non-owner) + * - Client 1 caches a global wrapping key + * - Client 2 wraps a LOCAL key (USER=client2_id) + * - Client 1 unwrap-and-export fails with WH_ERROR_ACCESS (not owner) + * - Client 1 unwrap-and-cache also fails with WH_ERROR_ACCESS + */ +static int _testWrappedKey_GlobalWrap_LocalKey_NonOwnerFails( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + uint16_t client2Id = WH_TEST_DEFAULT_CLIENT_ID + 1; + uint8_t wrapKey[AES_256_KEY_SIZE] = "GlobalWrapKey2Test8bXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "LocalPlainKey2Test8bXXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + whKeyId cachedKeyId = 0; + + printf("Test 8b: Global wrap key + Local wrapped key (Non-owner fails)\n"); + + /* Client 1 caches a global wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_8b", sizeof("WrapKey_8b"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 2 wraps a LOCAL key (USER=client2_id) */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + meta.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(client2Id, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client2, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 (non-owner) tries to unwrap and export - should fail */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + ret = wh_Client_KeyUnwrapAndExportResponse( + client1, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey)); + + /* Should fail - Client 1 is not the owner */ + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_ACCESS); + + /* Client 1 (non-owner) tries to unwrap and cache - should also fail */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndCacheRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + ret = wh_Client_KeyUnwrapAndCacheResponse(client1, WC_CIPHER_AES_GCM, + &cachedKeyId); + + /* Should also fail - Client 1 is not the owner */ + WH_TEST_ASSERT_RETURN(ret == WH_ERROR_ACCESS); + + /* Clean up */ + serverKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Global wrap key + Local wrapped key (Non-owner fails)\n"); + + return WH_ERROR_OK; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 9a: Local wrapping key + Local wrapped key (Positive - Same owner) + * - Client 1 caches a local wrapping key + * - Client 1 wraps a LOCAL key (USER=client1_id) + * - Client 1 unwraps and exports successfully + */ +static int _testWrappedKey_LocalWrap_LocalKey_SameOwner( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = DUMMY_KEYID_1; /* Local wrapping key */ + uint16_t client1Id = WH_TEST_DEFAULT_CLIENT_ID; + uint8_t wrapKey[AES_256_KEY_SIZE] = "LocalWrapKey2Test9aXXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "LocalPlainKey2Test9aXXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test 9a: Local wrap key + Local wrapped key (Same owner)\n"); + + /* Client 1 caches a LOCAL wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_9a", sizeof("WrapKey_9a"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 1 wraps a LOCAL key (USER=client1_id) */ + serverKeyId = DUMMY_KEYID_1; /* Use local wrapping key */ + meta.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(client1Id, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client1, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client1, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 (owner) unwraps and exports the local key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndExportResponse( + client1, WC_CIPHER_AES_GCM, &meta, unwrappedKey, sizeof(unwrappedKey))); + + /* Verify the unwrapped key matches the original */ + WH_TEST_ASSERT_RETURN(0 == + memcmp(unwrappedKey, plainKey, sizeof(plainKey))); + + /* Clean up */ + serverKeyId = DUMMY_KEYID_1; + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Local wrap key + Local wrapped key (Same owner)\n"); + + (void)ret; + (void)client2; + (void)server2; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 9b: Local wrapping key + Local wrapped key (Negative - No access without + * wrap key) + * - Client 1 caches a local wrapping key + * - Client 1 wraps a local key + * - Client 2 cannot unwrap (doesn't have wrapping key) + */ +static int _testWrappedKey_LocalWrap_LocalKey_NoAccessWithoutWrapKey( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = DUMMY_KEYID_1; /* Local wrapping key */ + uint16_t client1Id = WH_TEST_DEFAULT_CLIENT_ID; + uint8_t wrapKey[AES_256_KEY_SIZE] = "LocalWrapKey2Test9bXXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "LocalPlainKey2Test9bXXXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf( + "Test 9b: Local wrap key + Local wrapped key (No wrap key access)\n"); + + /* Client 1 caches a LOCAL wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_9b", sizeof("WrapKey_9b"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 1 wraps a LOCAL key */ + serverKeyId = DUMMY_KEYID_1; /* Use local wrapping key */ + meta.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(client1Id, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client1, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client1, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 2 tries to unwrap - should fail (no wrapping key) */ + ret = wh_Client_KeyUnwrapAndExportRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, wrappedKey, + sizeof(wrappedKey)); + if (ret == 0) { + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + ret = wh_Client_KeyUnwrapAndExportResponse(client2, WC_CIPHER_AES_GCM, + &meta, unwrappedKey, + sizeof(unwrappedKey)); + } + + /* Should fail - Client 2 doesn't have the wrapping key */ + WH_TEST_ASSERT_RETURN(ret != 0); + + /* Clean up */ + serverKeyId = DUMMY_KEYID_1; + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Local wrap key + Local wrapped key (No wrap key access)\n"); + + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 10a: Local wrapping key + Global wrapped key (Positive - Any cache + * global) + * - Client 1 caches a local wrapping key + * - Client 1 wraps a GLOBAL key (USER=0) + * - Client 1 unwraps and caches to global cache + * - Client 2 can read from global cache via KeyExport + */ +static int _testWrappedKey_LocalWrap_GlobalKey_AnyCacheGlobal( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = DUMMY_KEYID_1; /* Local wrapping key */ + uint8_t wrapKey[AES_256_KEY_SIZE] = "LocalWrapKey2Test10aXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "GlobalPlainKey2Test10aXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t exportedKey[AES_256_KEY_SIZE] = {0}; + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + uint16_t exportedSz = sizeof(exportedKey); + whNvmMetadata meta = {0}; + whKeyId cachedKeyId = 0; + + printf("Test 10a: Local wrap key + Global wrapped key (Cache global)\n"); + + /* Client 1 caches a LOCAL wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_10a", sizeof("WrapKey_10a"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 1 wraps a GLOBAL key (USER=0) */ + serverKeyId = DUMMY_KEYID_1; /* Use local wrapping key */ + meta.id = + WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client1, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client1, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 1 unwraps and caches to global cache */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndCacheRequest( + client1, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, + sizeof(wrappedKey))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyUnwrapAndCacheResponse( + client1, WC_CIPHER_AES_GCM, &cachedKeyId)); + + /* Client 2 reads from global cache via KeyExport */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportRequest( + client2, WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(cachedKeyId))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportResponse( + client2, label, labelSz, exportedKey, &exportedSz)); + + /* Verify the exported key matches the original */ + WH_TEST_ASSERT_RETURN(0 == memcmp(exportedKey, plainKey, sizeof(plainKey))); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest( + client2, WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(cachedKeyId))); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client2)); + + serverKeyId = DUMMY_KEYID_1; + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Local wrap key + Global wrapped key (Cache global)\n"); + + (void)ret; + return 0; +#undef WRAPPED_KEY_SIZE +} + +/* + * Test 10b: Local wrapping key + Global wrapped key (Negative - No wrap key) + * - Client 1 caches a local wrapping key + * - Client 1 wraps a global key + * - Client 2 cannot unwrap (doesn't have wrapping key) + */ +static int _testWrappedKey_LocalWrap_GlobalKey_NonOwnerNoWrapKey( + whClientContext* client1, whServerContext* server1, + whClientContext* client2, whServerContext* server2) +{ + int ret; + whKeyId serverKeyId = DUMMY_KEYID_1; /* Local wrapping key */ + uint8_t wrapKey[AES_256_KEY_SIZE] = "LocalWrapKey2Test10bXXXXXXXXX!"; + uint8_t plainKey[AES_256_KEY_SIZE] = "GlobalPlainKey2Test10bXXXXXXX!"; +#define WRAPPED_KEY_SIZE (12 + 16 + AES_256_KEY_SIZE + sizeof(whNvmMetadata)) + uint8_t wrappedKey[WRAPPED_KEY_SIZE] = {0}; + uint8_t unwrappedKey[AES_256_KEY_SIZE] = {0}; + whNvmMetadata meta = {0}; + + printf("Test 10b: Local wrap key + Global wrapped key (No wrap key)\n"); + + /* Client 1 caches a LOCAL wrapping key */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"WrapKey_10b", sizeof("WrapKey_10b"), wrapKey, + sizeof(wrapKey), serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheResponse(client1, &serverKeyId)); + + /* Client 1 wraps a GLOBAL key */ + serverKeyId = DUMMY_KEYID_1; /* Use local wrapping key */ + meta.id = + WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, DUMMY_KEYID_2); + meta.len = sizeof(plainKey); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapRequest(client1, WC_CIPHER_AES_GCM, + serverKeyId, plainKey, + sizeof(plainKey), &meta)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyWrapResponse( + client1, WC_CIPHER_AES_GCM, wrappedKey, sizeof(wrappedKey))); + + /* Client 2 tries to unwrap - should fail (no wrapping key) */ + ret = wh_Client_KeyUnwrapAndExportRequest(client2, WC_CIPHER_AES_GCM, + serverKeyId, wrappedKey, + sizeof(wrappedKey)); + if (ret == 0) { + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server2)); + ret = wh_Client_KeyUnwrapAndExportResponse(client2, WC_CIPHER_AES_GCM, + &meta, unwrappedKey, + sizeof(unwrappedKey)); + } + + /* Should fail - Client 2 doesn't have the wrapping key */ + WH_TEST_ASSERT_RETURN(ret != 0); + + /* Clean up */ + serverKeyId = DUMMY_KEYID_1; + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictRequest(client1, serverKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Local wrap key + Global wrapped key (No wrap key)\n"); + + return 0; +#undef WRAPPED_KEY_SIZE +} +#endif /* WOLFHSM_CFG_KEYWRAP */ + +/* Helper function to run all global keys tests */ +static int _runGlobalKeysTests(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyBasic(client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testLocalKeyIsolation(client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testMixedGlobalLocal(client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyNvmPersistence(client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyExportProtection(client1, server1, client2, server2)); + +#ifdef WOLFHSM_CFG_DMA + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyDma(client1, server1, client2, server2)); +#endif + +#ifdef WOLFHSM_CFG_KEYWRAP + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyWrapExport(client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testGlobalKeyUnwrapCache(client1, server1, client2, server2)); + + /* Comprehensive wrapped key access control tests */ + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_GlobalWrap_GlobalKey_Positive( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_GlobalWrap_GlobalKey_NonExportable( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_GlobalWrap_LocalKey_OwnerExport( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_GlobalWrap_LocalKey_NonOwnerFails( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_LocalWrap_LocalKey_SameOwner( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testWrappedKey_LocalWrap_LocalKey_NoAccessWithoutWrapKey( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL(_testWrappedKey_LocalWrap_GlobalKey_AnyCacheGlobal( + client1, server1, client2, server2)); + + WH_TEST_RETURN_ON_FAIL( + _testWrappedKey_LocalWrap_GlobalKey_NonOwnerNoWrapKey( + client1, server1, client2, server2)); +#endif + + printf("All Global Keys Tests PASSED ===\n"); + return 0; +} + +#endif /* WOLFHSM_CFG_GLOBAL_KEYS */ + +/* ============================================================================ + * MULTI-CLIENT SEQUENTIAL TEST FRAMEWORK + * ========================================================================== */ + +/* Generic setup/teardown for multi-client sequential tests using shared memory + */ +static int whTest_MultiClientSequential(void) +{ + int ret = 0; + + /* Transport memory configurations for both clients */ + static uint8_t req1[BUFFER_SIZE]; + static uint8_t resp1[BUFFER_SIZE]; + whTransportMemConfig tmcf1[1] = {{ + .req = (whTransportMemCsr*)req1, + .req_size = sizeof(req1), + .resp = (whTransportMemCsr*)resp1, + .resp_size = sizeof(resp1), + }}; + + static uint8_t req2[BUFFER_SIZE]; + static uint8_t resp2[BUFFER_SIZE]; + whTransportMemConfig tmcf2[1] = {{ + .req = (whTransportMemCsr*)req2, + .req_size = sizeof(req2), + .resp = (whTransportMemCsr*)resp2, + .resp_size = sizeof(resp2), + }}; + + /* Client 1 configuration */ + whTransportClientCb tccb1[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; + whTransportMemClientContext tmcc1[1] = {0}; + whCommClientConfig cc_conf1[1] = {{ + .transport_cb = tccb1, + .transport_context = (void*)tmcc1, + .transport_config = (void*)tmcf1, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, + .connect_cb = _connectCb1, + }}; + whClientContext client1[1] = {0}; + whClientConfig c_conf1[1] = {{ + .comm = cc_conf1, + }}; + + /* Client 2 configuration */ + whTransportClientCb tccb2[1] = {WH_TRANSPORT_MEM_CLIENT_CB}; + whTransportMemClientContext tmcc2[1] = {0}; + whCommClientConfig cc_conf2[1] = {{ + .transport_cb = tccb2, + .transport_context = (void*)tmcc2, + .transport_config = (void*)tmcf2, + .client_id = WH_TEST_DEFAULT_CLIENT_ID + 1, + .connect_cb = _connectCb2, + }}; + whClientContext client2[1] = {0}; + whClientConfig c_conf2[1] = {{ + .comm = cc_conf2, + }}; + + /* Shared NVM configuration using RamSim Flash */ + static uint8_t memory[FLASH_RAM_SIZE] = {0}; + whFlashRamsimCtx fc[1] = {0}; + whFlashRamsimCfg fc_conf[1] = {{ + .size = FLASH_RAM_SIZE, + .sectorSize = FLASH_SECTOR_SIZE, + .pageSize = FLASH_PAGE_SIZE, + .erasedByte = ~(uint8_t)0, + .memory = memory, + }}; + const whFlashCb fcb[1] = {WH_FLASH_RAMSIM_CB}; + + whNvmFlashConfig nf_conf[1] = {{ + .cb = fcb, + .context = fc, + .config = fc_conf, + }}; + whNvmFlashContext nfc[1] = {0}; + whNvmCb nfcb[1] = {WH_NVM_FLASH_CB}; + + whNvmConfig n_conf[1] = {{ + .cb = nfcb, + .context = nfc, + .config = nf_conf, + }}; + whNvmContext nvm[1] = {0}; /* Shared NVM */ + +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + /* Crypto contexts for both servers */ + whServerCryptoContext crypto1[1] = {{.devId = INVALID_DEVID}}; + whServerCryptoContext crypto2[1] = {{.devId = INVALID_DEVID}}; +#endif + + /* Server 1 configuration */ + whTransportServerCb tscb1[1] = {WH_TRANSPORT_MEM_SERVER_CB}; + whTransportMemServerContext tmsc1[1] = {0}; + whCommServerConfig cs_conf1[1] = {{ + .transport_cb = tscb1, + .transport_context = (void*)tmsc1, + .transport_config = (void*)tmcf1, + .server_id = 101, + }}; + whServerConfig s_conf1[1] = {{ + .comm_config = cs_conf1, + .nvm = nvm, /* Shared NVM */ +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + .crypto = crypto1, +#endif + }}; + whServerContext server1[1] = {0}; + + /* Server 2 configuration */ + whTransportServerCb tscb2[1] = {WH_TRANSPORT_MEM_SERVER_CB}; + whTransportMemServerContext tmsc2[1] = {0}; + whCommServerConfig cs_conf2[1] = {{ + .transport_cb = tscb2, + .transport_context = (void*)tmsc2, + .transport_config = (void*)tmcf2, + .server_id = 102, + }}; + whServerConfig s_conf2[1] = {{ + .comm_config = cs_conf2, + .nvm = nvm, /* Shared NVM */ + +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + .crypto = crypto2, +#endif + }}; + whServerContext server2[1] = {0}; + + /* Expose server contexts to connect callbacks */ + testServer1 = server1; + testServer2 = server2; + +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + /* Initialize wolfCrypt */ + ret = wolfCrypt_Init(); + if (ret != 0) + return ret; +#endif + + /* Initialize NVM (shared) */ + ret = wh_Nvm_Init(nvm, n_conf); + if (ret != 0) + return ret; + +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + /* Initialize RNGs */ + ret = wc_InitRng_ex(crypto1->rng, NULL, crypto1->devId); + if (ret != 0) + return ret; + + ret = wc_InitRng_ex(crypto2->rng, NULL, crypto2->devId); + if (ret != 0) + return ret; +#endif + + /* Initialize servers */ + ret = wh_Server_Init(server1, s_conf1); + if (ret != 0) + return ret; + + ret = wh_Server_Init(server2, s_conf2); + if (ret != 0) + return ret; + + /* Initialize clients */ + ret = wh_Client_Init(client1, c_conf1); + if (ret != 0) + return ret; + + ret = wh_Client_Init(client2, c_conf2); + if (ret != 0) + return ret; + + /* Initialize communication for both clients */ + uint32_t client_id = 0; + uint32_t server_id = 0; + + ret = wh_Client_CommInitRequest(client1); + if (ret != 0) + return ret; + ret = wh_Server_HandleRequestMessage(server1); + if (ret != 0) + return ret; + ret = wh_Client_CommInitResponse(client1, &client_id, &server_id); + if (ret != 0) + return ret; + + ret = wh_Client_CommInitRequest(client2); + if (ret != 0) + return ret; + ret = wh_Server_HandleRequestMessage(server2); + if (ret != 0) + return ret; + ret = wh_Client_CommInitResponse(client2, &client_id, &server_id); + if (ret != 0) + return ret; + + printf("=== Multi-Client Sequential Tests Begin ===\n"); + /* Run test suites that require multiple clients */ +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + WH_TEST_RETURN_ON_FAIL( + _runGlobalKeysTests(client1, server1, client2, server2)); +#endif + + /* Future test suites here */ + + /* Cleanup */ + wh_Client_Cleanup(client1); + wh_Client_Cleanup(client2); + wh_Server_Cleanup(server1); + wh_Server_Cleanup(server2); +#if !defined(WOLFHSM_CFG_NO_CRYPTO) + wc_FreeRng(crypto1->rng); + wc_FreeRng(crypto2->rng); + wolfCrypt_Cleanup(); +#endif + wh_Nvm_Cleanup(nvm); + + printf("=== Multi-Client Sequential Tests Complete ===\n"); + + return 0; +} + +/* ============================================================================ + * PUBLIC API + * ========================================================================== */ + +/* Main entry point for multi-client tests */ +int whTest_MultiClient(void) +{ + return whTest_MultiClientSequential(); +} + +#endif /* WOLFHSM_CFG_ENABLE_CLIENT && WOLFHSM_CFG_ENABLE_SERVER */ diff --git a/test/wh_test_multiclient.h b/test/wh_test_multiclient.h new file mode 100644 index 000000000..c1b39d7e4 --- /dev/null +++ b/test/wh_test_multiclient.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +#ifndef WH_TEST_MULTICLIENT_H_ +#define WH_TEST_MULTICLIENT_H_ + +/** + * @brief Multi-client test framework and test suite + * + * This test module provides a framework for testing features that require + * multiple clients connecting to separate servers sharing a common NVM context. + * + * The framework provides generic setup/teardown for: + * - Two client contexts with separate transport memory configs + * - Two server contexts sharing a single NVM context + * - Shared flash/NVM and crypto initialization + * - Sequential single-threaded test execution using memory transport + * + * Current test suites: + * - Global keys: Tests shared key functionality across multiple clients + * + * Future test suites can be added for features like: + * - Access control policies + * - Shared counter synchronization + * - Cross-client key operations + * + * @return 0 on success, error code on failure + */ +int whTest_MultiClient(void); + +#endif /* WH_TEST_MULTICLIENT_H_ */ diff --git a/test/wh_test_she.c b/test/wh_test_she.c index 7e5777820..64e3cc6a1 100644 --- a/test/wh_test_she.c +++ b/test/wh_test_she.c @@ -523,7 +523,7 @@ static int wh_ClientServer_MemThreadTest(void) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 1, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whClientConfig c_conf[1] = {{ .comm = cc_conf, diff --git a/test/wh_test_wolfcrypt_test.c b/test/wh_test_wolfcrypt_test.c index bf963a0de..50494a9de 100644 --- a/test/wh_test_wolfcrypt_test.c +++ b/test/wh_test_wolfcrypt_test.c @@ -196,7 +196,7 @@ static int wh_ClientServer_MemThreadTest(void) .transport_cb = tccb, .transport_context = (void*)tmcc, .transport_config = (void*)tmcf, - .client_id = 123, + .client_id = WH_TEST_DEFAULT_CLIENT_ID, }}; whClientConfig c_conf[1] = {{ .comm = cc_conf, diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index 87f082ea0..f5ca405fa 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -2485,4 +2485,102 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, #endif /* WOLFHSM_CFG_DMA */ +/* + * @brief Client-side keyId manipulation API + * + * This section defines the client-facing API for working with key identifiers. + * Clients use simple numeric IDs (0-255) with optional flags to indicate + * global or wrapped keys. The server translates these to full internal + * representations with TYPE/USER/ID fields. + * + * Client keyId usage: + * - Regular keys: Simple numeric ID (e.g., 5) + * - Global keys: ID with WH_CLIENT_KEYID_GLOBAL_FLAG set + * - Wrapped keys: ID with WH_CLIENT_KEYID_WRAPPED_FLAG set + * - Wrapped metadata: Must use full WH_MAKE_KEYID() construction including type + * and metadata when populating the ID field in metadata to be wrapped + */ + +/* Client-facing key flags (temporary, stripped by server during translation) */ + +/* Bit 8: Client-to-server signal for global key (shared across all clients) */ +#define WH_CLIENT_KEYID_GLOBAL_FLAG ((whKeyId)0x0100) + +/* Bit 9: Client-to-server signal for wrapped key */ +#define WH_CLIENT_KEYID_WRAPPED_FLAG ((whKeyId)0x0200) + +/* Combined mask of all client-facing flags */ +#define WH_CLIENT_KEYID_FLAGS_MASK \ + (WH_CLIENT_KEYID_GLOBAL_FLAG | WH_CLIENT_KEYID_WRAPPED_FLAG) + +/** + * @brief Mark a key ID as global (shared across all clients) + * + * Sets the global flag in a client keyId to indicate to the server that this + * key should be stored/accessed as a global key. The server will translate this + * to USER=0 encoding. + * + * @param _id The key ID (0-255) + * @return keyId with global flag set + * + * Example: + * whKeyId globalKey = WH_CLIENT_KEYID_MAKE_GLOBAL(5); + * wh_Client_KeyCache(client, globalKey, ...); // Stored as global key + */ +#define WH_CLIENT_KEYID_MAKE_GLOBAL(_id) ((_id) | WH_CLIENT_KEYID_GLOBAL_FLAG) + +/** + * @brief Mark a key ID as wrapped + * + * Sets the wrapped flag in a client keyId to indicate to the server that this + * is a wrapped key identifier. The server will translate this to + * KEYTYPE=WH_KEYTYPE_WRAPPED. + * + * @param _id The key ID (0-255) + * @return keyId with wrapped flag set + * + * Example: + * whKeyId wrappedKey = WH_CLIENT_KEYID_MAKE_WRAPPED(2); + * wh_Client_KeyExportRequest(client, wrappedKey, ...); + */ +#define WH_CLIENT_KEYID_MAKE_WRAPPED(_id) ((_id) | WH_CLIENT_KEYID_WRAPPED_FLAG) + +/** + * @brief Mark a key ID as both global and wrapped + * + * Convenience macro that sets both global and wrapped flags. + * The server will translate this to KEYTYPE=WH_KEYTYPE_WRAPPED, USER=0. + * + * @param _id The key ID (0-255) + * @return keyId with global and wrapped flags set + * + * Example: + * whKeyId globalWrappedKey = WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(2); + * wh_Client_AesSetKeyId(aes, globalWrappedKey); + */ +#define WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(_id) \ + ((_id) | WH_CLIENT_KEYID_GLOBAL_FLAG | WH_CLIENT_KEYID_WRAPPED_FLAG) + +/** + * @brief Construct wrapped key metadata ID with explicit ownership + * + * Creates the full internal keyId representation for wrapped key metadata. + * This is used when constructing the metadata structure that will be + * encrypted in the wrapped key blob. The user field specifies which + * client(s) can unwrap the key. + * + * @param _clientId Client ID that can unwrap (or WH_KEYUSER_GLOBAL for global) + * @param _id The key ID (0-255) + * @return Full keyId with TYPE=WH_KEYTYPE_WRAPPED, USER=_clientId, ID=_id + * + * Example: + * whNvmMetadata meta = { + * .id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(WH_KEYUSER_GLOBAL, 5), + * .len = keySize, + * }; + * wh_Client_KeyWrapRequest(client, ..., &meta, ...); + */ +#define WH_CLIENT_KEYID_MAKE_WRAPPED_META(_clientId, _id) \ + WH_MAKE_KEYID(WH_KEYTYPE_WRAPPED, (_clientId), (_id)) + #endif /* !WOLFHSM_WH_CLIENT_H_ */ diff --git a/wolfhsm/wh_common.h b/wolfhsm/wh_common.h index 7d079d213..74be57a7a 100644 --- a/wolfhsm/wh_common.h +++ b/wolfhsm/wh_common.h @@ -24,54 +24,13 @@ #ifndef WOLFHSM_WH_COMMON_H_ #define WOLFHSM_WH_COMMON_H_ +#include + /* Pick up compile-time configuration */ #include "wolfhsm/wh_settings.h" -#include - -/** Non-volatile counters */ -/* HSM Counter identifier type. */ -typedef uint16_t whCounterId; -#define WH_COUNTER_ID_INVALID ((whCounterId)0) - - -/** Key Management */ -/* HSM key identifier type. Top nibble identifies key type/location */ -typedef uint16_t whKeyId; - -/* KeyId Constants */ -#define WH_KEYID_ERASED 0x0000 -#define WH_KEYID_IDMAX 0xFF - -/* Key Masks */ -#define WH_KEYID_MASK 0x00FF -#define WH_KEYID_SHIFT 0 -#define WH_KEYUSER_MASK 0x0F00 -#define WH_KEYUSER_SHIFT 8 -#define WH_KEYTYPE_MASK 0xF000 -#define WH_KEYTYPE_SHIFT 12 - -/* Macro to construct a keyid */ -#define WH_MAKE_KEYID(_type, _user, _id) \ - ((whKeyId)( \ - (((_type) << WH_KEYTYPE_SHIFT) & WH_KEYTYPE_MASK) | \ - (((_user) << WH_KEYUSER_SHIFT) & WH_KEYUSER_MASK) | \ - (((_id) << WH_KEYID_SHIFT) & WH_KEYID_MASK))) -#define WH_KEYID_TYPE(_kid) (((_kid) & WH_KEYTYPE_MASK) >> WH_KEYTYPE_SHIFT) -#define WH_KEYID_USER(_kid) (((_kid) & WH_KEYUSER_MASK) >> WH_KEYUSER_SHIFT) -#define WH_KEYID_ID(_kid) (((_kid) & WH_KEYID_MASK) >> WH_KEYID_SHIFT) - -#define WH_KEYID_ISERASED(_kid) (WH_KEYID_ID(_kid) == WH_KEYID_ERASED) - -/* Key Types */ -#define WH_KEYTYPE_NVM 0x0 /* Ordinary NvmId. Not a key */ -#define WH_KEYTYPE_CRYPTO 0x1 /* Key for Crypto operations */ -#define WH_KEYTYPE_SHE 0x2 /* SKE keys are AES or CMAC binary arrays */ -#define WH_KEYTYPE_COUNTER 0x3 /* Monotonic counter */ - -/* Convert a keyId to a pointer to be stored in wolfcrypt devctx */ -#define WH_KEYID_TO_DEVCTX(_k) ((void*)((intptr_t)(_k))) -#define WH_DEVCTX_TO_KEYID(_d) ((whKeyId)((intptr_t)(_d))) +/* Key management types and helpers */ +#include "wolfhsm/wh_keyid.h" /** NVM Management */ /* HSM NVM object identifier type. */ diff --git a/wolfhsm/wh_error.h b/wolfhsm/wh_error.h index 35ad26706..c2b7682f1 100644 --- a/wolfhsm/wh_error.h +++ b/wolfhsm/wh_error.h @@ -41,8 +41,8 @@ enum WH_ERROR_ENUM { WH_ERROR_BUFFER_SIZE = -2006, /* Generic buffer size mismatch. Buffer * length is not what was expected */ WH_ERROR_NOHANDLER = -2007, /* No customcb handler registered */ - WH_ERROR_NOTIMPL = -2008, /* Functionality not implemented given the - compile-time configuration */ + WH_ERROR_NOTIMPL = -2008, /* Functionality not implemented given the + compile-time configuration */ /* NVM and keystore specific status returns */ WH_ERROR_LOCKED = -2100, /* Unlock and retry if necessary */ diff --git a/wolfhsm/wh_keyid.h b/wolfhsm/wh_keyid.h new file mode 100644 index 000000000..28831475b --- /dev/null +++ b/wolfhsm/wh_keyid.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2025 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ +/* + * wolfhsm/wh_keyid.h + * + * KeyId type definitions, constants, and helper functions for wolfHSM + */ + +#ifndef WOLFHSM_WH_KEYID_H_ +#define WOLFHSM_WH_KEYID_H_ + +/* Pick up compile-time configuration */ +#include "wolfhsm/wh_settings.h" + +#include + +/** Key Management */ +/* HSM key identifier type. Top nibble identifies key type/location */ +typedef uint16_t whKeyId; + +/* KeyId Constants */ +#define WH_KEYID_ERASED 0x0000 +#define WH_KEYID_IDMAX 0xFF + +/* Key Masks */ +#define WH_KEYID_MASK 0x00FF +#define WH_KEYID_SHIFT 0 +#define WH_KEYUSER_MASK 0x0F00 +#define WH_KEYUSER_SHIFT 8 +#define WH_KEYTYPE_MASK 0xF000 +#define WH_KEYTYPE_SHIFT 12 + +/* Client-facing key flags are defined in wh_client.h: + * - WH_CLIENT_KEYID_GLOBAL_FLAG + * - WH_CLIENT_KEYID_WRAPPED_FLAG + */ + +/* Macro to construct a server-unique keyid */ +#define WH_MAKE_KEYID(_type, _user, _id) \ + ((whKeyId)((((_type) << WH_KEYTYPE_SHIFT) & WH_KEYTYPE_MASK) | \ + (((_user) << WH_KEYUSER_SHIFT) & WH_KEYUSER_MASK) | \ + (((_id) << WH_KEYID_SHIFT) & WH_KEYID_MASK))) +#define WH_KEYID_TYPE(_kid) (((_kid)&WH_KEYTYPE_MASK) >> WH_KEYTYPE_SHIFT) +#define WH_KEYID_USER(_kid) (((_kid)&WH_KEYUSER_MASK) >> WH_KEYUSER_SHIFT) +#define WH_KEYID_ID(_kid) (((_kid)&WH_KEYID_MASK) >> WH_KEYID_SHIFT) + +#define WH_KEYID_ISERASED(_kid) (WH_KEYID_ID(_kid) == WH_KEYID_ERASED) +#define WH_KEYID_ISWRAPPED(_kid) (WH_KEYID_TYPE(_kid) == WH_KEYTYPE_WRAPPED) + +/* Reserve USER=0 for global keys in the internal keyId encoding. + * This is server-internal; clients use WH_CLIENT_KEYID_GLOBAL_FLAG from + * wh_client.h */ +#define WH_KEYUSER_GLOBAL 0 + +/* Key Types */ +#define WH_KEYTYPE_NVM 0x0 /* Ordinary NvmId. Not a key */ +#define WH_KEYTYPE_CRYPTO 0x1 /* Key for Crypto operations */ +#define WH_KEYTYPE_SHE 0x2 /* SKE keys are AES or CMAC binary arrays */ +#define WH_KEYTYPE_COUNTER 0x3 /* Monotonic counter */ +#define WH_KEYTYPE_WRAPPED 0x4 /* Wrapped key metadata */ + +/* Convert a keyId to a pointer to be stored in wolfcrypt devctx */ +#define WH_KEYID_TO_DEVCTX(_k) ((void*)((intptr_t)(_k))) +#define WH_DEVCTX_TO_KEYID(_d) ((whKeyId)((intptr_t)(_d))) + +/** + * @brief Translate client keyId (with flags) to server keyId encoding + * + * Translates client-facing keyId format (ID + flags) to server-internal format + * (TYPE + USER + ID). Client flags are: + * - 0x0100 (bit 8): WH_CLIENT_KEYID_GLOBAL_FLAG → USER = 0 + * - 0x0200 (bit 9): WH_CLIENT_KEYID_WRAPPED_FLAG → TYPE = WH_KEYTYPE_WRAPPED + * + * @param type Key type to use as the TYPE field. Input value is ignored and + * WH_KEYTYPE_WRAPPED is used if the input clientId has the + * WH_CLIENT_KEYID_WRAPPED flag set. + * @param clientId Client identifier to use as USER field + * @param reqId Requested keyId from client (may include flags) + * @return Server-internal keyId with TYPE, USER, and ID fields properly set. + */ +whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, + whKeyId reqId); + +#endif /* !WOLFHSM_WH_KEYID_H_ */ diff --git a/wolfhsm/wh_nvm.h b/wolfhsm/wh_nvm.h index a0c8cefd1..6e911f90e 100644 --- a/wolfhsm/wh_nvm.h +++ b/wolfhsm/wh_nvm.h @@ -42,7 +42,8 @@ #include -#include "wolfhsm/wh_common.h" /* For whNvm types */ +#include "wolfhsm/wh_common.h" /* For whNvm types */ +#include "wolfhsm/wh_server_cache.h" /* For whKeyCacheContext */ typedef struct { int (*Init)(void* context, const void *config); @@ -92,6 +93,9 @@ typedef struct { typedef struct whNvmContext_t { whNvmCb *cb; void* context; +#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_GLOBAL_KEYS) + whKeyCacheContext globalCache; /* Global key cache */ +#endif } whNvmContext; /* Simple helper configuration structure associated with an NVM instance */ diff --git a/wolfhsm/wh_server.h b/wolfhsm/wh_server.h index 664fcd993..000a1307b 100644 --- a/wolfhsm/wh_server.h +++ b/wolfhsm/wh_server.h @@ -38,6 +38,7 @@ typedef struct whServerContext_t whServerContext; #include "wolfhsm/wh_common.h" #include "wolfhsm/wh_comm.h" +#include "wolfhsm/wh_server_cache.h" #include "wolfhsm/wh_nvm.h" #include "wolfhsm/wh_message_customcb.h" #ifdef WOLFHSM_CFG_DMA @@ -62,18 +63,6 @@ typedef struct whServerContext_t whServerContext; #ifndef WOLFHSM_CFG_NO_CRYPTO -/** Server crypto context and resource allocation */ -typedef struct whServerCacheSlot { - uint8_t commited; - whNvmMetadata meta[1]; - uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE]; -} whServerCacheSlot; - -typedef struct whServerBigCacheSlot { - uint8_t commited; - whNvmMetadata meta[1]; - uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE]; -} whServerBigCacheSlot; typedef struct whServerCryptoContext { int devId; @@ -184,8 +173,7 @@ struct whServerContext_t { whCommServer comm[1]; #ifndef WOLFHSM_CFG_NO_CRYPTO whServerCryptoContext* crypto; - whServerCacheSlot cache[WOLFHSM_CFG_SERVER_KEYCACHE_COUNT]; - whServerBigCacheSlot bigCache[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT]; + whKeyCacheContext localCache; /* Unified cache structure */ #ifdef WOLFHSM_CFG_SHE_EXTENSION whServerSheContext* she; #endif diff --git a/wolfhsm/wh_server_cache.h b/wolfhsm/wh_server_cache.h new file mode 100644 index 000000000..3046a8451 --- /dev/null +++ b/wolfhsm/wh_server_cache.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfHSM. + * + * wolfHSM is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfHSM is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with wolfHSM. If not, see . + */ + +/* + * wolfhsm/wh_server_cache.h + * + * Exists as a separate header so it can be consumed by server, server keystore, and NVM + * layer without creating circular dependencies + */ + +#ifndef WOLFHSM_WH_SERVER_CACHE_H_ +#define WOLFHSM_WH_SERVER_CACHE_H_ + +/* Pick up compile-time configuration */ +#include "wolfhsm/wh_settings.h" +#include "wolfhsm/wh_common.h" + +#ifndef WOLFHSM_CFG_NO_CRYPTO + +/** Server cache slot structures */ +typedef struct whServerCacheSlot { + uint8_t committed; + whNvmMetadata meta[1]; + uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE]; +} whServerCacheSlot; + +typedef struct whServerBigCacheSlot { + uint8_t committed; + whNvmMetadata meta[1]; + uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE]; +} whServerBigCacheSlot; + +/** + * @brief Unified key cache context + * + * Holds both regular and big cache arrays. Used for client-local caches + * (embedded in whServerContext) and global caches (embedded in whNvmContext + * when WOLFHSM_CFG_GLOBAL_KEYS is enabled). + */ +typedef struct whKeyCacheContext_t { + whServerCacheSlot cache[WOLFHSM_CFG_SERVER_KEYCACHE_COUNT]; + whServerBigCacheSlot bigCache[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT]; +} whKeyCacheContext; + +#endif /* !WOLFHSM_CFG_NO_CRYPTO */ + +#endif /* !WOLFHSM_WH_SERVER_CACHE_H_ */ diff --git a/wolfhsm/wh_server_keystore.h b/wolfhsm/wh_server_keystore.h index 155cf2a55..267572567 100644 --- a/wolfhsm/wh_server_keystore.h +++ b/wolfhsm/wh_server_keystore.h @@ -49,16 +49,19 @@ int wh_Server_KeystoreGetUniqueId(whServerContext* server, whNvmId* inout_id); * @brief Find an available cache slot for the specified key size * * Searches for an empty slot or a slot with a committed key that can be - * evicted. Returns the slot's buffer (zeroed) and metadata. + * evicted. Returns the slot's buffer (zeroed) and metadata. Routes to the + * appropriate cache (global or local) based on keyId. * * @param[in] server Server context + * @param[in] keyId Key ID (used to route to correct cache) * @param[in] keySz Size of the key in bytes * @param[out] outBuf Pointer to the cache buffer * @param[out] outMeta Pointer to the metadata structure * @return 0 on success, error code on failure */ -int wh_Server_KeystoreGetCacheSlot(whServerContext* server, uint16_t keySz, - uint8_t** outBuf, whNvmMetadata** outMeta); +int wh_Server_KeystoreGetCacheSlot(whServerContext* server, whKeyId keyId, + uint16_t keySz, uint8_t** outBuf, + whNvmMetadata** outMeta); /** * @brief Cache a key in server memory @@ -186,4 +189,16 @@ int wh_Server_KeystoreCacheKeyDma(whServerContext* server, whNvmMetadata* meta, int wh_Server_KeystoreExportKeyDma(whServerContext* server, whKeyId keyId, uint64_t keyAddr, uint64_t keySz, whNvmMetadata* outMeta); + +/** + * @brief Query whether a key identifier refers to wrapped material + * + * @param[in] server Server context (unused, reserved for parity) + * @param[in] keyId Key identifier to inspect + * @param[out] outIsWrapped Optional pointer receiving 1 if wrapped, 0 otherwise + * @return 0 on success, error code on failure + */ +int wh_Server_KeystoreIsWrappedKey(whServerContext* server, whKeyId keyId, + int* outIsWrapped); + #endif /* !WOLFHSM_WH_SERVER_KEYSTORE_H_ */ diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h index 015c2d8b3..f92047d34 100644 --- a/wolfhsm/wh_settings.h +++ b/wolfhsm/wh_settings.h @@ -36,6 +36,10 @@ * WOLFHSM_CFG_SHE_EXTENSION - If defined, include AutoSAR SHE functionality * Default: Not defined * + * WOLFHSM_CFG_GLOBAL_KEYS - If defined, enable global key support allowing + * keys to be shared across multiple clients + * Default: Not defined + * * WOLFHSM_CFG_KEYWRAP - If defined, include the key wrap functionality * Default: Not defined * diff --git a/wolfhsm/wh_transport_mem.h b/wolfhsm/wh_transport_mem.h index 924703d26..032e95185 100644 --- a/wolfhsm/wh_transport_mem.h +++ b/wolfhsm/wh_transport_mem.h @@ -70,7 +70,7 @@ * .transport_cb = tmccb, * .transport_context = tmcc, * .transport_config = tmcfg, - * .client_id = 1234, + * .client_id = 1 * }}; * whCommClient cc[1] = {0}; * wh_CommClient_Init(cc, ccc); @@ -81,7 +81,7 @@ * .transport_cb = tmscb, * .transport_context = tmsc, * .transport_config = tmcfg, - * .server_id = 5678, + * .server_id = 2, * }}; * whCommServer cs[1] = {0}; * wh_CommServer_Init(cs, csc); From e8663e319ef2e8bbd3ff85dc908e2bb1ab3d94d4 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:06:16 -0600 Subject: [PATCH 2/5] support cache probe on freshen --- src/wh_server_keystore.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c index 941543573..a62ef06cf 100644 --- a/src/wh_server_keystore.c +++ b/src/wh_server_keystore.c @@ -527,6 +527,13 @@ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId, ret = _FindInCache(server, keyId, &foundIndex, &foundBigIndex, outBuf, outMeta); if (ret != WH_ERROR_OK) { + /* For wrapped keys, just probe the cache and error if not found. We + * don't support automatically unwrapping and caching outside of the + * keywrap API */ + if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { + return WH_ERROR_NOTFOUND; + } + /* Not in cache. Check if it is in NVM */ ret = wh_Nvm_GetMetadata(server->nvm, keyId, tmpMeta); if (ret == WH_ERROR_OK) { @@ -582,7 +589,9 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId, return 0; } - /* Prevent exposing wrapped blobs through the unwrapped read path */ + /* For wrapped keys, just probe the cache and error if not found. We + * don't support automatically unwrapping and caching outside of the + * keywrap API */ if (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED) { return WH_ERROR_NOTFOUND; } From 37f0c8bfec03d649b6cbab88bb4dd41af8b230dc Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Tue, 28 Oct 2025 15:57:19 -0600 Subject: [PATCH 3/5] keyId flag preservation --- src/wh_keyid.c | 21 +++++++ src/wh_server_cert.c | 10 ++-- src/wh_server_crypto.c | 14 ++--- src/wh_server_keystore.c | 13 ++--- test/wh_test_multiclient.c | 111 +++++++++++++++++++++++++++++++++++++ wolfhsm/wh_keyid.h | 16 ++++++ 6 files changed, 167 insertions(+), 18 deletions(-) diff --git a/src/wh_keyid.c b/src/wh_keyid.c index c2427ced0..031b7daab 100644 --- a/src/wh_keyid.c +++ b/src/wh_keyid.c @@ -46,3 +46,24 @@ whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, return WH_MAKE_KEYID(type, user, id); } + +whKeyId wh_KeyId_ToClient(whKeyId serverId) +{ + whKeyId clientId = WH_KEYID_ID(serverId); + +#ifdef WOLFHSM_CFG_GLOBAL_KEYS + /* Convert USER=0 to global flag (bit 8: 0x0100) */ + if (WH_KEYID_USER(serverId) == WH_KEYUSER_GLOBAL) { + clientId |= 0x0100; /* WH_CLIENT_KEYID_GLOBAL_FLAG */ + } +#endif + +#ifdef WOLFHSM_CFG_KEYWRAP + /* Convert TYPE=WRAPPED to wrapped flag (bit 9: 0x0200) */ + if (WH_KEYID_TYPE(serverId) == WH_KEYTYPE_WRAPPED) { + clientId |= 0x0200; /* WH_CLIENT_KEYID_WRAPPED_FLAG */ + } +#endif + + return clientId; +} diff --git a/src/wh_server_cert.c b/src/wh_server_cert.c index cc66a8842..3fbd47de1 100644 --- a/src/wh_server_cert.c +++ b/src/wh_server_cert.c @@ -497,8 +497,9 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, req.trustedRootNvmId, req.flags, &keyId); - /* Propagate the keyId back to the client */ - resp.keyId = WH_KEYID_ID(keyId); + /* Propagate the keyId back to the client with flags preserved + */ + resp.keyId = wh_KeyId_ToClient(keyId); } /* Convert the response struct */ @@ -626,8 +627,9 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, req.trustedRootNvmId, req.flags, &keyId); - /* Propagate the keyId back to the client */ - resp.keyId = WH_KEYID_ID(keyId); + /* Propagate the keyId back to the client with flags preserved + */ + resp.keyId = wh_KeyId_ToClient(keyId); } if (resp.rc == WH_ERROR_OK) { /* Post-process client address */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index 48a1626a3..fa93cc8de 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -346,7 +346,7 @@ static int _HandleRsaKeyGen(whServerContext* ctx, uint16_t magic, key_id, ret); #endif if (ret == 0) { - res.keyId = WH_KEYID_ID(key_id); + res.keyId = wh_KeyId_ToClient(key_id); res.len = 0; } } @@ -807,7 +807,7 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, } if (ret == WH_ERROR_OK) { - res.keyId = WH_KEYID_ID(key_id); + res.keyId = wh_KeyId_ToClient(key_id); res.len = res_size; wh_MessageCrypto_TranslateEccKeyGenResponse( @@ -1291,7 +1291,7 @@ static int _HandleHkdf(whServerContext* ctx, uint16_t magic, key_id, ret); #endif if (ret == WH_ERROR_OK) { - res.keyIdOut = WH_KEYID_ID(key_id); + res.keyIdOut = wh_KeyId_ToClient(key_id); res.outSz = 0; /* clear the output buffer */ memset(out, 0, outSz); @@ -1391,7 +1391,7 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic, } if (ret == 0) { - res.keyId = WH_KEYID_ID(key_id); + res.keyId = wh_KeyId_ToClient(key_id); res.len = ser_size; /* Translate response */ @@ -2343,7 +2343,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, ret = wh_Server_KeystoreCacheKey( ctx, meta, (uint8_t*)ctx->crypto->algoCtx.cmac); if (ret == 0) { - res.keyId = WH_KEYID_ID(keyId); + res.keyId = wh_KeyId_ToClient(keyId); res.outSz = 0; } } @@ -2788,7 +2788,7 @@ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, } if (ret == WH_ERROR_OK) { - res.keyId = WH_KEYID_ID(key_id); + res.keyId = wh_KeyId_ToClient(key_id); res.len = res_size; wh_MessageCrypto_TranslateMlDsaKeyGenResponse(magic, &res, @@ -3939,7 +3939,7 @@ static int _HandleMlDsaKeyGenDma(whServerContext* ctx, uint16_t magic, __func__, keyId, ret); #endif if (ret == 0) { - res.keyId = WH_KEYID_ID(keyId); + res.keyId = wh_KeyId_ToClient(keyId); res.keySize = keySize; } } diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c index a62ef06cf..da96d2d80 100644 --- a/src/wh_server_keystore.c +++ b/src/wh_server_keystore.c @@ -1114,9 +1114,8 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, return WH_ERROR_ABORTED; } - /* Store the assigned key ID in the response (ID portion only). We should - * NOT return the upper bits back to the client */ - resp->keyId = WH_KEYID_ID(metadata.id); + /* Store the assigned key ID in the response, preserving client flags */ + resp->keyId = wh_KeyId_ToClient(metadata.id); /* Cache the key */ return wh_Server_KeystoreCacheKey(server, &metadata, key); @@ -1181,8 +1180,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = WH_ERROR_OK; } if (ret == WH_ERROR_OK) { - /* remove the client_id, client may set type */ - resp.id = WH_KEYID_ID(meta->id); + /* Translate server keyId back to client format with flags */ + resp.id = wh_KeyId_ToClient(meta->id); (void)wh_MessageKeystore_TranslateCacheResponse( magic, &resp, @@ -1236,8 +1235,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = WH_ERROR_OK; } - /* remove the client_id, client may set type */ - resp.id = WH_KEYID_ID(meta->id); + /* Translate server keyId back to client format with flags */ + resp.id = wh_KeyId_ToClient(meta->id); (void)wh_MessageKeystore_TranslateCacheDmaResponse( magic, &resp, (whMessageKeystore_CacheDmaResponse*)resp_packet); diff --git a/test/wh_test_multiclient.c b/test/wh_test_multiclient.c index c4de85943..134e34753 100644 --- a/test/wh_test_multiclient.c +++ b/test/wh_test_multiclient.c @@ -1227,12 +1227,123 @@ static int _testWrappedKey_LocalWrap_GlobalKey_NonOwnerNoWrapKey( } #endif /* WOLFHSM_CFG_KEYWRAP */ +/* + * Test: KeyId flag preservation + * - Tests that global and wrapped flags are preserved in server responses + * - Verifies keyCache operations return correct flags + */ +static int _testKeyIdFlagPreservation(whClientContext* client1, + whServerContext* server1, + whClientContext* client2, + whServerContext* server2) +{ + (void)client2; + (void)server2; + + printf("Test: KeyId flag preservation\n"); + + /* Test 1: Global key cache preserves global flag */ + { + whKeyId keyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + whKeyId returnedKeyId = 0; + + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"GlobalKeyFlags", sizeof("GlobalKeyFlags"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyCacheResponse(client1, &returnedKeyId)); + + /* Verify global flag is preserved */ + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_CLIENT_KEYID_GLOBAL_FLAG) != + 0); + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_MASK) == DUMMY_KEYID_1); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyEvictRequest(client1, returnedKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Global key cache preserves global flag\n"); + } + + /* Test 2: Local key cache does not have global flag */ + { + whKeyId keyId = DUMMY_KEYID_2; /* Local key - no flags */ + whKeyId returnedKeyId = 0; + + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"LocalKeyFlags", sizeof("LocalKeyFlags"), + (uint8_t*)TEST_KEY_DATA_2, sizeof(TEST_KEY_DATA_2), keyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyCacheResponse(client1, &returnedKeyId)); + + /* Verify no global flag */ + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_CLIENT_KEYID_GLOBAL_FLAG) == + 0); + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_MASK) == DUMMY_KEYID_2); + + /* Clean up */ + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyEvictRequest(client1, returnedKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Local key cache has no global flag\n"); + } + + /* Test 3: Reusing returned keyId works correctly */ + { + whKeyId requestKeyId = WH_CLIENT_KEYID_MAKE_GLOBAL(DUMMY_KEYID_1); + whKeyId returnedKeyId = 0; + uint8_t outBuf[sizeof(TEST_KEY_DATA_1)] = {0}; + uint16_t outSz = sizeof(outBuf); + uint8_t label[WH_NVM_LABEL_LEN]; + uint16_t labelSz = sizeof(label); + + /* Cache a global key and get keyId back */ + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyCacheRequest_ex( + client1, 0, (uint8_t*)"ReuseTest", sizeof("ReuseTest"), + (uint8_t*)TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1), requestKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyCacheResponse(client1, &returnedKeyId)); + + /* Use the returned keyId to export the key (common pattern) */ + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyExportRequest(client1, returnedKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyExportResponse( + client1, label, labelSz, outBuf, &outSz)); + + /* Verify data matches */ + WH_TEST_ASSERT_RETURN(outSz == sizeof(TEST_KEY_DATA_1)); + WH_TEST_ASSERT_RETURN( + 0 == memcmp(outBuf, TEST_KEY_DATA_1, sizeof(TEST_KEY_DATA_1))); + + /* Clean up using returned keyId */ + WH_TEST_RETURN_ON_FAIL( + wh_Client_KeyEvictRequest(client1, returnedKeyId)); + WH_TEST_RETURN_ON_FAIL(wh_Server_HandleRequestMessage(server1)); + WH_TEST_RETURN_ON_FAIL(wh_Client_KeyEvictResponse(client1)); + + printf(" PASS: Reusing returned keyId works correctly\n"); + } + + return 0; +} + /* Helper function to run all global keys tests */ static int _runGlobalKeysTests(whClientContext* client1, whServerContext* server1, whClientContext* client2, whServerContext* server2) { + WH_TEST_RETURN_ON_FAIL( + _testKeyIdFlagPreservation(client1, server1, client2, server2)); + WH_TEST_RETURN_ON_FAIL( _testGlobalKeyBasic(client1, server1, client2, server2)); diff --git a/wolfhsm/wh_keyid.h b/wolfhsm/wh_keyid.h index 28831475b..712a353e7 100644 --- a/wolfhsm/wh_keyid.h +++ b/wolfhsm/wh_keyid.h @@ -97,4 +97,20 @@ typedef uint16_t whKeyId; whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, whKeyId reqId); +/** + * @brief Translate server keyId to client keyId format (with flags) + * + * Translates server-internal keyId format (TYPE + USER + ID) back to + * client-facing format (ID + flags). Server encoding is converted to flags: + * - USER = 0 (WH_KEYUSER_GLOBAL) → 0x0100 (WH_CLIENT_KEYID_GLOBAL_FLAG) + * - TYPE = WH_KEYTYPE_WRAPPED → 0x0200 (WH_CLIENT_KEYID_WRAPPED_FLAG) + * + * This ensures clients can identify global and wrapped keys after they are + * returned from server operations (cache, key generation, etc.). + * + * @param serverId Server-internal keyId with TYPE, USER, and ID fields + * @return Client-facing keyId with ID portion and appropriate flag bits set + */ +whKeyId wh_KeyId_ToClient(whKeyId serverId); + #endif /* !WOLFHSM_WH_KEYID_H_ */ From d026f0c6fdfe38da7525bcfdb7d6b1ca0b8d3712 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Wed, 29 Oct 2025 13:14:29 -0600 Subject: [PATCH 4/5] fixes for NOCRYPTO after scan-build PR --- test/wh_test_multiclient.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/test/wh_test_multiclient.c b/test/wh_test_multiclient.c index 134e34753..8a90ac14b 100644 --- a/test/wh_test_multiclient.c +++ b/test/wh_test_multiclient.c @@ -36,12 +36,6 @@ #include #include -#include "wolfssl/wolfcrypt/settings.h" -#include "wolfssl/wolfcrypt/types.h" -#include "wolfssl/wolfcrypt/rsa.h" -#include "wolfssl/wolfcrypt/ecc.h" -#include "wolfssl/wolfcrypt/asn.h" - #include "wolfhsm/wh_error.h" #include "wolfhsm/wh_comm.h" #include "wolfhsm/wh_message.h" From 4da2aaf6692aea821ed73dcb20a3de49a6d221d6 Mon Sep 17 00:00:00 2001 From: Brett Nicholas <7547222+bigbrett@users.noreply.github.com> Date: Thu, 30 Oct 2025 09:57:48 -0600 Subject: [PATCH 5/5] Review feedback: - Renamed whServerCacheXXX to whKeyCacheXXX - Relocated client global+wrapped flags to wh_keyid.h from wh_client.h - Fixed copyright year - Fixed wh_settings.h include order --- src/wh_keyid.c | 22 ++-- src/wh_server_cert.c | 8 +- src/wh_server_crypto.c | 120 +++++++++---------- src/wh_server_keystore.c | 62 ++++------ test/wh_test_multiclient.c | 4 +- test/wh_test_multiclient.h | 2 +- wolfhsm/wh_client.h | 34 +----- wolfhsm/wh_common.h | 4 +- wolfhsm/{wh_server_cache.h => wh_keycache.h} | 18 +-- wolfhsm/wh_keyid.h | 42 +++++-- wolfhsm/wh_nvm.h | 2 +- wolfhsm/wh_server.h | 2 +- wolfhsm/wh_server_keystore.h | 11 -- 13 files changed, 147 insertions(+), 184 deletions(-) rename wolfhsm/{wh_server_cache.h => wh_keycache.h} (82%) diff --git a/src/wh_keyid.c b/src/wh_keyid.c index 031b7daab..239d615a7 100644 --- a/src/wh_keyid.c +++ b/src/wh_keyid.c @@ -24,22 +24,22 @@ #include "wolfhsm/wh_keyid.h" -whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, - whKeyId reqId) +whKeyId wh_KeyId_TranslateFromClient(uint16_t type, uint16_t clientId, + whKeyId reqId) { uint16_t user = clientId; whKeyId id = reqId & WH_KEYID_MASK; #ifdef WOLFHSM_CFG_GLOBAL_KEYS - /* Check for global flag (bit 8: 0x0100) */ - if ((reqId & 0x0100) != 0) { + /* Convert global flag to USER=0 */ + if ((reqId & WH_KEYID_CLIENT_GLOBAL_FLAG) != 0) { user = WH_KEYUSER_GLOBAL; } #endif #ifdef WOLFHSM_CFG_KEYWRAP - /* Check for wrapped flag (bit 9: 0x0200) */ - if ((reqId & 0x0200) != 0) { + /* Convert wrapped flag to TYPE=WH_KETYPE_WRAPPED */ + if ((reqId & WH_KEYID_CLIENT_WRAPPED_FLAG) != 0) { type = WH_KEYTYPE_WRAPPED; } #endif @@ -47,21 +47,21 @@ whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, return WH_MAKE_KEYID(type, user, id); } -whKeyId wh_KeyId_ToClient(whKeyId serverId) +whKeyId wh_KeyId_TranslateToClient(whKeyId serverId) { whKeyId clientId = WH_KEYID_ID(serverId); #ifdef WOLFHSM_CFG_GLOBAL_KEYS - /* Convert USER=0 to global flag (bit 8: 0x0100) */ + /* Convert USER=0 to global flag */ if (WH_KEYID_USER(serverId) == WH_KEYUSER_GLOBAL) { - clientId |= 0x0100; /* WH_CLIENT_KEYID_GLOBAL_FLAG */ + clientId |= WH_KEYID_CLIENT_GLOBAL_FLAG; } #endif #ifdef WOLFHSM_CFG_KEYWRAP - /* Convert TYPE=WRAPPED to wrapped flag (bit 9: 0x0200) */ + /* Convert TYPE=WRAPPED to wrapped flag */ if (WH_KEYID_TYPE(serverId) == WH_KEYTYPE_WRAPPED) { - clientId |= 0x0200; /* WH_CLIENT_KEYID_WRAPPED_FLAG */ + clientId |= WH_KEYID_CLIENT_WRAPPED_FLAG; } #endif diff --git a/src/wh_server_cert.c b/src/wh_server_cert.c index 3fbd47de1..79d7b5033 100644 --- a/src/wh_server_cert.c +++ b/src/wh_server_cert.c @@ -489,7 +489,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, cert_data = (const uint8_t*)req_packet + sizeof(req); /* Map client keyId to server keyId space */ - whKeyId keyId = wh_KeyId_TranslateClient( + whKeyId keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.keyId); /* Process the verify action */ @@ -499,7 +499,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, /* Propagate the keyId back to the client with flags preserved */ - resp.keyId = wh_KeyId_ToClient(keyId); + resp.keyId = wh_KeyId_TranslateToClient(keyId); } /* Convert the response struct */ @@ -619,7 +619,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, } if (resp.rc == WH_ERROR_OK) { /* Map client keyId to server keyId space */ - whKeyId keyId = wh_KeyId_TranslateClient( + whKeyId keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.keyId); /* Process the verify action */ @@ -629,7 +629,7 @@ int wh_Server_HandleCertRequest(whServerContext* server, uint16_t magic, /* Propagate the keyId back to the client with flags preserved */ - resp.keyId = wh_KeyId_ToClient(keyId); + resp.keyId = wh_KeyId_TranslateToClient(keyId); } if (resp.rc == WH_ERROR_OK) { /* Post-process client address */ diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index fa93cc8de..6713b5f4d 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -287,8 +287,8 @@ static int _HandleRsaKeyGen(whServerContext* ctx, uint16_t magic, long e = req.e; /* Force incoming key_id to have current user/type */ - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint32_t label_size = WH_NVM_LABEL_LEN; @@ -346,7 +346,7 @@ static int _HandleRsaKeyGen(whServerContext* ctx, uint16_t magic, key_id, ret); #endif if (ret == 0) { - res.keyId = wh_KeyId_ToClient(key_id); + res.keyId = wh_KeyId_TranslateToClient(key_id); res.len = 0; } } @@ -386,8 +386,8 @@ static int _HandleRsaFunction( whServerContext* ctx, uint16_t magic, int op_type = (int)(req.opType); uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_RSA_OPTIONS_EVICT); - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); word32 in_len = (word32)(req.inLen); word32 out_len = (word32)(req.outLen); /* in and out are after the fixed size fields */ @@ -471,8 +471,8 @@ static int _HandleRsaGetSize(whServerContext* ctx, uint16_t magic, } /* Extract parameters from translated request */ - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_RSA_GET_SIZE_OPTIONS_EVICT); @@ -738,8 +738,8 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; int curve_id = req.curveId; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint16_t label_size = WH_NVM_LABEL_LEN; @@ -807,7 +807,7 @@ static int _HandleEccKeyGen(whServerContext* ctx, uint16_t magic, } if (ret == WH_ERROR_OK) { - res.keyId = wh_KeyId_ToClient(key_id); + res.keyId = wh_KeyId_TranslateToClient(key_id); res.len = res_size; wh_MessageCrypto_TranslateEccKeyGenResponse( @@ -841,9 +841,9 @@ static int _HandleEccSharedSecret(whServerContext* ctx, uint16_t magic, uint32_t options = req.options; int evict_pub = !!(options & WH_MESSAGE_CRYPTO_ECDH_OPTIONS_EVICTPUB); int evict_prv = !!(options & WH_MESSAGE_CRYPTO_ECDH_OPTIONS_EVICTPRV); - whKeyId pub_key_id = wh_KeyId_TranslateClient( + whKeyId pub_key_id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId); - whKeyId prv_key_id = wh_KeyId_TranslateClient( + whKeyId prv_key_id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId); /* Response message */ @@ -919,8 +919,8 @@ static int _HandleEccSign(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_EccSignRequest); - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); word32 in_len = req.sz; uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_ECCSIGN_OPTIONS_EVICT); @@ -991,8 +991,8 @@ static int _HandleEccVerify(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint32_t options = req.options; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); uint32_t hash_len = req.hashSz; uint32_t sig_len = req.sigSz; uint8_t* req_sig = @@ -1213,9 +1213,9 @@ static int _HandleHkdf(whServerContext* ctx, uint16_t magic, uint32_t saltSz = req.saltSz; uint32_t infoSz = req.infoSz; uint32_t outSz = req.outSz; - whKeyId key_id = wh_KeyId_TranslateClient( + whKeyId key_id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdOut); - whKeyId keyIdIn = wh_KeyId_TranslateClient( + whKeyId keyIdIn = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyIdIn); whNvmFlags flags = req.flags; uint8_t* label = req.label; @@ -1291,7 +1291,7 @@ static int _HandleHkdf(whServerContext* ctx, uint16_t magic, key_id, ret); #endif if (ret == WH_ERROR_OK) { - res.keyIdOut = wh_KeyId_ToClient(key_id); + res.keyIdOut = wh_KeyId_TranslateToClient(key_id); res.outSz = 0; /* clear the output buffer */ memset(out, 0, outSz); @@ -1335,8 +1335,8 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); whNvmFlags flags = req.flags; uint8_t* label = req.label; uint16_t label_size = WH_NVM_LABEL_LEN; @@ -1391,7 +1391,7 @@ static int _HandleCurve25519KeyGen(whServerContext* ctx, uint16_t magic, } if (ret == 0) { - res.keyId = wh_KeyId_ToClient(key_id); + res.keyId = wh_KeyId_TranslateToClient(key_id); res.len = ser_size; /* Translate response */ @@ -1429,9 +1429,9 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic, uint32_t options = req.options; int evict_pub = !!(options & WH_MESSAGE_CRYPTO_CURVE25519_OPTIONS_EVICTPUB); int evict_prv = !!(options & WH_MESSAGE_CRYPTO_CURVE25519_OPTIONS_EVICTPRV); - whKeyId pub_key_id = wh_KeyId_TranslateClient( + whKeyId pub_key_id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.publicKeyId); - whKeyId prv_key_id = wh_KeyId_TranslateClient( + whKeyId prv_key_id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.privateKeyId); int endian = req.endian; @@ -1517,8 +1517,8 @@ static int _HandleAesCtr(whServerContext* ctx, uint16_t magic, if (needed_size > inSize) { return WH_ERROR_BADARGS; } - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_AesCtrRequest); @@ -1634,8 +1634,8 @@ static int _HandleAesEcb(whServerContext* ctx, uint16_t magic, return WH_ERROR_BADARGS; } - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = @@ -1742,8 +1742,8 @@ static int _HandleAesCbc(whServerContext* ctx, uint16_t magic, const void* crypt return WH_ERROR_BADARGS; } - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); /* in, key, iv, and out are after fixed size fields */ uint8_t* in = @@ -1851,8 +1851,8 @@ static int _HandleAesGcm(whServerContext* ctx, uint16_t magic, uint32_t iv_len = req.ivSz; uint32_t authin_len = req.authInSz; uint32_t tag_len = req.authTagSz; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); /* in, key, iv, authin, tag, and out are after fixed size fields */ uint8_t* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_AesGcmRequest); @@ -2075,8 +2075,8 @@ static int _HandleAesGcmDma(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Handle keyId-based keys if no direct key was provided */ if (ret == WH_ERROR_OK && req.key.sz == 0) { - keyId = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + keyId = wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); keyLen = sizeof(tmpKey); ret = wh_Server_KeystoreReadKey(ctx, keyId, NULL, tmpKey, &keyLen); if (ret == WH_ERROR_OK) { @@ -2222,7 +2222,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, * 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_TranslateClient( + keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); ret = wh_Server_KeystoreReadKey( ctx, keyId, NULL, (uint8_t*)ctx->crypto->algoCtx.cmac, @@ -2299,9 +2299,9 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, if (!WH_KEYID_ISERASED(keyId)) { /* Don't override return value except on failure */ int tmpRet = wh_Server_KeystoreEvictKey( - ctx, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, keyId)); + ctx, wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, + keyId)); if (tmpRet != 0) { ret = tmpRet; } @@ -2312,9 +2312,9 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, /* Handle cancellation - evict key and abandon state */ if (!WH_KEYID_ISERASED(req.keyId)) { wh_Server_KeystoreEvictKey( - ctx, wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - req.keyId)); + ctx, wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, + req.keyId)); } } #endif @@ -2330,7 +2330,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, return ret; } else { - keyId = wh_KeyId_TranslateClient( + keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); } /* evict the aes sized key in the normal cache */ @@ -2343,7 +2343,7 @@ static int _HandleCmac(whServerContext* ctx, uint16_t magic, uint16_t seq, ret = wh_Server_KeystoreCacheKey( ctx, meta, (uint8_t*)ctx->crypto->algoCtx.cmac); if (ret == 0) { - res.keyId = wh_KeyId_ToClient(keyId); + res.keyId = wh_KeyId_TranslateToClient(keyId); res.outSz = 0; } } @@ -2716,8 +2716,8 @@ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ int key_size = req.sz; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); int level = req.level; whNvmFlags flags = req.flags; uint8_t* label = req.label; @@ -2788,7 +2788,7 @@ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, } if (ret == WH_ERROR_OK) { - res.keyId = wh_KeyId_ToClient(key_id); + res.keyId = wh_KeyId_TranslateToClient(key_id); res.len = res_size; wh_MessageCrypto_TranslateMlDsaKeyGenResponse(magic, &res, @@ -2830,8 +2830,8 @@ static int _HandleMlDsaSign(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ byte* in = (uint8_t*)(cryptoDataIn) + sizeof(whMessageCrypto_MlDsaSignRequest); - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); word32 in_len = req.sz; uint32_t options = req.options; int evict = !!(options & WH_MESSAGE_CRYPTO_MLDSA_SIGN_OPTIONS_EVICT); @@ -2910,8 +2910,8 @@ static int _HandleMlDsaVerify(whServerContext* ctx, uint16_t magic, /* Extract parameters from translated request */ uint32_t options = req.options; - whKeyId key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, req.keyId); + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); uint32_t hash_len = req.hashSz; uint32_t sig_len = req.sigSz; byte* req_sig = @@ -3911,7 +3911,7 @@ static int _HandleMlDsaKeyGenDma(whServerContext* ctx, uint16_t magic, else { /* Must import the key into the cache and return keyid */ - whKeyId keyId = wh_KeyId_TranslateClient( + whKeyId keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); if (WH_KEYID_ISERASED(keyId)) { @@ -3939,7 +3939,7 @@ static int _HandleMlDsaKeyGenDma(whServerContext* ctx, uint16_t magic, __func__, keyId, ret); #endif if (ret == 0) { - res.keyId = wh_KeyId_ToClient(keyId); + res.keyId = wh_KeyId_TranslateToClient(keyId); res.keySize = keySize; } } @@ -4000,8 +4000,8 @@ static int _HandleMlDsaSignDma(whServerContext* ctx, uint16_t magic, /* Get key ID and evict flag */ - key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, - req.keyId); + key_id = wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); evict = !!(req.options & WH_MESSAGE_CRYPTO_MLDSA_SIGN_OPTIONS_EVICT); /* Initialize key */ @@ -4109,8 +4109,8 @@ static int _HandleMlDsaVerifyDma(whServerContext* ctx, uint16_t magic, int evict = 0; /* Get key ID and evict flag */ - key_id = wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, ctx->comm->client_id, - req.keyId); + key_id = wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + ctx->comm->client_id, req.keyId); evict = !!(req.options & WH_MESSAGE_CRYPTO_MLDSA_VERIFY_OPTIONS_EVICT); /* Initialize key */ @@ -4379,9 +4379,9 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, * 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_TranslateClient(WH_KEYTYPE_CRYPTO, - ctx->comm->client_id, - clientKeyId); + keyId = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, + clientKeyId); keyLen = sizeof(tmpKey); /* Load key from cache */ @@ -4444,7 +4444,7 @@ static int _HandleCmacDma(whServerContext* ctx, uint16_t magic, uint16_t seq, whNvmId nvmId = WH_DEVCTX_TO_KEYID(cmac->devCtx); if (nvmId != WH_KEYID_ERASED) { /* Get key ID from CMAC context */ - keyId = wh_KeyId_TranslateClient( + keyId = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, ctx->comm->client_id, nvmId); keyLen = sizeof(tmpKey); diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c index da96d2d80..898ad4f75 100644 --- a/src/wh_server_keystore.c +++ b/src/wh_server_keystore.c @@ -171,7 +171,7 @@ static int _GetKeyCacheSlot(whKeyCacheContext* ctx, uint16_t keySz, /* Zero slot and return pointers */ if (foundIndex >= 0) { - memset(&ctx->cache[foundIndex], 0, sizeof(whServerCacheSlot)); + memset(&ctx->cache[foundIndex], 0, sizeof(whCacheSlot)); *outBuf = ctx->cache[foundIndex].buffer; *outMeta = ctx->cache[foundIndex].meta; } @@ -197,7 +197,7 @@ static int _GetKeyCacheSlot(whKeyCacheContext* ctx, uint16_t keySz, /* Zero slot and return pointers */ if (foundIndex >= 0) { - memset(&ctx->bigCache[foundIndex], 0, sizeof(whServerBigCacheSlot)); + memset(&ctx->bigCache[foundIndex], 0, sizeof(whBigCacheSlot)); *outBuf = ctx->bigCache[foundIndex].buffer; *outMeta = ctx->bigCache[foundIndex].meta; } @@ -485,26 +485,6 @@ static int _ExistsInCache(whServerContext* server, whKeyId keyId) } #endif /* WOLFHSM_CFG_KEYWRAP */ -#ifdef WOLFHSM_CFG_KEYWRAP -int wh_Server_KeystoreIsWrappedKey(whServerContext* server, whKeyId keyId, - int* outIsWrapped) -{ - int isWrapped; - - if (server == NULL || WH_KEYID_ISERASED(keyId)) { - return WH_ERROR_BADARGS; - } - - (void)server; - isWrapped = (WH_KEYID_TYPE(keyId) == WH_KEYTYPE_WRAPPED); - if (outIsWrapped != NULL) { - *outIsWrapped = isWrapped; - } - - return WH_ERROR_OK; -} -#endif /* WOLFHSM_CFG_KEYWRAP */ - /* try to put the specified key into cache if it isn't already, return pointers * to meta and the cached data*/ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId, @@ -742,8 +722,8 @@ static int _AesGcmWrapKey(whServerContext* server, whKeyId serverKeyId, /* Get the server side key */ ret = wh_Server_KeystoreReadKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, - serverKeyId), + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, + serverKeyId), NULL, serverKey, &serverKeySz); if (ret != WH_ERROR_OK) { return ret; @@ -815,8 +795,8 @@ static int _AesGcmUnwrapKey(whServerContext* server, uint16_t serverKeyId, /* Get the server side key */ ret = wh_Server_KeystoreReadKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, - serverKeyId), + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, server->comm->client_id, + serverKeyId), NULL, serverKey, &serverKeySz); if (ret != WH_ERROR_OK) { return ret; @@ -1115,7 +1095,7 @@ _HandleUnwrapAndCacheKeyRequest(whServerContext* server, } /* Store the assigned key ID in the response, preserving client flags */ - resp->keyId = wh_KeyId_ToClient(metadata.id); + resp->keyId = wh_KeyId_TranslateToClient(metadata.id); /* Cache the key */ return wh_Server_KeystoreCacheKey(server, &metadata, key); @@ -1153,7 +1133,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, in = (uint8_t*)req_packet + sizeof(req); /* set the metadata fields */ - meta->id = wh_KeyId_TranslateClient( + meta->id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.id); meta->access = WH_NVM_ACCESS_ANY; meta->flags = req.flags; @@ -1181,7 +1161,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, } if (ret == WH_ERROR_OK) { /* Translate server keyId back to client format with flags */ - resp.id = wh_KeyId_ToClient(meta->id); + resp.id = wh_KeyId_TranslateToClient(meta->id); (void)wh_MessageKeystore_TranslateCacheResponse( magic, &resp, @@ -1202,7 +1182,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, magic, (whMessageKeystore_CacheDmaRequest*)req_packet, &req); /* set the metadata fields */ - meta->id = wh_KeyId_TranslateClient( + meta->id = wh_KeyId_TranslateFromClient( WH_KEYTYPE_CRYPTO, server->comm->client_id, req.id); meta->access = WH_NVM_ACCESS_ANY; meta->flags = req.flags; @@ -1236,7 +1216,7 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, } /* Translate server keyId back to client format with flags */ - resp.id = wh_KeyId_ToClient(meta->id); + resp.id = wh_KeyId_TranslateToClient(meta->id); (void)wh_MessageKeystore_TranslateCacheDmaResponse( magic, &resp, (whMessageKeystore_CacheDmaResponse*)resp_packet); @@ -1254,8 +1234,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = wh_Server_KeystoreExportKeyDma( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id), + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id), req.key.addr, req.key.sz, meta); resp.rc = ret; /* propagate bad address to client if DMA operation failed */ @@ -1288,8 +1268,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = wh_Server_KeystoreEvictKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; @@ -1320,8 +1300,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, /* read the key */ ret = wh_Server_KeystoreReadKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id), + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id), meta, out, &keySz); /* Check if key is non-exportable */ @@ -1364,8 +1344,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = wh_Server_KeystoreCommitKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; @@ -1391,8 +1371,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic, ret = wh_Server_KeystoreEraseKey( server, - wh_KeyId_TranslateClient(WH_KEYTYPE_CRYPTO, - server->comm->client_id, req.id)); + wh_KeyId_TranslateFromClient(WH_KEYTYPE_CRYPTO, + server->comm->client_id, req.id)); resp.rc = ret; /* TODO: Are there any fatal server errors? */ ret = WH_ERROR_OK; diff --git a/test/wh_test_multiclient.c b/test/wh_test_multiclient.c index 8a90ac14b..d3b3629ad 100644 --- a/test/wh_test_multiclient.c +++ b/test/wh_test_multiclient.c @@ -1249,7 +1249,7 @@ static int _testKeyIdFlagPreservation(whClientContext* client1, wh_Client_KeyCacheResponse(client1, &returnedKeyId)); /* Verify global flag is preserved */ - WH_TEST_ASSERT_RETURN((returnedKeyId & WH_CLIENT_KEYID_GLOBAL_FLAG) != + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_CLIENT_GLOBAL_FLAG) != 0); WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_MASK) == DUMMY_KEYID_1); @@ -1275,7 +1275,7 @@ static int _testKeyIdFlagPreservation(whClientContext* client1, wh_Client_KeyCacheResponse(client1, &returnedKeyId)); /* Verify no global flag */ - WH_TEST_ASSERT_RETURN((returnedKeyId & WH_CLIENT_KEYID_GLOBAL_FLAG) == + WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_CLIENT_GLOBAL_FLAG) == 0); WH_TEST_ASSERT_RETURN((returnedKeyId & WH_KEYID_MASK) == DUMMY_KEYID_2); diff --git a/test/wh_test_multiclient.h b/test/wh_test_multiclient.h index c1b39d7e4..5d2de4cd0 100644 --- a/test/wh_test_multiclient.h +++ b/test/wh_test_multiclient.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2025 wolfSSL Inc. * * This file is part of wolfHSM. * diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h index acaf1f49f..12b02c68a 100644 --- a/wolfhsm/wh_client.h +++ b/wolfhsm/wh_client.h @@ -52,6 +52,7 @@ #ifdef WOLFHSM_CFG_DMA #include "wolfhsm/wh_dma.h" #endif /* WOLFHSM_CFG_DMA */ +#include "wolfhsm/wh_keyid.h" /* Forward declaration of the client structure so its elements can reference @@ -2493,33 +2494,6 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, #endif /* WOLFHSM_CFG_DMA */ -/* - * @brief Client-side keyId manipulation API - * - * This section defines the client-facing API for working with key identifiers. - * Clients use simple numeric IDs (0-255) with optional flags to indicate - * global or wrapped keys. The server translates these to full internal - * representations with TYPE/USER/ID fields. - * - * Client keyId usage: - * - Regular keys: Simple numeric ID (e.g., 5) - * - Global keys: ID with WH_CLIENT_KEYID_GLOBAL_FLAG set - * - Wrapped keys: ID with WH_CLIENT_KEYID_WRAPPED_FLAG set - * - Wrapped metadata: Must use full WH_MAKE_KEYID() construction including type - * and metadata when populating the ID field in metadata to be wrapped - */ - -/* Client-facing key flags (temporary, stripped by server during translation) */ - -/* Bit 8: Client-to-server signal for global key (shared across all clients) */ -#define WH_CLIENT_KEYID_GLOBAL_FLAG ((whKeyId)0x0100) - -/* Bit 9: Client-to-server signal for wrapped key */ -#define WH_CLIENT_KEYID_WRAPPED_FLAG ((whKeyId)0x0200) - -/* Combined mask of all client-facing flags */ -#define WH_CLIENT_KEYID_FLAGS_MASK \ - (WH_CLIENT_KEYID_GLOBAL_FLAG | WH_CLIENT_KEYID_WRAPPED_FLAG) /** * @brief Mark a key ID as global (shared across all clients) @@ -2535,7 +2509,7 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, * whKeyId globalKey = WH_CLIENT_KEYID_MAKE_GLOBAL(5); * wh_Client_KeyCache(client, globalKey, ...); // Stored as global key */ -#define WH_CLIENT_KEYID_MAKE_GLOBAL(_id) ((_id) | WH_CLIENT_KEYID_GLOBAL_FLAG) +#define WH_CLIENT_KEYID_MAKE_GLOBAL(_id) ((_id) | WH_KEYID_CLIENT_GLOBAL_FLAG) /** * @brief Mark a key ID as wrapped @@ -2551,7 +2525,7 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, * whKeyId wrappedKey = WH_CLIENT_KEYID_MAKE_WRAPPED(2); * wh_Client_KeyExportRequest(client, wrappedKey, ...); */ -#define WH_CLIENT_KEYID_MAKE_WRAPPED(_id) ((_id) | WH_CLIENT_KEYID_WRAPPED_FLAG) +#define WH_CLIENT_KEYID_MAKE_WRAPPED(_id) ((_id) | WH_KEYID_CLIENT_WRAPPED_FLAG) /** * @brief Mark a key ID as both global and wrapped @@ -2567,7 +2541,7 @@ int wh_Client_CertVerifyAcertDma(whClientContext* c, const void* cert, * wh_Client_AesSetKeyId(aes, globalWrappedKey); */ #define WH_CLIENT_KEYID_MAKE_WRAPPED_GLOBAL(_id) \ - ((_id) | WH_CLIENT_KEYID_GLOBAL_FLAG | WH_CLIENT_KEYID_WRAPPED_FLAG) + ((_id) | WH_KEYID_CLIENT_GLOBAL_FLAG | WH_KEYID_CLIENT_WRAPPED_FLAG) /** * @brief Construct wrapped key metadata ID with explicit ownership diff --git a/wolfhsm/wh_common.h b/wolfhsm/wh_common.h index 74be57a7a..13bfb995c 100644 --- a/wolfhsm/wh_common.h +++ b/wolfhsm/wh_common.h @@ -24,11 +24,11 @@ #ifndef WOLFHSM_WH_COMMON_H_ #define WOLFHSM_WH_COMMON_H_ -#include - /* Pick up compile-time configuration */ #include "wolfhsm/wh_settings.h" +#include + /* Key management types and helpers */ #include "wolfhsm/wh_keyid.h" diff --git a/wolfhsm/wh_server_cache.h b/wolfhsm/wh_keycache.h similarity index 82% rename from wolfhsm/wh_server_cache.h rename to wolfhsm/wh_keycache.h index 3046a8451..1e0e7795d 100644 --- a/wolfhsm/wh_server_cache.h +++ b/wolfhsm/wh_keycache.h @@ -18,10 +18,10 @@ */ /* - * wolfhsm/wh_server_cache.h + * wolfhsm/wh_keycache.h * - * Exists as a separate header so it can be consumed by server, server keystore, and NVM - * layer without creating circular dependencies + * Exists as a separate header so it can be consumed by server, server keystore, + * and NVM layer without creating circular dependencies */ #ifndef WOLFHSM_WH_SERVER_CACHE_H_ @@ -34,17 +34,17 @@ #ifndef WOLFHSM_CFG_NO_CRYPTO /** Server cache slot structures */ -typedef struct whServerCacheSlot { +typedef struct whCacheSlot { uint8_t committed; whNvmMetadata meta[1]; uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BUFSIZE]; -} whServerCacheSlot; +} whCacheSlot; -typedef struct whServerBigCacheSlot { +typedef struct whBigCacheSlot { uint8_t committed; whNvmMetadata meta[1]; uint8_t buffer[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_BUFSIZE]; -} whServerBigCacheSlot; +} whBigCacheSlot; /** * @brief Unified key cache context @@ -54,8 +54,8 @@ typedef struct whServerBigCacheSlot { * when WOLFHSM_CFG_GLOBAL_KEYS is enabled). */ typedef struct whKeyCacheContext_t { - whServerCacheSlot cache[WOLFHSM_CFG_SERVER_KEYCACHE_COUNT]; - whServerBigCacheSlot bigCache[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT]; + whCacheSlot cache[WOLFHSM_CFG_SERVER_KEYCACHE_COUNT]; + whBigCacheSlot bigCache[WOLFHSM_CFG_SERVER_KEYCACHE_BIG_COUNT]; } whKeyCacheContext; #endif /* !WOLFHSM_CFG_NO_CRYPTO */ diff --git a/wolfhsm/wh_keyid.h b/wolfhsm/wh_keyid.h index 712a353e7..a60056bbd 100644 --- a/wolfhsm/wh_keyid.h +++ b/wolfhsm/wh_keyid.h @@ -46,10 +46,30 @@ typedef uint16_t whKeyId; #define WH_KEYTYPE_MASK 0xF000 #define WH_KEYTYPE_SHIFT 12 -/* Client-facing key flags are defined in wh_client.h: - * - WH_CLIENT_KEYID_GLOBAL_FLAG - * - WH_CLIENT_KEYID_WRAPPED_FLAG +/* + * Client-facing key flags (temporary, stripped by server during translation) + * + * Clients use simple numeric IDs (0-255) with optional flags to indicate + * global or wrapped keys. The server translates these to full internal + * representations with TYPE/USER/ID fields. + + * Client keyId usage: + * - Regular keys: Simple numeric ID (e.g., 5) + * - Global keys: ID with WH_KEYID_CLIENT_GLOBAL_FLAG set + * - Wrapped keys: ID with WH_KEYID_CLIENT_WRAPPED_FLAG set + * - Wrapped metadata: Must use full WH_MAKE_KEYID() construction including type + * and metadata when populating the ID field in metadata to be wrapped + * */ +/* Bit 8: Client-to-server signal for global key (shared across all clients) */ +#define WH_KEYID_CLIENT_GLOBAL_FLAG ((whKeyId)0x0100) + +/* Bit 9: Client-to-server signal for wrapped key */ +#define WH_KEYID_CLIENT_WRAPPED_FLAG ((whKeyId)0x0200) + +/* Combined mask of all client-facing flags */ +#define WH_CLIENT_KEYID_FLAGS_MASK \ + (WH_KEYID_CLIENT_GLOBAL_FLAG | WH_KEYID_CLIENT_WRAPPED_FLAG) /* Macro to construct a server-unique keyid */ #define WH_MAKE_KEYID(_type, _user, _id) \ @@ -64,7 +84,7 @@ typedef uint16_t whKeyId; #define WH_KEYID_ISWRAPPED(_kid) (WH_KEYID_TYPE(_kid) == WH_KEYTYPE_WRAPPED) /* Reserve USER=0 for global keys in the internal keyId encoding. - * This is server-internal; clients use WH_CLIENT_KEYID_GLOBAL_FLAG from + * This is server-internal; clients use WH_KEYID_CLIENT_GLOBAL_FLAG from * wh_client.h */ #define WH_KEYUSER_GLOBAL 0 @@ -84,8 +104,8 @@ typedef uint16_t whKeyId; * * Translates client-facing keyId format (ID + flags) to server-internal format * (TYPE + USER + ID). Client flags are: - * - 0x0100 (bit 8): WH_CLIENT_KEYID_GLOBAL_FLAG → USER = 0 - * - 0x0200 (bit 9): WH_CLIENT_KEYID_WRAPPED_FLAG → TYPE = WH_KEYTYPE_WRAPPED + * - 0x0100 (bit 8): WH_KEYID_CLIENT_GLOBAL_FLAG → USER = 0 + * - 0x0200 (bit 9): WH_KEYID_CLIENT_WRAPPED_FLAG → TYPE = WH_KEYTYPE_WRAPPED * * @param type Key type to use as the TYPE field. Input value is ignored and * WH_KEYTYPE_WRAPPED is used if the input clientId has the @@ -94,16 +114,16 @@ typedef uint16_t whKeyId; * @param reqId Requested keyId from client (may include flags) * @return Server-internal keyId with TYPE, USER, and ID fields properly set. */ -whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, - whKeyId reqId); +whKeyId wh_KeyId_TranslateFromClient(uint16_t type, uint16_t clientId, + whKeyId reqId); /** * @brief Translate server keyId to client keyId format (with flags) * * Translates server-internal keyId format (TYPE + USER + ID) back to * client-facing format (ID + flags). Server encoding is converted to flags: - * - USER = 0 (WH_KEYUSER_GLOBAL) → 0x0100 (WH_CLIENT_KEYID_GLOBAL_FLAG) - * - TYPE = WH_KEYTYPE_WRAPPED → 0x0200 (WH_CLIENT_KEYID_WRAPPED_FLAG) + * - USER = 0 (WH_KEYUSER_GLOBAL) → 0x0100 (WH_KEYID_CLIENT_GLOBAL_FLAG) + * - TYPE = WH_KEYTYPE_WRAPPED → 0x0200 (WH_KEYID_CLIENT_WRAPPED_FLAG) * * This ensures clients can identify global and wrapped keys after they are * returned from server operations (cache, key generation, etc.). @@ -111,6 +131,6 @@ whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId, * @param serverId Server-internal keyId with TYPE, USER, and ID fields * @return Client-facing keyId with ID portion and appropriate flag bits set */ -whKeyId wh_KeyId_ToClient(whKeyId serverId); +whKeyId wh_KeyId_TranslateToClient(whKeyId serverId); #endif /* !WOLFHSM_WH_KEYID_H_ */ diff --git a/wolfhsm/wh_nvm.h b/wolfhsm/wh_nvm.h index 6e911f90e..17d1405fc 100644 --- a/wolfhsm/wh_nvm.h +++ b/wolfhsm/wh_nvm.h @@ -43,7 +43,7 @@ #include #include "wolfhsm/wh_common.h" /* For whNvm types */ -#include "wolfhsm/wh_server_cache.h" /* For whKeyCacheContext */ +#include "wolfhsm/wh_keycache.h" /* For whKeyCacheContext */ typedef struct { int (*Init)(void* context, const void *config); diff --git a/wolfhsm/wh_server.h b/wolfhsm/wh_server.h index 000a1307b..2c3dc02a3 100644 --- a/wolfhsm/wh_server.h +++ b/wolfhsm/wh_server.h @@ -38,7 +38,7 @@ typedef struct whServerContext_t whServerContext; #include "wolfhsm/wh_common.h" #include "wolfhsm/wh_comm.h" -#include "wolfhsm/wh_server_cache.h" +#include "wolfhsm/wh_keycache.h" #include "wolfhsm/wh_nvm.h" #include "wolfhsm/wh_message_customcb.h" #ifdef WOLFHSM_CFG_DMA diff --git a/wolfhsm/wh_server_keystore.h b/wolfhsm/wh_server_keystore.h index 267572567..2cf0d6642 100644 --- a/wolfhsm/wh_server_keystore.h +++ b/wolfhsm/wh_server_keystore.h @@ -190,15 +190,4 @@ int wh_Server_KeystoreExportKeyDma(whServerContext* server, whKeyId keyId, uint64_t keyAddr, uint64_t keySz, whNvmMetadata* outMeta); -/** - * @brief Query whether a key identifier refers to wrapped material - * - * @param[in] server Server context (unused, reserved for parity) - * @param[in] keyId Key identifier to inspect - * @param[out] outIsWrapped Optional pointer receiving 1 if wrapped, 0 otherwise - * @return 0 on success, error code on failure - */ -int wh_Server_KeystoreIsWrappedKey(whServerContext* server, whKeyId keyId, - int* outIsWrapped); - #endif /* !WOLFHSM_WH_SERVER_KEYSTORE_H_ */