From 615a9b8798e6ec58f1b2e1ec08a0f6b3c8cb7f60 Mon Sep 17 00:00:00 2001 From: Tomas Mraz Date: Thu, 18 Nov 2021 20:09:57 +0100 Subject: [PATCH] d2i_PublicKey: Make it work with EC parameters in a provided key Fixes #16989 Reviewed-by: Paul Dale (Merged from https://github.com/openssl/openssl/pull/17065) --- crypto/asn1/d2i_pu.c | 23 ++++++++++++++++++++--- test/ectest.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/crypto/asn1/d2i_pu.c b/crypto/asn1/d2i_pu.c index ddf1aad7009..1be114b8a2a 100644 --- a/crypto/asn1/d2i_pu.c +++ b/crypto/asn1/d2i_pu.c @@ -29,16 +29,27 @@ EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, long length) { EVP_PKEY *ret; + EVP_PKEY *copy = NULL; if ((a == NULL) || (*a == NULL)) { if ((ret = EVP_PKEY_new()) == NULL) { ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); return NULL; } - } else + } else { ret = *a; - if (type != EVP_PKEY_get_id(ret) && !EVP_PKEY_set_type(ret, type)) { +#ifndef OPENSSL_NO_EC + if (evp_pkey_is_provided(ret) + && EVP_PKEY_get_base_id(ret) == EVP_PKEY_EC) { + if (!evp_pkey_copy_downgraded(©, ret)) + goto err; + } +#endif + } + + if ((type != EVP_PKEY_get_id(ret) || copy != NULL) + && !EVP_PKEY_set_type(ret, type)) { ERR_raise(ERR_LIB_ASN1, ERR_R_EVP_LIB); goto err; } @@ -52,7 +63,6 @@ EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, break; #ifndef OPENSSL_NO_DSA case EVP_PKEY_DSA: - /* TMP UGLY CAST */ if (!d2i_DSAPublicKey(&ret->pkey.dsa, pp, length)) { ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); goto err; @@ -61,6 +71,11 @@ EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, #endif #ifndef OPENSSL_NO_EC case EVP_PKEY_EC: + if (copy != NULL) { + /* use downgraded parameters from copy */ + ret->pkey.ec = copy->pkey.ec; + copy->pkey.ec = NULL; + } if (!o2i_ECPublicKey(&ret->pkey.ec, pp, length)) { ERR_raise(ERR_LIB_ASN1, ERR_R_ASN1_LIB); goto err; @@ -73,9 +88,11 @@ EVP_PKEY *d2i_PublicKey(int type, EVP_PKEY **a, const unsigned char **pp, } if (a != NULL) (*a) = ret; + EVP_PKEY_free(copy); return ret; err: if (a == NULL || *a != ret) EVP_PKEY_free(ret); + EVP_PKEY_free(copy); return NULL; } diff --git a/test/ectest.c b/test/ectest.c index 30680c742de..8e62cf01e6e 100644 --- a/test/ectest.c +++ b/test/ectest.c @@ -2966,6 +2966,47 @@ static int custom_params_test(int id) return ret; } +static int ec_d2i_publickey_test(void) +{ + unsigned char buf[1000]; + unsigned char *pubkey_enc = buf; + const unsigned char *pk_enc = pubkey_enc; + EVP_PKEY *gen_key = NULL, *decoded_key = NULL; + EVP_PKEY_CTX *pctx = NULL; + int pklen, ret = 0; + OSSL_PARAM params[2]; + + if (!TEST_ptr(gen_key = EVP_EC_gen("P-256"))) + goto err; + + if (!TEST_int_gt(pklen = i2d_PublicKey(gen_key, &pubkey_enc), 0)) + goto err; + + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, + "P-256", 0); + params[1] = OSSL_PARAM_construct_end(); + + if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) + || !TEST_true(EVP_PKEY_fromdata_init(pctx)) + || !TEST_true(EVP_PKEY_fromdata(pctx, &decoded_key, + OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS, + params)) + || !TEST_ptr(decoded_key) + || !TEST_ptr(decoded_key = d2i_PublicKey(EVP_PKEY_EC, &decoded_key, + &pk_enc, pklen))) + goto err; + + if (!TEST_true(EVP_PKEY_eq(gen_key, decoded_key))) + goto err; + ret = 1; + + err: + EVP_PKEY_CTX_free(pctx); + EVP_PKEY_free(gen_key); + EVP_PKEY_free(decoded_key); + return ret; +} + int setup_tests(void) { crv_len = EC_get_builtin_curves(NULL, 0); @@ -2993,6 +3034,7 @@ int setup_tests(void) ADD_ALL_TESTS(ec_point_hex2point_test, crv_len); ADD_ALL_TESTS(custom_generator_test, crv_len); ADD_ALL_TESTS(custom_params_test, crv_len); + ADD_TEST(ec_d2i_publickey_test); return 1; } -- 2.47.2