[php-src] Issue #9261: Problem with enabling crypto on steam socket connection
| From: | stefanak-michal | Date: | Sat, 06 Aug 2022 19:54:22 +0000 |
| Subject: | [php-src] Issue #9261: Problem with enabling crypto on steam socket connection | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-242142@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/9261
Author: 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
<?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