提交 64954e2f 编写于 作者: P Pauli

Fix race condition & allow operation cache to grow.

This fixes a race condition where the index to the cache location was found
under a read lock and a later write lock set the cache entry.  The issue being
that two threads could get the same location index and then fight each other
over writing the cache entry.  The most likely outcome is a memory leak,
however it would be possible to set up an invalid cache entry.

The operation cache was a fixed sized array, once full an assertion failed.
The other fix here is to convert this to a stack.  The code is simplified and
it avoids a cache overflow condition.
Reviewed-by: NRichard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14062)
上级 11ddbf84
...@@ -87,7 +87,7 @@ int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection, ...@@ -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) void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
{ {
struct evp_keymgmt_util_try_import_data_st import_data; struct evp_keymgmt_util_try_import_data_st import_data;
size_t i = 0; OP_CACHE_ELEM *op;
/* Export to where? */ /* Export to where? */
if (keymgmt == NULL) if (keymgmt == NULL)
...@@ -104,15 +104,14 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) ...@@ -104,15 +104,14 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
CRYPTO_THREAD_read_lock(pk->lock); CRYPTO_THREAD_read_lock(pk->lock);
/* /*
* If the provider native "origin" hasn't changed since last time, we * 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, * try to find our keymgmt in the operation cache. If it has changed
* |i| remains zero, and we will clear the cache further down. * and our keymgmt isn't found, we will clear the cache further down.
*/ */
if (pk->dirty_cnt == pk->dirty_cnt_copy) { if (pk->dirty_cnt == pk->dirty_cnt_copy) {
/* If this key is already exported to |keymgmt|, no more to do */ /* If this key is already exported to |keymgmt|, no more to do */
i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt); op = evp_keymgmt_util_find_operation_cache(pk, keymgmt);
if (i < OSSL_NELEM(pk->operation_cache) if (op != NULL && op->keymgmt != NULL) {
&& pk->operation_cache[i].keymgmt != NULL) { void *ret = op->keydata;
void *ret = pk->operation_cache[i].keydata;
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
return ret; return ret;
...@@ -128,15 +127,6 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) ...@@ -128,15 +127,6 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
if (pk->keymgmt->export == NULL) if (pk->keymgmt->export == NULL)
return 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 * Make sure that the type of the keymgmt to export to matches the type
* of the "origin" * of the "origin"
...@@ -168,10 +158,9 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) ...@@ -168,10 +158,9 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
CRYPTO_THREAD_write_lock(pk->lock); CRYPTO_THREAD_write_lock(pk->lock);
/* Check to make sure some other thread didn't get there first */ /* Check to make sure some other thread didn't get there first */
i = evp_keymgmt_util_find_operation_cache_index(pk, keymgmt); op = evp_keymgmt_util_find_operation_cache(pk, keymgmt);
if (i < OSSL_NELEM(pk->operation_cache) if (op != NULL && op->keydata != NULL) {
&& pk->operation_cache[i].keymgmt != NULL) { void *ret = op->keydata;
void *ret = pk->operation_cache[i].keydata;
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
...@@ -192,7 +181,7 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) ...@@ -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); evp_keymgmt_util_clear_operation_cache(pk, 0);
/* Add the new export to the operation cache */ /* 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); evp_keymgmt_freedata(keymgmt, import_data.keydata);
return NULL; return NULL;
} }
...@@ -205,22 +194,20 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt) ...@@ -205,22 +194,20 @@ void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt)
return import_data.keydata; 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 (pk != NULL) {
if (locking && pk->lock != NULL && !CRYPTO_THREAD_write_lock(pk->lock)) if (locking && pk->lock != NULL && !CRYPTO_THREAD_write_lock(pk->lock))
return 0; return 0;
for (i = 0; i < end && pk->operation_cache[i].keymgmt != NULL; i++) { sk_OP_CACHE_ELEM_pop_free(pk->operation_cache, op_cache_free);
EVP_KEYMGMT *keymgmt = pk->operation_cache[i].keymgmt; pk->operation_cache = NULL;
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);
}
if (locking && pk->lock != NULL) if (locking && pk->lock != NULL)
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
} }
...@@ -228,28 +215,52 @@ int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking) ...@@ -228,28 +215,52 @@ int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking)
return 1; return 1;
} }
size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk, OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk,
EVP_KEYMGMT *keymgmt) 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) * A comparison and sk_P_CACHE_ELEM_find() are avoided to not cause
break; * 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 NULL;
return i;
} }
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) EVP_KEYMGMT *keymgmt, void *keydata)
{ {
OP_CACHE_ELEM *p = NULL;
if (keydata != 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; return 0;
p->keydata = keydata;
p->keymgmt = keymgmt;
pk->operation_cache[index].keydata = keydata; if (!EVP_KEYMGMT_up_ref(keymgmt)) {
pk->operation_cache[index].keymgmt = 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; return 1;
} }
......
...@@ -1629,6 +1629,7 @@ static void evp_pkey_free_it(EVP_PKEY *x) ...@@ -1629,6 +1629,7 @@ static void evp_pkey_free_it(EVP_PKEY *x)
/* internal function; x is never NULL */ /* internal function; x is never NULL */
evp_keymgmt_util_clear_operation_cache(x, 1); evp_keymgmt_util_clear_operation_cache(x, 1);
sk_OP_CACHE_ELEM_free(x->operation_cache);
#ifndef FIPS_MODULE #ifndef FIPS_MODULE
evp_pkey_free_legacy(x); evp_pkey_free_legacy(x);
#endif #endif
...@@ -1734,7 +1735,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx, ...@@ -1734,7 +1735,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
#ifndef FIPS_MODULE #ifndef FIPS_MODULE
if (pk->pkey.ptr != NULL) { if (pk->pkey.ptr != NULL) {
size_t i = 0; OP_CACHE_ELEM *op;
/* /*
* If the legacy "origin" hasn't changed since last time, we try * If the legacy "origin" hasn't changed since last time, we try
...@@ -1744,7 +1745,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx, ...@@ -1744,7 +1745,7 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
if (pk->ameth->dirty_cnt(pk) == pk->dirty_cnt_copy) { if (pk->ameth->dirty_cnt(pk) == pk->dirty_cnt_copy) {
if (!CRYPTO_THREAD_read_lock(pk->lock)) if (!CRYPTO_THREAD_read_lock(pk->lock))
goto end; goto end;
i = evp_keymgmt_util_find_operation_cache_index(pk, tmp_keymgmt); op = evp_keymgmt_util_find_operation_cache(pk, tmp_keymgmt);
/* /*
* If |tmp_keymgmt| is present in the operation cache, it means * If |tmp_keymgmt| is present in the operation cache, it means
...@@ -1752,23 +1753,14 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx, ...@@ -1752,23 +1753,14 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
* token copies of the cached pointers, to have token success * token copies of the cached pointers, to have token success
* values to return. * values to return.
*/ */
if (i < OSSL_NELEM(pk->operation_cache) if (op != NULL && op->keymgmt != NULL) {
&& pk->operation_cache[i].keymgmt != NULL) { keydata = op->keydata;
keydata = pk->operation_cache[i].keydata;
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
goto end; goto end;
} }
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
} }
/*
* 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)))
goto end;
/* Make sure that the keymgmt key type matches the legacy NID */ /* Make sure that the keymgmt key type matches the legacy NID */
if (!ossl_assert(EVP_KEYMGMT_is_a(tmp_keymgmt, OBJ_nid2sn(pk->type)))) if (!ossl_assert(EVP_KEYMGMT_is_a(tmp_keymgmt, OBJ_nid2sn(pk->type))))
goto end; goto end;
...@@ -1806,8 +1798,19 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx, ...@@ -1806,8 +1798,19 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OSSL_LIB_CTX *libctx,
} }
EVP_KEYMGMT_free(tmp_keymgmt); /* refcnt-- */ EVP_KEYMGMT_free(tmp_keymgmt); /* refcnt-- */
/* Check to make sure some other thread didn't get there first */
op = evp_keymgmt_util_find_operation_cache(pk, tmp_keymgmt);
if (op != NULL && op->keymgmt != NULL) {
void *tmp_keydata = op->keydata;
CRYPTO_THREAD_unlock(pk->lock);
evp_keymgmt_freedata(tmp_keymgmt, keydata);
keydata = tmp_keydata;
goto end;
}
/* Add the new export to the operation cache */ /* Add the new export to the operation cache */
if (!evp_keymgmt_util_cache_keydata(pk, i, tmp_keymgmt, keydata)) { if (!evp_keymgmt_util_cache_keydata(pk, tmp_keymgmt, keydata)) {
CRYPTO_THREAD_unlock(pk->lock); CRYPTO_THREAD_unlock(pk->lock);
evp_keymgmt_freedata(tmp_keymgmt, keydata); evp_keymgmt_freedata(tmp_keymgmt, keydata);
keydata = NULL; keydata = NULL;
...@@ -1972,7 +1975,7 @@ int evp_pkey_downgrade(EVP_PKEY *pk) ...@@ -1972,7 +1975,7 @@ int evp_pkey_downgrade(EVP_PKEY *pk)
* reference count, so we need to decrement it, or there will be a * reference count, so we need to decrement it, or there will be a
* leak. * leak.
*/ */
evp_keymgmt_util_cache_keydata(pk, 0, tmp_copy.keymgmt, evp_keymgmt_util_cache_keydata(pk, tmp_copy.keymgmt,
tmp_copy.keydata); tmp_copy.keydata);
EVP_KEYMGMT_free(tmp_copy.keymgmt); EVP_KEYMGMT_free(tmp_copy.keymgmt);
......
...@@ -4,24 +4,27 @@ ...@@ -4,24 +4,27 @@
evp_keymgmt_util_export, evp_keymgmt_util_export,
evp_keymgmt_util_export_to_provider, evp_keymgmt_util_export_to_provider,
evp_keymgmt_util_find_operation_cache_index, evp_keymgmt_util_find_operation_cache,
evp_keymgmt_util_clear_operation_cache, evp_keymgmt_util_clear_operation_cache,
evp_keymgmt_util_cache_keydata, evp_keymgmt_util_cache_keydata,
evp_keymgmt_util_cache_keyinfo, evp_keymgmt_util_cache_keyinfo,
evp_keymgmt_util_fromdata evp_keymgmt_util_fromdata,
OP_CACHE_ELEM
- internal KEYMGMT utility functions - internal KEYMGMT utility functions
=head1 SYNOPSIS =head1 SYNOPSIS
#include "crypto/evp.h" #include "crypto/evp.h"
typedef struct OP_CACHE_ELEM;
int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection, int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection,
OSSL_CALLBACK *export_cb, void *export_cbarg); OSSL_CALLBACK *export_cb, void *export_cbarg);
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt); void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt);
size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk, OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk,
EVP_KEYMGMT *keymgmt); EVP_KEYMGMT *keymgmt);
int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking); int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking);
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); EVP_KEYMGMT *keymgmt, void *keydata);
void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk); void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk);
void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
...@@ -41,20 +44,17 @@ of all provider side keys. ...@@ -41,20 +44,17 @@ of all provider side keys.
To export a legacy key, use L<evp_pkey_export_to_provider(3)> instead, To export a legacy key, use L<evp_pkey_export_to_provider(3)> instead,
as this function ignores any legacy key data. as this function ignores any legacy key data.
evp_keymgmt_util_find_operation_cache_index() finds the location if evp_keymgmt_util_find_operation_cache() finds
I<keymgmt> in I<pk>'s cache of provided keys for operations. If I<keymgmt> in I<pk>'s cache of provided keys for operations.
I<keymgmt> is NULL or couldn't be found in the cache, it finds the It should only be called while holding I<pk>'s lock (read or write).
first empty slot instead if there is any. It should only be called while
holding I<pk>'s lock (read or write).
evp_keymgmt_util_clear_operation_cache() can be used to explicitly evp_keymgmt_util_clear_operation_cache() can be used to explicitly
clear the cache of operation key references. If I<locking> is set to 1 then clear the cache of operation key references. If I<locking> is set to 1 then
then I<pk>'s lock will be obtained while doing the clear. Otherwise it will be then I<pk>'s lock will be obtained while doing the clear. Otherwise it will be
assumed that the lock has already been obtained or is not required. assumed that the lock has already been obtained or is not required.
evp_keymgmt_util_cache_keydata() can be used to assign a provider key evp_keymgmt_util_cache_keydata() can be used to add a provider key
object to a specific cache slot in the given I<target>. object to a B<PKEY>.
I<Use extreme care>.
evp_keymgmt_util_cache_keyinfo() can be used to get all kinds of evp_keymgmt_util_cache_keyinfo() can be used to get all kinds of
information from the provvider "origin" and save it in I<pk>'s information from the provvider "origin" and save it in I<pk>'s
...@@ -70,10 +70,9 @@ evp_keymgmt_export_to_provider() and evp_keymgmt_util_fromdata() ...@@ -70,10 +70,9 @@ evp_keymgmt_export_to_provider() and evp_keymgmt_util_fromdata()
return a pointer to the appropriate provider side key (created or return a pointer to the appropriate provider side key (created or
found again), or NULL on error. found again), or NULL on error.
evp_keymgmt_util_find_operation_cache_index() returns the index of the evp_keymgmt_util_find_operation_cache() returns a pointer to the
operation cache slot. If I<keymgmt> is NULL, or if there is no slot operation cache slot. If I<keymgmt> is NULL, or if there is no slot
with a match for I<keymgmt>, the index of the first empty slot is with a match for I<keymgmt>, NULL is returned.
returned, or the maximum number of slots if there isn't an empty one.
evp_keymgmt_util_cache_keydata() and evp_keymgmt_util_clear_operation_cache() evp_keymgmt_util_cache_keydata() and evp_keymgmt_util_clear_operation_cache()
return 1 on success or 0 otherwise. return 1 on success or 0 otherwise.
......
...@@ -548,6 +548,23 @@ int evp_cipher_param_to_asn1_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type, ...@@ -548,6 +548,23 @@ int evp_cipher_param_to_asn1_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type, int evp_cipher_asn1_to_param_ex(EVP_CIPHER_CTX *c, ASN1_TYPE *type,
evp_cipher_aead_asn1_params *params); evp_cipher_aead_asn1_params *params);
/*
* To support transparent execution of operation in backends other
* than the "origin" key, we support transparent export/import to
* those providers, and maintain a cache of the imported keydata,
* so we don't need to redo the export/import every time we perform
* the same operation in that same provider.
* This requires that the "origin" backend (whether it's a legacy or a
* provider "origin") implements exports, and that the target provider
* has an EVP_KEYMGMT that implements import.
*/
typedef struct {
EVP_KEYMGMT *keymgmt;
void *keydata;
} OP_CACHE_ELEM;
DEFINE_STACK_OF(OP_CACHE_ELEM)
/* /*
* An EVP_PKEY can have the following states: * An EVP_PKEY can have the following states:
* *
...@@ -644,18 +661,9 @@ struct evp_pkey_st { ...@@ -644,18 +661,9 @@ struct evp_pkey_st {
* those providers, and maintain a cache of the imported keydata, * those providers, and maintain a cache of the imported keydata,
* so we don't need to redo the export/import every time we perform * so we don't need to redo the export/import every time we perform
* the same operation in that same provider. * the same operation in that same provider.
* This requires that the "origin" backend (whether it's a legacy or a
* provider "origin") implements exports, and that the target provider
* has an EVP_KEYMGMT that implements import.
*
* The cache limit is set at 10 different providers using the same
* "origin". It's probably over the top, but is preferable to too
* few.
*/ */
struct { STACK_OF(OP_CACHE_ELEM) *operation_cache;
EVP_KEYMGMT *keymgmt;
void *keydata;
} operation_cache[10];
/* /*
* We keep a copy of that "origin"'s dirty count, so we know if the * We keep a copy of that "origin"'s dirty count, so we know if the
* operation cache needs flushing. * operation cache needs flushing.
...@@ -726,10 +734,10 @@ EVP_PKEY *evp_keymgmt_util_make_pkey(EVP_KEYMGMT *keymgmt, void *keydata); ...@@ -726,10 +734,10 @@ EVP_PKEY *evp_keymgmt_util_make_pkey(EVP_KEYMGMT *keymgmt, void *keydata);
int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection, int evp_keymgmt_util_export(const EVP_PKEY *pk, int selection,
OSSL_CALLBACK *export_cb, void *export_cbarg); OSSL_CALLBACK *export_cb, void *export_cbarg);
void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt); void *evp_keymgmt_util_export_to_provider(EVP_PKEY *pk, EVP_KEYMGMT *keymgmt);
size_t evp_keymgmt_util_find_operation_cache_index(EVP_PKEY *pk, OP_CACHE_ELEM *evp_keymgmt_util_find_operation_cache(EVP_PKEY *pk,
EVP_KEYMGMT *keymgmt); EVP_KEYMGMT *keymgmt);
int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking); int evp_keymgmt_util_clear_operation_cache(EVP_PKEY *pk, int locking);
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); EVP_KEYMGMT *keymgmt, void *keydata);
void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk); void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk);
void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册