Skip to content

Commit 47be55b

Browse files
committed
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
1 parent 8ac56d7 commit 47be55b

37 files changed

+2603
-441
lines changed

benchmark/wh_bench.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252

5353
#if defined(WOLFHSM_CFG_BENCH_ENABLE)
5454

55+
/* Default client ID for benchmarks */
56+
#define WH_BENCH_CLIENT_ID (1)
57+
5558
/* Buffer sizes for transport */
5659
/* Large enough to handle an RSA 4096 key */
5760
#define BUFFER_SIZE \
@@ -815,7 +818,7 @@ static whCommClientConfig g_mem_cc_conf = {
815818
.transport_cb = &g_mem_tccb,
816819
.transport_context = (void*)&g_mem_tmcc,
817820
.transport_config = (void*)&g_mem_tmcf,
818-
.client_id = 123,
821+
.client_id = WH_BENCH_CLIENT_ID,
819822
};
820823

821824
static whTransportServerCb g_mem_tscb = WH_TRANSPORT_MEM_SERVER_CB;
@@ -867,7 +870,7 @@ static int _configureClientTransport(whBenchTransportType transport,
867870
.transport_cb = pttcClientShmCb,
868871
.transport_context = (void*)&tccShm,
869872
.transport_config = (void*)&myshmconfig,
870-
.client_id = 12,
873+
.client_id = WH_BENCH_CLIENT_ID,
871874
};
872875

873876
memset(&tccShm, 0, sizeof(posixTransportShmClientContext));
@@ -887,7 +890,7 @@ static int _configureClientTransport(whBenchTransportType transport,
887890
.transport_cb = &pttcClientTcpCb,
888891
.transport_context = (void*)&tccTcp,
889892
.transport_config = (void*)&mytcpconfig,
890-
.client_id = 12,
893+
.client_id = WH_BENCH_CLIENT_ID,
891894
};
892895

893896
memset(&tccTcp, 0, sizeof(posixTransportTcpClientContext));

examples/demo/client/wh_demo_client_keywrap.c

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@
3535

3636
#ifdef WOLFHSM_CFG_KEYWRAP
3737

38-
#define WH_TEST_KEKID 1
38+
#define WH_DEMO_KEYWRAP_KEKID 1
3939
static int _InitServerKek(whClientContext* ctx)
4040
{
4141
/* IMPORTANT NOTE: Server KEK is typically intrinsic or set during
4242
* provisioning. Uploading the KEK via the client is for testing purposes
4343
* only and not intended as a recommendation */
44-
whKeyId serverKeyId = WH_TEST_KEKID;
44+
whKeyId serverKeyId = WH_DEMO_KEYWRAP_KEKID;
4545
whNvmFlags flags = WH_NVM_FLAGS_NONEXPORTABLE;
4646
uint8_t label[WH_NVM_LABEL_LEN] = "Server KEK key";
4747
uint8_t kek[] = {0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e,
@@ -55,43 +55,44 @@ static int _InitServerKek(whClientContext* ctx)
5555

5656
static int _CleanupServerKek(whClientContext* ctx)
5757
{
58-
return wh_Client_KeyErase(ctx, WH_TEST_KEKID);
58+
return wh_Client_KeyErase(ctx, WH_DEMO_KEYWRAP_KEKID);
5959
}
6060

6161
#ifndef NO_AES
6262
#ifdef HAVE_AESGCM
6363

64-
#define WH_TEST_AES_KEYSIZE 16
65-
#define WH_TEST_AES_TEXTSIZE 16
66-
#define WH_TEST_AES_IVSIZE 12
67-
#define WH_TEST_AES_TAGSIZE 16
68-
#define WH_TEST_AES_WRAPPED_KEYSIZE \
69-
(WH_TEST_AES_IVSIZE + WH_TEST_AES_TAGSIZE + WH_TEST_AES_KEYSIZE + \
70-
sizeof(whNvmMetadata))
71-
#define WH_TEST_AESGCM_WRAPKEY_ID 8
64+
#define WH_DEMO_KEYWRAP_AES_KEYSIZE 16
65+
#define WH_DEMO_KEYWRAP_AES_TEXTSIZE 16
66+
#define WH_DEMO_KEYWRAP_AES_IVSIZE 12
67+
#define WH_DEMO_KEYWRAP_AES_TAGSIZE 16
68+
#define WH_DEMO_KEYWRAP_AES_WRAPPED_KEYSIZE \
69+
(WH_DEMO_KEYWRAP_AES_IVSIZE + WH_DEMO_KEYWRAP_AES_TAGSIZE + \
70+
WH_DEMO_KEYWRAP_AES_KEYSIZE + sizeof(whNvmMetadata))
71+
#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8
7272

7373
int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
7474
{
7575
int ret = 0;
7676
Aes aes[1];
7777
WC_RNG rng[1];
78-
uint8_t key[WH_TEST_AES_KEYSIZE];
79-
uint8_t exportedKey[WH_TEST_AES_KEYSIZE];
78+
uint8_t key[WH_DEMO_KEYWRAP_AES_KEYSIZE];
79+
uint8_t exportedKey[WH_DEMO_KEYWRAP_AES_KEYSIZE];
8080
whNvmMetadata metadata = {
81-
.id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, 0, WH_TEST_AESGCM_WRAPKEY_ID),
82-
.label = "AES Key Label",
81+
.id = WH_CLIENT_KEYID_MAKE_WRAPPED_META(
82+
client->comm->client_id, WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID),
83+
.label = "AES Key Label",
8384
.access = WH_NVM_ACCESS_ANY,
84-
.len = WH_TEST_AES_KEYSIZE};
85+
.len = WH_DEMO_KEYWRAP_AES_KEYSIZE};
8586
whNvmMetadata exportedMetadata;
86-
uint8_t wrappedKey[WH_TEST_AES_WRAPPED_KEYSIZE];
87+
uint8_t wrappedKey[WH_DEMO_KEYWRAP_AES_WRAPPED_KEYSIZE];
8788
whKeyId wrappedKeyId;
8889

8990
const uint8_t plaintext[] = "hello, wolfSSL AES-GCM!";
9091
uint8_t ciphertext[sizeof(plaintext)];
9192
uint8_t decrypted[sizeof(plaintext)];
9293

93-
uint8_t tag[WH_TEST_AES_TAGSIZE];
94-
uint8_t iv[WH_TEST_AES_IVSIZE];
94+
uint8_t tag[WH_DEMO_KEYWRAP_AES_TAGSIZE];
95+
uint8_t iv[WH_DEMO_KEYWRAP_AES_IVSIZE];
9596
const uint8_t aad[] = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe,
9697
0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
9798
0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2};
@@ -127,8 +128,8 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
127128

128129
/* Now we request the server to wrap the key using the KEK we
129130
* establish above in the first step. */
130-
ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID, key,
131-
sizeof(key), &metadata, wrappedKey,
131+
ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEKID,
132+
key, sizeof(key), &metadata, wrappedKey,
132133
sizeof(wrappedKey));
133134
if (ret != 0) {
134135
printf("Failed to wh_Client_KeyWrap %d\n", ret);
@@ -144,9 +145,9 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
144145
/* Request the server to unwrap and cache the wrapped key we just created.
145146
* This will provide us back a key ID that the client can use to do crypto
146147
* operations */
147-
ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID,
148-
wrappedKey, sizeof(wrappedKey),
149-
&wrappedKeyId);
148+
ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM,
149+
WH_DEMO_KEYWRAP_KEKID, wrappedKey,
150+
sizeof(wrappedKey), &wrappedKeyId);
150151
if (ret != 0) {
151152
printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
152153
goto cleanup_rng;
@@ -161,7 +162,8 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
161162

162163
/* Set the key id for this AES context to the wrapped key ID that the server
163164
* provided us */
164-
ret = wh_Client_AesSetKeyId(aes, wrappedKeyId);
165+
ret =
166+
wh_Client_AesSetKeyId(aes, WH_CLIENT_KEYID_MAKE_WRAPPED(wrappedKeyId));
165167
if (ret != 0) {
166168
printf("Failed to wh_Client_AesSetKeyId %d\n", ret);
167169
goto cleanup_aes;
@@ -207,12 +209,12 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
207209
/* Exporting a wrapped key */
208210

209211
/* Request the server to unwrap and export the wrapped key we created */
210-
ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID,
211-
wrappedKey, sizeof(wrappedKey),
212-
&exportedMetadata, exportedKey,
213-
sizeof(exportedKey));
212+
ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM,
213+
WH_DEMO_KEYWRAP_KEKID, wrappedKey,
214+
sizeof(wrappedKey), &exportedMetadata,
215+
exportedKey, sizeof(exportedKey));
214216
if (ret != 0) {
215-
printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
217+
printf("Failed to wh_Client_KeyUnwrapAndExport%d\n", ret);
216218
goto cleanup_aes;
217219
}
218220

examples/demo/client/wh_demo_client_keywrap.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
#include "wolfhsm/wh_client.h"
55

6+
/* Exposed in header so the demo server can obtain the ID for registration */
7+
#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8
8+
69
int wh_DemoClient_KeyWrap(whClientContext* clientContext);
710

811
#endif /* !DEMO_CLIENT_KEYWRAP_H_ */

examples/posix/wh_posix_client/wh_posix_client.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ static int wh_ClientTask(void* cf, const char* type, int test)
6969

7070
ret = wh_Client_Init(client, config);
7171

72+
if (ret == 0) {
73+
ret = wh_Client_CommInit(client, NULL, NULL);
74+
if (ret != 0) {
75+
printf("Failed to initialize client communication\n");
76+
return -1;
77+
}
78+
}
79+
7280
if (strcmp(type, "dma") == 0) {
7381
#ifdef WOLFSSL_STATIC_MEMORY
7482
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)
8593

8694
printf("Client connecting to server...\n");
8795
if (ret == 0 && test) {
96+
printf("Running client demos...\n");
8897
return wh_DemoClient_All(client);
8998
}
9099

examples/posix/wh_posix_client/wolfhsm_cfg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@
3030
#define WOLFHSM_CFG_HEXDUMP
3131
#define WOLFHSM_CFG_COMM_DATA_LEN 5000
3232
#define WOLFHSM_CFG_KEYWRAP
33+
#define WOLFHSM_CFG_GLOBAL_KEYS
3334

3435
#endif /* WOLFHSM_CFG_H_ */

examples/posix/wh_posix_server/wh_posix_server.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,6 @@ static int loadAndStoreKeys(whServerContext* server, whKeyId* outKeyId,
118118
return ret;
119119
}
120120

121-
122121
static int wh_ServerTask(void* cf, const char* keyFilePath, int keyId,
123122
int clientId)
124123
{

examples/posix/wh_posix_server/wolfhsm_cfg.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,11 @@
4444
#define WOLFHSM_CFG_CERTIFICATE_MANAGER
4545
#define WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT
4646

47+
#define WOLFHSM_CFG_KEYWRAP
4748
#define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 5000
4849

50+
#define WOLFHSM_CFG_GLOBAL_KEYS
51+
4952
#define XMEMFENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST)
50-
#define WOLFHSM_CFG_KEYWRAP
5153

5254
#endif /* WOLFHSM_CFG_H_ */

src/wh_client_keywrap.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,13 +185,16 @@ int wh_Client_KeyUnwrapAndExportResponse(whClientContext* ctx,
185185
if (group != WH_MESSAGE_GROUP_KEY || action != WH_KEY_UNWRAPEXPORT ||
186186
size < sizeof(*resp) ||
187187
size > sizeof(*resp) + sizeof(*metadataOut) + keySz ||
188-
resp->keySz != keySz || resp->cipherType != cipherType) {
188+
resp->cipherType != cipherType) {
189189
return WH_ERROR_ABORTED;
190190
}
191191

192-
if (resp->rc != 0) {
192+
if (resp->rc != WH_ERROR_OK) {
193193
return resp->rc;
194194
}
195+
else if (resp->keySz != keySz) {
196+
return WH_ERROR_BUFFER_SIZE;
197+
}
195198

196199
/* Copy the metadata and key from the response data into metadataOut and
197200
* keyOut */
@@ -298,6 +301,8 @@ int wh_Client_KeyUnwrapAndCacheResponse(whClientContext* ctx,
298301
return resp->rc;
299302
}
300303

304+
/* Server returns ID portion only. Client must track ownership
305+
* and specify appropriate flags when later using the key. */
301306
*keyIdOut = resp->keyId;
302307

303308
return WH_ERROR_OK;

src/wh_keyid.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (C) 2025 wolfSSL Inc.
3+
*
4+
* This file is part of wolfHSM.
5+
*
6+
* wolfHSM is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* wolfHSM is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with wolfHSM. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
/*
20+
* src/wh_keyid.c
21+
*
22+
* KeyId helper function implementations for wolfHSM
23+
*/
24+
25+
#include "wolfhsm/wh_keyid.h"
26+
27+
whKeyId wh_KeyId_TranslateClient(uint16_t type, uint16_t clientId,
28+
whKeyId reqId)
29+
{
30+
uint16_t user = clientId;
31+
whKeyId id = reqId & WH_KEYID_MASK;
32+
33+
#ifdef WOLFHSM_CFG_GLOBAL_KEYS
34+
/* Check for global flag (bit 8: 0x0100) */
35+
if ((reqId & 0x0100) != 0) {
36+
user = WH_KEYUSER_GLOBAL;
37+
}
38+
#endif
39+
40+
#ifdef WOLFHSM_CFG_KEYWRAP
41+
/* Check for wrapped flag (bit 9: 0x0200) */
42+
if ((reqId & 0x0200) != 0) {
43+
type = WH_KEYTYPE_WRAPPED;
44+
}
45+
#endif
46+
47+
return WH_MAKE_KEYID(type, user, id);
48+
}

src/wh_nvm.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ int wh_Nvm_Init(whNvmContext* context, const whNvmConfig *config)
4646
context->cb = config->cb;
4747
context->context = config->context;
4848

49+
#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_GLOBAL_KEYS)
50+
/* Initialize the global key cache */
51+
memset(&context->globalCache, 0, sizeof(context->globalCache));
52+
#endif
53+
4954
if (context->cb->Init != NULL) {
5055
rc = context->cb->Init(context->context, config->config);
5156
if (rc != 0) {
@@ -64,6 +69,11 @@ int wh_Nvm_Cleanup(whNvmContext* context)
6469
return WH_ERROR_BADARGS;
6570
}
6671

72+
#if !defined(WOLFHSM_CFG_NO_CRYPTO) && defined(WOLFHSM_CFG_GLOBAL_KEYS)
73+
/* Initialize the global key cache */
74+
memset(&context->globalCache, 0, sizeof(context->globalCache));
75+
#endif
76+
6777
/* No callback? Return ABORTED */
6878
if (context->cb->Cleanup == NULL) {
6979
return WH_ERROR_ABORTED;

0 commit comments

Comments
 (0)