@@ -110,6 +110,8 @@ int odp_queue_term_global(void);
int odp_crypto_init_global(void);
int odp_crypto_term_global(void);
+int _odp_crypto_init_local(void);
+int _odp_crypto_term_local(void);
int odp_timer_init_global(const odp_init_t *params);
int odp_timer_term_global(void);
@@ -9,7 +9,6 @@
#include <odp_posix_extensions.h>
#include <odp/api/crypto.h>
#include <odp_internal.h>
-#include <odp/api/atomic.h>
#include <odp/api/spinlock.h>
#include <odp/api/sync.h>
#include <odp/api/debug.h>
@@ -98,6 +97,7 @@ typedef
odp_crypto_alg_err_t (*crypto_func_t)(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session);
+typedef void (*crypto_init_func_t)(odp_crypto_generic_session_t *session);
/**
* Per crypto session data structure
@@ -117,6 +117,7 @@ struct odp_crypto_generic_session_t {
const EVP_CIPHER *evp_cipher;
crypto_func_t func;
+ crypto_init_func_t init;
} cipher;
struct {
@@ -128,7 +129,10 @@ struct odp_crypto_generic_session_t {
const EVP_CIPHER *evp_cipher;
};
crypto_func_t func;
+ crypto_init_func_t init;
} auth;
+
+ unsigned idx;
};
typedef struct odp_crypto_global_s odp_crypto_global_t;
@@ -137,15 +141,42 @@ struct odp_crypto_global_s {
odp_spinlock_t lock;
odp_crypto_generic_session_t *free;
odp_crypto_generic_session_t sessions[MAX_SESSIONS];
+
+ /* These flags are cleared at alloc_session() */
+ uint8_t ctx_valid[ODP_THREAD_COUNT_MAX][MAX_SESSIONS];
+
odp_ticketlock_t openssl_lock[0];
};
static odp_crypto_global_t *global;
+typedef struct crypto_local_t {
+ HMAC_CTX *hmac_ctx[MAX_SESSIONS];
+ EVP_CIPHER_CTX *cipher_ctx[MAX_SESSIONS];
+ EVP_CIPHER_CTX *mac_cipher_ctx[MAX_SESSIONS];
+ uint8_t *ctx_valid;
+} crypto_local_t;
+
+static __thread crypto_local_t local;
+
+typedef enum { KIND_HMAC, KIND_CIPHER, KIND_MAC_CIPHER } crypto_kind_t;
+
+static inline void crypto_init(odp_crypto_generic_session_t *session)
+{
+ if (local.ctx_valid[session->idx])
+ return;
+
+ session->cipher.init(session);
+ session->auth.init(session);
+
+ local.ctx_valid[session->idx] = 1;
+}
+
static
odp_crypto_generic_session_t *alloc_session(void)
{
odp_crypto_generic_session_t *session = NULL;
+ unsigned i;
odp_spinlock_lock(&global->lock);
session = global->free;
@@ -155,6 +186,11 @@ odp_crypto_generic_session_t *alloc_session(void)
}
odp_spinlock_unlock(&global->lock);
+ session->idx = session - global->sessions;
+
+ for (i = 0; i < ODP_THREAD_COUNT_MAX; i++)
+ global->ctx_valid[i][session->idx] = 0;
+
return session;
}
@@ -175,24 +211,57 @@ null_crypto_routine(odp_packet_t pkt ODP_UNUSED,
return ODP_CRYPTO_ALG_ERR_NONE;
}
-static
-void packet_hmac_calculate(HMAC_CTX *ctx,
- odp_packet_t pkt,
- const odp_crypto_packet_op_param_t *param,
- odp_crypto_generic_session_t *session,
- uint8_t *hash)
+static void
+null_crypto_init_routine(odp_crypto_generic_session_t *session ODP_UNUSED)
{
- uint32_t offset = param->auth_range.offset;
- uint32_t len = param->auth_range.length;
+ return;
+}
- ODP_ASSERT(offset + len <= odp_packet_len(pkt));
+/* Mimic new OpenSSL 1.1.y API */
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+static HMAC_CTX *HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx = malloc(sizeof(*ctx));
+
+ HMAC_CTX_init(ctx);
+ return ctx;
+}
+
+static void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ HMAC_CTX_cleanup(ctx);
+ free(ctx);
+}
+#endif
+
+static void
+auth_init(odp_crypto_generic_session_t *session)
+{
+ HMAC_CTX *ctx = local.hmac_ctx[session->idx];
HMAC_Init_ex(ctx,
session->auth.key,
session->auth.key_length,
session->auth.evp_md,
NULL);
+}
+
+static
+void packet_hmac(odp_packet_t pkt,
+ const odp_crypto_packet_op_param_t *param,
+ odp_crypto_generic_session_t *session,
+ uint8_t *hash)
+{
+ HMAC_CTX *ctx = local.hmac_ctx[session->idx];
+ uint32_t offset = param->auth_range.offset;
+ uint32_t len = param->auth_range.length;
+ ODP_ASSERT(offset + len <= odp_packet_len(pkt));
+
+ /* Reinitialize HMAC calculation without resetting the key */
+ HMAC_Init_ex(ctx, NULL, 0, NULL, NULL);
+
+ /* Hash it */
while (len > 0) {
uint32_t seglen = 0; /* GCC */
void *mapaddr = odp_packet_offset(pkt, offset, &seglen, NULL);
@@ -206,36 +275,6 @@ void packet_hmac_calculate(HMAC_CTX *ctx,
HMAC_Final(ctx, hash, NULL);
}
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-static
-void packet_hmac(odp_packet_t pkt,
- const odp_crypto_packet_op_param_t *param,
- odp_crypto_generic_session_t *session,
- uint8_t *hash)
-{
- HMAC_CTX ctx;
-
- /* Hash it */
- HMAC_CTX_init(&ctx);
- packet_hmac_calculate(&ctx, pkt, param, session, hash);
- HMAC_CTX_cleanup(&ctx);
-}
-#else
-static
-void packet_hmac(odp_packet_t pkt,
- const odp_crypto_packet_op_param_t *param,
- odp_crypto_generic_session_t *session,
- uint8_t *hash)
-{
- HMAC_CTX *ctx;
-
- /* Hash it */
- ctx = HMAC_CTX_new();
- packet_hmac_calculate(ctx, pkt, param, session, hash);
- HMAC_CTX_free(ctx);
-}
-#endif
-
static
odp_crypto_alg_err_t auth_gen(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
@@ -425,12 +464,22 @@ int internal_decrypt(EVP_CIPHER_CTX *ctx,
return ret;
}
+static void
+cipher_encrypt_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
+
+ EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t cipher_encrypt(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
void *iv_ptr;
int ret;
@@ -441,27 +490,30 @@ odp_crypto_alg_err_t cipher_encrypt(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Encrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
- session->cipher.key_data, NULL);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
ret = internal_encrypt(ctx, pkt, param);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
ODP_CRYPTO_ALG_ERR_NONE;
}
+static void
+cipher_decrypt_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
+
+ EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t cipher_decrypt(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
void *iv_ptr;
int ret;
@@ -472,17 +524,10 @@ odp_crypto_alg_err_t cipher_decrypt(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Decrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
- session->cipher.key_data, NULL);
EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
ret = internal_decrypt(ctx, pkt, param);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
ODP_CRYPTO_ALG_ERR_NONE;
}
@@ -506,20 +551,35 @@ static int process_cipher_param(odp_crypto_generic_session_t *session,
session->p.cipher_key.length);
/* Set function */
- if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+ if (ODP_CRYPTO_OP_ENCODE == session->p.op) {
session->cipher.func = cipher_encrypt;
- else
+ session->cipher.init = cipher_encrypt_init;
+ } else {
session->cipher.func = cipher_decrypt;
+ session->cipher.init = cipher_decrypt_init;
+ }
return 0;
}
+static void
+aes_gcm_encrypt_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
+
+ EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t aes_gcm_encrypt(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
const uint8_t *aad_head = param->aad_ptr;
uint32_t aad_len = session->p.auth_aad_len;
void *iv_ptr;
@@ -534,14 +594,7 @@ odp_crypto_alg_err_t aes_gcm_encrypt(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Encrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_EncryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
- session->cipher.key_data, NULL);
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
- session->p.iv.length, NULL);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
/* Authenticate header data (if any) without encrypting them */
if (aad_len > 0)
@@ -555,18 +608,28 @@ odp_crypto_alg_err_t aes_gcm_encrypt(odp_packet_t pkt,
odp_packet_copy_from_mem(pkt, param->hash_result_offset,
session->p.auth_digest_len, block);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
ODP_CRYPTO_ALG_ERR_NONE;
}
+static void
+aes_gcm_decrypt_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
+
+ EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
+ session->cipher.key_data, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t aes_gcm_decrypt(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.cipher_ctx[session->idx];
const uint8_t *aad_head = param->aad_ptr;
uint32_t aad_len = session->p.auth_aad_len;
int dummy_len = 0;
@@ -581,14 +644,7 @@ odp_crypto_alg_err_t aes_gcm_decrypt(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Decrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_DecryptInit_ex(ctx, session->cipher.evp_cipher, NULL,
- session->cipher.key_data, NULL);
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
- session->p.iv.length, NULL);
EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
odp_packet_copy_to_mem(pkt, param->hash_result_offset,
session->p.auth_digest_len, block);
@@ -602,8 +658,6 @@ odp_crypto_alg_err_t aes_gcm_decrypt(odp_packet_t pkt,
ret = internal_decrypt(ctx, pkt, param);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_ICV_CHECK :
ODP_CRYPTO_ALG_ERR_NONE;
}
@@ -622,20 +676,35 @@ static int process_aes_gcm_param(odp_crypto_generic_session_t *session,
session->cipher.evp_cipher = cipher;
/* Set function */
- if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+ if (ODP_CRYPTO_OP_ENCODE == session->p.op) {
session->cipher.func = aes_gcm_encrypt;
- else
+ session->cipher.init = aes_gcm_encrypt_init;
+ } else {
session->cipher.func = aes_gcm_decrypt;
+ session->cipher.init = aes_gcm_decrypt_init;
+ }
return 0;
}
+static void
+aes_gmac_gen_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.mac_cipher_ctx[session->idx];
+
+ EVP_EncryptInit_ex(ctx, session->auth.evp_cipher, NULL,
+ session->auth.key, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t aes_gmac_gen(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.mac_cipher_ctx[session->idx];
void *iv_ptr;
uint8_t block[EVP_MAX_MD_SIZE];
int ret;
@@ -647,14 +716,7 @@ odp_crypto_alg_err_t aes_gmac_gen(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Encrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_EncryptInit_ex(ctx, session->auth.evp_cipher, NULL,
- session->auth.key, NULL);
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
- session->p.iv.length, NULL);
EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
ret = internal_aad(ctx, pkt, param);
@@ -663,18 +725,28 @@ odp_crypto_alg_err_t aes_gmac_gen(odp_packet_t pkt,
odp_packet_copy_from_mem(pkt, param->hash_result_offset,
session->p.auth_digest_len, block);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_DATA_SIZE :
ODP_CRYPTO_ALG_ERR_NONE;
}
+static void
+aes_gmac_check_init(odp_crypto_generic_session_t *session)
+{
+ EVP_CIPHER_CTX *ctx = local.mac_cipher_ctx[session->idx];
+
+ EVP_DecryptInit_ex(ctx, session->auth.evp_cipher, NULL,
+ session->auth.key, NULL);
+ EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
+ session->p.iv.length, NULL);
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+}
+
static
odp_crypto_alg_err_t aes_gmac_check(odp_packet_t pkt,
const odp_crypto_packet_op_param_t *param,
odp_crypto_generic_session_t *session)
{
- EVP_CIPHER_CTX *ctx;
+ EVP_CIPHER_CTX *ctx = local.mac_cipher_ctx[session->idx];
void *iv_ptr;
uint8_t block[EVP_MAX_MD_SIZE];
int ret;
@@ -686,14 +758,7 @@ odp_crypto_alg_err_t aes_gmac_check(odp_packet_t pkt,
else
return ODP_CRYPTO_ALG_ERR_IV_INVALID;
- /* Decrypt it */
- ctx = EVP_CIPHER_CTX_new();
- EVP_DecryptInit_ex(ctx, session->auth.evp_cipher, NULL,
- session->auth.key, NULL);
- EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN,
- session->p.iv.length, NULL);
EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, iv_ptr);
- EVP_CIPHER_CTX_set_padding(ctx, 0);
odp_packet_copy_to_mem(pkt, param->hash_result_offset,
session->p.auth_digest_len, block);
@@ -704,8 +769,6 @@ odp_crypto_alg_err_t aes_gmac_check(odp_packet_t pkt,
ret = internal_aad(ctx, pkt, param);
- EVP_CIPHER_CTX_free(ctx);
-
return ret <= 0 ? ODP_CRYPTO_ALG_ERR_ICV_CHECK :
ODP_CRYPTO_ALG_ERR_NONE;
}
@@ -724,10 +787,13 @@ static int process_aes_gmac_param(odp_crypto_generic_session_t *session,
session->auth.evp_cipher = cipher;
/* Set function */
- if (ODP_CRYPTO_OP_ENCODE == session->p.op)
+ if (ODP_CRYPTO_OP_ENCODE == session->p.op) {
session->auth.func = aes_gmac_gen;
- else
+ session->auth.init = aes_gmac_gen_init;
+ } else {
session->auth.func = aes_gmac_check;
+ session->auth.init = aes_gmac_check_init;
+ }
return 0;
}
@@ -741,6 +807,7 @@ static int process_auth_param(odp_crypto_generic_session_t *session,
session->auth.func = auth_gen;
else
session->auth.func = auth_check;
+ session->auth.init = auth_init;
session->auth.evp_md = evp_md;
@@ -923,6 +990,7 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
switch (param->cipher_alg) {
case ODP_CIPHER_ALG_NULL:
session->cipher.func = null_crypto_routine;
+ session->cipher.init = null_crypto_init_routine;
rc = 0;
break;
case ODP_CIPHER_ALG_3DES_CBC:
@@ -998,6 +1066,7 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
switch (param->auth_alg) {
case ODP_AUTH_ALG_NULL:
session->auth.func = null_crypto_routine;
+ session->auth.init = null_crypto_init_routine;
rc = 0;
break;
#if ODP_DEPRECATED_API
@@ -1037,6 +1106,7 @@ odp_crypto_session_create(odp_crypto_session_param_t *param,
* cipher at the same time */
if (param->cipher_alg == ODP_CIPHER_ALG_AES_GCM || aes_gcm) {
session->auth.func = null_crypto_routine;
+ session->auth.init = null_crypto_init_routine;
rc = 0;
} else {
rc = -1;
@@ -1216,6 +1286,49 @@ int odp_crypto_term_global(void)
return rc;
}
+int _odp_crypto_init_local(void)
+{
+ unsigned i;
+ int id;
+
+ memset(&local, 0, sizeof(local));
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ local.hmac_ctx[i] = HMAC_CTX_new();
+ local.cipher_ctx[i] = EVP_CIPHER_CTX_new();
+ local.mac_cipher_ctx[i] = EVP_CIPHER_CTX_new();
+
+ if (local.hmac_ctx[i] == NULL ||
+ local.cipher_ctx[i] == NULL ||
+ local.mac_cipher_ctx[i] == NULL) {
+ _odp_crypto_term_local();
+ return -1;
+ }
+ }
+
+ id = odp_thread_id();
+ local.ctx_valid = global->ctx_valid[id];
+ /* No need to clear flags here, alloc_session did the job for us */
+
+ return 0;
+}
+
+int _odp_crypto_term_local(void)
+{
+ unsigned i;
+
+ for (i = 0; i < MAX_SESSIONS; i++) {
+ if (local.hmac_ctx[i] != NULL)
+ HMAC_CTX_free(local.hmac_ctx[i]);
+ if (local.cipher_ctx[i] != NULL)
+ EVP_CIPHER_CTX_free(local.cipher_ctx[i]);
+ if (local.mac_cipher_ctx[i] != NULL)
+ EVP_CIPHER_CTX_free(local.mac_cipher_ctx[i]);
+ }
+
+ return 0;
+}
+
odp_random_kind_t odp_random_max_kind(void)
{
return ODP_RANDOM_CRYPTO;
@@ -1385,6 +1498,8 @@ int odp_crypto_int(odp_packet_t pkt_in,
pkt_in = ODP_PACKET_INVALID;
}
+ crypto_init(session);
+
/* Invoke the functions */
if (session->do_cipher_first) {
rc_cipher = session->cipher.func(out_pkt, param, session);
@@ -327,6 +327,12 @@ int odp_init_local(odp_instance_t instance, odp_thread_type_t thr_type)
}
stage = PKTIO_INIT;
+ if (_odp_crypto_init_local()) {
+ ODP_ERR("ODP crypto local init failed.\n");
+ goto init_fail;
+ }
+ stage = CRYPTO_INIT;
+
if (odp_pool_init_local()) {
ODP_ERR("ODP pool local init failed.\n");
goto init_fail;
@@ -379,6 +385,13 @@ int _odp_term_local(enum init_stage stage)
}
/* Fall through */
+ case CRYPTO_INIT:
+ if (_odp_crypto_term_local()) {
+ ODP_ERR("ODP crypto local term failed.\n");
+ rc = -1;
+ }
+ /* Fall through */
+
case POOL_INIT:
if (odp_pool_term_local()) {
ODP_ERR("ODP buffer pool local term failed.\n");