Skip to content
2 changes: 1 addition & 1 deletion examples/demo/client/wh_demo_client_all.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ int wh_DemoClient_All(whClientContext* clientContext)
#endif

#ifdef WOLFHSM_CFG_KEYWRAP
rc = wh_DemoClient_KeyWrapBasic(clientContext);
rc = wh_DemoClient_KeyWrap(clientContext);
if (rc != 0) {
return rc;
}
Expand Down
229 changes: 167 additions & 62 deletions examples/demo/client/wh_demo_client_keywrap.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,29 @@

#ifdef WOLFHSM_CFG_KEYWRAP

#define WH_TEST_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;
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,
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_TEST_KEKID);
}

#ifndef NO_AES
#ifdef HAVE_AESGCM

Expand All @@ -45,120 +68,202 @@
#define WH_TEST_AES_WRAPPED_KEYSIZE \
(WH_TEST_AES_IVSIZE + WH_TEST_AES_TAGSIZE + WH_TEST_AES_KEYSIZE + \
sizeof(whNvmMetadata))
#define WH_TEST_WRAPKEY_ID 8
#define WH_TEST_AESGCM_WRAPKEY_ID 8

int wh_DemoClient_AesGcmKeyWrapBasic(whClientContext* ctx, WC_RNG* rng)
int wh_DemoClient_AesGcmKeyWrap(whClientContext* client)
{
int ret = 0;
uint8_t kek[WH_TEST_AES_KEYSIZE];
uint8_t clientKey[WH_TEST_AES_KEYSIZE];
uint8_t tmpClientKey[WH_TEST_AES_KEYSIZE];
Aes aes[1];
WC_RNG rng[1];
uint8_t key[WH_TEST_AES_KEYSIZE];
uint8_t exportedKey[WH_TEST_AES_KEYSIZE];
whNvmMetadata metadata = {
.id = WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, 0, WH_TEST_AESGCM_WRAPKEY_ID),
.label = "AES Key Label",
.access = WH_NVM_ACCESS_ANY,
.len = WH_TEST_AES_KEYSIZE};
whNvmMetadata exportedMetadata;
uint8_t wrappedKey[WH_TEST_AES_WRAPPED_KEYSIZE];
uint8_t label[WH_NVM_LABEL_LEN] = "Server AES Key Label";
whKeyId serverKeyId;
whKeyId wrappedKeyId;
whNvmMetadata metadata = {.id = WH_TEST_WRAPKEY_ID,
.label = "AES Key Label",
.access = WH_NVM_ACCESS_ANY,
.len = WH_TEST_AES_KEYSIZE};
whNvmMetadata tmpMetadata;

/* Generate a random KEK to encrypt the client key */
ret = wc_RNG_GenerateBlock(rng, kek, sizeof(kek));
if (ret != 0) {
printf("Failed to wc_RNG_GenerateBlock for key %d\n", ret);

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];
const uint8_t aad[] = {0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe,
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) {
printf("Failed to _InitServerKek %d\n", ret);
return ret;
}

/* Generate a random client key */
ret = wc_RNG_GenerateBlock(rng, clientKey, sizeof(clientKey));
/* 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_DEV_ID);
if (ret != 0) {
printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret);
return ret;
printf("Failed to wc_InitRng_ex %d\n", ret);
goto cleanup_kek;
}

/* Request the server to cache the KEK and give us back a key ID*/
ret = wh_Client_KeyCache(ctx, 0, label, sizeof(label), kek, sizeof(kek),
&serverKeyId);
/* Now we generate the AES GCM key using the RNG */
ret = wc_RNG_GenerateBlock(rng, key, sizeof(key));
if (ret != 0) {
printf("Failed to wh_Client_KeyCache %d\n", ret);
return ret;
printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret);
goto cleanup_rng;
}

/* Request the server to wrap the client key using the KEK we just cached */
ret = wh_Client_KeyWrap(ctx, WC_CIPHER_AES_GCM, serverKeyId, clientKey,
sizeof(clientKey), &metadata, wrappedKey,
/* 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,
sizeof(wrappedKey));
if (ret != 0) {
printf("Failed to wh_Client_KeyWrap %d\n", ret);
return ret;
goto cleanup_rng;
}

/* Request the server to unwrap and cache the wrapped key we just created */
ret = wh_Client_KeyUnwrapAndCache(ctx, WC_CIPHER_AES_GCM, serverKeyId,
/* Now that the key is wrapped you store this in Non-Volatile Memory however
* you wish */


/* Using a wrapped key to do crypto operations*/

/* 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);
if (ret != 0) {
printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
return ret;
goto cleanup_rng;
}

/* Initialize AES context */
ret = wc_AesInit(aes, NULL, WH_DEV_ID);
if (ret != 0) {
printf("Failed to wc_AesInit %d\n", ret);
goto cleanup_cached_key;
}

/* Set the key id for this AES context to the wrapped key ID that the server
* provided us */
ret = wh_Client_AesSetKeyId(aes, wrappedKeyId);
if (ret != 0) {
printf("Failed to wh_Client_AesSetKeyId %d\n", ret);
goto cleanup_aes;
}

/* Generate a random IV for the AES GCM encryption operation we are about to
* do */
ret = wc_RNG_GenerateBlock(rng, iv, sizeof(iv));
if (ret != 0) {
printf("Failed to wc_RNG_GenerateBlock for AES-GCM key %d\n", ret);
goto cleanup_aes;
}

/* Request the server to encrypt some data using the
* unwrapped and cached key via the key ID */
ret = wc_AesGcmEncrypt(aes, ciphertext, plaintext, sizeof(plaintext), iv,
sizeof(iv), tag, sizeof(tag), aad, sizeof(aad));
if (ret != 0) {
printf("Failed to wc_AesGcmEncrypt %d\n", ret);
goto cleanup_aes;
}

/* Request the server to decrypt the encrypted data using the
* unwrapped and cached key via the key ID */
ret = wc_AesGcmDecrypt(aes, decrypted, /* out */
ciphertext, sizeof(ciphertext), /* in, inLen */
iv, sizeof(iv), /* iv, ivLen */
tag, sizeof(tag), /* authTag, authTagSz */
aad, sizeof(aad)); /* authIn (AAD), authInSz */
if (ret != 0) {
ret = WH_ERROR_ABORTED;
printf("Failed to wc_AesGcmDecrypt %d\n", ret);
goto cleanup_aes;
}

/* Check if the decrypted data matches an expected value */
if (memcmp(decrypted, plaintext, sizeof(decrypted)) != 0) {
ret = WH_ERROR_ABORTED;
printf("Decrypted value does not match expected value\n");
goto cleanup_aes;
}

/* Exporting a wrapped key */

/* Request the server to unwrap and export the wrapped key we created */
ret = wh_Client_KeyUnwrapAndExport(
ctx, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, sizeof(wrappedKey),
&tmpMetadata, tmpClientKey, sizeof(tmpClientKey));
ret = wh_Client_KeyUnwrapAndExport(client, WC_CIPHER_AES_GCM, WH_TEST_KEKID,
wrappedKey, sizeof(wrappedKey),
&exportedMetadata, exportedKey,
sizeof(exportedKey));
if (ret != 0) {
printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
return ret;
goto cleanup_aes;
}


/* Compare the exported key to the client key we requested to wrap */
if (memcmp(clientKey, tmpClientKey, sizeof(clientKey)) != 0) {
if (memcmp(key, exportedKey, sizeof(key)) != 0) {
ret = WH_ERROR_ABORTED;
printf("AES GCM wrap/unwrap key failed to match\n");
return ret;
goto cleanup_aes;
}

/* Compare the exported metadata to the metadata we requested to wrap */
if (memcmp(&metadata, &tmpMetadata, sizeof(metadata)) != 0) {
if (memcmp(&metadata, &exportedMetadata, sizeof(metadata)) != 0) {
ret = WH_ERROR_ABORTED;
printf("AES GCM wrap/unwrap metadata failed to match\n");
return ret;
goto cleanup_aes;
}

cleanup_aes:
wc_AesFree(aes);
cleanup_cached_key:
wh_Client_KeyErase(client, wrappedKeyId);
cleanup_rng:
wc_FreeRng(rng);
cleanup_kek:
_CleanupServerKek(client);

return ret;
}

#endif /* HAVE_AESGCM */

int wh_DemoClient_AesKeyWrapBasic(whClientContext* clientContext, WC_RNG* rng)
{
int ret = WH_ERROR_OK;

#ifdef HAVE_AESGCM
ret = wh_DemoClient_AesGcmKeyWrapBasic(clientContext, rng);
#endif

return ret;
}

#endif /* !NO_AES */
int wh_DemoClient_KeyWrapBasic(whClientContext* clientContext)

int wh_DemoClient_KeyWrap(whClientContext* client)
{

int ret;
WC_RNG rng[1];
int ret;

ret = wc_InitRng_ex(rng, NULL, WH_DEV_ID);
if (ret != 0) {
printf("Failed to wc_InitRng_ex %d\n", ret);
#ifndef NO_AES
#ifdef HAVE_AESGCM

ret = wh_DemoClient_AesGcmKeyWrap(client);
if (ret != WH_ERROR_OK) {
printf("Failed to wh_DemoClient_AesGcmKeyWrap %d\n", ret);
return ret;
}

#ifndef NO_AES
ret = wh_DemoClient_AesKeyWrapBasic(clientContext, rng);
#endif
#endif /* !NO_AES */
#endif /* HAVE_AESGCM */

wc_FreeRng(rng);
return ret;
}
#endif /* WOLFHSM_CFG_KEYWRAP */
2 changes: 1 addition & 1 deletion examples/demo/client/wh_demo_client_keywrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

#include "wolfhsm/wh_client.h"

int wh_DemoClient_KeyWrapBasic(whClientContext* clientContext);
int wh_DemoClient_KeyWrap(whClientContext* clientContext);

#endif /* !DEMO_CLIENT_KEYWRAP_H_ */
1 change: 1 addition & 0 deletions examples/posix/wh_posix_client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ SRC_C += $(wildcard $(WOLFHSM_DIR)/src/*.c)
# wolfHSM port/HAL code
SRC_C += $(wildcard $(WOLFHSM_PORT_DIR)/*.c)


# Project
SRC_C += $(wildcard $(PROJECT_DIR)/*.c)

Expand Down
2 changes: 1 addition & 1 deletion examples/posix/wh_posix_client/wolfhsm_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
/** wolfHSM settings */
#define WOLFHSM_CFG_ENABLE_CLIENT
#define WOLFHSM_CFG_HEXDUMP
#define WOLFHSM_CFG_COMM_DATA_LEN 1280
#define WOLFHSM_CFG_COMM_DATA_LEN 5000
#define WOLFHSM_CFG_KEYWRAP

#endif /* WOLFHSM_CFG_H_ */
2 changes: 2 additions & 0 deletions examples/posix/wh_posix_server/wolfhsm_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
#define WOLFHSM_CFG_CERTIFICATE_MANAGER
#define WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT

#define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 5000

#define XMEMFENCE() __atomic_thread_fence(__ATOMIC_SEQ_CST)
#define WOLFHSM_CFG_KEYWRAP

Expand Down
2 changes: 2 additions & 0 deletions src/wh_client_keywrap.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* Pick up compile-time configuration */
#include "wolfhsm/wh_settings.h"

#if defined(WOLFHSM_CFG_KEYWRAP)
#if defined(WOLFHSM_CFG_ENABLE_CLIENT)
#include <stdint.h>
#include <wolfhsm/wh_client.h>
Expand Down Expand Up @@ -326,3 +327,4 @@ int wh_Client_KeyUnwrapAndCache(whClientContext* ctx,
}

#endif /* WOLFHSM_CFG_ENABLE_CLIENT */
#endif /* WOLFHSM_CFG_KEYWRAP */
2 changes: 2 additions & 0 deletions test/config/wolfhsm_cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
/* Enable Image Manager feature */
#define WOLFHSM_CFG_SERVER_IMG_MGR

#ifndef WOLFHSM_CFG_NO_CRYPTO
#define WOLFHSM_CFG_KEYWRAP
#endif

#endif /* WOLFHSM_CFG_H_ */
Loading