summaryrefslogtreecommitdiffstats
path: root/crypto/evp/keymgmt_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/evp/keymgmt_lib.c')
-rw-r--r--crypto/evp/keymgmt_lib.c99
1 files changed, 55 insertions, 44 deletions
diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c
index 0112036263..85a39b3d89 100644
--- a/crypto/evp/keymgmt_lib.c
+++ b/crypto/evp/keymgmt_lib.c
@@ -87,7 +87,7 @@ int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection,
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
{
struct evp_keymgmt_util_try_import_data_st import_data;
- size_t i = 0;
+ OP_CACHE_ELEM *op;
/* Export to where? */
if (keymgmt == NULL)
@@ -104,15 +104,14 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
CRYPTO_THREAD_read_lock(pk->lock);
/*
* If the provider native "origin" hasn't changed since last time, we
- * try to find our keymgmt in the operation cache. If it has changed,
- * |i| remains zero, and we will clear the cache further down.
+ * try to find our keymgmt in the operation cache. If it has changed
+ * and our keymgmt isn't found, we will clear the cache further down.
*/
if (pk->dirty_cnt == pk->dirty_cnt_copy) {
/* If this key is already exported to |keymgmt|, no more to do */
- i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt);
- if (i < OSSL_NELEM(pk->operation_cache)
- && pk->operation_cache[i].keymgmt != NULL) {
- void *ret = pk->operation_cache[i].keydata;
+ op = evp_keymgmt_util_find_operation_cache(pk, keymgmt);
+ if (op != NULL && op->keymgmt != NULL) {
+ void *ret = op->keydata;
CRYPTO_THREAD_unlock(pk->lock);
return ret;
@@ -128,15 +127,6 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
if (pk->keymgmt->export == NULL)
return NULL;
- /* Check that we have found an empty slot in the export cache */
- /*
- * TODO(3.0) Right now, we assume we have ample space. We will have to
- * think about a cache aging scheme, though, if |i| indexes outside the
- * array.
- */
- if (!ossl_assert(i < OSSL_NELEM(pk->operation_cache)))
- return NULL;
-
/*
* Make sure that the type of the keymgmt to export to matches the type
* of the "origin"
@@ -168,10 +158,9 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
CRYPTO_THREAD_write_lock(pk->lock);
/* Check to make sure some other thread didn't get there first */
- i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt);
- if (i < OSSL_NELEM(pk->operation_cache)
- && pk->operation_cache[i].keymgmt != NULL) {
- void *ret = pk->operation_cache[i].keydata;
+ op = evp_keymgmt_util_find_operation_cache(pk, keymgmt);
+ if (op != NULL && op->keydata != NULL) {
+ void *ret = op->keydata;
CRYPTO_THREAD_unlock(pk->lock);
@@ -192,7 +181,7 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
evp_keymgmt_util_clear_operation_cache(pk, 0);
/* Add the new export to the operation cache */
- if (!evp_keymgmt_util_cache_keydata(pk, i, keymgmt, import_data.keydata)) {
+ if (!evp_keymgmt_util_cache_keydata(pk, keymgmt, import_data.keydata)) {
evp_keymgmt_freedata(keymgmt, import_data.keydata);
return NULL;
}
@@ -205,22 +194,20 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
return import_data.keydata;
}
-int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking)
+static void op_cache_free(OP_CACHE_ELEM *e)
{
- size_t i, end = OSSL_NELEM(pk->operation_cache);
+ evp_keymgmt_freedata(e->keymgmt, e->keydata);
+ EVP_KEYMGMT_free(e->keymgmt);
+ OPENSSL_free(e);
+}
+int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking)
+{
if (pk != NULL) {
if (locking && pk->lock != NULL && !CRYPTO_THREAD_write_lock(pk->lock))
return 0;
- for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) {
- EVP_KEYMGMT *keymgmt = pk->operation_cache[i].keymgmt;
- void *keydata = pk->operation_cache[i].keydata;
-
- pk->operation_cache[i].keymgmt = NULL;
- pk->operation_cache[i].keydata = NULL;
- evp_keymgmt_freedata(keymgmt, keydata);
- EVP_KEYMGMT_free(keymgmt);
- }
+ sk_OP_CACHE_ELEM_pop_free(pk->operation_cache, op_cache_free);
+ pk->operation_cache = NULL;
if (locking && pk->lock != NULL)
CRYPTO_THREAD_unlock(pk->lock);
}
@@ -228,28 +215,52 @@ int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking)
return 1;
}
-size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk,
- EVP_KEYMGMT *keymgmt)
+OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk,
+ EVP_KEYMGMT *keymgmt)
{
- size_t i, end = OSSL_NELEM(pk->operation_cache);
+ int i, end = sk_OP_CACHE_ELEM_num(pk->operation_cache);
+ OP_CACHE_ELEM *p;
- for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) {
- if (keymgmt == pk->operation_cache[i].keymgmt)
- break;
+ /*
+ * A comparison and sk_P_CACHE_ELEM_find() are avoided to not cause
+ * problems when we've only a read lock.
+ */
+ for (i = 0; i < end; i++) {
+ p = sk_OP_CACHE_ELEM_value(pk->operation_cache, i);
+ if (keymgmt == p->keymgmt)
+ return p;
}
-
- return i;
+ return NULL;
}
-int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk, size_t index,
+int evp_keymgmt_util_cache_keydata(EVP_PKEY *pk,
EVP_KEYMGMT *keymgmt, void *keydata)
{
+ OP_CACHE_ELEM *p = NULL;
+
if (keydata != NULL) {
- if (!EVP_KEYMGMT_up_ref(keymgmt))
+ if (pk->operation_cache == NULL) {
+ pk->operation_cache = sk_OP_CACHE_ELEM_new_null();
+ if (pk->operation_cache == NULL)
+ return 0;
+ }
+
+ p = OPENSSL_malloc(sizeof(*p));
+ if (p == NULL)
return 0;
+ p->keydata = keydata;
+ p->keymgmt = keymgmt;
- pk->operation_cache[index].keydata = keydata;
- pk->operation_cache[index].keymgmt = keymgmt;
+ if (!EVP_KEYMGMT_up_ref(keymgmt)) {
+ OPENSSL_free(p);
+ return 0;
+ }
+
+ if (!sk_OP_CACHE_ELEM_push(pk->operation_cache, p)) {
+ EVP_KEYMGMT_free(keymgmt);
+ OPENSSL_free(p);
+ return 0;
+ }
}
return 1;
}