php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #48182 asynchronous socket connection over ssl fails entirely
Submitted: 2009-05-07 16:23 UTC Modified: 2009-08-21 00:46 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:1 (100.0%)
From: frase at cs dot wisc dot edu Assigned: srinatar (profile)
Status: Closed Package: OpenSSL related
PHP Version: 5.2.11RC1 OS: *
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please !
Your email address:
MUST BE VALID
Solve the problem:
10 - 3 = ?
Subscribe to this entry?

 
 [2009-05-07 16:23 UTC] frase at cs dot wisc dot edu
Description:
------------
When opening a socket connection with stream_socket_client() and the ssl:// wrapper, the connect-asynchronously flag (STREAM_CLIENT_ASYNC_CONNECT) causes ssl encryption to fail.  Connecting asynchronously with tcp:// works, as does connecting synchronously with ssl://.

If I remove the ASYNC flag from the example code, I get normal HTTP headers and HTML content.  If I leave the flag but change the scheme to tcp:// and port to 80, launchpad.net gives me a normal HTTP/HTML redirect to the encrypted url (https://...).  But as written, I instead get an error from the server indicating that my request could not be decrypted via SSL, and no HTTP headers whatsoever.

I'm not sure if this bug is more properly "OpenSSL related" or "Sockets related", so I've guessed the former.  But I wonder if maybe stream_select() considers the socket writable once it's opened, but before the SSL handshake is complete; that might cause this code to fwrite() too early, possibly going out plaintext.  Then I suppose the solution is for stream_select() to not return ssl:// sockets until the handshake is complete, in addition to simply being opened.

Reproduce code:
---------------
<?php
header('Content-type: text/plain');
$scheme = 'ssl://';
$host = 'launchpad.net';
$port = 443;
$path = '/';
$begin = microtime(true);
$flags = STREAM_CLIENT_CONNECT | STREAM_CLIENT_ASYNC_CONNECT;
echo "resolving ".$host."...\n";
$ip = gethostbyname($host);
echo "connecting to ".$ip."...\n";
$errno = null;
$errstr = null;
$socket = stream_socket_client($scheme.$ip.':'.$port, $errno, $errstr, 10, $flags);
stream_set_blocking($socket, 0);
echo "sending HTTP GET ".$path."...\n";
$data = "GET ".$path." HTTP/1.0\r\n" .
		"Host: ".$host."\r\n" .
		"Connection: close\r\n" .
		"\r\n";
$selR = null;
$selW = array($socket);
$selE = null;
while ($data) {
	$selW[0] = $socket;
	if (stream_select($selR, $selW, $selE, 0, 50000)) {
		$wrote = fwrite($socket, $data, strlen($data));
		$data = substr($data, $wrote);
	}
}
echo "waiting for data...\n";
$html = "";
$selR = array($socket);
$selW = null;
$selE = null;
$timeout = microtime(true) + 30;
while (!feof($socket)) {
	$selR[0] = $socket;
	if (stream_select($selR, $selW, $selE, 0, 50000))
		$html .= fread($socket, 8192);
}
fclose($socket);
echo "got ".strlen($html)." bytes in ".(microtime(true)-$begin)." seconds\n";
echo "----------\n".$html;


Expected result:
----------------
The HTTP headers and HTML source for launchpad.net's main page, i.e.:

HTTP/1.1 200 OK
...
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      lang="en" dir="ltr">
  <head>
    <title>Launchpad</title>
...

etc

Actual result:
--------------
An HTML source error message:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>400 Bad Request</title>
</head><body>
<h1>Bad Request</h1>
<p>Your browser sent a request that this server could not understand.<br />
Reason: You're speaking plain HTTP to an SSL-enabled server port.<br />
Instead use the HTTPS scheme to access this URL, please.<br />
<blockquote>Hint: <a href="https://launchpad.net/"><b>https://launchpad.net/</b></a></blockquote></p>
<hr>
<address>Apache/2.2.8 (Ubuntu) mod_ssl/2.2.8 OpenSSL/0.9.8g Server at launchpad.net Port 443</address>
</body></html>


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-06-08 14:14 UTC] frase at cs dot wisc dot edu
Hate to bump my own bug, but it's been a month.

Nobody's concerned that ssl:// streams + ASYNC_CONNECT has this silent failure?  And that there's a chance it's causing data intended for ssl:// to instead be transmitted in plaintext?
 [2009-06-19 13:38 UTC] frase at cs dot wisc dot edu
This bug is still present in 5.3.0 as of RC4, and also affects Linux hosts.
 [2009-06-30 14:28 UTC] frase at cs dot wisc dot edu
This bug remains in 5.3.0 final.
 [2009-07-01 16:28 UTC] frase at cs dot wisc dot edu
This bug remains also in 5.2.10.

Let's try a new summary and changing the category to "Sockets", maybe it will get someone's attention.
 [2009-07-09 21:47 UTC] sriram dot natarajan at gmail dot com
thanks for your patience.

here is a patch that should address your issue. to apply this patch, save the above text into a file and run

--- ext/openssl/xp_ssl.c.ORIG   Thu Jul  9 12:20:44 2009
+++ ext/openssl/xp_ssl.c        Thu Jul  9 12:29:18 2009
@@ -672,7 +672,11 @@
                                         * we notice that the connect has actually been established */
                                        php_stream_socket_ops.set_option(stream, option, value, ptrparam TSRMLS_CC);
 
-                                       if (xparam->outputs.returncode == 0 && sslsock->enable_on_connect) {
+                                       if ((sslsock->enable_on_connect) &&
+                                               ((xparam->outputs.returncode == 0) ||
+                                                (xparam->op == STREAM_XPORT_OP_CONNECT_ASYNC && xparam->outputs.returncode == 1 && 
+                                                xparam->outputs.error_code == EINPROGRESS)))
+                                       {
                                                if (php_stream_xport_crypto_setup(stream, sslsock->method, NULL TSRMLS_CC) < 0 ||
                                                                php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) {
                                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to enable crypto");


- download and unzip the latest php 5.3snapshot from http://snaps.php.net
- cd <php-workspace> ; patch -p0 -d . < <filename>

now, you can run make and should be able to test it.

i will wait for some one to review this patch . hopefully, should happen before next release :-)
 [2009-07-09 21:53 UTC] sriram dot natarajan at gmail dot com
better still, here is the patch (more readable format)
http://pastebin.org/805
 [2009-07-10 13:38 UTC] frase at cs dot wisc dot edu
The supplied patch does fix the problem in 5.3.0 on Linux; I have no Windows build environment so I can't test it there but can't see why it wouldn't also work.  Since the patch was to OpenSSL I've changed the category back.

Many thanks!
 [2009-07-28 19:34 UTC] srinatar@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

Committed revision 286465.
 [2009-08-14 13:49 UTC] frase at cs dot wisc dot edu
I'm re-opening this bug as the fix appears not to work in 5.2.11RC1.  With the same testing code as in the original report, when connecting synchronously, all is well.  But when connecting asynchronously I get these warnings:


Warning: stream_socket_client() [function.stream-socket-client]: SSL: The operation completed successfully. in test-async-ssl.php on line 14

Warning: stream_socket_client() [function.stream-socket-client]: Failed to enable crypto in test-async-ssl.php on line 14

Warning: stream_socket_client() [function.stream-socket-client]: unable to connect to ssl://91.189.90.211:443 (Unknown error) in test-async-ssl.php on line 14


Line 14 is of course the stream_socket_client() call.  Additionally, after these warnings, $errno contains 10035 and $errstr is empty.
 [2009-08-14 13:56 UTC] frase at cs dot wisc dot edu
To clarify, I tested the posted patch by recompiling 5.3.0 on Ubuntu Linux, and the fix worked.  I was not able to test the patch in 5.2.10 on Windows as I have no suitable build environment.  The posted 5.2.11RC1 binaries (under Apache 2.2.11) now exhibit this new problem.
 [2009-08-18 02:11 UTC] srinatar@php.net
thanks for verifying it. let me try this again with php 5.2.11rc1 and see why it is happening (again). 
 [2009-08-18 13:40 UTC] frase at cs dot wisc dot edu
The new problem could be unrelated, it is definitely different behavior than before.  I've reported it here only because it still only affects ssl:// socket connections opened asynchronously -- 
tcp sockets open fine (both sync and async), and ssl sockets open fine synchronously.

Also, I have a new clue.  The very first attempt (ssl+async) on a freshly booted Apache server works fine.  It is only on the second and subsequent attempts that the new warnings appear and the socket won't open.  When I restart Apache, it works one more time.

This is Windows 2000 Professional SP4, Apache 2.2.11, with the posted PHP 5.2.11RC1-Win32-VC6 binary (threadsafe, and apparently including OpenSSL 0.9.8k) configured as an Apache module (not CGI).

Hope that helps.
 [2009-08-19 03:35 UTC] srinatar@php.net
i was able to verify this successfully by compiling php 5.2.11 rc1 (did not use the rc1 candidate build) on windows and run the below script that you attached as part of this bug report. 

now, if you have a different test script that is causing this issue then i would suggest that you should better file a separate bug and attach this new test case. this way , we can track different issues separately rather than overloading this bug.

 [2009-08-19 13:54 UTC] frase at cs dot wisc dot edu
It is exactly the same script that produces this new error for me on Windows.  However as you request, I have opened a new bug#49295 for this behavior.
 [2009-08-21 00:46 UTC] srinatar@php.net
This bug has been fixed in SVN.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.

the original reported issue is now resolved in all platforms. however, the bug submitter is noticing the same script behaving differently on windows. and has filed a separate bug to track this (#49295). hence, closing this as fixed in svn . 


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 21:01:30 2024 UTC