提交 5246183e 编写于 作者: R Richard Levitte

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: NTomas Mraz <tomas@openssl.org>
Reviewed-by: NMatt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/16725)
上级 33561e0d
...@@ -40,55 +40,53 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -40,55 +40,53 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
goto legacy; goto legacy;
/* /*
* Ensure that the key is provided, either natively, or as a cached export. * Try to derive the supported asym cipher from |ctx->keymgmt|.
* If not, go legacy
*/ */
tmp_keymgmt = ctx->keymgmt; if (!ossl_assert(ctx->pkey->keymgmt == NULL
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, || ctx->pkey->keymgmt == ctx->keymgmt)) {
&tmp_keymgmt, ctx->propquery); ERR_clear_last_mark();
if (provkey == NULL) ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
goto legacy; goto err;
if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { }
supported_ciph
= evp_keymgmt_util_query_operation_name(ctx->keymgmt,
OSSL_OP_ASYM_CIPHER);
if (supported_ciph == NULL) {
ERR_clear_last_mark(); ERR_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; 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 * Because we cleared out old ops, we shouldn't need to worry about
* checking if cipher is already there. * checking if cipher is already there.
*/ */
cipher = cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph,
EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph, ctx->propquery); ctx->propquery);
if (cipher == NULL 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);
goto legacy; goto legacy;
}
/* /*
* If we don't have the full support we need with provided methods, * Ensure that the key is provided, either natively, or as a cached export.
* let's go see if legacy does. * 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(); ERR_pop_to_mark();
/* No more legacy from here down to legacy: */ /* 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, ...@@ -125,6 +123,7 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
if (ret <= 0) if (ret <= 0)
goto err; goto err;
EVP_KEYMGMT_free(tmp_keymgmt);
return 1; return 1;
legacy: legacy:
...@@ -133,6 +132,8 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -133,6 +132,8 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
* let's go see if legacy does. * let's go see if legacy does.
*/ */
ERR_pop_to_mark(); ERR_pop_to_mark();
EVP_KEYMGMT_free(tmp_keymgmt);
tmp_keymgmt = NULL;
if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) { if (ctx->pmeth == NULL || ctx->pmeth->encrypt == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); 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, ...@@ -159,6 +160,7 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
evp_pkey_ctx_free_old_ops(ctx); evp_pkey_ctx_free_old_ops(ctx);
ctx->operation = EVP_PKEY_OP_UNDEFINED; ctx->operation = EVP_PKEY_OP_UNDEFINED;
} }
EVP_KEYMGMT_free(tmp_keymgmt);
return ret; return ret;
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <openssl/crypto.h> #include <openssl/crypto.h>
#include <openssl/evp.h> #include <openssl/evp.h>
#include <openssl/err.h> #include <openssl/err.h>
#include "internal/cryptlib.h"
#include "internal/refcount.h" #include "internal/refcount.h"
#include "internal/provider.h" #include "internal/provider.h"
#include "internal/core.h" #include "internal/core.h"
...@@ -207,73 +208,69 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) ...@@ -207,73 +208,69 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
goto legacy; goto legacy;
/* /*
* Ensure that the key is provided, either natively, or as a cached export. * Some algorithms (e.g. legacy KDFs) don't have a pkey - so we create
* If not, goto legacy * a blank one.
*/ */
tmp_keymgmt = ctx->keymgmt;
if (ctx->pkey == NULL) { 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(); 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(); ERR_clear_last_mark();
EVP_PKEY_free(pkey); EVP_PKEY_free(pkey);
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; goto err;
} }
provkey = pkey->keydata = evp_keymgmt_newdata(tmp_keymgmt); ctx->pkey = pkey;
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);
} }
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_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; 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 * Because we cleared out old ops, we shouldn't need to worry about
* checking if exchange is already there. * checking if exchange is already there.
*/ */
exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery); exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
if (exchange == NULL)
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);
goto legacy; goto legacy;
}
/* /*
* If we don't have the full support we need with provided methods, * Ensure that the key is provided, either natively, or as a cached export.
* let's go see if legacy does. * 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(); ERR_pop_to_mark();
/* No more legacy from here down to legacy: */ /* 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[]) ...@@ -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); ret = exchange->init(ctx->op.kex.algctx, provkey, params);
EVP_KEYMGMT_free(tmp_keymgmt);
return ret ? 1 : 0; return ret ? 1 : 0;
err: err:
evp_pkey_ctx_free_old_ops(ctx); evp_pkey_ctx_free_old_ops(ctx);
ctx->operation = EVP_PKEY_OP_UNDEFINED; ctx->operation = EVP_PKEY_OP_UNDEFINED;
EVP_KEYMGMT_free(tmp_keymgmt);
return 0; return 0;
legacy: legacy:
...@@ -313,6 +312,7 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[]) ...@@ -313,6 +312,7 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
ret = ctx->pmeth->derive_init(ctx); ret = ctx->pmeth->derive_init(ctx);
if (ret <= 0) if (ret <= 0)
ctx->operation = EVP_PKEY_OP_UNDEFINED; ctx->operation = EVP_PKEY_OP_UNDEFINED;
EVP_KEYMGMT_free(tmp_keymgmt);
return ret; return ret;
#endif #endif
} }
......
...@@ -35,37 +35,49 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -35,37 +35,49 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
ctx->operation = 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; if (!ossl_assert(ctx->pkey->keymgmt == NULL
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, || ctx->pkey->keymgmt == ctx->keymgmt)) {
&tmp_keymgmt, ctx->propquery); ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
if (provkey == NULL goto err;
|| !EVP_KEYMGMT_up_ref(tmp_keymgmt)) { }
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); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; 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); kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
if (kem == NULL if (kem == NULL) {
|| (EVP_KEYMGMT_get0_provider(ctx->keymgmt) != EVP_KEM_get0_provider(kem))) {
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
ret = -2; ret = -2;
goto err; 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.kem = kem;
ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov)); ctx->op.encap.algctx = kem->newctx(ossl_provider_ctx(kem->prov));
if (ctx->op.encap.algctx == NULL) { if (ctx->op.encap.algctx == NULL) {
...@@ -96,6 +108,9 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -96,6 +108,9 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
goto err; goto err;
} }
EVP_KEYMGMT_free(tmp_keymgmt);
tmp_keymgmt = NULL;
if (ret > 0) if (ret > 0)
return 1; return 1;
err: err:
...@@ -103,6 +118,7 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -103,6 +118,7 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
evp_pkey_ctx_free_old_ops(ctx); evp_pkey_ctx_free_old_ops(ctx);
ctx->operation = EVP_PKEY_OP_UNDEFINED; ctx->operation = EVP_PKEY_OP_UNDEFINED;
} }
EVP_KEYMGMT_free(tmp_keymgmt);
return ret; return ret;
} }
......
...@@ -562,3 +562,22 @@ int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt, ...@@ -562,3 +562,22 @@ int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt,
OPENSSL_strlcpy(mdname, result, mdname_sz); OPENSSL_strlcpy(mdname, result, mdname_sz);
return rv; 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;
}
...@@ -81,34 +81,21 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, ...@@ -81,34 +81,21 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
goto legacy; 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; if (!ossl_assert(locpctx->pkey->keymgmt == NULL
provkey = evp_pkey_export_to_provider(locpctx->pkey, locpctx->libctx, || locpctx->pkey->keymgmt == locpctx->keymgmt)) {
&tmp_keymgmt, locpctx->propquery);
if (provkey == NULL) {
ERR_clear_last_mark(); ERR_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
goto err; 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_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; 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 * 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, ...@@ -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, signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
locpctx->propquery); locpctx->propquery);
if (signature == NULL 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);
goto legacy; goto legacy;
}
/* /*
* If we don't have the full support we need with provided methods, * Ensure that the key is provided, either natively, or as a cached export.
* let's go see if legacy does. * 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(); ERR_pop_to_mark();
/* No more legacy from here down to legacy: */ /* 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, ...@@ -221,6 +219,7 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
err: err:
evp_pkey_ctx_free_old_ops(locpctx); evp_pkey_ctx_free_old_ops(locpctx);
locpctx->operation = EVP_PKEY_OP_UNDEFINED; locpctx->operation = EVP_PKEY_OP_UNDEFINED;
EVP_KEYMGMT_free(tmp_keymgmt);
return 0; return 0;
legacy: legacy:
...@@ -229,6 +228,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, ...@@ -229,6 +228,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
* let's go see if legacy does. * let's go see if legacy does.
*/ */
ERR_pop_to_mark(); ERR_pop_to_mark();
EVP_KEYMGMT_free(tmp_keymgmt);
tmp_keymgmt = NULL;
if (type == NULL && mdname != NULL) if (type == NULL && mdname != NULL)
type = evp_get_digestbyname_ex(locpctx->libctx, mdname); 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, ...@@ -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); ret = evp_pkey_ctx_use_cached_data(locpctx);
#endif #endif
EVP_KEYMGMT_free(tmp_keymgmt);
return ret > 0 ? 1 : 0; return ret > 0 ? 1 : 0;
} }
......
...@@ -265,7 +265,20 @@ static EVP_PKEY_CTX *int_ctx_new(OSSL_LIB_CTX *libctx, ...@@ -265,7 +265,20 @@ static EVP_PKEY_CTX *int_ctx_new(OSSL_LIB_CTX *libctx,
* fetching a provider implementation. * fetching a provider implementation.
*/ */
if (e == NULL && app_pmeth == NULL && keytype != NULL) { 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) if (keymgmt == NULL)
return NULL; /* EVP_KEYMGMT_fetch() recorded an error */ return NULL; /* EVP_KEYMGMT_fetch() recorded an error */
......
...@@ -402,31 +402,21 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -402,31 +402,21 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
goto legacy; goto legacy;
/* /*
* Ensure that the key is provided, either natively, or as a cached export. * Try to derive the supported signature from |ctx->keymgmt|.
* If not, go legacy
*/ */
tmp_keymgmt = ctx->keymgmt; if (!ossl_assert(ctx->pkey->keymgmt == NULL
provkey = evp_pkey_export_to_provider(ctx->pkey, ctx->libctx, || ctx->pkey->keymgmt == ctx->keymgmt)) {
&tmp_keymgmt, ctx->propquery); ERR_clear_last_mark();
if (tmp_keymgmt == NULL) ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
goto legacy; goto err;
if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) { }
supported_sig = evp_keymgmt_util_query_operation_name(ctx->keymgmt,
OSSL_OP_SIGNATURE);
if (supported_sig == NULL) {
ERR_clear_last_mark(); ERR_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err; 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 * 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, ...@@ -435,21 +425,29 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
signature = signature =
EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery); EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
if (signature == NULL 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);
goto legacy; goto legacy;
}
/* /*
* If we don't have the full support we need with provided methods, * Ensure that the key is provided, either natively, or as a cached export.
* let's go see if legacy does. * 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(); ERR_pop_to_mark();
/* No more legacy from here down to legacy: */ /* No more legacy from here down to legacy: */
...@@ -507,6 +505,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation, ...@@ -507,6 +505,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
* let's go see if legacy does. * let's go see if legacy does.
*/ */
ERR_pop_to_mark(); ERR_pop_to_mark();
EVP_KEYMGMT_free(tmp_keymgmt);
tmp_keymgmt = NULL;
if (ctx->pmeth == NULL if (ctx->pmeth == NULL
|| (operation == EVP_PKEY_OP_SIGN && ctx->pmeth->sign == 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, ...@@ -545,10 +545,12 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
ret = evp_pkey_ctx_use_cached_data(ctx); ret = evp_pkey_ctx_use_cached_data(ctx);
#endif #endif
EVP_KEYMGMT_free(tmp_keymgmt);
return ret; return ret;
err: err:
evp_pkey_ctx_free_old_ops(ctx); evp_pkey_ctx_free_old_ops(ctx);
ctx->operation = EVP_PKEY_OP_UNDEFINED; ctx->operation = EVP_PKEY_OP_UNDEFINED;
EVP_KEYMGMT_free(tmp_keymgmt);
return ret; return ret;
} }
......
...@@ -38,6 +38,7 @@ struct evp_pkey_ctx_st { ...@@ -38,6 +38,7 @@ struct evp_pkey_ctx_st {
OSSL_LIB_CTX *libctx; OSSL_LIB_CTX *libctx;
char *propquery; char *propquery;
const char *keytype; const char *keytype;
/* If |pkey| below is set, this field is always a reference to its keymgmt */
EVP_KEYMGMT *keymgmt; EVP_KEYMGMT *keymgmt;
union { union {
...@@ -794,6 +795,8 @@ void *evp_keymgmt_util_gen(EVP_PKEY *target, EVP_KEYMGMT *keymgmt, ...@@ -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, int evp_keymgmt_util_get_deflt_digest_name(EVP_KEYMGMT *keymgmt,
void *keydata, void *keydata,
char *mdname, size_t mdname_sz); char *mdname, size_t mdname_sz);
const char *evp_keymgmt_util_query_operation_name(EVP_KEYMGMT *keymgmt,
int op_id);
/* /*
* KEYMGMT provider interface functions * KEYMGMT provider interface functions
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册