diff mbox

[RFC,OPNESSL-ODP,2/2] Adding Async ODP engine for AES cipher

Message ID 1467911676-7160-1-git-send-email-nikhil.agarwal@linaro.org
State New
Headers show

Commit Message

Nikhil Agarwal July 7, 2016, 5:14 p.m. UTC
---
 README           |  21 +++
 engine/eng_odp.c | 437 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 458 insertions(+)
 create mode 100644 README
 create mode 100644 engine/eng_odp.c

-- 
2.8.2
diff mbox

Patch

diff --git a/README b/README
new file mode 100644
index 0000000..b13393a
--- /dev/null
+++ b/README
@@ -0,0 +1,21 @@ 
+Copyright (c) 2013-2014, Linaro Limited
+All rights reserved.
+
+SPDX-License-Identifier:        BSD-3-Clause
+
+OpenDataPlane (ODP) project source code.
+    http://www.opendataplane.org/
+
+    How to build:
+    Following are the steep to build this object:
+    ./bootstrap
+    ./configure --with-openssl-path=<openssl install path> --with-odp-path=<ODP install path>
+    make
+
+    How to run.
+    Copy the shared object engine/.libs/libsslodp.so to "opnessl path"/lib/engines/.
+    Execute any openssl application with arguments  "-engine libsslodp".
+
+    Currently, we have tested openssl speed application with NXP platform.
+
+
diff --git a/engine/eng_odp.c b/engine/eng_odp.c
new file mode 100644
index 0000000..91151ae
--- /dev/null
+++ b/engine/eng_odp.c
@@ -0,0 +1,437 @@ 
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/engine.h>
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/async.h>
+#include <openssl/bn.h>
+#include <openssl/crypto.h>
+#include <openssl/ssl.h>
+#include <openssl/modes.h>
+#include <odp.h>
+#include <pthread.h>
+#include <unistd.h>
+
+odp_pool_t pool;
+int num_queue = 8;
+odp_queue_t out_queue[8];
+
+typedef struct ossl_odp_status {
+	bool is_complete;
+	bool is_successful;
+} ossl_odp_status_t;
+
+/* Engine Id and Name */
+static const char *engine_odp_id = "libsslodp";
+static const char *engine_odp_name = "ODP based engine";
+
+/* Engine Lifetime functions */
+static int ossl_odp_destroy(ENGINE *e);
+static int ossl_odp_init(ENGINE *e);
+static int ossl_odp_finish(ENGINE *e);
+
+/* Set up digests. Just SHA1 for now */
+static int ossl_odp_digests(ENGINE *e, const EVP_MD **digest,
+		const int **nids, int nid);
+
+/*
+ * Holds the EVP_MD object for sha1 in this engine. Set up once only during
+ * engine bind and can then be reused many times.
+ */
+static EVP_MD *_hidden_sha1_md = NULL;
+static const EVP_MD *ossl_odp_sha1(void)
+{
+	return _hidden_sha1_md;
+}
+static void destroy_digests(void)
+{
+	EVP_MD_meth_free(_hidden_sha1_md);
+	_hidden_sha1_md = NULL;
+}
+
+
+static int ossl_odp_digest_nids(const int **nids)
+{
+	static int digest_nids[2] = { 0, 0 };
+	static int pos = 0;
+	static int init = 0;
+
+	if (!init) {
+		const EVP_MD *md;
+		if ((md = ossl_odp_sha1()) != NULL)
+			digest_nids[pos++] = EVP_MD_type(md);
+		digest_nids[pos] = 0;
+		init = 1;
+	}
+	*nids = digest_nids;
+	return pos;
+}
+
+/* AES */
+
+static int ossl_odp_aes128_init_key(EVP_CIPHER_CTX *ctx,
+		const unsigned char *key, const unsigned char *iv, int enc);
+static int ossl_odp_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		const unsigned char *in, size_t inl);
+static int ossl_odp_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx);
+
+struct ossl_odp_ctx {
+	odp_crypto_session_t session;
+};
+
+/*
+ * Holds the EVP_CIPHER object for aes_128_cbc in this engine. Set up once only
+ * during engine bind and can then be reused many times.
+ */
+static EVP_CIPHER *_hidden_aes_128_cbc;
+static const EVP_CIPHER *ossl_odp_aes_128_cbc(void)
+{
+	return _hidden_aes_128_cbc;
+}
+
+static void destroy_ciphers(void)
+{
+	EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+	_hidden_aes_128_cbc = NULL;
+}
+
+static int ossl_odp_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+		const int **nids, int nid);
+
+static int ossl_odp_cipher_nids[] = {
+	NID_aes_128_cbc,
+	0
+};
+
+
+static int bind_odp(ENGINE *e)
+{
+	odp_queue_param_t qparam;
+	odp_pool_param_t params;
+	int i;
+	if (0 != odp_init_global(NULL, NULL)) {
+		printf("error: odp_init_global() failed.\n");
+		return -1;
+	}
+
+	if (0 != odp_init_local(ODP_THREAD_WORKER)) {
+		printf("error: odp_init_local() failed.\n");
+		return -1;
+	}
+
+	memset(&params, 0, sizeof(params));
+	params.pkt.seg_len = 20480;
+	params.pkt.len = 20480;
+	params.pkt.num = 4096;
+	params.type = ODP_POOL_PACKET;
+
+	pool = odp_pool_create("ossl_odp_pool", &params);
+
+	if (ODP_POOL_INVALID == pool) {
+		printf("Packet pool creation failed.\n");
+		odp_term_local();
+		odp_term_global();
+		return -1;
+	}
+	odp_queue_param_init(&qparam);
+	qparam.sched.prio = ODP_SCHED_PRIO_HIGHEST;
+	qparam.sched.sync = ODP_SCHED_SYNC_ATOMIC;
+	qparam.sched.group = ODP_SCHED_GROUP_ALL;
+	for (i = 0; i < num_queue; i++) {
+		char queue_name[256] = {0};
+		sprintf(queue_name, "%s%d", "ossl_out_queue_", i);
+		out_queue[i] = odp_queue_create(queue_name,
+				ODP_QUEUE_TYPE_SCHED, &qparam);
+		printf("Created queue %s\n", queue_name);
+		if (ODP_QUEUE_INVALID == out_queue[i]) {
+			printf("Crypto outq creation failed.\n");
+			for (; i >= 0; i--)
+				odp_queue_destroy(out_queue[i]);
+			odp_pool_destroy(pool);
+			odp_term_local();
+			odp_term_global();
+			return -1;
+		}
+	}
+
+	if (!ENGINE_set_id(e, engine_odp_id)
+			|| !ENGINE_set_name(e, engine_odp_name)
+			|| !ENGINE_set_ciphers(e, ossl_odp_ciphers)
+			|| !ENGINE_set_digests(e, ossl_odp_digests)
+			|| !ENGINE_set_destroy_function(e, ossl_odp_destroy)
+			|| !ENGINE_set_init_function(e, ossl_odp_init)
+			|| !ENGINE_set_finish_function(e, ossl_odp_finish)) {
+		return 0;
+	}
+
+	_hidden_aes_128_cbc = EVP_CIPHER_meth_new(NID_aes_128_cbc,
+			16 /* block size */,
+			16 /* key len */);
+	if (_hidden_aes_128_cbc == NULL
+		|| !EVP_CIPHER_meth_set_iv_length(_hidden_aes_128_cbc, 16)
+		|| !EVP_CIPHER_meth_set_flags(_hidden_aes_128_cbc,
+			EVP_CIPH_FLAG_DEFAULT_ASN1
+			| EVP_CIPH_CBC_MODE)
+		|| !EVP_CIPHER_meth_set_init(_hidden_aes_128_cbc,
+			ossl_odp_aes128_init_key)
+		|| !EVP_CIPHER_meth_set_do_cipher(_hidden_aes_128_cbc,
+			ossl_odp_aes128_cbc_cipher)
+		|| !EVP_CIPHER_meth_set_cleanup(_hidden_aes_128_cbc,
+			ossl_odp_aes128_cbc_cleanup)
+		|| !EVP_CIPHER_meth_set_impl_ctx_size(_hidden_aes_128_cbc,
+				sizeof(struct ossl_odp_ctx))) {
+		EVP_CIPHER_meth_free(_hidden_aes_128_cbc);
+		_hidden_aes_128_cbc = NULL;
+	}
+
+	return 1;
+}
+
+static int bind_helper(ENGINE *e, const char *id)
+{
+	if (id && (strcmp(id, engine_odp_id) != 0))
+		return 0;
+	if (!bind_odp(e))
+		return 0;
+	return 1;
+}
+
+IMPLEMENT_DYNAMIC_CHECK_FN()
+IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
+
+static int ossl_odp_init(ENGINE *e)
+{
+
+	if (0 != odp_init_local(ODP_THREAD_WORKER)) {
+		printf("error: odp_init_local() failed.\n");
+		return -1;
+	}
+
+	return 1;
+}
+
+
+static int ossl_odp_finish(ENGINE *e)
+{
+	int i;
+
+	for (i = 0; i < num_queue; i++)
+		odp_queue_destroy(out_queue[i]);
+
+	odp_pool_destroy(pool);
+	odp_term_local();
+	odp_term_global();
+	return 1;
+}
+
+
+static int ossl_odp_destroy(ENGINE *e)
+{
+	destroy_ciphers();
+	return 1;
+}
+
+static int ossl_odp_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
+		const int **nids, int nid)
+{
+	int ok = 1;
+
+	if (cipher == NULL) {
+		/* We are returning a list of supported nids */
+		*nids = ossl_odp_cipher_nids;
+		return (sizeof(ossl_odp_cipher_nids) -
+				1) / sizeof(ossl_odp_cipher_nids[0]);
+	}
+	/* We are being asked for a specific cipher */
+	switch (nid) {
+	case NID_aes_128_cbc:
+		*cipher = ossl_odp_aes_128_cbc();
+		break;
+	default:
+		ok = 0;
+		*cipher = NULL;
+		break;
+	}
+	return ok;
+}
+
+static int ossl_odp_digests(ENGINE *e, const EVP_MD **digest,
+		const int **nids, int nid)
+{
+	int ok = 1;
+	if (!digest) {
+		/* We are returning a list of supported nids */
+		return ossl_odp_digest_nids(nids);
+	}
+	/* We are being asked for a specific digest */
+	switch (nid) {
+		case NID_sha1:
+			*digest = ossl_odp_sha1();
+			break;
+		default:
+			ok = 0;
+			*digest = NULL;
+			break;
+	}
+	return ok;
+}
+
+
+static void wait_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
+		OSSL_ASYNC_FD readfd, void *pvwritefd)
+{
+	/*Nothing todo for now*/
+}
+
+/* Cipher helper functions */
+static int ossl_odp_cipher_init_key_helper(EVP_CIPHER_CTX *ctx,
+		const unsigned char *key,
+		const unsigned char *iv, int enc,
+		const EVP_CIPHER *cipher)
+{
+	int ret;
+	enum odp_crypto_ses_create_err status;
+	odp_crypto_session_params_t ses_params;
+	odp_crypto_key_t cipher_key = { .data = NULL, .length = 0 },
+			 auth_key = { .data = NULL, .length = 0 };
+	odp_crypto_iv_t ses_iv;
+	static int next;
+
+	if (next == num_queue)
+		next = 0;
+
+
+	struct ossl_odp_ctx *odp_ctx =
+		(struct ossl_odp_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+	/* Create a crypto session */
+	memset(&ses_params, 0, sizeof(ses_params));
+	ses_params.op = (enc == 1) ? ODP_CRYPTO_OP_ENCODE:ODP_CRYPTO_OP_DECODE;
+	ses_params.auth_cipher_text = false;
+	ses_params.pref_mode = ODP_CRYPTO_ASYNC;
+	ses_params.cipher_alg = ODP_CIPHER_ALG_AES128_CBC;
+	ses_params.auth_alg = ODP_AUTH_ALG_NULL;
+	cipher_key.data = (unsigned char *)key;
+	cipher_key.length = 16;
+	ses_iv.data = (unsigned char *)iv;
+	ses_iv.length = 16;
+	ses_params.cipher_key = cipher_key;
+	ses_params.iv = ses_iv;
+	ses_params.auth_key = auth_key;
+	ses_params.compl_queue = out_queue[next];
+	ses_params.output_pool = pool;
+
+	ret = odp_crypto_session_create(&ses_params,
+			&(odp_ctx->session), &status);
+
+	next++;
+	if (ODP_CRYPTO_SES_CREATE_ERR_NONE != status)
+		return 0;
+
+	return 1;
+}
+
+static int ossl_odp_cipher_helper(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		const unsigned char *in, size_t inl,
+		const EVP_CIPHER *cipher)
+{
+	odp_crypto_op_params_t params;
+	odp_packet_t pkt;
+	odp_bool_t posted;
+	odp_event_t event;
+	odp_crypto_compl_t compl_event;
+	ossl_odp_status_t compl, *dequeued;
+	ASYNC_WAIT_CTX *waitctx;
+	OSSL_ASYNC_FD *fd;
+	char completed = 0;
+	odp_crypto_op_result_t result;
+	ASYNC_JOB *job = ASYNC_get_current_job();
+	struct ossl_odp_ctx *odp_ctx =
+		(struct ossl_odp_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+	if (job == NULL) {
+		printf("\nSYNC operation not yet supported\n");
+		return 0;
+	}
+	compl.is_complete = 0;
+
+	waitctx = ASYNC_get_wait_ctx(job);
+
+	pkt = odp_packet_alloc(pool, inl);
+
+	if (ODP_PACKET_INVALID == pkt)
+		return 0;
+
+	odp_packet_copydata_in(pkt, 0, inl, in);
+	memset(&params, 0, sizeof(params));
+	params.ctx = NULL;
+	params.session = odp_ctx->session;
+	params.pkt = pkt;
+	params.ctx = &compl;
+	params.out_pkt = pkt;
+	params.cipher_range.offset = 0;
+	params.cipher_range.length = inl;
+	params.override_iv_ptr = NULL;
+	if (odp_crypto_operation(&params,
+				&posted,
+				&result)) {
+		odp_packet_free(pkt);
+		return 0;
+	}
+	if (posted) {
+		while (!compl.is_complete) {
+			ASYNC_pause_job();
+			/* Poll completion queue for results */
+			event = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
+
+			while (event != ODP_EVENT_INVALID) {
+				compl_event =
+					odp_crypto_compl_from_event(event);
+				odp_crypto_compl_result(compl_event, &result);
+				odp_crypto_compl_free(compl_event);
+				dequeued = (ossl_odp_status_t *)result.ctx;
+				dequeued->is_complete = 1;
+				dequeued->is_successful = result.ok;
+
+				event = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
+			}
+		}
+	}
+	if(!compl.is_successful) {
+		odp_packet_free(pkt);
+		return 0;
+	}
+	odp_packet_copydata_out(pkt, 0, inl, out);
+	odp_packet_free(pkt);
+	return 1;
+}
+
+/*
+ * AES128 CBC Implementation
+ */
+
+static int ossl_odp_aes128_init_key(EVP_CIPHER_CTX *ctx,
+		const unsigned char *key, const unsigned char *iv, int enc)
+{
+	return ossl_odp_cipher_init_key_helper(ctx, key, iv,
+						enc, EVP_aes_128_cbc());
+}
+
+static int ossl_odp_aes128_cbc_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out,
+		const unsigned char *in, size_t inl)
+{
+	return ossl_odp_cipher_helper(ctx, out, in, inl, EVP_aes_128_cbc());
+}
+
+static int ossl_odp_aes128_cbc_cleanup(EVP_CIPHER_CTX *ctx)
+{
+	struct ossl_odp_ctx *odp_ctx =
+		(struct ossl_odp_ctx *)EVP_CIPHER_CTX_get_cipher_data(ctx);
+
+	odp_crypto_session_destroy(odp_ctx->session);
+
+	return 1;
+}
+