Commit 3678f391d8f for php
commit 3678f391d8f64738cdb37d3e2a95aeba615413c4
Author: Weilin Du <weilindu@php.net>
Date: Tue Oct 27 01:37:55 2026 +0800
ext/openssl: Fix build with OpenSSL 4.1 (#24686)
OpenSSL 4.1 deprecates ASN1_STRING_set() and ASN1_STRING_length().
use ASN1_STRING_set1_data() and ASN1_STRING_get_length() instead as
recommended in official doc
https://docs.openssl.org/4.1/man7/ossl-guide-migration/#asn1_string-values-have-never-been-nul-byte-terminated
diff --git a/NEWS b/NEWS
index 1995c82d1e8..355ea8880a6 100644
--- a/NEWS
+++ b/NEWS
@@ -33,6 +33,9 @@ PHP NEWS
. Fixed bug GH-24745 (File cache loses attributes on constants on 32-bit
builds). (Yannick Decat, Lazizbek Ergashev)
+- 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 0f36f7b42c5..0466bbf06c6 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;
@@ -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 8ea132a1ab0..995d836deea 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)
@@ -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;
@@ -131,24 +132,25 @@ 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);
+ 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));
@@ -636,7 +638,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 +660,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 fcbb8d42542..364f27eec23 100644
--- a/ext/openssl/php_openssl_backend.h
+++ b/ext/openssl/php_openssl_backend.h
@@ -35,6 +35,11 @@
#include <openssl/pkcs12.h>
#include <openssl/cms.h>
+#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/tests/openssl_spki_export_challenge_binary.phpt b/ext/openssl/tests/openssl_spki_export_challenge_binary.phpt
new file mode 100644
index 00000000000..d5eb8617cb1
--- /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--
+<?php
+$key = openssl_pkey_get_private('file://' . __DIR__ . '/private_rsa_2048.key');
+
+foreach (["", "challenge", "\0challenge", "challenge\0", "left\0right"] as $challenge) {
+ $spkac = openssl_spki_new($key, $challenge, OPENSSL_ALGO_SHA256);
+ var_dump(openssl_spki_export_challenge(substr($spkac, 6)) === $challenge);
+}
+?>
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
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 5563b0c22cf..5c7512d73a3 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 @@
// 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 b1e33c2d03b..20084df4fb2 100644
--- a/ext/openssl/tests/session_unserialize_repeat.phpt
+++ b/ext/openssl/tests/session_unserialize_repeat.phpt
@@ -13,6 +13,7 @@
$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,
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index ad06af444ff..5cead037715 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");