Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-and-run-examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ jobs:
- name: Build POSIX server
run: |
if [ "${{ matrix.transport }}" = "dma" ]; then
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} DMA=1 make -j WOLFSSL_DIR=../../../wolfssl
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} DMA=1 DEMO_KEK=1 make -j WOLFSSL_DIR=../../../wolfssl
else
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} TLS=${{ env.TLS }} make -j WOLFSSL_DIR=../../../wolfssl
cd examples/posix/wh_posix_server && ${{ matrix.asan }} ${{ matrix.debug }} ${{ matrix.auth }} TLS=${{ env.TLS }} DEMO_KEK=1 make -j WOLFSSL_DIR=../../../wolfssl
fi

- name: Build POSIX client
Expand Down
59 changes: 49 additions & 10 deletions docs/src/5-Features.md

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ Set the `WOLFHSM_DIR` and `WOLFSSL_DIR` variables to point to your local install
### Building POSIX server example wh_posix_server
`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.

#### Keywrap demo: DEMO_KEK=1
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:

```
make DEMO_KEK=1
```

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.

### Building POSIX client example wh_posix_client
`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.

Expand Down
54 changes: 11 additions & 43 deletions examples/demo/client/wh_demo_client_keywrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,6 @@

#ifdef WOLFHSM_CFG_KEYWRAP

#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_DEMO_KEYWRAP_KEKID;
whNvmFlags flags = WH_NVM_FLAGS_NONEXPORTABLE | WH_NVM_FLAGS_USAGE_WRAP;
uint8_t label[WH_NVM_LABEL_LEN] = "Server KEK key";
uint8_t kek[] = {0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e,
0x06, 0x6e, 0x19, 0xce, 0x98, 0x44, 0x54, 0x0d,
0x78, 0xa0, 0xbe, 0xe7, 0x35, 0x43, 0x40, 0xa4,
0x22, 0x8a, 0xd1, 0x0e, 0xa3, 0x63, 0x1c, 0x0b};

return wh_Client_KeyCache(ctx, flags, label, sizeof(label), kek,
sizeof(kek), &serverKeyId);
}

static int _CleanupServerKek(whClientContext* ctx)
{
return wh_Client_KeyErase(ctx, WH_DEMO_KEYWRAP_KEKID);
}

#ifndef NO_AES
#ifdef HAVE_AESGCM

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

/* Initialize the server KEK */

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

/* Generating and wrapping a key */

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

/* Now we generate the AES GCM key using the RNG */
Expand All @@ -133,9 +103,9 @@ 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_DEMO_KEYWRAP_KEKID, key,
sizeof(key), &metadata, wrappedKey, &wrappedKeySz);
ret = wh_Client_KeyWrap(client, WC_CIPHER_AES_GCM, WH_DEMO_KEYWRAP_KEK_ID,
key, sizeof(key), &metadata, wrappedKey,
&wrappedKeySz);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wh_Client_KeyWrap %d\n", ret);
goto cleanup_rng;
Expand All @@ -151,7 +121,7 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
* 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_DEMO_KEYWRAP_KEKID, wrappedKey,
WH_DEMO_KEYWRAP_KEK_ID, wrappedKey,
sizeof(wrappedKey), &wrappedKeyId);
if (ret != 0) {
WOLFHSM_CFG_PRINTF("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
Expand Down Expand Up @@ -215,7 +185,7 @@ int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)

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

return ret;
}
Expand Down
6 changes: 6 additions & 0 deletions examples/demo/client/wh_demo_client_keywrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
/* Exposed in header so the demo server can obtain the ID for registration */
#define WH_DEMO_KEYWRAP_AESGCM_WRAPKEY_ID 8

/* Id of the trusted key-encryption key (KEK) the demo names in wrap/unwrap
* requests. A client cannot create a trusted KEK, so the server must
* provision one at this id before the demo runs. Exposed in header so server
* provisioning code uses the same id. */
#define WH_DEMO_KEYWRAP_KEK_ID 9

int wh_DemoClient_KeyWrap(whClientContext* clientContext);

#endif /* !DEMO_CLIENT_KEYWRAP_H_ */
14 changes: 14 additions & 0 deletions examples/demo/client/wh_demo_keywrap_kek.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef WH_DEMO_KEYWRAP_KEK_H_
#define WH_DEMO_KEYWRAP_KEK_H_

#include <stdint.h>

/* Key bytes for the keywrap demo KEK. Server provisioning code stores this as
* a trusted KEK (WH_NVM_FLAGS_KEK) at WH_DEMO_KEYWRAP_KEK_ID before the demo
* runs. */
static const uint8_t whDemoKeywrapKek[32] = {
0x03, 0x03, 0x0d, 0xd9, 0xeb, 0x18, 0x17, 0x2e, 0x06, 0x6e, 0x19,
0xce, 0x98, 0x44, 0x54, 0x0d, 0x78, 0xa0, 0xbe, 0xe7, 0x35, 0x43,
0x40, 0xa4, 0x22, 0x8a, 0xd1, 0x0e, 0xa3, 0x63, 0x1c, 0x0b};

#endif /* !WH_DEMO_KEYWRAP_KEK_H_ */
10 changes: 9 additions & 1 deletion examples/posix/wh_posix_server/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ SHARED_CONFIG_DIR ?= $(PROJECT_DIR)/../
WOLFSSL_DIR ?= ../../../../wolfssl
WOLFHSM_DIR ?= ../../../
WOLFHSM_PORT_DIR ?= $(WOLFHSM_DIR)/port/posix
WOLFHSM_DEMO_CLIENT_DIR ?= $(WOLFHSM_DIR)/examples/demo/client

# Output directory for build files
BUILD_DIR ?= $(PROJECT_DIR)/Build
Expand All @@ -23,7 +24,8 @@ INC = -I$(PROJECT_DIR) \
-I$(SHARED_CONFIG_DIR) \
-I$(WOLFSSL_DIR) \
-I$(WOLFHSM_DIR) \
-I$(WOLFHSM_PORT_DIR)
-I$(WOLFHSM_PORT_DIR) \
-I$(WOLFHSM_DEMO_CLIENT_DIR)

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

# Provision the keywrap demo's trusted KEK in NVM. Off by default so the
# client-only test suite sees an empty NVM; enable to run the keywrap demo.
ifeq ($(DEMO_KEK),1)
CFLAGS += -DWH_POSIX_PROVISION_DEMO_KEK
endif

## Source files
# Assembly source files
SRC_ASM +=
Expand Down
33 changes: 33 additions & 0 deletions examples/posix/wh_posix_server/wh_posix_server_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@

#include "wolfhsm/wh_server.h"
#include "wolfhsm/wh_error.h"
#include "wolfhsm/wh_common.h"
#include "wolfhsm/wh_nvm.h"
#include "wolfhsm/wh_nvm_flash.h"
#include "wolfhsm/wh_flash_ramsim.h"

#if defined(WOLFHSM_CFG_KEYWRAP) && defined(WH_POSIX_PROVISION_DEMO_KEK)
/* For the keywrap demo KEK id and key bytes */
#include "wh_demo_client_keywrap.h"
#include "wh_demo_keywrap_kek.h"
#endif
#ifdef WOLFHSM_CFG_ENABLE_AUTHENTICATION
#include "wolfhsm/wh_auth.h"
#include "wolfhsm/wh_auth_base.h"
Expand Down Expand Up @@ -641,6 +648,32 @@ int wh_PosixServer_ExampleNvmConfig(void* conf, const char* nvmInitFilePath)
return rc;
}

#if defined(WOLFHSM_CFG_KEYWRAP) && defined(WH_POSIX_PROVISION_DEMO_KEK)
/* Provision the trusted keywrap KEK the demo uses (built with DEMO_KEK=1).
* A client can never create a trusted KEK (it cannot set WH_NVM_FLAGS_KEK),
* so it is provisioned here the way whnvmtool or secure boot would on a
* real device. Gated by a build flag so it stays off for the client-only
* test suite, which asserts the server NVM starts empty. */
{
whNvmMetadata kekMeta = {0};

kekMeta.id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, WH_POSIX_CLIENT_ID,
WH_DEMO_KEYWRAP_KEK_ID);
kekMeta.access = WH_NVM_ACCESS_ANY;
kekMeta.flags = WH_NVM_FLAGS_KEK | WH_NVM_FLAGS_USAGE_WRAP |
WH_NVM_FLAGS_NONEXPORTABLE | WH_NVM_FLAGS_NONMODIFIABLE;
kekMeta.len = (whNvmSize)sizeof(whDemoKeywrapKek);
memcpy(kekMeta.label, "keywrap demo KEK", sizeof("keywrap demo KEK"));

rc = wh_Nvm_AddObject(nvm, &kekMeta, kekMeta.len, whDemoKeywrapKek);
if (rc != 0) {
WOLFHSM_CFG_PRINTF("Failed to provision keywrap demo KEK: %d\n",
rc);
return rc;
}
}
#endif /* WOLFHSM_CFG_KEYWRAP && WH_POSIX_PROVISION_DEMO_KEK */

/* Initialize NVM with contents from the NVM init file if provided */
if (nvmInitFilePath != NULL) {
WOLFHSM_CFG_PRINTF("Initializing NVM with contents from %s\n", nvmInitFilePath);
Expand Down
104 changes: 104 additions & 0 deletions src/wh_client_keywrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,110 @@ int wh_Client_KeyWrap(whClientContext* ctx, enum wc_CipherType cipherType,
return ret;
}

int wh_Client_KeyWrapExportRequest(whClientContext* ctx,
enum wc_CipherType cipherType,
uint16_t keyId, uint16_t keyType,
uint16_t serverKeyId)
{
uint16_t group = WH_MESSAGE_GROUP_KEY;
uint16_t action = WH_KEY_KEYWRAPEXPORT;
whMessageKeystore_KeyWrapExportRequest* req = NULL;

if (ctx == NULL) {
return WH_ERROR_BADARGS;
}

/* Set the request pointer to the shared comm data memory region */
req = (whMessageKeystore_KeyWrapExportRequest*)wh_CommClient_GetDataPtr(
ctx->comm);
if (req == NULL) {
return WH_ERROR_BADARGS;
}

/* Initialize the request */
req->keyId = keyId;
req->keyType = keyType;
req->serverKeyId = serverKeyId;
req->cipherType = cipherType;

return wh_Client_SendRequest(ctx, group, action, sizeof(*req),
(uint8_t*)req);
}

int wh_Client_KeyWrapExportResponse(whClientContext* ctx,
enum wc_CipherType cipherType,
void* wrappedKeyOut,
uint16_t* wrappedKeyInOutSz)
{
int ret;
uint16_t group;
uint16_t action;
uint16_t size;
whMessageKeystore_KeyWrapExportResponse* resp = NULL;
uint8_t* respData;

if (ctx == NULL || wrappedKeyOut == NULL || wrappedKeyInOutSz == NULL) {
return WH_ERROR_BADARGS;
}

/* Set the response pointer to the shared comm data memory region */
resp = (whMessageKeystore_KeyWrapExportResponse*)wh_CommClient_GetDataPtr(
ctx->comm);
if (resp == NULL) {
return WH_ERROR_BADARGS;
}

/* Receive the response */
ret = wh_Client_RecvResponse(ctx, &group, &action, &size, (uint8_t*)resp);
if (ret != WH_ERROR_OK) {
return ret;
}

if (group != WH_MESSAGE_GROUP_KEY || action != WH_KEY_KEYWRAPEXPORT ||
size < sizeof(*resp) || size < sizeof(*resp) + resp->wrappedKeySz ||
resp->cipherType != cipherType) {
return WH_ERROR_ABORTED;
}

if (resp->rc != 0) {
return resp->rc;
}
else if (resp->wrappedKeySz > *wrappedKeyInOutSz) {
return WH_ERROR_BUFFER_SIZE;
}

respData = (uint8_t*)(resp + 1);
memcpy(wrappedKeyOut, respData, resp->wrappedKeySz);
*wrappedKeyInOutSz = resp->wrappedKeySz;

return WH_ERROR_OK;
}

int wh_Client_KeyWrapExport(whClientContext* ctx, enum wc_CipherType cipherType,
uint16_t keyId, uint16_t keyType,
uint16_t serverKeyId, void* wrappedKeyOut,
uint16_t* wrappedKeyInOutSz)
{
int ret = WH_ERROR_OK;

if (ctx == NULL || wrappedKeyOut == NULL || wrappedKeyInOutSz == NULL) {
return WH_ERROR_BADARGS;
}

ret = wh_Client_KeyWrapExportRequest(ctx, cipherType, keyId, keyType,
serverKeyId);
if (ret != WH_ERROR_OK) {
return ret;
}

do {
ret = wh_Client_KeyWrapExportResponse(ctx, cipherType, wrappedKeyOut,
wrappedKeyInOutSz);
} while (ret == WH_ERROR_NOTREADY);

return ret;
}

int wh_Client_KeyUnwrapAndExportRequest(whClientContext* ctx,
enum wc_CipherType cipherType,
uint16_t serverKeyId,
Expand Down
29 changes: 29 additions & 0 deletions src/wh_message_keystore.c
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,35 @@ int wh_MessageKeystore_TranslateKeyWrapResponse(
return 0;
}

/* Wrap-and-export (by id) Request translation */
int wh_MessageKeystore_TranslateKeyWrapExportRequest(
uint16_t magic, const whMessageKeystore_KeyWrapExportRequest* src,
whMessageKeystore_KeyWrapExportRequest* dest)
{
if ((src == NULL) || (dest == NULL)) {
return WH_ERROR_BADARGS;
}
WH_T16(magic, dest, src, keyId);
WH_T16(magic, dest, src, keyType);
WH_T16(magic, dest, src, serverKeyId);
WH_T16(magic, dest, src, cipherType);
return 0;
}

/* Wrap-and-export (by id) Response translation */
int wh_MessageKeystore_TranslateKeyWrapExportResponse(
uint16_t magic, const whMessageKeystore_KeyWrapExportResponse* src,
whMessageKeystore_KeyWrapExportResponse* dest)
{
if ((src == NULL) || (dest == NULL)) {
return WH_ERROR_BADARGS;
}
WH_T32(magic, dest, src, rc);
WH_T16(magic, dest, src, wrappedKeySz);
WH_T16(magic, dest, src, cipherType);
return 0;
}

/* Key Unwrap Request translation */
int wh_MessageKeystore_TranslateKeyUnwrapAndExportRequest(
uint16_t magic, const whMessageKeystore_KeyUnwrapAndExportRequest* src,
Expand Down
Loading
Loading