From bb2df033ccf2b5166904378928cba07eb49e450b Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Tue, 9 Jun 2026 22:40:15 +0530 Subject: [PATCH 1/3] Fix OpenSSL 4 test compatibility --- ext/openssl/openssl.c | 4 ++-- ext/openssl/openssl_backend_v3.c | 2 +- ext/openssl/php_openssl.h | 1 + ext/openssl/tests/bug28382.phpt | 8 ++++++- ext/openssl/tests/ecc_custom_params.phpt | 24 +++++++++++++++++++ .../openssl_x509_parse_basic_openssl32.phpt | 20 ++++++++++++++-- ext/openssl/xp_ssl.c | 2 +- 7 files changed, 54 insertions(+), 7 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index e7f29c6a354b..993da394895b 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -810,7 +810,7 @@ PHP_MINIT_FUNCTION(openssl) ssl_stream_data_index = SSL_get_ex_new_index(0, "PHP stream index", NULL, NULL, NULL); php_stream_xport_register("ssl", php_openssl_ssl_socket_factory); -#ifndef OPENSSL_NO_SSL3 +#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3) php_stream_xport_register("sslv3", php_openssl_ssl_socket_factory); #endif php_stream_xport_register("tls", php_openssl_ssl_socket_factory); @@ -884,7 +884,7 @@ PHP_MSHUTDOWN_FUNCTION(openssl) php_unregister_url_stream_wrapper("ftps"); php_stream_xport_unregister("ssl"); -#ifndef OPENSSL_NO_SSL3 +#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3) php_stream_xport_unregister("sslv3"); #endif php_stream_xport_unregister("tls"); diff --git a/ext/openssl/openssl_backend_v3.c b/ext/openssl/openssl_backend_v3.c index 339ff53f7b62..375c0104fac5 100644 --- a/ext/openssl/openssl_backend_v3.c +++ b/ext/openssl/openssl_backend_v3.c @@ -402,7 +402,7 @@ EVP_PKEY *php_openssl_pkey_init_ec(zval *data, bool *is_private) { } OPENSSL_PKEY_SET_BN(data, cofactor); - if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor) || + if ((cofactor && !OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) || !EC_GROUP_set_generator(group, point_g, order, cofactor)) { goto cleanup; } diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index 20a04bbcd1a0..acd0ed1c90a6 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -23,6 +23,7 @@ extern zend_module_entry openssl_module_entry; #include "php_version.h" #define PHP_OPENSSL_VERSION PHP_VERSION +#include #include /* OpenSSL version check */ #if OPENSSL_VERSION_NUMBER < 0x30000000L diff --git a/ext/openssl/tests/bug28382.phpt b/ext/openssl/tests/bug28382.phpt index e2842023135c..7627da2931b5 100644 --- a/ext/openssl/tests/bug28382.phpt +++ b/ext/openssl/tests/bug28382.phpt @@ -6,6 +6,12 @@ openssl = 0x40000000) { + $extensions = &$ext['extensions']; + $extensions['crlDistributionPoints'] = preg_replace('/^Full Name:\R\s*/', '', trim($extensions['crlDistributionPoints'])); +} + var_dump($ext['extensions']); /* * The reason for %A at the end of crlDistributionPoints and authorityKeyIdentifier is that @@ -30,7 +36,7 @@ array(11) { string(59) "B0:A7:FF:F9:41:15:DE:23:39:BD:DD:31:0F:97:A0:B2:A2:74:E0:FC" ["authorityKeyIdentifier"]=> string(%d) "DirName:/C=RO/ST=Romania/L=Craiova/O=Sergiu/OU=Sergiu SRL/CN=Sergiu CA/emailAddress=n_sergiu@hotmail.com -serial:00%A" +serial:%A" ["keyUsage"]=> string(71) "Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment" ["nsBaseUrl"]=> diff --git a/ext/openssl/tests/ecc_custom_params.phpt b/ext/openssl/tests/ecc_custom_params.phpt index 0c63af1450ba..e3854eefa4d8 100644 --- a/ext/openssl/tests/ecc_custom_params.phpt +++ b/ext/openssl/tests/ecc_custom_params.phpt @@ -5,6 +5,30 @@ openssl --SKIPIF-- = 0x40000000) { + $d = hex2bin('8D0AC65AAEA0D6B96254C65817D4A143A9E7A03876F1A37D'); + $p = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D46F4C318CEFE4AFE3B6B8551F'); + $a = hex2bin('BB8E5E8FBC115E139FE6A814FE48AAA6F0ADA1AA5DF91985'); + $b = hex2bin('1854BEBDC31B21B7AEFC80AB0ECD10D5B1B3308E6DBF11C1'); + $g_x = hex2bin('4AD5F7048DE709AD51236DE65E4D4B482C836DC6E4106640'); + $g_y = hex2bin('02BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2'); + $order = hex2bin('BDB6F4FE3E8B1D9E0DA8C0D40FC962195DFAE76F56564677'); + + if (@openssl_pkey_new(array( + 'ec' => array( + 'p' => $p, + 'a' => $a, + 'b' => $b, + 'order' => $order, + 'g_x' => $g_x, + 'g_y' => $g_y, + 'd' => $d, + ), + )) === false) { + die("skip EC custom params unsupported with OpenSSL 4"); + } +} ?> --FILE-- = 3.2'); ?> --FILE-- --EXPECTF-- bool(true) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index a154aa4572f7..9b94eaca04bf 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -93,7 +93,7 @@ #define HAVE_SEC_LEVEL 1 #endif -#ifndef OPENSSL_NO_SSL3 +#if OPENSSL_VERSION_NUMBER < 0x40000000L && !defined(OPENSSL_NO_SSL3) #define HAVE_SSL3 1 #define PHP_OPENSSL_MIN_PROTO_VERSION STREAM_CRYPTO_METHOD_SSLv3 #else From 782a1d1b6e09a054961aa0ef83e5f9cd8528db61 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Wed, 10 Jun 2026 14:40:52 +0530 Subject: [PATCH 2/3] Fix OpenSSL 4 build compatibility --- ext/openssl/openssl.c | 6 ++--- ext/openssl/openssl_backend_common.c | 33 +++++++++++++++++------ ext/openssl/php_openssl_backend.h | 12 ++++++--- ext/openssl/xp_ssl.c | 40 +++++++++++++++++++++------- 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 993da394895b..a41ad4e7b1ef 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1384,8 +1384,8 @@ PHP_FUNCTION(openssl_x509_parse) zval subitem; zval critext; int critcount = 0; - X509_EXTENSION *extension; - X509_NAME *subject_name; + PHP_OPENSSL_X509_EXTENSION *extension; + const X509_NAME *subject_name; char *cert_name; char *extname; BIO *bio_out; @@ -2359,7 +2359,7 @@ PHP_FUNCTION(openssl_csr_get_subject) zend_object *csr_obj; zend_string *csr_str; bool use_shortnames = 1; - X509_NAME *subject; + const X509_NAME *subject; ZEND_PARSE_PARAMETERS_START(1, 2) Z_PARAM_OBJ_OF_CLASS_OR_STR(csr_obj, php_openssl_request_ce, csr_str) diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 5aa8d246177e..5db2a65ce573 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -33,16 +33,16 @@ /* true global; readonly after module startup */ static char default_ssl_conf_filename[MAXPATHLEN]; -void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname) +void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname) { zval *data; zval subitem, tmp; int i; char *sname; int nid; - X509_NAME_ENTRY * ne; - ASN1_STRING * str = NULL; - ASN1_OBJECT * obj; + const X509_NAME_ENTRY * ne; + const ASN1_STRING * str = NULL; + const ASN1_OBJECT * obj; if (key != NULL) { array_init(&subitem); @@ -106,7 +106,7 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, } } -void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str) +void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str) { add_assoc_stringl(val, key, (const char *)ASN1_STRING_get0_data(str), ASN1_STRING_length(str)); } @@ -612,11 +612,11 @@ zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool r /* Special handling of subjectAltName, see CVE-2013-4073 * Christian Heimes */ -int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension) +int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension) { GENERAL_NAMES *names; const X509V3_EXT_METHOD *method = NULL; - ASN1_OCTET_STRING *extension_data; + const ASN1_OCTET_STRING *extension_data; long i, length, num; const unsigned char *p; @@ -972,7 +972,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr, zval *item, *subitem; zend_string *strindex = NULL; - subj = X509_REQ_get_subject_name(csr); + subj = X509_NAME_new(); + if (subj == NULL) { + php_openssl_store_errors(); + return FAILURE; + } + /* apply values from the dn hash */ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(dn), strindex, item) { if (strindex) { @@ -981,10 +986,12 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr, if (Z_TYPE_P(item) == IS_ARRAY) { ZEND_HASH_FOREACH_NUM_KEY_VAL(Z_ARRVAL_P(item), i, subitem) { if (php_openssl_csr_add_subj_entry(subitem, subj, nid) == FAILURE) { + X509_NAME_free(subj); return FAILURE; } } ZEND_HASH_FOREACH_END(); } else if (php_openssl_csr_add_subj_entry(item, subj, nid) == FAILURE) { + X509_NAME_free(subj); return FAILURE; } } else { @@ -1035,13 +1042,23 @@ zend_result php_openssl_csr_make(struct php_x509_request * req, X509_REQ * csr, if (!X509_NAME_add_entry_by_txt(subj, type, MBSTRING_UTF8, (unsigned char*)v->value, -1, -1, 0)) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "add_entry_by_txt %s -> %s (failed)", type, v->value); + X509_NAME_free(subj); return FAILURE; } if (!X509_NAME_entry_count(subj)) { php_error_docref(NULL, E_WARNING, "No objects specified in config file"); + X509_NAME_free(subj); return FAILURE; } } + + if (!X509_REQ_set_subject_name(csr, subj)) { + php_openssl_store_errors(); + X509_NAME_free(subj); + return FAILURE; + } + X509_NAME_free(subj); + if (attribs) { ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(attribs), strindex, item) { int nid; diff --git a/ext/openssl/php_openssl_backend.h b/ext/openssl/php_openssl_backend.h index 2d37e594ea57..ce9ac390bf7f 100644 --- a/ext/openssl/php_openssl_backend.h +++ b/ext/openssl/php_openssl_backend.h @@ -35,6 +35,12 @@ #include #include +#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 4 +typedef const X509_EXTENSION PHP_OPENSSL_X509_EXTENSION; +#else +typedef X509_EXTENSION PHP_OPENSSL_X509_EXTENSION; +#endif + /* number conversion flags checks */ #define PHP_OPENSSL_CHECK_NUMBER_CONVERSION(_cond, _name, _arg_num) \ do { \ @@ -166,8 +172,8 @@ struct php_x509_request { const EVP_CIPHER * priv_key_encrypt_cipher; }; -void php_openssl_add_assoc_name_entry(zval * val, char * key, X509_NAME * name, int shortname); -void php_openssl_add_assoc_asn1_string(zval * val, char * key, ASN1_STRING * str); +void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * name, int shortname); +void php_openssl_add_assoc_asn1_string(zval * val, char * key, const ASN1_STRING * str); time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr); int php_openssl_config_check_syntax(const char * section_label, const char * config_filename, const char * section, CONF *config); char *php_openssl_conf_get_string(CONF *conf, const char *group, const char *name); @@ -264,7 +270,7 @@ X509 *php_openssl_x509_from_zval( zend_string* php_openssl_x509_fingerprint(X509 *peer, const char *method, bool raw); -int openssl_x509v3_subjectAltName(BIO *bio, X509_EXTENSION *extension); +int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extension); STACK_OF(X509) *php_openssl_load_all_certs_from_file( char *cert_file, size_t cert_file_len, uint32_t arg_num); diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 9b94eaca04bf..cf0e3cc8ad80 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -273,7 +273,7 @@ static int php_openssl_handle_ssl_error(php_stream *stream, int nr_bytes, bool i errno = EAGAIN; retry = is_init ? true : sslsock->s.is_blocked; if (!retry) { - sslsock->last_status = err == SSL_ERROR_WANT_READ ? + sslsock->last_status = err == SSL_ERROR_WANT_READ ? STREAM_CRYPTO_STATUS_WANT_READ : STREAM_CRYPTO_STATUS_WANT_WRITE; } break; @@ -557,26 +557,46 @@ static bool php_openssl_matches_san_list(X509 *peer, const char *subject_name) / static bool php_openssl_matches_common_name(X509 *peer, const char *subject_name) /* {{{ */ { - char buf[1024]; - X509_NAME *cert_name; + unsigned char *cert_name = NULL; + const X509_NAME *name; + const X509_NAME_ENTRY *name_entry; + const ASN1_STRING *name_asn1; bool is_match = false; + int name_index; int cert_name_len; - cert_name = X509_get_subject_name(peer); - cert_name_len = X509_NAME_get_text_by_NID(cert_name, NID_commonName, buf, sizeof(buf)); + name = X509_get_subject_name(peer); + name_index = X509_NAME_get_index_by_NID(name, NID_commonName, -1); + if (name_index == -1) { + php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN"); + return false; + } - if (cert_name_len == -1) { + name_entry = X509_NAME_get_entry(name, name_index); + if (name_entry == NULL) { php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN"); - } else if ((size_t)cert_name_len != strlen(buf)) { - php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, buf); - } else if (php_openssl_matches_wildcard_name(subject_name, buf)) { + return false; + } + name_asn1 = X509_NAME_ENTRY_get_data(name_entry); + cert_name_len = ASN1_STRING_to_UTF8(&cert_name, name_asn1); + if (cert_name_len < 0) { + php_openssl_store_errors(); + php_error_docref(NULL, E_WARNING, "Unable to locate peer certificate CN"); + return false; + } + + if ((size_t)cert_name_len != strlen((const char *)cert_name)) { + php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' is malformed", cert_name_len, (const char *)cert_name); + } else if (php_openssl_matches_wildcard_name(subject_name, (const char *)cert_name)) { is_match = true; } else { php_error_docref(NULL, E_WARNING, "Peer certificate CN=`%.*s' did not match expected CN=`%s'", - cert_name_len, buf, subject_name); + cert_name_len, (const char *)cert_name, subject_name); } + OPENSSL_free(cert_name); + return is_match; } /* }}} */ From 6ffd0fa1fce0c3e043ad86923fd27f6b0328622e Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Wed, 10 Jun 2026 14:40:52 +0530 Subject: [PATCH 3/3] Use OpenSSL 4 in macOS CI --- .github/actions/brew/action.yml | 4 +++- .github/actions/configure-macos/action.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/actions/brew/action.yml b/.github/actions/brew/action.yml index f90a66f239de..db43010f396f 100644 --- a/.github/actions/brew/action.yml +++ b/.github/actions/brew/action.yml @@ -33,4 +33,6 @@ runs: t1lib \ libxml2 \ libjpeg \ - libxslt + libxslt \ + openssl@4 + brew link --force --overwrite openssl@4 diff --git a/.github/actions/configure-macos/action.yml b/.github/actions/configure-macos/action.yml index f0af959d2102..b9739a790530 100644 --- a/.github/actions/configure-macos/action.yml +++ b/.github/actions/configure-macos/action.yml @@ -11,7 +11,7 @@ runs: set -x BREW_OPT="$(brew --prefix)"/opt export PATH="$BREW_OPT/bison/bin:$PATH" - export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl/lib/pkgconfig" + export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/openssl@4/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/curl/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libffi/lib/pkgconfig" export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$BREW_OPT/libxml2/lib/pkgconfig"