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 \