summaryrefslogtreecommitdiffstats
path: root/crypto/evp
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2021-10-01 14:05:02 +0200
committerRichard Levitte <levitte@openssl.org>2021-10-27 12:46:16 +0200
commit72d93b93ba502582d3488ee256858b8923343804 (patch)
tree73003562765d158b8f339d0dbdc07cb868a79e23 /crypto/evp
parente36f3fdeb1bce59a11ac529a1b4f0310308171cd (diff)
EVP: Allow a fallback for operations that work with an EVP_PKEY
Functions like EVP_PKEY_sign_init() do an implicit fetch of the operation implementation (EVP_SIGNATURE in this case), then get the KEYMGMT from the same provider, and tries to export the key there if necessary. If an export of the key isn't possible (because the provider that holds the key is an HSM and therefore can't export), we would simply fail without looking any further. This change modifies the behaviour a bit by trying a second fetch of the operation implementation, but specifically from the provider of the EVP_PKEY that's being used. This is done with the same properties that were used with the initial operation implementation fetch, and should therefore be safe, allowing only what those properties allow. 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) (cherry picked from commit 839ffdd11cd48d329a1d89565d62e0be082f9d08)
Diffstat (limited to 'crypto/evp')
-rw-r--r--crypto/evp/asymcipher.c92
-rw-r--r--crypto/evp/exchange.c92
-rw-r--r--crypto/evp/kem.c95
-rw-r--r--crypto/evp/m_sigver.c93
-rw-r--r--crypto/evp/signature.c93
5 files changed, 347 insertions, 118 deletions
diff --git a/crypto/evp/asymcipher.c b/crypto/evp/asymcipher.c
index e2912829e2..f158b815cf 100644
--- a/crypto/evp/asymcipher.c
+++ b/crypto/evp/asymcipher.c
@@ -24,7 +24,9 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
void *provkey = NULL;
EVP_ASYM_CIPHER *cipher = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const OSSL_PROVIDER *tmp_prov = NULL;
const char *supported_ciph = NULL;
+ int iter;
if (ctx == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -58,34 +60,76 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation,
}
/*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if cipher is already there.
+ * We perform two iterations:
+ *
+ * 1. Do the normal asym cipher fetch, using the fetching data given by
+ * the EVP_PKEY_CTX.
+ * 2. Do the provider specific asym cipher fetch, from the same provider
+ * as |ctx->keymgmt|
+ *
+ * We then try to fetch the keymgmt from the same provider as the
+ * asym cipher, and try to export |ctx->pkey| to that keymgmt (when
+ * this keymgmt happens to be the same as |ctx->keymgmt|, the export
+ * is a no-op, but we call it anyway to not complicate the code even
+ * more).
+ * If the export call succeeds (returns a non-NULL provider key pointer),
+ * we're done and can perform the operation itself. If not, we perform
+ * the second iteration, or jump to legacy.
*/
- cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph,
- ctx->propquery);
+ for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
+ EVP_KEYMGMT *tmp_keymgmt_tofree;
- if (cipher == NULL)
- goto legacy;
+ /*
+ * If we're on the second iteration, free the results from the first.
+ * They are NULL on the first iteration, so no need to check what
+ * iteration we're on.
+ */
+ EVP_ASYM_CIPHER_free(cipher);
+ EVP_KEYMGMT_free(tmp_keymgmt);
+
+ switch (iter) {
+ case 1:
+ cipher = EVP_ASYM_CIPHER_fetch(ctx->libctx, supported_ciph,
+ ctx->propquery);
+ if (cipher != NULL)
+ tmp_prov = EVP_ASYM_CIPHER_get0_provider(cipher);
+ break;
+ case 2:
+ tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
+ cipher =
+ evp_asym_cipher_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ supported_ciph, ctx->propquery);
+ if (cipher == NULL)
+ goto legacy;
+ break;
+ }
+ if (cipher == NULL)
+ continue;
- /*
- * 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)
+ /*
+ * 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_tofree = tmp_keymgmt
+ = evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ 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 (tmp_keymgmt == NULL)
+ EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+ }
+
+ if (provkey == NULL) {
+ EVP_ASYM_CIPHER_free(cipher);
goto legacy;
+ }
ERR_pop_to_mark();
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 35da4743a4..d12dcee947 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -203,7 +203,9 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
void *provkey = NULL;
EVP_KEYEXCH *exchange = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const OSSL_PROVIDER *tmp_prov = NULL;
const char *supported_exch = NULL;
+ int iter;
if (ctx == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_PASSED_NULL_PARAMETER);
@@ -255,32 +257,76 @@ int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, const OSSL_PARAM params[])
/*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if exchange is already there.
+ * We perform two iterations:
+ *
+ * 1. Do the normal exchange fetch, using the fetching data given by
+ * the EVP_PKEY_CTX.
+ * 2. Do the provider specific exchange fetch, from the same provider
+ * as |ctx->keymgmt|
+ *
+ * We then try to fetch the keymgmt from the same provider as the
+ * exchange, and try to export |ctx->pkey| to that keymgmt (when
+ * this keymgmt happens to be the same as |ctx->keymgmt|, the export
+ * is a no-op, but we call it anyway to not complicate the code even
+ * more).
+ * If the export call succeeds (returns a non-NULL provider key pointer),
+ * we're done and can perform the operation itself. If not, we perform
+ * the second iteration, or jump to legacy.
*/
- exchange = EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
- if (exchange == NULL)
- goto legacy;
+ for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
+ EVP_KEYMGMT *tmp_keymgmt_tofree;
- /*
- * 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)
+ /*
+ * If we're on the second iteration, free the results from the first.
+ * They are NULL on the first iteration, so no need to check what
+ * iteration we're on.
+ */
+ EVP_KEYEXCH_free(exchange);
+ EVP_KEYMGMT_free(tmp_keymgmt);
+
+ switch (iter) {
+ case 1:
+ exchange =
+ EVP_KEYEXCH_fetch(ctx->libctx, supported_exch, ctx->propquery);
+ if (exchange != NULL)
+ tmp_prov = EVP_KEYEXCH_get0_provider(exchange);
+ break;
+ case 2:
+ tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
+ exchange =
+ evp_keyexch_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ supported_exch, ctx->propquery);
+ if (exchange == NULL)
+ goto legacy;
+ break;
+ }
+ if (exchange == NULL)
+ continue;
+
+ /*
+ * 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 exchange method, using
+ * the same property query as when fetching the exchange 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_tofree = tmp_keymgmt =
+ evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ 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 (tmp_keymgmt == NULL)
+ EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+ }
+
+ if (provkey == NULL) {
+ EVP_KEYEXCH_free(exchange);
goto legacy;
+ }
ERR_pop_to_mark();
diff --git a/crypto/evp/kem.c b/crypto/evp/kem.c
index a3537cc452..d5bdc6290a 100644
--- a/crypto/evp/kem.c
+++ b/crypto/evp/kem.c
@@ -23,8 +23,10 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
int ret = 0;
EVP_KEM *kem = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const OSSL_PROVIDER *tmp_prov = NULL;
void *provkey = NULL;
const char *supported_kem = NULL;
+ int iter;
if (ctx == NULL || ctx->keytype == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
@@ -49,31 +51,80 @@ static int evp_kem_init(EVP_PKEY_CTX *ctx, int operation,
goto err;
}
- kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
- 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)
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if kem is already there.
+ * We perform two iterations:
+ *
+ * 1. Do the normal kem fetch, using the fetching data given by
+ * the EVP_PKEY_CTX.
+ * 2. Do the provider specific kem fetch, from the same provider
+ * as |ctx->keymgmt|
+ *
+ * We then try to fetch the keymgmt from the same provider as the
+ * kem, and try to export |ctx->pkey| to that keymgmt (when this
+ * keymgmt happens to be the same as |ctx->keymgmt|, the export is
+ * a no-op, but we call it anyway to not complicate the code even
+ * more).
+ * If the export call succeeds (returns a non-NULL provider key pointer),
+ * we're done and can perform the operation itself. If not, we perform
+ * the second iteration, or jump to legacy.
*/
- 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);
+ for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
+ EVP_KEYMGMT *tmp_keymgmt_tofree;
+
+ /*
+ * If we're on the second iteration, free the results from the first.
+ * They are NULL on the first iteration, so no need to check what
+ * iteration we're on.
+ */
+ EVP_KEM_free(kem);
+ EVP_KEYMGMT_free(tmp_keymgmt);
+
+ switch (iter) {
+ case 1:
+ kem = EVP_KEM_fetch(ctx->libctx, supported_kem, ctx->propquery);
+ if (kem != NULL)
+ tmp_prov = EVP_KEM_get0_provider(kem);
+ break;
+ case 2:
+ tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
+ kem = evp_kem_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ supported_kem, ctx->propquery);
+
+ if (kem == NULL) {
+ ERR_raise(ERR_LIB_EVP,
+ EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
+ ret = -2;
+ goto err;
+ }
+ }
+ if (kem == NULL)
+ continue;
+
+ /*
+ * 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_tofree = tmp_keymgmt =
+ evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ 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 (tmp_keymgmt == NULL)
+ EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+ }
+
if (provkey == NULL) {
+ EVP_KEM_free(kem);
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err;
}
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index 55675c36e1..eeb1a9adfa 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -45,10 +45,11 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
EVP_PKEY_CTX *locpctx = NULL;
EVP_SIGNATURE *signature = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const OSSL_PROVIDER *tmp_prov = NULL;
const char *supported_sig = NULL;
char locmdname[80] = ""; /* 80 chars should be enough */
void *provkey = NULL;
- int ret;
+ int ret, iter;
if (ctx->algctx != NULL) {
if (!ossl_assert(ctx->digest != NULL)) {
@@ -98,33 +99,75 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
}
/*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if signature is already there.
+ * We perform two iterations:
+ *
+ * 1. Do the normal signature fetch, using the fetching data given by
+ * the EVP_PKEY_CTX.
+ * 2. Do the provider specific signature fetch, from the same provider
+ * as |ctx->keymgmt|
+ *
+ * We then try to fetch the keymgmt from the same provider as the
+ * signature, and try to export |ctx->pkey| to that keymgmt (when
+ * this keymgmt happens to be the same as |ctx->keymgmt|, the export
+ * is a no-op, but we call it anyway to not complicate the code even
+ * more).
+ * If the export call succeeds (returns a non-NULL provider key pointer),
+ * we're done and can perform the operation itself. If not, we perform
+ * the second iteration, or jump to legacy.
*/
- signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
- locpctx->propquery);
-
- if (signature == NULL)
- goto legacy;
+ for (iter = 1, provkey = NULL; iter < 3 && provkey == NULL; iter++) {
+ EVP_KEYMGMT *tmp_keymgmt_tofree = NULL;
+
+ /*
+ * If we're on the second iteration, free the results from the first.
+ * They are NULL on the first iteration, so no need to check what
+ * iteration we're on.
+ */
+ EVP_SIGNATURE_free(signature);
+ EVP_KEYMGMT_free(tmp_keymgmt);
+
+ switch (iter) {
+ case 1:
+ signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
+ locpctx->propquery);
+ if (signature != NULL)
+ tmp_prov = EVP_SIGNATURE_get0_provider(signature);
+ break;
+ case 2:
+ tmp_prov = EVP_KEYMGMT_get0_provider(locpctx->keymgmt);
+ signature =
+ evp_signature_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ supported_sig, locpctx->propquery);
+ if (signature == NULL)
+ goto legacy;
+ break;
+ }
+ if (signature == NULL)
+ continue;
+
+ /*
+ * 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_tofree = tmp_keymgmt =
+ evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ 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 (tmp_keymgmt == NULL)
+ EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+ }
- /*
- * 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) {
+ EVP_SIGNATURE_free(signature);
ERR_clear_last_mark();
ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
goto err;
diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c
index f5c3bbcb1e..b33fe0d952 100644
--- a/crypto/evp/signature.c
+++ b/crypto/evp/signature.c
@@ -397,7 +397,9 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
void *provkey = NULL;
EVP_SIGNATURE *signature = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const OSSL_PROVIDER *tmp_prov = NULL;
const char *supported_sig = NULL;
+ int iter;
if (ctx == NULL) {
ERR_raise(ERR_LIB_EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -430,34 +432,77 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation,
}
/*
- * Because we cleared out old ops, we shouldn't need to worry about
- * checking if signature is already there.
+ * We perform two iterations:
+ *
+ * 1. Do the normal signature fetch, using the fetching data given by
+ * the EVP_PKEY_CTX.
+ * 2. Do the provider specific signature fetch, from the same provider
+ * as |ctx->keymgmt|
+ *
+ * We then try to fetch the keymgmt from the same provider as the
+ * signature, and try to export |ctx->pkey| to that keymgmt (when
+ * this keymgmt happens to be the same as |ctx->keymgmt|, the export
+ * is a no-op, but we call it anyway to not complicate the code even
+ * more).
+ * If the export call succeeds (returns a non-NULL provider key pointer),
+ * we're done and can perform the operation itself. If not, we perform
+ * the second iteration, or jump to legacy.
*/
- signature =
- EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+ for (iter = 1; iter < 3 && provkey == NULL; iter++) {
+ EVP_KEYMGMT *tmp_keymgmt_tofree;
- if (signature == NULL)
- goto legacy;
+ /*
+ * If we're on the second iteration, free the results from the first.
+ * They are NULL on the first iteration, so no need to check what
+ * iteration we're on.
+ */
+ EVP_SIGNATURE_free(signature);
+ EVP_KEYMGMT_free(tmp_keymgmt);
+
+ switch (iter) {
+ case 1:
+ signature =
+ EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+ if (signature != NULL)
+ tmp_prov = EVP_SIGNATURE_get0_provider(signature);
+ break;
+ case 2:
+ tmp_prov = EVP_KEYMGMT_get0_provider(ctx->keymgmt);
+ signature =
+ evp_signature_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ supported_sig, ctx->propquery);
+ if (signature == NULL)
+ goto legacy;
+ break;
+ }
+ if (signature == NULL)
+ continue;
- /*
- * 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)
+ /*
+ * 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_tofree = tmp_keymgmt =
+ evp_keymgmt_fetch_from_prov((OSSL_PROVIDER *)tmp_prov,
+ 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 (tmp_keymgmt == NULL)
+ EVP_KEYMGMT_free(tmp_keymgmt_tofree);
+ }
+
+ if (provkey == NULL) {
+ EVP_SIGNATURE_free(signature);
goto legacy;
+ }
ERR_pop_to_mark();