mirror of
https://github.com/openssl/openssl.git
synced 2024-11-21 01:15:20 +08:00
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)
This commit is contained in:
parent
33561e0d5b
commit
5246183e7a
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user