diff --git a/examples/demo/client/wh_demo_client_all.c b/examples/demo/client/wh_demo_client_all.c
index 2b9f651a..ff6bb72a 100644
--- a/examples/demo/client/wh_demo_client_all.c
+++ b/examples/demo/client/wh_demo_client_all.c
@@ -4,6 +4,7 @@
#include "wh_demo_client_keystore.h"
#include "wh_demo_client_crypto.h"
#include "wh_demo_client_secboot.h"
+#include "wh_demo_client_keywrap.h"
#include "wh_demo_client_all.h"
int wh_DemoClient_All(whClientContext* clientContext)
@@ -45,6 +46,11 @@ int wh_DemoClient_All(whClientContext* clientContext)
}
#endif
+ rc = wh_DemoClient_KeyWrapBasic(clientContext);
+ if (rc != 0) {
+ return rc;
+ }
+
/**Crypto demos */
#ifndef NO_RSA
rc = wh_DemoClient_CryptoRsa(clientContext);
diff --git a/examples/demo/client/wh_demo_client_keystore.c b/examples/demo/client/wh_demo_client_keystore.c
index f58dea25..8acced7f 100644
--- a/examples/demo/client/wh_demo_client_keystore.c
+++ b/examples/demo/client/wh_demo_client_keystore.c
@@ -126,8 +126,10 @@ int wh_DemoClient_KeystoreAes(whClientContext* clientContext)
{
int ret;
Aes aes = {0};
- uint8_t key[AES_128_KEY_SIZE] = "0123456789abcdef";
- uint8_t iv[AES_IV_SIZE] = "1234567890abcdef";
+ uint8_t key[AES_128_KEY_SIZE] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ uint8_t iv[AES_IV_SIZE] = {'1', '2', '3', '4', '5', '6', '7', '8',
+ '9', '0', 'a', 'b', 'c', 'd', 'e', 'f'};
uint8_t label[] = "my secret AES key";
uint8_t plainText[] = "This is a test.";
uint8_t cipherText[sizeof(plainText)];
diff --git a/examples/demo/client/wh_demo_client_keywrap.c b/examples/demo/client/wh_demo_client_keywrap.c
new file mode 100644
index 00000000..bf237e7f
--- /dev/null
+++ b/examples/demo/client/wh_demo_client_keywrap.c
@@ -0,0 +1,162 @@
+/*
+ * 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 .
+ */
+
+#include "wolfhsm/wh_settings.h"
+#include
+#include
+#include
+
+#include "wolfhsm/wh_common.h"
+#include "wolfhsm/wh_error.h"
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_client_crypto.h"
+
+#include "wolfssl/wolfcrypt/settings.h"
+#include "wolfssl/wolfcrypt/aes.h"
+#include "wolfssl/wolfcrypt/random.h"
+
+#include "wh_demo_client_keywrap.h"
+
+#ifndef NO_AES
+#define HAVE_AESGCM
+#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_WRAPKEY_ID 8
+
+int wh_DemoClient_AesGcmKeyWrapBasic(whClientContext* ctx, WC_RNG* rng)
+{
+ int ret = 0;
+ uint8_t kek[WH_TEST_AES_KEYSIZE];
+ uint8_t clientKey[WH_TEST_AES_KEYSIZE];
+ uint8_t tmpClientKey[WH_TEST_AES_KEYSIZE];
+ 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);
+ return ret;
+ }
+
+ /* Generate a random client key */
+ ret = wc_RNG_GenerateBlock(rng, clientKey, sizeof(clientKey));
+ if (ret != 0) {
+ printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret);
+ return ret;
+ }
+
+ /* 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);
+ if (ret != 0) {
+ printf("Failed to wh_Client_KeyCache %d\n", ret);
+ return ret;
+ }
+
+ /* 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,
+ sizeof(wrappedKey));
+ if (ret != 0) {
+ printf("Failed to wh_Client_KeyWrap %d\n", ret);
+ return ret;
+ }
+
+ /* Request the server to unwrap and cache the wrapped key we just created */
+ ret = wh_Client_KeyUnwrapAndCache(ctx, WC_CIPHER_AES_GCM, serverKeyId,
+ wrappedKey, sizeof(wrappedKey),
+ &wrappedKeyId);
+ if (ret != 0) {
+ printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
+ return ret;
+ }
+
+ /* 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));
+ if (ret != 0) {
+ printf("Failed to wh_Client_KeyUnwrapAndCache %d\n", ret);
+ return ret;
+ }
+
+
+ /* Compare the exported key to the client key we requested to wrap */
+ if (memcmp(clientKey, tmpClientKey, sizeof(clientKey)) != 0) {
+ printf("AES GCM wrap/unwrap key failed to match\n");
+ return ret;
+ }
+
+ /* Compare the exported metadata to the metadata we requested to wrap */
+ if (memcmp(&metadata, &tmpMetadata, sizeof(metadata)) != 0) {
+ printf("AES GCM wrap/unwrap metadata failed to match\n");
+ return ret;
+ }
+
+ 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 ret;
+ WC_RNG rng[1];
+
+ ret = wc_InitRng_ex(rng, NULL, WH_DEV_ID);
+ if (ret != 0) {
+ printf("Failed to wc_InitRng_ex %d\n", ret);
+ return ret;
+ }
+
+#ifndef NO_AES
+ ret = wh_DemoClient_AesKeyWrapBasic(clientContext, rng);
+#endif
+
+ wc_FreeRng(rng);
+ return ret;
+}
diff --git a/examples/demo/client/wh_demo_client_keywrap.h b/examples/demo/client/wh_demo_client_keywrap.h
new file mode 100644
index 00000000..c60331d7
--- /dev/null
+++ b/examples/demo/client/wh_demo_client_keywrap.h
@@ -0,0 +1,8 @@
+#ifndef DEMO_CLIENT_KEYWRAP_H_
+#define DEMO_CLIENT_KEYWRAP_H_
+
+#include "wolfhsm/wh_client.h"
+
+int wh_DemoClient_KeyWrapBasic(whClientContext* clientContext);
+
+#endif /* !DEMO_CLIENT_KEYWRAP_H_ */
diff --git a/examples/demo/client/wh_demo_client_nvm.c b/examples/demo/client/wh_demo_client_nvm.c
index f4e41472..760b584c 100644
--- a/examples/demo/client/wh_demo_client_nvm.c
+++ b/examples/demo/client/wh_demo_client_nvm.c
@@ -28,7 +28,7 @@ int wh_DemoClient_Nvm(whClientContext* clientContext)
whNvmId reclaimObjects;
whNvmId objectIds[] = {1, 2, 3};
- uint8_t labels[][6] = {"label1", "label2", "label3"};
+ uint8_t labels[][7] = {"label1", "label2", "label3"};
uint8_t data[][6] = {"data1", "data2", "data3"};
uint8_t readData[6];
whNvmSize dataLen = 6;
diff --git a/src/wh_client_keywrap.c b/src/wh_client_keywrap.c
new file mode 100644
index 00000000..8183ed85
--- /dev/null
+++ b/src/wh_client_keywrap.c
@@ -0,0 +1,328 @@
+/* Pick up compile-time configuration */
+#include "wolfhsm/wh_settings.h"
+
+#if defined(WOLFHSM_CFG_ENABLE_CLIENT)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+int wh_Client_KeyWrapRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* key, uint16_t keySz,
+ whNvmMetadata* metadata)
+{
+ uint16_t group = WH_MESSAGE_GROUP_KEY;
+ uint16_t action = WH_KEY_WRAP;
+ whMessageKeystore_WrapRequest* req = NULL;
+ uint8_t* reqData;
+
+ if (ctx == NULL || key == NULL || metadata == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Set the request pointer to the shared comm data memory region */
+ req = (whMessageKeystore_WrapRequest*)wh_CommClient_GetDataPtr(ctx->comm);
+ if (req == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Initialize the request */
+ req->keySz = keySz;
+ req->serverKeyId = serverKeyId;
+ req->cipherType = cipherType;
+
+ /* Place the metadata + key right after the request */
+ reqData = (uint8_t*)(req + 1);
+ memcpy(reqData, metadata, sizeof(*metadata));
+ memcpy(reqData + sizeof(*metadata), key, keySz);
+
+ return wh_Client_SendRequest(ctx, group, action,
+ sizeof(*req) + sizeof(*metadata) + keySz,
+ (uint8_t*)req);
+}
+
+int wh_Client_KeyWrapResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ void* wrappedKeyOut, uint16_t wrappedKeySz)
+{
+ int ret;
+ uint16_t group;
+ uint16_t action;
+ uint16_t size;
+ whMessageKeystore_WrapResponse* resp = NULL;
+ uint8_t* respData;
+
+ if (ctx == NULL || wrappedKeyOut == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Set the response pointer to the shared comm data memory region */
+ resp = (whMessageKeystore_WrapResponse*)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_WRAP ||
+ size < sizeof(*resp) || size > sizeof(*resp) + wrappedKeySz ||
+ resp->wrappedKeySz != wrappedKeySz || resp->cipherType != cipherType) {
+ return WH_ERROR_ABORTED;
+ }
+
+ if (resp->rc != 0) {
+ return resp->rc;
+ }
+
+ /* Copy the wrapped key from the response data into wrappedKeyOut */
+ respData = (uint8_t*)(resp + 1);
+ memcpy(wrappedKeyOut, respData, wrappedKeySz);
+
+ return WH_ERROR_OK;
+}
+
+int wh_Client_KeyWrap(whClientContext* ctx, enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* keyIn, uint16_t keySz,
+ whNvmMetadata* metadataIn, void* wrappedKeyOut,
+ uint16_t wrappedKeySz)
+{
+ int ret = WH_ERROR_OK;
+
+ if (ctx == NULL || keyIn == NULL || metadataIn == NULL ||
+ wrappedKeyOut == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ ret = wh_Client_KeyWrapRequest(ctx, cipherType, serverKeyId, keyIn, keySz,
+ metadataIn);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ do {
+ ret = wh_Client_KeyWrapResponse(ctx, cipherType, wrappedKeyOut,
+ wrappedKeySz);
+ } while (ret == WH_ERROR_NOTREADY);
+
+ return ret;
+}
+
+int wh_Client_KeyUnwrapAndExportRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId,
+ void* wrappedKeyIn,
+ uint16_t wrappedKeySz)
+
+{
+ uint16_t group = WH_MESSAGE_GROUP_KEY;
+ uint16_t action = WH_KEY_UNWRAPEXPORT;
+ whMessageKeystore_UnwrapAndExportRequest* req = NULL;
+ uint8_t* reqData;
+
+ if (ctx == NULL || wrappedKeyIn == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Set the request pointer to the shared comm data memory region */
+ req = (whMessageKeystore_UnwrapAndExportRequest*)wh_CommClient_GetDataPtr(
+ ctx->comm);
+ if (req == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Initialize the request */
+ req->wrappedKeySz = wrappedKeySz;
+ req->serverKeyId = serverKeyId;
+ req->cipherType = cipherType;
+
+ /* Place the wrapped key right after the request */
+ reqData = (uint8_t*)(req + 1);
+ memcpy(reqData, wrappedKeyIn, wrappedKeySz);
+
+ return wh_Client_SendRequest(ctx, group, action,
+ sizeof(*req) + wrappedKeySz, (uint8_t*)req);
+}
+
+int wh_Client_KeyUnwrapAndExportResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ whNvmMetadata* metadataOut,
+ void* keyOut, uint16_t keySz)
+{
+ int ret;
+ uint16_t group;
+ uint16_t action;
+ uint16_t size;
+ whMessageKeystore_UnwrapAndExportResponse* resp = NULL;
+ uint8_t* respData;
+
+ if (ctx == NULL || metadataOut == NULL || keyOut == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Set the response pointer to the shared comm data memory region */
+ resp = (whMessageKeystore_UnwrapAndExportResponse*)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_UNWRAPEXPORT ||
+ size < sizeof(*resp) ||
+ size > sizeof(*resp) + sizeof(*metadataOut) + keySz ||
+ resp->keySz != keySz || resp->cipherType != cipherType) {
+ return WH_ERROR_ABORTED;
+ }
+
+ if (resp->rc != 0) {
+ return resp->rc;
+ }
+
+ /* Copy the metadata and key from the response data into metadataOut and
+ * keyOut */
+ respData = (uint8_t*)(resp + 1);
+ memcpy(metadataOut, respData, sizeof(*metadataOut));
+ memcpy(keyOut, respData + sizeof(*metadataOut), keySz);
+
+ return WH_ERROR_OK;
+}
+
+int wh_Client_KeyUnwrapAndExport(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz,
+ whNvmMetadata* metadataOut, void* keyOut,
+ uint16_t keySz)
+{
+ int ret = WH_ERROR_OK;
+
+ if (ctx == NULL || wrappedKeyIn == NULL || metadataOut == NULL ||
+ keyOut == NULL)
+ return WH_ERROR_BADARGS;
+
+ ret = wh_Client_KeyUnwrapAndExportRequest(ctx, cipherType, serverKeyId,
+ wrappedKeyIn, wrappedKeySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ do {
+ ret = wh_Client_KeyUnwrapAndExportResponse(ctx, cipherType, metadataOut,
+ keyOut, keySz);
+ } while (ret == WH_ERROR_NOTREADY);
+
+ return ret;
+}
+
+int wh_Client_KeyUnwrapAndCacheRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz)
+{
+ uint16_t group = WH_MESSAGE_GROUP_KEY;
+ uint16_t action = WH_KEY_UNWRAPCACHE;
+
+ whMessageKeystore_UnwrapAndCacheRequest* req = NULL;
+ uint8_t* reqData;
+
+ if (ctx == NULL || wrappedKeyIn == NULL)
+ return WH_ERROR_BADARGS;
+
+ /* Set the request pointer to the shared comm data memory region */
+ req = (whMessageKeystore_UnwrapAndCacheRequest*)wh_CommClient_GetDataPtr(
+ ctx->comm);
+ if (req == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Initialize the request */
+ req->wrappedKeySz = wrappedKeySz;
+ req->serverKeyId = serverKeyId;
+ req->cipherType = cipherType;
+
+ /* Place the wrapped key right after the request */
+ reqData = (uint8_t*)(req + 1);
+ memcpy(reqData, wrappedKeyIn, wrappedKeySz);
+
+ return wh_Client_SendRequest(ctx, group, action,
+ sizeof(*req) + wrappedKeySz, (uint8_t*)req);
+}
+
+int wh_Client_KeyUnwrapAndCacheResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t* keyIdOut)
+{
+ int ret;
+ uint16_t group;
+ uint16_t action;
+ uint16_t size;
+ whMessageKeystore_UnwrapAndCacheResponse* resp = NULL;
+
+ if (ctx == NULL || keyIdOut == NULL)
+ return WH_ERROR_BADARGS;
+
+ /* Set the response pointer to the shared comm data memory region */
+ resp = (whMessageKeystore_UnwrapAndCacheResponse*)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_UNWRAPCACHE ||
+ size < sizeof(*resp) || resp->cipherType != cipherType) {
+ return WH_ERROR_ABORTED;
+ }
+
+ if (resp->rc != 0) {
+ return resp->rc;
+ }
+
+ *keyIdOut = resp->keyId;
+
+ return WH_ERROR_OK;
+}
+
+int wh_Client_KeyUnwrapAndCache(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz, uint16_t* keyIdOut)
+{
+ int ret = WH_ERROR_OK;
+
+ if (ctx == NULL || wrappedKeyIn == NULL || keyIdOut == NULL)
+ return WH_ERROR_BADARGS;
+
+ ret = wh_Client_KeyUnwrapAndCacheRequest(ctx, cipherType, serverKeyId,
+ wrappedKeyIn, wrappedKeySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ do {
+ ret = wh_Client_KeyUnwrapAndCacheResponse(ctx, cipherType, keyIdOut);
+ } while (ret == WH_ERROR_NOTREADY);
+
+ return ret;
+}
+
+#endif /* WOLFHSM_CFG_ENABLE_CLIENT */
diff --git a/src/wh_message_keystore.c b/src/wh_message_keystore.c
index 1162ce75..3c544e62 100644
--- a/src/wh_message_keystore.c
+++ b/src/wh_message_keystore.c
@@ -237,3 +237,87 @@ int wh_MessageKeystore_TranslateExportDmaResponse(
}
#endif /* WOLFHSM_CFG_DMA */
+
+/* Key Wrap Request translation */
+int wh_MessageKeystore_TranslateWrapRequest(
+ uint16_t magic, const whMessageKeystore_WrapRequest* src,
+ whMessageKeystore_WrapRequest* dest)
+{
+ if ((src == NULL) || (dest == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+ WH_T16(magic, dest, src, keySz);
+ WH_T16(magic, dest, src, serverKeyId);
+ WH_T16(magic, dest, src, cipherType);
+ return 0;
+}
+
+/* Key Wrap Response translation */
+int wh_MessageKeystore_TranslateWrapResponse(
+ uint16_t magic, const whMessageKeystore_WrapResponse* src,
+ whMessageKeystore_WrapResponse* 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_TranslateUnwrapAndExportRequest(
+ uint16_t magic, const whMessageKeystore_UnwrapAndExportRequest* src,
+ whMessageKeystore_UnwrapAndExportRequest* dest)
+{
+ if ((src == NULL) || (dest == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+ WH_T16(magic, dest, src, wrappedKeySz);
+ WH_T16(magic, dest, src, serverKeyId);
+ WH_T16(magic, dest, src, cipherType);
+ return 0;
+}
+
+/* Key Unwrap Response translation */
+int wh_MessageKeystore_TranslateUnwrapAndExportResponse(
+ uint16_t magic, const whMessageKeystore_UnwrapAndExportResponse* src,
+ whMessageKeystore_UnwrapAndExportResponse* dest)
+{
+ if ((src == NULL) || (dest == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+ WH_T32(magic, dest, src, rc);
+ WH_T16(magic, dest, src, keySz);
+ WH_T16(magic, dest, src, cipherType);
+ return 0;
+}
+
+/* Wrapped Key Cache Request translation */
+int wh_MessageKeystore_TranslateUnwrapAndCacheRequest(
+ uint16_t magic, const whMessageKeystore_UnwrapAndCacheRequest* src,
+ whMessageKeystore_UnwrapAndCacheRequest* dest)
+{
+ if ((src == NULL) || (dest == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+ WH_T16(magic, dest, src, wrappedKeySz);
+ WH_T16(magic, dest, src, serverKeyId);
+ WH_T16(magic, dest, src, cipherType);
+ return 0;
+}
+
+/* Key Cache Response translation */
+int wh_MessageKeystore_TranslateUnwrapAndCacheResponse(
+ uint16_t magic, const whMessageKeystore_UnwrapAndCacheResponse* src,
+ whMessageKeystore_UnwrapAndCacheResponse* dest)
+{
+ if ((src == NULL) || (dest == NULL)) {
+ return WH_ERROR_BADARGS;
+ }
+ WH_T32(magic, dest, src, rc);
+ WH_T16(magic, dest, src, keyId);
+ WH_T16(magic, dest, src, cipherType);
+ return 0;
+}
diff --git a/src/wh_server_keystore.c b/src/wh_server_keystore.c
index 61d0391d..c5eaa475 100644
--- a/src/wh_server_keystore.c
+++ b/src/wh_server_keystore.c
@@ -48,9 +48,9 @@
#include "wolfhsm/wh_server_keystore.h"
-static int _FindInCache(whServerContext* server, whKeyId keyId,
- int *out_index, int *out_big, uint8_t* *out_buffer,
- whNvmMetadata* *out_meta);
+static int _FindInCache(whServerContext* server, whKeyId keyId, int* out_index,
+ int* out_big, uint8_t** out_buffer,
+ whNvmMetadata** out_meta);
int wh_Server_KeystoreGetUniqueId(whServerContext* server, whNvmId* inout_id)
@@ -158,7 +158,7 @@ int wh_Server_KeystoreGetCacheSlot(whServerContext* server, uint16_t keySz,
}
if (foundIndex >= 0) {
memset(&server->bigCache[foundIndex], 0,
- sizeof(whServerBigCacheSlot));
+ sizeof(whServerBigCacheSlot));
*outBuf = server->bigCache[foundIndex].buffer;
*outMeta = server->bigCache[foundIndex].meta;
}
@@ -230,7 +230,7 @@ int wh_Server_KeystoreCacheKey(whServerContext* server, whNvmMetadata* meta,
if (foundIndex != -1) {
memcpy((uint8_t*)server->cache[foundIndex].buffer, in, meta->len);
memcpy((uint8_t*)server->cache[foundIndex].meta, (uint8_t*)meta,
- sizeof(whNvmMetadata));
+ sizeof(whNvmMetadata));
/* check if the key is already commited */
if (wh_Nvm_GetMetadata(server->nvm, meta->id, meta) ==
WH_ERROR_NOTFOUND) {
@@ -269,9 +269,9 @@ 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);
+ meta->len);
memcpy((uint8_t*)server->bigCache[foundIndex].meta, (uint8_t*)meta,
- sizeof(whNvmMetadata));
+ sizeof(whNvmMetadata));
/* check if the key is already commited */
if (wh_Nvm_GetMetadata(server->nvm, meta->id, meta) ==
WH_ERROR_NOTFOUND) {
@@ -344,6 +344,26 @@ static int _FindInCache(whServerContext* server, whKeyId keyId, int* out_index,
return ret;
}
+static int _ExistsInCache(whServerContext* server, whKeyId keyId)
+{
+ int ret = 0;
+ int foundIndex = -1;
+ int foundBigIndex = -1;
+ whNvmMetadata* tmpMeta;
+ uint8_t* tmpBuf;
+
+ ret = _FindInCache(server, keyId, &foundIndex, &foundBigIndex, &tmpBuf,
+ &tmpMeta);
+
+ if (ret != WH_ERROR_OK) {
+ /* Key doesn't exist in the cache */
+ return 0;
+ }
+
+ /* Key exists in the cache */
+ return 1;
+}
+
/* 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,
@@ -374,7 +394,7 @@ int wh_Server_KeystoreFreshenKey(whServerContext* server, whKeyId keyId,
/* Copy the metadata to the cache slot if key read is
* successful*/
memcpy((uint8_t*)*outMeta, (uint8_t*)tmpMeta,
- sizeof(whNvmMetadata));
+ sizeof(whNvmMetadata));
}
}
}
@@ -405,11 +425,11 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId,
return WH_ERROR_NOSPACE;
if (outMeta != NULL) {
memcpy((uint8_t*)outMeta, (uint8_t*)server->cache[i].meta,
- sizeof(whNvmMetadata));
+ sizeof(whNvmMetadata));
}
if (out != NULL) {
memcpy(out, server->cache[i].buffer,
- server->cache[i].meta->len);
+ server->cache[i].meta->len);
}
*outSz = server->cache[i].meta->len;
return 0;
@@ -424,11 +444,11 @@ int wh_Server_KeystoreReadKey(whServerContext* server, whKeyId keyId,
return WH_ERROR_NOSPACE;
if (outMeta != NULL) {
memcpy((uint8_t*)outMeta, (uint8_t*)server->bigCache[i].meta,
- sizeof(whNvmMetadata));
+ sizeof(whNvmMetadata));
}
if (out != NULL) {
memcpy(out, server->bigCache[i].buffer,
- server->bigCache[i].meta->len);
+ server->bigCache[i].meta->len);
}
*outSz = server->bigCache[i].meta->len;
return 0;
@@ -531,6 +551,353 @@ int wh_Server_KeystoreEraseKey(whServerContext* server, whNvmId keyId)
return wh_Nvm_DestroyObjects(server->nvm, 1, &keyId);
}
+#ifndef NO_AES
+#ifdef HAVE_AESGCM
+
+#define WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE 16
+#define WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE 12
+
+static int _AesGcmWrapKey(whServerContext* server, whKeyId serverKeyId,
+ uint8_t* keyIn, uint16_t keySz,
+ whNvmMetadata* metadataIn, uint8_t* wrappedKeyOut,
+ uint16_t wrappedKeySz)
+{
+ int ret = 0;
+ Aes aes[1];
+ uint8_t authTag[WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE];
+ uint8_t iv[WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE];
+ uint8_t serverKey[AES_MAX_KEY_SIZE];
+ uint32_t serverKeySz = sizeof(serverKey);
+
+ if (server == NULL || keyIn == NULL || metadataIn == NULL ||
+ wrappedKeyOut == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Check if the buffer is big enough to hold the wrapped key */
+ if (wrappedKeySz <
+ sizeof(iv) + sizeof(authTag) + sizeof(*metadataIn) + keySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Get the server side key */
+ ret = wh_Server_KeystoreReadKey(
+ server,
+ WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, serverKeyId),
+ NULL, serverKey, &serverKeySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ /* Initialize AES context and set it to use the server side key */
+ ret = wc_AesInit(aes, NULL, server->crypto->devId);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = wc_AesGcmSetKey(aes, serverKey, serverKeySz);
+ if (ret != 0) {
+ wc_AesFree(aes);
+ return ret;
+ }
+
+ /* Generate the IV */
+ ret = wc_RNG_GenerateBlock(server->crypto->rng, iv, sizeof(iv));
+ if (ret != 0) {
+ wc_AesFree(aes);
+ return ret;
+ }
+
+ /* Combine key and metadata into one blob */
+ uint8_t plainBlob[sizeof(*metadataIn) + keySz];
+ memcpy(plainBlob, metadataIn, sizeof(*metadataIn));
+ memcpy(plainBlob + sizeof(*metadataIn), keyIn, keySz);
+
+ /* Place the encrypted blob after the IV and Auth Tag*/
+ uint8_t* encBlob = (uint8_t*)wrappedKeyOut + sizeof(iv) + sizeof(authTag);
+
+ /* Encrypt the blob */
+ ret = wc_AesGcmEncrypt(aes, encBlob, plainBlob, sizeof(plainBlob), iv,
+ sizeof(iv), authTag, sizeof(authTag), NULL, 0);
+ if (ret != 0) {
+ wc_AesFree(aes);
+ return ret;
+ }
+
+ /* Prepend IV + authTag to encrypted blob */
+ memcpy(wrappedKeyOut, iv, sizeof(iv));
+ memcpy(wrappedKeyOut + sizeof(iv), authTag, sizeof(authTag));
+
+ wc_AesFree(aes);
+
+ return WH_ERROR_OK;
+}
+
+static int _AesGcmUnwrapKey(whServerContext* server, uint16_t serverKeyId,
+ void* wrappedKeyIn, uint16_t wrappedKeySz,
+ whNvmMetadata* metadataOut, void* keyOut,
+ uint16_t keySz)
+{
+ int ret = 0;
+ Aes aes[1];
+ uint8_t authTag[WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE];
+ uint8_t iv[WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE];
+ uint8_t serverKey[AES_MAX_KEY_SIZE];
+ uint32_t serverKeySz = sizeof(serverKey);
+ uint8_t* encBlob = (uint8_t*)wrappedKeyIn + sizeof(iv) + sizeof(authTag);
+ uint16_t encBlobSz = wrappedKeySz - sizeof(iv) - sizeof(authTag);
+ uint8_t plainBlob[sizeof(*metadataOut) + keySz];
+
+ if (server == NULL || wrappedKeyIn == NULL || metadataOut == NULL ||
+ keyOut == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Get the server side key */
+ ret = wh_Server_KeystoreReadKey(
+ server,
+ WH_MAKE_KEYID(WH_KEYTYPE_CRYPTO, server->comm->client_id, serverKeyId),
+ NULL, serverKey, &serverKeySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ /* Initialize AES context and set it to use the server side key */
+ ret = wc_AesInit(aes, NULL, server->crypto->devId);
+ if (ret != 0) {
+ return ret;
+ }
+
+ ret = wc_AesGcmSetKey(aes, serverKey, serverKeySz);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* Extract IV and authTag from wrappedKeyIn */
+ memcpy(iv, wrappedKeyIn, sizeof(iv));
+ memcpy(authTag, wrappedKeyIn + sizeof(iv), sizeof(authTag));
+
+ /* Decrypt the encrypted blob */
+ ret = wc_AesGcmDecrypt(aes, plainBlob, encBlob, encBlobSz, iv, sizeof(iv),
+ authTag, sizeof(authTag), NULL, 0);
+ if (ret != 0) {
+ wc_AesFree(aes);
+ return ret;
+ }
+
+ /* Extract metadata and key from the decrypted blob */
+ memcpy(metadataOut, plainBlob, sizeof(*metadataOut));
+ memcpy(keyOut, plainBlob + sizeof(*metadataOut), keySz);
+
+ wc_AesFree(aes);
+ return WH_ERROR_OK;
+}
+
+#endif /* HAVE_AESGCM */
+#endif /* !NO_AES */
+
+static int _HandleWrapKeyRequest(whServerContext* server,
+ whMessageKeystore_WrapRequest* req,
+ uint8_t* reqData, uint32_t reqDataSz,
+ whMessageKeystore_WrapResponse* resp,
+ uint8_t* respData, uint32_t respDataSz)
+{
+
+ int ret;
+ uint8_t* wrappedKey;
+ whNvmMetadata metadata;
+ uint8_t key[WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE];
+
+ if (server == NULL || req == NULL || reqData == NULL || resp == NULL ||
+ respData == NULL || req->keySz > WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Check if the reqData is big enough to hold the metadata and key */
+ if (reqDataSz < sizeof(metadata) + req->keySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Extract the metadata and key from reqData */
+ memcpy(&metadata, reqData, sizeof(metadata));
+ memcpy(key, reqData + sizeof(metadata), req->keySz);
+
+ /* Store the wrapped key in the response data */
+ wrappedKey = respData;
+
+ switch (req->cipherType) {
+
+#ifndef NO_AES
+#ifdef HAVE_AESGCM
+ case WC_CIPHER_AES_GCM: {
+ uint16_t wrappedKeySz = WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE +
+ WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE +
+ sizeof(metadata) + req->keySz;
+
+ /* Check if the response data can fit the wrapped key */
+ if (respDataSz < wrappedKeySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Wrap the key */
+ ret = _AesGcmWrapKey(server, req->serverKeyId, key, req->keySz,
+ &metadata, wrappedKey, wrappedKeySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ /* Tell the client how big the wrapped key is */
+ resp->wrappedKeySz = wrappedKeySz;
+ resp->cipherType = WC_CIPHER_AES_GCM;
+
+ } break;
+#endif /* HAVE_AESGCM */
+#endif /* !NO_AES */
+
+ default:
+ return WH_ERROR_BADARGS;
+ }
+
+ return WH_ERROR_OK;
+}
+
+static int _HandleUnwrapAndExportKeyRequest(
+ whServerContext* server, whMessageKeystore_UnwrapAndExportRequest* req,
+ uint8_t* reqData, uint32_t reqDataSz,
+ whMessageKeystore_UnwrapAndExportResponse* resp, uint8_t* respData,
+ uint32_t respDataSz)
+{
+ if (server == NULL || req == NULL || reqData == NULL || resp == NULL ||
+ respData == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ int ret;
+ uint8_t* wrappedKey;
+ whNvmMetadata* metadata;
+ uint8_t* key;
+
+ /* Check if the reqData is big enough to hold the wrapped key */
+ if (reqDataSz < req->wrappedKeySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Set the wrapped key to the request data */
+ wrappedKey = reqData;
+
+ /* Store the metadata and key in the respData */
+ metadata = (whNvmMetadata*)respData;
+ key = respData + sizeof(*metadata);
+
+ switch (req->cipherType) {
+
+#ifndef NO_AES
+#ifdef HAVE_AESGCM
+ case WC_CIPHER_AES_GCM: {
+ uint16_t keySz =
+ req->wrappedKeySz - WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE -
+ WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE - sizeof(*metadata);
+
+ /* Check if the response data can fit the metadata + key */
+ if (respDataSz < sizeof(*metadata) + keySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Unwrap the key */
+ ret = _AesGcmUnwrapKey(server, req->serverKeyId, wrappedKey,
+ req->wrappedKeySz, metadata, key, keySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ /* 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;
+
+ } break;
+#endif /* HAVE_AESGCM */
+#endif /* !NO_AES */
+
+ default:
+ return WH_ERROR_BADARGS;
+ }
+
+ return ret;
+}
+
+static int
+_HandleUnwrapAndCacheKeyRequest(whServerContext* server,
+ whMessageKeystore_UnwrapAndCacheRequest* req,
+ uint8_t* reqData, uint32_t reqDataSz,
+ whMessageKeystore_UnwrapAndCacheResponse* resp,
+ uint8_t* respData, uint32_t respDataSz)
+{
+ /* The server doesn't have any extra response data to send back to the
+ * client */
+ (void)respData;
+ (void)respDataSz;
+
+ if (server == NULL || req == NULL || reqData == NULL || resp == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ int ret;
+ uint8_t* wrappedKey;
+ whNvmMetadata metadata;
+ uint16_t keySz = 0;
+ uint8_t key[WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE];
+
+ /* Check if the reqData is big enough to hold the wrapped key */
+ if (reqDataSz < req->wrappedKeySz) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Set the wrapped key to the request data */
+ wrappedKey = reqData;
+
+ /* Unwrap the key based on the cipher type */
+ switch (req->cipherType) {
+#ifndef NO_AES
+#ifdef HAVE_AESGCM
+ case WC_CIPHER_AES_GCM: {
+ keySz = req->wrappedKeySz - WOLFHSM_KEYWRAP_AES_GCM_IV_SIZE -
+ WOLFHSM_KEYWRAP_AES_GCM_TAG_SIZE - sizeof(metadata);
+
+ ret = _AesGcmUnwrapKey(server, req->serverKeyId, wrappedKey,
+ req->wrappedKeySz, &metadata, key, keySz);
+ if (ret != WH_ERROR_OK) {
+ return ret;
+ }
+
+ resp->cipherType = WC_CIPHER_AES_GCM;
+ resp->keyId = metadata.id;
+
+ } break;
+#endif /* HAVE_AESGCM */
+#endif /* !NO_AES */
+ default:
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Verify the key size argument and key size from the the metadata match */
+ if (keySz != metadata.len) {
+ return WH_ERROR_BADARGS;
+ }
+
+ /* Check if this key already exists in the cache */
+ if (_ExistsInCache(server, metadata.id)) {
+ return WH_ERROR_ABORTED;
+ }
+
+ /* Cache the key */
+ return wh_Server_KeystoreCacheKey(server, &metadata, key);
+}
+
int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
uint16_t action, uint16_t req_size,
const void* req_packet, uint16_t* out_resp_size,
@@ -743,7 +1110,8 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
/* Only provide key output if no error */
if (resp.rc == WH_ERROR_OK) {
resp.len = keySz;
- } else {
+ }
+ else {
resp.len = 0;
}
memcpy(resp.label, meta->label, sizeof(meta->label));
@@ -807,6 +1175,115 @@ int wh_Server_HandleKeyRequest(whServerContext* server, uint16_t magic,
*out_resp_size = sizeof(resp);
}
} break;
+ case WH_KEY_WRAP: {
+ whMessageKeystore_WrapRequest wrapReq;
+ whMessageKeystore_WrapResponse wrapResp;
+ uint8_t* reqData;
+ uint8_t* respData;
+ uint32_t reqDataSz = WOLFHSM_CFG_COMM_DATA_LEN - sizeof(wrapReq);
+ uint32_t respDataSz = WOLFHSM_CFG_COMM_DATA_LEN - sizeof(wrapResp);
+
+ /* Validate the bounds of the request data */
+ if (reqDataSz < req_size) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Translate request */
+ (void)wh_MessageKeystore_TranslateWrapRequest(magic, req_packet,
+ &wrapReq);
+
+
+ /* Set the request data pointer directly after the request */
+ reqData =
+ (uint8_t*)req_packet + sizeof(whMessageKeystore_WrapRequest);
+
+ /* Set the response data pointer directly after the response */
+ respData =
+ (uint8_t*)resp_packet + sizeof(whMessageKeystore_WrapResponse);
+
+ ret = _HandleWrapKeyRequest(server, &wrapReq, reqData, reqDataSz,
+ &wrapResp, respData, respDataSz);
+ wrapResp.rc = ret;
+
+ (void)wh_MessageKeystore_TranslateWrapResponse(magic, &wrapResp,
+ resp_packet);
+ *out_resp_size = sizeof(wrapResp) + wrapResp.wrappedKeySz;
+
+ } break;
+
+ case WH_KEY_UNWRAPEXPORT: {
+ whMessageKeystore_UnwrapAndExportRequest unwrapReq;
+ whMessageKeystore_UnwrapAndExportResponse unwrapResp;
+ uint8_t* reqData;
+ uint8_t* respData;
+ uint32_t reqDataSz = WOLFHSM_CFG_COMM_DATA_LEN - sizeof(unwrapReq);
+ uint32_t respDataSz =
+ WOLFHSM_CFG_COMM_DATA_LEN - sizeof(unwrapResp);
+
+ /* Validate the bounds of the request data */
+ if (reqDataSz < req_size) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Translate request */
+ (void)wh_MessageKeystore_TranslateUnwrapAndExportRequest(
+ magic, req_packet, &unwrapReq);
+
+ /* Set the request data pointer directly after the request */
+ reqData = (uint8_t*)req_packet +
+ sizeof(whMessageKeystore_UnwrapAndExportRequest);
+
+ /* Set the response data pointer directly after the response */
+ respData = (uint8_t*)resp_packet +
+ sizeof(whMessageKeystore_UnwrapAndExportResponse);
+
+ ret = _HandleUnwrapAndExportKeyRequest(server, &unwrapReq, reqData,
+ reqDataSz, &unwrapResp,
+ respData, respDataSz);
+ unwrapResp.rc = ret;
+
+ (void)wh_MessageKeystore_TranslateUnwrapAndExportResponse(
+ magic, &unwrapResp, resp_packet);
+ *out_resp_size =
+ sizeof(unwrapResp) + sizeof(whNvmMetadata) + unwrapResp.keySz;
+
+ } break;
+
+ case WH_KEY_UNWRAPCACHE: {
+ whMessageKeystore_UnwrapAndCacheRequest cacheReq;
+ whMessageKeystore_UnwrapAndCacheResponse cacheResp;
+ uint8_t* reqData;
+ uint8_t* respData;
+ uint32_t reqDataSz = WOLFHSM_CFG_COMM_DATA_LEN - sizeof(cacheReq);
+ uint32_t respDataSz = WOLFHSM_CFG_COMM_DATA_LEN - sizeof(cacheResp);
+
+ /* Validate the bounds of the request data */
+ if (reqDataSz < req_size) {
+ return WH_ERROR_BUFFER_SIZE;
+ }
+
+ /* Translate request */
+ (void)wh_MessageKeystore_TranslateUnwrapAndCacheRequest(
+ magic, req_packet, &cacheReq);
+
+ /* Set the request data pointer directly after the request */
+ reqData = (uint8_t*)req_packet +
+ sizeof(whMessageKeystore_UnwrapAndCacheRequest);
+
+ /* Set the response data pointer directly after the response */
+ respData = (uint8_t*)resp_packet +
+ sizeof(whMessageKeystore_UnwrapAndCacheResponse);
+
+ ret = _HandleUnwrapAndCacheKeyRequest(server, &cacheReq, reqData,
+ reqDataSz, &cacheResp,
+ respData, respDataSz);
+ cacheResp.rc = ret;
+
+ (void)wh_MessageKeystore_TranslateUnwrapAndCacheResponse(
+ magic, &cacheResp, resp_packet);
+ *out_resp_size = sizeof(cacheResp);
+
+ } break;
default:
ret = WH_ERROR_BADARGS;
@@ -902,4 +1379,4 @@ int wh_Server_KeystoreExportKeyDma(whServerContext* server, whKeyId keyId,
}
#endif /* WOLFHSM_CFG_DMA */
-#endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_ENABLE_SERVER */
\ No newline at end of file
+#endif /* !WOLFHSM_CFG_NO_CRYPTO && WOLFHSM_CFG_ENABLE_SERVER */
diff --git a/test/wh_test.c b/test/wh_test.c
index 70a3769b..ecbf7bf0 100644
--- a/test/wh_test.c
+++ b/test/wh_test.c
@@ -36,6 +36,7 @@
#include "wh_test_crypto.h"
#include "wh_test_she.h"
#include "wh_test_clientserver.h"
+#include "wh_test_keywrap.h"
#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER)
#include "wh_test_cert.h"
@@ -110,6 +111,7 @@ int whTest_ClientConfig(whClientConfig* clientCfg)
#if !defined(WOLFHSM_CFG_NO_CRYPTO)
WH_TEST_RETURN_ON_FAIL(whTest_CryptoClientConfig(clientCfg));
+ WH_TEST_RETURN_ON_FAIL(whTest_KeyWrapClientConfig(clientCfg));
#endif /* !WOLFHSM_CFG_NO_CRYPTO */
#if defined(WOLFHSM_CFG_SHE_EXTENSION)
diff --git a/test/wh_test_keywrap.c b/test/wh_test_keywrap.c
new file mode 100644
index 00000000..c1af2b28
--- /dev/null
+++ b/test/wh_test_keywrap.c
@@ -0,0 +1,204 @@
+/*
+ * 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 .
+ */
+
+#include "wolfhsm/wh_settings.h"
+
+
+#include
+#include /* For printf */
+#include /* For memset, memcpy */
+
+#include "wolfssl/wolfcrypt/settings.h"
+#include "wolfssl/wolfcrypt/types.h"
+
+#include "wolfhsm/wh_error.h"
+
+#ifdef WOLFHSM_CFG_ENABLE_CLIENT
+#include "wolfhsm/wh_client.h"
+#include "wolfhsm/wh_client_crypto.h"
+#endif
+
+#include "wolfhsm/wh_comm.h"
+#include "wolfhsm/wh_message.h"
+#include "wolfhsm/wh_transport_mem.h"
+
+#include "wh_test_common.h"
+
+#ifdef WOLFHSM_CFG_ENABLE_CLIENT
+
+#ifndef WOLFHSM_CFG_NO_CRYPTO
+
+#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))
+
+static int whTest_Client_AesGcmKeyWrap(whClientContext* ctx, WC_RNG* rng)
+{
+
+ int ret = 0;
+ uint8_t iv[WH_TEST_AES_IVSIZE];
+ uint8_t key[WH_TEST_AES_KEYSIZE];
+ uint8_t plainKey[WH_TEST_AES_KEYSIZE];
+ uint8_t tmpPlainKey[WH_TEST_AES_KEYSIZE];
+ 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 = 8, .label = "AES Key Label", .len = WH_TEST_AES_KEYSIZE};
+ whNvmMetadata tmpMetadata;
+
+ /* Randomize inputs */
+ ret = wc_RNG_GenerateBlock(rng, key, sizeof(key));
+ if (ret != 0) {
+ printf("Failed to wc_RNG_GenerateBlock for key %d\n", ret);
+ return ret;
+ }
+
+ ret = wc_RNG_GenerateBlock(rng, plainKey, sizeof(plainKey));
+ if (ret != 0) {
+ printf("Failed to wc_RNG_GenerateBlock for key data %d\n", ret);
+ return ret;
+ }
+
+ ret = wc_RNG_GenerateBlock(rng, iv, sizeof(iv));
+ if (ret != 0) {
+ printf("Failed to wc_RNG_GenerateBlock for IV %d\n", ret);
+ return ret;
+ }
+
+ /* Initialize the AES GCM Server key */
+ ret = wh_Client_KeyCache(ctx, 0, label, sizeof(label), key, sizeof(key),
+ &serverKeyId);
+ if (ret != 0) {
+ printf("Failed to wh_Client_KeyCache %d\n", ret);
+ return ret;
+ }
+
+ ret = wh_Client_KeyWrap(ctx, WC_CIPHER_AES_GCM, serverKeyId, plainKey,
+ sizeof(plainKey), &metadata, wrappedKey,
+ sizeof(wrappedKey));
+ if (ret != 0) {
+ printf("Failed to wh_Client_AesGcmKeyWrap %d\n", ret);
+ return ret;
+ }
+
+ ret = wh_Client_KeyUnwrapAndCache(ctx, WC_CIPHER_AES_GCM, serverKeyId,
+ wrappedKey, sizeof(wrappedKey),
+ &wrappedKeyId);
+ if (ret != 0) {
+ printf("Failed to wh_Client_AesGcmKeyWrapCache %d\n", ret);
+ return ret;
+ }
+
+ ret = wh_Client_KeyUnwrapAndExport(
+ ctx, WC_CIPHER_AES_GCM, serverKeyId, wrappedKey, sizeof(wrappedKey),
+ &tmpMetadata, tmpPlainKey, sizeof(tmpPlainKey));
+ if (ret != 0) {
+ printf("Failed to wh_Client_AesGcmKeyUnwrapAndCache %d\n", ret);
+ return ret;
+ }
+
+ if (memcmp(plainKey, tmpPlainKey, sizeof(plainKey)) != 0) {
+ printf("AES GCM wrap/unwrap key failed to match\n");
+ return ret;
+ }
+
+ if (memcmp(&metadata, &tmpMetadata, sizeof(metadata)) != 0) {
+ printf("AES GCM wrap/unwrap metadata failed to match\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+#endif /* HAVE_AESGCM */
+#ifndef NO_AES
+
+static int whTest_Client_AesKeyWrap(whClientContext* ctx, WC_RNG* rng)
+{
+ int ret = 0;
+
+#ifdef HAVE_AESGCM
+ ret = whTest_Client_AesGcmKeyWrap(ctx, rng);
+
+#endif
+
+ return ret;
+}
+
+#endif /* !NO_AES */
+
+static int whTest_Client_KeyWrap(whClientContext* ctx, int devId)
+{
+ int ret = 0;
+ WC_RNG rng[1];
+
+ ret = wc_InitRng_ex(rng, NULL, devId);
+ if (ret != 0) {
+ WH_ERROR_PRINT("Failed to wc_InitRng_ex %d\n", ret);
+ return ret;
+ }
+
+#ifndef NO_AES
+ ret = whTest_Client_AesKeyWrap(ctx, rng);
+#endif
+
+ (void)wc_FreeRng(rng);
+ return ret;
+}
+
+int whTest_KeyWrapClientConfig(whClientConfig* config)
+{
+ int ret = 0;
+ whClientContext client[1] = {0};
+
+ if (config == NULL) {
+ return WH_ERROR_BADARGS;
+ }
+
+ WH_TEST_RETURN_ON_FAIL(wh_Client_Init(client, config));
+
+ ret = wh_Client_CommInit(client, NULL, NULL);
+ if (ret != 0) {
+ WH_ERROR_PRINT("Failed to wh_Client_Init %d\n", ret);
+ (void)wh_Client_Cleanup(client);
+ return ret;
+ }
+
+ ret = whTest_Client_KeyWrap(client, WH_DEV_ID);
+ if (ret != 0) {
+ WH_ERROR_PRINT("Failed to whTest_Client_KeyWrap %d\n", ret);
+ }
+
+ /* Clean up used resources */
+ (void)wh_Client_CommClose(client);
+ (void)wh_Client_Cleanup(client);
+
+ return ret;
+}
+#endif /* WOLFHSM_CFG_ENABLE_CLIENT */
+
+#endif /* !WOLFHSM_CFG_NO_CRYPTO */
diff --git a/test/wh_test_keywrap.h b/test/wh_test_keywrap.h
new file mode 100644
index 00000000..5dfdbc6b
--- /dev/null
+++ b/test/wh_test_keywrap.h
@@ -0,0 +1,28 @@
+/*
+ * 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 .
+ */
+#ifndef WH_TEST_KEYWRAP_H_
+#define WH_TEST_KEYWRAP_H_
+
+#include "wolfhsm/wh_server.h"
+#include "wolfhsm/wh_client.h"
+
+int whTest_KeyWrapClientConfig(whClientConfig* cf);
+
+
+#endif /* WH_TEST_COMM_H_ */
diff --git a/wolfhsm/wh_client.h b/wolfhsm/wh_client.h
index 42e0beff..33498349 100644
--- a/wolfhsm/wh_client.h
+++ b/wolfhsm/wh_client.h
@@ -50,6 +50,8 @@
#include "wolfhsm/wh_comm.h"
#include "wolfhsm/wh_message_customcb.h"
+/* WolfCrypt types and defines */
+#include "wolfssl/wolfcrypt/types.h"
#ifndef WOLFHSM_CFG_NO_CRYPTO
@@ -820,6 +822,197 @@ int wh_Client_KeyExportDma(whClientContext* c, uint16_t keyId,
uint16_t labelSz, uint16_t* outSz);
#endif /* WOLFHSM_CFG_DMA */
+/**
+ * @brief Sends a key wrap request to the server and receives the response
+ *
+ * This function handles the complete process of sending a key wrap request
+ * to the server and receiving the response. It sends the request and repeatedly
+ * attempts to receive a valid response, extracting the wrapped key from the
+ * response data once received. This function will block until the entire
+ * operation completes or an error occurs.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used to wrap the key.
+ * @param[in] serverKeyId Key ID of the key encryption key on the server.
+ * @param[in] keyIn Pointer to the key material to wrap.
+ * @param[in] keySz The size in bytes of the key material to wrap.
+ * @param[in] metadataIn Pointer to the metadata for the wrapped key.
+ * @param[out] wrappedKeyOut Pointer to store the wrapped key.
+ * @param[in] wrappedKeySz Size of the wrappedKeyOut buffer.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyWrap(whClientContext* ctx, enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* keyIn, uint16_t keySz,
+ whNvmMetadata* metadataIn, void* wrappedKeyOut,
+ uint16_t wrappedKeySz);
+
+/**
+ * @brief Sends a key wrap request to the server
+ *
+ * This function prepares and sends a key wrap request to the server.
+ * The request data contains the key data and metadata to be wrapped.
+ * This function does not block; it returns immediately after sending
+ * the request.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used to wrap the key.
+ * @param[in] serverKeyId Key ID of the key encryption key on the server.
+ * @param[in] key Pointer to the key material to wrap.
+ * @param[in] keySz The size in bytes of the key material to wrap.
+ * @param[in] metadataIn Pointer to the metadata for the wrapped key.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyWrapRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* key, uint16_t keySz,
+ whNvmMetadata* metadata);
+
+/**
+ * @brief Receives a key wrap response from the server.
+ *
+ * This function attempts to process a key wrap response message from the
+ * server. It will validate the response and extract the wrapped key from
+ * the response data. This function does not block; it returns WH_ERROR_NOTREADY
+ * if a response has not been received.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used to wrap the key.
+ * @param[out] wrappedKeyOut Pointer to store the wrapped key.
+ * @param[in] wrappedKeySz Size of the wrappedKeyOut buffer.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyWrapResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ void* wrappedKeyOut, uint16_t wrappedKeySz);
+
+/**
+ * @brief Requests the server to unwrap and export a wrapped key and receives
+ * the response
+ *
+ * This function handles the complete process of sending a unwrap key and export
+ * request to the server and receiving the response. It sends the request and
+ * repeatedly attempts to receive a valid response, extracting the unwrapped key
+ * and metadata from the response data once received. This function will block
+ * until the entire operation completes or an error occurs.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when for unwrapping the key.
+ * @param[in] serverKeyId Key ID to be used for unwrapping the key.
+ * @param[in] wrappedKeyIn Pointer to the wrapped key data.
+ * @param[in] wrappedKeySz The size in bytes of the wrapped key data.
+ * @param[out] metadataOut Pointer to store the unwrapped key metadata.
+ * @param[out] keyOut Pointer to store the unwrapped key.
+ * @param[in] keySz Size of the keyOut buffer.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyUnwrapAndExport(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz,
+ whNvmMetadata* metadataOut, void* keyOut,
+ uint16_t keySz);
+
+/**
+ * @brief Requests the server to unwrap-and-export a wrapped key
+ *
+ * This function prepares and sends a key unwrap-and-export request to
+ * the server. The request data contains the wrapped key for the server
+ * to unwrap. This function does not block; it returns immediately after
+ * sending the request.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when for unwrapping the key.
+ * @param[in] serverKeyId Key ID to be used for unwrapping the key.
+ * @param[in] wrappedKeyIn Pointer to the wrapped key data.
+ * @param[in] wrappedKeySz The size in bytes of the wrapped key data.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyUnwrapAndExportRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId,
+ void* wrappedKeyIn,
+ uint16_t wrappedKeySz);
+
+/**
+ * @brief Receives an unwrap-and-export response from the server
+ *
+ * This function attempts to process an unwrap-and-export response
+ * message from the server. It will validate the response and extract
+ * the metadata and unwrapped key from from the response data. This
+ * function does not block; it returns WH_ERROR_NOTREADY if a response
+ * has not been received.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when for unwrapping the key.
+ * @param[out] metadataOut Pointer to store the unwrapped key metadata.
+ * @param[out] keyOut Pointer to store the unwrapped key.
+ * @param[in] keySz Size of the keyOut buffer.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyUnwrapAndExportResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ whNvmMetadata* metadataOut,
+ void* keyOut, uint16_t keySz);
+
+/**
+ * @brief Requests the server to unwrap and cache a wrapped key and receives the
+ * response
+ *
+ * This function handles the complete process of sending a unwrap-and-cache
+ * request to the server and receiving the response. It sends the request
+ * and repeatedly attempts to receive a valid response, extracting the
+ * server-assigned key ID for the unwrapped key once received. This function
+ * will block until the entire operation completes or an error occurs.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when unwrapping the key.
+ * @param[in] serverKeyId Key ID to be used for unwrapping the key.
+ * @param[in] wrappedKeyIn Pointer to the wrapped key data.
+ * @param[in] wrappedKeySz The size in bytes of the wrapped key data.
+ * @param[out] keyIdOut Pointer to store the server-assigned ID of the cached
+ * key.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyUnwrapAndCache(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz, uint16_t* keyIdOut);
+/**
+ * @brief Sends a key unwrap-and-cache request to the server
+ *
+ * This function prepares and sends a key unwrap-and-cache request to the
+ * server. The request data contains the wrapped key for the server to unwrap
+ * and cache. This function does not block; it returns immediately after sending
+ * the request.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when unwrapping the key.
+ * @param[in] serverKeyId Key ID to be used for unwrapping the key.
+ * @param[in] wrappedKeyIn Pointer to the wrapped key data.
+ * @param[in] wrappedKeySz The size in bytes of the wrapped key data.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_KeyUnwrapAndCacheRequest(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t serverKeyId, void* wrappedKeyIn,
+ uint16_t wrappedKeySz);
+/**
+ * @brief Receives an unwrap-and-cache response from the server
+ *
+ * This function attempts to process an unwrap-and-cache response message
+ * from the server. It will validate the response and extract the
+ * server-assigned key ID for the cached key. This function does not block;
+ * it returns WH_ERROR_NOTREADY if a response has not been received.
+ *
+ * @param[in] ctx Pointer to the client context.
+ * @param[in] cipherType Cipher used when unwrapping the key.
+ * @param[out] keyIdOut Pointer to store the server-assigned ID of the cached
+ * key.
+ * @return int Returns 0 on success, or a negative error code on failure.
+ */
+int wh_Client_UnrapKeyAndCacheResponse(whClientContext* ctx,
+ enum wc_CipherType cipherType,
+ uint16_t* keyIdOut);
/* Counter functions */
int wh_Client_CounterInitRequest(whClientContext* c, whNvmId counterId,
diff --git a/wolfhsm/wh_message.h b/wolfhsm/wh_message.h
index 62dc5e89..6b7f1b2f 100644
--- a/wolfhsm/wh_message.h
+++ b/wolfhsm/wh_message.h
@@ -30,26 +30,26 @@
/* Message groups and kind */
enum WH_MESSAGE_ENUM {
- WH_MESSAGE_KIND_NONE = 0x0000, /* No message kind. Invalid */
+ WH_MESSAGE_KIND_NONE = 0x0000, /* No message kind. Invalid */
- WH_MESSAGE_GROUP_MASK = 0xFF00, /* 255 groups */
- WH_MESSAGE_GROUP_NONE = 0x0000, /* No group. Invalid. */
+ WH_MESSAGE_GROUP_MASK = 0xFF00, /* 255 groups */
+ WH_MESSAGE_GROUP_NONE = 0x0000, /* No group. Invalid. */
- WH_MESSAGE_GROUP_COMM = 0x0100, /* Messages used for comms */
- WH_MESSAGE_GROUP_NVM = 0x0200, /* NVM functions */
- WH_MESSAGE_GROUP_KEY = 0x0300, /* Key/counter management */
- WH_MESSAGE_GROUP_CRYPTO = 0x0400, /* wolfCrypt CryptoCb */
- WH_MESSAGE_GROUP_IMAGE = 0x0500, /* Image/boot management */
- WH_MESSAGE_GROUP_PKCS11 = 0x0600, /* PKCS11 protocol */
- WH_MESSAGE_GROUP_SHE = 0x0700, /* SHE protocol */
- WH_MESSAGE_GROUP_COUNTER = 0x0800, /* monotonic counters */
- WH_MESSAGE_GROUP_CANCEL = 0x0900, /* request cancellation */
- WH_MESSAGE_GROUP_CUSTOM = 0x0A00, /* User-specified features */
- WH_MESSAGE_GROUP_CRYPTO_DMA = 0x0B00, /* DMA crypto operations */
- WH_MESSAGE_GROUP_CERT = 0x0C00, /* Certificate operations */
+ WH_MESSAGE_GROUP_COMM = 0x0100, /* Messages used for comms */
+ WH_MESSAGE_GROUP_NVM = 0x0200, /* NVM functions */
+ WH_MESSAGE_GROUP_KEY = 0x0300, /* Key/counter management */
+ WH_MESSAGE_GROUP_CRYPTO = 0x0400, /* wolfCrypt CryptoCb */
+ WH_MESSAGE_GROUP_IMAGE = 0x0500, /* Image/boot management */
+ WH_MESSAGE_GROUP_PKCS11 = 0x0600, /* PKCS11 protocol */
+ WH_MESSAGE_GROUP_SHE = 0x0700, /* SHE protocol */
+ WH_MESSAGE_GROUP_COUNTER = 0x0800, /* monotonic counters */
+ WH_MESSAGE_GROUP_CANCEL = 0x0900, /* request cancellation */
+ WH_MESSAGE_GROUP_CUSTOM = 0x0A00, /* User-specified features */
+ WH_MESSAGE_GROUP_CRYPTO_DMA = 0x0B00, /* DMA crypto operations */
+ WH_MESSAGE_GROUP_CERT = 0x0C00, /* Certificate operations */
- WH_MESSAGE_ACTION_MASK = 0x00FF, /* 255 subtypes per group*/
- WH_MESSAGE_ACTION_NONE = 0x0000, /* No action. Invalid. */
+ WH_MESSAGE_ACTION_MASK = 0x00FF, /* 255 subtypes per group*/
+ WH_MESSAGE_ACTION_NONE = 0x0000, /* No action. Invalid. */
};
/* keystore actions */
@@ -61,6 +61,9 @@ enum WH_KEY_ENUM {
WH_KEY_ERASE,
WH_KEY_CACHE_DMA,
WH_KEY_EXPORT_DMA,
+ WH_KEY_WRAP,
+ WH_KEY_UNWRAPEXPORT,
+ WH_KEY_UNWRAPCACHE
};
/* SHE actions */
diff --git a/wolfhsm/wh_message_comm.h b/wolfhsm/wh_message_comm.h
index 884653e8..711f2998 100644
--- a/wolfhsm/wh_message_comm.h
+++ b/wolfhsm/wh_message_comm.h
@@ -45,12 +45,11 @@ enum WH_MESSAGE_COMM_ACTION_ENUM {
/* Info request/response data sizes*/
enum WH_INFO_ENUM {
- WH_INFO_VERSION_LEN = 8,
- WH_INFO_BUILD_LEN = 8,
+ WH_INFO_VERSION_LEN = 9,
+ WH_INFO_BUILD_LEN = 9,
};
-
/* Generic error response message. */
typedef struct {
int return_code;
@@ -94,6 +93,7 @@ typedef struct {
uint32_t nvm_state;
uint8_t version[WH_INFO_VERSION_LEN];
uint8_t build[WH_INFO_BUILD_LEN];
+ uint8_t WH_PAD[6];
} whMessageCommInfoResponse;
int wh_MessageComm_TranslateInfoResponse(uint16_t magic,
diff --git a/wolfhsm/wh_message_keystore.h b/wolfhsm/wh_message_keystore.h
index fdf687f8..48659cf0 100644
--- a/wolfhsm/wh_message_keystore.h
+++ b/wolfhsm/wh_message_keystore.h
@@ -223,4 +223,94 @@ int wh_MessageKeystore_TranslateExportDmaResponse(
uint16_t magic, const whMessageKeystore_ExportDmaResponse* src,
whMessageKeystore_ExportDmaResponse* dest);
-#endif /* !WOLFHSM_WH_MESSAGE_KEYSTORE_H_ */
\ No newline at end of file
+/* Wrap Key Request */
+typedef struct {
+ uint16_t keySz;
+ uint16_t serverKeyId;
+ uint16_t cipherType;
+ /* Data follows:
+ * whNvmMetadata metadata
+ * uint8_t key[keySz]
+ */
+} whMessageKeystore_WrapRequest;
+
+/* Wrap Key Response */
+typedef struct {
+ uint32_t rc;
+ uint16_t wrappedKeySz;
+ uint16_t cipherType;
+ /* Data follows:
+ * uint8_t wrappedKey[wrappedKeySz]
+ */
+} whMessageKeystore_WrapResponse;
+
+/* Wrap key translation functions */
+int wh_MessageKeystore_TranslateWrapRequest(
+ uint16_t magic, const whMessageKeystore_WrapRequest* src,
+ whMessageKeystore_WrapRequest* dest);
+
+int wh_MessageKeystore_TranslateWrapResponse(
+ uint16_t magic, const whMessageKeystore_WrapResponse* src,
+ whMessageKeystore_WrapResponse* dest);
+
+/* Unwrap Key export Request */
+typedef struct {
+ uint16_t wrappedKeySz;
+ uint16_t serverKeyId;
+ uint16_t cipherType;
+ uint8_t WH_PAD[2];
+ /* Data follows:
+ * uint8_t wrappedKey[wrappedKeySz]
+ */
+} whMessageKeystore_UnwrapAndExportRequest;
+
+/* Unwrap Key export Response*/
+typedef struct {
+ uint32_t rc;
+ uint16_t keySz;
+ uint16_t cipherType;
+ /* Data follows:
+ * whNvmMetadata metadata
+ * uint8_t key[keySz]
+ */
+} whMessageKeystore_UnwrapAndExportResponse;
+
+
+/* Unwrap Key export translation functions */
+int wh_MessageKeystore_TranslateUnwrapAndExportRequest(
+ uint16_t magic, const whMessageKeystore_UnwrapAndExportRequest* src,
+ whMessageKeystore_UnwrapAndExportRequest* dest);
+
+int wh_MessageKeystore_TranslateUnwrapAndExportResponse(
+ uint16_t magic, const whMessageKeystore_UnwrapAndExportResponse* src,
+ whMessageKeystore_UnwrapAndExportResponse* dest);
+
+/* Unwrap Key Cache Request */
+typedef struct {
+ uint16_t wrappedKeySz;
+ uint16_t serverKeyId;
+ uint16_t cipherType;
+ uint8_t WH_PAD[2];
+ /* Data follows:
+ * uint8_t wrappedKey[wrappedKeySz]
+ */
+} whMessageKeystore_UnwrapAndCacheRequest;
+
+/* Unwrap Key Cache Response*/
+typedef struct {
+ uint32_t rc;
+ uint16_t keyId;
+ uint16_t cipherType;
+} whMessageKeystore_UnwrapAndCacheResponse;
+
+/* Unwrap Key Cache translation functions */
+int wh_MessageKeystore_TranslateUnwrapAndCacheRequest(
+ uint16_t magic, const whMessageKeystore_UnwrapAndCacheRequest* src,
+ whMessageKeystore_UnwrapAndCacheRequest* dest);
+
+int wh_MessageKeystore_TranslateUnwrapAndCacheResponse(
+ uint16_t magic, const whMessageKeystore_UnwrapAndCacheResponse* src,
+ whMessageKeystore_UnwrapAndCacheResponse* dest);
+
+
+#endif /* !WOLFHSM_WH_MESSAGE_KEYSTORE_H_ */
diff --git a/wolfhsm/wh_settings.h b/wolfhsm/wh_settings.h
index 4bb03832..32ab6014 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_KEYWRAP_MAX_KEY_SIZE - The maximum size (in bytes) of a key that
+ * can be wrapped
+ * Default: 512
+ *
* WOLFHSM_CFG_HEXDUMP - If defined, include wh_Utils_HexDump functionality
* using stdio.h
* Default: Not defined
@@ -229,6 +233,26 @@
#endif
#endif
+#if !defined(NO_AES)
+#if defined(HAVE_AESGCM)
+
+#ifndef WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE
+#define WOLFHSM_CFG_KEYWRAP_MAX_KEY_SIZE 2000
+#endif
+
+#endif
+#endif
+
+#if defined(WOLFHSM_CFG_NO_CRYPTO)
+#error "WOLFHSM_CFG_KEYWRAP is incompatible with WOLFHSM_CFG_NO_CRYPTO"
+#endif
+
+#if defined(NO_AES) || !defined(HAVE_AESGCM)
+#error \
+ "WOLFHSM_CFG_KEYWRAP requires NO_AES to be undefined and HAVE_AESGCM to be defined"
+#endif
+
+
#if defined(WOLFHSM_CFG_CERTIFICATE_MANAGER_ACERT)
#if !defined(WOLFSSL_ACERT) || !defined(WOLFSSL_ASN_TEMPLATE)
#error \