Skip to content

Commit 62eea4e

Browse files
authored
Merge pull request #413 from bigbrett/she-wrapped-interop
SHE+keywrap interop
2 parents d873b5e + 0a48012 commit 62eea4e

45 files changed

Lines changed: 5905 additions & 392 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build-and-run-examples.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ jobs:
4343
- name: Build POSIX server
4444
run: |
4545
if [ "${{ matrix.transport }}" = "dma" ]; then
46-
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} DMA=1 make -j WOLFSSL_DIR=../../../wolfssl
46+
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} DMA=1 DEMO_KEK=1 make -j WOLFSSL_DIR=../../../wolfssl
4747
else
48-
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} TLS=${{ env.TLS }} make -j WOLFSSL_DIR=../../../wolfssl
48+
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} TLS=${{ env.TLS }} DEMO_KEK=1 make -j WOLFSSL_DIR=../../../wolfssl
4949
fi
5050
5151
- name: Build POSIX client

docs/src/5-Features.md

Lines changed: 51 additions & 11 deletions
Large diffs are not rendered by default.

examples/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ Set the `WOLFHSM_DIR` and `WOLFSSL_DIR` variables to point to your local install
2525
### Building POSIX server example wh_posix_server
2626
`cd` into `examples/posix/wh_posix_server` and run `make`. Once completed, the output server executable `wh_posix_server.elf` will be located in the `Build` directory.
2727

28+
#### Keywrap demo: DEMO_KEK=1
29+
The client demo suite includes a keywrap demo (enabled by default via `WOLFHSM_CFG_KEYWRAP` in the example configs). It requires the server to hold a trusted Key Encryption Key (KEK), which a client can never create itself. Build the server with `DEMO_KEK=1` to have it provision this KEK (`WH_DEMO_KEYWRAP_KEK_ID`, shared with the server through the demo client header) in its NVM at startup:
30+
31+
```
32+
make DEMO_KEK=1
33+
```
34+
35+
Without it, the keywrap demo fails at `wh_Client_KeyWrap` with `WH_ERROR_NOTFOUND` (-2104) because the KEK it names does not exist on the server.
36+
2837
### Building POSIX client example wh_posix_client
2938
`cd` into `examples/posix/wh_posix_client` and run `make`. Once completed, the output server executable `wh_posix_client.elf` will be located in the `Build` directory.
3039

examples/demo/client/wh_demo_client_keywrap.c

Lines changed: 11 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -37,29 +37,6 @@
3737

3838
#ifdef WOLFHSM_CFG_KEYWRAP
3939

40-
#define WH_DEMO_KEYWRAP_KEKID 1
41-
static int _InitServerKek(whClientContext* ctx)
42-
{
43-
/* IMPORTANT NOTE: Server KEK is typically intrinsic or set during
44-
* provisioning. Uploading the KEK via the client is for testing purposes
45-
* only and not intended as a recommendation */
46-
whKeyId serverKeyId = WH_DEMO_KEYWRAP_KEKID;
47-
whNvmFlags flags = WH_NVM_FLAGS_NONEXPORTABLE | WH_NVM_FLAGS_USAGE_WRAP;
48-
uint8_t label[WH_NVM_LABEL_LEN] = "Server KEK key";
49-
uint8_t kek[] = {0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e,
50-
0x06, 0x6e, 0x19, 0xce, 0x98, 0x44, 0x54, 0x0d,
51-
0x78, 0xa0, 0xbe, 0xe7, 0x35, 0x43, 0x40, 0xa4,
52-
0x22, 0x8a, 0xd1, 0x0e, 0xa3, 0x63, 0x1c, 0x0b};
53-
54-
return wh_Client_KeyCache(ctx, flags, label, sizeof(label), kek,
55-
sizeof(kek), &serverKeyId);
56-
}
57-
58-
static int _CleanupServerKek(whClientContext* ctx)
59-
{
60-
return wh_Client_KeyErase(ctx, WH_DEMO_KEYWRAP_KEKID);
61-
}
62-
6340
#ifndef NO_AES
6441
#ifdef HAVE_AESGCM
6542

@@ -102,26 +79,19 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
10279
0xef, 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad,
10380
0xbe, 0xef, 0xab, 0xad, 0xda, 0xd2};
10481

105-
/* Initialize the server KEK */
106-
107-
/* The key wrap feature requires the server to have a Key Encryption Key
108-
* (I.E. KEK) available for the client to use. In the case of this demo we
109-
* have the client initializing the KEK which is not recommended. Typically
110-
* the KEK ID would be a hard coded value that the client and server share
111-
* and the KEK would be provisioned on the server prior to runtime */
112-
ret = _InitServerKek(client);
113-
if (ret != WH_ERROR_OK) {
114-
WOLFHSM_CFG_PRINTF("Failed to _InitServerKek %d\n", ret);
115-
return ret;
116-
}
82+
/* The keywrap feature requires the server to hold a trusted Key Encryption
83+
* Key (KEK) that the client references by a shared id
84+
* (WH_DEMO_KEYWRAP_KEK_ID). The server must provision it before this demo
85+
* runs (the POSIX example server does so at startup when built with
86+
* DEMO_KEK=1); a client cannot create a trusted KEK itself. */
11787

11888
/* Generating and wrapping a key */
11989

12090
/* Initialize the RNG so we can generate an AES GCM key to wrap */
12191
ret = wc_InitRng_ex(rng, NULL, WH_CLIENT_DEVID(client));
12292
if (ret != 0) {
12393
WOLFHSM_CFG_PRINTF("Failed to wc_InitRng_ex %d\n", ret);
124-
goto cleanup_kek;
94+
return ret;
12595
}
12696

12797
/* Now we generate the AES GCM key using the RNG */
@@ -133,9 +103,9 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
133103

134104
/* Now we request the server to wrap the key using the KEK we
135105
* establish above in the first step. */
136-
ret =
137-
wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEKID, key,
138-
sizeof(key), &metadata, wrappedKey, &wrappedKeySz);
106+
ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEK_ID,
107+
key, sizeof(key), &metadata, wrappedKey,
108+
&wrappedKeySz);
139109
if (ret != 0) {
140110
WOLFHSM_CFG_PRINTF("Failed to wh_Client_KeyWrap %d\n", ret);
141111
goto cleanup_rng;
@@ -151,7 +121,7 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
151121
* This will provide us back a key ID that the client can use to do crypto
152122
* operations */
153123
ret = wh_Client_KeyUnwrapAndCache(client, WC_CIPHER_AES_GCM,
154-
WH_DEMO_KEYWRAP_KEKID, wrappedKey,
124+
WH_DEMO_KEYWRAP_KEK_ID, wrappedKey,
155125
sizeof(wrappedKey), &wrappedKeyId);
156126
if (ret != 0) {
157127
WOLFHSM_CFG_PRINTF("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
@@ -215,7 +185,7 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
215185

216186
/* Request the server to unwrap and export the wrapped key we created */
217187
ret = wh_Client_KeyUnwrapAndExport(
218-
client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEKID, wrappedKey,
188+
client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEK_ID, wrappedKey,
219189
sizeof(wrappedKey), &exportedMetadata, exportedKey, &exportedKeySz);
220190
if (ret != 0) {
221191
WOLFHSM_CFG_PRINTF("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
@@ -242,8 +212,6 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
242212
wh_Client_KeyErase(client, wrappedKeyId);
243213
cleanup_rng:
244214
wc_FreeRng(rng);
245-
cleanup_kek:
246-
_CleanupServerKek(client);
247215

248216
return ret;
249217
}

examples/demo/client/wh_demo_client_keywrap.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@
66
/* Exposed in header so the demo server can obtain the ID for registration */
77
#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8
88

9+
/* Id of the trusted key-encryption key (KEK) the demo names in wrap/unwrap
10+
* requests. A client cannot create a trusted KEK, so the server must
11+
* provision one at this id before the demo runs. Exposed in header so server
12+
* provisioning code uses the same id. */
13+
#define WH_DEMO_KEYWRAP_KEK_ID 9
14+
915
int wh_DemoClient_KeyWrap(whClientContext* clientContext);
1016

1117
#endif /* !DEMO_CLIENT_KEYWRAP_H_ */
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#ifndef WH_DEMO_KEYWRAP_KEK_H_
2+
#define WH_DEMO_KEYWRAP_KEK_H_
3+
4+
#include <stdint.h>
5+
6+
/* Key bytes for the keywrap demo KEK. Server provisioning code stores this as
7+
* a trusted KEK (WH_NVM_FLAGS_TRUSTED) at WH_DEMO_KEYWRAP_KEK_ID before the
8+
* demo runs. */
9+
static const uint8_t whDemoKeywrapKek[32] = {
10+
0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e, 0x06, 0x6e, 0x19,
11+
0xce, 0x98, 0x44, 0x54, 0x0d, 0x78, 0xa0, 0xbe, 0xe7, 0x35, 0x43,
12+
0x40, 0xa4, 0x22, 0x8a, 0xd1, 0x0e, 0xa3, 0x63, 0x1c, 0x0b};
13+
14+
#endif /* !WH_DEMO_KEYWRAP_KEK_H_ */

examples/posix/wh_posix_server/Makefile

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ SHARED_CONFIG_DIR ?= $(PROJECT_DIR)/../
1313
WOLFSSL_DIR ?= ../../../../wolfssl
1414
WOLFHSM_DIR ?= ../../../
1515
WOLFHSM_PORT_DIR ?= $(WOLFHSM_DIR)/port/posix
16+
WOLFHSM_DEMO_CLIENT_DIR ?= $(WOLFHSM_DIR)/examples/demo/client
1617

1718
# Output directory for build files
1819
BUILD_DIR ?= $(PROJECT_DIR)/Build
@@ -23,7 +24,8 @@ INC = -I$(PROJECT_DIR) \
2324
-I$(SHARED_CONFIG_DIR) \
2425
-I$(WOLFSSL_DIR) \
2526
-I$(WOLFHSM_DIR) \
26-
-I$(WOLFHSM_PORT_DIR)
27+
-I$(WOLFHSM_PORT_DIR) \
28+
-I$(WOLFHSM_DEMO_CLIENT_DIR)
2729

2830
# POSIX requires C source be defined before any header
2931
DEF += -D_POSIX_C_SOURCE=200809L
@@ -113,6 +115,12 @@ ifeq ($(DMA),1)
113115
CFLAGS += -DWOLFHSM_CFG_DMA
114116
endif
115117

118+
# Provision the keywrap demo's trusted KEK in NVM. Off by default so the
119+
# client-only test suite sees an empty NVM; enable to run the keywrap demo.
120+
ifeq ($(DEMO_KEK),1)
121+
CFLAGS += -DWH_POSIX_PROVISION_DEMO_KEK
122+
endif
123+
116124
## Source files
117125
# Assembly source files
118126
SRC_ASM +=

examples/posix/wh_posix_server/wh_posix_server_cfg.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,16 @@
1111

1212
#include "wolfhsm/wh_server.h"
1313
#include "wolfhsm/wh_error.h"
14+
#include "wolfhsm/wh_common.h"
1415
#include "wolfhsm/wh_nvm.h"
1516
#include "wolfhsm/wh_nvm_flash.h"
1617
#include "wolfhsm/wh_flash_ramsim.h"
18+
19+
#if defined(WOLFHSM_CFG_KEYWRAP) && defined(WH_POSIX_PROVISION_DEMO_KEK)
20+
/* For the keywrap demo KEK id and key bytes */
21+
#include "wh_demo_client_keywrap.h"
22+
#include "wh_demo_keywrap_kek.h"
23+
#endif
1724
#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
1825
#include "wolfhsm/wh_auth.h"
1926
#include "wolfhsm/wh_auth_base.h"
@@ -641,6 +648,33 @@ int wh_PosixServer_ExampleNvmConfig(void* conf, const char* nvmInitFilePath)
641648
return rc;
642649
}
643650

651+
#if defined(WOLFHSM_CFG_KEYWRAP) && defined(WH_POSIX_PROVISION_DEMO_KEK)
652+
/* Provision the trusted keywrap KEK the demo uses (built with DEMO_KEK=1).
653+
* A client can never create a trusted KEK (it cannot set
654+
* WH_NVM_FLAGS_TRUSTED), so it is provisioned here the way whnvmtool or
655+
* secure boot would on a real device. Gated by a build flag so it stays
656+
* off for the client-only test suite, which asserts the server NVM
657+
* starts empty. */
658+
{
659+
whNvmMetadata kekMeta = {0};
660+
661+
kekMeta.id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, WH_POSIX_CLIENT_ID,
662+
WH_DEMO_KEYWRAP_KEK_ID);
663+
kekMeta.access = WH_NVM_ACCESS_ANY;
664+
kekMeta.flags = WH_NVM_FLAGS_TRUSTED | WH_NVM_FLAGS_USAGE_WRAP |
665+
WH_NVM_FLAGS_NONEXPORTABLE | WH_NVM_FLAGS_NONMODIFIABLE;
666+
kekMeta.len = (whNvmSize)sizeof(whDemoKeywrapKek);
667+
memcpy(kekMeta.label, "keywrap demo KEK", sizeof("keywrap demo KEK"));
668+
669+
rc = wh_Nvm_AddObject(nvm, &kekMeta, kekMeta.len, whDemoKeywrapKek);
670+
if (rc != 0) {
671+
WOLFHSM_CFG_PRINTF("Failed to provision keywrap demo KEK: %d\n",
672+
rc);
673+
return rc;
674+
}
675+
}
676+
#endif /* WOLFHSM_CFG_KEYWRAP && WH_POSIX_PROVISION_DEMO_KEK */
677+
644678
/* Initialize NVM with contents from the NVM init file if provided */
645679
if (nvmInitFilePath != NULL) {
646680
WOLFHSM_CFG_PRINTF("Initializing NVM with contents from %s\n", nvmInitFilePath);

src/wh_client_keywrap.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,110 @@ int wh_Client_KeyWrap(whClientContext* ctx, enum wc_CipherType cipherType,
127127
return ret;
128128
}
129129

130+
int wh_Client_KeyWrapExportRequest(whClientContext* ctx,
131+
enum wc_CipherType cipherType,
132+
uint16_t keyId, uint16_t keyType,
133+
uint16_t serverKeyId)
134+
{
135+
uint16_t group = WH_MESSAGE_GROUP_KEY;
136+
uint16_t action = WH_KEY_KEYWRAPEXPORT;
137+
whMessageKeystore_KeyWrapExportRequest* req = NULL;
138+
139+
if (ctx == NULL) {
140+
return WH_ERROR_BADARGS;
141+
}
142+
143+
/* Set the request pointer to the shared comm data memory region */
144+
req = (whMessageKeystore_KeyWrapExportRequest*)wh_CommClient_GetDataPtr(
145+
ctx->comm);
146+
if (req == NULL) {
147+
return WH_ERROR_BADARGS;
148+
}
149+
150+
/* Initialize the request */
151+
req->keyId = keyId;
152+
req->keyType = keyType;
153+
req->serverKeyId = serverKeyId;
154+
req->cipherType = cipherType;
155+
156+
return wh_Client_SendRequest(ctx, group, action, sizeof(*req),
157+
(uint8_t*)req);
158+
}
159+
160+
int wh_Client_KeyWrapExportResponse(whClientContext* ctx,
161+
enum wc_CipherType cipherType,
162+
void* wrappedKeyOut,
163+
uint16_t* wrappedKeyInOutSz)
164+
{
165+
int ret;
166+
uint16_t group;
167+
uint16_t action;
168+
uint16_t size;
169+
whMessageKeystore_KeyWrapExportResponse* resp = NULL;
170+
uint8_t* respData;
171+
172+
if (ctx == NULL || wrappedKeyOut == NULL || wrappedKeyInOutSz == NULL) {
173+
return WH_ERROR_BADARGS;
174+
}
175+
176+
/* Set the response pointer to the shared comm data memory region */
177+
resp = (whMessageKeystore_KeyWrapExportResponse*)wh_CommClient_GetDataPtr(
178+
ctx->comm);
179+
if (resp == NULL) {
180+
return WH_ERROR_BADARGS;
181+
}
182+
183+
/* Receive the response */
184+
ret = wh_Client_RecvResponse(ctx, &group, &action, &size, (uint8_t*)resp);
185+
if (ret != WH_ERROR_OK) {
186+
return ret;
187+
}
188+
189+
if (group != WH_MESSAGE_GROUP_KEY || action != WH_KEY_KEYWRAPEXPORT ||
190+
size < sizeof(*resp) || size < sizeof(*resp) + resp->wrappedKeySz ||
191+
resp->cipherType != cipherType) {
192+
return WH_ERROR_ABORTED;
193+
}
194+
195+
if (resp->rc != 0) {
196+
return resp->rc;
197+
}
198+
else if (resp->wrappedKeySz > *wrappedKeyInOutSz) {
199+
return WH_ERROR_BUFFER_SIZE;
200+
}
201+
202+
respData = (uint8_t*)(resp + 1);
203+
memcpy(wrappedKeyOut, respData, resp->wrappedKeySz);
204+
*wrappedKeyInOutSz = resp->wrappedKeySz;
205+
206+
return WH_ERROR_OK;
207+
}
208+
209+
int wh_Client_KeyWrapExport(whClientContext* ctx, enum wc_CipherType cipherType,
210+
uint16_t keyId, uint16_t keyType,
211+
uint16_t serverKeyId, void* wrappedKeyOut,
212+
uint16_t* wrappedKeyInOutSz)
213+
{
214+
int ret = WH_ERROR_OK;
215+
216+
if (ctx == NULL || wrappedKeyOut == NULL || wrappedKeyInOutSz == NULL) {
217+
return WH_ERROR_BADARGS;
218+
}
219+
220+
ret = wh_Client_KeyWrapExportRequest(ctx, cipherType, keyId, keyType,
221+
serverKeyId);
222+
if (ret != WH_ERROR_OK) {
223+
return ret;
224+
}
225+
226+
do {
227+
ret = wh_Client_KeyWrapExportResponse(ctx, cipherType, wrappedKeyOut,
228+
wrappedKeyInOutSz);
229+
} while (ret == WH_ERROR_NOTREADY);
230+
231+
return ret;
232+
}
233+
130234
int wh_Client_KeyUnwrapAndExportRequest(whClientContext* ctx,
131235
enum wc_CipherType cipherType,
132236
uint16_t serverKeyId,

src/wh_message_keystore.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,35 @@ int wh_MessageKeystore_TranslateKeyWrapResponse(
386386
return 0;
387387
}
388388

389+
/* Wrap-and-export (by id) Request translation */
390+
int wh_MessageKeystore_TranslateKeyWrapExportRequest(
391+
uint16_t magic, const whMessageKeystore_KeyWrapExportRequest* src,
392+
whMessageKeystore_KeyWrapExportRequest* dest)
393+
{
394+
if ((src == NULL) || (dest == NULL)) {
395+
return WH_ERROR_BADARGS;
396+
}
397+
WH_T16(magic, dest, src, keyId);
398+
WH_T16(magic, dest, src, keyType);
399+
WH_T16(magic, dest, src, serverKeyId);
400+
WH_T16(magic, dest, src, cipherType);
401+
return 0;
402+
}
403+
404+
/* Wrap-and-export (by id) Response translation */
405+
int wh_MessageKeystore_TranslateKeyWrapExportResponse(
406+
uint16_t magic, const whMessageKeystore_KeyWrapExportResponse* src,
407+
whMessageKeystore_KeyWrapExportResponse* dest)
408+
{
409+
if ((src == NULL) || (dest == NULL)) {
410+
return WH_ERROR_BADARGS;
411+
}
412+
WH_T32(magic, dest, src, rc);
413+
WH_T16(magic, dest, src, wrappedKeySz);
414+
WH_T16(magic, dest, src, cipherType);
415+
return 0;
416+
}
417+
389418
/* Key Unwrap Request translation */
390419
int wh_MessageKeystore_TranslateKeyUnwrapAndExportRequest(
391420
uint16_t magic, const whMessageKeystore_KeyUnwrapAndExportRequest* src,

0 commit comments

Comments
 (0)