From d27d1fdc696387cc8849e950b7c2aeaa334df2b9 Mon Sep 17 00:00:00 2001 From: ThanhNguyxn Date: Fri, 13 Feb 2026 00:25:07 -0500 Subject: [PATCH] Fix GH-21083: openssl_pkey_new() fails for EC keys when private_key_bits is not set The MIN_KEY_LENGTH check in php_openssl_generate_private_key() was applied unconditionally to all key types, including EC where key size is determined by the curve rather than private_key_bits. This caused failures when private_key_bits defaulted to 0 (below the 384-bit minimum), particularly visible with OpenSSL 3.6's stricter error handling. Skip the minimum bits validation for EC key types since the parameter is not applicable to them. Closes GH-21083 --- NEWS | 3 +++ ext/openssl/openssl.c | 19 +++++++++++------ ext/openssl/tests/gh21083.phpt | 39 ++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 ext/openssl/tests/gh21083.phpt diff --git a/NEWS b/NEWS index f20e8d63b0259..2dc594397c301 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.31 +- OpenSSL: + . Fixed bug GH-21083 (openssl_pkey_new() fails for EC keys when + private_key_bits is not explicitly set). (ThanhNguyxn) 15 Jan 2026, PHP 8.3.30 diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 256d152158496..24020a42cac3a 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -3732,18 +3732,25 @@ static int php_openssl_get_evp_pkey_type(int key_type) { /* {{{ php_openssl_generate_private_key */ static EVP_PKEY * php_openssl_generate_private_key(struct php_x509_request * req) { - if (req->priv_key_bits < MIN_KEY_LENGTH) { - php_error_docref(NULL, E_WARNING, "Private key length must be at least %d bits, configured to %d", - MIN_KEY_LENGTH, req->priv_key_bits); - return NULL; - } - int type = php_openssl_get_evp_pkey_type(req->priv_key_type); if (type < 0) { php_error_docref(NULL, E_WARNING, "Unsupported private key type"); return NULL; } + /* EC key sizes are determined by the curve, not by private_key_bits, + * so the minimum key length check does not apply to them. */ + if ( +#ifdef HAVE_EVP_PKEY_EC + type != EVP_PKEY_EC && +#endif + req->priv_key_bits < MIN_KEY_LENGTH + ) { + php_error_docref(NULL, E_WARNING, "Private key length must be at least %d bits, configured to %d", + MIN_KEY_LENGTH, req->priv_key_bits); + return NULL; + } + int egdsocket, seeded; char *randfile = php_openssl_conf_get_string(req->req_config, req->section_name, "RANDFILE"); php_openssl_load_rand_file(randfile, &egdsocket, &seeded); diff --git a/ext/openssl/tests/gh21083.phpt b/ext/openssl/tests/gh21083.phpt new file mode 100644 index 0000000000000..ad41ff5192cd5 --- /dev/null +++ b/ext/openssl/tests/gh21083.phpt @@ -0,0 +1,39 @@ +--TEST-- +GH-21083: openssl_pkey_new() should not require private_key_bits for EC keys +--EXTENSIONS-- +openssl +--SKIPIF-- + +--FILE-- + 'prime256v1', + 'private_key_type' => OPENSSL_KEYTYPE_EC, + 'config' => $config, +]); +var_dump($key instanceof OpenSSLAsymmetricKey); + +$details = openssl_pkey_get_details($key); +var_dump($details['ec']['curve_name']); +var_dump($details['type'] === OPENSSL_KEYTYPE_EC); + +$key2 = openssl_pkey_new([ + 'curve_name' => 'secp384r1', + 'private_key_type' => OPENSSL_KEYTYPE_EC, + 'config' => $config, +]); +var_dump($key2 instanceof OpenSSLAsymmetricKey); + +$details2 = openssl_pkey_get_details($key2); +var_dump($details2['ec']['curve_name']); +?> +--EXPECT-- +bool(true) +string(10) "prime256v1" +bool(true) +bool(true) +string(9) "secp384r1"