aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinkyung Park <[email protected]>2026-08-04 09:05:46 +0200
committerEugene Syromiatnikov <[email protected]>2026-10-18 17:34:31 +0200
commitb13e07ec6c77a33e7bdc8378744d5a1462895544 (patch)
tree00e0a0e1ec1e1b05ce2c4d748194cdd77d2c49c2
parenttest/cmp_vfy_test.c: prevent memory leak in test_msg_check_update_malicious_s... (diff)
downloadopenssl-b13e07ec6c77a33e7bdc8378744d5a1462895544.tar.gz
openssl-b13e07ec6c77a33e7bdc8378744d5a1462895544.zip
Fix use-after-free in EC_GROUP_get_ecpkparameters()
When a caller-supplied ECPKPARAMETERS object is passed in, the CHOICE member it already holds is released on entry, but the union pointer was left untouched. If a later step then failed, the error exit called ECPKPARAMETERS_free() on that object, which followed the still valid selector and freed the already released member a second time. Clear the pointer once it has been released, so that the error exit has nothing left to free. This does not change the fact that a caller supplied object is freed on error. That behaviour differs from the sibling function EC_GROUP_get_ecparameters(), which only frees the object it allocated itself, but it is left as-is here. The new test only fails on a sanitizer build; the ECPKPARAMETERS layout is private to ec_asn1.c, so the state cannot be inspected directly. The regression test and the pull request description were written with AI assistance. Fixes: 012c86ab74ae "move ECC ASN1 that is not specific to ECDSA into crypto/ec/, and make some appropriate changes to the EC library." Co-authored-by: Jakub Zelenka <[email protected]> Assisted-by: Claude:claude-fable-5 Reviewed-by: Jakub Zelenka <[email protected]> Reviewed-by: Frederik Wedel-Heinen <[email protected]> Reviewed-by: Eugene Syromiatnikov <[email protected]> Merge-date: Sun Oct 18 15:26:51 2026 Merged-from: https://github.com/openssl/openssl/pull/32169 (cherry picked from commit 4c49f3f1103fc731cf1ec64fec5b744fa031241e)
-rw-r--r--crypto/ec/ec_asn1.c9
-rw-r--r--test/ec_internal_test.c38
2 files changed, 43 insertions, 4 deletions
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index e86a95cba0e..3551d990a42 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -467,11 +467,14 @@ ECPKPARAMETERS *EC_GROUP_get_ecpkparameters(const EC_GROUP *group,
return NULL;
}
} else {
- if (ret->type == ECPKPARAMETERS_TYPE_NAMED)
+ if (ret->type == ECPKPARAMETERS_TYPE_NAMED) {
ASN1_OBJECT_free(ret->value.named_curve);
- else if (ret->type == ECPKPARAMETERS_TYPE_EXPLICIT
- && ret->value.parameters != NULL)
+ ret->value.named_curve = NULL;
+ } else if (ret->type == ECPKPARAMETERS_TYPE_EXPLICIT
+ && ret->value.parameters != NULL) {
ECPARAMETERS_free(ret->value.parameters);
+ ret->value.parameters = NULL;
+ }
}
if (EC_GROUP_get_asn1_flag(group) == OPENSSL_EC_NAMED_CURVE) {
diff --git a/test/ec_internal_test.c b/test/ec_internal_test.c
index 751bc9c2b9e..287618b8cff 100644
--- a/test/ec_internal_test.c
+++ b/test/ec_internal_test.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2019-2025 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2019-2026 The OpenSSL Project Authors. All Rights Reserved.
*
* Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
@@ -436,6 +436,41 @@ err:
return testresult;
}
+/*
+ * Test that reusing an ECPKPARAMETERS object for a call that fails does not
+ * touch the CHOICE member that was released on entry.
+ */
+static int ecpkparams_reuse_error_test(void)
+{
+ EC_GROUP *grp = NULL;
+ ECPKPARAMETERS *params = NULL;
+ int testresult = 0;
+
+ if (!TEST_ptr(grp = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)))
+ goto err;
+
+ /* Populate the explicit parameters arm of the CHOICE. */
+ EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_EXPLICIT_CURVE);
+ if (!TEST_ptr(params = EC_GROUP_get_ecpkparameters(grp, NULL)))
+ goto err;
+
+ /* Take the named curve arm and make it fail on the undefined NID. */
+ EC_GROUP_set_curve_name(grp, NID_undef);
+ EC_GROUP_set_asn1_flag(grp, OPENSSL_EC_NAMED_CURVE);
+
+ /* On failure the passed in object is consumed, so do not free it again. */
+ params = EC_GROUP_get_ecpkparameters(grp, params);
+ if (!TEST_ptr_null(params))
+ goto err;
+ testresult = 1;
+
+err:
+ ECPKPARAMETERS_free(params);
+ EC_GROUP_free(grp);
+
+ return testresult;
+}
+
static int ecpkparams_i2d2i_test(int n)
{
EC_GROUP *g1 = NULL, *g2 = NULL;
@@ -556,6 +591,7 @@ int setup_tests(void)
#endif
ADD_TEST(set_private_key);
ADD_TEST(decoded_flag_test);
+ ADD_TEST(ecpkparams_reuse_error_test);
ADD_ALL_TESTS(ecpkparams_i2d2i_test, (int)crv_len);
ADD_TEST(named_group_creation_test);