Skip to content

Crash when TLS authentication fails with verify_peer #21613

Closed as duplicate

Description

@bwoebi

Description

The following code:

<?php

// Start a local "proxy" that answers CONNECT with 200 then closes immediately,
// causing the SSL handshake to fail on the client side.
$server = stream_socket_server("tcp://127.0.0.1:0", $errno, $errstr);
if (!$server) {
    die("Could not start proxy server: $errstr\n");
}
$proxyAddr = stream_socket_get_name($server, false);

$pid = pcntl_fork();
if ($pid === -1) {
    die("pcntl_fork failed\n");
}

if ($pid === 0) {
    // Child: minimal HTTP CONNECT proxy
    $conn = stream_socket_accept($server, 5);
    if ($conn) {
        // Drain the CONNECT request headers
        while (($line = fgets($conn)) !== false) {
            if (rtrim($line) === '') {
                break;
            }
        }
        // Acknowledge the tunnel — then immediately close.
        // The client will attempt the TLS handshake and fail.
        fwrite($conn, "HTTP/1.1 200 Connection established\r\n\r\n");
        fclose($conn);
    }
    exit(0);
}

// Parent: HTTPS request through the proxy.
// 'verify_peer' => true ensures reset_ssl_peer_name is set (peer_name not pre-set).
// No cafile needed; the TLS handshake itself will fail because the proxy closed.
$ctx = stream_context_create([
    'ssl' => [
        'verify_peer'      => true,
        'verify_peer_name' => true,
    ],
    'http' => [
        'proxy' => "tcp://$proxyAddr",
    ],
]);

// Suppress the expected PHP warning; we only care about the crash.
@file_get_contents("https://127.0.0.1/", false, $ctx);

pcntl_waitpid($pid, $status);
echo "Done\n";

Resulted in this output:

     ==80357== Invalid read of size 8                                                                                       
     ==80357==    at 0x5980384: php_stream_url_wrap_http_ex (/usr/local/src/php/ext/standard/http_fopen_wrapper.c:580)       
     ==80357==    by 0x597F3AB: php_stream_url_wrap_http (/usr/local/src/php/ext/standard/http_fopen_wrapper.c:1204)       
     ==80357==    by 0xC5474B3: dd_stream_opener (handlers_httpstreams.c:112)             
     ==80357==    by 0xC546B7F: dd_stream_opener_https (handlers_httpstreams.c:130)
     ==80357==    by 0x5B5A657: _php_stream_open_wrapper_ex (/usr/local/src/php/main/streams/streams.c:2270)
     ==80357==    by 0x594B46F: zif_file_get_contents (/usr/local/src/php/ext/standard/file.c:409)
     ==80357==    by 0x57646DB: zif_phar_file_get_contents (/usr/local/src/php/ext/phar/func_interceptors.c:230)
     ==80357==    by 0x5D029FB: ZEND_DO_ICALL_SPEC_OBSERVER_HANDLER (zend_vm_execute.h:1487)
     ==80357==    by 0x5C7B50F: execute_ex (zend_vm_execute.h:116172)
     ==80357==    by 0x5C7B927: zend_execute (zend_vm_execute.h:121884)                                                                    
     ==80357==    by 0x5E09387: zend_execute_script (/usr/local/src/php/Zend/zend.c:1977)                                  
     ==80357==    by 0x5B23AE3: php_execute_script_ex (/usr/local/src/php/main/main.c:2641)
     ==80357==  Address 0x90 is not stack'd, malloc'd or (recently) free'd

The fix should be trivially putting the whole of

if (stream) {
char header_line[HTTP_HEADER_BLOCK_SIZE];
/* get response header */
while (php_stream_gets(stream, header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL) {
if (header_line[0] == '\n' ||
header_line[0] == '\r' ||
header_line[0] == '\0') {
break;
}
}
}
/* enable SSL transport layer */
if (stream) {
if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL) < 0 ||
php_stream_xport_crypto_enable(stream, 1) < 0) {
php_stream_wrapper_log_error(wrapper, options, "Cannot connect to HTTPS server through proxy");
php_stream_close(stream);
stream = NULL;
}
}
if (reset_ssl_peer_name) {
php_stream_context_unset_option(PHP_STREAM_CONTEXT(stream), "ssl", "peer_name");
}
into the same if (stream) branch.

PHP Version

PHP 8.4+

Introduced with 42f6c15.

Operating System

No response

Activity

  1. ndossche commented on Apr 2, 2026

    @ndossche
    Member

    Please see #21468 this seems like a dupe

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions