diff options
author | Richard Levitte <levitte@openssl.org> | 2021-10-01 08:57:03 +0200 |
---|---|---|
committer | Richard Levitte <levitte@openssl.org> | 2021-10-27 12:41:12 +0200 |
commit | 5246183e7a9f9fb1819d50ab40e2fecc68235e0d (patch) | |
tree | 408f58790a0348bb654ac8be3094832b153aab67 | |
parent | 33561e0d5b89a06d1c03b952196d008b5014914a (diff) |
EVP: Reverse the fetch logic in all pkey using functionality
In all initializing functions for functionality that use an EVP_PKEY, the
coded logic was to find an KEYMGMT implementation first, and then try to
find the operation method (for example, SIGNATURE implementation) in the
same provider.
This implies that in providers where there is a KEYMGMT implementation,
there must also be a SIGNATURE implementation, along with a KEYEXCH,
ASYM_CIPHER, etc implementation.
The intended design was, however, the opposite implication, i.e. that
where there is a SIGNATURE implementation, there must also be KEYMGMT.
This change reverses the logic of the code to be closer to the intended
design.
There is a consequence; we now use the query_operation_name function from
the KEYMGMT of the EVP_PKEY given by the EVP_PKEY_CTX (ultimately given by
the application). Previously, we used the query_operation_name function
from the KEYMGMT found alongside the SIGNATURE implementation.
Another minor consequence is that the |keymgmt| field in EVP_PKEY_CTX
is now always a reference to the KEYMGMT of the |pkey| field if that
one is given (|pkey| isn't NULL) and is provided (|pkey->keymgmt|
isn't NULL).
Fixes #16614
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16725)
-rw-r--r-- | crypto/evp/asymcipher.c | 70 | ||||
-rw-r--r-- | crypto/evp/exchange.c | 84 | ||||
-rw-r--r-- | crypto/evp/kem.c | 56 | ||||
-rw-r--r-- | crypto/evp/keymgmt_lib.c | 19 | ||||
-rw-r--r-- | crypto/evp/m_sigver.c | 64 | ||||
-rw-r--r-- | crypto/evp/pmeth_lib.c | 15 | ||||
-rw-r--r-- | crypto/evp/signature.c | 64 | ||||
-rw-r--r-- | include/crypto/evp.h | 3 |
8 files changed, 216 insertions, 159 deletions
diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c index 3150bfa94b..41aea6b1d8 100644 --- a/crypto/evp/asymcipher.c +++ b/crypto/evp/asymcipher.c @@ -40,55 +40,53 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, goto legacy; /* - * Ensure that the key is provided, either natively, or as a cached export. - * If not, go legacy + * Try to derive the supported asym cipher from |ctx->keymgmt|. */ - tmp_keymgmt = ctx->keymgmt; - provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, - &tmp_keymgmt, ctx->propquery); - if (provkey == NULL) - goto legacy; - if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { + if (!ossl_assert(ctx->pkey->keymgmt == NULL + || ctx->pkey->keymgmt == ctx->keymgmt)) { + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + goto err; + } + supported_ciph + = evp_keymgmt_util_query_operation_name(ctx->keymgmt, + OSSL_OP_ASYM_CIPHER); + if (supported_ciph == NULL) { ERR_clear_last_mark(); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - EVP_KEYMGMT_free(ctx->keymgmt); - ctx->keymgmt = tmp_keymgmt; - - if (ctx->keymgmt->query_operation_name != NULL) - supported_ciph = - ctx->keymgmt->query_operation_name(OSSL_OP_ASYM_CIPHER); - - /* - * If we didn't get a supported ciph, assume there is one with the - * same name as the key type. - */ - if (supported_ciph == NULL) - supported_ciph = ctx->keytype; /* * Because we cleared out old ops, we shouldn't need to worry about * checking if cipher is already there. */ - cipher = - EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery); + cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, + ctx->propquery); - if (cipher == NULL - || (EVP_KEYMGMT_get0_provider(ctx->keymgmt) - != EVP_ASYM_CIPHER_get0_provider(cipher))) { - /* - * We don't need to free ctx->keymgmt here, as it's not necessarily - * tied to this operation. It will be freed by EVP_PKEY_CTX_free(). - */ - EVP_ASYM_CIPHER_free(cipher); + if (cipher == NULL) goto legacy; - } /* - * If we don't have the full support we need with provided methods, - * let's go see if legacy does. + * Ensure that the key is provided, either natively, or as a cached export. + * We start by fetching the keymgmt with the same name as |ctx->pkey|, + * but from the provider of the asym cipher method, using the same property + * query as when fetching the asym cipher method. + * With the keymgmt we found (if we did), we try to export |ctx->pkey| + * to it (evp_pkey_export_to_provider() is smart enough to only actually + + * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt) */ + tmp_keymgmt + = evp_keymgmt_fetch_from_prov(EVP_ASYM_CIPHER_get0_provider(cipher), + EVP_KEYMGMT_get0_name(ctx->keymgmt), + ctx->propquery); + if (tmp_keymgmt != NULL) + provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, + &tmp_keymgmt, ctx->propquery); + if (provkey == NULL) + goto legacy; + ERR_pop_to_mark(); /* No more legacy from here down to legacy: */ @@ -125,6 +123,7 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, if (ret <= 0) goto err; + EVP_KEYMGMT_free(tmp_keymgmt); return 1; legacy: @@ -133,6 +132,8 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, * let's go see if legacy does. */ ERR_pop_to_mark(); + EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); @@ -159,6 +160,7 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_UNDEFINED; } + EVP_KEYMGMT_free(tmp_keymgmt); return ret; } diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c index ca8a049a1b..14e734dde8 100644 --- a/crypto/evp/exchange.c +++ b/crypto/evp/exchange.c @@ -10,6 +10,7 @@ #include <openssl/crypto.h> #include <openssl/evp.h> #include <openssl/err.h> +#include "internal/cryptlib.h" #include "internal/refcount.h" #include "internal/provider.h" #include "internal/core.h" @@ -207,73 +208,69 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) goto legacy; /* - * Ensure that the key is provided, either natively, or as a cached export. - * If not, goto legacy + * Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create + * a blank one. */ - tmp_keymgmt = ctx->keymgmt; if (ctx->pkey == NULL) { - /* - * Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create - * a blank one. - */ EVP_PKEY *pkey = EVP_PKEY_new(); - if (pkey == NULL || !EVP_PKEY_set_type_by_keymgmt(pkey, tmp_keymgmt)) { + if (pkey == NULL + || !EVP_PKEY_set_type_by_keymgmt(pkey, ctx->keymgmt) + || (pkey->keydata = evp_keymgmt_newdata(ctx->keymgmt)) == NULL) { ERR_clear_last_mark(); EVP_PKEY_free(pkey); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - provkey = pkey->keydata = evp_keymgmt_newdata(tmp_keymgmt); - if (provkey == NULL) - EVP_PKEY_free(pkey); - else - ctx->pkey = pkey; - } else { - provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, - &tmp_keymgmt, ctx->propquery); + ctx->pkey = pkey; } - if (provkey == NULL) - goto legacy; - if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { + + /* + * Try to derive the supported exch from |ctx->keymgmt|. + */ + if (!ossl_assert(ctx->pkey->keymgmt == NULL + || ctx->pkey->keymgmt == ctx->keymgmt)) { + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + goto err; + } + supported_exch = evp_keymgmt_util_query_operation_name(ctx->keymgmt, + OSSL_OP_KEYEXCH); + if (supported_exch == NULL) { ERR_clear_last_mark(); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - EVP_KEYMGMT_free(ctx->keymgmt); - ctx->keymgmt = tmp_keymgmt; - if (ctx->keymgmt->query_operation_name != NULL) - supported_exch = ctx->keymgmt->query_operation_name(OSSL_OP_KEYEXCH); - - /* - * If we didn't get a supported exch, assume there is one with the - * same name as the key type. - */ - if (supported_exch == NULL) - supported_exch = ctx->keytype; /* * Because we cleared out old ops, we shouldn't need to worry about * checking if exchange is already there. */ exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery); - - if (exchange == NULL - || (EVP_KEYMGMT_get0_provider(ctx->keymgmt) - != EVP_KEYEXCH_get0_provider(exchange))) { - /* - * We don't need to free ctx->keymgmt here, as it's not necessarily - * tied to this operation. It will be freed by EVP_PKEY_CTX_free(). - */ - EVP_KEYEXCH_free(exchange); + if (exchange == NULL) goto legacy; - } /* - * If we don't have the full support we need with provided methods, - * let's go see if legacy does. + * Ensure that the key is provided, either natively, or as a cached export. + * We start by fetching the keymgmt with the same name as |ctx->pkey|, + * but from the provider of the exch method, using the same property + * query as when fetching the exch method. + * With the keymgmt we found (if we did), we try to export |ctx->pkey| + * to it (evp_pkey_export_to_provider() is smart enough to only actually + + * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt) */ + tmp_keymgmt + = evp_keymgmt_fetch_from_prov(EVP_KEYEXCH_get0_provider(exchange), + EVP_KEYMGMT_get0_name(ctx->keymgmt), + ctx->propquery); + if (tmp_keymgmt != NULL) + provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, + &tmp_keymgmt, ctx->propquery); + if (provkey == NULL) + goto legacy; + ERR_pop_to_mark(); /* No more legacy from here down to legacy: */ @@ -287,10 +284,12 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) } ret = exchange->init(ctx->op.kex.algctx, provkey, params); + EVP_KEYMGMT_free(tmp_keymgmt); return ret ? 1 : 0; err: evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_UNDEFINED; + EVP_KEYMGMT_free(tmp_keymgmt); return 0; legacy: @@ -313,6 +312,7 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) ret = ctx->pmeth->derive_init(ctx); if (ret <= 0) ctx->operation = EVP_PKEY_OP_UNDEFINED; + EVP_KEYMGMT_free(tmp_keymgmt); return ret; #endif } diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c index cb904a6b26..0640e31144 100644 --- a/crypto/evp/kem.c +++ b/crypto/evp/kem.c @@ -35,37 +35,49 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, ctx->operation = operation; /* - * Ensure that the key is provided, either natively, or as a cached export. + * Try to derive the supported kem from |ctx->keymgmt|. */ - tmp_keymgmt = ctx->keymgmt; - provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, - &tmp_keymgmt, ctx->propquery); - if (provkey == NULL - || !EVP_KEYMGMT_up_ref(tmp_keymgmt)) { + if (!ossl_assert(ctx->pkey->keymgmt == NULL + || ctx->pkey->keymgmt == ctx->keymgmt)) { + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + goto err; + } + supported_kem = evp_keymgmt_util_query_operation_name(ctx->keymgmt, + OSSL_OP_KEM); + if (supported_kem == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - EVP_KEYMGMT_free(ctx->keymgmt); - ctx->keymgmt = tmp_keymgmt; - - if (ctx->keymgmt->query_operation_name != NULL) - supported_kem = ctx->keymgmt->query_operation_name(OSSL_OP_KEM); - - /* - * If we didn't get a supported kem, assume there is one with the - * same name as the key type. - */ - if (supported_kem == NULL) - supported_kem = ctx->keytype; kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery); - if (kem == NULL - || (EVP_KEYMGMT_get0_provider(ctx->keymgmt) != EVP_KEM_get0_provider(kem))) { + if (kem == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); ret = -2; goto err; } + /* + * Ensure that the key is provided, either natively, or as a cached export. + * We start by fetching the keymgmt with the same name as |ctx->pkey|, + * but from the provider of the kem method, using the same property + * query as when fetching the kem method. + * With the keymgmt we found (if we did), we try to export |ctx->pkey| + * to it (evp_pkey_export_to_provider() is smart enough to only actually + + * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt) + */ + tmp_keymgmt + = evp_keymgmt_fetch_from_prov(EVP_KEM_get0_provider(kem), + EVP_KEYMGMT_get0_name(ctx->keymgmt), + ctx->propquery); + if (tmp_keymgmt != NULL) + provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, + &tmp_keymgmt, ctx->propquery); + if (provkey == NULL) { + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + goto err; + } + ctx->op.encap.kem = kem; ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov)); if (ctx->op.encap.algctx == NULL) { @@ -96,6 +108,9 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, goto err; } + EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; + if (ret > 0) return 1; err: @@ -103,6 +118,7 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_UNDEFINED; } + EVP_KEYMGMT_free(tmp_keymgmt); return ret; } diff --git a/crypto/evp/keymgmt_lib.c b/crypto/evp/keymgmt_lib.c index 875c9a83de..2a73e9a2be 100644 --- a/crypto/evp/keymgmt_lib.c +++ b/crypto/evp/keymgmt_lib.c @@ -562,3 +562,22 @@ int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt, OPENSSL_strlcpy(mdname, result, mdname_sz); return rv; } + +/* + * If |keymgmt| has the method function |query_operation_name|, use it to get + * the name of a supported operation identity. Otherwise, return the keytype, + * assuming that it works as a default operation name. + */ +const char *evp_keymgmt_util_query_operation_name(EVP_KEYMGMT *keymgmt, + int op_id) +{ + const char *name = NULL; + + if (keymgmt != NULL) { + if (keymgmt->query_operation_name != NULL) + name = keymgmt->query_operation_name(op_id); + if (name == NULL) + name = EVP_KEYMGMT_get0_name(keymgmt); + } + return name; +} diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c index 70669c3e6d..55675c36e1 100644 --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -81,34 +81,21 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, goto legacy; /* - * Ensure that the key is provided, either natively, or as a cached export. + * Try to derive the supported signature from |locpctx->keymgmt|. */ - tmp_keymgmt = locpctx->keymgmt; - provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx, - &tmp_keymgmt, locpctx->propquery); - if (provkey == NULL) { + if (!ossl_assert(locpctx->pkey->keymgmt == NULL + || locpctx->pkey->keymgmt == locpctx->keymgmt)) { ERR_clear_last_mark(); - ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); goto err; } - if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { + supported_sig = evp_keymgmt_util_query_operation_name(locpctx->keymgmt, + OSSL_OP_SIGNATURE); + if (supported_sig == NULL) { ERR_clear_last_mark(); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - EVP_KEYMGMT_free(locpctx->keymgmt); - locpctx->keymgmt = tmp_keymgmt; - - if (locpctx->keymgmt->query_operation_name != NULL) - supported_sig = - locpctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE); - - /* - * If we didn't get a supported sig, assume there is one with the - * same name as the key type. - */ - if (supported_sig == NULL) - supported_sig = locpctx->keytype; /* * Because we cleared out old ops, we shouldn't need to worry about @@ -117,21 +104,32 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig, locpctx->propquery); - if (signature == NULL - || (EVP_KEYMGMT_get0_provider(locpctx->keymgmt) - != EVP_SIGNATURE_get0_provider(signature))) { - /* - * We don't need to free ctx->keymgmt here, as it's not necessarily - * tied to this operation. It will be freed by EVP_PKEY_CTX_free(). - */ - EVP_SIGNATURE_free(signature); + if (signature == NULL) goto legacy; - } /* - * If we don't have the full support we need with provided methods, - * let's go see if legacy does. + * Ensure that the key is provided, either natively, or as a cached export. + * We start by fetching the keymgmt with the same name as |locpctx->pkey|, + * but from the provider of the signature method, using the same property + * query as when fetching the signature method. + * With the keymgmt we found (if we did), we try to export |locpctx->pkey| + * to it (evp_pkey_export_to_provider() is smart enough to only actually + + * export it if |tmp_keymgmt| is different from |locpctx->pkey|'s keymgmt) */ + tmp_keymgmt + = evp_keymgmt_fetch_from_prov(EVP_SIGNATURE_get0_provider(signature), + EVP_KEYMGMT_get0_name(locpctx->keymgmt), + locpctx->propquery); + if (tmp_keymgmt != NULL) + provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx, + &tmp_keymgmt, locpctx->propquery); + if (provkey == NULL) { + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + goto err; + } + ERR_pop_to_mark(); /* No more legacy from here down to legacy: */ @@ -221,6 +219,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, err: evp_pkey_ctx_free_old_ops(locpctx); locpctx->operation = EVP_PKEY_OP_UNDEFINED; + EVP_KEYMGMT_free(tmp_keymgmt); return 0; legacy: @@ -229,6 +228,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, * let's go see if legacy does. */ ERR_pop_to_mark(); + EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; if (type == NULL && mdname != NULL) type = evp_get_digestbyname_ex(locpctx->libctx, mdname); @@ -299,6 +300,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, ret = evp_pkey_ctx_use_cached_data(locpctx); #endif + EVP_KEYMGMT_free(tmp_keymgmt); return ret > 0 ? 1 : 0; } diff --git a/crypto/evp/pmeth_lib.c b/crypto/evp/pmeth_lib.c index 1af1628823..2b9c6c2351 100644 --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -265,7 +265,20 @@ static EVP_PKEY_CTX *int_ctx_new(OSSL_LIB_CTX *libctx, * fetching a provider implementation. */ if (e == NULL && app_pmeth == NULL && keytype != NULL) { - keymgmt = EVP_KEYMGMT_fetch(libctx, keytype, propquery); + /* + * If |pkey| is given and is provided, we take a reference to its + * keymgmt. Otherwise, we fetch one for the keytype we got. This + * is to ensure that operation init functions can access what they + * need through this single pointer. + */ + if (pkey != NULL && pkey->keymgmt != NULL) { + if (!EVP_KEYMGMT_up_ref(pkey->keymgmt)) + ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); + else + keymgmt = pkey->keymgmt; + } else { + keymgmt = EVP_KEYMGMT_fetch(libctx, keytype, propquery); + } if (keymgmt == NULL) return NULL; /* EVP_KEYMGMT_fetch() recorded an error */ diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c index b636889c3b..b893a2fc12 100644 --- a/crypto/evp/signature.c +++ b/crypto/evp/signature.c @@ -402,31 +402,21 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, goto legacy; /* - * Ensure that the key is provided, either natively, or as a cached export. - * If not, go legacy + * Try to derive the supported signature from |ctx->keymgmt|. */ - tmp_keymgmt = ctx->keymgmt; - provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, - &tmp_keymgmt, ctx->propquery); - if (tmp_keymgmt == NULL) - goto legacy; - if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { + if (!ossl_assert(ctx->pkey->keymgmt == NULL + || ctx->pkey->keymgmt == ctx->keymgmt)) { + ERR_clear_last_mark(); + ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR); + goto err; + } + supported_sig = evp_keymgmt_util_query_operation_name(ctx->keymgmt, + OSSL_OP_SIGNATURE); + if (supported_sig == NULL) { ERR_clear_last_mark(); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); goto err; } - EVP_KEYMGMT_free(ctx->keymgmt); - ctx->keymgmt = tmp_keymgmt; - - if (ctx->keymgmt->query_operation_name != NULL) - supported_sig = ctx->keymgmt->query_operation_name(OSSL_OP_SIGNATURE); - - /* - * If we didn't get a supported sig, assume there is one with the - * same name as the key type. - */ - if (supported_sig == NULL) - supported_sig = ctx->keytype; /* * Because we cleared out old ops, we shouldn't need to worry about @@ -435,21 +425,29 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, signature = EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery); - if (signature == NULL - || (EVP_KEYMGMT_get0_provider(ctx->keymgmt) - != EVP_SIGNATURE_get0_provider(signature))) { - /* - * We don't need to free ctx->keymgmt here, as it's not necessarily - * tied to this operation. It will be freed by EVP_PKEY_CTX_free(). - */ - EVP_SIGNATURE_free(signature); + if (signature == NULL) goto legacy; - } /* - * If we don't have the full support we need with provided methods, - * let's go see if legacy does. + * Ensure that the key is provided, either natively, or as a cached export. + * We start by fetching the keymgmt with the same name as |ctx->pkey|, + * but from the provider of the signature method, using the same property + * query as when fetching the signature method. + * With the keymgmt we found (if we did), we try to export |ctx->pkey| + * to it (evp_pkey_export_to_provider() is smart enough to only actually + + * export it if |tmp_keymgmt| is different from |ctx->pkey|'s keymgmt) */ + tmp_keymgmt + = evp_keymgmt_fetch_from_prov(EVP_SIGNATURE_get0_provider(signature), + EVP_KEYMGMT_get0_name(ctx->keymgmt), + ctx->propquery); + if (tmp_keymgmt != NULL) + provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, + &tmp_keymgmt, ctx->propquery); + if (provkey == NULL) + goto legacy; + ERR_pop_to_mark(); /* No more legacy from here down to legacy: */ @@ -507,6 +505,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, * let's go see if legacy does. */ ERR_pop_to_mark(); + EVP_KEYMGMT_free(tmp_keymgmt); + tmp_keymgmt = NULL; if (ctx->pmeth == NULL || (operation == EVP_PKEY_OP_SIGN && ctx->pmeth->sign == NULL) @@ -545,10 +545,12 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, ret = evp_pkey_ctx_use_cached_data(ctx); #endif + EVP_KEYMGMT_free(tmp_keymgmt); return ret; err: evp_pkey_ctx_free_old_ops(ctx); ctx->operation = EVP_PKEY_OP_UNDEFINED; + EVP_KEYMGMT_free(tmp_keymgmt); return ret; } diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 41ac80ed9d..c5d3a930f7 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -38,6 +38,7 @@ struct evp_pkey_ctx_st { OSSL_LIB_CTX *libctx; char *propquery; const char *keytype; + /* If |pkey| below is set, this field is always a reference to its keymgmt */ EVP_KEYMGMT *keymgmt; union { @@ -794,6 +795,8 @@ void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt, void *keydata, char *mdname, size_t mdname_sz); +const char *evp_keymgmt_util_query_operation_name(EVP_KEYMGMT *keymgmt, + int op_id); /* * KEYMGMT provider interface functions |