[v2,5/6] examples/fips_validation: support EDDSA

Message ID 20240905133933.741-5-gmuthukrishn@marvell.com (mailing list archive)
State Superseded
Delegated to: akhil goyal
Headers
Series [v2,1/6] cryptodev: add EDDSA asymmetric crypto algorithm |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Gowrishankar Muthukrishnan Sept. 5, 2024, 1:39 p.m. UTC
Add EDDSA support in fips_validation app.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
---
 examples/fips_validation/fips_validation.c    |   2 +
 examples/fips_validation/fips_validation.h    |  23 ++
 .../fips_validation/fips_validation_eddsa.c   | 307 +++++++++++++++++
 examples/fips_validation/main.c               | 323 ++++++++++++++++--
 examples/fips_validation/meson.build          |   1 +
 5 files changed, 623 insertions(+), 33 deletions(-)
 create mode 100644 examples/fips_validation/fips_validation_eddsa.c
  

Patch

diff --git a/examples/fips_validation/fips_validation.c b/examples/fips_validation/fips_validation.c
index c15178e55b..43d1e55532 100644
--- a/examples/fips_validation/fips_validation.c
+++ b/examples/fips_validation/fips_validation.c
@@ -475,6 +475,8 @@  fips_test_parse_one_json_vector_set(void)
 		info.algo = FIPS_TEST_ALGO_RSA;
 	else if (strstr(algo_str, "ECDSA"))
 		info.algo = FIPS_TEST_ALGO_ECDSA;
+	else if (strstr(algo_str, "EDDSA"))
+		info.algo = FIPS_TEST_ALGO_EDDSA;
 	else
 		return -EINVAL;
 
diff --git a/examples/fips_validation/fips_validation.h b/examples/fips_validation/fips_validation.h
index abc1d64742..795cf834e8 100644
--- a/examples/fips_validation/fips_validation.h
+++ b/examples/fips_validation/fips_validation.h
@@ -46,6 +46,7 @@  enum fips_test_algorithms {
 		FIPS_TEST_ALGO_SHA,
 		FIPS_TEST_ALGO_RSA,
 		FIPS_TEST_ALGO_ECDSA,
+		FIPS_TEST_ALGO_EDDSA,
 		FIPS_TEST_ALGO_MAX
 };
 
@@ -106,6 +107,12 @@  struct fips_test_vector {
 		struct fips_val s;
 		struct fips_val k;
 	} ecdsa;
+	struct {
+		struct fips_val pkey;
+		struct fips_val q;
+		struct fips_val ctx;
+		struct fips_val sign;
+	} eddsa;
 
 	struct fips_val pt;
 	struct fips_val ct;
@@ -177,6 +184,11 @@  enum fips_ecdsa_test_types {
 	ECDSA_AFT = 0,
 };
 
+enum fips_eddsa_test_types {
+	EDDSA_AFT = 0,
+	EDDSA_BFT
+};
+
 struct aesavs_interim_data {
 	enum fips_aesavs_test_types test_type;
 	uint32_t cipher_algo;
@@ -241,6 +253,13 @@  struct ecdsa_interim_data {
 	uint8_t pubkey_gen;
 };
 
+struct eddsa_interim_data {
+	enum rte_crypto_curve_id curve_id;
+	uint8_t curve_len;
+	uint8_t pubkey_gen;
+	bool prehash;
+};
+
 #ifdef USE_JANSSON
 /*
  * Maximum length of buffer to hold any json string.
@@ -288,6 +307,7 @@  struct fips_test_interim_info {
 		struct xts_interim_data xts_data;
 		struct rsa_interim_data rsa_data;
 		struct ecdsa_interim_data ecdsa_data;
+		struct eddsa_interim_data eddsa_data;
 	} interim_info;
 
 	enum fips_test_op op;
@@ -374,6 +394,9 @@  parse_test_rsa_json_init(void);
 int
 parse_test_ecdsa_json_init(void);
 
+int
+parse_test_eddsa_json_init(void);
+
 int
 fips_test_randomize_message(struct fips_val *msg, struct fips_val *rand);
 #endif /* USE_JANSSON */
diff --git a/examples/fips_validation/fips_validation_eddsa.c b/examples/fips_validation/fips_validation_eddsa.c
new file mode 100644
index 0000000000..8ccf7501bd
--- /dev/null
+++ b/examples/fips_validation/fips_validation_eddsa.c
@@ -0,0 +1,307 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2023 Marvell.
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifdef USE_OPENSSL
+#include <openssl/bn.h>
+#include <openssl/rand.h>
+#endif /* USE_OPENSSL */
+
+#include <rte_cryptodev.h>
+#include <rte_malloc.h>
+
+#include "fips_validation.h"
+
+#define TESTTYPE_JSON_STR "testType"
+#define CURVE_JSON_STR    "curve"
+#define PH_JSON_STR       "preHash"
+
+#define MSG_JSON_STR "message"
+#define CTX_JSON_STR "context"
+#define Q_JSON_STR	 "q"
+#define SIG_JSON_STR "signature"
+
+#ifdef USE_JANSSON
+struct {
+	uint8_t type;
+	const char *desc;
+} eddsa_test_types[] = {
+	{EDDSA_AFT, "AFT"},
+	{EDDSA_BFT, "BFT"}
+};
+
+struct {
+	enum rte_crypto_curve_id curve_id;
+	const char *desc;
+} eddsa_curve_ids[] = {
+	{RTE_CRYPTO_EC_GROUP_ED25519, "ED-25519"},
+	{RTE_CRYPTO_EC_GROUP_ED448, "ED-448"},
+};
+
+struct {
+	uint8_t curve_len;
+	const char *desc;
+} eddsa_curve_len[] = {
+	{32, "ED-25519"},
+	{64, "ED-448"},
+};
+
+#ifdef USE_OPENSSL
+#define MAX_TRIES 10
+static int
+prepare_vec_eddsa(void)
+{
+	BIGNUM *pkey = NULL, *order = NULL;
+	int ret = -1, j;
+	unsigned long pid;
+
+	/* For EDDSA prime fields, order of base points (RFC 8032 Section 5.1 and 5.2).
+	 */
+	static const char * const orderstr[] = {
+			"7237005577332262213973186563042994240857116359379907606001950938285454250989",
+			"181709681073901722637330951972001133588410340171829515070372549795146003961539585716195755291692375963310293709091662304773755859649779",
+	};
+
+	pid = getpid();
+	RAND_seed(&pid, sizeof(pid));
+
+	if (!RAND_status())
+		return -1;
+
+	order = BN_new();
+	if (!order)
+		goto err;
+
+	j = info.interim_info.eddsa_data.curve_id - RTE_CRYPTO_EC_GROUP_ED25519;
+	if (!BN_hex2bn(&order, orderstr[j]))
+		goto err;
+
+	pkey = BN_new();
+	if (!pkey)
+		goto err;
+
+	for (j = 0; j < MAX_TRIES; j++) {
+		/* pkey should be in [1, order - 1] */
+		if (!BN_rand_range(pkey, order))
+			goto err;
+
+		if (!BN_is_zero(pkey))
+			break;
+	}
+
+	if (j == MAX_TRIES)
+		goto err;
+
+	parse_uint8_hex_str("", BN_bn2hex(pkey), &vec.eddsa.pkey);
+
+	ret = 0;
+err:
+	BN_free(order);
+	BN_free(pkey);
+	return ret;
+}
+#else
+static int
+prepare_vec_eddsa(void)
+{
+	/*
+	 * Generate EDDSA values.
+	 */
+	return -ENOTSUP;
+}
+#endif /* USE_OPENSSL */
+
+static int
+parse_test_eddsa_json_interim_writeback(struct fips_val *val)
+{
+	RTE_SET_USED(val);
+
+	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		/* For siggen tests, EDDSA values can be created soon after
+		 * the test group data are parsed.
+		 */
+		if (vec.eddsa.pkey.val) {
+			rte_free(vec.eddsa.pkey.val);
+			vec.eddsa.pkey.val = NULL;
+		}
+
+		if (prepare_vec_eddsa() < 0)
+			return -1;
+
+		info.interim_info.eddsa_data.pubkey_gen = 1;
+	}
+
+	return 0;
+}
+
+static int
+post_test_eddsa_json_interim_writeback(struct fips_val *val)
+{
+	RTE_SET_USED(val);
+
+	if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+		json_t *obj;
+
+		writeback_hex_str("", info.one_line_text, &vec.eddsa.q);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_group, "q", obj);
+	}
+
+	return 0;
+}
+
+static int
+parse_test_eddsa_json_writeback(struct fips_val *val)
+{
+	json_t *tcId;
+
+	RTE_SET_USED(val);
+
+	tcId = json_object_get(json_info.json_test_case, "tcId");
+
+	json_info.json_write_case = json_object();
+	json_object_set(json_info.json_write_case, "tcId", tcId);
+
+	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		json_t *obj;
+
+		writeback_hex_str("", info.one_line_text, &vec.eddsa.sign);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "signature", obj);
+	} else if (info.op == FIPS_TEST_ASYM_SIGVER) {
+		if (vec.status == RTE_CRYPTO_OP_STATUS_SUCCESS)
+			json_object_set_new(json_info.json_write_case, "testPassed", json_true());
+		else
+			json_object_set_new(json_info.json_write_case, "testPassed", json_false());
+	} else if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+		json_t *obj;
+
+		writeback_hex_str("", info.one_line_text, &vec.eddsa.pkey);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "d", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.eddsa.q);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "q", obj);
+	}
+
+	return 0;
+}
+
+static int
+parse_interim_str(const char *key, char *src, struct fips_val *val)
+{
+	uint32_t i;
+
+	RTE_SET_USED(val);
+
+	if (strcmp(key, TESTTYPE_JSON_STR) == 0) {
+		for (i = 0; i < RTE_DIM(eddsa_test_types); i++)
+			if (strstr(src, eddsa_test_types[i].desc)) {
+				info.parse_writeback = parse_test_eddsa_json_writeback;
+				break;
+			}
+
+		if (!info.parse_writeback || i >= RTE_DIM(eddsa_test_types))
+			return -EINVAL;
+
+	} else if (strcmp(key, CURVE_JSON_STR) == 0) {
+		for (i = 0; i < RTE_DIM(eddsa_curve_ids); i++)
+			if (strstr(src, eddsa_curve_ids[i].desc)) {
+				info.interim_info.eddsa_data.curve_id = eddsa_curve_ids[i].curve_id;
+				info.interim_info.eddsa_data.curve_len =
+					eddsa_curve_len[i].curve_len;
+				break;
+			}
+
+		if (i >= RTE_DIM(eddsa_curve_ids))
+			return -EINVAL;
+	} else if (strcmp(key, PH_JSON_STR) == 0) {
+		info.interim_info.eddsa_data.prehash = false;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+parse_keygen_tc_str(const char *key, char *src, struct fips_val *val)
+{
+	RTE_SET_USED(key);
+	RTE_SET_USED(src);
+	RTE_SET_USED(val);
+
+	if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+		if (vec.eddsa.pkey.val) {
+			rte_free(vec.eddsa.pkey.val);
+			vec.eddsa.pkey.val = NULL;
+		}
+
+		if (prepare_vec_eddsa() < 0)
+			return -1;
+
+		info.interim_info.eddsa_data.pubkey_gen = 1;
+	}
+
+	return 0;
+}
+
+struct fips_test_callback eddsa_interim_json_vectors[] = {
+		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
+		{CURVE_JSON_STR, parse_interim_str, NULL},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback eddsa_siggen_json_vectors[] = {
+		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
+		{CTX_JSON_STR, parse_uint8_hex_str, &vec.eddsa.ctx},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback eddsa_sigver_json_vectors[] = {
+		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
+		{Q_JSON_STR, parse_uint8_hex_str, &vec.eddsa.q},
+		{SIG_JSON_STR, parse_uint8_hex_str, &vec.eddsa.sign},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback eddsa_keygen_json_vectors[] = {
+		{"tcId", parse_keygen_tc_str, &vec.pt},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+int
+parse_test_eddsa_json_init(void)
+{
+	json_t *mode_obj = json_object_get(json_info.json_vector_set, "mode");
+	const char *mode_str = json_string_value(mode_obj);
+
+	info.callbacks = NULL;
+	info.parse_writeback = NULL;
+
+	info.interim_callbacks = eddsa_interim_json_vectors;
+	info.post_interim_writeback = post_test_eddsa_json_interim_writeback;
+	info.parse_interim_writeback = parse_test_eddsa_json_interim_writeback;
+	if (strcmp(mode_str, "sigGen") == 0) {
+		info.op = FIPS_TEST_ASYM_SIGGEN;
+		info.callbacks = eddsa_siggen_json_vectors;
+	} else if (strcmp(mode_str, "sigVer") == 0) {
+		info.op = FIPS_TEST_ASYM_SIGVER;
+		info.callbacks = eddsa_sigver_json_vectors;
+	} else if (strcmp(mode_str, "keyGen") == 0) {
+		info.op = FIPS_TEST_ASYM_KEYGEN;
+		info.callbacks = eddsa_keygen_json_vectors;
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+#endif /* USE_JANSSON */
diff --git a/examples/fips_validation/main.c b/examples/fips_validation/main.c
index 7ae2c6c007..522373ac1d 100644
--- a/examples/fips_validation/main.c
+++ b/examples/fips_validation/main.c
@@ -1041,6 +1041,64 @@  prepare_ecdsa_op(void)
 	return 0;
 }
 
+static int
+prepare_eddsa_op(void)
+{
+	struct rte_crypto_asym_op *asym;
+	struct fips_val msg;
+
+	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_ASYMMETRIC);
+
+	asym = env.op->asym;
+	if (env.digest) {
+		msg.val = env.digest;
+		msg.len = env.digest_len;
+	} else {
+		msg.val = vec.pt.val;
+		msg.len = vec.pt.len;
+	}
+
+	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		asym->eddsa.op_type = RTE_CRYPTO_ASYM_OP_SIGN;
+		asym->eddsa.message.data = msg.val;
+		asym->eddsa.message.length = msg.len;
+		asym->eddsa.context.data = vec.eddsa.ctx.val;
+		asym->eddsa.context.length = vec.eddsa.ctx.len;
+
+		rte_free(vec.eddsa.sign.val);
+
+		vec.eddsa.sign.len = info.interim_info.eddsa_data.curve_len;
+		vec.eddsa.sign.val = rte_zmalloc(NULL, vec.eddsa.sign.len, 0);
+
+		asym->eddsa.sign.data = vec.eddsa.sign.val;
+		asym->eddsa.sign.length = 0;
+	} else if (info.op == FIPS_TEST_ASYM_SIGVER) {
+		asym->eddsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY;
+		asym->eddsa.message.data = msg.val;
+		asym->eddsa.message.length = msg.len;
+		asym->eddsa.sign.data = vec.eddsa.sign.val;
+		asym->eddsa.sign.length = vec.eddsa.sign.len;
+	} else {
+		RTE_LOG(ERR, USER1, "Invalid op %d\n", info.op);
+		return -EINVAL;
+	}
+
+	if (info.interim_info.eddsa_data.curve_id == RTE_CRYPTO_EC_GROUP_ED25519) {
+		asym->eddsa.instance = RTE_CRYPTO_EDCURVE_25519;
+		if (info.interim_info.eddsa_data.prehash)
+			asym->eddsa.instance = RTE_CRYPTO_EDCURVE_25519PH;
+		if (vec.eddsa.ctx.len > 0)
+			asym->eddsa.instance = RTE_CRYPTO_EDCURVE_25519CTX;
+	} else {
+		asym->eddsa.instance = RTE_CRYPTO_EDCURVE_448;
+		if (info.interim_info.eddsa_data.prehash)
+			asym->eddsa.instance = RTE_CRYPTO_EDCURVE_448PH;
+	}
+	rte_crypto_op_attach_asym_session(env.op, env.asym.sess);
+
+	return 0;
+}
+
 static int
 prepare_ecfpm_op(void)
 {
@@ -1072,6 +1130,31 @@  prepare_ecfpm_op(void)
 	return 0;
 }
 
+static int
+prepare_edfpm_op(void)
+{
+	struct rte_crypto_asym_op *asym;
+
+	__rte_crypto_op_reset(env.op, RTE_CRYPTO_OP_TYPE_ASYMMETRIC);
+
+	asym = env.op->asym;
+	asym->ecpm.scalar.data = vec.eddsa.pkey.val;
+	asym->ecpm.scalar.length = vec.eddsa.pkey.len;
+
+	rte_free(vec.eddsa.q.val);
+
+	vec.eddsa.q.len = info.interim_info.eddsa_data.curve_len;
+	vec.eddsa.q.val = rte_zmalloc(NULL, vec.eddsa.q.len, 0);
+
+	asym->ecpm.r.x.data = vec.eddsa.q.val;
+	asym->ecpm.r.x.length = 0;
+	asym->flags |= RTE_CRYPTO_ASYM_FLAG_PUB_KEY_COMPRESSED;
+
+	rte_crypto_op_attach_asym_session(env.op, env.asym.sess);
+
+	return 0;
+}
+
 static int
 prepare_aes_xform(struct rte_crypto_sym_xform *xform)
 {
@@ -1589,6 +1672,56 @@  prepare_ecdsa_xform(struct rte_crypto_asym_xform *xform)
 	return 0;
 }
 
+static int
+prepare_eddsa_xform(struct rte_crypto_asym_xform *xform)
+{
+	const struct rte_cryptodev_asymmetric_xform_capability *cap;
+	struct rte_cryptodev_asym_capability_idx cap_idx;
+
+	xform->xform_type = RTE_CRYPTO_ASYM_XFORM_EDDSA;
+	xform->next = NULL;
+
+	cap_idx.type = xform->xform_type;
+	cap = rte_cryptodev_asym_capability_get(env.dev_id, &cap_idx);
+	if (!cap) {
+		RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+				env.dev_id);
+		return -EINVAL;
+	}
+
+	switch (info.op) {
+	case FIPS_TEST_ASYM_SIGGEN:
+		if (!rte_cryptodev_asym_xform_capability_check_optype(cap,
+			RTE_CRYPTO_ASYM_OP_SIGN)) {
+			RTE_LOG(ERR, USER1, "PMD %s xform_op %u\n",
+				info.device_name, RTE_CRYPTO_ASYM_OP_SIGN);
+			return -EPERM;
+		}
+
+		xform->ec.pkey.data = vec.eddsa.pkey.val;
+		xform->ec.pkey.length = vec.eddsa.pkey.len;
+		xform->ec.q.x.data = vec.eddsa.q.val;
+		xform->ec.q.x.length = vec.eddsa.q.len;
+		break;
+	case FIPS_TEST_ASYM_SIGVER:
+		if (!rte_cryptodev_asym_xform_capability_check_optype(cap,
+			RTE_CRYPTO_ASYM_OP_VERIFY)) {
+			RTE_LOG(ERR, USER1, "PMD %s xform_op %u\n",
+				info.device_name, RTE_CRYPTO_ASYM_OP_VERIFY);
+			return -EPERM;
+		}
+
+		xform->ec.q.x.data = vec.eddsa.q.val;
+		xform->ec.q.x.length = vec.eddsa.q.len;
+		break;
+	default:
+		break;
+	}
+
+	xform->ec.curve_id = info.interim_info.eddsa_data.curve_id;
+	return 0;
+}
+
 static int
 prepare_ecfpm_xform(struct rte_crypto_asym_xform *xform)
 {
@@ -1610,6 +1743,27 @@  prepare_ecfpm_xform(struct rte_crypto_asym_xform *xform)
 	return 0;
 }
 
+static int
+prepare_edfpm_xform(struct rte_crypto_asym_xform *xform)
+{
+	const struct rte_cryptodev_asymmetric_xform_capability *cap;
+	struct rte_cryptodev_asym_capability_idx cap_idx;
+
+	xform->xform_type = RTE_CRYPTO_ASYM_XFORM_ECFPM;
+	xform->next = NULL;
+
+	cap_idx.type = xform->xform_type;
+	cap = rte_cryptodev_asym_capability_get(env.dev_id, &cap_idx);
+	if (!cap) {
+		RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+				env.dev_id);
+		return -EINVAL;
+	}
+
+	xform->ec.curve_id = info.interim_info.eddsa_data.curve_id;
+	return 0;
+}
+
 static int
 get_writeback_data(struct fips_val *val)
 {
@@ -1709,7 +1863,9 @@  fips_run_asym_test(void)
 	struct rte_crypto_op *deqd_op;
 	int ret;
 
-	if (info.op == FIPS_TEST_ASYM_KEYGEN && info.algo != FIPS_TEST_ALGO_ECDSA) {
+	if (info.op == FIPS_TEST_ASYM_KEYGEN &&
+		(info.algo != FIPS_TEST_ALGO_ECDSA &&
+		 info.algo != FIPS_TEST_ALGO_EDDSA)) {
 		RTE_SET_USED(asym);
 		ret = 0;
 		goto exit;
@@ -1758,53 +1914,140 @@  fips_run_test(void)
 {
 	int ret;
 
-	env.op = env.sym.op;
-	if (env.is_asym_test) {
-		if (info.op == FIPS_TEST_ASYM_KEYGEN &&
-			info.algo == FIPS_TEST_ALGO_ECDSA) {
-			env.op = env.asym.op;
+	env.op = NULL;
+	if (!env.is_asym_test) {
+		env.op = env.sym.op;
+		return fips_run_sym_test();
+	}
+
+	if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+		if (info.algo == FIPS_TEST_ALGO_ECDSA) {
 			test_ops.prepare_asym_xform = prepare_ecfpm_xform;
 			test_ops.prepare_asym_op = prepare_ecfpm_op;
-			ret = fips_run_asym_test();
-			if (ret < 0)
-				return ret;
-
 			info.interim_info.ecdsa_data.pubkey_gen = 0;
-			return ret;
+
+		} else if (info.algo == FIPS_TEST_ALGO_EDDSA) {
+			test_ops.prepare_asym_xform = prepare_edfpm_xform;
+			test_ops.prepare_asym_op = prepare_edfpm_op;
+			info.interim_info.eddsa_data.pubkey_gen = 0;
 		}
 
-		vec.cipher_auth.digest.len = parse_test_sha_hash_size(
-						info.interim_info.rsa_data.auth);
+		env.op = env.asym.op;
+		return fips_run_asym_test();
+	}
+
+	if (info.algo == FIPS_TEST_ALGO_ECDSA) {
+		vec.cipher_auth.digest.len =
+			parse_test_sha_hash_size(info.interim_info.ecdsa_data.auth);
 		test_ops.prepare_sym_xform = prepare_sha_xform;
 		test_ops.prepare_sym_op = prepare_auth_op;
+
+		env.op = env.sym.op;
 		ret = fips_run_sym_test();
 		if (ret < 0)
 			return ret;
-	} else {
-		return fips_run_sym_test();
 	}
 
 	env.op = env.asym.op;
-	if (info.op == FIPS_TEST_ASYM_SIGGEN &&
-		info.algo == FIPS_TEST_ALGO_ECDSA &&
-		info.interim_info.ecdsa_data.pubkey_gen == 1) {
-		fips_prepare_asym_xform_t ecdsa_xform;
-		fips_prepare_op_t ecdsa_op;
-
-		ecdsa_xform = test_ops.prepare_asym_xform;
-		ecdsa_op = test_ops.prepare_asym_op;
-		info.op = FIPS_TEST_ASYM_KEYGEN;
-		test_ops.prepare_asym_xform = prepare_ecfpm_xform;
-		test_ops.prepare_asym_op = prepare_ecfpm_op;
-		ret = fips_run_asym_test();
-		if (ret < 0)
-			return ret;
+	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		fips_prepare_asym_xform_t old_xform;
+		fips_prepare_op_t old_op;
+
+		old_xform = test_ops.prepare_asym_xform;
+		old_op = test_ops.prepare_asym_op;
+
+		if (info.algo == FIPS_TEST_ALGO_ECDSA &&
+		    info.interim_info.ecdsa_data.pubkey_gen == 1) {
+			info.op = FIPS_TEST_ASYM_KEYGEN;
+			test_ops.prepare_asym_xform = prepare_ecfpm_xform;
+			test_ops.prepare_asym_op = prepare_ecfpm_op;
 
-		info.post_interim_writeback(NULL);
-		info.interim_info.ecdsa_data.pubkey_gen = 0;
+			ret = fips_run_asym_test();
+			if (ret < 0)
+				return ret;
+
+			info.post_interim_writeback(NULL);
+			info.interim_info.ecdsa_data.pubkey_gen = 0;
 
-		test_ops.prepare_asym_xform = ecdsa_xform;
-		test_ops.prepare_asym_op = ecdsa_op;
+		} else if (info.algo == FIPS_TEST_ALGO_EDDSA &&
+				   info.interim_info.eddsa_data.pubkey_gen == 1) {
+			info.op = FIPS_TEST_ASYM_KEYGEN;
+			test_ops.prepare_asym_xform = prepare_edfpm_xform;
+			test_ops.prepare_asym_op = prepare_edfpm_op;
+
+			const struct rte_cryptodev_asymmetric_xform_capability *cap;
+			struct rte_cryptodev_asym_capability_idx cap_idx;
+
+			cap_idx.type = RTE_CRYPTO_ASYM_XFORM_EDDSA;
+			cap = rte_cryptodev_asym_capability_get(env.dev_id, &cap_idx);
+			if (!cap) {
+				RTE_LOG(ERR, USER1, "Failed to get capability for cdev %u\n",
+						env.dev_id);
+				return -EINVAL;
+			}
+
+			if (cap->op_types & (1 << RTE_CRYPTO_ASYM_KE_PUB_KEY_GENERATE)) {
+				ret = fips_run_asym_test();
+				if (ret < 0)
+					return ret;
+			} else {
+				/* Below is only a workaround by using known keys. */
+				struct rte_crypto_asym_xform xform = {0};
+
+				prepare_edfpm_xform(&xform);
+				prepare_edfpm_op();
+				uint8_t pkey25519[] = {
+					0x83, 0x3f, 0xe6, 0x24, 0x09, 0x23, 0x7b, 0x9d,
+					0x62, 0xec, 0x77, 0x58, 0x75, 0x20, 0x91, 0x1e,
+					0x9a, 0x75, 0x9c, 0xec, 0x1d, 0x19, 0x75, 0x5b,
+					0x7d, 0xa9, 0x01, 0xb9, 0x6d, 0xca, 0x3d, 0x42
+				};
+				uint8_t q25519[] = {
+					0xec, 0x17, 0x2b, 0x93, 0xad, 0x5e, 0x56, 0x3b,
+					0xf4, 0x93, 0x2c, 0x70, 0xe1, 0x24, 0x50, 0x34,
+					0xc3, 0x54, 0x67, 0xef, 0x2e, 0xfd, 0x4d, 0x64,
+					0xeb, 0xf8, 0x19, 0x68, 0x34, 0x67, 0xe2, 0xbf
+				};
+				uint8_t pkey448[] = {
+					0xd6, 0x5d, 0xf3, 0x41, 0xad, 0x13, 0xe0, 0x08,
+					0x56, 0x76, 0x88, 0xba, 0xed, 0xda, 0x8e, 0x9d,
+					0xcd, 0xc1, 0x7d, 0xc0, 0x24, 0x97, 0x4e, 0xa5,
+					0xb4, 0x22, 0x7b, 0x65, 0x30, 0xe3, 0x39, 0xbf,
+					0xf2, 0x1f, 0x99, 0xe6, 0x8c, 0xa6, 0x96, 0x8f,
+					0x3c, 0xca, 0x6d, 0xfe, 0x0f, 0xb9, 0xf4, 0xfa,
+					0xb4, 0xfa, 0x13, 0x5d, 0x55, 0x42, 0xea, 0x3f,
+					0x01
+				};
+				uint8_t q448[] = {
+					0xdf, 0x97, 0x05, 0xf5, 0x8e, 0xdb, 0xab, 0x80,
+					0x2c, 0x7f, 0x83, 0x63, 0xcf, 0xe5, 0x56, 0x0a,
+					0xb1, 0xc6, 0x13, 0x2c, 0x20, 0xa9, 0xf1, 0xdd,
+					0x16, 0x34, 0x83, 0xa2, 0x6f, 0x8a, 0xc5, 0x3a,
+					0x39, 0xd6, 0x80, 0x8b, 0xf4, 0xa1, 0xdf, 0xbd,
+					0x26, 0x1b, 0x09, 0x9b, 0xb0, 0x3b, 0x3f, 0xb5,
+					0x09, 0x06, 0xcb, 0x28, 0xbd, 0x8a, 0x08, 0x1f,
+					0x00
+				};
+				if (info.interim_info.eddsa_data.curve_id ==
+					RTE_CRYPTO_EC_GROUP_ED25519) {
+					memcpy(vec.eddsa.pkey.val, pkey25519, RTE_DIM(pkey25519));
+					vec.eddsa.pkey.len = 32;
+					memcpy(vec.eddsa.q.val, q25519, RTE_DIM(q25519));
+					vec.eddsa.q.len = 32;
+				} else {
+					memcpy(vec.eddsa.pkey.val, pkey448, RTE_DIM(pkey448));
+					vec.eddsa.pkey.len = 32;
+					memcpy(vec.eddsa.q.val, q448, RTE_DIM(q448));
+					vec.eddsa.q.len = 32;
+				}
+			}
+			info.post_interim_writeback(NULL);
+			info.interim_info.eddsa_data.pubkey_gen = 0;
+
+		}
+
+		test_ops.prepare_asym_xform = old_xform;
+		test_ops.prepare_asym_op = old_op;
 		info.op = FIPS_TEST_ASYM_SIGGEN;
 		ret = fips_run_asym_test();
 	} else {
@@ -2536,6 +2779,17 @@  init_test_ops(void)
 			test_ops.test = fips_generic_test;
 		}
 		break;
+	case FIPS_TEST_ALGO_EDDSA:
+		if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+			test_ops.prepare_asym_op = prepare_edfpm_op;
+			test_ops.prepare_asym_xform = prepare_edfpm_xform;
+			test_ops.test = fips_generic_test;
+		} else {
+			test_ops.prepare_asym_op = prepare_eddsa_op;
+			test_ops.prepare_asym_xform = prepare_eddsa_xform;
+			test_ops.test = fips_generic_test;
+		}
+		break;
 	default:
 		if (strstr(info.file_name, "TECB") ||
 				strstr(info.file_name, "TCBC")) {
@@ -2719,6 +2973,9 @@  fips_test_one_test_group(void)
 	case FIPS_TEST_ALGO_ECDSA:
 		ret = parse_test_ecdsa_json_init();
 		break;
+	case FIPS_TEST_ALGO_EDDSA:
+		ret = parse_test_eddsa_json_init();
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/examples/fips_validation/meson.build b/examples/fips_validation/meson.build
index 34d3c7c8ca..7d4e440c6c 100644
--- a/examples/fips_validation/meson.build
+++ b/examples/fips_validation/meson.build
@@ -20,6 +20,7 @@  sources = files(
         'fips_validation_xts.c',
         'fips_validation_rsa.c',
         'fips_validation_ecdsa.c',
+        'fips_validation_eddsa.c',
         'fips_dev_self_test.c',
         'main.c',
 )