EVP: Add evp_pkey_upgrade_to_provider(), for EVP_PKEY upgrades

This function "upgrades" a key from a legacy key container to a
provider side key container.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11148)
This commit is contained in:
Richard Levitte 2020-02-20 22:55:41 +01:00
parent 3c6ed9555c
commit badf51c869
3 changed files with 124 additions and 11 deletions

View File

@ -866,28 +866,40 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
return ((i > 1) ? 1 : 0);
}
#ifndef FIPS_MODE
static void evp_pkey_free_legacy(EVP_PKEY *x)
{
if (x->ameth != NULL) {
if (x->ameth->pkey_free)
x->ameth->pkey_free(x);
x->pkey.ptr = NULL;
x->ameth = NULL;
}
# ifndef OPENSSL_NO_ENGINE
ENGINE_finish(x->engine);
x->engine = NULL;
ENGINE_finish(x->pmeth_engine);
x->pmeth_engine = NULL;
# endif
x->type = x->save_type = EVP_PKEY_NONE;
}
#endif /* FIPS_MODE */
static void evp_pkey_free_it(EVP_PKEY *x)
{
/* internal function; x is never NULL */
evp_keymgmt_util_clear_operation_cache(x);
#ifndef FIPS_MODE
evp_pkey_free_legacy(x);
#endif
if (x->ameth && x->ameth->pkey_free) {
x->ameth->pkey_free(x);
x->pkey.ptr = NULL;
}
if (x->keymgmt != NULL) {
evp_keymgmt_freedata(x->keymgmt, x->keydata);
EVP_KEYMGMT_free(x->keymgmt);
x->keymgmt = NULL;
x->keydata = NULL;
}
#if !defined(OPENSSL_NO_ENGINE) && !defined(FIPS_MODE)
ENGINE_finish(x->engine);
x->engine = NULL;
ENGINE_finish(x->pmeth_engine);
x->pmeth_engine = NULL;
#endif
}
void EVP_PKEY_free(EVP_PKEY *x)
@ -1053,3 +1065,100 @@ void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
EVP_KEYMGMT_free(allocated_keymgmt);
return keydata;
}
#ifndef FIPS_MODE
/*
* This differs from exporting in that it releases the legacy key and assigns
* the export keymgmt and keydata to the "origin" provider side key instead
* of the operation cache.
*/
void *evp_pkey_upgrade_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
EVP_KEYMGMT **keymgmt,
const char *propquery)
{
EVP_KEYMGMT *allocated_keymgmt = NULL;
EVP_KEYMGMT *tmp_keymgmt = NULL;
void *keydata = NULL;
if (pk == NULL)
return NULL;
/*
* If this key is already "upgraded", this function shouldn't have been
* called.
*/
if (!ossl_assert(pk->keymgmt == NULL))
return NULL;
if (keymgmt != NULL) {
tmp_keymgmt = *keymgmt;
*keymgmt = NULL;
}
/* If the key isn't a legacy one, bail out, but with proper values */
if (pk->pkey.ptr == NULL) {
tmp_keymgmt = pk->keymgmt;
keydata = pk->keydata;
} else {
/* If the legacy key doesn't have an export function, give up */
if (pk->ameth->export_to == NULL)
return NULL;
/* If no keymgmt was given, get a default keymgmt */
if (tmp_keymgmt == NULL) {
EVP_PKEY_CTX *ctx =
EVP_PKEY_CTX_new_from_pkey(libctx, pk, propquery);
if (ctx != NULL && ctx->keytype != NULL)
tmp_keymgmt = allocated_keymgmt =
EVP_KEYMGMT_fetch(ctx->libctx, ctx->keytype, propquery);
EVP_PKEY_CTX_free(ctx);
}
/* If we still don't have a keymgmt, give up */
if (tmp_keymgmt == NULL)
goto end;
/* Make sure that the keymgmt key type matches the legacy NID */
if (!ossl_assert(EVP_KEYMGMT_is_a(tmp_keymgmt, OBJ_nid2sn(pk->type))))
goto end;
if ((keydata = evp_keymgmt_newdata(tmp_keymgmt)) == NULL)
goto end;
if (!pk->ameth->export_to(pk, keydata, tmp_keymgmt)
|| !EVP_KEYMGMT_up_ref(tmp_keymgmt)) {
evp_keymgmt_freedata(tmp_keymgmt, keydata);
keydata = NULL;
goto end;
}
/*
* Clear the operation cache, all the legacy data, as well as the
* dirty counters
*/
evp_pkey_free_legacy(pk);
pk->dirty_cnt_copy = 0;
evp_keymgmt_util_clear_operation_cache(pk);
pk->keymgmt = tmp_keymgmt;
pk->keydata = keydata;
evp_keymgmt_util_cache_keyinfo(pk);
}
end:
/*
* If nothing was upgraded, |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 (keydata == NULL)
tmp_keymgmt = NULL;
if (keymgmt != NULL)
*keymgmt = tmp_keymgmt;
EVP_KEYMGMT_free(allocated_keymgmt);
return keydata;
}
#endif /* FIPS_MODE */

View File

@ -603,6 +603,9 @@ void evp_app_cleanup_int(void);
void *evp_pkey_export_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
EVP_KEYMGMT **keymgmt,
const char *propquery);
void *evp_pkey_upgrade_to_provider(EVP_PKEY *pk, OPENSSL_CTX *libctx,
EVP_KEYMGMT **keymgmt,
const char *propquery);
/*
* KEYMGMT utility functions

View File

@ -207,7 +207,8 @@ static int test_pass_rsa(FIXTURE *fixture)
|| !TEST_ptr_ne(km1, km2))
goto err;
if (!TEST_ptr(evp_pkey_make_provided(pk, NULL, &km1, NULL))
if (!TEST_ptr(evp_pkey_export_to_provider(pk, NULL, &km1, NULL))
|| !TEST_ptr(evp_pkey_upgrade_to_provider(pk, NULL, &km1, NULL))
|| !TEST_ptr(provkey = evp_keymgmt_util_export_to_provider(pk, km2)))
goto err;