DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v1 0/2] FIPS validation capability
@ 2018-09-07 17:13 Marko Kovacevic
  2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 1/2] test/test: cryptodev application for FIPS certification Marko Kovacevic
  2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 2/2] test/test: cryptodev application parser " Marko Kovacevic
  0 siblings, 2 replies; 3+ messages in thread
From: Marko Kovacevic @ 2018-09-07 17:13 UTC (permalink / raw)
  To: dev; +Cc: akhil.goyal, roy.fan.zhang, Marko Kovacevic

Adding capability into DPDK to allow certification for FIPS
validation, I have just added one test for one algo will be adding other
algos into other versions of the patch and i will be refactoring the code and
cleaning the parser once i start adding the different algos.

Marko Kovacevic (2):
  test/test: cryptodev application for FIPS certification
  test/test: cryptodev application parser for FIPS certification

 test/test/Makefile                           |   4 +
 test/test/test_cryptodev_fips.c              | 771 +++++++++++++++++++++++++++
 test/test/test_cryptodev_fips_parse.h        | 156 ++++++
 test/test/test_cryptodev_fips_parse_aes.c    | 399 ++++++++++++++
 test/test/test_cryptodev_fips_parse_common.c | 330 ++++++++++++
 5 files changed, 1660 insertions(+)
 create mode 100644 test/test/test_cryptodev_fips.c
 create mode 100644 test/test/test_cryptodev_fips_parse.h
 create mode 100644 test/test/test_cryptodev_fips_parse_aes.c
 create mode 100644 test/test/test_cryptodev_fips_parse_common.c

-- 
2.9.5

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dpdk-dev] [PATCH v1 1/2] test/test: cryptodev application for FIPS certification
  2018-09-07 17:13 [dpdk-dev] [PATCH v1 0/2] FIPS validation capability Marko Kovacevic
@ 2018-09-07 17:13 ` Marko Kovacevic
  2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 2/2] test/test: cryptodev application parser " Marko Kovacevic
  1 sibling, 0 replies; 3+ messages in thread
From: Marko Kovacevic @ 2018-09-07 17:13 UTC (permalink / raw)
  To: dev; +Cc: akhil.goyal, roy.fan.zhang, Marko Kovacevic

Adding initial set up for the FIPS ceritifcation into DPDK,
more algos will be added in other versions of the code.
Also documentation will be added with steps on how to run.

Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
 test/test/Makefile              |   1 +
 test/test/test_cryptodev_fips.c | 771 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 772 insertions(+)
 create mode 100644 test/test/test_cryptodev_fips.c

diff --git a/test/test/Makefile b/test/test/Makefile
index e6967ba..ee74450 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -182,6 +182,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_PMD_RING) += test_pmd_ring_perf.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_blockcipher.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_asym.c
+SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_fips.c
 
 ifeq ($(CONFIG_RTE_COMPRESSDEV_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += test_compressdev.c
diff --git a/test/test/test_cryptodev_fips.c b/test/test/test_cryptodev_fips.c
new file mode 100644
index 0000000..4bfc24e
--- /dev/null
+++ b/test/test/test_cryptodev_fips.c
@@ -0,0 +1,771 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+#include <sys/stat.h>
+#include <dirent.h>
+
+#include <rte_common.h>
+#include <rte_hexdump.h>
+#include <rte_mbuf.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_pause.h>
+#include <rte_bus_vdev.h>
+
+#include <rte_crypto.h>
+#include <rte_cryptodev.h>
+#include <rte_cryptodev_pmd.h>
+#include <rte_string_fns.h>
+
+#include "test.h"
+#include "test_cryptodev.h"
+#include "test_cryptodev_fips_parse.h"
+
+#define AES_IV_LENGTH    16
+#define AES_BLOCK_LENGTH 16
+#define AES_MCT_NUM_INTERNAL_ITER 1000
+#define AES_MCT_NUM_EXTERNAL_ITER 100
+
+
+
+struct crypto_testsuite_params {
+	struct rte_mempool *mbuf_pool;
+	struct rte_mempool *op_mpool;
+	struct rte_mempool *session_mpool;
+	struct rte_cryptodev_config conf;
+	struct rte_cryptodev_qp_conf qp_conf;
+	uint8_t enabled_devs[RTE_CRYPTO_MAX_DEVS];
+	uint8_t nb_enabled_devs;
+};
+
+static struct crypto_testsuite_params testsuite_params = { NULL };
+
+static int
+fips_testsuite_setup(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	uint8_t nb_devs;
+	uint8_t dev_id, i;
+	uint32_t max_session_size = 0;
+
+	memset(ts_params, 0, sizeof(*ts_params));
+
+	ts_params->mbuf_pool = rte_mempool_lookup("mbuf pool");
+	if (ts_params->mbuf_pool == NULL) {
+		/* Not already created so create */
+		ts_params->mbuf_pool = rte_pktmbuf_pool_create(
+				"Mbuf pool",
+				1, 0, 0, UINT16_MAX,
+				rte_socket_id());
+		if (ts_params->mbuf_pool == NULL) {
+			RTE_LOG(ERR, USER1, "Can't create CRYPTO_MBUFPOOL\n");
+			return TEST_FAILED;
+		}
+	}
+
+	ts_params->op_mpool = rte_crypto_op_pool_create(
+			"Op pool",
+			RTE_CRYPTO_OP_TYPE_SYMMETRIC,
+			1, 0,
+			MAXIMUM_IV_LENGTH,
+			rte_socket_id());
+	if (ts_params->op_mpool == NULL) {
+		RTE_LOG(ERR, USER1, "Can't create CRYPTO_OP_POOL\n");
+		return TEST_FAILED;
+	}
+
+	nb_devs = rte_cryptodev_count();
+	if (nb_devs < 1) {
+		RTE_LOG(ERR, USER1, "No crypto devices found?\n");
+		return TEST_FAILED;
+	}
+
+	ts_params->conf.nb_queue_pairs = 1;
+	ts_params->conf.socket_id = SOCKET_ID_ANY;
+
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+
+	/* Configure device capable of encrypting with AES-CBC */
+	for (dev_id = 0; dev_id < nb_devs; dev_id++) {
+		cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+		cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_AES_CBC;
+		if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) != NULL) {
+			ts_params->enabled_devs[ts_params->nb_enabled_devs] = dev_id;
+			(ts_params->nb_enabled_devs)++;
+			break;
+		}
+	}
+
+	if (dev_id == nb_devs)
+		RTE_LOG(WARNING, USER1, "There is no device that supports AES-CBC\n");
+
+	/* Configure device capable of encrypting with AES-GCM */
+	for (dev_id = 0; dev_id < nb_devs; dev_id++) {
+		cap_idx.type = RTE_CRYPTO_SYM_XFORM_AEAD;
+		cap_idx.algo.aead = RTE_CRYPTO_AEAD_AES_GCM;
+		if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) != NULL) {
+			for (i = 0; i < ts_params->nb_enabled_devs; i++)
+				if (ts_params->enabled_devs[i] == dev_id)
+					break;
+			if (i == ts_params->nb_enabled_devs) {
+				ts_params->enabled_devs[ts_params->nb_enabled_devs] = dev_id;
+				(ts_params->nb_enabled_devs)++;
+			}
+
+			break;
+		}
+	}
+
+	if (dev_id == nb_devs)
+		RTE_LOG(WARNING, USER1, "There is no device that supports AES-GCM\n");
+
+	/* Configure device capable of authenticating with HMAC */
+	for (dev_id = 0; dev_id < nb_devs; dev_id++) {
+		cap_idx.type = RTE_CRYPTO_SYM_XFORM_AUTH;
+		cap_idx.algo.auth = RTE_CRYPTO_AUTH_SHA1_HMAC;
+		if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) != NULL) {
+			/*
+			 * Check if device supports other HMAC algorithms,
+			 * apart from SHA1
+			 */
+			cap_idx.algo.auth = RTE_CRYPTO_AUTH_SHA224_HMAC;
+			if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) == NULL)
+				continue;
+
+			cap_idx.algo.auth = RTE_CRYPTO_AUTH_SHA256_HMAC;
+			if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) == NULL)
+				continue;
+
+			cap_idx.algo.auth = RTE_CRYPTO_AUTH_SHA384_HMAC;
+			if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) == NULL)
+				continue;
+
+			cap_idx.algo.auth = RTE_CRYPTO_AUTH_SHA512_HMAC;
+			if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) == NULL)
+				continue;
+
+			for (i = 0; i < ts_params->nb_enabled_devs; i++)
+				if (ts_params->enabled_devs[i] == dev_id)
+					break;
+			if (i == ts_params->nb_enabled_devs) {
+				ts_params->enabled_devs[ts_params->nb_enabled_devs] = dev_id;
+				(ts_params->nb_enabled_devs)++;
+			}
+
+			break;
+		}
+	}
+
+	if (dev_id == nb_devs)
+		RTE_LOG(WARNING, USER1, "There is no device that supports all HMAC algorithms\n");
+
+	if (ts_params->nb_enabled_devs == 0) {
+		RTE_LOG(ERR, USER1,
+			"There are no crypto devices that support at least "
+			"one algorithm for the FIPS testing\n");
+		return TEST_FAILED;
+	}
+
+	for (i = 0; i < ts_params->nb_enabled_devs; i++) {
+		uint32_t session_size;
+		dev_id = ts_params->enabled_devs[i];
+		TEST_ASSERT_SUCCESS(rte_cryptodev_configure(dev_id,
+				&ts_params->conf),
+				"Failed to configure cryptodev %u with %u qps",
+				dev_id, ts_params->conf.nb_queue_pairs);
+
+		ts_params->qp_conf.nb_descriptors = 128;
+
+		TEST_ASSERT_SUCCESS(rte_cryptodev_queue_pair_setup(
+				dev_id, 0, &ts_params->qp_conf,
+				rte_cryptodev_socket_id(dev_id),
+				ts_params->session_mpool),
+				"Failed to setup queue pair %u on cryptodev %u",
+				0, dev_id);
+
+		/* Start the device */
+		TEST_ASSERT_SUCCESS(rte_cryptodev_start(dev_id),
+				"Failed to start cryptodev %u",
+				dev_id);
+		session_size = rte_cryptodev_sym_get_private_session_size(dev_id);
+
+		if (session_size > max_session_size)
+			max_session_size = session_size;
+	}
+
+	/*
+	 * Create mempool with session header and private session data
+	 */
+	ts_params->session_mpool = rte_mempool_create(
+				"Session pool",
+				2,
+				max_session_size,
+				0, 0, NULL, NULL, NULL,
+				NULL, SOCKET_ID_ANY,
+				0);
+
+	TEST_ASSERT_NOT_NULL(ts_params->session_mpool,
+			"session mempool allocation failed");
+
+	return TEST_SUCCESS;
+}
+
+static void
+testsuite_teardown(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	uint16_t i;
+
+	if (ts_params->mbuf_pool != NULL) {
+		rte_mempool_free(ts_params->mbuf_pool);
+		ts_params->mbuf_pool = NULL;
+	}
+
+	if (ts_params->op_mpool != NULL) {
+		rte_mempool_free(ts_params->op_mpool);
+		ts_params->op_mpool = NULL;
+	}
+
+	/* Free session mempools */
+	if (ts_params->session_mpool != NULL) {
+		rte_mempool_free(ts_params->session_mpool);
+		ts_params->session_mpool = NULL;
+	}
+
+	for (i = 0; i < ts_params->nb_enabled_devs; i++) {
+		rte_cryptodev_stop(ts_params->enabled_devs[i]);
+	}
+}
+
+static int
+test_aes_single_case(struct fips_aes_test_data *aes_data,
+	uint8_t *second_last_out,
+	uint16_t dev_id,
+	uint16_t vid,
+	uint32_t *num_test_vectors_run,
+	uint16_t *num_test_vectors_skipped)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	uint8_t *pt = NULL;
+	uint8_t *ct = NULL;
+	struct rte_cryptodev_sym_session *session = NULL;
+	struct rte_crypto_op *op = NULL;
+	struct rte_mbuf *mbuf = NULL;
+	int ret;
+	uint16_t i;
+	struct rte_crypto_sym_xform cipher_xform = {
+		.next = NULL,
+		.type = RTE_CRYPTO_SYM_XFORM_CIPHER,
+		.cipher = {
+			.algo = RTE_CRYPTO_CIPHER_AES_CBC,
+			.op = aes_data->test_cases[vid].test_op,
+			.key = {
+				.length = aes_data->key_len,
+				.data = aes_data->test_cases[vid].key
+			},
+			.iv = {
+				.offset = IV_OFFSET,
+				.length = AES_IV_LENGTH
+			}
+		}
+	};
+
+	struct rte_cryptodev_sym_capability_idx cap_idx;
+	const struct rte_cryptodev_symmetric_capability *capability;
+	cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+	cap_idx.algo.aead = RTE_CRYPTO_CIPHER_AES_CBC;
+	capability = rte_cryptodev_sym_capability_get(dev_id, &cap_idx);
+	if (capability == NULL) {
+		RTE_LOG(ERR, USER1, "Could not get capability\n");
+		return -1;
+	}
+	if (rte_cryptodev_sym_capability_check_cipher(capability,
+						cipher_xform.cipher.key.length,
+						cipher_xform.cipher.iv.length) != 0) {
+		RTE_LOG(DEBUG, USER1, "Operation not supported by device\n");
+		(*num_test_vectors_skipped)++;
+		aes_data->test_cases[vid].skip_flag = 1;
+		ret = 0;
+		goto exit;
+	}
+
+	/* Create crypto session */
+	session = rte_cryptodev_sym_session_create(ts_params->session_mpool);
+	if (session == NULL) {
+		RTE_LOG(ERR, USER1, "Session creation failed\n");
+		return -1;
+	}
+
+	ret = rte_cryptodev_sym_session_init(dev_id, session,
+				&cipher_xform, ts_params->session_mpool);
+	if (ret < 0) {
+		if (ret == -ENOTSUP) {
+			(*num_test_vectors_skipped)++;
+			aes_data->test_cases[vid].skip_flag = 1;
+			RTE_LOG(INFO, USER1, "Session not supported\n");
+			ret = 0;
+		} else {
+			RTE_LOG(ERR, USER1, "Session init failed\n");
+			ret = -1;
+		}
+		goto exit;
+	}
+
+	op = rte_crypto_op_alloc(ts_params->op_mpool,
+			RTE_CRYPTO_OP_TYPE_SYMMETRIC);
+	if (op == NULL) {
+		RTE_LOG(ERR, USER1, "Operation allocation failed\n");
+		ret = -1;
+		goto exit;
+	}
+
+	mbuf = rte_pktmbuf_alloc(ts_params->mbuf_pool);
+	if (mbuf == NULL) {
+		RTE_LOG(ERR, USER1, "Mbuf allocation failed\n");
+		ret = -1;
+		goto exit;
+	}
+
+	if (aes_data->test_cases[vid].test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+		pt = (uint8_t *)rte_pktmbuf_append(mbuf,
+				aes_data->test_cases[vid].plaintext_len);
+		if (pt == NULL) {
+			RTE_LOG(ERR, USER1, "Appending data failed\n");
+			ret = -1;
+			goto exit;
+		}
+		memcpy(pt, aes_data->test_cases[vid].plaintext,
+			aes_data->test_cases[vid].plaintext_len);
+	} else {
+		ct = (uint8_t *)rte_pktmbuf_append(mbuf,
+				aes_data->test_cases[vid].ciphertext_len);
+		if (ct == NULL) {
+			RTE_LOG(ERR, USER1, "Appending data failed\n");
+			ret = -1;
+			goto exit;
+		}
+		memcpy(ct, aes_data->test_cases[vid].ciphertext,
+			aes_data->test_cases[vid].ciphertext_len);
+	}
+
+	/* Set up crypto op */
+	uint8_t *iv = rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET);
+	memcpy(iv, aes_data->test_cases[vid].iv,
+			AES_IV_LENGTH);
+	op->sym->m_src = mbuf;
+	op->sym->cipher.data.offset = 0;
+	if (aes_data->test_cases[vid].test_op ==
+			RTE_CRYPTO_CIPHER_OP_ENCRYPT)
+		op->sym->cipher.data.length = aes_data->test_cases[vid].plaintext_len;
+	else
+		op->sym->cipher.data.length = aes_data->test_cases[vid].ciphertext_len;
+
+
+	/* Attach the crypto session to the operation */
+	rte_crypto_op_attach_sym_session(op, session);
+
+	uint16_t num_enqd = rte_cryptodev_enqueue_burst(dev_id, 0,
+			&op, 1);
+	if (num_enqd < 1) {
+		RTE_LOG(ERR, USER1, "Operation could not be enqueued\n");
+		ret = -1;
+		goto exit;
+	}
+
+	uint16_t num_deqd = 0;
+	do {
+		struct rte_crypto_op *deqd_op;
+		num_deqd = rte_cryptodev_dequeue_burst(dev_id, 0, &deqd_op, 1);
+
+		if (num_deqd == 0)
+			continue;
+
+		if (deqd_op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
+			RTE_LOG(ERR, USER1, "Operation status was not successful\n");
+			ret = -1;
+			goto exit;
+		}
+	} while (num_deqd == 0);
+
+	/*
+	 * If Monte Carlo test, process plaintext with following algo:
+	 * For j = 0 to 999
+	 *   If ( j=0 )
+	 *     CT[j] = AES(Key[i], IV[i], PT[j])
+	 *     PT[j+1] = IV[i]
+	 *   Else
+	 *      CT[j] = AES(Key[i], PT[j])
+	 *      PT[j+1] = CT[j-1]
+	 * Output CT[j]
+	 */
+	if (aes_data->test_type == AESAVS_TYPE_MCT) {
+		uint8_t prev_out[AES_BLOCK_LENGTH];
+		uint8_t new_out[AES_BLOCK_LENGTH];
+		uint8_t prev_in[AES_BLOCK_LENGTH];
+		uint8_t *iv;
+
+		memcpy(prev_in, aes_data->test_cases[vid].ciphertext,
+			aes_data->test_cases[vid].ciphertext_len);
+
+		if (aes_data->test_cases[vid].test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+			/* PT[1] = IV, save CT[0] */
+			pt = (uint8_t *)rte_pktmbuf_mtod(mbuf, uint8_t *);
+			memcpy(prev_out, pt, AES_BLOCK_LENGTH);
+			memcpy(pt, aes_data->test_cases[vid].iv,
+				AES_IV_LENGTH);
+			iv = rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET);
+			memcpy(iv, prev_out, AES_IV_LENGTH);
+		} else {
+			/* CT[1] = IV, save PT[0] */
+			ct = (uint8_t *)rte_pktmbuf_mtod(mbuf, uint8_t *);
+			memcpy(prev_out, ct, AES_BLOCK_LENGTH);
+			memcpy(ct, aes_data->test_cases[vid].iv,
+				AES_IV_LENGTH);
+			iv = rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET);
+			memcpy(iv, prev_in, AES_IV_LENGTH);
+
+		}
+
+		/* The other 999 iterations */
+		for (i = 1; i <= (AES_MCT_NUM_INTERNAL_ITER - 1); i++) {
+			memcpy(prev_in, rte_pktmbuf_mtod(mbuf, uint8_t *), AES_BLOCK_LENGTH);
+			uint16_t num_enqd = rte_cryptodev_enqueue_burst(dev_id, 0,
+					&op, 1);
+			if (num_enqd < 1) {
+				RTE_LOG(ERR, USER1, "Operation could not be enqueued\n");
+				ret = -1;
+				goto exit;
+			}
+
+			uint16_t num_deqd = 0;
+			do {
+				struct rte_crypto_op *deqd_op;
+				num_deqd = rte_cryptodev_dequeue_burst(dev_id, 0, &deqd_op, 1);
+
+				if (num_deqd == 0)
+					continue;
+
+				if (deqd_op->status != RTE_CRYPTO_OP_STATUS_SUCCESS) {
+					RTE_LOG(ERR, USER1, "Operation status was not successful\n");
+					ret = -1;
+					goto exit;
+				}
+			} while (num_deqd == 0);
+
+			if (i == (AES_MCT_NUM_INTERNAL_ITER - 1)) {
+				memcpy(second_last_out, prev_out, AES_BLOCK_LENGTH);
+				break;
+			}
+
+			if (aes_data->test_cases[vid].test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+				/* PT[j+1] = CT[j-1] (CT[j-1] stored in prev_out, store CT[j]) */
+				pt = (uint8_t *)rte_pktmbuf_mtod(mbuf, uint8_t *);
+				memcpy(new_out, pt, AES_BLOCK_LENGTH);
+				memcpy(pt, prev_out, AES_IV_LENGTH);
+				memcpy(prev_out, new_out, AES_IV_LENGTH);
+				iv = rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET);
+				memcpy(iv, prev_out, AES_IV_LENGTH);
+			} else {
+				/* CT[j+1] = PT[j-1] (PT[j-1] stored in prev_out, store PT[j]) */
+				ct = (uint8_t *)rte_pktmbuf_mtod(mbuf, uint8_t *);
+				memcpy(new_out, ct, AES_BLOCK_LENGTH);
+				memcpy(ct, prev_out, AES_IV_LENGTH);
+				memcpy(prev_out, new_out, AES_IV_LENGTH);
+				iv = rte_crypto_op_ctod_offset(op, uint8_t *, IV_OFFSET);
+				memcpy(iv, prev_in, AES_IV_LENGTH);
+			}
+		}
+	}
+
+	/* Output result */
+	if (aes_data->test_cases[vid].test_op ==
+			RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+		ct = rte_pktmbuf_mtod(op->sym->m_src, uint8_t *);
+		aes_data->test_cases[vid].ciphertext_len =
+			aes_data->test_cases[vid].plaintext_len;
+		memcpy(aes_data->test_cases[vid].ciphertext, ct,
+				aes_data->test_cases[vid].ciphertext_len);
+	} else {
+		pt = rte_pktmbuf_mtod(op->sym->m_src, uint8_t *);
+		aes_data->test_cases[vid].plaintext_len =
+			aes_data->test_cases[vid].ciphertext_len;
+		memcpy(aes_data->test_cases[vid].plaintext, ct,
+				aes_data->test_cases[vid].plaintext_len);
+	}
+
+	ret = 0;
+	(*num_test_vectors_run)++;
+exit:
+	/* Clean up */
+	if (op != NULL) {
+		rte_pktmbuf_free(op->sym->m_src);
+		rte_crypto_op_free(op);
+	}
+
+	if (session != NULL) {
+		ret = rte_cryptodev_sym_session_clear(dev_id, session);
+		TEST_ASSERT(ret == 0, "Session clear failed");
+		ret = rte_cryptodev_sym_session_free(session);
+		TEST_ASSERT(ret == 0, "Session free failed");
+	}
+
+	return ret;
+}
+
+
+
+#define MAX_NUM_FILES 32
+#define MAX_FILE_PATH 128
+static int
+test_fips_aes(void)
+{
+	struct crypto_testsuite_params *ts_params = &testsuite_params;
+	struct fips_aes_test_data *aes_data = NULL;
+	struct fips_aes_test_data *aes_mct_data = NULL;
+	uint16_t mct_vec_id = 0;
+	uint16_t num_test_vectors_skipped = 0;
+	uint32_t num_test_vectors_run = 0;
+	uint32_t num_total_run = 0;
+	uint32_t num_total_skipped = 0;
+	unsigned int num_files = 0;
+	uint16_t i, j, k, m;
+	char file_paths[MAX_NUM_FILES][MAX_FILE_PATH];
+	char file_names[MAX_NUM_FILES][MAX_FILE_PATH];
+	uint8_t dev_id;
+	int ret;
+
+	/* Find the first device which supports AES-CBC */
+	for (i = 0; i < ts_params->nb_enabled_devs; i++) {
+		struct rte_cryptodev_sym_capability_idx cap_idx;
+		dev_id = ts_params->enabled_devs[i];
+		cap_idx.type = RTE_CRYPTO_SYM_XFORM_CIPHER;
+		cap_idx.algo.cipher = RTE_CRYPTO_CIPHER_AES_CBC;
+		if (rte_cryptodev_sym_capability_get(dev_id, &cap_idx) != NULL) {
+			break;
+		}
+	}
+
+	if (i == ts_params->nb_enabled_devs) {
+		RTE_LOG(WARNING, USER1, "Skipping AES-CBC tests\n");
+		return -ENOTSUP;
+	}
+
+	DIR *d;
+	struct dirent *dir;
+	d = opendir("./AES/req/");
+	if (d) {
+		while ((dir = readdir(d)) != NULL) {
+			if (strstr(dir->d_name, "req") != NULL) {
+				snprintf(file_paths[num_files], MAX_FILE_PATH,
+					"%s%s", "./AES/req/", dir->d_name);
+				strlcpy(file_names[num_files], dir->d_name,
+						strlen(dir->d_name) - 3);
+				num_files++;
+			}
+		}
+		closedir(d);
+	}
+
+	if (num_files == 0) {
+		RTE_LOG(INFO, USER1, "No AES test vector files available\n");
+		return TEST_SKIPPED;
+	}
+
+	aes_data = rte_malloc(NULL, sizeof(struct fips_aes_test_data), 0);
+	TEST_ASSERT_NOT_NULL(aes_data, "memory could not be allocated\n");
+	aes_mct_data = rte_malloc(NULL, sizeof(struct fips_aes_test_data), 0);
+	TEST_ASSERT_NOT_NULL(aes_mct_data, "memory could not be allocated\n");
+
+	for (i = 0; i < num_files; i++) {
+		printf("Testing vectors from file %s\n", file_paths[i]);
+		/* Vector parsing function */
+		parse_aes_vectors(aes_data, file_paths[i]);
+		/*
+		 * Output data will contain more test vectors than the input data,
+		 * so first thing to be done is to create the structure big enough
+		 * to hold all the vectors.
+		 */
+		if (aes_data->test_type == AESAVS_TYPE_MCT) {
+			uint8_t second_last_out[AES_BLOCK_LENGTH];
+
+			memcpy(aes_mct_data, aes_data,
+				sizeof(struct fips_aes_test_data));
+			memset(aes_mct_data->test_cases, 0,
+				sizeof(struct fips_aes_test_case) * MAX_NB_TESTS);
+			/* Each test case has 100 iterations */
+			aes_mct_data->nb_test_cases *= AES_MCT_NUM_EXTERNAL_ITER;
+
+			mct_vec_id = 0;
+			for (j = 0; j < aes_data->nb_test_cases; j++) {
+				/* Copy initial vector */
+				memcpy(&aes_mct_data->test_cases[mct_vec_id],
+					&aes_data->test_cases[j],
+					sizeof(struct fips_aes_test_case));
+
+				for (k = 0; k < AES_MCT_NUM_EXTERNAL_ITER; k++) {
+					aes_mct_data->test_cases[mct_vec_id].count = (aes_data->test_cases[j].count * AES_MCT_NUM_EXTERNAL_ITER) + k;
+					int ret = test_aes_single_case(aes_mct_data,
+							second_last_out,
+							dev_id, mct_vec_id,
+							&num_test_vectors_run,
+							&num_test_vectors_skipped);
+					if (ret < 0) {
+						ret = TEST_FAILED;
+						goto exit;
+					}
+					mct_vec_id++;
+					if (k != AES_MCT_NUM_EXTERNAL_ITER) {
+						/* Prepare next vector */
+						aes_mct_data->test_cases[mct_vec_id].test_op = aes_data->test_cases[j].test_op;
+						aes_mct_data->test_cases[mct_vec_id].iv_len = aes_data->test_cases[j].iv_len;
+						aes_mct_data->test_cases[mct_vec_id].count = mct_vec_id;
+						if (aes_data->test_cases[j].test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+							aes_mct_data->test_cases[mct_vec_id].plaintext_len = aes_data->test_cases[j].plaintext_len;
+							if (aes_data->key_len == 16) {
+								for (m = 0; m < aes_data->key_len; m++) {
+									/* Key[i+1] = Key[i] xor CT[j] */
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].ciphertext[m];
+								}
+							} else if (aes_data->key_len == 24) {
+								/* Key[i+1] = Key[i] xor (last 64-bits of CT[j-1] || CT[j]) */
+								for (m = 0; m < 8; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										second_last_out[m + 8];
+								for (m = 8; m < aes_data->key_len; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].ciphertext[m - 8];
+							} else {
+								/* Key[i+1] = Key[i] xor (CT[j-1] || CT[j]) */
+								for (m = 0; m < 16; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										second_last_out[m];
+								for (m = 16; m < aes_data->key_len; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].ciphertext[m - 16];
+							}
+
+							/* IV[i+1] = CT[j] */
+							memcpy(aes_mct_data->test_cases[mct_vec_id].iv,
+									aes_mct_data->test_cases[mct_vec_id - 1].ciphertext,
+									AES_IV_LENGTH);
+							/* PT[0] = CT[j-1] */
+							memcpy(aes_mct_data->test_cases[mct_vec_id].plaintext,
+									second_last_out, AES_BLOCK_LENGTH);
+						} else {
+							aes_mct_data->test_cases[mct_vec_id].ciphertext_len = aes_data->test_cases[j].ciphertext_len;
+							if (aes_data->key_len == 16) {
+								for (m = 0; m < aes_data->key_len; m++) {
+									/* Key[i+1] = Key[i] xor PT[j] */
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].plaintext[m];
+								}
+							} else if (aes_data->key_len == 24) {
+								/* Key[i+1] = Key[i] xor (last 64-bits of PT[j-1] || PT[j]) */
+								for (m = 0; m < 8; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										second_last_out[m + 8];
+								for (m = 8; m < aes_data->key_len; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].plaintext[m - 8];
+							} else {
+								/* Key[i+1] = Key[i] xor (PT[j-1] || PT[j]) */
+								for (m = 0; m < 16; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										second_last_out[m];
+								for (m = 16; m < aes_data->key_len; m++)
+									aes_mct_data->test_cases[mct_vec_id].key[m] =
+										aes_mct_data->test_cases[mct_vec_id - 1].key[m] ^
+										aes_mct_data->test_cases[mct_vec_id - 1].plaintext[m - 16];
+							}
+							/* IV[i+1] = PT[j] */
+							memcpy(aes_mct_data->test_cases[mct_vec_id].iv,
+									aes_mct_data->test_cases[mct_vec_id - 1].plaintext,
+									AES_IV_LENGTH);
+							/* CT[0] = PT[j-1] */
+							memcpy(aes_mct_data->test_cases[mct_vec_id].ciphertext,
+									second_last_out, AES_BLOCK_LENGTH);
+						}
+
+					}
+				}
+			}
+
+		} else {
+			for (j = 0; j < aes_data->nb_test_cases; j++) {
+				int ret = test_aes_single_case(aes_data, NULL,
+						dev_id, j,
+						&num_test_vectors_run,
+						&num_test_vectors_skipped);
+				if (ret < 0) {
+					ret = TEST_FAILED;
+					goto exit;
+				}
+			}
+		}
+
+		printf("Test vectors run: %u\n", num_test_vectors_run);
+		printf("Test vectors skipped: %u\n", num_test_vectors_skipped);
+		num_total_skipped += num_test_vectors_skipped;
+		num_total_run += num_test_vectors_run;
+		num_test_vectors_skipped = 0;
+
+		char output_path[MAX_FILE_PATH];
+		char device_name[128];
+		struct rte_cryptodev_info info;
+		rte_cryptodev_info_get(dev_id, &info);
+		mkdir("./AES/resp/", 0700);
+		snprintf(output_path, MAX_FILE_PATH, "%s%s%s", "./AES/resp/",
+					file_names[i], ".rsp");
+		snprintf(device_name, 128, "%s%s%s", "DPDK Cryptodev ",
+				info.driver_name, " PMD");
+		if (aes_data->test_type == AESAVS_TYPE_MCT) {
+			write_aes_vectors(aes_mct_data, output_path, device_name);
+			memset(aes_mct_data, 0, sizeof(struct fips_aes_test_data));
+		} else {
+			write_aes_vectors(aes_data, output_path, device_name);
+		}
+		memset(aes_data, 0, sizeof(struct fips_aes_test_data));
+	}
+
+	printf("================================\n");
+	printf("Total test vectors run: %u\n", num_total_run);
+	printf("Total test vectors skipped: %u\n", num_total_skipped);
+	printf("================================\n");
+
+	ret = TEST_SUCCESS;
+exit:
+	rte_free(aes_data);
+	rte_free(aes_mct_data);
+
+	return ret;
+}
+
+static struct unit_test_suite cryptodev_fips_testsuite  = {
+	.suite_name = "Crypto FIPS Test Suite",
+	.setup = fips_testsuite_setup,
+	.teardown = testsuite_teardown,
+	.unit_test_cases = {
+		TEST_CASE_ST(NULL, NULL,
+			test_fips_aes),
+		TEST_CASES_END() /**< NULL terminate unit test array */
+	}
+};
+
+static int
+test_cryptodev_fips(void)
+{
+	return unit_test_suite_runner(&cryptodev_fips_testsuite);
+}
+
+REGISTER_TEST_COMMAND(cryptodev_fips, test_cryptodev_fips);
+
-- 
2.9.5

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [dpdk-dev] [PATCH v1 2/2] test/test: cryptodev application parser for FIPS certification
  2018-09-07 17:13 [dpdk-dev] [PATCH v1 0/2] FIPS validation capability Marko Kovacevic
  2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 1/2] test/test: cryptodev application for FIPS certification Marko Kovacevic
@ 2018-09-07 17:13 ` Marko Kovacevic
  1 sibling, 0 replies; 3+ messages in thread
From: Marko Kovacevic @ 2018-09-07 17:13 UTC (permalink / raw)
  To: dev; +Cc: akhil.goyal, roy.fan.zhang, Marko Kovacevic

Added parser to parser required request file which has
different algos required by the fips certification
and to generate the response file needed.

Signed-off-by: Marko Kovacevic <marko.kovacevic@intel.com>
---
 test/test/Makefile                           |   3 +
 test/test/test_cryptodev_fips_parse.h        | 156 +++++++++++
 test/test/test_cryptodev_fips_parse_aes.c    | 399 +++++++++++++++++++++++++++
 test/test/test_cryptodev_fips_parse_common.c | 330 ++++++++++++++++++++++
 4 files changed, 888 insertions(+)
 create mode 100644 test/test/test_cryptodev_fips_parse.h
 create mode 100644 test/test/test_cryptodev_fips_parse_aes.c
 create mode 100644 test/test/test_cryptodev_fips_parse_common.c

diff --git a/test/test/Makefile b/test/test/Makefile
index ee74450..9d6abb5 100644
--- a/test/test/Makefile
+++ b/test/test/Makefile
@@ -183,6 +183,9 @@ SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_blockcipher.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_asym.c
 SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_fips.c
+SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_fips_parse_common.c
+SRCS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += test_cryptodev_fips_parse_aes.c
+
 
 ifeq ($(CONFIG_RTE_COMPRESSDEV_TEST),y)
 SRCS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += test_compressdev.c
diff --git a/test/test/test_cryptodev_fips_parse.h b/test/test/test_cryptodev_fips_parse.h
new file mode 100644
index 0000000..edb1d41
--- /dev/null
+++ b/test/test/test_cryptodev_fips_parse.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+#ifndef _TEST_CRYPTODEV_FIPS_PARSE_
+#define _TEST_CRYPTODEV_FIPS_PARSE_
+
+#include <rte_cryptodev.h>
+
+#define FIPS_PARSE_ERR(line, fmt, args...)				\
+	RTE_LOG(ERR, USER1, "[%s] %s() line %u: Error in file line %u "	\
+		fmt "\n", "FIPS", __func__, __LINE__, line, ## args)
+
+#define ERR_MSG_SIZE	128
+#define MAX_CASE_LINE	15
+#define MAX_NB_CHAR	1024 /*< maximum number of characters per line */
+#define MAX_NB_TESTS	10240
+#define MAX_BUF_SIZE	2048 /*< maximum plain/cipher text size */
+#define MAX_KEY_LEN	64
+#define MAX_IV_LEN	256
+
+#define POSITIVE_TEST	0
+#define NEGATIVE_TEST	-1
+
+#define REQ_FILE_PERFIX	"req"
+#define RSP_FILE_PERFIX	"rsp"
+#define FAX_FILE_PERFIX	"fax"
+
+#define HEADER_IND	"#"
+#define GEN_TIME_STR	"# Generated on "
+
+enum file_types {
+	FIPS_FILE_TYPE_REQ = 1,
+	FIPS_FILE_TYPE_FAX,
+	FIPS_FILE_TYPE_RSP
+};
+
+struct fips_aes_test_case {
+	char case_desc[MAX_CASE_LINE][MAX_NB_CHAR];
+#define AESAVS_OP_ENC		1
+#define AESAVS_OP_DEC		2
+	enum rte_crypto_cipher_operation test_op;
+	uint8_t key[MAX_KEY_LEN];
+	uint8_t iv[MAX_IV_LEN];
+	uint32_t iv_len;
+	uint8_t plaintext[MAX_BUF_SIZE];
+	uint32_t plaintext_len;
+	uint8_t ciphertext[MAX_BUF_SIZE];
+	uint32_t ciphertext_len;
+	uint32_t count;
+	uint32_t skip_flag;
+};
+
+/* AES TEST DATA */
+struct fips_aes_test_data {
+	enum file_types f_type;
+	char file_header[MAX_CASE_LINE][MAX_NB_CHAR];
+
+/* follow the sequence as test_type_strings declared above */
+#define AESAVS_TYPE_GFXBOX	0
+#define AESAVS_TYPE_KEYSBOX	1
+#define AESAVS_TYPE_VARKEY	2
+#define AESAVS_TYPE_VARTXT	3
+#define AESAVS_TYPE_MMT		4
+#define AESAVS_TYPE_MCT		5
+	uint32_t test_type;
+
+	/* *_algo == 0 means no algo */
+	enum rte_crypto_cipher_algorithm cipher_algo;
+	enum rte_crypto_auth_algorithm auth_algo;
+
+	uint32_t key_len;
+
+	uint32_t nb_test_cases;
+
+	struct fips_aes_test_case test_cases[MAX_NB_TESTS];
+};
+
+/**
+ * INTERNAL APIS, used for other parsers
+ */
+int
+fips_get_file_line(FILE **fp, char *line,  uint32_t max_line_char);
+
+int
+parser_read_uint64(uint64_t *value, const char *p);
+
+int
+parser_read_uint64_hex(uint64_t *value, const char *p);
+
+int
+parser_read_uint32(uint32_t *value, const char *p);
+
+int
+parser_read_uint32_hex(uint32_t *value, const char *p);
+
+int
+parser_read_uint16(uint16_t *value, const char *p);
+
+int
+parser_read_uint16_hex(uint16_t *value, const char *p);
+
+int
+parser_read_uint8(uint8_t *value, const char *p);
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p);
+
+int
+parse_uint8_hex_str(uint8_t *dst, char *src, uint32_t max_len);
+
+enum file_types
+parse_file_type(const char *path);
+
+int
+fetch_block(FILE **fp, char *line[MAX_CASE_LINE], uint32_t from_line,
+		const char *trigger, uint32_t max_nb_line_char);
+
+void
+copy_block(char dst[][MAX_NB_CHAR], char *src[MAX_CASE_LINE],
+		uint32_t nb_lines, uint32_t max_nb_line_char);
+
+void
+write_block_to_file(FILE *fp, char from[][MAX_NB_CHAR]);
+
+void
+write_uint8_str_to_file(FILE *fp, const uint8_t *from, uint32_t size);
+
+int
+alloc_line_block_mem(char *block[MAX_CASE_LINE], uint32_t max_nb_line_char);
+
+void
+free_line_block_mem(char *block[MAX_CASE_LINE]);
+
+static inline void
+MEMSET_BLOCK(char *line[], uint32_t line_len)
+{
+	uint32_t i;
+
+	for (i = 0; i < MAX_CASE_LINE; i++)
+		memset(line[i], 0, line_len);
+}
+
+
+/**
+ * API to parse one AES FIPS test vector file into struct FIPS_aes_test_data
+ * No init is necessary, this function will memset it for you
+ * No fopen/fclose necessary
+ */
+int
+parse_aes_vectors(struct fips_aes_test_data *aes_test_data, const char *path);
+
+int
+write_aes_vectors(struct fips_aes_test_data *test_data,
+		const char *path_write, const char *device_name);
+
+#endif
diff --git a/test/test/test_cryptodev_fips_parse_aes.c b/test/test/test_cryptodev_fips_parse_aes.c
new file mode 100644
index 0000000..552a493
--- /dev/null
+++ b/test/test/test_cryptodev_fips_parse_aes.c
@@ -0,0 +1,399 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#include <string.h>
+#include <time.h>
+
+#include "test_cryptodev_fips_parse.h"
+
+#define MODE_STR	"AESVS"
+#define ALGO_STR	"test data for "
+#define OP_STR		"State"
+#define KEY_SIZE_STR	"Key Length : "
+#define DEVICE_STR	"# Config info for "
+
+#define COUNT_STR	"COUNT = "
+#define KEY_STR		"KEY = "
+#define IV_STR		"IV = "
+#define PT_STR		"PLAINTEXT = "
+#define CT_STR		"CIPHERTEXT = "
+
+#define OP_ENC_STR	"ENCRYPT"
+#define OP_DEC_STR	"DECRYPT"
+
+#define SKIP_OUTPUT	"FAIL(Not supported)"
+
+const char *aes_test_type_strings[] = {
+		"GFSbox",
+		"KeySbox",
+		"VarKey",
+		"VarTxt",
+		"MMT",
+		"MCT"
+};
+
+struct aes_test_algo_conv {
+	const char *name;
+	enum rte_crypto_cipher_algorithm algo;
+} const algo_convs[] = {
+		{"CBC", RTE_CRYPTO_CIPHER_AES_CBC},
+};
+
+static int
+parse_one_case(struct fips_aes_test_data *test_data, char *lines[],
+		uint32_t nb_lines, enum rte_crypto_cipher_operation op,
+		uint32_t from_line)
+{
+	struct fips_aes_test_case *test_case;
+	uint32_t i;
+	char *tmp;
+	int ret;
+
+	if (test_data->nb_test_cases >= MAX_NB_TESTS)
+		return -ENOMEM;
+
+	test_case = &test_data->test_cases[test_data->nb_test_cases];
+	test_case->test_op = op;
+
+	for (i = 0; i < nb_lines; i++) {
+		char *line = lines[i];
+
+		tmp = strstr(line, COUNT_STR);
+		if (tmp) {
+			uint32_t count;
+
+			tmp += strlen(COUNT_STR);
+			if (parser_read_uint32(&count, tmp) < 0) {
+				ret = -EINVAL;
+				goto error_exit;
+			}
+
+			test_case->count = count;
+			continue;
+		}
+
+		/* key */
+		tmp = strstr(line, KEY_STR);
+		if (tmp) {
+			tmp += strlen(KEY_STR);
+			ret = parse_uint8_hex_str(test_case->key, tmp, MAX_KEY_LEN);
+			if (ret < 0)
+				goto error_exit;
+			continue;
+		}
+
+		/* iv */
+		tmp = strstr(line, IV_STR);
+		if (tmp) {
+			tmp += strlen(IV_STR);
+
+			ret = parse_uint8_hex_str(test_case->iv, tmp, MAX_IV_LEN);
+			if (ret < 0)
+				goto error_exit;
+
+			test_case->iv_len = ret;
+			continue;
+		}
+
+		/* plaintext */
+		tmp = strstr(line, PT_STR);
+		if (tmp) {
+			tmp += strlen(PT_STR);
+
+			ret = parse_uint8_hex_str(test_case->plaintext, tmp,
+					MAX_BUF_SIZE);
+			if (ret < 0)
+				goto error_exit;
+
+			test_case->plaintext_len = ret;
+			continue;
+		}
+
+		/* ciphertext */
+		tmp = strstr(line, CT_STR);
+		if (tmp) {
+			tmp += strlen(CT_STR);
+
+			ret = parse_uint8_hex_str(test_case->ciphertext, tmp,
+					MAX_BUF_SIZE);
+			if (ret < 0)
+				goto error_exit;
+
+			test_case->ciphertext_len = ret;
+			continue;
+		}
+	}
+
+	copy_block(test_case->case_desc, lines, nb_lines, MAX_NB_CHAR);
+	test_data->nb_test_cases++;
+	return 0;
+
+error_exit:
+	FIPS_PARSE_ERR(from_line + i, "Error code %i", ret);
+	memset(test_case, 0, sizeof(*test_case));
+	return ret;
+}
+
+static int
+parse_header(struct fips_aes_test_data *test_data, char *lines[],
+		uint32_t nb_lines)
+{
+	char *tmp;
+	uint32_t i, j;
+
+	for (i = 0; i < nb_lines; i++) {
+		char *line = lines[i];
+
+		tmp = strstr(line, MODE_STR);
+		if (tmp) {
+			for (j = 0; j < RTE_DIM(aes_test_type_strings); j++)
+				if (strstr(line, aes_test_type_strings[j])
+						!= NULL) {
+					test_data->test_type = j;
+					break;
+				}
+			if (j >= RTE_DIM(aes_test_type_strings))
+				return -EINVAL;
+
+			tmp = strstr(line, ALGO_STR);
+			if (!tmp)
+				return -EINVAL;
+
+			tmp += strlen(ALGO_STR);
+			for (j = 0; j < RTE_DIM(algo_convs); j++)
+				if (strcmp(algo_convs[j].name, tmp) == 0) {
+					test_data->cipher_algo =
+							algo_convs[j].algo;
+					break;
+				}
+			if (j >= RTE_DIM(algo_convs))
+				return -EINVAL;
+
+			continue;
+		}
+
+		/* State : <op> {and <op>} Encrypt and Decrypt, we don't care*/
+		tmp = strstr(line, OP_STR);
+		if (tmp)
+			continue;
+
+		/* Key Length : 128 */
+		tmp = strstr(line, KEY_SIZE_STR);
+		if (tmp) {
+			tmp += strlen(KEY_SIZE_STR);
+			if (parser_read_uint32(&test_data->key_len, tmp) < 0)
+				return -EINVAL;
+
+			test_data->key_len /= 8;
+			if (test_data->key_len > MAX_KEY_LEN)
+				return -EINVAL;
+
+			continue;
+		}
+	}
+
+	return 0;
+}
+
+int
+parse_aes_vectors(struct fips_aes_test_data *test_data, const char *path)
+{
+	FILE *fp;
+	char *line[MAX_CASE_LINE];
+	uint32_t line_idx = 0;
+	enum rte_crypto_cipher_operation op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
+	int ret = 0, file_ret = 0;
+	char *tmp;
+
+	fp = fopen(path, "r");
+	if (fp == NULL) {
+		FIPS_PARSE_ERR(0, "Cannot open file %s", path);
+		return -EINVAL;
+	}
+
+	if ((ret = alloc_line_block_mem(line, MAX_NB_CHAR)) < 0)
+		goto error_exit;
+
+	memset(test_data, 0, sizeof(*test_data));
+
+	test_data->f_type = parse_file_type(path);
+	if (test_data->f_type == 0) {
+		FIPS_PARSE_ERR(0, "Cannot get file type %s", path);
+		goto error_exit;
+	}
+
+	while (file_ret != -EOF) {
+		line_idx++;
+
+		file_ret = fips_get_file_line(&fp, line[0], MAX_NB_CHAR);
+		if (file_ret < 0) {
+			FIPS_PARSE_ERR(line_idx, "Error code %i", ret);
+			ret = file_ret;
+			goto error_exit;
+		}
+
+		ret = fetch_block(&fp, line, line_idx, HEADER_IND, MAX_NB_CHAR);
+		if (ret <= 0) {
+			ret = -EINVAL;
+			goto error_exit;
+		}
+
+		copy_block(test_data->file_header, line, ret, MAX_NB_CHAR);
+
+		ret = parse_header(test_data, line, ret);
+		if (ret < 0)
+			goto error_exit;
+		break;
+	}
+
+	MEMSET_BLOCK(line, MAX_NB_CHAR);
+
+	while (file_ret != -EOF) {
+		line_idx++;
+
+		file_ret = fips_get_file_line(&fp, line[0], MAX_NB_CHAR);
+		if (file_ret < 0) {
+			FIPS_PARSE_ERR(line_idx, "Error code %i", ret);
+			ret = file_ret;
+			goto error_exit;
+		}
+
+		if (strlen(line[0]) == 0)
+			continue;
+
+		tmp = strstr(line[0], OP_ENC_STR);
+		if (tmp) {
+			op = RTE_CRYPTO_CIPHER_OP_ENCRYPT;
+			continue;
+		}
+
+		tmp = strstr(line[0], OP_DEC_STR);
+		if (tmp) {
+			op = RTE_CRYPTO_CIPHER_OP_DECRYPT;
+			continue;
+		}
+
+		ret = fetch_block(&fp, line, line_idx, COUNT_STR, MAX_NB_CHAR);
+		if (ret > 0) {
+			uint32_t start_line = line_idx;
+
+			line_idx += ret;
+			ret = parse_one_case(test_data, line, ret, op,
+					start_line);
+
+			MEMSET_BLOCK(line, MAX_NB_CHAR);
+		}
+		if (ret < 0)
+			goto error_exit;
+
+	}
+
+	free_line_block_mem(line);
+	if (fp)
+		fclose(fp);
+
+	return 0;
+error_exit:
+	free_line_block_mem(line);
+	if (fp)
+		fclose(fp);
+	return ret;
+}
+
+int
+write_aes_vectors(struct fips_aes_test_data *test_data,
+		const char *path_write, const char *device_name)
+{
+	FILE *fp;
+	uint32_t i;
+	enum rte_crypto_cipher_operation op = 0xf;
+	time_t t = time(NULL);
+	struct tm *tm_now = localtime(&t);
+
+	if (test_data->f_type != FIPS_FILE_TYPE_REQ) {
+		FIPS_PARSE_ERR(0, "Write only works for REQ test vectors");
+		return 0;
+	}
+
+	fp = fopen(path_write, "w");
+	if (fp == NULL) {
+		FIPS_PARSE_ERR(0, "Cannot open file %s", path_write);
+		return -EINVAL;
+	}
+
+	/* write back header */
+	for (i = 0; i < MAX_CASE_LINE; i++) {
+		char *line = test_data->file_header[i];
+
+		if (strlen(line) == 0)
+			break;
+
+		if (strstr(line, DEVICE_STR)) {
+			fprintf(fp, "%s%s\n", DEVICE_STR, device_name);
+			continue;
+		}
+
+		if (strstr(line, GEN_TIME_STR)) {
+			fprintf(fp, "%s%s\n", GEN_TIME_STR, asctime(tm_now));
+			continue;
+		}
+
+		fprintf(fp, "%s\n", line);
+	}
+
+	/* write back test case */
+	for (i = 0; i < test_data->nb_test_cases; i++) {
+		struct fips_aes_test_case *tc = &test_data->test_cases[i];
+
+		if (op != tc->test_op) {
+			fprintf(fp, "%s\n\n", tc->test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT ?
+					"[ENCRYPT]" : "[DECRYPT]");
+			op = tc->test_op;
+		}
+
+		if (tc->skip_flag)
+				continue;
+
+		if (test_data->test_type == AESAVS_TYPE_MCT) {
+			fprintf(fp, "%s%u\n", COUNT_STR, tc->count);
+			fprintf(fp, "%s", KEY_STR);
+			write_uint8_str_to_file(fp, tc->key, test_data->key_len);
+			fprintf(fp, "%s", IV_STR);
+			write_uint8_str_to_file(fp, tc->iv, tc->iv_len);
+			if (tc->test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+				fprintf(fp, "%s", PT_STR);
+				write_uint8_str_to_file(fp, tc->plaintext,
+						tc->plaintext_len);
+				fprintf(fp, "%s", CT_STR);
+				write_uint8_str_to_file(fp, tc->ciphertext,
+						tc->ciphertext_len);
+			} else {
+				fprintf(fp, "%s", CT_STR);
+				write_uint8_str_to_file(fp, tc->ciphertext,
+						tc->ciphertext_len);
+				fprintf(fp, "%s", PT_STR);
+				write_uint8_str_to_file(fp, tc->plaintext,
+						tc->plaintext_len);
+			}
+		} else {
+			write_block_to_file(fp, tc->case_desc);
+
+			if (tc->test_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) {
+				fprintf(fp, "%s", CT_STR);
+				write_uint8_str_to_file(fp, tc->ciphertext,
+						tc->ciphertext_len);
+			} else {
+				fprintf(fp, "%s", PT_STR);
+				write_uint8_str_to_file(fp, tc->plaintext,
+						tc->plaintext_len);
+			}
+		}
+
+		fprintf(fp, "\n");
+	}
+
+	fclose(fp);
+
+	return 0;
+}
diff --git a/test/test/test_cryptodev_fips_parse_common.c b/test/test/test_cryptodev_fips_parse_common.c
new file mode 100644
index 0000000..1caa755
--- /dev/null
+++ b/test/test/test_cryptodev_fips_parse_common.c
@@ -0,0 +1,330 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+#include <string.h>
+#include <stdio.h>
+
+#include <rte_cryptodev.h>
+
+#include "test_cryptodev_fips_parse.h"
+
+/*
+ * copy a line in the file to the buffer
+ * if EOF, return -EOF
+ * otherwise return 0
+ */
+int
+fips_get_file_line(FILE **fp, char *line, uint32_t max_line_char)
+{
+	char c;
+	uint32_t loc = 0;
+
+	memset(line, 0, max_line_char);
+
+	while ((c = fgetc(*fp)) != EOF) {
+		if (loc >= max_line_char - 1)
+			return -ENOMEM;
+
+		if (c == '\n')
+			return 0;
+
+		line[loc++] = c;
+	}
+
+	return -EOF;
+}
+
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
+
+int
+parser_read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint64_hex(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+
+	val = strtoul(p, &next, 16);
+	if (p == next)
+		return -EINVAL;
+
+	p = skip_white_spaces(next);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint32_hex(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint16_hex(uint16_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT16_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parser_read_uint8_hex(uint8_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = parser_read_uint64_hex(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT8_MAX)
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+int
+parse_uint8_hex_str(uint8_t *dst, char *src, uint32_t max_len)
+{
+	uint32_t len, j;
+
+	len = strlen(src) / 2;
+	if (len > max_len)
+		return -ENOMEM;
+
+	for (j = 0; j < len; j++) {
+		char byte[3] = {src[j * 2], src[j * 2 + 1], '\0'};
+
+		if (parser_read_uint8_hex(&dst[j], byte) < 0)
+			return -EINVAL;
+	}
+
+	return len;
+}
+
+enum file_types
+parse_file_type(const char *path)
+{
+	const char *tmp = path + strlen(path) - 3;
+
+	if (strstr(tmp, REQ_FILE_PERFIX))
+		return FIPS_FILE_TYPE_REQ;
+	else if (strstr(tmp, RSP_FILE_PERFIX))
+		return FIPS_FILE_TYPE_RSP;
+	else if (strstr(path, FAX_FILE_PERFIX))
+		return FIPS_FILE_TYPE_FAX;
+
+	return 0;
+}
+
+/* copy block text from file, stop on line with size of 0 or EOF, max
+ * MAX_CASE_LINE lines */
+int
+fetch_block(FILE **fp, char *line[MAX_CASE_LINE], uint32_t from_line,
+		const char *trigger, uint32_t max_nb_line_char)
+{
+	uint32_t i = 1;
+	int ret = 0;
+
+	if (strstr(line[0], trigger) == NULL)
+		return 0;
+
+	while (i < MAX_CASE_LINE && ret != -EOF) {
+		ret = fips_get_file_line(fp, line[i], max_nb_line_char);
+		if (ret < 0) {
+			FIPS_PARSE_ERR(from_line + i, "Error code %i", ret);
+			return ret;
+		}
+
+		if (ret == -EOF || strlen(line[i]) == 0)
+			break;
+
+		i++;
+	}
+
+	return i;
+}
+
+void
+copy_block(char dst[][MAX_NB_CHAR], char *src[MAX_CASE_LINE],
+		uint32_t nb_lines, uint32_t max_nb_line_char)
+{
+	uint32_t i;
+
+	for (i = 0; i < nb_lines; i++)
+		memcpy(dst[i], src[i], max_nb_line_char - 1);
+}
+
+void
+write_block_to_file(FILE *fp, char from[][MAX_NB_CHAR])
+{
+	uint32_t i;
+
+	for (i = 0; i < MAX_CASE_LINE; i++) {
+		if (from[i] == NULL)
+			break;
+		if (strlen(from[i]) == 0)
+			break;
+		fprintf(fp, "%s\n", from[i]);
+	}
+}
+
+void
+write_uint8_str_to_file(FILE *fp, const uint8_t *from, uint32_t size)
+{
+	uint32_t i;
+
+	for (i = 0; i < size; i++)
+		fprintf(fp, "%02x", from[i]);
+
+	fprintf(fp, "\n");
+}
+
+int
+alloc_line_block_mem(char *block[MAX_CASE_LINE], uint32_t max_nb_line_char)
+{
+	uint32_t i;
+
+	for (i = 0; i < MAX_CASE_LINE; i++)
+		block[i] = NULL;
+
+	for (i = 0; i < MAX_CASE_LINE; i++) {
+		block[i] = malloc(max_nb_line_char);
+		if (!block[i])
+			goto error_exit;
+	}
+
+	return 0;
+
+error_exit:
+	for (i = 0; i < MAX_CASE_LINE; i++)
+		if (block[i])
+			free(block[i]);
+
+	return -ENOMEM;
+}
+
+void
+free_line_block_mem(char *block[MAX_CASE_LINE])
+{
+	uint32_t i;
+
+	for (i = 0; i < MAX_CASE_LINE; i++)
+		if (block[i])
+			free(block[i]);
+}
-- 
2.9.5

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-09-07 17:15 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-07 17:13 [dpdk-dev] [PATCH v1 0/2] FIPS validation capability Marko Kovacevic
2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 1/2] test/test: cryptodev application for FIPS certification Marko Kovacevic
2018-09-07 17:13 ` [dpdk-dev] [PATCH v1 2/2] test/test: cryptodev application parser " Marko Kovacevic

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).