From: Simo Sorce Date: Mon, 3 Nov 2025 21:53:41 +0000 (-0500) Subject: Derive EC public key from private key if missing X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f9971f0936547abae6dec1e4d778ad333eb38ea6;p=thirdparty%2Fopenssl.git Derive EC public key from private key if missing Update ossl_ec_key_fromdata to compute the public key if it is not provided in the input parameters but the private key is. This allows for the creation of a complete EC_KEY object from only private key data. Signed-off-by: Simo Sorce Reviewed-by: Dmitry Belyavskiy Reviewed-by: Neil Horman (Merged from https://github.com/openssl/openssl/pull/29054) --- diff --git a/crypto/ec/ec_backend.c b/crypto/ec/ec_backend.c index 20627117852..b100af0c60f 100644 --- a/crypto/ec/ec_backend.c +++ b/crypto/ec/ec_backend.c @@ -483,6 +483,15 @@ int ossl_ec_key_fromdata(EC_KEY *ec, const OSSL_PARAM params[], int include_priv && !EC_KEY_set_public_key(ec, pub_point)) goto err; + /* Fallback computation of public key if not provided */ + if (priv_key != NULL && pub_point == NULL) { + if ((pub_point = EC_POINT_new(ecg)) == NULL + || !EC_KEY_set_public_key(ec, pub_point)) + goto err; + if (!ossl_ec_key_simple_generate_public_key(ec)) + goto err; + } + ok = 1; err: diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index 532983a69f4..176587bcd28 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -1477,13 +1477,11 @@ static int test_EC_priv_pub(void) bld = NULL; /* - * We indicate only parameters here, in spite of having built a key that - * has a private part, because the PEM_write_bio_PrivateKey_ex call is - * expected to fail because it does not support exporting a private EC - * key without a corresponding public key + * ossl_ec_key_fromdata() automatically generates the public key on import + * if one is not provided, so fail the test if a public key is not + * available. */ - if (!test_selection(params_and_priv, OSSL_KEYMGMT_SELECT_ALL_PARAMETERS) - || test_selection(params_and_priv, OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) + if (!test_selection(params_and_priv, OSSL_KEYMGMT_SELECT_KEYPAIR)) goto err; /* Test !priv and pub */ diff --git a/test/evp_pkey_dhkem_test.c b/test/evp_pkey_dhkem_test.c index 98338993604..b2903a9b952 100644 --- a/test/evp_pkey_dhkem_test.c +++ b/test/evp_pkey_dhkem_test.c @@ -394,8 +394,7 @@ err: } /* - * ECX keys autogen the public key if a private key is loaded, - * So this test passes for ECX, but fails for EC + * ECX and EC keys autogen the public key if a private key is loaded. */ static int test_nopublic(int tstid) { @@ -405,7 +404,6 @@ static int test_nopublic(int tstid) int encap = ((tstid & 1) == 0); int keytype = tstid >= TEST_KEM_ENCAP_DECAP; const TEST_ENCAPDATA *t = &ec_encapdata[keytype]; - int expected = (keytype == TEST_KEYTYPE_X25519); TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); if (!TEST_ptr(priv = new_raw_private_key(t->curve, t->rpriv, t->rprivlen, @@ -415,15 +413,12 @@ static int test_nopublic(int tstid) goto err; if (encap) { - if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), expected)) + if (!TEST_int_eq(EVP_PKEY_encapsulate_init(ctx, opparam), 1)) goto err; } else { - if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), expected)) + if (!TEST_int_eq(EVP_PKEY_decapsulate_init(ctx, opparam), 1)) goto err; } - if (expected == 0 - && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), PROV_R_NOT_A_PUBLIC_KEY)) - goto err; ret = 1; err: EVP_PKEY_free(priv); @@ -431,7 +426,10 @@ err: return ret; } -/* Test that not setting the auth public key fails the auth encap/decap init */ +/* + * Test that not setting the auth public key does not fail the auth + * encap/decap init + */ static int test_noauthpublic(int tstid) { int ret = 0; @@ -440,28 +438,23 @@ static int test_noauthpublic(int tstid) int keytype = tstid >= TEST_KEM_ENCAP_DECAP; const TEST_ENCAPDATA *t = &ec_encapdata[keytype]; EVP_PKEY_CTX *ctx = rctx[keytype]; - int expected = (keytype == TEST_KEYTYPE_X25519); TEST_note("%s %s", t->curve, encap ? "Encap" : "Decap"); if (!TEST_ptr(auth = new_raw_private_key(t->curve, t->rpriv, - t->rprivlen, NULL, expected))) + t->rprivlen, NULL, 1))) goto err; if (encap) { if (!TEST_int_eq(EVP_PKEY_auth_encapsulate_init(ctx, auth, opparam), - expected)) + 1)) goto err; } else { if (!TEST_int_eq(EVP_PKEY_auth_decapsulate_init(ctx, auth, opparam), - expected)) + 1)) goto err; } - if (expected == 0 - && !TEST_int_eq(ERR_GET_REASON(ERR_get_error()), - PROV_R_NOT_A_PUBLIC_KEY)) - goto err; ret = 1; err: EVP_PKEY_free(auth);