Commit 54d175c7d5 for openssl.org
commit 54d175c7d5f476e2a2c93c050dc145f484c93fbd
Author: Dmitry Belyavskiy <beldmit@gmail.com>
Date: Wed Jan 14 17:59:38 2026 +0100
Disabling explicit EC curves encoding
In case the parameters don't exactly match the well-known ones
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Simo Sorce <simo@redhat.com>
(Merged from https://github.com/openssl/openssl/pull/29639)
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 33444738e9..c915b6b217 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -93,7 +93,7 @@ jobs:
run: echo "FIPS_VENDOR=CI" >> VERSION.dat
- name: config
# enable-quic is on by default, but we leave it here to check we're testing the explicit enable somewhere
- run: CC=gcc ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-sslkeylog enable-fips enable-quic enable-lms && perl configdata.pm --dump
+ run: CC=gcc ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-ec_explicit_curves enable-sslkeylog enable-fips enable-quic enable-lms && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -414,7 +414,7 @@ jobs:
sudo cat /proc/sys/vm/mmap_rnd_bits
sudo sysctl -w vm.mmap_rnd_bits=28
- name: config
- run: ./config --strict-warnings --banner=Configured --debug enable-demos enable-h3demo enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips enable-lms && perl configdata.pm --dump
+ run: ./config --strict-warnings --banner=Configured --debug enable-demos enable-h3demo enable-asan enable-ec_explicit_curves enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips enable-lms && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -443,7 +443,7 @@ jobs:
sudo cat /proc/sys/vm/mmap_rnd_bits
sudo sysctl -w vm.mmap_rnd_bits=28
- name: config
- run: ./config --strict-warnings --banner=Configured --debug -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-weak-ssl-ciphers enable-nextprotoneg && perl configdata.pm --dump
+ run: ./config --strict-warnings --banner=Configured --debug -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION enable-asan enable-ec_explicit_curves enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-weak-ssl-ciphers enable-nextprotoneg && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -474,7 +474,7 @@ jobs:
sudo sysctl -w vm.mmap_rnd_bits=28
- name: config
# --debug -O1 is to produce a debug build that runs in a reasonable amount of time
- run: CC=clang ./config --strict-warnings --banner=Configured --debug no-shared -O1 -fsanitize=memory -DOSSL_SANITIZE_MEMORY -fno-optimize-sibling-calls enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips enable-lms no-slh-dsa && perl configdata.pm --dump
+ run: CC=clang ./config --strict-warnings --banner=Configured --debug no-shared -O1 -fsanitize=memory -DOSSL_SANITIZE_MEMORY -fno-optimize-sibling-calls enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-ec_explicit_curves enable-fips enable-lms no-slh-dsa && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -563,7 +563,7 @@ jobs:
- name: install extra config support
run: sudo apt-get -y install libsctp-dev abigail-tools libzstd-dev zstd
- name: config
- run: ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-ktls enable-fips enable-lms enable-egd enable-ec_nistp_64_gcc_128 enable-md2 enable-rc5 enable-sctp enable-weak-ssl-ciphers enable-trace enable-zlib enable-zstd && perl configdata.pm --dump
+ run: ./config --strict-warnings --banner=Configured enable-demos enable-h3demo enable-ec_explicit_curves enable-ktls enable-fips enable-lms enable-egd enable-ec_nistp_64_gcc_128 enable-md2 enable-rc5 enable-sctp enable-weak-ssl-ciphers enable-trace enable-zlib enable-zstd && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
@@ -613,7 +613,7 @@ jobs:
- name: checkout fuzz/corpora submodule
run: git submodule update --init --depth 1 fuzz/corpora
- name: config
- run: ./config --strict-warnings --banner=Configured --debug enable-demos enable-h3demo no-shared enable-crypto-mdebug enable-rc5 enable-md2 enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-fips && perl configdata.pm --dump
+ run: ./config --strict-warnings --banner=Configured --debug enable-demos enable-h3demo no-shared enable-crypto-mdebug enable-rc5 enable-md2 enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 enable-ec_explicit_curves no-fips && perl configdata.pm --dump
- name: make
run: make -s -j4
- name: get cpu info
diff --git a/CHANGES.md b/CHANGES.md
index ff960d0dcc..dfe4b0d2d3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -45,6 +45,12 @@ OpenSSL 4.0
*Shane Lontis*
+ * Support of explicit EC curves was disabled by default, an error will occur if
+ an explicit EC curve doesn't match any known one. New configuration option,
+ `enable-ec_explicit_curves` is added.
+
+ *Dmitry Belyavskiy*
+
* Removed configure options can now only be disabled. You may continue to use
`disable-<feature>`, which will remain supported. Using `enable-<feature>`
for a removed feature is no longer permitted.
diff --git a/Configure b/Configure
index 3b8f2e4587..7682185697 100755
--- a/Configure
+++ b/Configure
@@ -466,6 +466,7 @@ my @disablables = (
"dtls",
"ec",
"ec2m",
+ "ec_explicit_curves",
"ec_nistp_64_gcc_128",
"ecdh",
"ecdsa",
@@ -601,6 +602,7 @@ our %disabled = ( # "what" => "comment"
"demos" => "default",
"h3demo" => "default",
"hqinterop" => "default",
+ "ec_explicit_curves" => "default",
"ec_nistp_64_gcc_128" => "default",
"egd" => "default",
"engine" => "default",
@@ -654,7 +656,7 @@ my @disable_cascades = (
"zstd" => [ "zstd-dynamic" ],
"des" => [ "mdc2" ],
"deprecated" => [ "tls-deprecated-ec" ],
- "ec" => [ qw(ec2m ecdsa ecdh sm2 gost ecx tls-deprecated-ec) ],
+ "ec" => [ qw(ec2m ec_explicit_curves ecdsa ecdh sm2 gost ecx tls-deprecated-ec) ],
"dgram" => [ "dtls", "quic", "sctp" ],
"sock" => [ "dgram", "tfo" ],
"dtls" => [ @dtls ],
diff --git a/INSTALL.md b/INSTALL.md
index 9884caabe9..252bc13e7c 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -771,6 +771,12 @@ Disable legacy TLS EC groups that were deprecated in RFC8422. These are the
Koblitz curves, B<secp160r1>, B<secp160r2>, B<secp192r1>, B<secp224r1>, and the
binary Elliptic curves that would also be disabled by C<no-ec2m>.
+### enable-ec_expicit_curves
+
+Enable support for explictitly specified elliptic curves not matching the
+well-known ones. Until this option is on, such curves can't be instantiated
+from ASN.1 formats.
+
### enable-ec_nistp_64_gcc_128
Enable support for optimised implementations of some commonly used NIST
diff --git a/crypto/ec/ec_asn1.c b/crypto/ec/ec_asn1.c
index 01a3933713..c6deacc1a7 100644
--- a/crypto/ec/ec_asn1.c
+++ b/crypto/ec/ec_asn1.c
@@ -888,6 +888,14 @@ EC_GROUP *d2i_ECPKParameters(EC_GROUP **a, const unsigned char **in, long len)
if (params->type == ECPKPARAMETERS_TYPE_EXPLICIT)
group->decoded_from_explicit_params = 1;
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ if (EC_GROUP_check_named_curve(group, 0, NULL) == NID_undef) {
+ EC_GROUP_free(group);
+ ECPKPARAMETERS_free(params);
+ ERR_raise(ERR_LIB_EC, EC_R_UNKNOWN_GROUP);
+ return NULL;
+ }
+#endif
if (a) {
EC_GROUP_free(*a);
@@ -948,6 +956,13 @@ EC_KEY *d2i_ECPrivateKey(EC_KEY **a, const unsigned char **in, long len)
goto err;
}
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ if (EC_GROUP_check_named_curve(ret->group, 0, NULL) == NID_undef) {
+ ERR_raise(ERR_LIB_EC, EC_R_UNKNOWN_GROUP);
+ goto err;
+ }
+#endif
+
ret->version = priv_key->version;
if (priv_key->privateKey) {
diff --git a/crypto/ec/ec_lib.c b/crypto/ec/ec_lib.c
index b041ecd0f7..079a02b59f 100644
--- a/crypto/ec/ec_lib.c
+++ b/crypto/ec/ec_lib.c
@@ -1577,7 +1577,9 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
int is_prime_field = 1;
BN_CTX *bnctx = NULL;
const unsigned char *buf = NULL;
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
int encoding_flag = -1;
+#endif
#endif
/* This is the simple named group case */
@@ -1752,6 +1754,12 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
goto err;
}
if (named_group == group) {
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ if (EC_GROUP_check_named_curve(group, 0, NULL) == NID_undef) {
+ ERR_raise(ERR_LIB_EC, EC_R_UNKNOWN_GROUP);
+ goto err;
+ }
+#else
/*
* If we did not find a named group then the encoding should be explicit
* if it was specified
@@ -1767,6 +1775,7 @@ EC_GROUP *EC_GROUP_new_from_params(const OSSL_PARAM params[],
goto err;
}
EC_GROUP_set_asn1_flag(group, OPENSSL_EC_EXPLICIT_CURVE);
+#endif
} else {
EC_GROUP_free(group);
group = named_group;
diff --git a/test/ectest.c b/test/ectest.c
index 9fca45bad4..c4d2c97ea7 100644
--- a/test/ectest.c
+++ b/test/ectest.c
@@ -2555,6 +2555,7 @@ err:
return r;
}
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
/*-
* random 256-bit explicit parameters curve, cofactor absent
* order: 0x0c38d96a9f892b88772ec2e39614a82f4f (132 bit)
@@ -2644,6 +2645,7 @@ err:
EC_GROUP_free(group);
return ret;
}
+#endif
/*-
* For named curves, test that:
@@ -2887,23 +2889,28 @@ err:
static int do_test_custom_explicit_fromdata(EC_GROUP *group, BN_CTX *ctx,
unsigned char *gen, size_t gen_size)
{
- int ret = 0, i_out;
+ int ret = 0;
EVP_PKEY_CTX *pctx = NULL;
EVP_PKEY *pkeyparam = NULL;
OSSL_PARAM_BLD *bld = NULL;
const char *field_name;
OSSL_PARAM *params = NULL;
- const OSSL_PARAM *gettable;
BIGNUM *p, *a, *b;
BIGNUM *p_out = NULL, *a_out = NULL, *b_out = NULL;
BIGNUM *order_out = NULL, *cofactor_out = NULL;
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
+ const OSSL_PARAM *gettable;
+ int i_out;
char name[80];
unsigned char buf[1024];
size_t buf_len, name_len;
#ifndef OPENSSL_NO_EC2M
- unsigned int k1 = 0, k2 = 0, k3 = 0;
const char *basis_name = NULL;
#endif
+#endif
+#ifndef OPENSSL_NO_EC2M
+ unsigned int k1 = 0, k2 = 0, k3 = 0;
+#endif
p = BN_CTX_get(ctx);
a = BN_CTX_get(ctx);
@@ -2919,11 +2926,15 @@ static int do_test_custom_explicit_fromdata(EC_GROUP *group, BN_CTX *ctx,
field_name = SN_X9_62_characteristic_two_field;
#ifndef OPENSSL_NO_EC2M
if (EC_GROUP_get_basis_type(group) == NID_X9_62_tpBasis) {
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
basis_name = SN_X9_62_tpBasis;
+#endif
if (!TEST_true(EC_GROUP_get_trinomial_basis(group, &k1)))
goto err;
} else {
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
basis_name = SN_X9_62_ppBasis;
+#endif
if (!TEST_true(EC_GROUP_get_pentanomial_basis(group, &k1, &k2, &k3)))
goto err;
}
@@ -2958,11 +2969,19 @@ static int do_test_custom_explicit_fromdata(EC_GROUP *group, BN_CTX *ctx,
if (!TEST_ptr(params = OSSL_PARAM_BLD_to_param(bld))
|| !TEST_ptr(pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL))
|| !TEST_int_gt(EVP_PKEY_fromdata_init(pctx), 0)
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ || !TEST_int_le(EVP_PKEY_fromdata(pctx, &pkeyparam,
+ EVP_PKEY_KEY_PARAMETERS, params),
+ 0)
+#else
|| !TEST_int_gt(EVP_PKEY_fromdata(pctx, &pkeyparam,
EVP_PKEY_KEY_PARAMETERS, params),
- 0))
+ 0)
+#endif
+ )
goto err;
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
/*- Check that all the set values are retrievable -*/
/* There should be no match to a group name since the generator changed */
@@ -3096,6 +3115,7 @@ static int do_test_custom_explicit_fromdata(EC_GROUP *group, BN_CTX *ctx,
#endif
)
goto err;
+#endif
ret = 1;
err:
BN_free(order_out);
@@ -3218,12 +3238,15 @@ static int custom_params_test(int id)
EC_KEY *eckey1 = NULL, *eckey2 = NULL;
EVP_PKEY *pkey1 = NULL, *pkey2 = NULL;
EVP_PKEY_CTX *pctx1 = NULL, *pctx2 = NULL, *dctx = NULL;
- size_t sslen, t, bsize;
+ size_t bsize;
unsigned char *pub1 = NULL, *pub2 = NULL;
OSSL_PARAM_BLD *param_bld = NULL;
OSSL_PARAM *params1 = NULL, *params2 = NULL;
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
const unsigned char *export = NULL;
size_t export_size = 0;
+ size_t sslen, t;
+#endif
EVP_SKEY *skey = NULL;
/* Do some setup */
@@ -3391,6 +3414,16 @@ static int custom_params_test(int id)
goto err;
eckey2 = NULL; /* ownership passed to pkey2 */
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ /* Compute keyexchange in both directions - fail with custom params */
+ if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL))
+ || !TEST_int_le(EVP_PKEY_derive_init(pctx1), 0))
+ goto err;
+ if (!TEST_ptr(pctx2 = EVP_PKEY_CTX_new(pkey2, NULL))
+ || !TEST_int_le(EVP_PKEY_derive_init(pctx2), 0))
+ goto err;
+
+#else
/* Compute keyexchange in both directions */
if (!TEST_ptr(pctx1 = EVP_PKEY_CTX_new(pkey1, NULL))
|| !TEST_int_eq(EVP_PKEY_derive_init(pctx1), 1)
@@ -3474,7 +3507,7 @@ static int custom_params_test(int id)
/* compare with previous result */
|| !TEST_mem_eq(export, export_size, buf2, sslen))
goto err;
-
+#endif
ret = 1;
err:
@@ -3561,7 +3594,9 @@ int setup_tests(void)
ADD_TEST(parameter_test);
ADD_TEST(ossl_parameter_test);
+#ifndef OPENSSL_NO_EC_EXPLICIT_CURVES
ADD_TEST(cofactor_range_test);
+#endif
ADD_ALL_TESTS(cardinality_test, (int)crv_len);
ADD_TEST(prime_field_tests);
#ifndef OPENSSL_NO_EC2M
diff --git a/test/evp_test.c b/test/evp_test.c
index c8920b6f73..7ce3be9779 100644
--- a/test/evp_test.c
+++ b/test/evp_test.c
@@ -5433,8 +5433,16 @@ top:
pkey = NULL;
start:
if (strcmp(pp->key, "PrivateKey") == 0) {
+ int unsupported = 0;
+
pkey = PEM_read_bio_PrivateKey_ex(t->s.key, NULL, 0, NULL, libctx, NULL);
- if (pkey == NULL && !key_unsupported()) {
+ if (pkey == NULL)
+ unsupported = key_unsupported();
+#ifdef OPENSSL_NO_EC_EXPLICIT_CURVES
+ if (strcmp(pp->value, "EC_EXPLICIT") == 0)
+ unsupported = 1;
+#endif
+ if (pkey == NULL && !unsupported) {
EVP_PKEY_free(pkey);
TEST_info("Can't read private key %s", pp->value);
TEST_openssl_errors();