From 2169b6810d2e76a5075e233b24d59ada87741959 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Sun, 25 Oct 2026 21:30:52 +0800 Subject: [PATCH 1/3] ext/openssl: Fix build with OpenSSL 4.1 --- NEWS | 3 +++ ext/openssl/openssl.c | 2 +- ext/openssl/openssl_backend_common.c | 14 +++++++------- ext/openssl/php_openssl_backend.h | 5 +++++ ext/openssl/xp_ssl.c | 8 ++++---- 5 files changed, 20 insertions(+), 12 deletions(-) diff --git a/NEWS b/NEWS index 1d89beaec1ae..c05e1cfe571f 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,9 @@ PHP NEWS . Fixed JIT treating an array as packed after a string key write turned it into a hash. (jorgsowa) +- OpenSSL: + . Fixed build with OpenSSL 4.1. (Weilin Du) + - PDO_PGSQL: . Fixed bug GH-24461 (DISCARD ALL on persistent connection cleanup drops PgBouncer's prepared statements). (David Carlier, Artem Ukrainskiy) diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index 0f36f7b42c59..aa02a1ead34d 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1019,7 +1019,7 @@ PHP_FUNCTION(openssl_spki_new) } if (challenge) { - if (!ASN1_STRING_set(spki->spkac->challenge, challenge, (int)challenge_len)) { + if (!ASN1_STRING_set1_data(spki->spkac->challenge, (const unsigned char *) challenge, challenge_len)) { php_openssl_store_errors(); php_error_docref(NULL, E_WARNING, "Unable to set challenge data"); goto cleanup; diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 8ea132a1ab0c..8fb76ee4c0e8 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -72,7 +72,7 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * } else { /* ASN1_STRING_get0_data(3): Since this is an internal pointer it should not be freed or modified in any way */ to_add = ASN1_STRING_get0_data(str); - to_add_len = ASN1_STRING_length(str); + to_add_len = ASN1_STRING_get_length(str); } if (to_add_len != -1) { @@ -107,7 +107,7 @@ void php_openssl_add_assoc_name_entry(zval * val, char * key, const X509_NAME * 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)); + add_assoc_stringl(val, key, (const char *)ASN1_STRING_get0_data(str), ASN1_STRING_get_length(str)); } time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) @@ -131,7 +131,7 @@ time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) return (time_t)-1; } - timestr_len = (size_t)ASN1_STRING_length(timestr); + timestr_len = ASN1_STRING_get_length(timestr); if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) { php_error_docref(NULL, E_WARNING, "Illegal length in timestamp"); @@ -636,7 +636,7 @@ int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extensio extension_data = X509_EXTENSION_get_data(extension); p = ASN1_STRING_get0_data(extension_data); - length = ASN1_STRING_length(extension_data); + length = ASN1_STRING_get_length(extension_data); if (method->it) { names = (GENERAL_NAMES*) (ASN1_item_d2i(NULL, &p, length, ASN1_ITEM_ptr(method->it))); @@ -658,19 +658,19 @@ int openssl_x509v3_subjectAltName(BIO *bio, PHP_OPENSSL_X509_EXTENSION *extensio BIO_puts(bio, "email:"); as = name->d.rfc822Name; BIO_write(bio, ASN1_STRING_get0_data(as), - ASN1_STRING_length(as)); + ASN1_STRING_get_length(as)); break; case GEN_DNS: BIO_puts(bio, "DNS:"); as = name->d.dNSName; BIO_write(bio, ASN1_STRING_get0_data(as), - ASN1_STRING_length(as)); + ASN1_STRING_get_length(as)); break; case GEN_URI: BIO_puts(bio, "URI:"); as = name->d.uniformResourceIdentifier; BIO_write(bio, ASN1_STRING_get0_data(as), - ASN1_STRING_length(as)); + ASN1_STRING_get_length(as)); break; default: /* use builtin print for GEN_OTHERNAME, GEN_X400, diff --git a/ext/openssl/php_openssl_backend.h b/ext/openssl/php_openssl_backend.h index fcbb8d42542f..364f27eec23e 100644 --- a/ext/openssl/php_openssl_backend.h +++ b/ext/openssl/php_openssl_backend.h @@ -35,6 +35,11 @@ #include #include +#if OPENSSL_VERSION_NUMBER < 0x40100000L +#define ASN1_STRING_set1_data(str, data, len) ASN1_STRING_set((str), (data), (int) (len)) +#define ASN1_STRING_get_length(str) ((size_t) ASN1_STRING_length(str)) +#endif + #if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 4 typedef const X509_EXTENSION PHP_OPENSSL_X509_EXTENSION; #else diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index ad06af444ffe..5cead037715a 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -541,7 +541,7 @@ static bool php_openssl_matches_san_list( /* TODO: warn ? */ continue; } - if ((size_t)ASN1_STRING_length(san->d.dNSName) != strlen((const char*)cert_name)) { + if (ASN1_STRING_get_length(san->d.dNSName) != strlen((const char*)cert_name)) { OPENSSL_free(cert_name); /* prevent null-byte poisoning*/ continue; @@ -561,7 +561,7 @@ static bool php_openssl_matches_san_list( } OPENSSL_free(cert_name); } else if (san->type == GEN_IPADD) { - if (ASN1_STRING_length(san->d.iPAddress) == 4) { + if (ASN1_STRING_get_length(san->d.iPAddress) == 4) { snprintf(ipbuffer, sizeof(ipbuffer), "%d.%d.%d.%d", ASN1_STRING_get0_data(san->d.iPAddress)[0], ASN1_STRING_get0_data(san->d.iPAddress)[1], @@ -575,7 +575,7 @@ static bool php_openssl_matches_san_list( } } #ifdef HAVE_IPV6_SAN - else if (ASN1_STRING_length(san->d.ip) == 16 && subject_name_is_ipv6) { + else if (ASN1_STRING_get_length(san->d.ip) == 16 && subject_name_is_ipv6) { ipbuffer[0] = 0; EXPAND_IPV6_ADDRESS(ipbuffer, ASN1_STRING_get0_data(san->d.iPAddress)); if (strcasecmp((const char*)subject_name_ipv6_expanded, (const char*)ipbuffer) == 0) { @@ -630,7 +630,7 @@ static bool php_openssl_matches_common_name(php_stream *stream, const X509 *peer return false; } name_asn1 = X509_NAME_ENTRY_get_data(name_entry); - cert_name_len = ASN1_STRING_length(name_asn1); + cert_name_len = ASN1_STRING_get_length(name_asn1); cert_name = (unsigned char *) OPENSSL_strndup((const char *) ASN1_STRING_get0_data(name_asn1), cert_name_len); if (cert_name == NULL) { php_stream_warn(stream, NetworkRecvFailed, "Unable to locate peer certificate CN"); From 1ef92a5b79d80abf65e1fe6d7009f55095ec6ad7 Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Mon, 26 Oct 2026 15:47:37 +0800 Subject: [PATCH 2/3] feedback Co-Authored-By: Shivam Mathur --- ext/openssl/openssl.c | 3 ++- ext/openssl/openssl_backend_common.c | 10 ++++++---- .../openssl_spki_export_challenge_binary.phpt | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 ext/openssl/tests/openssl_spki_export_challenge_binary.phpt diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index aa02a1ead34d..0466bbf06c6c 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -1206,7 +1206,8 @@ PHP_FUNCTION(openssl_spki_export_challenge) goto cleanup; } - RETVAL_STRING((const char *)ASN1_STRING_get0_data(spki->spkac->challenge)); + RETVAL_STRINGL_FAST((const char *)ASN1_STRING_get0_data(spki->spkac->challenge), + ASN1_STRING_get_length(spki->spkac->challenge)); goto cleanup; cleanup: diff --git a/ext/openssl/openssl_backend_common.c b/ext/openssl/openssl_backend_common.c index 8fb76ee4c0e8..995d836deead 100644 --- a/ext/openssl/openssl_backend_common.c +++ b/ext/openssl/openssl_backend_common.c @@ -123,6 +123,7 @@ time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) struct tm thetime; char * strbuf; char * thestr; + const char *timestr_data; long gmadjust = 0; size_t timestr_len; @@ -132,23 +133,24 @@ time_t php_openssl_asn1_time_to_time_t(ASN1_UTCTIME * timestr) } timestr_len = ASN1_STRING_get_length(timestr); + timestr_data = timestr_len ? (const char *)ASN1_STRING_get0_data(timestr) : ""; - if (timestr_len != strlen((const char *)ASN1_STRING_get0_data(timestr))) { + if (memchr(timestr_data, '\0', timestr_len) != NULL) { php_error_docref(NULL, E_WARNING, "Illegal length in timestamp"); return (time_t)-1; } if (timestr_len < 13) { - php_error_docref(NULL, E_WARNING, "Unable to parse time string %s correctly", ASN1_STRING_get0_data(timestr)); + php_error_docref(NULL, E_WARNING, "Unable to parse time string %.*s correctly", (int)timestr_len, timestr_data); 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", ASN1_STRING_get0_data(timestr)); + php_error_docref(NULL, E_WARNING, "Unable to parse time string %.*s correctly", (int)timestr_len, timestr_data); return (time_t)-1; } - strbuf = estrdup((const char *)ASN1_STRING_get0_data(timestr)); + strbuf = estrndup(timestr_data, timestr_len); memset(&thetime, 0, sizeof(thetime)); diff --git a/ext/openssl/tests/openssl_spki_export_challenge_binary.phpt b/ext/openssl/tests/openssl_spki_export_challenge_binary.phpt new file mode 100644 index 000000000000..d5eb8617cb1f --- /dev/null +++ b/ext/openssl/tests/openssl_spki_export_challenge_binary.phpt @@ -0,0 +1,19 @@ +--TEST-- +openssl_spki_export_challenge() preserves empty challenges and embedded NUL bytes +--EXTENSIONS-- +openssl +--FILE-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) From 22ea4b2400da2f17ee699e02f2c1e347dcfcbbef Mon Sep 17 00:00:00 2001 From: Weilin Du Date: Mon, 26 Oct 2026 16:55:19 +0800 Subject: [PATCH 3/3] Fix CI --- .../tests/session_resumption_get_cb_num_tickets_positive.phpt | 1 + ext/openssl/tests/session_unserialize_repeat.phpt | 1 + 2 files changed, 2 insertions(+) diff --git a/ext/openssl/tests/session_resumption_get_cb_num_tickets_positive.phpt b/ext/openssl/tests/session_resumption_get_cb_num_tickets_positive.phpt index 5563b0c22cf8..5c7512d73a35 100644 --- a/ext/openssl/tests/session_resumption_get_cb_num_tickets_positive.phpt +++ b/ext/openssl/tests/session_resumption_get_cb_num_tickets_positive.phpt @@ -16,6 +16,7 @@ $serverCode = <<<'CODE' // Test with num_tickets = 3 (should issue 3 tickets) $ctx = stream_context_create(['ssl' => [ 'local_cert' => '%s', + 'session_id_context' => 'num-tickets-test', 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_3_SERVER, 'num_tickets' => 3, // Issue 3 tickets per connection ]]); diff --git a/ext/openssl/tests/session_unserialize_repeat.phpt b/ext/openssl/tests/session_unserialize_repeat.phpt index b1e33c2d03bd..20084df4fb24 100644 --- a/ext/openssl/tests/session_unserialize_repeat.phpt +++ b/ext/openssl/tests/session_unserialize_repeat.phpt @@ -13,6 +13,7 @@ $certFile = __DIR__ . DIRECTORY_SEPARATOR . 'session_unserialize_repeat.pem.tmp' $serverCode = <<<'CODE' $serverCtx = stream_context_create(['ssl' => [ 'local_cert' => '%s', + 'session_id_context' => 'unserialize-repeat-test', ]]); $server = stream_socket_server('tls://127.0.0.1:0', $errno, $errstr,