Skip to content

Problem with enabling crypto on stream socket connection #9261

Description

@stefanak-michal

Description

Hi.

I'm trying to deal with some things in php and I can't find my workaround about it and it starting to feel like there is something buggy. I tried looking on internet even asked on stackoverflow but nothing.

My goal is to create stream socket connection with disabled SSL but request certificate, then analyze it and update connection parameters. It works great on server with SSL but when I try it on server without SSL I'm not able to write into that connection even when I try to disable crypto on it.

<?php
$context = stream_context_create([
    'socket' => [
        'tcp_nodelay' => true,
    ],
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false,
        'SNI_enabled' => false,
        'allow_self_signed' => true,
        'capture_peer_cert' => true,
        'capture_peer_cert_chain' => true
    ]
]);

$stream = stream_socket_client('tcp://' . $this->ip . ':' . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT, $context);
if ($stream === false) {
    throw new ConnectException($errstr, $errno);
}

if (!stream_set_blocking($stream, true)) {
    throw new ConnectException('Cannot set socket into blocking mode');
}

$enableCrypto = stream_socket_enable_crypto($stream, true, STREAM_CRYPTO_METHOD_ANY_CLIENT);
if ($enableCrypto === true) {
    $params = stream_context_get_params($stream);

    if (isset($params['options']['ssl']['peer_certificate']) && is_resource($params['options']['ssl']['peer_certificate'])) {
        $cert = openssl_x509_parse($params['options']['ssl']['peer_certificate']);
        stream_context_set_params($stream, [
            'ssl' => [
                'verify_peer' => true,
                'verify_peer_name' => true,
                'SNI_enabled' => true,
                'peer_name' => $cert['subject']['CN'],
                'allow_self_signed' => count($params['options']['ssl']['peer_certificate_chain']) == 1 && $cert['subject'] == $cert['issuer']
            ]
        ]);
    }
} else {
    stream_socket_enable_crypto($stream, false, STREAM_CRYPTO_METHOD_ANY_CLIENT);
}

You can see in the code what I described. I'm testing the connectivity against graph database Neo4j but I believe it doesn't matter. SSL certificate request is executed at first stream_socket_enable_crypto. Maybe there is different way to request capture of that certificate, I don't know.

What is weird when I enable crypto with stream_socket_enable_crypto against non-SSL host I get warning:

Warning: stream_socket_enable_crypto(): SSL: The operation completed successfully.

and $enableCrypto contains (int)0. The warning doesn't make sense.

After all this logic the connection is still open but when I try to use it I get error

Notice: fwrite(): send of 16 bytes failed with errno=10053 An established connection was aborted by the software in your host machine.

At this moment it feels like the encryption is enabled on client side (php) and the messages sent over socket therefore are not properly decoded on host, because there is no encryption at all. Like stream_socket_enable_crypto($stream, false) did not disable crypto.

PHP Version

PHP 7.4.16 with OpenSSL/1.1.1k and PHP 8.1.9 with OpenSSL/1.1.1q

Operating System

Windows 10

Activity

  1. stefanak-michal commented on Aug 6, 2022

    @stefanak-michal
    Author

    I would like to add when I don't call stream_socket_enable_crypto for the first time to enable it, it does work against non-SSL host without any problem.

  2. changed the title [-]Problem with enabling crypto on steam socket connection[/-] [+]Problem with enabling crypto on stream socket connection[/+] on Aug 6, 2022
  3. stefanak-michal commented on Aug 8, 2022

    @stefanak-michal
    Author

    I did some sniffing with Wireshark and I discovered when you invoke TLS handshake and host doesn't have SSL it answers with flag FIN (connection finish). That means the connection is closed by host immediatelly.

    Still the warning "SSL: The operation completed successfully." doesn't make sense.

  4. bukka commented on Aug 9, 2022

    @bukka
    Member

    Hmm I can't find any place where we would trigger such warning. I even double checked OpenSSL and nothing like this is there either. Are you sure this is a PHP warning and not something triggered by application?

  5. stefanak-michal commented on Aug 15, 2022

    @stefanak-michal
    Author

    I'll check it out more deeply and return.

  6. bukka commented on Aug 17, 2022

    @bukka
    Member

    I found the warning - it's actually OS socket error message prefixed with SSL:

    char *estr = php_socket_strerror(php_socket_errno(), NULL, 0);
    php_error_docref(NULL, E_WARNING,
    "SSL: %s", estr);
    .

    Coincidentally I just stumbled on it when writing a test for some SNI error and have to agree that this really does not make much sense. I will look into it.

  7. added a commit that references this issue on Jul 26, 2025
    0b4fbf9
  8. bukka commented on Jul 26, 2025

    @bukka
    Member

    I have been looking into this more closely.

    The error that I noticed before was actually something else: #19245 . It doesn't actually hit this specific SSL: %s at all.

    This looks more like a Windows specific issue because on syscall, errno should be usually set but it seems that for this particular case, it's 0 for some reason. I can't really see from the code why so might need to try it on Windows. I pushed a simple test (the linked commit above which is not the actual fix but just the test) so will give a try later and see.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions