Bug #73929 [Opn->Fbk]: SSL client socket errors under load with SSL_CTX_new:null ssl method passed in
| From: | cmb@php.net | Date: | Thu, 19 Mar 2020 12:24:44 +0000 |
| Subject: | Bug #73929 [Opn->Fbk]: SSL client socket errors under load with SSL_CTX_new:null ssl method passed in | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-226179@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=73929&edit=1
ID: 73929
Updated by: cmb@php.net
Reported by: tonyp at valvesoftware dot com
Summary: SSL client socket errors under load with
SSL_CTX_new:null ssl method passed in
-Status: Open
+Status: Feedback
Type: Bug
Package: Sockets related
Operating System: Ubuntu 16.04
PHP Version: 7.0.14
-Assigned To:
+Assigned To: cmb
Block user comment: N
Private report: N
New Comment:
> The bug is actually that the CURL extension doesn't always clear
> the OpenSSL error stack upon encountering an error, [â¦]
Can you please check whether the fix for bug #78775 also solves
your issue? That fix is available as of PHP 7.2.25, 7.3.12 and
7.4.0.
Previous Comments:
------------------------------------------------------------------------
[2017-01-31 00:42:25] henryg at valvesoftware dot com
The PHP OpenSSL socket code is fragile in the face of any existing OpenSSL errors. The function
which performs SSL_read and SSL_write incorrectly fail the socket operation even when the operations
succeeded, but there was a pre-existing OpenSSL error.
Many extensions such as CURL can fill the OpenSSL error stack even when called from perfectly valid
PHP code, depending only on the behavior of the remote server. The only way to reliably use
fsockopen and other stream sockets with SSL in PHP is to always manually clear the OpenSSL error
stack using openssl_error_string() in a loop before every call to fsockopen(), fread() or fwrite().
This is obviously not reasonable behavior; the PHP OpenSSL socket implementation should instead
clear the OpenSSL error state (possibly reporting it to the log) before attempting new operations,
but the new operations should not fail due to old errors.
------------------------------------------------------------------------
[2017-01-27 23:29:58] henryg at valvesoftware dot com
The bug is actually that the CURL extension doesn't always clear the OpenSSL error stack upon
encountering an error, and then later the PHP socket implementation unconditionally checks
SSL_get_error even when the return value from SSL_read or SSL_write is positive (which should
indicate no error). PHP then believes that the error was related to the socket operation and aborts
the operation, when really the error was unrelated and just happened to be sitting on the OpenSSL
error stack.
------------------------------------------------------------------------
[2017-01-14 00:19:51] tonyp at valvesoftware dot com
Description:
------------
Almost every hit to our web server makes a socket request to another server. Under load, when using
PHP 7, we get errors like the following:
[Fri Jan 13 15:27:28.692030 2017] [proxy_fcgi:error] [pid 2362] [client <redacted>:60929]
AH01071: Got error 'PHP message: PHP Warning: fread(): SSL operation failed with code 1.
OpenSSL Error messages:\nerror:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed in
<redacted>
[Fri Jan 13 15:27:28.751464 2017] [proxy_fcgi:error] [pid 1960] [client <redacted>:61262]
AH01071: Got error 'PHP message: PHP Warning: fread(): SSL operation failed with code 1.
OpenSSL Error messages:\nerror:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed in
<redacted>
[Fri Jan 13 15:27:29.404802 2017] [proxy_fcgi:error] [pid 2362] [client <redacted>:60929]
AH01071: Got error 'PHP message: PHP Warning: fread(): SSL operation failed with code 1.
OpenSSL Error messages:\nerror:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed in
<redacted>
[Fri Jan 13 15:27:29.487308 2017] [proxy_fcgi:error] [pid 2346] [client <redacted>:63548]
AH01071: Got error 'PHP message: PHP Warning: fread(): SSL operation failed with code 1.
OpenSSL Error messages:\nerror:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed in
<redacted>
[Fri Jan 13 15:27:29.668853 2017] [proxy_fcgi:error] [pid 2420] [client <redacted>:42796]
AH01071: Got error 'PHP message: PHP Warning: fread(): SSL operation failed with code 1.
OpenSSL Error messages:\nerror:140A90C4:SSL routines:SSL_CTX_new:null ssl method passed in
<redacted>
I have verified that it's actually a socket resource being passed into fread.
We do not get these errors in PHP 5. We do not get errors when using non-SSL sockets. Using
persistent sockets seems to make the errors occur more frequently, but the problem still occurs when
not using persistent sockets. We do use non-SSL persistent sockets elsewhere for things like
connections to memcache (Memcache::pconnect).
I have tried PHP as an Apache module, and I have tried PHP-FPM. The problem occurs in both.
Unfortunately, I have not been able to come up with a reliable repro test script. I have got the
error to occur in a script that spins up 1,000 forks and has each fork connect and send data back
and forth using SSL sockets, but it's very unreliable. I'm not sure what's happening
in production to make the error happen more frequently.
The sockets are created using stream_socket_client with the STREAM_CLIENT_CONNECT flag. We create a
context using stream_context_create and set allow_self_signed to true. verify_peer and
verify_peer_name are set to false. I have not been able to verify whether or not the errors occur
without passing or context, or whether or not they occur using fsockopen. The errors occur if even
if a specific cipher is specified, or at least occur with the ciphers I've tried
(ECDHE-RSA-AES256-GCM-SHA384 for example).
The errors occur using ssl://, tls://, and tlsv1.2:// transports. The errors still occur when adding
a random identifier after the ip:port combo, for example: 'tls://10.1.2.3:1234/' .
rand(0,999999).
The code that's failing is an fread call immediately after an fwrite. The fwrite call returns a
positive value as it should, and the fread call fails immediately. I have not verified whether or
not the data sent by the fwrite call preceding the failing fread call is actually received by the
server.
Let me know if there's something I can try that will give you more information about the nature
of the problem.
Test script:
---------------
$context = stream_context_create();
stream_context_set_option( $context, 'ssl', 'allow_self_signed', true );
stream_context_set_option( $context, 'ssl', 'verify_peer', false );
stream_context_set_option( $context, 'ssl', 'verify_peer_name', false );
$this->m_pfSocket = stream_socket_client( 'tlsv1.2://' . $ip . ':' . $port,
$errno, $errstr, 1.0, STREAM_CLIENT_CONNECT, $context );
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=73929&edit=1