diff options
author | Nikhil Agarwal <nikhil.agarwal@linaro.org> | 2016-06-03 23:05:50 +0530 |
---|---|---|
committer | Nikhil Agarwal <nikhil.agarwal@linaro.org> | 2016-06-03 23:05:50 +0530 |
commit | 0860c35dc215bc0f2f913b2d7109c83f9dd5743f (patch) | |
tree | 407099aac5285866f8b28a0d1cdb430a3637d43a | |
parent | 4d22dd584c36b845bdd4912851f509a7aac56d8c (diff) |
Adding Async ODP engine for AES cipher
-rw-r--r-- | engine/eng_odp.c | 375 |
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(¶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("packet_pool", ¶ms); + + 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(¶ms, 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(¶ms, + &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; +} + |