EVP: Add support for copying provided EVP_PKEYs

This adds evp_keymgmt_util_copy() and affects EVP_PKEY_copy_parameters()

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11158)
This commit is contained in:
Richard Levitte 2020-02-05 16:30:21 +01:00
parent 13697f1c62
commit ff3b59e170
3 changed files with 128 additions and 8 deletions

View File

@ -293,3 +293,60 @@ int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
}
int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection)
{
/* Save copies of pointers we want to play with without affecting |to| */
EVP_KEYMGMT *to_keymgmt = to->keymgmt;
void *to_keydata = to->keydata, *alloc_keydata = NULL;
/* An unassigned key can't be copied */
if (from == NULL || from->keymgmt == NULL)
return 0;
/* If |from| doesn't support copying, we fail */
if (from->keymgmt->copy == NULL)
return 0;
/* If |to| doesn't have a provider side "origin" yet, create one */
if (to_keymgmt == NULL) {
to_keydata = alloc_keydata = evp_keymgmt_newdata(from->keymgmt);
if (to_keydata == NULL)
return 0;
to_keymgmt = from->keymgmt;
}
if (to_keymgmt == from->keymgmt) {
/* |to| and |from| have the same keymgmt, just copy and be done */
if (!evp_keymgmt_copy(to_keymgmt, to_keydata, from->keydata,
selection))
return 0;
} else if (match_type(to_keymgmt, from->keymgmt)) {
struct import_data_st import_data;
import_data.keymgmt = to_keymgmt;
import_data.keydata = to_keydata;
import_data.selection = selection;
if (!evp_keymgmt_export(from->keymgmt, from->keydata, selection,
&try_import, &import_data)) {
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
return 0;
}
} else {
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
return 0;
}
if (to->keymgmt == NULL
&& !EVP_KEYMGMT_up_ref(to_keymgmt)) {
evp_keymgmt_freedata(to_keymgmt, alloc_keydata);
return 0;
}
evp_keymgmt_util_clear_operation_cache(to);
to->keymgmt = to_keymgmt;
to->keydata = to_keydata;
evp_keymgmt_util_cache_keyinfo(to);
return 1;
}

View File

@ -86,12 +86,25 @@ int EVP_PKEY_save_parameters(EVP_PKEY *pkey, int mode)
int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
{
if (to->type == EVP_PKEY_NONE) {
if (EVP_PKEY_set_type(to, from->type) == 0)
return 0;
} else if (to->type != from->type) {
EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
goto err;
/*
* TODO: clean up legacy stuff from this function when legacy support
* is gone.
*/
/*
* Only check that type match this early when both keys are legacy.
* If either of them is provided, we let evp_keymgmt_util_copy()
* do this check, after having exported either of them that isn't
* provided.
*/
if (to->keymgmt == NULL && from->keymgmt == NULL) {
if (to->type == EVP_PKEY_NONE) {
if (EVP_PKEY_set_type(to, from->type) == 0)
return 0;
} else if (to->type != from->type) {
EVPerr(EVP_F_EVP_PKEY_COPY_PARAMETERS, EVP_R_DIFFERENT_KEY_TYPES);
goto err;
}
}
if (EVP_PKEY_missing_parameters(from)) {
@ -106,7 +119,56 @@ int EVP_PKEY_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
return 0;
}
if (from->ameth && from->ameth->param_copy)
/*
* If |from| is provided, we upgrade |to| to be provided as well.
* This drops the legacy key from |to|.
* evp_pkey_upgrade_to_provider() checks if |to| is already provided,
* we don't need to do that here.
*
* TODO(3.0) We should investigate if that's too aggressive and make
* this scenario unsupported instead.
*/
if (from->keymgmt != NULL) {
EVP_KEYMGMT *tmp_keymgmt = from->keymgmt;
/*
* The returned pointer is known to be cached, so we don't have to
* save it. However, if it's NULL, something went wrong and we can't
* copy.
*/
if (evp_pkey_upgrade_to_provider(to, NULL,
&tmp_keymgmt, NULL) == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
}
/* For purely provided keys, we just call the keymgmt utility */
if (to->keymgmt != NULL && from->keymgmt != NULL)
return evp_keymgmt_util_copy(to, (EVP_PKEY *)from,
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
/*
* If |to| is provided, we know that |from| is legacy at this point.
* Try exporting |from| to |to|'s keymgmt, then use evp_keymgmt_copy()
* to copy the appropriate data to |to|'s keydata.
*/
if (to->keymgmt != NULL) {
EVP_KEYMGMT *to_keymgmt = to->keymgmt;
void *from_keydata =
evp_pkey_export_to_provider((EVP_PKEY *)from, NULL, &to_keymgmt,
NULL);
if (from_keydata == NULL) {
ERR_raise(ERR_LIB_EVP, ERR_R_INTERNAL_ERROR);
return 0;
}
return evp_keymgmt_copy(to->keymgmt, to->keydata, from_keydata,
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
}
/* Both keys are legacy */
if (from->ameth != NULL && from->ameth->param_copy != NULL)
return from->ameth->param_copy(to, from);
err:
return 0;
@ -953,7 +1015,7 @@ int EVP_PKEY_up_ref(EVP_PKEY *pkey)
static void evp_pkey_free_legacy(EVP_PKEY *x)
{
if (x->ameth != NULL) {
if (x->ameth->pkey_free)
if (x->ameth->pkey_free != NULL)
x->ameth->pkey_free(x);
x->pkey.ptr = NULL;
x->ameth = NULL;

View File

@ -621,6 +621,7 @@ void *evp_keymgmt_util_fromdata(EVP_PKEY *target, EVP_KEYMGMT *keymgmt,
int selection, const OSSL_PARAM params[]);
int evp_keymgmt_util_has(EVP_PKEY *pk, int selection);
int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection);
int evp_keymgmt_util_copy(EVP_PKEY *to, EVP_PKEY *from, int selection);
/*