Skip to content

Server with Transport Layer Security. #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Server with Transport Layer Security.
Change Connection::handleData to use `fread` once again so that, when it
is appropriate,  the data is filtered by an ssl/tls stream wrapper.

Add a third argument to Server::listen which should be an array which
can be passed directly to stream_context_create.  If the context has an
'ssl' key then it will stream_socket_enable_crypto for connected
sockets.
  • Loading branch information
boite committed Apr 5, 2016
commit 615500dc87e5b5336622ec2a547216bc15ebb411
4 changes: 1 addition & 3 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ class Connection extends Stream implements ConnectionInterface
{
public function handleData($stream)
{
// Socket is raw, not using fread as it's interceptable by filters
// See issues #192, #209, and #240
$data = stream_socket_recvfrom($stream, $this->bufferSize);
$data = fread($stream, $this->bufferSize);
if ('' !== $data && false !== $data) {
$this->emit('data', array($data, $this));
}
Expand Down
51 changes: 48 additions & 3 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,35 @@ class Server extends EventEmitter implements ServerInterface
{
public $master;
private $loop;
private $isSecure = false;

public function __construct(LoopInterface $loop)
{
$this->loop = $loop;
}

public function listen($port, $host = '127.0.0.1')
public function listen($port, $host = '127.0.0.1', $streamContext = array())
{
if (strpos($host, ':') !== false) {
// enclose IPv6 addresses in square brackets before appending port
$host = '[' . $host . ']';
}
if (isset($streamContext['ssl'])) {
$this->isSecure = true;
}

$this->master = @stream_socket_server("tcp://$host:$port", $errno, $errstr);
$this->master = @stream_socket_server(
"tcp://$host:$port",
$errno,
$errstr,
STREAM_SERVER_BIND | STREAM_SERVER_LISTEN,
stream_context_create($streamContext)
);
if (false === $this->master) {
$message = "Could not bind to tcp://$host:$port: $errstr";
throw new ConnectionException($message, $errno);
}
stream_set_blocking($this->master, 0);
stream_set_blocking($this->master, (int) $this->isSecure);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would love to know if anybody has managed to solve the requirement for this master socket to block for secure connections.

Copy link

@CriseX CriseX Apr 19, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a way to do it... I don't have react specific code samples for it, however, the gist of it is to try until stream_socket_enable_crypto returns success.

        $result = stream_socket_enable_crypto($this->stream, true, $crypto_method);
        if ($result === 0)
            return true;

        if ($result === false)
            return false;

        $this->secure = self::STATE_ENCRYPTED;
        return true;

Assume the above to be part of a member function which you keep polling until the value of secure == STATE_ENCRYPTED. You don't need to do blocking at all in this way, see documentation of stream_socket_enable_crypto. Depending on the stream_select timeout values typically doing it this way results in 1-3 cycles of polling to enable cryptography (tested on loopback interface).

Edit: you might want to look at an old closed pull request from way back when... before the repositories were shuffled around. They got the gist of this approach right.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @CriseX, your comment was very helpful. I've added the suggested improvements to this PR.


$that = $this;

Expand All @@ -45,6 +55,10 @@ public function listen($port, $host = '127.0.0.1')

public function handleConnection($socket)
{
if ($this->isSecure) {
$this->enableConnectionSecurity($socket);
}

stream_set_blocking($socket, 0);

$client = $this->createConnection($socket);
Expand All @@ -70,4 +84,35 @@ public function createConnection($socket)
{
return new Connection($socket, $this->loop);
}

/**
* Turn on encryption for the supplied socket. If the socket does not have
* a stream context with a value for ['ssl']['crypto_method'] then a default
* crypto method is used. For PHP before 5.6 this means only SSLv2, SSLv3
* and TLSv1.0 are enabled and only if PHP was built with an OpenSSL that
* supports those protocols. You might find that only TLSv1.0 is made
* available, for example with an Ubuntu packaged PHP 5.5.9. For PHP 5.6
* and above, any protocol made available to PHP by OpenSSL will be enabled.
*
* @param resource $socket
*/
private function enableConnectionSecurity($socket)
{
$context = stream_context_get_options($socket);

if (! isset($context['ssl']['crypto_method'])) {

$defaultCrypto = defined('STREAM_CRYPTO_METHOD_ANY_SERVER')
? STREAM_CRYPTO_METHOD_ANY_SERVER
: STREAM_CRYPTO_METHOD_SSLv23_SERVER|STREAM_CRYPTO_METHOD_TLS_SERVER
;
stream_socket_enable_crypto($socket, true, $defaultCrypto);

} else if (PHP_VERSION_ID < 50600) {
# "When enabling encryption you must specify the crypto type"
stream_socket_enable_crypto($socket, true, $context['ssl']['crypto_method']);
} else {
stream_socket_enable_crypto($socket, true);
}
}
}
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy