diff mbox series

[v2,5/7] examples/fips_validation: add asymmetric validation

Message ID da6c7aec7de7da40883d3dc2ce4792ef7969c958.1664263264.git.gmuthukrishn@marvell.com (mailing list archive)
State Changes Requested, archived
Delegated to: akhil goyal
Headers show
Series FIPS asymmetric validation | expand

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Gowrishankar Muthukrishnan Sept. 27, 2022, 7:26 a.m. UTC
Add support for asymmetric crypto validation starting with RSA.
For the generation of crypto values which is multiprecision in
math, openssl library is used only for this purpose.

Signed-off-by: Gowrishankar Muthukrishnan <gmuthukrishn@marvell.com>
Acked-by: Brian Dooley <brian.dooley@intel.com>

--
v2:
 - improved handling priv key type.
---
 config/meson.build                            |   6 +
 doc/guides/sample_app_ug/fips_validation.rst  |   1 +
 examples/fips_validation/fips_validation.c    |   2 +
 examples/fips_validation/fips_validation.h    |  47 +-
 .../fips_validation/fips_validation_gcm.c     |   8 +-
 .../fips_validation/fips_validation_rsa.c     | 520 ++++++++++++++++++
 examples/fips_validation/main.c               | 464 +++++++++++++---
 examples/fips_validation/meson.build          |   6 +
 8 files changed, 962 insertions(+), 92 deletions(-)
 create mode 100644 examples/fips_validation/fips_validation_rsa.c
diff mbox series

Patch

diff --git a/config/meson.build b/config/meson.build
index 7f7b6c92fd..ed21a8e470 100644
--- a/config/meson.build
+++ b/config/meson.build
@@ -226,6 +226,12 @@  if jansson_dep.found()
     dpdk_conf.set('RTE_HAS_JANSSON', 1)
 endif
 
+# check for openssl
+openssl_dep = dependency('openssl', required: false, method: 'pkg-config')
+if openssl_dep.found()
+    dpdk_conf.set('RTE_HAS_OPENSSL', 1)
+endif
+
 # check for pcap
 pcap_dep = dependency('libpcap', required: false, method: 'pkg-config')
 pcap_lib = is_windows ? 'wpcap' : 'pcap'
diff --git a/doc/guides/sample_app_ug/fips_validation.rst b/doc/guides/sample_app_ug/fips_validation.rst
index 33a8c97575..5e9ad2d006 100644
--- a/doc/guides/sample_app_ug/fips_validation.rst
+++ b/doc/guides/sample_app_ug/fips_validation.rst
@@ -66,6 +66,7 @@  ACVP
     * SHA (1, 256, 384, 512) - AFT, MCT
     * TDES-CBC - AFT, MCT
     * TDES-ECB - AFT, MCT
+    * RSA
 
 
 Application Information
diff --git a/examples/fips_validation/fips_validation.c b/examples/fips_validation/fips_validation.c
index be0634c3ac..5d485a2bd5 100644
--- a/examples/fips_validation/fips_validation.c
+++ b/examples/fips_validation/fips_validation.c
@@ -471,6 +471,8 @@  fips_test_parse_one_json_vector_set(void)
 	else if (strstr(algo_str, "TDES-CBC") ||
 		strstr(algo_str, "TDES-ECB"))
 		info.algo = FIPS_TEST_ALGO_TDES;
+	else if (strstr(algo_str, "RSA"))
+		info.algo = FIPS_TEST_ALGO_RSA;
 	else
 		return -EINVAL;
 
diff --git a/examples/fips_validation/fips_validation.h b/examples/fips_validation/fips_validation.h
index 43e5ffe4b0..ed59322635 100644
--- a/examples/fips_validation/fips_validation.h
+++ b/examples/fips_validation/fips_validation.h
@@ -42,6 +42,7 @@  enum fips_test_algorithms {
 		FIPS_TEST_ALGO_HMAC,
 		FIPS_TEST_ALGO_TDES,
 		FIPS_TEST_ALGO_SHA,
+		FIPS_TEST_ALGO_RSA,
 		FIPS_TEST_ALGO_MAX
 };
 
@@ -55,6 +56,9 @@  enum file_types {
 enum fips_test_op {
 	FIPS_TEST_ENC_AUTH_GEN = 1,
 	FIPS_TEST_DEC_AUTH_VERIF,
+	FIPS_TEST_ASYM_KEYGEN,
+	FIPS_TEST_ASYM_SIGGEN,
+	FIPS_TEST_ASYM_SIGVER
 };
 
 #define MAX_LINE_PER_VECTOR            16
@@ -78,11 +82,22 @@  struct fips_test_vector {
 			struct fips_val aad;
 		} aead;
 	};
+	struct {
+		struct fips_val seed;
+		struct fips_val signature;
+		struct fips_val e;
+		struct fips_val n;
+		struct fips_val d;
+		struct fips_val p;
+		struct fips_val q;
+		struct fips_val dp;
+		struct fips_val dq;
+		struct fips_val qinv;
+	} rsa;
 
 	struct fips_val pt;
 	struct fips_val ct;
 	struct fips_val iv;
-
 	enum rte_crypto_op_status status;
 };
 
@@ -138,6 +153,12 @@  enum fips_sha_test_types {
 	SHA_MCT
 };
 
+enum fips_rsa_test_types {
+	RSA_AFT = 0,
+	RSA_GDT,
+	RSA_KAT
+};
+
 struct aesavs_interim_data {
 	enum fips_aesavs_test_types test_type;
 	uint32_t cipher_algo;
@@ -164,8 +185,9 @@  struct ccm_interim_data {
 };
 
 struct sha_interim_data {
-	enum fips_sha_test_types test_type;
+	/* keep algo always on top as it is also used in asym digest */
 	enum rte_crypto_auth_algorithm algo;
+	enum fips_sha_test_types test_type;
 };
 
 struct gcm_interim_data {
@@ -182,6 +204,14 @@  struct xts_interim_data {
 	enum xts_tweak_modes tweak_mode;
 };
 
+struct rsa_interim_data {
+	enum rte_crypto_auth_algorithm auth;
+	uint16_t modulo;
+	uint16_t saltlen;
+	enum rte_crypto_rsa_padding_type padding;
+	enum rte_crypto_rsa_priv_key_type privkey;
+};
+
 #ifdef USE_JANSSON
 /*
  * Maximum length of buffer to hold any json string.
@@ -227,6 +257,7 @@  struct fips_test_interim_info {
 		struct sha_interim_data sha_data;
 		struct gcm_interim_data gcm_data;
 		struct xts_interim_data xts_data;
+		struct rsa_interim_data rsa_data;
 	} interim_info;
 
 	enum fips_test_op op;
@@ -302,6 +333,9 @@  parse_test_sha_json_test_type(void);
 
 int
 parse_test_tdes_json_init(void);
+
+int
+parse_test_rsa_json_init(void);
 #endif /* USE_JANSSON */
 
 int
@@ -363,11 +397,14 @@  update_info_vec(uint32_t count);
 
 typedef int (*fips_test_one_case_t)(void);
 typedef int (*fips_prepare_op_t)(void);
-typedef int (*fips_prepare_xform_t)(struct rte_crypto_sym_xform *);
+typedef int (*fips_prepare_sym_xform_t)(struct rte_crypto_sym_xform *);
+typedef int (*fips_prepare_asym_xform_t)(struct rte_crypto_asym_xform *);
 
 struct fips_test_ops {
-	fips_prepare_xform_t prepare_xform;
-	fips_prepare_op_t prepare_op;
+	fips_prepare_sym_xform_t prepare_sym_xform;
+	fips_prepare_asym_xform_t prepare_asym_xform;
+	fips_prepare_op_t prepare_sym_op;
+	fips_prepare_op_t prepare_asym_op;
 	fips_test_one_case_t test;
 };
 
diff --git a/examples/fips_validation/fips_validation_gcm.c b/examples/fips_validation/fips_validation_gcm.c
index 6b3d158629..e76c38ffc8 100644
--- a/examples/fips_validation/fips_validation_gcm.c
+++ b/examples/fips_validation/fips_validation_gcm.c
@@ -80,12 +80,12 @@  parser_read_gcm_pt_len(const char *key, char *src,
 
 	if (vec.pt.len == 0) {
 		info.interim_info.gcm_data.is_gmac = 1;
-		test_ops.prepare_op = prepare_auth_op;
-		test_ops.prepare_xform = prepare_gmac_xform;
+		test_ops.prepare_sym_op = prepare_auth_op;
+		test_ops.prepare_sym_xform = prepare_gmac_xform;
 	} else {
 		info.interim_info.gcm_data.is_gmac = 0;
-		test_ops.prepare_op = prepare_aead_op;
-		test_ops.prepare_xform = prepare_gcm_xform;
+		test_ops.prepare_sym_op = prepare_aead_op;
+		test_ops.prepare_sym_xform = prepare_gcm_xform;
 	}
 
 	return ret;
diff --git a/examples/fips_validation/fips_validation_rsa.c b/examples/fips_validation/fips_validation_rsa.c
new file mode 100644
index 0000000000..d3699f54d0
--- /dev/null
+++ b/examples/fips_validation/fips_validation_rsa.c
@@ -0,0 +1,520 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2022 Marvell.
+ */
+
+#include <string.h>
+#include <time.h>
+#include <stdio.h>
+#include <sys/random.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 SIGTYPE_JSON_STR "sigType"
+#define MOD_JSON_STR	"modulo"
+#define HASH_JSON_STR	"hashAlg"
+#define SALT_JSON_STR	"saltLen"
+#define E_JSON_STR	"e"
+#define N_JSON_STR	"n"
+
+#define SEED_JSON_STR	"seed"
+#define MSG_JSON_STR	"message"
+#define SIG_JSON_STR	"signature"
+
+#ifdef USE_JANSSON
+struct {
+	uint8_t type;
+	const char *desc;
+} rsa_test_types[] = {
+		{RSA_AFT, "AFT"},
+		{RSA_GDT, "GDT"},
+		{RSA_KAT, "KAT"},
+};
+
+struct {
+	enum rte_crypto_auth_algorithm auth;
+	const char *desc;
+} rsa_auth_algs[] = {
+		{RTE_CRYPTO_AUTH_SHA1, "SHA-1"},
+		{RTE_CRYPTO_AUTH_SHA224, "SHA2-224"},
+		{RTE_CRYPTO_AUTH_SHA256, "SHA2-256"},
+		{RTE_CRYPTO_AUTH_SHA384, "SHA2-384"},
+		{RTE_CRYPTO_AUTH_SHA512, "SHA2-512"},
+};
+
+struct {
+	enum rte_crypto_rsa_padding_type padding;
+	const char *desc;
+} rsa_padding_types[] = {
+		{RTE_CRYPTO_RSA_PADDING_NONE, "none"},
+		{RTE_CRYPTO_RSA_PADDING_PKCS1_5, "pkcs1v1.5"},
+		{RTE_CRYPTO_RSA_PADDING_OAEP, "oaep"},
+		{RTE_CRYPTO_RSA_PADDING_PSS, "pss"},
+};
+
+#ifdef USE_OPENSSL
+static int
+prepare_vec_rsa(void)
+{
+	BIGNUM *p = NULL, *q = NULL, *n = NULL, *d = NULL, *e = NULL;
+	BIGNUM *dp = NULL, *dq = NULL, *qinv = NULL;
+	BIGNUM *r0, *r1, *r2, *r3, *r4;
+	BIGNUM *m = NULL, *r = NULL;
+	int bits, ret = -1, i;
+	char modbuf[8], *buf;
+	BN_CTX *ctx = NULL;
+	unsigned long pid;
+
+	/* Seed PRNG */
+	if (vec.rsa.seed.val) {
+		writeback_hex_str("", info.one_line_text, &vec.rsa.seed);
+		RAND_seed((char *)info.one_line_text, strlen(info.one_line_text));
+	} else {
+		pid = getpid();
+		RAND_seed(&pid, sizeof(pid));
+	}
+
+	if (!RAND_status())
+		return -1;
+
+	/* Check if e is known already */
+	if (vec.rsa.e.val) {
+		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
+		ret = BN_hex2bn(&e, info.one_line_text);
+		if ((uint32_t)ret != strlen(info.one_line_text))
+			goto err;
+	}
+
+	/* BN context initialization */
+	ctx = BN_CTX_new();
+	if (!ctx)
+		goto err;
+
+	BN_CTX_start(ctx);
+	r0 = BN_CTX_get(ctx);
+	r1 = BN_CTX_get(ctx);
+	r2 = BN_CTX_get(ctx);
+	r3 = BN_CTX_get(ctx);
+	r4 = BN_CTX_get(ctx);
+	if (!r4)
+		goto err;
+
+	/* Calculate bit length for prime numbers */
+	m = BN_new();
+	if (!m)
+		goto err;
+
+	snprintf(modbuf, sizeof(modbuf), "%d", info.interim_info.rsa_data.modulo);
+	if (!BN_dec2bn(&m, modbuf))
+		goto err;
+
+	r = BN_new();
+	if (!r)
+		goto err;
+
+	if (!BN_rshift1(r, m))
+		goto err;
+
+	buf = BN_bn2dec(r);
+	bits = atoi(buf);
+
+	p = BN_new();
+	if (!p)
+		goto err;
+
+	q = BN_new();
+	if (!q)
+		goto err;
+
+	n = BN_new();
+	if (!n)
+		goto err;
+
+	d = BN_new();
+	if (!d)
+		goto err;
+
+	/* Generate p and q suitably for RSA */
+	for (i = 0; i < 10; i++) {
+		uint8_t j = 0;
+
+		if (!BN_generate_prime_ex(p, bits, 0, NULL, NULL, NULL))
+			goto err;
+
+		do {
+			RAND_add(&j, sizeof(j), 1);
+			if (!BN_generate_prime_ex(q, bits, 0, NULL, NULL, NULL))
+				goto err;
+
+		} while ((BN_cmp(p, q) == 0) && (j++ < 100));
+
+		if (j >= 100) {
+			RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate q", j);
+			goto err;
+		}
+
+		/* pq */
+		if (!BN_mul(n, p, q, ctx))
+			goto err;
+
+		/* p-1 */
+		if (!BN_sub(r1, p, BN_value_one()))
+			goto err;
+
+		/* q-1 */
+		if (!BN_sub(r2, q, BN_value_one()))
+			goto err;
+
+		/* (p-1 * q-1) */
+		if (!BN_mul(r0, r1, r2, ctx))
+			goto err;
+
+		/* gcd(p-1, q-1)*/
+		if (!BN_gcd(r3, r1, r2, ctx))
+			goto err;
+
+		/* lcm(p-1, q-1) */
+		if (!BN_div(r4, r, r0, r3, ctx))
+			goto err;
+
+		/* check if div and rem are non-zero */
+		if (!r4 || !r)
+			goto err;
+
+		/* 0 < e < lcm */
+		if (!e) {
+			int k = 0;
+
+			e = BN_new();
+			do {
+				RAND_add(&k, sizeof(k), 1);
+				if (!BN_rand(e, 32, 1, 1))
+					goto err;
+
+				if (!BN_gcd(r3, e, r4, ctx))
+					goto err;
+
+				if (BN_is_one(r3))
+					break;
+			} while (k++ < 10);
+
+			if (k >= 10) {
+				RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate e",
+					k);
+				goto err;
+			}
+		}
+
+		/* (de) mod lcm == 1 */
+		if (!BN_mod_inverse(d, e, r4, ctx))
+			goto err;
+
+		if (!BN_gcd(r3, r1, e, ctx))
+			goto err;
+
+		if (!BN_gcd(r4, r2, e, ctx))
+			goto err;
+
+		/* check if gcd(p-1, e) and gcd(q-1, e) are 1 */
+		if (BN_is_one(r3) && BN_is_one(r4))
+			break;
+	}
+
+	if (i >= 10) {
+		RTE_LOG(ERR, USER1, "Error: insufficient %d retries to generate p and q", i);
+		goto err;
+	}
+
+	/* d mod (p-1) */
+	dp = BN_new();
+	if (!dp)
+		goto err;
+
+	if (!BN_mod(dp, d, r1, ctx))
+		goto err;
+
+	/* d mod (q-1) */
+	dq = BN_new();
+	if (!dq)
+		goto err;
+
+	if (!BN_mod(dq, d, r2, ctx))
+		goto err;
+
+	/* modinv of q and p */
+	qinv = BN_new();
+	if (!qinv)
+		goto err;
+
+	if (!BN_mod_inverse(qinv, q, p, ctx))
+		goto err;
+
+	parse_uint8_hex_str("", BN_bn2hex(e), &vec.rsa.e);
+	parse_uint8_hex_str("", BN_bn2hex(p), &vec.rsa.p);
+	parse_uint8_hex_str("", BN_bn2hex(q), &vec.rsa.q);
+	parse_uint8_hex_str("", BN_bn2hex(n), &vec.rsa.n);
+	parse_uint8_hex_str("", BN_bn2hex(d), &vec.rsa.d);
+	parse_uint8_hex_str("", BN_bn2hex(dp), &vec.rsa.dp);
+	parse_uint8_hex_str("", BN_bn2hex(dq), &vec.rsa.dq);
+	parse_uint8_hex_str("", BN_bn2hex(qinv), &vec.rsa.qinv);
+
+	ret = 0;
+err:
+	BN_CTX_end(ctx);
+	BN_CTX_free(ctx);
+	BN_free(m);
+	BN_free(r);
+	BN_free(p);
+	BN_free(q);
+	BN_free(n);
+	BN_free(d);
+	BN_free(e);
+	return ret;
+}
+#else
+static int
+prepare_vec_rsa(void)
+{
+	/*
+	 * Generate RSA values.
+	 */
+	return -ENOTSUP;
+}
+#endif /* USE_OPENSSL */
+
+static int
+parse_test_rsa_json_interim_writeback(struct fips_val *val)
+{
+	RTE_SET_USED(val);
+
+	if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		json_t *obj;
+
+		/* For siggen tests, RSA values can be created soon after
+		 * the test group data are parsed.
+		 */
+		if (vec.rsa.e.val) {
+			rte_free(vec.rsa.e.val);
+			vec.rsa.e.val = NULL;
+		}
+
+		if (prepare_vec_rsa() < 0)
+			return -1;
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.n);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_group, "n", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_group, "e", obj);
+	}
+
+	return 0;
+}
+
+static int
+parse_test_rsa_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_KEYGEN) {
+		json_t *obj;
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.seed);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "seed", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.n);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "n", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.e);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "e", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.p);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "p", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.q);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "q", obj);
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.d);
+		obj = json_string(info.one_line_text);
+		json_object_set_new(json_info.json_write_case, "d", obj);
+	} else if (info.op == FIPS_TEST_ASYM_SIGGEN) {
+		json_t *obj;
+
+		writeback_hex_str("", info.one_line_text, &vec.rsa.signature);
+		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());
+	}
+
+	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, SIGTYPE_JSON_STR) == 0) {
+		for (i = 0; i < RTE_DIM(rsa_padding_types); i++)
+			if (strstr(src, rsa_padding_types[i].desc)) {
+				info.interim_info.rsa_data.padding = rsa_padding_types[i].padding;
+				break;
+			}
+
+		if (i >= RTE_DIM(rsa_padding_types))
+			return -EINVAL;
+
+	}  else if (strcmp(key, MOD_JSON_STR) == 0) {
+		info.interim_info.rsa_data.modulo = atoi(src);
+	} else if (strcmp(key, HASH_JSON_STR) == 0) {
+		for (i = 0; i < RTE_DIM(rsa_auth_algs); i++)
+			if (strstr(src, rsa_auth_algs[i].desc)) {
+				info.interim_info.rsa_data.auth = rsa_auth_algs[i].auth;
+				break;
+			}
+
+		if (i >= RTE_DIM(rsa_auth_algs))
+			return -EINVAL;
+
+	}  else if (strcmp(key, SALT_JSON_STR) == 0) {
+		info.interim_info.rsa_data.saltlen = atoi(src);
+	} else if (strcmp(key, TESTTYPE_JSON_STR) == 0) {
+		for (i = 0; i < RTE_DIM(rsa_test_types); i++)
+			if (strstr(src, rsa_test_types[i].desc)) {
+				info.parse_writeback = parse_test_rsa_json_writeback;
+				break;
+			}
+
+		if (!info.parse_writeback || i >= RTE_DIM(rsa_test_types))
+			return -EINVAL;
+
+	} else {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
+parse_keygen_e_str(const char *key, char *src, struct fips_val *val)
+{
+	parse_uint8_hex_str(key, src, val);
+
+	/* For keygen tests, key "e" can be the end of input data
+	 * to generate RSA values.
+	 */
+	return prepare_vec_rsa();
+}
+
+struct fips_test_callback rsa_keygen_interim_json_vectors[] = {
+		{MOD_JSON_STR, parse_interim_str, NULL},
+		{HASH_JSON_STR, parse_interim_str, NULL},
+		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback rsa_siggen_interim_json_vectors[] = {
+		{SIGTYPE_JSON_STR, parse_interim_str, NULL},
+		{MOD_JSON_STR, parse_interim_str, NULL},
+		{HASH_JSON_STR, parse_interim_str, NULL},
+		{SALT_JSON_STR, parse_interim_str, NULL},
+		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback rsa_sigver_interim_json_vectors[] = {
+		{SIGTYPE_JSON_STR, parse_interim_str, NULL},
+		{MOD_JSON_STR, parse_interim_str, NULL},
+		{HASH_JSON_STR, parse_interim_str, NULL},
+		{SALT_JSON_STR, parse_interim_str, NULL},
+		{N_JSON_STR, parse_uint8_hex_str, &vec.rsa.n},
+		{E_JSON_STR, parse_uint8_hex_str, &vec.rsa.e},
+		{TESTTYPE_JSON_STR, parse_interim_str, NULL},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback rsa_keygen_json_vectors[] = {
+		{SEED_JSON_STR, parse_uint8_hex_str, &vec.rsa.seed},
+		{E_JSON_STR, parse_keygen_e_str, &vec.rsa.e},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback rsa_siggen_json_vectors[] = {
+		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+struct fips_test_callback rsa_sigver_json_vectors[] = {
+		{MSG_JSON_STR, parse_uint8_hex_str, &vec.pt},
+		{SIG_JSON_STR, parse_uint8_hex_str, &vec.rsa.signature},
+		{NULL, NULL, NULL} /**< end pointer */
+};
+
+int
+parse_test_rsa_json_init(void)
+{
+	json_t *keyfmt_obj = json_object_get(json_info.json_vector_set, "keyFormat");
+	json_t *mode_obj = json_object_get(json_info.json_vector_set, "mode");
+	const char *keyfmt_str = json_string_value(keyfmt_obj);
+	const char *mode_str = json_string_value(mode_obj);
+
+	info.callbacks = NULL;
+	info.parse_writeback = NULL;
+	info.interim_callbacks = NULL;
+	info.parse_interim_writeback = NULL;
+
+	if (strcmp(mode_str, "keyGen") == 0) {
+		info.op = FIPS_TEST_ASYM_KEYGEN;
+		info.callbacks = rsa_keygen_json_vectors;
+		info.interim_callbacks = rsa_keygen_interim_json_vectors;
+	} else if (strcmp(mode_str, "sigGen") == 0) {
+		info.op = FIPS_TEST_ASYM_SIGGEN;
+		info.callbacks = rsa_siggen_json_vectors;
+		info.interim_callbacks = rsa_siggen_interim_json_vectors;
+		info.parse_interim_writeback = parse_test_rsa_json_interim_writeback;
+	} else if (strcmp(mode_str, "sigVer") == 0) {
+		info.op = FIPS_TEST_ASYM_SIGVER;
+		info.callbacks = rsa_sigver_json_vectors;
+		info.interim_callbacks = rsa_sigver_interim_json_vectors;
+	} else {
+		return -EINVAL;
+	}
+
+	info.interim_info.rsa_data.privkey = RTE_RSA_KEY_TYPE_QT;
+	if (keyfmt_str != NULL && strcmp(keyfmt_str, "standard") == 0)
+		info.interim_info.rsa_data.privkey = RTE_RSA_KEY_TYPE_EXP;
+
+	return 0;
+}
+#endif /* USE_JANSSON */
+
diff --git a/examples/fips_validation/main.c b/examples/fips_validation/main.c
index 8babbb3298..ed86c10350 100644
--- a/examples/fips_validation/main.c
+++ b/examples/fips_validation/main.c
@@ -36,6 +36,8 @@  enum {
 	OPT_CRYPTODEV_BK_DIR_KEY_NUM,
 #define OPT_USE_JSON                "use-json"
 	OPT_USE_JSON_NUM,
+#define OPT_CRYPTODEV_ASYM          "asymmetric"
+	OPT_CRYPTODEV_ASYM_NUM,
 };
 
 struct fips_test_vector vec;
@@ -50,27 +52,133 @@  struct cryptodev_fips_validate_env {
 	const char *rsp_path;
 	uint32_t is_path_folder;
 	uint8_t dev_id;
-	uint8_t dev_support_sgl;
-	uint16_t mbuf_data_room;
 	struct rte_mempool *mpool;
-	struct rte_mempool *sess_mpool;
 	struct rte_mempool *sess_priv_mpool;
-	struct rte_mempool *op_pool;
+	struct fips_sym_env {
+		struct rte_mempool *sess_mpool;
+		struct rte_mempool *op_pool;
+		struct rte_cryptodev_sym_session *sess;
+		struct rte_crypto_op *op;
+	} sym;
+	struct fips_asym_env {
+		struct rte_mempool *sess_mpool;
+		struct rte_mempool *op_pool;
+		struct rte_cryptodev_asym_session *sess;
+		struct rte_crypto_op *op;
+	} asym;
+	struct rte_crypto_op *op;
+	uint8_t dev_support_sgl;
+	uint16_t mbuf_data_room;
 	struct rte_mbuf *mbuf;
 	uint8_t *digest;
 	uint16_t digest_len;
-	struct rte_crypto_op *op;
-	struct rte_cryptodev_sym_session *sess;
+	bool is_asym_test;
 	uint16_t self_test;
 	struct fips_dev_broken_test_config *broken_test_config;
 } env;
 
 static int
-cryptodev_fips_validate_app_int(void)
+cryptodev_fips_validate_app_sym_init(void)
+{
+	struct rte_cryptodev_info dev_info;
+	struct fips_sym_env *sym = &env.sym;
+	int ret;
+
+	rte_cryptodev_info_get(env.dev_id, &dev_info);
+	if (dev_info.feature_flags & RTE_CRYPTODEV_FF_IN_PLACE_SGL)
+		env.dev_support_sgl = 1;
+	else
+		env.dev_support_sgl = 0;
+
+	ret = -ENOMEM;
+	sym->sess_mpool = rte_cryptodev_sym_session_pool_create(
+			"FIPS_SYM_SESS_MEMPOOL", 16, 0, 0, 0, rte_socket_id());
+	if (!sym->sess_mpool)
+		goto error_exit;
+
+	sym->op_pool = rte_crypto_op_pool_create(
+			"FIPS_OP_SYM_POOL",
+			RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			1, 0,
+			16,
+			rte_socket_id());
+	if (!sym->op_pool)
+		goto error_exit;
+
+	sym->op = rte_crypto_op_alloc(sym->op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+	if (!sym->op)
+		goto error_exit;
+
+	return 0;
+
+error_exit:
+	rte_mempool_free(sym->sess_mpool);
+	rte_mempool_free(sym->op_pool);
+	return ret;
+}
+
+static void
+cryptodev_fips_validate_app_sym_uninit(void)
+{
+	struct fips_sym_env *sym = &env.sym;
+
+	rte_pktmbuf_free(env.mbuf);
+	rte_crypto_op_free(sym->op);
+	rte_cryptodev_sym_session_clear(env.dev_id, sym->sess);
+	rte_cryptodev_sym_session_free(sym->sess);
+	rte_mempool_free(sym->sess_mpool);
+	rte_mempool_free(sym->op_pool);
+}
+
+static int
+cryptodev_fips_validate_app_asym_init(void)
+{
+	struct fips_asym_env *asym = &env.asym;
+	int ret;
+
+	ret = -ENOMEM;
+	asym->sess_mpool = rte_cryptodev_asym_session_pool_create(
+			"FIPS_ASYM_SESS_MEMPOOL", 16, 0, 0, rte_socket_id());
+	if (!asym->sess_mpool)
+		goto error_exit;
+
+	asym->op_pool = rte_crypto_op_pool_create(
+			"FIPS_OP_ASYM_POOL",
+			RTE_CRYPTO_OP_TYPE_ASYMMETRIC,
+			1, 0,
+			16,
+			rte_socket_id());
+	if (!asym->op_pool)
+		goto error_exit;
+
+	asym->op = rte_crypto_op_alloc(asym->op_pool, RTE_CRYPTO_OP_TYPE_ASYMMETRIC);
+	if (!asym->op)
+		goto error_exit;
+
+	return 0;
+
+error_exit:
+	rte_mempool_free(asym->sess_mpool);
+	rte_mempool_free(asym->op_pool);
+	return ret;
+}
+
+static void
+cryptodev_fips_validate_app_asym_uninit(void)
+{
+	struct fips_asym_env *asym = &env.asym;
+
+	rte_crypto_op_free(asym->op);
+	rte_cryptodev_asym_session_free(env.dev_id, asym->sess);
+	rte_mempool_free(asym->sess_mpool);
+	rte_mempool_free(asym->op_pool);
+}
+
+static int
+cryptodev_fips_validate_app_init(void)
 {
 	struct rte_cryptodev_config conf = {rte_socket_id(), 1, 0};
 	struct rte_cryptodev_qp_conf qp_conf = {128, NULL, NULL};
-	struct rte_cryptodev_info dev_info;
 	uint32_t sess_sz = rte_cryptodev_sym_get_private_session_size(
 			env.dev_id);
 	uint32_t nb_mbufs = UINT16_MAX / env.mbuf_data_room + 1;
@@ -89,50 +197,30 @@  cryptodev_fips_validate_app_int(void)
 	if (ret < 0)
 		return ret;
 
-	rte_cryptodev_info_get(env.dev_id, &dev_info);
-	if (dev_info.feature_flags & RTE_CRYPTODEV_FF_IN_PLACE_SGL)
-		env.dev_support_sgl = 1;
-	else
-		env.dev_support_sgl = 0;
-
+	ret = -ENOMEM;
 	env.mpool = rte_pktmbuf_pool_create("FIPS_MEMPOOL", nb_mbufs,
 			0, 0, sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM +
 			env.mbuf_data_room, rte_socket_id());
 	if (!env.mpool)
 		return ret;
 
-	ret = rte_cryptodev_queue_pair_setup(env.dev_id, 0, &qp_conf,
-			rte_socket_id());
-	if (ret < 0)
-		return ret;
-
-	ret = -ENOMEM;
-
-	env.sess_mpool = rte_cryptodev_sym_session_pool_create(
-			"FIPS_SESS_MEMPOOL", 16, 0, 0, 0, rte_socket_id());
-	if (!env.sess_mpool)
-		goto error_exit;
-
 	env.sess_priv_mpool = rte_mempool_create("FIPS_SESS_PRIV_MEMPOOL",
 			16, sess_sz, 0, 0, NULL, NULL, NULL,
 			NULL, rte_socket_id(), 0);
 	if (!env.sess_priv_mpool)
 		goto error_exit;
 
-	env.op_pool = rte_crypto_op_pool_create(
-			"FIPS_OP_POOL",
-			RTE_CRYPTO_OP_TYPE_SYMMETRIC,
-			1, 0,
-			16,
-			rte_socket_id());
-	if (!env.op_pool)
+	ret = cryptodev_fips_validate_app_sym_init();
+	if (ret < 0)
 		goto error_exit;
 
-	env.op = rte_crypto_op_alloc(env.op_pool, RTE_CRYPTO_OP_TYPE_SYMMETRIC);
-	if (!env.op)
-		goto error_exit;
+	if (env.is_asym_test) {
+		ret = cryptodev_fips_validate_app_asym_init();
+		if (ret < 0)
+			goto error_exit;
+	}
 
-	qp_conf.mp_session = env.sess_mpool;
+	qp_conf.mp_session = env.sym.sess_mpool;
 	qp_conf.mp_session_private = env.sess_priv_mpool;
 
 	ret = rte_cryptodev_queue_pair_setup(env.dev_id, 0, &qp_conf,
@@ -147,26 +235,21 @@  cryptodev_fips_validate_app_int(void)
 	return 0;
 
 error_exit:
-
 	rte_mempool_free(env.mpool);
-	rte_mempool_free(env.sess_mpool);
 	rte_mempool_free(env.sess_priv_mpool);
-	rte_mempool_free(env.op_pool);
-
 	return ret;
 }
 
 static void
 cryptodev_fips_validate_app_uninit(void)
 {
-	rte_pktmbuf_free(env.mbuf);
-	rte_crypto_op_free(env.op);
-	rte_cryptodev_sym_session_clear(env.dev_id, env.sess);
-	rte_cryptodev_sym_session_free(env.sess);
+	cryptodev_fips_validate_app_sym_uninit();
+
+	if (env.is_asym_test)
+		cryptodev_fips_validate_app_asym_uninit();
+
 	rte_mempool_free(env.mpool);
-	rte_mempool_free(env.sess_mpool);
 	rte_mempool_free(env.sess_priv_mpool);
-	rte_mempool_free(env.op_pool);
 }
 
 static int
@@ -262,6 +345,8 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 				NULL, OPT_CRYPTODEV_BK_ID_NUM},
 		{OPT_CRYPTODEV_BK_DIR_KEY, required_argument,
 				NULL, OPT_CRYPTODEV_BK_DIR_KEY_NUM},
+		{OPT_CRYPTODEV_ASYM, no_argument,
+				NULL, OPT_CRYPTODEV_ASYM_NUM},
 		{NULL, 0, 0, 0}
 	};
 
@@ -374,6 +459,10 @@  cryptodev_fips_validate_parse_args(int argc, char **argv)
 			}
 			break;
 
+		case OPT_CRYPTODEV_ASYM_NUM:
+			env.is_asym_test = true;
+			break;
+
 		default:
 			cryptodev_fips_validate_usage(prgname);
 			return -EINVAL;
@@ -414,7 +503,7 @@  main(int argc, char *argv[])
 	if (ret < 0)
 		rte_exit(EXIT_FAILURE, "Failed to parse arguments!\n");
 
-	ret = cryptodev_fips_validate_app_int();
+	ret = cryptodev_fips_validate_app_init();
 	if (ret < 0) {
 		RTE_LOG(ERR, USER1, "Error %i: Failed init\n", ret);
 		return -1;
@@ -653,7 +742,7 @@  prepare_cipher_op(void)
 		sym->cipher.data.length = vec.ct.len;
 	}
 
-	rte_crypto_op_attach_sym_session(env.op, env.sess);
+	rte_crypto_op_attach_sym_session(env.op, env.sym.sess);
 
 	sym->m_src = env.mbuf;
 	sym->cipher.data.offset = 0;
@@ -701,7 +790,7 @@  prepare_auth_op(void)
 		memcpy(env.digest, vec.cipher_auth.digest.val,
 				vec.cipher_auth.digest.len);
 
-	rte_crypto_op_attach_sym_session(env.op, env.sess);
+	rte_crypto_op_attach_sym_session(env.op, env.sym.sess);
 
 	return 0;
 }
@@ -757,7 +846,55 @@  prepare_aead_op(void)
 	sym->aead.aad.data = vec.aead.aad.val;
 	sym->aead.aad.phys_addr = rte_malloc_virt2iova(sym->aead.aad.data);
 
-	rte_crypto_op_attach_sym_session(env.op, env.sess);
+	rte_crypto_op_attach_sym_session(env.op, env.sym.sess);
+
+	return 0;
+}
+
+static int
+prepare_rsa_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;
+	asym->rsa.padding.type = info.interim_info.rsa_data.padding;
+	asym->rsa.padding.hash = info.interim_info.rsa_data.auth;
+
+	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->rsa.op_type = RTE_CRYPTO_ASYM_OP_SIGN;
+		asym->rsa.message.data = msg.val;
+		asym->rsa.message.length = msg.len;
+
+		if (vec.rsa.signature.val)
+			rte_free(vec.rsa.signature.val);
+
+		vec.rsa.signature.val = rte_zmalloc(NULL, vec.rsa.n.len, 0);
+		vec.rsa.signature.len = vec.rsa.n.len;
+		asym->rsa.sign.data = vec.rsa.signature.val;
+		asym->rsa.sign.length = 0;
+	} else if (info.op == FIPS_TEST_ASYM_SIGVER) {
+		asym->rsa.op_type = RTE_CRYPTO_ASYM_OP_VERIFY;
+		asym->rsa.message.data = msg.val;
+		asym->rsa.message.length = msg.len;
+		asym->rsa.sign.data = vec.rsa.signature.val;
+		asym->rsa.sign.length = vec.rsa.signature.len;
+	} else {
+		RTE_LOG(ERR, USER1, "Invalid op %d\n", info.op);
+		return -EINVAL;
+	}
+
+	rte_crypto_op_attach_asym_session(env.op, env.asym.sess);
 
 	return 0;
 }
@@ -1145,6 +1282,87 @@  prepare_xts_xform(struct rte_crypto_sym_xform *xform)
 	return 0;
 }
 
+static int
+prepare_rsa_xform(struct rte_crypto_asym_xform *xform)
+{
+	const struct rte_cryptodev_asymmetric_xform_capability *cap;
+	struct rte_cryptodev_asym_capability_idx cap_idx;
+	struct rte_cryptodev_info dev_info;
+
+	xform->xform_type = RTE_CRYPTO_ASYM_XFORM_RSA;
+	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;
+		}
+		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;
+		}
+		break;
+	case FIPS_TEST_ASYM_KEYGEN:
+		break;
+	default:
+		break;
+	}
+
+	rte_cryptodev_info_get(env.dev_id, &dev_info);
+	xform->rsa.key_type = info.interim_info.rsa_data.privkey;
+	switch (xform->rsa.key_type) {
+	case RTE_RSA_KEY_TYPE_QT:
+		if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_RSA_PRIV_OP_KEY_QT)) {
+			RTE_LOG(ERR, USER1, "PMD %s does not support QT key type\n",
+				info.device_name);
+			return -EPERM;
+		}
+		xform->rsa.qt.p.data = vec.rsa.p.val;
+		xform->rsa.qt.p.length = vec.rsa.p.len;
+		xform->rsa.qt.q.data = vec.rsa.q.val;
+		xform->rsa.qt.q.length = vec.rsa.q.len;
+		xform->rsa.qt.dP.data = vec.rsa.dp.val;
+		xform->rsa.qt.dP.length = vec.rsa.dp.len;
+		xform->rsa.qt.dQ.data = vec.rsa.dq.val;
+		xform->rsa.qt.dQ.length = vec.rsa.dq.len;
+		xform->rsa.qt.qInv.data = vec.rsa.qinv.val;
+		xform->rsa.qt.qInv.length = vec.rsa.qinv.len;
+		break;
+	case RTE_RSA_KEY_TYPE_EXP:
+		if (!(dev_info.feature_flags & RTE_CRYPTODEV_FF_RSA_PRIV_OP_KEY_EXP)) {
+			RTE_LOG(ERR, USER1, "PMD %s does not support EXP key type\n",
+				info.device_name);
+			return -EPERM;
+		}
+		xform->rsa.d.data = vec.rsa.d.val;
+		xform->rsa.d.length = vec.rsa.d.len;
+		break;
+	default:
+		break;
+	}
+
+	xform->rsa.e.data = vec.rsa.e.val;
+	xform->rsa.e.length = vec.rsa.e.len;
+	xform->rsa.n.data = vec.rsa.n.val;
+	xform->rsa.n.length = vec.rsa.n.len;
+	return 0;
+}
+
 static int
 get_writeback_data(struct fips_val *val)
 {
@@ -1191,29 +1409,29 @@  get_writeback_data(struct fips_val *val)
 }
 
 static int
-fips_run_test(void)
+fips_run_sym_test(void)
 {
 	struct rte_crypto_sym_xform xform = {0};
 	uint16_t n_deqd;
 	int ret;
 
-	ret = test_ops.prepare_xform(&xform);
+	ret = test_ops.prepare_sym_xform(&xform);
 	if (ret < 0)
 		return ret;
 
-	env.sess = rte_cryptodev_sym_session_create(env.sess_mpool);
-	if (!env.sess)
+	env.sym.sess = rte_cryptodev_sym_session_create(env.sym.sess_mpool);
+	if (!env.sym.sess)
 		return -ENOMEM;
 
 	ret = rte_cryptodev_sym_session_init(env.dev_id,
-			env.sess, &xform, env.sess_priv_mpool);
+			env.sym.sess, &xform, env.sess_priv_mpool);
 	if (ret < 0) {
 		RTE_LOG(ERR, USER1, "Error %i: Init session\n",
 				ret);
 		goto exit;
 	}
 
-	ret = test_ops.prepare_op();
+	ret = test_ops.prepare_sym_op();
 	if (ret < 0) {
 		RTE_LOG(ERR, USER1, "Error %i: Prepare op\n",
 				ret);
@@ -1229,20 +1447,90 @@  fips_run_test(void)
 	do {
 		struct rte_crypto_op *deqd_op;
 
-		n_deqd = rte_cryptodev_dequeue_burst(env.dev_id, 0, &deqd_op,
-				1);
+		n_deqd = rte_cryptodev_dequeue_burst(env.dev_id, 0, &deqd_op, 1);
 	} while (n_deqd == 0);
 
 	vec.status = env.op->status;
 
 exit:
-	rte_cryptodev_sym_session_clear(env.dev_id, env.sess);
-	rte_cryptodev_sym_session_free(env.sess);
-	env.sess = NULL;
+	rte_cryptodev_sym_session_clear(env.dev_id, env.sym.sess);
+	rte_cryptodev_sym_session_free(env.sym.sess);
+	env.sym.sess = NULL;
 
 	return ret;
 }
 
+static int
+fips_run_asym_test(void)
+{
+	struct rte_crypto_asym_xform xform = {0};
+	struct rte_crypto_asym_op *asym;
+	struct rte_crypto_op *deqd_op;
+	int ret;
+
+	if (info.op == FIPS_TEST_ASYM_KEYGEN) {
+		RTE_SET_USED(asym);
+		ret = 0;
+		goto exit;
+	}
+
+	asym = env.op->asym;
+	ret = test_ops.prepare_asym_xform(&xform);
+	if (ret < 0)
+		return ret;
+
+	ret = rte_cryptodev_asym_session_create(env.dev_id, &xform,  env.asym.sess_mpool,
+			(void *)&env.asym.sess);
+	if (ret < 0)
+		return ret;
+
+	ret = test_ops.prepare_asym_op();
+	if (ret < 0) {
+		RTE_LOG(ERR, USER1, "Error %i: Prepare op\n", ret);
+		goto exit;
+	}
+
+	if (rte_cryptodev_enqueue_burst(env.dev_id, 0, &env.op, 1) < 1) {
+		RTE_LOG(ERR, USER1, "Error: Failed enqueue\n");
+		ret = -1;
+		goto exit;
+	}
+
+	while (rte_cryptodev_dequeue_burst(env.dev_id, 0, &deqd_op, 1) == 0)
+		rte_pause();
+
+	vec.status = env.op->status;
+
+ exit:
+	if (env.asym.sess)
+		rte_cryptodev_asym_session_free(env.dev_id, env.asym.sess);
+
+	env.asym.sess = NULL;
+	return ret;
+}
+
+static int
+fips_run_test(void)
+{
+	int ret;
+
+	env.op = env.sym.op;
+	if (env.is_asym_test) {
+		vec.cipher_auth.digest.len = parse_test_sha_hash_size(
+						info.interim_info.rsa_data.auth);
+		test_ops.prepare_sym_xform = prepare_sha_xform;
+		test_ops.prepare_sym_op = prepare_auth_op;
+		ret = fips_run_sym_test();
+		if (ret < 0)
+			return ret;
+	} else {
+		return fips_run_sym_test();
+	}
+
+	env.op = env.asym.op;
+	return fips_run_asym_test();
+}
+
 static int
 fips_generic_test(void)
 {
@@ -1265,9 +1553,11 @@  fips_generic_test(void)
 		return ret;
 	}
 
-	ret = get_writeback_data(&val);
-	if (ret < 0)
-		return ret;
+	if (!env.is_asym_test) {
+		ret = get_writeback_data(&val);
+		if (ret < 0)
+			return ret;
+	}
 
 	switch (info.file_type) {
 	case FIPS_TYPE_REQ:
@@ -1814,60 +2104,65 @@  init_test_ops(void)
 	switch (info.algo) {
 	case FIPS_TEST_ALGO_AES_CBC:
 	case FIPS_TEST_ALGO_AES:
-		test_ops.prepare_op = prepare_cipher_op;
-		test_ops.prepare_xform  = prepare_aes_xform;
+		test_ops.prepare_sym_op = prepare_cipher_op;
+		test_ops.prepare_sym_xform  = prepare_aes_xform;
 		if (info.interim_info.aes_data.test_type == AESAVS_TYPE_MCT)
 			test_ops.test = fips_mct_aes_test;
 		else
 			test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_HMAC:
-		test_ops.prepare_op = prepare_auth_op;
-		test_ops.prepare_xform = prepare_hmac_xform;
+		test_ops.prepare_sym_op = prepare_auth_op;
+		test_ops.prepare_sym_xform = prepare_hmac_xform;
 		test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_TDES:
-		test_ops.prepare_op = prepare_cipher_op;
-		test_ops.prepare_xform  = prepare_tdes_xform;
+		test_ops.prepare_sym_op = prepare_cipher_op;
+		test_ops.prepare_sym_xform = prepare_tdes_xform;
 		if (info.interim_info.tdes_data.test_type == TDES_MCT)
 			test_ops.test = fips_mct_tdes_test;
 		else
 			test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_AES_GCM:
-		test_ops.prepare_op = prepare_aead_op;
-		test_ops.prepare_xform = prepare_gcm_xform;
+		test_ops.prepare_sym_op = prepare_aead_op;
+		test_ops.prepare_sym_xform = prepare_gcm_xform;
 		test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_AES_CMAC:
-		test_ops.prepare_op = prepare_auth_op;
-		test_ops.prepare_xform = prepare_cmac_xform;
+		test_ops.prepare_sym_op = prepare_auth_op;
+		test_ops.prepare_sym_xform = prepare_cmac_xform;
 		test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_AES_CCM:
-		test_ops.prepare_op = prepare_aead_op;
-		test_ops.prepare_xform = prepare_ccm_xform;
+		test_ops.prepare_sym_op = prepare_aead_op;
+		test_ops.prepare_sym_xform = prepare_ccm_xform;
 		test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_SHA:
-		test_ops.prepare_op = prepare_auth_op;
-		test_ops.prepare_xform = prepare_sha_xform;
+		test_ops.prepare_sym_op = prepare_auth_op;
+		test_ops.prepare_sym_xform = prepare_sha_xform;
 		if (info.interim_info.sha_data.test_type == SHA_MCT)
 			test_ops.test = fips_mct_sha_test;
 		else
 			test_ops.test = fips_generic_test;
 		break;
 	case FIPS_TEST_ALGO_AES_XTS:
-		test_ops.prepare_op = prepare_cipher_op;
-		test_ops.prepare_xform = prepare_xts_xform;
+		test_ops.prepare_sym_op = prepare_cipher_op;
+		test_ops.prepare_sym_xform = prepare_xts_xform;
+		test_ops.test = fips_generic_test;
+		break;
+	case FIPS_TEST_ALGO_RSA:
+		test_ops.prepare_asym_op = prepare_rsa_op;
+		test_ops.prepare_asym_xform = prepare_rsa_xform;
 		test_ops.test = fips_generic_test;
 		break;
 	default:
 		if (strstr(info.file_name, "TECB") ||
 				strstr(info.file_name, "TCBC")) {
 			info.algo = FIPS_TEST_ALGO_TDES;
-			test_ops.prepare_op = prepare_cipher_op;
-			test_ops.prepare_xform	= prepare_tdes_xform;
+			test_ops.prepare_sym_op = prepare_cipher_op;
+			test_ops.prepare_sym_xform = prepare_tdes_xform;
 			if (info.interim_info.tdes_data.test_type == TDES_MCT)
 				test_ops.test = fips_mct_tdes_test;
 			else
@@ -2033,6 +2328,9 @@  fips_test_one_test_group(void)
 	case FIPS_TEST_ALGO_TDES:
 		ret = parse_test_tdes_json_init();
 		break;
+	case FIPS_TEST_ALGO_RSA:
+		ret = parse_test_rsa_json_init();
+		break;
 	default:
 		return -EINVAL;
 	}
diff --git a/examples/fips_validation/meson.build b/examples/fips_validation/meson.build
index 8bca26a095..d310093189 100644
--- a/examples/fips_validation/meson.build
+++ b/examples/fips_validation/meson.build
@@ -18,6 +18,7 @@  sources = files(
         'fips_validation_ccm.c',
         'fips_validation_sha.c',
         'fips_validation_xts.c',
+        'fips_validation_rsa.c',
         'fips_dev_self_test.c',
         'main.c',
 )
@@ -26,3 +27,8 @@  if dpdk_conf.has('RTE_HAS_JANSSON')
     ext_deps += jansson_dep
     cflags += '-DUSE_JANSSON'
 endif
+
+if dpdk_conf.has('RTE_HAS_OPENSSL')
+    ext_deps += openssl_dep
+    cflags += '-DUSE_OPENSSL'
+endif