From 19255f4b784cedf6dd4bb21e97def348d335dd69 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 2 May 2026 01:49:34 +0200 Subject: [PATCH 1/2] Backport compatibility changes for OpenSSL 4.0 This backports: - 266f85f4e89957a02142f5fc9baea723d57bd90b - ff1bb13315740a80c8072acb91d82ee3aed86c9d --- NEWS | 3 +++ ext/openssl/openssl.c | 16 ++++++++-------- ext/openssl/php_openssl.h | 4 +++- ext/openssl/xp_ssl.c | 14 +++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index aa91603d8723..c9b334b1645a 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,9 @@ PHP NEWS - Curl: . Add support for brotli and zstd on Windows. (Shivam Mathur) +- OpenSSL: + . Fix compatibility issues with OpenSSL 4.0. (jordikroon, Remi) + 18 Dec 2025, PHP 8.2.30 - Curl: diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 9e703f758636..1d467f5b50af 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -469,9 +469,9 @@ void php_openssl_store_errors() errors = OPENSSL_G(errors); do { - errors->top = (errors->top + 1) % ERR_NUM_ERRORS; + errors->top = (errors->top + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; if (errors->top == errors->bottom) { - errors->bottom = (errors->bottom + 1) % ERR_NUM_ERRORS; + errors->bottom = (errors->bottom + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; } errors->buffer[errors->top] = error_code; } while ((error_code = ERR_get_error())); @@ -685,7 +685,7 @@ static void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * static void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) /* {{{ */ { - add_assoc_stringl(val, key, (char *)str->data, str->length); + add_assoc_stringl(val, key, (const char *)ASN1_STRING_get0_data(str), ASN1_STRING_length(str)); } /* }}} */ @@ -718,12 +718,12 @@ static time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) /* {{{ */ } if (timestr_len < 13 && timestr_len != 11) { - php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", timestr->data); + php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", ASN1_STRING_get0_data(timestr)); return (time_t)-1; } if (ASN1_STRING_type(timestr) == V_ASN1_GENERALIZEDTIME && timestr_len < 15) { - php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", timestr->data); + php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", ASN1_STRING_get0_data(timestr)); return (time_t)-1; } @@ -1982,8 +1982,8 @@ static int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) } extension_data = X509_EXTENSION_get_data(extension); - p = extension_data->data; - length = extension_data->length; + p = ASN1_STRING_get0_data(extension_data); + length = ASN1_STRING_length(extension_data); if (method->it) { names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length, ASN1_ITEM_ptr(method->it))); @@ -6709,7 +6709,7 @@ PHP_FUNCTION(openssl_error_string) RETURN_FALSE; } - OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % ERR_NUM_ERRORS; + OPENSSL_G(errors)->bottom = (OPENSSL_G(errors)->bottom + 1) % PHP_OPENSSL_ERR_BUFFER_SIZE; val = OPENSSL_G(errors)->buffer[OPENSSL_G(errors)->bottom]; if (val) { diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 5cfadbedc982..fd7f818d30bd 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -44,6 +44,8 @@ extern zend_module_entry openssl_module_entry; #endif #endif +#define PHP_OPENSSL_ERR_BUFFER_SIZE 16 + #define OPENSSL_RAW_DATA 1 #define OPENSSL_ZERO_PADDING 2 #define OPENSSL_DONT_ZERO_PAD_KEY 4 @@ -73,7 +75,7 @@ extern zend_module_entry openssl_module_entry; #endif struct php_openssl_errors { - int buffer[ERR_NUM_ERRORS]; + int buffer[PHP_OPENSSL_ERR_BUFFER_SIZE]; int top; int bottom; }; diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index a0db38c20bc0..46b4de67ee7d 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -497,12 +497,12 @@ static bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) / } OPENSSL_free(cert_name); } else if (san->type == GEN_IPADD) { - if (san->d.iPAddress->length == 4) { + if (ASN1_STRING_length(san->d.iPAddress) == 4) { sprintf(ipbuffer, "%d.%d.%d.%d", - san->d.iPAddress->data[0], - san->d.iPAddress->data[1], - san->d.iPAddress->data[2], - san->d.iPAddress->data[3] + ASN1_STRING_get0_data(san->d.iPAddress)[0], + ASN1_STRING_get0_data(san->d.iPAddress)[1], + ASN1_STRING_get0_data(san->d.iPAddress)[2], + ASN1_STRING_get0_data(san->d.iPAddress)[3] ); if (strcasecmp(subject_name, (const char*)ipbuffer) == 0) { sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); @@ -511,9 +511,9 @@ static bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) / } } #ifdef HAVE_IPV6_SAN - else if (san->d.ip->length == 16 && subject_name_is_ipv6) { + else if (ASN1_STRING_length(san->d.ip) == 16 && subject_name_is_ipv6) { ipbuffer[0] = 0; - EXPAND_IPV6_ADDRESS(ipbuffer, san->d.iPAddress->data); + EXPAND_IPV6_ADDRESS(ipbuffer, ASN1_STRING_get0_data(san->d.iPAddress)); if (strcasecmp((const char*)subject_name_ipv6_expanded, (const char*)ipbuffer) == 0) { sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free); From d4c195c41c26115413fa96097827910b4c549025 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Fri, 1 May 2026 18:36:28 -0700 Subject: [PATCH 2/2] Zend/Optimizer/block_pass.c: remove code disabled with `#if 0` (#21791) It has been that way since the initial public release of the optimizer in 528006a3b49fd45d6b2803c7b7843b2e7d6929d6 and survived through the merging as ext/opcache (34d3202edac0a56b91eb8a305fc1801bbd9b7653) and then moving it into core (#6642). If it hasn't been needed in the last 13 years, should be safe to drop. --- Zend/Optimizer/block_pass.c | 53 ------------------------------------- 1 file changed, 53 deletions(-) diff --git a/Zend/Optimizer/block_pass.c b/Zend/Optimizer/block_pass.c index c85b444640a8..02c28ead33e1 100644 --- a/Zend/Optimizer/block_pass.c +++ b/Zend/Optimizer/block_pass.c @@ -344,59 +344,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array } break; -#if 0 - /* pre-evaluate functions: - constant(x) - function_exists(x) - extension_loaded(x) - BAD: interacts badly with Accelerator - */ - if((opline->op1_type & IS_VAR) && - VAR_SOURCE(opline->op1) && VAR_SOURCE(opline->op1)->opcode == ZEND_DO_CF_FCALL && - VAR_SOURCE(opline->op1)->extended_value == 1) { - zend_op *fcall = VAR_SOURCE(opline->op1); - zend_op *sv = fcall-1; - if(sv >= block->start_opline && sv->opcode == ZEND_SEND_VAL && - sv->op1_type == IS_CONST && Z_TYPE(OPLINE_OP1_LITERAL(sv)) == IS_STRING && - Z_LVAL(OPLINE_OP2_LITERAL(sv)) == 1 - ) { - zval *arg = &OPLINE_OP1_LITERAL(sv); - char *fname = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].function_name; - size_t flen = FUNCTION_CACHE->funcs[Z_LVAL(ZEND_OP1_LITERAL(fcall))].name_len; - if((flen == sizeof("function_exists")-1 && zend_binary_strcasecmp(fname, flen, "function_exists", sizeof("function_exists")-1) == 0) || - (flen == sizeof("is_callable")-1 && zend_binary_strcasecmp(fname, flen, "is_callable", sizeof("is_callable")-1) == 0) - ) { - zend_function *function; - if((function = zend_hash_find_ptr(EG(function_table), Z_STR_P(arg))) != NULL) { - literal_dtor(arg); - MAKE_NOP(sv); - MAKE_NOP(fcall); - LITERAL_BOOL(opline->op1, 1); - opline->op1_type = IS_CONST; - } - } else if(flen == sizeof("constant")-1 && zend_binary_strcasecmp(fname, flen, "constant", sizeof("constant")-1) == 0) { - zval c; - if (zend_optimizer_get_persistent_constant(Z_STR_P(arg), &c, true ELS_CC)) { - literal_dtor(arg); - MAKE_NOP(sv); - MAKE_NOP(fcall); - ZEND_OP1_LITERAL(opline) = zend_optimizer_add_literal(op_array, &c); - /* no copy ctor - get already copied it */ - opline->op1_type = IS_CONST; - } - } else if(flen == sizeof("extension_loaded")-1 && zend_binary_strcasecmp(fname, flen, "extension_loaded", sizeof("extension_loaded")-1) == 0) { - if(zend_hash_exists(&module_registry, Z_STR_P(arg))) { - literal_dtor(arg); - MAKE_NOP(sv); - MAKE_NOP(fcall); - LITERAL_BOOL(opline->op1, 1); - opline->op1_type = IS_CONST; - } - } - } - } -#endif - case ZEND_FETCH_LIST_R: case ZEND_FETCH_LIST_W: if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) {