diff options
| author | Minkyung Park <[email protected]> | 2026-08-04 09:05:46 +0200 |
|---|---|---|
| committer | Eugene Syromiatnikov <[email protected]> | 2026-10-18 17:34:31 +0200 |
| commit | b13e07ec6c77a33e7bdc8378744d5a1462895544 (patch) | |
| tree | 00e0a0e1ec1e1b05ce2c4d748194cdd77d2c49c2 | |
| parent | test/cmp_vfy_test.c: prevent memory leak in test_msg_check_update_malicious_s... (diff) | |
| download | openssl-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.c | 9 | ||||
| -rw-r--r-- | test/ec_internal_test.c | 38 |
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); |
