new file mode 100644
@@ -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.
+
+
new file mode 100644
@@ -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(¶ms, 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", ¶ms);
+
+ 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(¶ms, 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(¶ms,
+ &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;
+}
+