Commit ae429f100b7 for php
commit ae429f100b70183a7d93e099be0dc911c49e019b
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Sat Sep 26 18:15:04 2026 -0400
ext/openssl: Restore blocking mode after a handshake timeout
A handshake timeout returned before php_openssl_enable_crypto() restored
the socket blocking mode saved at entry. That return now restores it, as
the normal return already does.
Closes GH-23932
diff --git a/NEWS b/NEWS
index 9756d72077d..7468a698253 100644
--- a/NEWS
+++ b/NEWS
@@ -81,6 +81,10 @@ PHP NEWS
(David Carlier)
. Fix incorrect DCE due to unsound escape analysis. (ndossche)
+- OpenSSL:
+ . Fixed stream_socket_enable_crypto() leaving the socket non-blocking
+ after a handshake timeout. (Ilia Alshanetsky)
+
- PCNTL:
. Fixed pcntl_signal_dispatch() dropping the queued signals when it runs while
an exception is pending. (nicolas-grekas)
diff --git a/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt b/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt
new file mode 100644
index 00000000000..39a8f973b86
--- /dev/null
+++ b/ext/openssl/tests/stream_crypto_enable_timeout_blocking.phpt
@@ -0,0 +1,53 @@
+--TEST--
+OpenSSL handshake timeout restores the stream blocking mode
+--EXTENSIONS--
+openssl
+--SKIPIF--
+<?php
+if (!function_exists('proc_open')) die('skip no proc_open');
+?>
+--FILE--
+<?php
+$serverCode = <<<'CODE'
+ $server = stream_socket_server('tcp://127.0.0.1:0', $errno, $errstr);
+ phpt_notify_server_start($server);
+
+ $conn = stream_socket_accept($server, 5);
+ phpt_wait();
+ fclose($conn);
+CODE;
+
+$clientCode = <<<'CODE'
+ $context = stream_context_create(['ssl' => [
+ 'verify_peer' => false,
+ 'verify_peer_name' => false,
+ ]]);
+ $client = stream_socket_client('tcp://{{ ADDR }}', $errno, $errstr, 1, STREAM_CLIENT_CONNECT, $context);
+
+ $metadata = stream_get_meta_data($client);
+ var_dump($metadata['blocked']);
+
+ set_error_handler(function (int $errno, string $errstr) use ($client): bool {
+ $metadata = stream_get_meta_data($client);
+ var_dump($metadata['blocked']);
+ echo $errstr, "\n";
+ fclose($client);
+ return true;
+ });
+
+ var_dump(stream_socket_enable_crypto($client, true, STREAM_CRYPTO_METHOD_TLS_CLIENT));
+ restore_error_handler();
+ var_dump(is_resource($client));
+
+ phpt_notify();
+CODE;
+
+include 'ServerClientTestCase.inc';
+ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
+?>
+--EXPECT--
+bool(true)
+bool(true)
+stream_socket_enable_crypto(): SSL: Handshake timed out
+bool(false)
+bool(false)
diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c
index ae12c8eb612..b564be8cad5 100644
--- a/ext/openssl/xp_ssl.c
+++ b/ext/openssl/xp_ssl.c
@@ -2004,6 +2004,7 @@ static int php_openssl_enable_crypto(php_stream *stream,
elapsed_time = php_openssl_subtract_timeval(cur_time, start_time);
if (php_openssl_compare_timeval( elapsed_time, *timeout) > 0) {
+ php_openssl_set_blocking(sslsock, blocked);
php_error_docref(NULL, E_WARNING, "SSL: Handshake timed out");
return -1;
}