summaryrefslogtreecommitdiff
path: root/crypto/evp
diff options
context:
space:
mode:
authorRichard Levitte <levitte@openssl.org>2020-01-14 14:11:47 +0100
committerRichard Levitte <levitte@openssl.org>2020-01-18 05:27:50 +0100
commitf6aa57741254723b0c32f0dfe1ed8ad886b43c80 (patch)
tree203488625e054b4f1624066a87d428c0a8568c7d /crypto/evp
parentc8a557357789a8a23fe7b87ec352bd5ea2c1251b (diff)
downloadopenssl-new-f6aa57741254723b0c32f0dfe1ed8ad886b43c80.tar.gz
EVP: Add evp_pkey_make_provided() and refactor around it
The code to ensure that an EVP_PKEY is exported to providers is repeated all over the place, enough that copying it again has the usual future hazards with code copying. Instead, we refactor that code into one function, evp_pkey_make_provided(), and make sure to use that everywhere. It relies on the creation of EVP_PKEY_CTX to figure out facts about the input key, should it need to. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/10850)
Diffstat (limited to 'crypto/evp')
-rw-r--r--crypto/evp/evp_local.h3
-rw-r--r--crypto/evp/exchange.c58
-rw-r--r--crypto/evp/m_sigver.c61
-rw-r--r--crypto/evp/p_lib.c45
-rw-r--r--crypto/evp/pmeth_fn.c65
-rw-r--r--crypto/evp/signature.c66
6 files changed, 169 insertions, 129 deletions
diff --git a/crypto/evp/evp_local.h b/crypto/evp/evp_local.h
index 0feace2aa5..894fdf996e 100644
--- a/crypto/evp/evp_local.h
+++ b/crypto/evp/evp_local.h
@@ -281,3 +281,6 @@ void evp_names_do_all(OSSL_PROVIDER *prov, int number,
void (*fn)(const char *name, void *data),
void *data);
int evp_cipher_cache_constants(EVP_CIPHER *cipher);
+void *evp_pkey_make_provided(EVP_PKEY *pk, OPENSSL_CTX *libctx,
+ EVP_KEYMGMT **keymgmt, const char *propquery,
+ int domainparams);
diff --git a/crypto/evp/exchange.c b/crypto/evp/exchange.c
index 56896390e0..9bb241fe14 100644
--- a/crypto/evp/exchange.c
+++ b/crypto/evp/exchange.c
@@ -164,6 +164,8 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
int ret;
void *provkey = NULL;
EVP_KEYEXCH *exchange = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_exch = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -176,33 +178,36 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
if (ctx->engine != NULL || ctx->keytype == NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_exch = NULL;
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ 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 (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;
+ /*
+ * 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);
- }
+ /*
+ * 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 (ctx->keymgmt == NULL
- || exchange == NULL
+ if (exchange == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_KEYEXCH_provider(exchange))) {
/*
@@ -217,13 +222,6 @@ int EVP_PKEY_derive_init(EVP_PKEY_CTX *ctx)
ctx->op.kex.exchange = exchange;
-
- if (ctx->pkey != NULL) {
- provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.kex.exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
if (ctx->op.kex.exchprovctx == NULL) {
/* The provider key can stay in the cache */
diff --git a/crypto/evp/m_sigver.c b/crypto/evp/m_sigver.c
index dbfa01b3ed..20c0a1ad59 100644
--- a/crypto/evp/m_sigver.c
+++ b/crypto/evp/m_sigver.c
@@ -31,6 +31,8 @@ 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 char *supported_sig = NULL;
void *provkey = NULL;
int ret;
@@ -71,33 +73,38 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
}
}
- if (locpctx->keymgmt == NULL)
- locpctx->keymgmt = EVP_KEYMGMT_fetch(locpctx->libctx, locpctx->keytype,
- locpctx->propquery);
- if (locpctx->keymgmt != NULL) {
- const char *supported_sig = NULL;
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = locpctx->keymgmt;
+ provkey = evp_pkey_make_provided(locpctx->pkey, locpctx->libctx,
+ &tmp_keymgmt, locpctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ 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 (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;
+ /*
+ * 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
- * checking if signature is already there.
- */
- signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
- locpctx->propquery);
- }
+ /*
+ * Because we cleared out old ops, we shouldn't need to worry about
+ * checking if signature is already there.
+ */
+ signature = EVP_SIGNATURE_fetch(locpctx->libctx, supported_sig,
+ locpctx->propquery);
- if (locpctx->keymgmt == NULL
- || signature == NULL
+ if (signature == NULL
|| (EVP_KEYMGMT_provider(locpctx->keymgmt)
!= EVP_SIGNATURE_provider(signature))) {
/*
@@ -113,16 +120,8 @@ static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
/* No more legacy from here down to legacy: */
locpctx->op.sig.signature = signature;
-
- provkey =
- evp_keymgmt_export_to_provider(locpctx->pkey, locpctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
-
locpctx->operation = ver ? EVP_PKEY_OP_VERIFYCTX
: EVP_PKEY_OP_SIGNCTX;
-
locpctx->op.sig.sigprovctx
= signature->newctx(ossl_provider_ctx(signature->prov));
if (locpctx->op.sig.sigprovctx == NULL) {
diff --git a/crypto/evp/p_lib.c b/crypto/evp/p_lib.c
index 2e0890cac5..016bcf93c2 100644
--- a/crypto/evp/p_lib.c
+++ b/crypto/evp/p_lib.c
@@ -27,6 +27,7 @@
#include "crypto/asn1.h"
#include "crypto/evp.h"
#include "internal/provider.h"
+#include "evp_local.h"
static void evp_pkey_free_it(EVP_PKEY *key);
@@ -827,3 +828,47 @@ int EVP_PKEY_size(const EVP_PKEY *pkey)
}
return 0;
}
+
+void *evp_pkey_make_provided(EVP_PKEY *pk, OPENSSL_CTX *libctx,
+ EVP_KEYMGMT **keymgmt, const char *propquery,
+ int domainparams)
+{
+ EVP_KEYMGMT *allocated_keymgmt = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ void *provdata = NULL;
+
+ if (pk == NULL)
+ return NULL;
+
+ if (keymgmt != NULL) {
+ tmp_keymgmt = *keymgmt;
+ *keymgmt = NULL;
+ }
+
+ if (tmp_keymgmt == NULL) {
+ EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pk);
+
+ if (ctx != NULL && ctx->keytype != NULL)
+ tmp_keymgmt = allocated_keymgmt =
+ EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, propquery);
+ EVP_PKEY_CTX_free(ctx);
+ }
+
+ if (tmp_keymgmt != NULL)
+ provdata =
+ evp_keymgmt_export_to_provider(pk, tmp_keymgmt, domainparams);
+
+ /*
+ * If nothing was exported, |tmp_keymgmt| might point at a freed
+ * EVP_KEYMGMT, so we clear it to be safe. It shouldn't be useful for
+ * the caller either way in that case.
+ */
+ if (provdata == NULL)
+ tmp_keymgmt = NULL;
+
+ if (keymgmt != NULL)
+ *keymgmt = tmp_keymgmt;
+
+ EVP_KEYMGMT_free(allocated_keymgmt);
+ return provdata;
+}
diff --git a/crypto/evp/pmeth_fn.c b/crypto/evp/pmeth_fn.c
index aa226fcc7b..19bc56c654 100644
--- a/crypto/evp/pmeth_fn.c
+++ b/crypto/evp/pmeth_fn.c
@@ -21,6 +21,8 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation)
int ret = 0;
void *provkey = NULL;
EVP_ASYM_CIPHER *cipher = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_ciph = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -33,33 +35,35 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation)
if (ctx->keytype == NULL || ctx->engine != NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_ciph = NULL;
-
- 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);
- }
-
- if (ctx->keymgmt == NULL
- || cipher == NULL
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ EVP_KEYMGMT_up_ref(tmp_keymgmt);
+ 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);
+
+ if (cipher == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_ASYM_CIPHER_provider(cipher))) {
/*
@@ -73,13 +77,6 @@ static int evp_pkey_asym_cipher_init(EVP_PKEY_CTX *ctx, int operation)
}
ctx->op.ciph.cipher = cipher;
-
- if (ctx->pkey != NULL) {
- provkey = evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.ciph.ciphprovctx = cipher->newctx(ossl_provider_ctx(cipher->prov));
if (ctx->op.ciph.ciphprovctx == NULL) {
/* The provider key can stay in the cache */
diff --git a/crypto/evp/signature.c b/crypto/evp/signature.c
index 1cef4649ed..0adf59be2a 100644
--- a/crypto/evp/signature.c
+++ b/crypto/evp/signature.c
@@ -322,6 +322,8 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation)
int ret = 0;
void *provkey = NULL;
EVP_SIGNATURE *signature = NULL;
+ EVP_KEYMGMT *tmp_keymgmt = NULL;
+ const char *supported_sig = NULL;
if (ctx == NULL) {
EVPerr(0, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
@@ -334,33 +336,37 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation)
if (ctx->keytype == NULL)
goto legacy;
- if (ctx->keymgmt == NULL)
- ctx->keymgmt =
- EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, ctx->propquery);
- if (ctx->keymgmt != NULL) {
- const char *supported_sig = NULL;
-
- 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
- * checking if signature is already there.
- */
- signature =
- EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+ /* Ensure that the key is provided. If not, go legacy */
+ tmp_keymgmt = ctx->keymgmt;
+ provkey = evp_pkey_make_provided(ctx->pkey, ctx->libctx,
+ &tmp_keymgmt, ctx->propquery, 0);
+ if (provkey == NULL)
+ goto legacy;
+ if (!EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
+ ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR);
+ goto err;
}
-
- if (ctx->keymgmt == NULL
- || signature == NULL
+ 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
+ * checking if signature is already there.
+ */
+ signature =
+ EVP_SIGNATURE_fetch(ctx->libctx, supported_sig, ctx->propquery);
+
+ if (signature == NULL
|| (EVP_KEYMGMT_provider(ctx->keymgmt)
!= EVP_SIGNATURE_provider(signature))) {
/*
@@ -374,14 +380,6 @@ static int evp_pkey_signature_init(EVP_PKEY_CTX *ctx, int operation)
}
ctx->op.sig.signature = signature;
-
- if (ctx->pkey != NULL) {
- provkey =
- evp_keymgmt_export_to_provider(ctx->pkey, ctx->keymgmt, 0);
- /* If export failed, legacy may be able to pick it up */
- if (provkey == NULL)
- goto legacy;
- }
ctx->op.sig.sigprovctx = signature->newctx(ossl_provider_ctx(signature->prov));
if (ctx->op.sig.sigprovctx == NULL) {
/* The provider key can stay in the cache */