Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
--TEST--
stream_socket_get_crypto_status(): reports status NONE after supplemental read
--EXTENSIONS--
openssl
--SKIPIF--
<?php
if (!function_exists("proc_open")) die("skip no proc_open");
?>
--FILE--
<?php
$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'crypto_status_supplemental_read.pem.tmp';
$peerName = 'crypto-status-supplemental-read';

$serverCode = <<<'CODE'
$ctx = stream_context_create(['ssl' => ['local_cert' => '%s']]);
$flags = STREAM_SERVER_BIND|STREAM_SERVER_LISTEN;
$server = stream_socket_server("tls://127.0.0.1:0", $errno, $errstr, $flags, $ctx);
phpt_notify_server_start($server);

$conn = stream_socket_accept($server, 30);

fwrite($conn, "hello\n");

phpt_wait();
fclose($conn);
CODE;
$serverCode = sprintf($serverCode, $certFile);

$clientCode = <<<'CODE'
$ctx = stream_context_create(['ssl' => [
'verify_peer' => false,
'verify_peer_name' => false,
'peer_name' => '%s',
]]);

$client = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $ctx);
stream_set_blocking($client, false);

$buf = '';
$read = [$client];
$write = $except = null;
while (stream_select($read, $write, $except, 5)) {
// Initially, read only the first char, then request more than is stored
// in the buffer, triggering a supplemental read.
$chunk = fread($client, strlen($buf) === 0 ? 1 : 10);
if ($chunk === '' || $chunk === false) {
/* A non-application record (e.g. a TLS 1.3 session ticket) may arrive first. */
if (feof($client)) {
break;
}
} else {
$buf .= $chunk;
if (strlen($buf) >= 6) {
break;
}
}
$read = [$client];
$write = $except = null;
}

echo trim($buf), "\n";
/* A successful read clears the pending status back to NONE. */
var_dump(stream_socket_get_crypto_status($client) === STREAM_CRYPTO_STATUS_NONE);

phpt_notify();
fclose($client);
CODE;
$clientCode = sprintf($clientCode, $peerName);

include 'CertificateGenerator.inc';
$certificateGenerator = new CertificateGenerator();
$certificateGenerator->saveNewCertAsFileWithKey($peerName, $certFile);

include 'ServerClientTestCase.inc';
ServerClientTestCase::getInstance()->run($clientCode, $serverCode);
?>
--CLEAN--
<?php
@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'crypto_status_supplemental_read.pem.tmp');
?>
--EXPECT--
hello
bool(true)
10 changes: 10 additions & 0 deletions ext/openssl/xp_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2997,6 +2997,16 @@ static ssize_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, si
php_stream_notify_progress_increment(PHP_STREAM_CONTEXT(stream), nr_bytes, 0);
}

/* This might be a supplemental read after consuming buffered data. If
* the read returned nothing, ignore status WANT_READ. */
if (read &&
nr_bytes <= 0 &&
sslsock->last_status == STREAM_CRYPTO_STATUS_WANT_READ &&
stream->has_buffered_data
) {
sslsock->last_status = STREAM_CRYPTO_STATUS_NONE;
}

/* And if we were originally supposed to be blocking, let's reset the socket to that. */
if (began_blocked) {
php_openssl_set_blocking(sslsock, 1);
Expand Down
Loading