From: frase at cs dot wisc dot edu Operating system: Windows 2000 Pro SP4 PHP version: 5.2.9 PHP Bug Type: OpenSSL related Bug description: stream_socket_client(ssl:// ... STREAM_CLIENT_ASYNC_CONNECT) fails
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> -- Edit bug report at http://bugs.php.net/?id=48182&edit=1 -- Try a CVS snapshot (PHP 5.2): http://bugs.php.net/fix.php?id=48182&r=trysnapshot52 Try a CVS snapshot (PHP 5.3): http://bugs.php.net/fix.php?id=48182&r=trysnapshot53 Try a CVS snapshot (PHP 6.0): http://bugs.php.net/fix.php?id=48182&r=trysnapshot60 Fixed in CVS: http://bugs.php.net/fix.php?id=48182&r=fixedcvs Fixed in CVS and need be documented: http://bugs.php.net/fix.php?id=48182&r=needdocs Fixed in release: http://bugs.php.net/fix.php?id=48182&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=48182&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=48182&r=needscript Try newer version: http://bugs.php.net/fix.php?id=48182&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=48182&r=support Expected behavior: http://bugs.php.net/fix.php?id=48182&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=48182&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=48182&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=48182&r=globals PHP 4 support discontinued: http://bugs.php.net/fix.php?id=48182&r=php4 Daylight Savings: http://bugs.php.net/fix.php?id=48182&r=dst IIS Stability: http://bugs.php.net/fix.php?id=48182&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=48182&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=48182&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=48182&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=48182&r=mysqlcfg