summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crypto/evp/asymcipher.c70
-rw-r--r--crypto/evp/exchange.c84
-rw-r--r--crypto/evp/kem.c56
-rw-r--r--crypto/evp/keymgmt_lib.c19
-rw-r--r--crypto/evp/m_sigver.c64
-rw-r--r--crypto/evp/pmeth_lib.c15
-rw-r--r--crypto/evp/signature.c64
-rw-r--r--include/crypto/evp.h3
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