From 6adc360e42286fdbd5e225f1a41033e29742ff96 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 14 Jan 2025 17:53:28 -0500 Subject: [PATCH] Add additional EVP_SKEY helpers EVP_SKEY_is_a() allows to check if a key is of a specific type. EVP_SKEY_to_provider() provides an easy way to move a key to a different provider. Signed-off-by: Simo Sorce --- crypto/evp/kdf_lib.c | 18 ++++++++-- crypto/evp/s_lib.c | 76 +++++++++++++++++++++++++++++++++++++++++++ doc/man3/EVP_SKEY.pod | 25 ++++++++++++-- include/openssl/evp.h | 3 ++ util/libcrypto.num | 2 ++ 5 files changed, 118 insertions(+), 6 deletions(-) diff --git a/crypto/evp/kdf_lib.c b/crypto/evp/kdf_lib.c index 7a99990f1e82b..376fc0c46e8d5 100644 --- a/crypto/evp/kdf_lib.c +++ b/crypto/evp/kdf_lib.c @@ -178,11 +178,23 @@ int EVP_KDF_CTX_set_SKEY(EVP_KDF_CTX *ctx, EVP_SKEY *key, const char *paramname) ckey.name = (paramname != NULL) ? paramname : OSSL_KDF_PARAM_KEY; if (ctx->meth->set_skey != NULL) { + EVP_SKEY *tmp_key = NULL; + int ret; + + /* Transfer key to meth provider if different from key's */ if (ctx->meth->prov != key->skeymgmt->prov) { - /* TODO: export/import dance */ - return 0; + /* FIXME: no libctx, no propquery */ + tmp_key = EVP_SKEY_to_provider(key, NULL, ctx->meth->prov, NULL); + if (tmp_key == NULL) + return 0; + } else { + tmp_key = key; } - return ctx->meth->set_skey(ctx->algctx, key->keydata, ckey.name); + ret = ctx->meth->set_skey(ctx->algctx, key->keydata, ckey.name); + if (tmp_key != key) + EVP_SKEY_free(tmp_key); + + return ret; } else { /* * Provider does not support opaque keys, try to export and diff --git a/crypto/evp/s_lib.c b/crypto/evp/s_lib.c index ff42d4083ec8b..4c8f05ccc1f58 100644 --- a/crypto/evp/s_lib.c +++ b/crypto/evp/s_lib.c @@ -233,3 +233,79 @@ const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey) return ossl_provider_name(skey->skeymgmt->prov); } + +int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name) +{ + if (skey == NULL) + return 0; + + if (skey->skeymgmt == NULL) + return 0; + + return EVP_SKEYMGMT_is_a(skey->skeymgmt, name); +} + +struct transfer_cb_ctx { + int selection; + EVP_SKEYMGMT *skeymgmt; + void *keydata; +}; + +static int transfer_cb(const OSSL_PARAM params[], void *arg) +{ + struct transfer_cb_ctx *ctx = arg; + + ctx->keydata = evp_skeymgmt_import(ctx->skeymgmt, ctx->selection, params); + return 1; +} + +EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx, + OSSL_PROVIDER *prov, const char *propquery) +{ + struct transfer_cb_ctx ctx = { 0 }; + EVP_SKEYMGMT *skeymgmt = NULL; + EVP_SKEY *ret = NULL; + + if (prov) { + skeymgmt = evp_skeymgmt_fetch_from_prov(prov, + skey->skeymgmt->type_name, + propquery); + + } else { + /* If no provider, get the default skeymgmt */ + skeymgmt = EVP_SKEYMGMT_fetch(libctx, skey->skeymgmt->type_name, + propquery); + } + + /* Short-circuit if destination provider is the same as origin */ + if (skey->skeymgmt->name_id == skeymgmt->name_id + && skey->skeymgmt->prov == skeymgmt->prov) { + if (!EVP_SKEY_up_ref(skey)) + goto err; + EVP_SKEYMGMT_free(skeymgmt); + return skey; + } + + ctx.selection = OSSL_SKEYMGMT_SELECT_ALL; + ctx.skeymgmt = skeymgmt; + + if (!EVP_SKEY_export(skey, ctx.selection, transfer_cb, &ctx)) + goto err; + + if (ctx.keydata == NULL) + goto err; + + ret = evp_skey_alloc(); + if (ret == NULL) + goto err; + + ret->keydata = ctx.keydata; + ret->skeymgmt = skeymgmt; + + return ret; + + err: + EVP_SKEYMGMT_free(skeymgmt); + EVP_SKEY_free(ret); + return NULL; +} diff --git a/doc/man3/EVP_SKEY.pod b/doc/man3/EVP_SKEY.pod index 0819623da971e..8235f02b7fda5 100644 --- a/doc/man3/EVP_SKEY.pod +++ b/doc/man3/EVP_SKEY.pod @@ -6,7 +6,7 @@ EVP_SKEY, EVP_SKEY_generate, EVP_SKEY_import, EVP_SKEY_import_raw_key, EVP_SKEY_up_ref, EVP_SKEY_export, EVP_SKEY_get_raw_key, EVP_SKEY_get0_key_id, EVP_SKEY_get0_skeymgmt_name, EVP_SKEY_get0_provider_name, -EVP_SKEY_free +EVP_SKEY_free, EVP_SKEY_is_a, EVP_SKEY_to_provider - opaque symmetric key allocation and handling functions =head1 SYNOPSIS @@ -34,6 +34,10 @@ EVP_SKEY_free int EVP_SKEY_up_ref(EVP_SKEY *key); void EVP_SKEY_free(EVP_SKEY *key); + int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name); + EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx, + OSSL_PROVIDER *prov, const char *propquery); + =head1 DESCRIPTION @@ -80,6 +84,12 @@ EVP_SKEY_up_ref() increments the reference count of I. EVP_SKEY_free() decrements the reference count of I and, if the reference count is zero, frees it. If I is NULL, nothing is done. +EVP_SKEY_is_a() checks if the key type of I is I. + +EVP_SKEY_to_provider() simplifies the task of importing a I into a +different provider identified by I. If I is NULL, the default +provider for the key type identified via I is used. + =head2 Selections The following constants can be used for I: @@ -106,6 +116,9 @@ All parameters will be selected. The B structure is used by various OpenSSL functions which require a general symmetric key without reference to any particular algorithm. +The EVP_SKEY_to_provider() function will fail and return NULL if the origin +key I cannot be exported from its provider. + =head1 RETURN VALUES EVP_SKEY_generate(), EVP_SKEY_import() and EVP_SKEY_import_raw_key() return @@ -120,6 +133,12 @@ EVP_SKEY_export() and EVP_SKEY_get_raw_key() return 1 for success and 0 on failu EVP_SKEY_get0_skeymgmt_name() and EVP_SKEY_get0_provider_name() return the names of the associated EVP_SKEYMGMT object and its provider correspondigly. +EVP_SKEY_is_a() returns 1 if I has the key type I, +otherwise 0. + +EVP_SKEY_to_provider() returns a new B suitable for operations with +the I provider or NULL in case of failure. + =head1 SEE ALSO L, L, L @@ -129,8 +148,8 @@ L, L, L The B API and functions EVP_SKEY_export(), EVP_SKEY_free(), EVP_SKEY_get_raw_key(), EVP_SKEY_import(), EVP_SKEY_import_raw_key(), EVP_SKEY_up_ref(), EVP_SKEY_generate(), -EVP_SKEY_get0_key_id(), EVP_SKEY_get0_provider_name(), and -EVP_SKEY_get0_skeymgmt_name() +EVP_SKEY_get0_key_id(), EVP_SKEY_get0_provider_name(), +EVP_SKEY_get0_skeymgmt_name(), EVP_SKEY_is_a(), EVP_SKEY_to_provider() were introduced in OpenSSL 3.5. =head1 COPYRIGHT diff --git a/include/openssl/evp.h b/include/openssl/evp.h index 5c4d2e6eed65a..1500b6e989dda 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -2270,6 +2270,7 @@ OSSL_LIB_CTX *EVP_PKEY_CTX_get0_libctx(EVP_PKEY_CTX *ctx); const char *EVP_PKEY_CTX_get0_propq(const EVP_PKEY_CTX *ctx); const OSSL_PROVIDER *EVP_PKEY_CTX_get0_provider(const EVP_PKEY_CTX *ctx); +int EVP_SKEY_is_a(const EVP_SKEY *skey, const char *name); EVP_SKEY *EVP_SKEY_import(OSSL_LIB_CTX *libctx, const char *skeymgmtname, const char *propquery, int selection, const OSSL_PARAM *params); EVP_SKEY *EVP_SKEY_generate(OSSL_LIB_CTX *libctx, const char *skeymgmtname, @@ -2286,6 +2287,8 @@ int EVP_SKEY_up_ref(EVP_SKEY *skey); void EVP_SKEY_free(EVP_SKEY *skey); const char *EVP_SKEY_get0_skeymgmt_name(const EVP_SKEY *skey); const char *EVP_SKEY_get0_provider_name(const EVP_SKEY *skey); +EVP_SKEY *EVP_SKEY_to_provider(EVP_SKEY *skey, OSSL_LIB_CTX *libctx, + OSSL_PROVIDER *prov, const char *propquery); # ifdef __cplusplus } diff --git a/util/libcrypto.num b/util/libcrypto.num index 5868fc2b4a43e..29c2dc13670f0 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5902,3 +5902,5 @@ EVP_SKEY_get0_provider_name ? 3_5_0 EXIST::FUNCTION: EVP_SKEYMGMT_get0_gen_settable_params ? 3_5_0 EXIST::FUNCTION: EVP_SKEYMGMT_get0_imp_settable_params ? 3_5_0 EXIST::FUNCTION: EVP_KDF_CTX_set_SKEY ? 3_5_0 EXIST::FUNCTION: +EVP_SKEY_is_a ? 3_5_0 EXIST::FUNCTION: +EVP_SKEY_to_provider ? 3_5_0 EXIST::FUNCTION: