|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2008-08-13 17:41 UTC] six at aegis-corp dot org
Description:
------------
The documentation says about stream_socket_enable_crypto :
Returns TRUE on success, FALSE if negotiation has failed or 0 if there isn't enough data and you should try again (only for non-blocking sockets).
In practice, if you feed a non blocking server socket to it, it will block and consume lots of CPU until the SSL/TLS handshake is done or the client connection is dropped.
Reproduce code:
---------------
<?php
$s = stream_socket_server("tcp://127.0.0.1:8888");
$c = stream_socket_accept($s);
stream_set_blocking($c, false);
$ret = stream_socket_enable_crypto($c, true, STREAM_CRYPTO_METHOD_TLS_SERVER);
var_dump($ret);
?>
then just "telnet localhost 8888" from another term
Expected result:
----------------
script should print "int(0)" and exit
Actual result:
--------------
script blocks at the stream_socket_enable_crypto() call and is stuck in a CPU consuming loop until the client connection is either handshaked or dropped.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Nov 08 20:00:02 2025 UTC |
Bug is in ext/openssl/xp_ssl.c Function handle_ssl_error: (line 107) case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_WRITE: /* re-negotiation, or perhaps the SSL layer needs more * packets: retry in next iteration */ errno = EAGAIN; retry = is_init ? 1 : sslsock->s.is_blocked; //BUG break; it sets retry to 1 in php_openssl_enable_crypto no matter if socket is blocking or not.Here is a patch to fix this issue (diff against 5.3.0) As far as I have tested, everything works as expected with this patch applied. --- xp_ssl.c.orig 2009-10-12 19:34:31.000000000 +0200 +++ xp_ssl.c 2009-10-12 20:39:19.000000000 +0200 @@ -299,8 +299,12 @@ SSL_METHOD *method; if (sslsock->ssl_handle) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); - return -1; + if (sslsock->is_client) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); + return -1; + } else { + return 0; + } } /* need to do slightly different things, based on client/server method, @@ -415,7 +419,7 @@ } if (n <= 0) { - retry = handle_ssl_error(stream, n, 1 TSRMLS_CC); + retry = handle_ssl_error(stream, n, sslsock->is_client TSRMLS_CC); } else { break; }Actually I fixed some things in the patch, see below ... It makes more sense to test whether the socket is in blocking mode, even if a client ssl socket doesn't need multiple calls to stream_socket_enable_crypto() --- xp_ssl.c.orig 2009-10-12 19:34:31.000000000 +0200 +++ xp_ssl.c 2009-10-13 12:30:24.000000000 +0200 @@ -299,8 +299,12 @@ SSL_METHOD *method; if (sslsock->ssl_handle) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); - return -1; + if (sslsock->s.is_blocked) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "SSL/TLS already set-up for this stream"); + return -1; + } else { + return 0; + } } /* need to do slightly different things, based on client/server method, @@ -415,7 +419,7 @@ } if (n <= 0) { - retry = handle_ssl_error(stream, n, 1 TSRMLS_CC); + retry = handle_ssl_error(stream, n, sslsock->is_client || sslsock->s.is_blocked TSRMLS_CC); } else { break; }