mirror of
https://github.com/openssl/openssl.git
synced 2025-01-30 14:01:55 +08:00
EVP: Add support for comparing provided EVP_PKEYs
This adds evp_keymgmt_util_match() and affects EVP_PKEY_cmp() and EVP_PKEY_cmp_parameters(). The word 'match' was used for the new routines because many associate 'cmp' with comparison functions that allows sorting, i.e. return -1, 0 or 1 depending on the order in which the two compared elements should be sorted. EVP_PKEY_cmp() and EVP_PKEY_cmp_parameters() don't quite do that. Reviewed-by: Shane Lontis <shane.lontis@oracle.com> (Merged from https://github.com/openssl/openssl/pull/11158)
This commit is contained in:
parent
bee5d6cd3f
commit
1e9101c404
@ -223,3 +223,73 @@ int evp_keymgmt_util_has(EVP_PKEY *pk, int selection)
|
||||
|
||||
return evp_keymgmt_has(pk->keymgmt, pk->keydata, selection);
|
||||
}
|
||||
|
||||
/*
|
||||
* evp_keymgmt_util_match() doesn't just look at the provider side "origin",
|
||||
* but also in the operation cache to see if there's any common keymgmt that
|
||||
* supplies OP_keymgmt_match.
|
||||
*
|
||||
* evp_keymgmt_util_match() adheres to the return values that EVP_PKEY_cmp()
|
||||
* and EVP_PKEY_cmp_parameters() return, i.e.:
|
||||
*
|
||||
* 1 same key
|
||||
* 0 not same key
|
||||
* -1 not same key type
|
||||
* -2 unsupported operation
|
||||
*/
|
||||
int evp_keymgmt_util_match(EVP_PKEY *pk1, EVP_PKEY *pk2, int selection)
|
||||
{
|
||||
EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
|
||||
void *keydata1 = NULL, *keydata2 = NULL;
|
||||
|
||||
if (pk1 == NULL || pk2 == NULL) {
|
||||
if (pk1 == NULL && pk2 == NULL)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
keymgmt1 = pk1->keymgmt;
|
||||
keydata1 = pk1->keydata;
|
||||
keymgmt2 = pk2->keymgmt;
|
||||
keydata2 = pk2->keydata;
|
||||
|
||||
if (keymgmt1 != keymgmt2) {
|
||||
void *tmp_keydata = NULL;
|
||||
|
||||
/* Complex case, where the keymgmt differ */
|
||||
if (keymgmt1 != NULL
|
||||
&& keymgmt2 != NULL
|
||||
&& !match_type(keymgmt1, keymgmt2)) {
|
||||
ERR_raise(ERR_LIB_EVP, EVP_R_DIFFERENT_KEY_TYPES);
|
||||
return -1; /* Not the same type */
|
||||
}
|
||||
|
||||
/*
|
||||
* The key types are determined to match, so we try cross export,
|
||||
* but only to keymgmt's that supply a matching function.
|
||||
*/
|
||||
if (keymgmt2 != NULL
|
||||
&& keymgmt2->match != NULL) {
|
||||
tmp_keydata = evp_keymgmt_util_export_to_provider(pk1, keymgmt2);
|
||||
if (tmp_keydata != NULL) {
|
||||
keymgmt1 = keymgmt2;
|
||||
keydata1 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
if (tmp_keydata == NULL
|
||||
&& keymgmt1 != NULL
|
||||
&& keymgmt1->match != NULL) {
|
||||
tmp_keydata = evp_keymgmt_util_export_to_provider(pk2, keymgmt1);
|
||||
if (tmp_keydata != NULL) {
|
||||
keymgmt2 = keymgmt1;
|
||||
keydata2 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we still don't have matching keymgmt implementations, we give up */
|
||||
if (keymgmt1 != keymgmt2)
|
||||
return -2;
|
||||
|
||||
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
|
||||
}
|
||||
|
@ -124,30 +124,108 @@ int EVP_PKEY_missing_parameters(const EVP_PKEY *pkey)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called for any mixture of keys except pure legacy pair.
|
||||
* TODO When legacy keys are gone, we replace a call to this functions with
|
||||
* a call to evp_keymgmt_util_match().
|
||||
*/
|
||||
static int evp_pkey_cmp_any(const EVP_PKEY *a, const EVP_PKEY *b,
|
||||
int selection)
|
||||
{
|
||||
EVP_KEYMGMT *keymgmt1 = NULL, *keymgmt2 = NULL;
|
||||
void *keydata1 = NULL, *keydata2 = NULL, *tmp_keydata = NULL;
|
||||
|
||||
/* If none of them are provided, this function shouldn't have been called */
|
||||
if (!ossl_assert(a->keymgmt != NULL || b->keymgmt != NULL))
|
||||
return -2;
|
||||
|
||||
/* For purely provided keys, we just call the keymgmt utility */
|
||||
if (a->keymgmt != NULL && b->keymgmt != NULL)
|
||||
return evp_keymgmt_util_match((EVP_PKEY *)a, (EVP_PKEY *)b, selection);
|
||||
|
||||
/*
|
||||
* Here, we know that we have a mixture of legacy and provided keys.
|
||||
* Try cross export and compare the resulting key data.
|
||||
*/
|
||||
keymgmt1 = a->keymgmt;
|
||||
keydata1 = a->keydata;
|
||||
keymgmt2 = b->keymgmt;
|
||||
keydata2 = b->keydata;
|
||||
|
||||
if ((keymgmt1 == NULL
|
||||
&& !EVP_KEYMGMT_is_a(keymgmt2, OBJ_nid2sn(a->type)))
|
||||
|| (keymgmt2 == NULL
|
||||
&& !EVP_KEYMGMT_is_a(keymgmt1, OBJ_nid2sn(b->type))))
|
||||
return -1; /* not the same key type */
|
||||
|
||||
if (keymgmt2 != NULL && keymgmt2->match != NULL) {
|
||||
tmp_keydata =
|
||||
evp_pkey_export_to_provider((EVP_PKEY *)a, NULL, &keymgmt2, NULL);
|
||||
if (tmp_keydata != NULL) {
|
||||
keymgmt1 = keymgmt2;
|
||||
keydata1 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
if (tmp_keydata == NULL && keymgmt1 != NULL && keymgmt1->match != NULL) {
|
||||
tmp_keydata =
|
||||
evp_pkey_export_to_provider((EVP_PKEY *)b, NULL, &keymgmt1, NULL);
|
||||
if (tmp_keydata != NULL) {
|
||||
keymgmt2 = keymgmt1;
|
||||
keydata2 = tmp_keydata;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we still don't have matching keymgmt implementations, we give up */
|
||||
if (keymgmt1 != keymgmt2)
|
||||
return -2;
|
||||
|
||||
return evp_keymgmt_match(keymgmt1, keydata1, keydata2, selection);
|
||||
}
|
||||
|
||||
int EVP_PKEY_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
|
||||
{
|
||||
/*
|
||||
* TODO: clean up legacy stuff from this function when legacy support
|
||||
* is gone.
|
||||
*/
|
||||
|
||||
if (a->keymgmt != NULL || b->keymgmt != NULL)
|
||||
return evp_pkey_cmp_any(a, b, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS);
|
||||
|
||||
/* All legacy keys */
|
||||
if (a->type != b->type)
|
||||
return -1;
|
||||
if (a->ameth && a->ameth->param_cmp)
|
||||
if (a->ameth != NULL && a->ameth->param_cmp != NULL)
|
||||
return a->ameth->param_cmp(a, b);
|
||||
return -2;
|
||||
}
|
||||
|
||||
int EVP_PKEY_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
|
||||
{
|
||||
/*
|
||||
* TODO: clean up legacy stuff from this function when legacy support
|
||||
* is gone.
|
||||
*/
|
||||
|
||||
if (a->keymgmt != NULL || b->keymgmt != NULL)
|
||||
return evp_pkey_cmp_any(a, b,
|
||||
OSSL_KEYMGMT_SELECT_ALL_PARAMETERS
|
||||
| OSSL_KEYMGMT_SELECT_PUBLIC_KEY);
|
||||
|
||||
/* All legacy keys */
|
||||
if (a->type != b->type)
|
||||
return -1;
|
||||
|
||||
if (a->ameth) {
|
||||
if (a->ameth != NULL) {
|
||||
int ret;
|
||||
/* Compare parameters if the algorithm has them */
|
||||
if (a->ameth->param_cmp) {
|
||||
if (a->ameth->param_cmp != NULL) {
|
||||
ret = a->ameth->param_cmp(a, b);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (a->ameth->pub_cmp)
|
||||
if (a->ameth->pub_cmp != NULL)
|
||||
return a->ameth->pub_cmp(a, b);
|
||||
}
|
||||
|
||||
|
@ -620,6 +620,7 @@ void evp_keymgmt_util_cache_keyinfo(EVP_PKEY *pk);
|
||||
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);
|
||||
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user