diff --git a/examples/posix/wh_posix_server/user_settings.h b/examples/posix/wh_posix_server/user_settings.h index a21b90deb..70df2dc6a 100644 --- a/examples/posix/wh_posix_server/user_settings.h +++ b/examples/posix/wh_posix_server/user_settings.h @@ -99,6 +99,9 @@ extern "C" { /** Curve25519 Options */ #define HAVE_CURVE25519 +/** Ed25519 Options */ +#define HAVE_ED25519 + /** DH and DHE Options */ #define NO_DH #define HAVE_DH_DEFAULT_PARAMS diff --git a/src/wh_client_crypto.c b/src/wh_client_crypto.c index 108be1d21..c11b931ac 100644 --- a/src/wh_client_crypto.c +++ b/src/wh_client_crypto.c @@ -53,6 +53,7 @@ #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/ecc.h" #include "wolfssl/wolfcrypt/curve25519.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/dilithium.h" #include "wolfssl/wolfcrypt/sha256.h" #include "wolfssl/wolfcrypt/sha512.h" @@ -2037,6 +2038,744 @@ int wh_Client_Curve25519SharedSecret(whClientContext* ctx, } #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 +int wh_Client_Ed25519SetKeyId(ed25519_key* key, whKeyId keyId) +{ + if (key == NULL) { + return WH_ERROR_BADARGS; + } + key->devCtx = WH_KEYID_TO_DEVCTX(keyId); + return WH_ERROR_OK; +} + +int wh_Client_Ed25519GetKeyId(ed25519_key* key, whKeyId* outId) +{ + if ((key == NULL) || (outId == NULL)) { + return WH_ERROR_BADARGS; + } + *outId = WH_DEVCTX_TO_KEYID(key->devCtx); + return WH_ERROR_OK; +} + +int wh_Client_Ed25519ImportKey(whClientContext* ctx, ed25519_key* key, + whKeyId* inout_keyId, whNvmFlags flags, + uint16_t label_len, uint8_t* label) +{ + int ret = WH_ERROR_OK; + whKeyId key_id = WH_KEYID_ERASED; + uint8_t buffer[128] = {0}; + uint16_t buffer_len = sizeof(buffer); + + if ((ctx == NULL) || (key == NULL) || + ((label_len != 0) && (label == NULL))) { + return WH_ERROR_BADARGS; + } + + if (inout_keyId != NULL) { + key_id = *inout_keyId; + } + + ret = + wh_Crypto_Ed25519SerializeKeyDer(key, buffer_len, buffer, &buffer_len); + if (ret == WH_ERROR_OK) { + ret = wh_Client_KeyCache(ctx, flags, label, label_len, buffer, + buffer_len, &key_id); + if ((ret == WH_ERROR_OK) && (inout_keyId != NULL)) { + *inout_keyId = key_id; + } + } + + return ret; +} + +int wh_Client_Ed25519ExportKey(whClientContext* ctx, whKeyId keyId, + ed25519_key* key, uint16_t label_len, + uint8_t* label) +{ + int ret = WH_ERROR_OK; + uint8_t buffer[128] = {0}; + uint16_t buffer_len = sizeof(buffer); + + if ((ctx == NULL) || WH_KEYID_ISERASED(keyId) || (key == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = + wh_Client_KeyExport(ctx, keyId, label, label_len, buffer, &buffer_len); + if (ret == WH_ERROR_OK) { + ret = wh_Crypto_Ed25519DeserializeKeyDer(buffer, buffer_len, key); + if (ret == 0) { + wh_Client_Ed25519SetKeyId(key, keyId); + } + } + + return ret; +} + +static int _Ed25519MakeKey(whClientContext* ctx, whKeyId* inout_key_id, + whNvmFlags flags, uint16_t label_len, uint8_t* label, + ed25519_key* key) +{ + int ret = WH_ERROR_OK; + whKeyId key_id = WH_KEYID_ERASED; + uint8_t* dataPtr = NULL; + whMessageCrypto_Ed25519KeyGenRequest* req = NULL; + whMessageCrypto_Ed25519KeyGenResponse* res = NULL; + + if (ctx == NULL || ((label_len != 0) && (label == NULL))) { + return WH_ERROR_BADARGS; + } + + if (inout_key_id != NULL) { + key_id = *inout_key_id; + } + + dataPtr = wh_CommClient_GetDataPtr(ctx->comm); + if (dataPtr == NULL) { + return WH_ERROR_BADARGS; + } + + req = (whMessageCrypto_Ed25519KeyGenRequest*)_createCryptoRequest( + dataPtr, WC_PK_TYPE_ED25519_KEYGEN); + + uint16_t group = WH_MESSAGE_GROUP_CRYPTO; + uint16_t action = WC_ALGO_TYPE_PK; + uint16_t req_len = + sizeof(whMessageCrypto_GenericRequestHeader) + sizeof(*req); + + if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_BADARGS; + } + + memset(req, 0, sizeof(*req)); + req->flags = flags; + req->keyId = key_id; + req->access = WH_NVM_ACCESS_ANY; + if ((label != NULL) && (label_len > 0)) { + if (label_len > WH_NVM_LABEL_LEN) { + label_len = WH_NVM_LABEL_LEN; + } + memcpy(req->label, label, label_len); + } + + ret = wh_Client_SendRequest(ctx, group, action, req_len, (uint8_t*)dataPtr); + if (ret != WH_ERROR_OK) { + return ret; + } + uint16_t res_len = 0; + do { + ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); + } while (ret == WH_ERROR_NOTREADY); + + if (ret != WH_ERROR_OK) { + return ret; + } + + if (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_PK) { + return WH_ERROR_ABORTED; + } + + ret = + _getCryptoResponse(dataPtr, WC_PK_TYPE_ED25519_KEYGEN, (uint8_t**)&res); + if (ret >= 0) { + key_id = (whKeyId)res->keyId; + if (inout_key_id != NULL) { + *inout_key_id = key_id; + } + if (key != NULL) { + wh_Client_Ed25519SetKeyId(key, key_id); + if (flags & WH_NVM_FLAGS_EPHEMERAL) { + uint8_t* out = (uint8_t*)(res + 1); + uint16_t outSz = (uint16_t)res->outSz; + if (outSz + sizeof(whMessageCrypto_GenericResponseHeader) + + sizeof(*res) > + WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_ABORTED; + } + ret = wh_Crypto_Ed25519DeserializeKeyDer(out, outSz, key); + } + } + } + + return ret; +} + +int wh_Client_Ed25519MakeExportKey(whClientContext* ctx, ed25519_key* key) +{ + if (key == NULL) { + return WH_ERROR_BADARGS; + } + + return _Ed25519MakeKey(ctx, NULL, WH_NVM_FLAGS_EPHEMERAL, 0, NULL, key); +} + +int wh_Client_Ed25519MakeCacheKey(whClientContext* ctx, whKeyId* inout_key_id, + whNvmFlags flags, uint16_t label_len, + uint8_t* label) +{ + if (inout_key_id == NULL) { + return WH_ERROR_BADARGS; + } + + return _Ed25519MakeKey(ctx, inout_key_id, flags, label_len, label, NULL); +} + +int wh_Client_Ed25519Sign(whClientContext* ctx, ed25519_key* key, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + uint8_t* sig, uint32_t* inout_sig_len) +{ + int ret = 0; + whMessageCrypto_Ed25519SignRequest* req = NULL; + whMessageCrypto_Ed25519SignResponse* res = NULL; + uint8_t* dataPtr = NULL; + + whKeyId key_id = WH_DEVCTX_TO_KEYID(key->devCtx); + int evict = 0; + + if ((ctx == NULL) || (key == NULL) || ((msg == NULL) && (msgLen > 0)) || + ((sig != NULL) && (inout_sig_len == NULL)) || + ((context == NULL) && (contextLen > 0))) { + return WH_ERROR_BADARGS; + } + + if ((type != (byte)Ed25519) && (type != (byte)Ed25519ctx) && + (type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + if ((type == (byte)Ed25519) && (contextLen != 0 || context != NULL)) { + return WH_ERROR_BADARGS; + } + if (contextLen > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + + uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) + + sizeof(*req) + msgLen + contextLen; + if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_BADARGS; + } + + if (WH_KEYID_ISERASED(key_id)) { + uint8_t keyLabel[] = "TempEd25519Sign"; + whNvmFlags flags = WH_NVM_FLAGS_USAGE_SIGN; + + ret = wh_Client_Ed25519ImportKey(ctx, key, &key_id, flags, + sizeof(keyLabel), keyLabel); + if (ret == WH_ERROR_OK) { + evict = 1; + } + } + + if (ret == WH_ERROR_OK) { + uint16_t group = WH_MESSAGE_GROUP_CRYPTO; + uint16_t action = WC_ALGO_TYPE_PK; + uint32_t options = 0; + + dataPtr = wh_CommClient_GetDataPtr(ctx->comm); + if (dataPtr == NULL) { + return WH_ERROR_BADARGS; + } + + req = (whMessageCrypto_Ed25519SignRequest*)_createCryptoRequest( + dataPtr, WC_PK_TYPE_ED25519_SIGN); + + uint8_t* req_msg = (uint8_t*)(req + 1); + uint8_t* req_ctx = req_msg + msgLen; + + if (evict != 0) { + options |= WH_MESSAGE_CRYPTO_ED25519_SIGN_OPTIONS_EVICT; + } + + memset(req, 0, sizeof(*req)); + req->options = options; + req->keyId = key_id; + req->msgSz = msgLen; + req->type = type; + req->ctxSz = contextLen; + if ((msg != NULL) && (msgLen > 0)) { + memcpy(req_msg, msg, msgLen); + } + if ((context != NULL) && (contextLen > 0)) { + memcpy(req_ctx, context, contextLen); + } + + ret = wh_Client_SendRequest(ctx, group, action, req_len, + (uint8_t*)dataPtr); + if (ret == WH_ERROR_OK) { + /* Server will evict at this point. Reset evict */ + evict = 0; + + uint16_t res_len = 0; + do { + ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); + } while (ret == WH_ERROR_NOTREADY); + + if (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_PK) { + ret = WH_ERROR_ABORTED; + } + + if (ret == WH_ERROR_OK) { + ret = _getCryptoResponse(dataPtr, WC_PK_TYPE_ED25519_SIGN, + (uint8_t**)&res); + if (ret >= 0) { + uint32_t res_total = + sizeof(whMessageCrypto_GenericResponseHeader) + + sizeof(*res) + res->sigSz; + if (res_total > res_len) { + ret = WH_ERROR_ABORTED; + } + } + if (ret >= 0) { + uint8_t* res_sig = (uint8_t*)(res + 1); + uint32_t sig_len = res->sigSz; + if (inout_sig_len != NULL) { + if (sig_len > *inout_sig_len) { + sig_len = *inout_sig_len; + } + *inout_sig_len = sig_len; + } + if ((sig != NULL) && (sig_len > 0)) { + memcpy(sig, res_sig, sig_len); + } + } + } + } + } + + if (evict != 0) { + (void)wh_Client_KeyEvict(ctx, key_id); + } + + /* map ASN key decoding errors to WH_ERROR_BADARGS */ + if (ret == ASN_PARSE_E) + ret = WH_ERROR_BADARGS; + + return ret; +} + +int wh_Client_Ed25519Verify(whClientContext* ctx, ed25519_key* key, + const uint8_t* sig, uint32_t sigLen, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + int* out_res) +{ + int ret = 0; + whMessageCrypto_Ed25519VerifyRequest* req = NULL; + whMessageCrypto_Ed25519VerifyResponse* res = NULL; + uint8_t* dataPtr = NULL; + whKeyId key_id = WH_DEVCTX_TO_KEYID(key->devCtx); + int evict = 0; + uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) + + sizeof(*req) + sigLen + msgLen + contextLen; + + if ((ctx == NULL) || (key == NULL) || (sig == NULL) || (msg == NULL) || + (out_res == NULL) || ((context == NULL) && (contextLen > 0))) { + return WH_ERROR_BADARGS; + } + + if ((type != (byte)Ed25519) && (type != (byte)Ed25519ctx) && + (type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + if ((type == (byte)Ed25519) && (contextLen != 0 || context != NULL)) { + return WH_ERROR_BADARGS; + } + if (contextLen > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + + if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_BADARGS; + } + + *out_res = 0; + + if (WH_KEYID_ISERASED(key_id)) { + uint8_t keyLabel[] = "TempEd25519Verify"; + whNvmFlags flags = WH_NVM_FLAGS_USAGE_VERIFY; + + ret = wh_Client_Ed25519ImportKey(ctx, key, &key_id, flags, + sizeof(keyLabel), keyLabel); + if (ret == WH_ERROR_OK) { + evict = 1; + } + } + + if (ret == WH_ERROR_OK) { + uint16_t group = WH_MESSAGE_GROUP_CRYPTO; + uint16_t action = WC_ALGO_TYPE_PK; + uint32_t options = 0; + + dataPtr = wh_CommClient_GetDataPtr(ctx->comm); + if (dataPtr == NULL) { + return WH_ERROR_BADARGS; + } + + req = (whMessageCrypto_Ed25519VerifyRequest*)_createCryptoRequest( + dataPtr, WC_PK_TYPE_ED25519_VERIFY); + + uint8_t* req_sig = (uint8_t*)(req + 1); + uint8_t* req_msg = req_sig + sigLen; + uint8_t* req_ctx = req_msg + msgLen; + + if (evict != 0) { + options |= WH_MESSAGE_CRYPTO_ED25519_VERIFY_OPTIONS_EVICT; + } + + memset(req, 0, sizeof(*req)); + req->options = options; + req->keyId = key_id; + req->sigSz = sigLen; + req->msgSz = msgLen; + req->type = type; + req->ctxSz = contextLen; + + memcpy(req_sig, sig, sigLen); + memcpy(req_msg, msg, msgLen); + if ((context != NULL) && (contextLen > 0)) { + memcpy(req_ctx, context, contextLen); + } + + ret = wh_Client_SendRequest(ctx, group, action, req_len, + (uint8_t*)dataPtr); + if (ret == WH_ERROR_OK) { + /* Server will evict at this point. Reset evict */ + evict = 0; + + uint16_t res_len = 0; + do { + ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); + } while (ret == WH_ERROR_NOTREADY); + + if (group != WH_MESSAGE_GROUP_CRYPTO || action != WC_ALGO_TYPE_PK) { + ret = WH_ERROR_ABORTED; + } + + if (ret == WH_ERROR_OK) { + ret = _getCryptoResponse(dataPtr, WC_PK_TYPE_ED25519_VERIFY, + (uint8_t**)&res); + if (ret >= 0 && res != NULL) { + uint32_t res_total = + sizeof(whMessageCrypto_GenericResponseHeader) + + sizeof(*res); + if (res_total > res_len) { + ret = WH_ERROR_ABORTED; + } + *out_res = res->res; + } + } + } + } + + if (evict != 0) { + (void)wh_Client_KeyEvict(ctx, key_id); + } + + /* map ASN key decoding errors to WH_ERROR_BADARGS */ + if (ret == ASN_PARSE_E) + ret = WH_ERROR_BADARGS; + + return ret; +} + +#ifdef WOLFHSM_CFG_DMA +int wh_Client_Ed25519SignDma(whClientContext* ctx, ed25519_key* key, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + uint8_t* sig, uint32_t* inout_sig_len) +{ + int ret = 0; + whMessageCrypto_Ed25519SignDmaRequest* req = NULL; + whMessageCrypto_Ed25519SignDmaResponse* res = NULL; + uint8_t* dataPtr = NULL; + uintptr_t msgAddr = 0; + uintptr_t sigAddr = 0; + + whKeyId key_id = WH_DEVCTX_TO_KEYID(key->devCtx); + int evict = 0; + + if ((ctx == NULL) || (key == NULL) || ((msg == NULL) && (msgLen > 0)) || + (sig == NULL) || (inout_sig_len == NULL) || + ((context == NULL) && (contextLen > 0))) { + return WH_ERROR_BADARGS; + } + + if ((type != (byte)Ed25519) && (type != (byte)Ed25519ctx) && + (type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + if ((type == (byte)Ed25519) && (contextLen != 0 || context != NULL)) { + return WH_ERROR_BADARGS; + } + if (contextLen > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + + uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) + + sizeof(*req) + contextLen; + if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_BADARGS; + } + + if (WH_KEYID_ISERASED(key_id)) { + uint8_t keyLabel[] = "TempEd25519SignDma"; + whNvmFlags flags = WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY; + + ret = wh_Client_Ed25519ImportKey(ctx, key, &key_id, flags, + sizeof(keyLabel), keyLabel); + if (ret == WH_ERROR_OK) { + evict = 1; + } + } + + if (ret == WH_ERROR_OK) { + uint16_t group = WH_MESSAGE_GROUP_CRYPTO_DMA; + uint16_t action = WC_ALGO_TYPE_PK; + uint32_t options = 0; + + dataPtr = wh_CommClient_GetDataPtr(ctx->comm); + if (dataPtr == NULL) { + return WH_ERROR_BADARGS; + } + + req = (whMessageCrypto_Ed25519SignDmaRequest*)_createCryptoRequest( + dataPtr, WC_PK_TYPE_ED25519_SIGN); + + uint8_t* req_ctx = (uint8_t*)(req + 1); + + if (evict != 0) { + options |= WH_MESSAGE_CRYPTO_ED25519_SIGN_OPTIONS_EVICT; + } + + memset(req, 0, sizeof(*req)); + req->options = options; + req->keyId = key_id; + req->type = type; + req->ctxSz = contextLen; + req->msg.sz = msgLen; + req->sig.sz = (inout_sig_len != NULL) ? *inout_sig_len : 0; + if ((context != NULL) && (contextLen > 0)) { + memcpy(req_ctx, context, contextLen); + } + + ret = wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)msg, (void**)&msgAddr, req->msg.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whDmaFlags){0}); + if (ret == WH_ERROR_OK) { + req->msg.addr = msgAddr; + ret = wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)sig, (void**)&sigAddr, req->sig.sz, + WH_DMA_OPER_CLIENT_WRITE_PRE, (whDmaFlags){0}); + } + if (ret == WH_ERROR_OK) { + req->sig.addr = sigAddr; + + ret = wh_Client_SendRequest(ctx, group, action, req_len, + (uint8_t*)dataPtr); + } + if (ret == WH_ERROR_OK) { + evict = 0; + + uint16_t res_len = 0; + do { + ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); + } while (ret == WH_ERROR_NOTREADY); + + if (group != WH_MESSAGE_GROUP_CRYPTO_DMA || + action != WC_ALGO_TYPE_PK) { + ret = WH_ERROR_ABORTED; + } + + if (ret == WH_ERROR_OK) { + ret = _getCryptoResponse(dataPtr, WC_PK_TYPE_ED25519_SIGN, + (uint8_t**)&res); + if (ret >= 0 && res != NULL) { + uint32_t res_total = + sizeof(whMessageCrypto_GenericResponseHeader) + + sizeof(*res); + if (res_total > res_len) { + ret = WH_ERROR_ABORTED; + } + } + if (ret >= 0) { + if (inout_sig_len != NULL) { + *inout_sig_len = res->sigSz; + } + } + } + } + + (void)wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)sig, (void**)&sigAddr, req->sig.sz, + WH_DMA_OPER_CLIENT_WRITE_POST, (whDmaFlags){0}); + (void)wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)msg, (void**)&msgAddr, req->msg.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whDmaFlags){0}); + } + + if (evict != 0) { + (void)wh_Client_KeyEvict(ctx, key_id); + } + + /* map ASN key decoding errors to WH_ERROR_BADARGS */ + if (ret == ASN_PARSE_E) + ret = WH_ERROR_BADARGS; + + return ret; +} + +int wh_Client_Ed25519VerifyDma(whClientContext* ctx, ed25519_key* key, + const uint8_t* sig, uint32_t sigLen, + const uint8_t* msg, uint32_t msgLen, + uint8_t type, const uint8_t* context, + uint32_t contextLen, int* out_res) +{ + int ret = 0; + whMessageCrypto_Ed25519VerifyDmaRequest* req = NULL; + whMessageCrypto_Ed25519VerifyDmaResponse* res = NULL; + uint8_t* dataPtr = NULL; + uintptr_t sigAddr = 0; + uintptr_t msgAddr = 0; + uint16_t req_len = sizeof(whMessageCrypto_GenericRequestHeader) + + sizeof(*req) + contextLen; + whKeyId key_id = WH_DEVCTX_TO_KEYID(key->devCtx); + int evict = 0; + + if ((ctx == NULL) || (key == NULL) || (sig == NULL) || (msg == NULL) || + (out_res == NULL) || ((context == NULL) && (contextLen > 0))) { + return WH_ERROR_BADARGS; + } + + if ((type != (byte)Ed25519) && (type != (byte)Ed25519ctx) && + (type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + if ((type == (byte)Ed25519) && (contextLen != 0 || context != NULL)) { + return WH_ERROR_BADARGS; + } + if (contextLen > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + + if (req_len > WOLFHSM_CFG_COMM_DATA_LEN) { + return WH_ERROR_BADARGS; + } + + *out_res = 0; + + if (WH_KEYID_ISERASED(key_id)) { + uint8_t keyLabel[] = "TempEd25519VerifyDma"; + whNvmFlags flags = WH_NVM_FLAGS_USAGE_SIGN | WH_NVM_FLAGS_USAGE_VERIFY; + + ret = wh_Client_Ed25519ImportKey(ctx, key, &key_id, flags, + sizeof(keyLabel), keyLabel); + if (ret == WH_ERROR_OK) { + evict = 1; + } + } + + if (ret == WH_ERROR_OK) { + uint16_t group = WH_MESSAGE_GROUP_CRYPTO_DMA; + uint16_t action = WC_ALGO_TYPE_PK; + uint32_t options = 0; + + dataPtr = wh_CommClient_GetDataPtr(ctx->comm); + if (dataPtr == NULL) { + return WH_ERROR_BADARGS; + } + + req = (whMessageCrypto_Ed25519VerifyDmaRequest*)_createCryptoRequest( + dataPtr, WC_PK_TYPE_ED25519_VERIFY); + + uint8_t* req_ctx = (uint8_t*)(req + 1); + + if (evict != 0) { + options |= WH_MESSAGE_CRYPTO_ED25519_VERIFY_OPTIONS_EVICT; + } + + memset(req, 0, sizeof(*req)); + req->options = options; + req->keyId = key_id; + req->type = type; + req->ctxSz = contextLen; + req->sig.sz = sigLen; + req->msg.sz = msgLen; + if ((context != NULL) && (contextLen > 0)) { + memcpy(req_ctx, context, contextLen); + } + + ret = wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)sig, (void**)&sigAddr, req->sig.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whDmaFlags){0}); + if (ret == WH_ERROR_OK) { + req->sig.addr = sigAddr; + ret = wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)msg, (void**)&msgAddr, req->msg.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whDmaFlags){0}); + } + if (ret == WH_ERROR_OK) { + req->msg.addr = msgAddr; + + ret = wh_Client_SendRequest(ctx, group, action, req_len, + (uint8_t*)dataPtr); + } + if (ret == WH_ERROR_OK) { + evict = 0; + + uint16_t res_len = 0; + do { + ret = wh_Client_RecvResponse(ctx, &group, &action, &res_len, + (uint8_t*)dataPtr); + } while (ret == WH_ERROR_NOTREADY); + + if (group != WH_MESSAGE_GROUP_CRYPTO_DMA || + action != WC_ALGO_TYPE_PK) { + ret = WH_ERROR_ABORTED; + } + + if (ret == WH_ERROR_OK) { + ret = _getCryptoResponse(dataPtr, WC_PK_TYPE_ED25519_VERIFY, + (uint8_t**)&res); + if (ret >= 0 && res != NULL) { + uint32_t res_total = + sizeof(whMessageCrypto_GenericResponseHeader) + + sizeof(*res); + if (res_total > res_len) { + ret = WH_ERROR_ABORTED; + } + } + if (ret >= 0) { + *out_res = res->verifyResult; + } + } + } + + (void)wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)msg, (void**)&msgAddr, req->msg.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whDmaFlags){0}); + (void)wh_Client_DmaProcessClientAddress( + ctx, (uintptr_t)sig, (void**)&sigAddr, req->sig.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whDmaFlags){0}); + } + + if (evict != 0) { + (void)wh_Client_KeyEvict(ctx, key_id); + } + + /* map ASN key decoding errors to WH_ERROR_BADARGS */ + if (ret == ASN_PARSE_E) + ret = WH_ERROR_BADARGS; + + return ret; +} +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifndef NO_RSA int wh_Client_RsaSetKeyId(RsaKey* key, whNvmId keyId) { diff --git a/src/wh_client_cryptocb.c b/src/wh_client_cryptocb.c index cd1deb8e7..2eb38cf0b 100644 --- a/src/wh_client_cryptocb.c +++ b/src/wh_client_cryptocb.c @@ -357,6 +357,65 @@ int wh_Client_CryptoCb(int devId, wc_CryptoInfo* info, void* inCtx) *out_len = len; } } break; + +#ifdef HAVE_ED25519 + case WC_PK_TYPE_ED25519_KEYGEN: { + ed25519_key* key = info->pk.ed25519kg.key; + /* Only default Ed25519 supported */ + ret = wh_Client_Ed25519MakeExportKey(ctx, key); + if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + } break; + + case WC_PK_TYPE_ED25519_SIGN: { + ed25519_key* key = info->pk.ed25519sign.key; + const uint8_t* in = (const uint8_t*)info->pk.ed25519sign.in; + uint32_t inLen = info->pk.ed25519sign.inLen; + uint8_t* out = info->pk.ed25519sign.out; + word32* outLen = info->pk.ed25519sign.outLen; + uint8_t type = info->pk.ed25519sign.type; + uint32_t len; + + len = 0; + if (outLen != NULL) { + len = *outLen; + } + ret = wh_Client_Ed25519Sign( + ctx, key, in, inLen, type, info->pk.ed25519sign.context, + info->pk.ed25519sign.contextLen, out, &len); + if (ret == WH_ERROR_OK && outLen != NULL) { + *outLen = len; + } + else if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + else if (ret == WH_ERROR_NOTIMPL) { + ret = CRYPTOCB_UNAVAILABLE; + } + } break; + + case WC_PK_TYPE_ED25519_VERIFY: { + ed25519_key* key = info->pk.ed25519verify.key; + const uint8_t* sig = info->pk.ed25519verify.sig; + uint32_t sigLen = info->pk.ed25519verify.sigLen; + const uint8_t* msg = info->pk.ed25519verify.msg; + uint32_t msgLen = info->pk.ed25519verify.msgLen; + int* res = info->pk.ed25519verify.res; + uint8_t type = info->pk.ed25519verify.type; + + ret = + wh_Client_Ed25519Verify(ctx, key, sig, sigLen, msg, msgLen, + type, info->pk.ed25519verify.context, + info->pk.ed25519verify.contextLen, res); + if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + else if (ret == WH_ERROR_NOTIMPL) { + ret = CRYPTOCB_UNAVAILABLE; + } + } break; +#endif /* HAVE_ED25519 */ #endif /* HAVE_CURVE25519 */ #if defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) @@ -802,6 +861,65 @@ int wh_Client_CryptoCbDma(int devId, wc_CryptoInfo* info, void* inCtx) ret = _handlePqcSigCheckPrivKey(ctx, info, 1); break; #endif /* HAVE_DILITHIUM || HAVE_FALCON */ +#ifdef HAVE_ED25519 + case WC_PK_TYPE_ED25519_KEYGEN: { + ed25519_key* key = info->pk.ed25519kg.key; + /* Only default Ed25519 supported */ + ret = wh_Client_Ed25519MakeExportKey(ctx, key); + if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + } break; + + case WC_PK_TYPE_ED25519_SIGN: { + ed25519_key* key = info->pk.ed25519sign.key; + const uint8_t* in = (const uint8_t*)info->pk.ed25519sign.in; + uint32_t inLen = info->pk.ed25519sign.inLen; + uint8_t* out = info->pk.ed25519sign.out; + word32* outLen = info->pk.ed25519sign.outLen; + uint8_t type = info->pk.ed25519sign.type; + uint32_t len; + + len = 0; + if (outLen != NULL) { + len = *outLen; + } + ret = wh_Client_Ed25519SignDma( + ctx, key, in, inLen, type, info->pk.ed25519sign.context, + info->pk.ed25519sign.contextLen, out, &len); + if (ret == WH_ERROR_OK && outLen != NULL) { + *outLen = len; + } + else if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + else if (ret == WH_ERROR_NOTIMPL) { + ret = CRYPTOCB_UNAVAILABLE; + } + } break; + + case WC_PK_TYPE_ED25519_VERIFY: { + ed25519_key* key = info->pk.ed25519verify.key; + const uint8_t* sig = info->pk.ed25519verify.sig; + uint32_t sigLen = info->pk.ed25519verify.sigLen; + const uint8_t* msg = info->pk.ed25519verify.msg; + uint32_t msgLen = info->pk.ed25519verify.msgLen; + int* res = info->pk.ed25519verify.res; + uint8_t type = info->pk.ed25519verify.type; + + ret = wh_Client_Ed25519VerifyDma( + ctx, key, sig, sigLen, msg, msgLen, type, + info->pk.ed25519verify.context, + info->pk.ed25519verify.contextLen, res); + if (ret == WH_ERROR_BADARGS) { + ret = BAD_FUNC_ARG; + } + else if (ret == WH_ERROR_NOTIMPL) { + ret = CRYPTOCB_UNAVAILABLE; + } + } break; +#endif /* HAVE_ED25519 */ + } } break; /* case WC_ALGO_TYPE_PK */ diff --git a/src/wh_crypto.c b/src/wh_crypto.c index 57a66650a..878a6df2b 100644 --- a/src/wh_crypto.c +++ b/src/wh_crypto.c @@ -39,6 +39,7 @@ #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/dilithium.h" #include "wolfhsm/wh_error.h" @@ -247,6 +248,55 @@ int wh_Crypto_Curve25519DeserializeKey(const uint8_t* derBuffer, } #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 +int wh_Crypto_Ed25519SerializeKeyDer(const ed25519_key* key, uint16_t max_size, + uint8_t* buffer, uint16_t* out_size) +{ + int ret = 0; + + if ((key == NULL) || (buffer == NULL)) { + return WH_ERROR_BADARGS; + } + + if (key->privKeySet) { + ret = wc_Ed25519KeyToDer(key, buffer, max_size); + } + else if (key->pubKeySet) { + ret = wc_Ed25519PublicKeyToDer(key, buffer, max_size, 1); + } + else { + ret = WH_ERROR_BADARGS; + } + + if (ret > 0) { + if (out_size != NULL) { + *out_size = (uint16_t)ret; + } + ret = WH_ERROR_OK; + } + return ret; +} + +int wh_Crypto_Ed25519DeserializeKeyDer(const uint8_t* buffer, uint16_t size, + ed25519_key* key) +{ + word32 idx = 0; + int ret; + + if ((buffer == NULL) || (key == NULL) || (size == 0)) { + return WH_ERROR_BADARGS; + } + + /* Try private key first; fall back to public key */ + ret = wc_Ed25519PrivateKeyDecode(buffer, &idx, key, size); + if (ret != 0) { + idx = 0; + ret = wc_Ed25519PublicKeyDecode(buffer, &idx, key, size); + } + return ret; +} +#endif /* HAVE_ED25519 */ + #ifdef HAVE_DILITHIUM int wh_Crypto_MlDsaSerializeKeyDer(MlDsaKey* key, uint16_t max_size, uint8_t* buffer, uint16_t* out_size) diff --git a/src/wh_message_crypto.c b/src/wh_message_crypto.c index 009ea2193..cb914a46c 100644 --- a/src/wh_message_crypto.c +++ b/src/wh_message_crypto.c @@ -538,6 +538,93 @@ int wh_MessageCrypto_TranslateCurve25519Response( return 0; } +/* Ed25519 Key Generation Request translation */ +int wh_MessageCrypto_TranslateEd25519KeyGenRequest( + uint16_t magic, const whMessageCrypto_Ed25519KeyGenRequest* src, + whMessageCrypto_Ed25519KeyGenRequest* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, flags); + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, access); + if (src != dest) { + memcpy(dest->label, src->label, sizeof(src->label)); + } + return 0; +} + +/* Ed25519 Key Generation Response translation */ +int wh_MessageCrypto_TranslateEd25519KeyGenResponse( + uint16_t magic, const whMessageCrypto_Ed25519KeyGenResponse* src, + whMessageCrypto_Ed25519KeyGenResponse* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, outSz); + return 0; +} + +/* Ed25519 Sign Request translation */ +int wh_MessageCrypto_TranslateEd25519SignRequest( + uint16_t magic, const whMessageCrypto_Ed25519SignRequest* src, + whMessageCrypto_Ed25519SignRequest* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, options); + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, msgSz); + WH_T32(magic, dest, src, type); + WH_T32(magic, dest, src, ctxSz); + return 0; +} + +/* Ed25519 Sign Response translation */ +int wh_MessageCrypto_TranslateEd25519SignResponse( + uint16_t magic, const whMessageCrypto_Ed25519SignResponse* src, + whMessageCrypto_Ed25519SignResponse* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, sigSz); + return 0; +} + +/* Ed25519 Verify Request translation */ +int wh_MessageCrypto_TranslateEd25519VerifyRequest( + uint16_t magic, const whMessageCrypto_Ed25519VerifyRequest* src, + whMessageCrypto_Ed25519VerifyRequest* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, options); + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, sigSz); + WH_T32(magic, dest, src, msgSz); + WH_T32(magic, dest, src, type); + WH_T32(magic, dest, src, ctxSz); + return 0; +} + +/* Ed25519 Verify Response translation */ +int wh_MessageCrypto_TranslateEd25519VerifyResponse( + uint16_t magic, const whMessageCrypto_Ed25519VerifyResponse* src, + whMessageCrypto_Ed25519VerifyResponse* dest) +{ + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + WH_T32(magic, dest, src, res); + return 0; +} + /* SHA256 Request translation */ int wh_MessageCrypto_TranslateSha256Request( uint16_t magic, const whMessageCrypto_Sha256Request* src, @@ -1002,6 +1089,116 @@ int wh_MessageCrypto_TranslateMlDsaVerifyDmaResponse( return 0; } +/* Ed25519 DMA Sign Request translation */ +int wh_MessageCrypto_TranslateEd25519SignDmaRequest( + uint16_t magic, const whMessageCrypto_Ed25519SignDmaRequest* src, + whMessageCrypto_Ed25519SignDmaRequest* dest) +{ + int ret; + + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->msg, &dest->msg); + if (ret != 0) { + return ret; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->sig, &dest->sig); + if (ret != 0) { + return ret; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->pub, &dest->pub); + if (ret != 0) { + return ret; + } + + WH_T32(magic, dest, src, options); + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, type); + WH_T32(magic, dest, src, ctxSz); + return 0; +} + +/* Ed25519 DMA Sign Response translation */ +int wh_MessageCrypto_TranslateEd25519SignDmaResponse( + uint16_t magic, const whMessageCrypto_Ed25519SignDmaResponse* src, + whMessageCrypto_Ed25519SignDmaResponse* dest) +{ + int ret; + + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateDmaAddrStatus(magic, &src->dmaAddrStatus, + &dest->dmaAddrStatus); + if (ret != 0) { + return ret; + } + + WH_T32(magic, dest, src, sigSz); + WH_T32(magic, dest, src, pubSz); + return 0; +} + +/* Ed25519 DMA Verify Request translation */ +int wh_MessageCrypto_TranslateEd25519VerifyDmaRequest( + uint16_t magic, const whMessageCrypto_Ed25519VerifyDmaRequest* src, + whMessageCrypto_Ed25519VerifyDmaRequest* dest) +{ + int ret; + + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->sig, &dest->sig); + if (ret != 0) { + return ret; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->msg, &dest->msg); + if (ret != 0) { + return ret; + } + + ret = wh_MessageCrypto_TranslateDmaBuffer(magic, &src->pub, &dest->pub); + if (ret != 0) { + return ret; + } + + WH_T32(magic, dest, src, options); + WH_T32(magic, dest, src, keyId); + WH_T32(magic, dest, src, type); + WH_T32(magic, dest, src, ctxSz); + return 0; +} + +/* Ed25519 DMA Verify Response translation */ +int wh_MessageCrypto_TranslateEd25519VerifyDmaResponse( + uint16_t magic, const whMessageCrypto_Ed25519VerifyDmaResponse* src, + whMessageCrypto_Ed25519VerifyDmaResponse* dest) +{ + int ret; + + if ((src == NULL) || (dest == NULL)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateDmaAddrStatus(magic, &src->dmaAddrStatus, + &dest->dmaAddrStatus); + if (ret != 0) { + return ret; + } + + WH_T32(magic, dest, src, verifyResult); + WH_T32(magic, dest, src, pubSz); + return 0; +} + /* AES DMA Request translation */ int wh_MessageCrypto_TranslateAesDmaRequest( uint16_t magic, const whMessageCrypto_AesDmaRequest* src, diff --git a/src/wh_server_crypto.c b/src/wh_server_crypto.c index ef90c71d4..7bdec659d 100644 --- a/src/wh_server_crypto.c +++ b/src/wh_server_crypto.c @@ -38,6 +38,7 @@ #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/aes.h" #include "wolfssl/wolfcrypt/sha256.h" #include "wolfssl/wolfcrypt/sha512.h" @@ -173,6 +174,26 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic, uint16_t* outSize); #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 +static int _HandleEd25519KeyGen(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize); +static int _HandleEd25519Sign(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize); +static int _HandleEd25519Verify(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize); +#ifdef WOLFHSM_CFG_DMA +static int _HandleEd25519SignDma(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize); +static int _HandleEd25519VerifyDma(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize); +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifdef HAVE_DILITHIUM /* Process a Dilithium KeyGen request packet and produce a response packet */ static int _HandleMlDsaKeyGen(whServerContext* ctx, uint16_t magic, @@ -608,6 +629,63 @@ int wh_Server_EccKeyCacheExport(whServerContext* ctx, whKeyId keyId, } #endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 +int wh_Server_CacheImportEd25519Key(whServerContext* ctx, ed25519_key* key, + whKeyId keyId, whNvmFlags flags, + uint16_t label_len, uint8_t* label) +{ + int ret = WH_ERROR_OK; + uint8_t* cacheBuf = NULL; + whNvmMetadata* cacheMeta; + /* Ed25519 DER (private key) is small; 128 bytes is ample headroom */ + uint16_t max_size = 128; + uint16_t der_size = 0; + + if ((ctx == NULL) || (key == NULL) || WH_KEYID_ISERASED(keyId) || + ((label != NULL) && (label_len > sizeof(cacheMeta->label)))) { + return WH_ERROR_BADARGS; + } + + ret = wh_Server_KeystoreGetCacheSlot(ctx, keyId, max_size, &cacheBuf, + &cacheMeta); + if (ret == WH_ERROR_OK) { + ret = wh_Crypto_Ed25519SerializeKeyDer(key, max_size, cacheBuf, + &der_size); + } + + if (ret == WH_ERROR_OK) { + cacheMeta->id = keyId; + cacheMeta->len = der_size; + cacheMeta->flags = flags; + cacheMeta->access = WH_NVM_ACCESS_ANY; + + if ((label != NULL) && (label_len > 0)) { + memcpy(cacheMeta->label, label, label_len); + } + } + + return ret; +} + +int wh_Server_CacheExportEd25519Key(whServerContext* ctx, whKeyId keyId, + ed25519_key* key) +{ + uint8_t* cacheBuf = NULL; + whNvmMetadata* cacheMeta; + int ret = WH_ERROR_OK; + + if ((ctx == NULL) || (key == NULL) || WH_KEYID_ISERASED(keyId)) { + return WH_ERROR_BADARGS; + } + + ret = wh_Server_KeystoreFreshenKey(ctx, keyId, &cacheBuf, &cacheMeta); + if (ret == WH_ERROR_OK) { + ret = wh_Crypto_Ed25519DeserializeKeyDer(cacheBuf, cacheMeta->len, key); + } + return ret; +} +#endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 int wh_Server_CacheImportCurve25519Key(whServerContext* server, curve25519_key* key, whKeyId keyId, @@ -1758,6 +1836,485 @@ static int _HandleCurve25519SharedSecret(whServerContext* ctx, uint16_t magic, } #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 +static int _HandleEd25519KeyGen(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize) +{ + (void)inSize; + + int ret = WH_ERROR_OK; + ed25519_key key[1]; + whMessageCrypto_Ed25519KeyGenRequest req; + whMessageCrypto_Ed25519KeyGenResponse res; + + ret = wh_MessageCrypto_TranslateEd25519KeyGenRequest( + magic, (const whMessageCrypto_Ed25519KeyGenRequest*)cryptoDataIn, &req); + if (ret != 0) { + return ret; + } + + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + whNvmFlags flags = req.flags; + uint8_t* label = req.label; + uint16_t label_size = WH_NVM_LABEL_LEN; + + uint8_t* res_out = + (uint8_t*)cryptoDataOut + sizeof(whMessageCrypto_Ed25519KeyGenResponse); + uint16_t max_size = (uint16_t)(WOLFHSM_CFG_COMM_DATA_LEN - + (res_out - (uint8_t*)cryptoDataOut)); + uint16_t ser_size = 0; + + ret = wc_ed25519_init_ex(key, NULL, ctx->crypto->devId); + if (ret == 0) { + ret = wc_ed25519_make_key(ctx->crypto->rng, ED25519_KEY_SIZE, key); + if (ret == 0) { + if (flags & WH_NVM_FLAGS_EPHEMERAL) { + key_id = WH_KEYID_ERASED; + ret = wh_Crypto_Ed25519SerializeKeyDer(key, max_size, res_out, + &ser_size); + } + else { + ser_size = 0; + if (WH_KEYID_ISERASED(key_id)) { + ret = wh_Server_KeystoreGetUniqueId(ctx, &key_id); + if (ret != WH_ERROR_OK) { + wc_ed25519_free(key); + return ret; + } + } + if (ret == 0) { + ret = wh_Server_CacheImportEd25519Key( + ctx, key, key_id, flags, label_size, label); + } + } + } + wc_ed25519_free(key); + } + + if (ret == WH_ERROR_OK) { + if (flags & WH_NVM_FLAGS_EPHEMERAL) { + res.keyId = WH_KEYID_ERASED; + } + else { + res.keyId = wh_KeyId_TranslateToClient(key_id); + } + res.outSz = ser_size; + + wh_MessageCrypto_TranslateEd25519KeyGenResponse( + magic, &res, (whMessageCrypto_Ed25519KeyGenResponse*)cryptoDataOut); + + *outSize = sizeof(whMessageCrypto_Ed25519KeyGenResponse) + ser_size; + } + + return ret; +} + +static int _HandleEd25519Sign(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize) +{ + int ret; + ed25519_key key[1]; + whMessageCrypto_Ed25519SignRequest req; + uint8_t sig[ED25519_SIG_SIZE]; + + if (inSize < sizeof(req)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateEd25519SignRequest( + magic, (const whMessageCrypto_Ed25519SignRequest*)cryptoDataIn, &req); + if (ret != 0) { + return ret; + } + WOLFHSM_CFG_PRINTF( + "[server] Ed25519Sign req: options=0x%08X key_id=0x%X msgSz=%u\n", + (unsigned int)req.options, (unsigned int)req.keyId, + (unsigned int)req.msgSz); + + uint32_t available = inSize - sizeof(req); + if (req.msgSz > available) { + return WH_ERROR_BADARGS; + } + available -= req.msgSz; + if (req.ctxSz > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + if (req.ctxSz > available) { + return WH_ERROR_BADARGS; + } + + if ((req.type != (byte)Ed25519) && (req.type != (byte)Ed25519ctx) && + (req.type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + + if (req.type == (byte)Ed25519 && (req.ctxSz != 0U)) { + return WH_ERROR_BADARGS; + } + + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + uint32_t msg_len = req.msgSz; + uint8_t* req_msg = (uint8_t*)cryptoDataIn + sizeof(req); + uint8_t* req_ctx = req_msg + msg_len; + int evict = !!(req.options & WH_MESSAGE_CRYPTO_ED25519_SIGN_OPTIONS_EVICT); + + if (!WH_KEYID_ISERASED(key_id)) { + ret = wh_Server_KeystoreFindEnforceKeyUsage(ctx, key_id, + WH_NVM_FLAGS_USAGE_SIGN); + if (ret != WH_ERROR_OK) { + return ret; + } + } + + uint8_t* res_sig = + (uint8_t*)cryptoDataOut + sizeof(whMessageCrypto_Ed25519SignResponse); + word32 sig_len = sizeof(sig); + + ret = wc_ed25519_init_ex(key, NULL, ctx->crypto->devId); + if (ret == 0) { + ret = wh_Server_CacheExportEd25519Key(ctx, key_id, key); + if (ret == WH_ERROR_OK) { + ret = wc_ed25519_sign_msg_ex(req_msg, msg_len, sig, &sig_len, key, + (byte)req.type, req_ctx, + (byte)req.ctxSz); + } + wc_ed25519_free(key); + } + if (sig_len > WOLFHSM_CFG_COMM_DATA_LEN - + sizeof(whMessageCrypto_Ed25519SignResponse) - + sizeof(whMessageCrypto_GenericResponseHeader)) { + ret = WH_ERROR_ABORTED; + } + if (ret == 0) { + memcpy(res_sig, sig, sig_len); + } + + if (evict) { + /* User requested to evict from cache, even if the call failed */ + (void)wh_Server_KeystoreEvictKey(ctx, key_id); + } + + if (ret == 0) { + whMessageCrypto_Ed25519SignResponse res; + res.sigSz = sig_len; + + wh_MessageCrypto_TranslateEd25519SignResponse( + magic, &res, (whMessageCrypto_Ed25519SignResponse*)cryptoDataOut); + + *outSize = sizeof(whMessageCrypto_Ed25519SignResponse) + sig_len; + } + + return ret; +} + +static int _HandleEd25519Verify(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize) +{ + int ret; + ed25519_key key[1]; + whMessageCrypto_Ed25519VerifyRequest req; + whMessageCrypto_Ed25519VerifyResponse res; + + if (inSize < sizeof(req)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateEd25519VerifyRequest( + magic, (const whMessageCrypto_Ed25519VerifyRequest*)cryptoDataIn, &req); + if (ret != 0) { + return ret; + } + WOLFHSM_CFG_PRINTF("[server] Ed25519Verify req: options=0x%08X key_id=0x%X " + "sigSz=%u msgSz=%u\n", + (unsigned int)req.options, (unsigned int)req.keyId, + (unsigned int)req.sigSz, (unsigned int)req.msgSz); + + uint32_t available = inSize - sizeof(req); + if (req.sigSz > available) { + return WH_ERROR_BADARGS; + } + available -= req.sigSz; + if (req.msgSz > available) { + return WH_ERROR_BADARGS; + } + available -= req.msgSz; + if (req.ctxSz > available) { + return WH_ERROR_BADARGS; + } + if (req.ctxSz > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + + if ((req.type != (byte)Ed25519) && (req.type != (byte)Ed25519ctx) && + (req.type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + uint32_t sig_len = req.sigSz; + uint32_t msg_len = req.msgSz; + uint8_t* req_sig = + (uint8_t*)cryptoDataIn + sizeof(whMessageCrypto_Ed25519VerifyRequest); + uint8_t* req_msg = req_sig + sig_len; + uint8_t* req_ctx = req_msg + msg_len; + int evict = + !!(req.options & WH_MESSAGE_CRYPTO_ED25519_VERIFY_OPTIONS_EVICT); + + if (!WH_KEYID_ISERASED(key_id)) { + ret = wh_Server_KeystoreFindEnforceKeyUsage(ctx, key_id, + WH_NVM_FLAGS_USAGE_VERIFY); + if (ret != WH_ERROR_OK) { + return ret; + } + } + + int result = 0; + + ret = wc_ed25519_init_ex(key, NULL, ctx->crypto->devId); + if (ret == 0) { + ret = wh_Server_CacheExportEd25519Key(ctx, key_id, key); + if (ret == WH_ERROR_OK) { + ret = wc_ed25519_verify_msg_ex(req_sig, sig_len, req_msg, msg_len, + &result, key, (byte)req.type, + req_ctx, (byte)req.ctxSz); + } + wc_ed25519_free(key); + } + + if (evict != 0) { + (void)wh_Server_KeystoreEvictKey(ctx, key_id); + } + + if (ret == 0) { + res.res = result; + + wh_MessageCrypto_TranslateEd25519VerifyResponse( + magic, &res, (whMessageCrypto_Ed25519VerifyResponse*)cryptoDataOut); + + *outSize = sizeof(whMessageCrypto_Ed25519VerifyResponse); + } + + return ret; +} +#ifdef WOLFHSM_CFG_DMA +static int _HandleEd25519SignDma(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize) +{ + int ret = 0; + ed25519_key key[1]; + void* msgAddr = NULL; + void* sigAddr = NULL; + whMessageCrypto_Ed25519SignDmaRequest req; + whMessageCrypto_Ed25519SignDmaResponse res; + word32 sigLen = 0; + + if (inSize < sizeof(req)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateEd25519SignDmaRequest( + magic, (const whMessageCrypto_Ed25519SignDmaRequest*)cryptoDataIn, + &req); + if (ret != WH_ERROR_OK) { + return ret; + } + + uint32_t available = inSize - sizeof(req); + if (req.ctxSz > available) { + return WH_ERROR_BADARGS; + } + if (req.ctxSz > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + uint8_t* req_ctx = (uint8_t*)cryptoDataIn + sizeof(req); + + if ((req.type != (byte)Ed25519) && (req.type != (byte)Ed25519ctx) && + (req.type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + int evict = !!(req.options & WH_MESSAGE_CRYPTO_ED25519_SIGN_OPTIONS_EVICT); + + if (!WH_KEYID_ISERASED(key_id)) { + ret = wh_Server_KeystoreFindEnforceKeyUsage(ctx, key_id, + WH_NVM_FLAGS_USAGE_SIGN); + if (ret != WH_ERROR_OK) { + return ret; + } + } + + memset(&res, 0, sizeof(res)); + + sigLen = req.sig.sz; + ret = wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.msg.addr, &msgAddr, req.msg.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret != WH_ERROR_OK) { + res.dmaAddrStatus.badAddr = req.msg; + } + if (ret == WH_ERROR_OK) { + ret = wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.sig.addr, &sigAddr, req.sig.sz, + WH_DMA_OPER_CLIENT_WRITE_PRE, (whServerDmaFlags){0}); + if (ret != WH_ERROR_OK) { + res.dmaAddrStatus.badAddr = req.sig; + } + } + if (ret == WH_ERROR_OK) { + ret = wc_ed25519_init_ex(key, NULL, ctx->crypto->devId); + if (ret == 0) { + ret = wh_Server_CacheExportEd25519Key(ctx, key_id, key); + if (ret == WH_ERROR_OK) { + ret = wc_ed25519_sign_msg_ex(msgAddr, req.msg.sz, sigAddr, + &sigLen, key, (byte)req.type, + req_ctx, (byte)req.ctxSz); + if (ret == WH_ERROR_OK) { + res.sigSz = sigLen; + } + } + if ((ret != WH_ERROR_OK) && (res.dmaAddrStatus.badAddr.sz == 0)) { + res.dmaAddrStatus.badAddr = req.sig; + } + } + wc_ed25519_free(key); + } + + (void)wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.sig.addr, &sigAddr, sigLen, + WH_DMA_OPER_CLIENT_WRITE_POST, (whServerDmaFlags){0}); + (void)wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.msg.addr, &msgAddr, req.msg.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whServerDmaFlags){0}); + + if (evict != 0) { + (void)wh_Server_KeystoreEvictKey(ctx, key_id); + } + + if (ret == WH_ERROR_OK) { + (void)wh_MessageCrypto_TranslateEd25519SignDmaResponse( + magic, &res, + (whMessageCrypto_Ed25519SignDmaResponse*)cryptoDataOut); + *outSize = sizeof(res); + } + + return ret; +} + +static int _HandleEd25519VerifyDma(whServerContext* ctx, uint16_t magic, + const void* cryptoDataIn, uint16_t inSize, + void* cryptoDataOut, uint16_t* outSize) +{ + int ret = 0; + ed25519_key key[1]; + void* msgAddr = NULL; + void* sigAddr = NULL; + whMessageCrypto_Ed25519VerifyDmaRequest req; + whMessageCrypto_Ed25519VerifyDmaResponse res; + + if (inSize < sizeof(req)) { + return WH_ERROR_BADARGS; + } + + ret = wh_MessageCrypto_TranslateEd25519VerifyDmaRequest( + magic, (const whMessageCrypto_Ed25519VerifyDmaRequest*)cryptoDataIn, + &req); + if (ret != WH_ERROR_OK) { + return ret; + } + + uint32_t available = inSize - sizeof(req); + if (req.ctxSz > available) { + return WH_ERROR_BADARGS; + } + if (req.ctxSz > WH_CRYPTO_ED25519_MAX_CTX_LEN) { + return WH_ERROR_BADARGS; + } + uint8_t* req_ctx = (uint8_t*)cryptoDataIn + sizeof(req); + + if ((req.type != (byte)Ed25519) && (req.type != (byte)Ed25519ctx) && + (req.type != (byte)Ed25519ph)) { + return WH_ERROR_BADARGS; + } + + whKeyId key_id = wh_KeyId_TranslateFromClient( + WH_KEYTYPE_CRYPTO, ctx->comm->client_id, req.keyId); + int evict = + !!(req.options & WH_MESSAGE_CRYPTO_ED25519_VERIFY_OPTIONS_EVICT); + + if (!WH_KEYID_ISERASED(key_id)) { + ret = wh_Server_KeystoreFindEnforceKeyUsage(ctx, key_id, + WH_NVM_FLAGS_USAGE_VERIFY); + if (ret != WH_ERROR_OK) { + return ret; + } + } + + memset(&res, 0, sizeof(res)); + + ret = wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.sig.addr, &sigAddr, req.sig.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.sig; + } + if (ret == WH_ERROR_OK) { + ret = wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.msg.addr, &msgAddr, req.msg.sz, + WH_DMA_OPER_CLIENT_READ_PRE, (whServerDmaFlags){0}); + if (ret == WH_ERROR_ACCESS) { + res.dmaAddrStatus.badAddr = req.msg; + } + } + + if (ret == WH_ERROR_OK) { + ret = wc_ed25519_init_ex(key, NULL, ctx->crypto->devId); + if (ret == 0) { + ret = wh_Server_CacheExportEd25519Key(ctx, key_id, key); + if (ret == WH_ERROR_OK) { + int verified = 0; + ret = wc_ed25519_verify_msg_ex( + sigAddr, req.sig.sz, msgAddr, req.msg.sz, &verified, key, + (byte)req.type, req_ctx, (byte)req.ctxSz); + if (ret == WH_ERROR_OK) { + res.verifyResult = verified; + } + } + wc_ed25519_free(key); + } + } + + (void)wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.msg.addr, &msgAddr, req.msg.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whServerDmaFlags){0}); + (void)wh_Server_DmaProcessClientAddress( + ctx, (uintptr_t)req.sig.addr, &sigAddr, req.sig.sz, + WH_DMA_OPER_CLIENT_READ_POST, (whServerDmaFlags){0}); + + if (evict != 0) { + (void)wh_Server_KeystoreEvictKey(ctx, key_id); + } + + if (ret == WH_ERROR_OK) { + (void)wh_MessageCrypto_TranslateEd25519VerifyDmaResponse( + magic, &res, + (whMessageCrypto_Ed25519VerifyDmaResponse*)cryptoDataOut); + *outSize = sizeof(res); + } + + return ret; +} +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifndef NO_AES #ifdef WOLFSSL_AES_COUNTER static int _HandleAesCtr(whServerContext* ctx, uint16_t magic, @@ -3523,6 +4080,24 @@ int wh_Server_HandleCryptoRequest(whServerContext* ctx, uint16_t magic, break; #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 + case WC_PK_TYPE_ED25519_KEYGEN: + ret = _HandleEd25519KeyGen(ctx, magic, cryptoDataIn, + cryptoInSize, cryptoDataOut, + &cryptoOutSize); + break; + case WC_PK_TYPE_ED25519_SIGN: + ret = _HandleEd25519Sign(ctx, magic, cryptoDataIn, + cryptoInSize, cryptoDataOut, + &cryptoOutSize); + break; + case WC_PK_TYPE_ED25519_VERIFY: + ret = _HandleEd25519Verify(ctx, magic, cryptoDataIn, + cryptoInSize, cryptoDataOut, + &cryptoOutSize); + break; +#endif /* HAVE_ED25519 */ + #if defined(HAVE_DILITHIUM) || defined(HAVE_FALCON) case WC_PK_TYPE_PQC_SIG_KEYGEN: case WC_PK_TYPE_PQC_SIG_SIGN: @@ -5103,6 +5678,18 @@ int wh_Server_HandleCryptoDmaRequest(whServerContext* ctx, uint16_t magic, rqstHeader.algoSubType); break; #endif /* HAVE_DILITHIUM || HAVE_FALCON */ +#ifdef HAVE_ED25519 + case WC_PK_TYPE_ED25519_SIGN: + ret = _HandleEd25519SignDma(ctx, magic, cryptoDataIn, + cryptoInSize, cryptoDataOut, + &cryptoOutSize); + break; + case WC_PK_TYPE_ED25519_VERIFY: + ret = _HandleEd25519VerifyDma(ctx, magic, cryptoDataIn, + cryptoInSize, cryptoDataOut, + &cryptoOutSize); + break; +#endif /* HAVE_ED25519 */ } break; /* WC_ALGO_TYPE_PK */ diff --git a/test/config/user_settings.h b/test/config/user_settings.h index 776050c59..b2eab3e00 100644 --- a/test/config/user_settings.h +++ b/test/config/user_settings.h @@ -137,6 +137,9 @@ #define WOLFSSL_SHAKE128 #define WOLFSSL_SHAKE256 +/* Ed25519 Options */ +#define HAVE_ED25519 + /* The following options can be individually controlled to customize the * ML-DSA configuration */ #if 0 diff --git a/test/wh_test_crypto.c b/test/wh_test_crypto.c index 686622b87..29ce8626a 100644 --- a/test/wh_test_crypto.c +++ b/test/wh_test_crypto.c @@ -32,6 +32,7 @@ #include "wolfssl/wolfcrypt/settings.h" #include "wolfssl/wolfcrypt/types.h" #include "wolfssl/wolfcrypt/kdf.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfhsm/wh_error.h" @@ -398,6 +399,368 @@ static int whTest_CryptoEcc(whClientContext* ctx, int devId, WC_RNG* rng) } #endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 + +static int whTest_Ed25519ImportToServer(whClientContext* ctx, int devId, + ed25519_key* key, ed25519_key* pubKey, + uint8_t* label, uint16_t labelLen, + whKeyId* outSignKeyId, + whKeyId* outVerifyKeyId) +{ + int ret = 0; + byte pubKeyRaw[ED25519_PUB_KEY_SIZE]; + word32 pubKeySize = sizeof(pubKeyRaw); + whKeyId signKeyId = WH_KEYID_ERASED; + whKeyId verifyKeyId = WH_KEYID_ERASED; + + ret = wc_ed25519_export_public(key, pubKeyRaw, &pubKeySize); + if (ret != 0) { + WH_ERROR_PRINT("Failed to export Ed25519 public key: %d\n", ret); + } + else { + ret = wc_ed25519_import_public(pubKeyRaw, pubKeySize, pubKey); + if (ret != 0) { + WH_ERROR_PRINT("Failed to import Ed25519 public key: %d\n", ret); + } + } + + if (ret == 0) { + ret = wh_Client_Ed25519ImportKey( + ctx, key, &signKeyId, WH_NVM_FLAGS_USAGE_SIGN, labelLen, label); + if (ret != 0) { + WH_ERROR_PRINT("Failed to import Ed25519 key to server: %d\n", ret); + } + else { + /* remove key material from local key structure */ + wc_ed25519_free(key); + ret = wc_ed25519_init_ex(key, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to re-initialize Ed25519 key: %d\n", + ret); + } + else { + wh_Client_Ed25519SetKeyId(key, signKeyId); + } + } + } + + if (ret == 0) { + ret = wh_Client_Ed25519ImportKey(ctx, pubKey, &verifyKeyId, + WH_NVM_FLAGS_USAGE_VERIFY, labelLen, + label); + if (ret != 0) { + WH_ERROR_PRINT( + "Failed to import Ed25519 public key to server: %d\n", ret); + } + else { + /* remove key material from local key structure */ + wc_ed25519_free(pubKey); + ret = wc_ed25519_init_ex(pubKey, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT( + "Failed to re-initialize Ed25519 public key: %d\n", ret); + } + else { + wh_Client_Ed25519SetKeyId(pubKey, verifyKeyId); + } + } + } + + if (ret == 0) { + if (outSignKeyId != NULL) { + *outSignKeyId = signKeyId; + } + if (outVerifyKeyId != NULL) { + *outVerifyKeyId = verifyKeyId; + } + } + + return ret; +} + +static int whTest_CryptoEd25519Inline(whClientContext* ctx, int devId, + WC_RNG* rng) +{ + (void)ctx; + + int ret = 0; + ed25519_key key[1] = {0}; + ed25519_key pubKey[1] = {0}; + byte msg[] = "Test message for Ed25519 signing"; + byte sig[ED25519_SIG_SIZE]; + word32 sigSz = sizeof(sig); + int verified = 0; + const word32 msgSz = (word32)sizeof(msg); + byte pubKeyRaw[ED25519_PUB_KEY_SIZE]; + word32 pubKeySize = sizeof(pubKeyRaw); + + ret = wc_ed25519_init_ex(key, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 key: %d\n", ret); + return ret; + } + + ret = wc_ed25519_init_ex(pubKey, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 public key: %d\n", ret); + wc_ed25519_free(key); + return ret; + } + + ret = wc_ed25519_make_key(rng, ED25519_KEY_SIZE, key); + if (ret != 0) { + WH_ERROR_PRINT("Failed to generate Ed25519 key: %d\n", ret); + } + else { + ret = wc_ed25519_export_public(key, pubKeyRaw, &pubKeySize); + if (ret != 0) { + WH_ERROR_PRINT("Failed to export Ed25519 public key: %d\n", ret); + } + else { + ret = wc_ed25519_import_public(pubKeyRaw, pubKeySize, pubKey); + if (ret != 0) { + WH_ERROR_PRINT("Failed to import Ed25519 public key: %d\n", + ret); + } + } + } + + if (ret == 0) { + sigSz = sizeof(sig); + ret = wc_ed25519_sign_msg(msg, msgSz, sig, &sigSz, key); + if (ret != 0) { + WH_ERROR_PRINT("Failed to sign message with Ed25519: %d\n", ret); + } + else { + ret = wc_ed25519_verify_msg(sig, sigSz, msg, msgSz, &verified, + pubKey); + if (ret != 0) { + WH_ERROR_PRINT("Failed to verify Ed25519 signature: %d\n", ret); + } + else if (verified != 1) { + WH_ERROR_PRINT("Ed25519 signature verification failed\n"); + ret = -1; + } + } + } + + if (ret == 0) { + /* Corrupt signature to ensure verification fails */ + sig[0] ^= 0xFF; + verified = 0; + ret = wc_ed25519_verify_msg(sig, sigSz, msg, msgSz, &verified, pubKey); + if (ret == 0 && verified == 1) { + WH_ERROR_PRINT( + "Modified Ed25519 signature unexpectedly verified\n"); + ret = -1; + } + else { + ret = 0; + } + } + + if (ret == 0) { + WH_TEST_PRINT("Ed25519 INLINE DEVID=0x%X SUCCESS\n", devId); + } + + wc_ed25519_free(pubKey); + wc_ed25519_free(key); + return ret; +} + +static int whTest_CryptoEd25519ServerKey(whClientContext* ctx, int devId, + WC_RNG* rng) +{ + int ret = 0; + ed25519_key key[1] = {0}; + ed25519_key pubKey[1] = {0}; + whKeyId signKeyId = WH_KEYID_ERASED; + whKeyId verifyKeyId = WH_KEYID_ERASED; + byte msg[] = "Ed25519 server key message"; + byte sig[ED25519_SIG_SIZE]; + uint32_t sigSz = sizeof(sig); + int verified = 0; + uint8_t label[] = "Ed25519 Server Key"; + + ret = wc_ed25519_init_ex(key, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 key: %d\n", ret); + return ret; + } + + ret = wc_ed25519_init_ex(pubKey, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 public key: %d\n", ret); + wc_ed25519_free(key); + return ret; + } + + ret = wc_ed25519_make_key(rng, ED25519_KEY_SIZE, key); + if (ret != 0) { + WH_ERROR_PRINT("Failed to generate Ed25519 key: %d\n", ret); + } + else { + ret = whTest_Ed25519ImportToServer(ctx, devId, key, pubKey, label, + sizeof(label), &signKeyId, + &verifyKeyId); + } + + if (ret == 0) { + ret = wh_Client_Ed25519Sign(ctx, key, msg, (uint32_t)sizeof(msg), + (uint8_t)Ed25519, NULL, 0, sig, &sigSz); + if (ret != 0) { + WH_ERROR_PRINT("Failed to sign with server Ed25519 key: %d\n", ret); + } + } + + if (ret == 0) { + ret = wh_Client_Ed25519Verify(ctx, pubKey, sig, sigSz, msg, + (uint32_t)sizeof(msg), (uint8_t)Ed25519, + NULL, 0, &verified); + if (ret != 0) { + WH_ERROR_PRINT("Failed to verify server Ed25519 signature: %d\n", + ret); + } + else if (verified != 1) { + WH_ERROR_PRINT("Server Ed25519 signature verification failed\n"); + ret = -1; + } + } + + if (ret == 0) { + /* Sign-only key should not be allowed to verify */ + int negVerified = 0; + int negRet = wh_Client_Ed25519Verify( + ctx, key, sig, sigSz, msg, (uint32_t)sizeof(msg), (uint8_t)Ed25519, + NULL, 0, &negVerified); + if (negRet == 0) { + WH_ERROR_PRINT("Sign-only Ed25519 key unexpectedly verified\n"); + ret = -1; + } + } + + if (ret == 0) { + sig[0] ^= 0xAA; + verified = 0; + ret = wh_Client_Ed25519Verify(ctx, pubKey, sig, sigSz, msg, + (uint32_t)sizeof(msg), (uint8_t)Ed25519, + NULL, 0, &verified); + if (ret == 0 && verified == 1) { + WH_ERROR_PRINT("Modified server Ed25519 signature unexpectedly " + "verified\n"); + ret = -1; + } + else { + ret = 0; + } + } + + if (!WH_KEYID_ISERASED(signKeyId)) { + (void)wh_Client_KeyEvict(ctx, signKeyId); + } + if (!WH_KEYID_ISERASED(verifyKeyId)) { + (void)wh_Client_KeyEvict(ctx, verifyKeyId); + } + + if (ret == 0) { + WH_TEST_PRINT("Ed25519 SERVER KEY DEVID=0x%X SUCCESS\n", devId); + } + + wc_ed25519_free(pubKey); + wc_ed25519_free(key); + return ret; +} + +#ifdef WOLFHSM_CFG_DMA +static int whTest_CryptoEd25519Dma(whClientContext* ctx, int devId, WC_RNG* rng) +{ + int ret = 0; + ed25519_key key[1] = {0}; + ed25519_key pubKey[1] = {0}; + whKeyId signKeyId = WH_KEYID_ERASED; + whKeyId verifyKeyId = WH_KEYID_ERASED; + byte msg[] = "Ed25519 DMA message"; + byte sig[ED25519_SIG_SIZE]; + uint32_t sigSz = sizeof(sig); + int verified = 0; + uint8_t label[] = "Ed25519 DMA Key"; + + ret = wc_ed25519_init_ex(key, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 key (DMA): %d\n", ret); + return ret; + } + + ret = wc_ed25519_init_ex(pubKey, NULL, devId); + if (ret != 0) { + WH_ERROR_PRINT("Failed to initialize Ed25519 public key (DMA): %d\n", + ret); + wc_ed25519_free(key); + return ret; + } + + ret = wc_ed25519_make_key(rng, ED25519_KEY_SIZE, key); + if (ret != 0) { + WH_ERROR_PRINT("Failed to generate Ed25519 key (DMA): %d\n", ret); + } + else { + ret = whTest_Ed25519ImportToServer(ctx, devId, key, pubKey, label, + sizeof(label), &signKeyId, + &verifyKeyId); + } + + if (ret == 0) { + ret = wh_Client_Ed25519SignDma(ctx, key, msg, (uint32_t)sizeof(msg), + (uint8_t)Ed25519, NULL, 0, sig, &sigSz); + if (ret != 0) { + WH_ERROR_PRINT("Failed to sign via DMA Ed25519 key: %d\n", ret); + } + } + + if (ret == 0) { + ret = wh_Client_Ed25519VerifyDma(ctx, pubKey, sig, sigSz, msg, + (uint32_t)sizeof(msg), + (uint8_t)Ed25519, NULL, 0, &verified); + if (ret != 0) { + WH_ERROR_PRINT("Failed to verify DMA Ed25519 signature: %d\n", ret); + } + else if (verified != 1) { + WH_ERROR_PRINT("DMA Ed25519 signature verification failed\n"); + ret = -1; + } + } + + if (ret == 0) { + /* Sign-only key should not be allowed to verify (DMA) */ + int negVerified = 0; + int negRet = wh_Client_Ed25519VerifyDma( + ctx, key, sig, sigSz, msg, (uint32_t)sizeof(msg), (uint8_t)Ed25519, + NULL, 0, &negVerified); + if (negRet == 0) { + WH_ERROR_PRINT( + "Sign-only Ed25519 key unexpectedly verified (DMA)\n"); + ret = -1; + } + } + + if (!WH_KEYID_ISERASED(signKeyId)) { + (void)wh_Client_KeyEvict(ctx, signKeyId); + } + if (!WH_KEYID_ISERASED(verifyKeyId)) { + (void)wh_Client_KeyEvict(ctx, verifyKeyId); + } + + if (ret == 0) { + WH_TEST_PRINT("Ed25519 DMA DEVID=0x%X SUCCESS\n", devId); + } + + wc_ed25519_free(pubKey); + wc_ed25519_free(key); + return ret; +} +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 static int whTest_CryptoCurve25519(whClientContext* ctx, int devId, WC_RNG* rng) { @@ -4305,6 +4668,33 @@ int whTest_CryptoClientConfig(whClientConfig* config) } #endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 + if (ret != 0) { + WH_ERROR_PRINT("Pre-Ed25519 tests ret=%d\n", ret); + return ret; + } + if (ret == 0) { + ret = whTest_CryptoEd25519Inline(client, WH_DEV_ID, rng); + if (ret != 0) { + WH_ERROR_PRINT("Ed25519 inline test failed: %d\n", ret); + } + } + if (ret == 0) { + ret = whTest_CryptoEd25519ServerKey(client, WH_DEV_ID, rng); + if (ret != 0) { + WH_ERROR_PRINT("Ed25519 server key test failed: %d\n", ret); + } + } +#ifdef WOLFHSM_CFG_DMA + if (ret == 0) { + ret = whTest_CryptoEd25519Dma(client, WH_DEV_ID_DMA, rng); + if (ret != 0) { + WH_ERROR_PRINT("Ed25519 DMA test failed: %d\n", ret); + } + } +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 /* test curve25519 */ if (ret == 0) { @@ -4420,6 +4810,10 @@ int whTest_CryptoClientConfig(whClientConfig* config) (void)wh_Client_CommClose(client); (void)wh_Client_Cleanup(client); + if (ret != 0) { + WH_ERROR_PRINT("whTest_CryptoClientConfig returning error: %d\n", ret); + } + return ret; } #endif /* WOLFHSM_CFG_ENABLE_CLIENT */ @@ -4495,7 +4889,11 @@ int whTest_CryptoServerConfig(whServerConfig* config) !defined(WOLFHSM_CFG_TEST_CLIENT_ONLY_TCP) static void* _whClientTask(void *cf) { - WH_TEST_ASSERT(0 == whTest_CryptoClientConfig(cf)); + int rc = whTest_CryptoClientConfig(cf); + if (rc != 0) { + WH_ERROR_PRINT("whTest_CryptoClientConfig returned %d\n", rc); + } + WH_TEST_ASSERT(0 == rc); return NULL; } #endif /* WOLFHSM_CFG_TEST_POSIX && WOLFHSM_CFG_ENABLE_CLIENT */ diff --git a/wolfhsm/wh_client_crypto.h b/wolfhsm/wh_client_crypto.h index 096d4d1b7..856740b02 100644 --- a/wolfhsm/wh_client_crypto.h +++ b/wolfhsm/wh_client_crypto.h @@ -48,6 +48,7 @@ #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/dilithium.h" #include "wolfssl/wolfcrypt/hmac.h" @@ -274,6 +275,82 @@ int wh_Client_EccVerify(whClientContext* ctx, ecc_key* key, #endif /* HAVE_ECC */ +#ifdef HAVE_ED25519 +/** + * @brief Associates an Ed25519 key with a specific key ID. + * + * Sets the device context of an Ed25519 key to the provided key ID. + */ +int wh_Client_Ed25519SetKeyId(ed25519_key* key, whKeyId keyId); + +/** + * @brief Retrieves the key ID from an Ed25519 key device context. + */ +int wh_Client_Ed25519GetKeyId(ed25519_key* key, whKeyId* outId); + +/** + * @brief Import an Ed25519 key into the server keystore/cache. + */ +int wh_Client_Ed25519ImportKey(whClientContext* ctx, ed25519_key* key, + whKeyId* inout_keyId, whNvmFlags flags, + uint16_t label_len, uint8_t* label); + +/** + * @brief Export an Ed25519 key from the server to the client. + */ +int wh_Client_Ed25519ExportKey(whClientContext* ctx, whKeyId keyId, + ed25519_key* key, uint16_t label_len, + uint8_t* label); + +/** + * @brief Create a new Ed25519 key on the server and export it without caching. + */ +int wh_Client_Ed25519MakeExportKey(whClientContext* ctx, ed25519_key* key); + +/** + * @brief Create a new Ed25519 key on the server and store it in cache/NVM. + */ +int wh_Client_Ed25519MakeCacheKey(whClientContext* ctx, whKeyId* inout_key_id, + whNvmFlags flags, uint16_t label_len, + uint8_t* label); + +/** + * @brief Sign a message using an Ed25519 key on the server. + */ +int wh_Client_Ed25519Sign(whClientContext* ctx, ed25519_key* key, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + uint8_t* sig, uint32_t* inout_sig_len); + +/** + * @brief Verify a message signature using an Ed25519 key on the server. + */ +int wh_Client_Ed25519Verify(whClientContext* ctx, ed25519_key* key, + const uint8_t* sig, uint32_t sigLen, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + int* out_res); + +#ifdef WOLFHSM_CFG_DMA +/** + * @brief Sign a message using an Ed25519 key via DMA. + */ +int wh_Client_Ed25519SignDma(whClientContext* ctx, ed25519_key* key, + const uint8_t* msg, uint32_t msgLen, uint8_t type, + const uint8_t* context, uint32_t contextLen, + uint8_t* sig, uint32_t* inout_sig_len); + +/** + * @brief Verify a signature using an Ed25519 key via DMA. + */ +int wh_Client_Ed25519VerifyDma(whClientContext* ctx, ed25519_key* key, + const uint8_t* sig, uint32_t sigLen, + const uint8_t* msg, uint32_t msgLen, + uint8_t type, const uint8_t* context, + uint32_t contextLen, int* out_res); +#endif /* WOLFHSM_CFG_DMA */ +#endif /* HAVE_ED25519 */ + #ifndef NO_RSA /** * @brief Associates an RSA key with a specific key ID. diff --git a/wolfhsm/wh_crypto.h b/wolfhsm/wh_crypto.h index e0fb95a14..fd729edb4 100644 --- a/wolfhsm/wh_crypto.h +++ b/wolfhsm/wh_crypto.h @@ -40,6 +40,7 @@ #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/dilithium.h" #ifndef NO_AES @@ -85,6 +86,15 @@ int wh_Crypto_Curve25519DeserializeKey(const uint8_t* derBuffer, uint16_t derSize, curve25519_key* key); #endif /* HAVE_CURVE25519 */ +#ifdef HAVE_ED25519 +#define WH_CRYPTO_ED25519_MAX_CTX_LEN (255U) +int wh_Crypto_Ed25519SerializeKeyDer(const ed25519_key* key, uint16_t max_size, + uint8_t* buffer, uint16_t* out_size); + +int wh_Crypto_Ed25519DeserializeKeyDer(const uint8_t* buffer, uint16_t size, + ed25519_key* key); +#endif /* HAVE_ED25519 */ + #ifdef HAVE_DILITHIUM /* Store a MlDsaKey to a byte sequence */ int wh_Crypto_MlDsaSerializeKeyDer(MlDsaKey* key, uint16_t max_size, @@ -97,4 +107,3 @@ int wh_Crypto_MlDsaDeserializeKeyDer(const uint8_t* buffer, uint16_t size, #endif /* !WOLFHSM_CFG_NO_CRYPTO */ #endif /* WOLFHSM_WH_CRYPTO_H_ */ - diff --git a/wolfhsm/wh_message_crypto.h b/wolfhsm/wh_message_crypto.h index 6b4272c12..24b5d2638 100644 --- a/wolfhsm/wh_message_crypto.h +++ b/wolfhsm/wh_message_crypto.h @@ -642,6 +642,94 @@ int wh_MessageCrypto_TranslateCurve25519Response( uint16_t magic, const whMessageCrypto_Curve25519Response* src, whMessageCrypto_Curve25519Response* dest); +/* + * Ed25519 + */ + +/* Ed25519 Key Generation Request */ +typedef struct { + uint32_t flags; + uint32_t keyId; + uint32_t access; + uint8_t label[WH_NVM_LABEL_LEN]; +} whMessageCrypto_Ed25519KeyGenRequest; + +/* Ed25519 Key Generation Response */ +typedef struct { + uint32_t keyId; + uint32_t outSz; + /* Data follows: + * uint8_t out[outSz]; + */ +} whMessageCrypto_Ed25519KeyGenResponse; + +int wh_MessageCrypto_TranslateEd25519KeyGenRequest( + uint16_t magic, const whMessageCrypto_Ed25519KeyGenRequest* src, + whMessageCrypto_Ed25519KeyGenRequest* dest); + +int wh_MessageCrypto_TranslateEd25519KeyGenResponse( + uint16_t magic, const whMessageCrypto_Ed25519KeyGenResponse* src, + whMessageCrypto_Ed25519KeyGenResponse* dest); + +/* Ed25519 Sign Request */ +typedef struct { + uint32_t options; +#define WH_MESSAGE_CRYPTO_ED25519_SIGN_OPTIONS_EVICT (1 << 0) + uint32_t keyId; + uint32_t msgSz; + uint32_t type; /* wolfCrypt Ed25519 mode */ + uint32_t ctxSz; /* Optional context length */ + /* Data follows: + * uint8_t msg[msgSz]; + * uint8_t ctx[ctxSz]; + */ +} whMessageCrypto_Ed25519SignRequest; + +/* Ed25519 Sign Response */ +typedef struct { + uint32_t sigSz; + /* Data follows: + * uint8_t sig[sigSz]; + */ +} whMessageCrypto_Ed25519SignResponse; + +int wh_MessageCrypto_TranslateEd25519SignRequest( + uint16_t magic, const whMessageCrypto_Ed25519SignRequest* src, + whMessageCrypto_Ed25519SignRequest* dest); + +int wh_MessageCrypto_TranslateEd25519SignResponse( + uint16_t magic, const whMessageCrypto_Ed25519SignResponse* src, + whMessageCrypto_Ed25519SignResponse* dest); + +/* Ed25519 Verify Request */ +typedef struct { + uint32_t options; +#define WH_MESSAGE_CRYPTO_ED25519_VERIFY_OPTIONS_EVICT (1 << 0) + uint32_t keyId; + uint32_t sigSz; + uint32_t msgSz; + uint32_t type; /* wolfCrypt Ed25519 mode */ + uint32_t ctxSz; /* Optional context length */ + /* Data follows: + * uint8_t sig[sigSz]; + * uint8_t msg[msgSz]; + * uint8_t ctx[ctxSz]; + */ +} whMessageCrypto_Ed25519VerifyRequest; + +/* Ed25519 Verify Response */ +typedef struct { + int32_t res; +} whMessageCrypto_Ed25519VerifyResponse; + +int wh_MessageCrypto_TranslateEd25519VerifyRequest( + uint16_t magic, const whMessageCrypto_Ed25519VerifyRequest* src, + whMessageCrypto_Ed25519VerifyRequest* dest); + +int wh_MessageCrypto_TranslateEd25519VerifyResponse( + uint16_t magic, const whMessageCrypto_Ed25519VerifyResponse* src, + whMessageCrypto_Ed25519VerifyResponse* dest); + /* * SHA */ @@ -1011,6 +1099,64 @@ int wh_MessageCrypto_TranslateMlDsaVerifyDmaResponse( uint16_t magic, const whMessageCrypto_MlDsaVerifyDmaResponse* src, whMessageCrypto_MlDsaVerifyDmaResponse* dest); +/* Ed25519 DMA Sign Request */ +typedef struct { + whMessageCrypto_DmaBuffer msg; /* Message buffer */ + whMessageCrypto_DmaBuffer sig; /* Signature buffer */ + whMessageCrypto_DmaBuffer pub; /* Signature buffer */ + uint32_t options; + uint32_t keyId; + uint32_t type; /* wolfCrypt Ed25519 mode */ + uint32_t ctxSz; /* Optional context length */ + /* Data follows: + * uint8_t ctx[ctxSz]; + */ +} whMessageCrypto_Ed25519SignDmaRequest; + +/* Ed25519 DMA Sign Response */ +typedef struct { + whMessageCrypto_DmaAddrStatus dmaAddrStatus; + uint32_t sigSz; + uint32_t pubSz; +} whMessageCrypto_Ed25519SignDmaResponse; + +/* Ed25519 DMA Verify Request */ +typedef struct { + whMessageCrypto_DmaBuffer sig; /* Signature buffer */ + whMessageCrypto_DmaBuffer msg; /* Message buffer */ + whMessageCrypto_DmaBuffer pub; /* Public key buffer if exported */ + uint32_t options; + uint32_t keyId; + uint32_t type; /* wolfCrypt Ed25519 mode */ + uint32_t ctxSz; /* Optional context length */ + /* Data follows: + * uint8_t ctx[ctxSz]; + */ +} whMessageCrypto_Ed25519VerifyDmaRequest; + +/* Ed25519 DMA Verify Response */ +typedef struct { + whMessageCrypto_DmaAddrStatus dmaAddrStatus; + int32_t verifyResult; + uint32_t pubSz; +} whMessageCrypto_Ed25519VerifyDmaResponse; + +int wh_MessageCrypto_TranslateEd25519SignDmaRequest( + uint16_t magic, const whMessageCrypto_Ed25519SignDmaRequest* src, + whMessageCrypto_Ed25519SignDmaRequest* dest); + +int wh_MessageCrypto_TranslateEd25519SignDmaResponse( + uint16_t magic, const whMessageCrypto_Ed25519SignDmaResponse* src, + whMessageCrypto_Ed25519SignDmaResponse* dest); + +int wh_MessageCrypto_TranslateEd25519VerifyDmaRequest( + uint16_t magic, const whMessageCrypto_Ed25519VerifyDmaRequest* src, + whMessageCrypto_Ed25519VerifyDmaRequest* dest); + +int wh_MessageCrypto_TranslateEd25519VerifyDmaResponse( + uint16_t magic, const whMessageCrypto_Ed25519VerifyDmaResponse* src, + whMessageCrypto_Ed25519VerifyDmaResponse* dest); + /* RNG DMA Request */ typedef struct { whMessageCrypto_DmaBuffer output; /* Output buffer for random bytes */ diff --git a/wolfhsm/wh_server_crypto.h b/wolfhsm/wh_server_crypto.h index 439dd112a..655f67690 100644 --- a/wolfhsm/wh_server_crypto.h +++ b/wolfhsm/wh_server_crypto.h @@ -36,6 +36,7 @@ #include "wolfssl/wolfcrypt/rsa.h" #include "wolfssl/wolfcrypt/curve25519.h" #include "wolfssl/wolfcrypt/ecc.h" +#include "wolfssl/wolfcrypt/ed25519.h" #include "wolfssl/wolfcrypt/aes.h" #include "wolfssl/wolfcrypt/sha256.h" #include "wolfssl/wolfcrypt/cmac.h" @@ -72,6 +73,15 @@ int wh_Server_EccKeyCacheExport(whServerContext* ctx, whKeyId keyId, ecc_key* key); #endif +#ifdef HAVE_ED25519 +int wh_Server_CacheImportEd25519Key(whServerContext* ctx, ed25519_key* key, + whKeyId keyId, whNvmFlags flags, + uint16_t label_len, uint8_t* label); + +int wh_Server_CacheExportEd25519Key(whServerContext* ctx, whKeyId keyId, + ed25519_key* key); +#endif /* HAVE_ED25519 */ + #ifdef HAVE_CURVE25519 /* Store a curve25519_key into a server key cache with optional metadata */