Skip to content

Support explicitly choosing TLS version to negotiate with remote side #149

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

Merged
merged 1 commit into from
Jan 17, 2018
Merged
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
49 changes: 48 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,19 @@ $server = new Server('tls://127.0.0.1:8000', $loop, array(
));
```

By default, this server supports TLSv1.0+ and excludes support for legacy
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
want to negotiate with the remote side:

```php
$server = new Server('tls://127.0.0.1:8000', $loop, array(
'tls' => array(
'local_cert' => 'server.pem',
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
)
));
```

> Note that available [TLS context options](http://php.net/manual/en/context.ssl.php),
their defaults and effects of changing these may vary depending on your system
and/or PHP version.
Expand Down Expand Up @@ -612,6 +625,18 @@ $server = new SecureServer($server, $loop, array(
));
```

By default, this server supports TLSv1.0+ and excludes support for legacy
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
want to negotiate with the remote side:

```php
$server = new TcpServer(8000, $loop);
$server = new SecureServer($server, $loop, array(
'local_cert' => 'server.pem',
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
));
```

> Note that available [TLS context options](http://php.net/manual/en/context.ssl.php),
their defaults and effects of changing these may vary depending on your system
and/or PHP version.
Expand Down Expand Up @@ -1000,6 +1025,18 @@ $connector->connect('tls://localhost:443')->then(function (ConnectionInterface $
});
```

By default, this connector supports TLSv1.0+ and excludes support for legacy
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
want to negotiate with the remote side:

```php
$connector = new Connector($loop, array(
'tls' => array(
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
)
));
```

> For more details about context options, please refer to the PHP documentation
about [socket context options](http://php.net/manual/en/context.socket.php)
and [SSL context options](http://php.net/manual/en/context.ssl.php).
Expand Down Expand Up @@ -1189,7 +1226,7 @@ $promise->cancel();
```

Calling `cancel()` on a pending promise will cancel the underlying TCP/IP
connection and/or the SSL/TLS negonation and reject the resulting promise.
connection and/or the SSL/TLS negotiation and reject the resulting promise.

You can optionally pass additional
[SSL context options](http://php.net/manual/en/context.ssl.php)
Expand All @@ -1202,6 +1239,16 @@ $secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
));
```

By default, this connector supports TLSv1.0+ and excludes support for legacy
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
want to negotiate with the remote side:

```php
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT
));
```

> Advanced usage: Internally, the `SecureConnector` relies on setting up the
required *context options* on the underlying stream resource.
It should therefor be used with a `TcpConnector` somewhere in the connector
Expand Down
22 changes: 18 additions & 4 deletions src/StreamEncryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ public function __construct(LoopInterface $loop, $server = true)
$this->loop = $loop;
$this->server = $server;

// support TLSv1.0+ by default and exclude legacy SSLv2/SSLv3.
// PHP 5.6+ supports bitmasks, legacy PHP only supports predefined
// constants, so apply accordingly below.
// Also, since PHP 5.6.7 up until before PHP 7.2.0 the main constant did
// only support TLSv1.0, so we explicitly apply all versions.
// @link http://php.net/manual/en/migration56.openssl.php#migration56.openssl.crypto-method
// @link https://3v4l.org/plbFn
if ($server) {
$this->method = STREAM_CRYPTO_METHOD_TLS_SERVER;

Expand Down Expand Up @@ -78,9 +85,16 @@ public function toggle(Connection $stream, $toggle)
// get actual stream socket from stream instance
$socket = $stream->stream;

// get crypto method from context options or use global setting from constructor
$method = $this->method;
$context = stream_context_get_options($socket);
if (isset($context['ssl']['crypto_method'])) {
$method = $context['ssl']['crypto_method'];
}

$that = $this;
$toggleCrypto = function () use ($socket, $deferred, $toggle, $that) {
$that->toggleCrypto($socket, $deferred, $toggle);
$toggleCrypto = function () use ($socket, $deferred, $toggle, $method, $that) {
$that->toggleCrypto($socket, $deferred, $toggle, $method);
};

$this->loop->addReadStream($socket, $toggleCrypto);
Expand All @@ -105,10 +119,10 @@ public function toggle(Connection $stream, $toggle)
});
}

public function toggleCrypto($socket, Deferred $deferred, $toggle)
public function toggleCrypto($socket, Deferred $deferred, $toggle, $method)
{
set_error_handler(array($this, 'handleError'));
$result = stream_socket_enable_crypto($socket, $toggle, $this->method);
$result = stream_socket_enable_crypto($socket, $toggle, $method);
restore_error_handler();

if (true === $result) {
Expand Down
48 changes: 48 additions & 0 deletions tests/FunctionalSecureServerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,54 @@ public function testPipesDataBackInMultipleChunksFromConnection()
$this->assertEquals(400000, $received);
}

/**
* @requires PHP 5.6
*/
public function testEmitsConnectionForNewTlsv11Connection()
{
$loop = Factory::create();

$server = new TcpServer(0, $loop);
$server = new SecureServer($server, $loop, array(
'local_cert' => __DIR__ . '/../examples/localhost.pem',
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_SERVER
));
$server->on('connection', $this->expectCallableOnce());

$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
'verify_peer' => false,
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT
));
$promise = $connector->connect($server->getAddress());

Block\await($promise, $loop, self::TIMEOUT);
}

/**
* @requires PHP 5.6
*/
public function testEmitsErrorForClientWithTlsVersionMismatch()
{
$loop = Factory::create();

$server = new TcpServer(0, $loop);
$server = new SecureServer($server, $loop, array(
'local_cert' => __DIR__ . '/../examples/localhost.pem',
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_1_SERVER|STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
));
$server->on('connection', $this->expectCallableNever());
$server->on('error', $this->expectCallableOnce());

$connector = new SecureConnector(new TcpConnector($loop), $loop, array(
'verify_peer' => false,
'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT
));
$promise = $connector->connect($server->getAddress());

$this->setExpectedException('RuntimeException', 'handshake');
Block\await($promise, $loop, self::TIMEOUT);
}

public function testEmitsConnectionForNewConnectionWithEncryptedCertificate()
{
$loop = Factory::create();
Expand Down
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