aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikhil Agarwal <nikhil.agarwal@linaro.org>2016-06-03 23:05:50 +0530
committerNikhil Agarwal <nikhil.agarwal@linaro.org>2016-06-03 23:05:50 +0530
commit0860c35dc215bc0f2f913b2d7109c83f9dd5743f (patch)
tree407099aac5285866f8b28a0d1cdb430a3637d43a
parent4d22dd584c36b845bdd4912851f509a7aac56d8c (diff)
Adding Async ODP engine for AES cipher
-rw-r--r--engine/eng_odp.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/engine/eng_odp.c b/engine/eng_odp.c
new file mode 100644
index 0000000..3340649
--- /dev/null
+++ b/engine/eng_odp.c
@@ -0,0 +1,375 @@
+
+#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>
+
+#define DUMMY_CHAR 'X'
+odp_pool_t pool;
+int num_queue = 8;
+odp_queue_t out_queue[8];
+OSSL_ASYNC_FD pipefds[2] = {0, 0};
+
+/* 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 void destroy_digests(void)
+{
+ /*Nothing for now*/
+}
+
+static int ossl_odp_digest_nids(const int **nids)
+{
+ int digest_nids[2] = { 0, 0 };
+
+ *nids = digest_nids;
+ return 1;
+}
+
+/* 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)
+{
+ if (!ENGINE_set_id(e, engine_odp_id)
+ || !ENGINE_set_name(e, engine_odp_name)
+ || !ENGINE_set_ciphers(e, ossl_odp_ciphers)
+ || !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)
+{
+ odp_queue_param_t qparam;
+ odp_pool_param_t params;
+ int i;
+ char buf = DUMMY_CHAR;
+
+ 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("packet_pool", &params);
+
+ if (ODP_POOL_INVALID == pool) {
+ printf("Packet pool creation failed.\n");
+ 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++) {
+ out_queue[i] = odp_queue_create("crypto-out",
+ ODP_QUEUE_TYPE_SCHED, &qparam);
+ if (ODP_QUEUE_INVALID == out_queue[i]) {
+ printf("Crypto outq creation failed.\n");
+ return -1;
+ }
+ }
+ if (pipe(pipefds) != 0)
+ return;
+
+ write(pipefds[1], &buf, 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 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 ret;
+}
+
+static int ossl_odp_cipher_helper(EVP_CIPHER_CTX *ctx, unsigned char *out,
+ const unsigned char *in, size_t inl,
+ const EVP_CIPHER *cipher)
+{
+ int ret = 1;
+ odp_crypto_op_params_t params;
+ odp_packet_t pkt;
+ odp_bool_t posted;
+ odp_event_t event;
+ odp_crypto_compl_t compl_event;
+ 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;
+ }
+
+ waitctx = ASYNC_get_wait_ctx(job);
+
+ if (!ASYNC_WAIT_CTX_get_fd(waitctx, engine_odp_id, &pipefds[0],
+ (void **)&fd)) {
+ ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_odp_id, pipefds[0],
+ NULL, wait_cleanup);
+ }
+ pkt = odp_packet_alloc(pool, inl);
+ memcpy(odp_packet_data(pkt), in, inl);
+ memset(&params, 0, sizeof(params));
+ params.ctx = NULL;
+ params.session = odp_ctx->session;
+ params.pkt = pkt;
+ params.ctx = &completed;
+ 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)) {
+ abort();
+ }
+ if (posted) {
+ while (!completed) {
+ 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);
+ *((char *)result.ctx) = 1;
+
+ if (!result.ok)
+ return;
+ event = odp_schedule(NULL, ODP_SCHED_NO_WAIT);
+ }
+ }
+ }
+ memcpy(out, odp_packet_data(pkt), inl);
+ odp_packet_free(pkt);
+ return ret;
+}
+
+/*
+ * 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;
+}
+