@@ -23,6 +23,8 @@ handle multiple concurrent connections without blocking.
23
23
* [ ConnectionInterface] ( #connectioninterface )
24
24
* [ getRemoteAddress()] ( #getremoteaddress )
25
25
* [ getLocalAddress()] ( #getlocaladdress )
26
+ * [ OpportunisticTlsConnectionInterface] ( #opportunistictlsconnectioninterface )
27
+ * [ enableEncryption()] ( #enableencryption )
26
28
* [ Server usage] ( #server-usage )
27
29
* [ ServerInterface] ( #serverinterface )
28
30
* [ connection event] ( #connection-event )
@@ -193,6 +195,62 @@ If your system has multiple interfaces (e.g. a WAN and a LAN interface),
193
195
you can use this method to find out which interface was actually
194
196
used for this connection.
195
197
198
+ ### OpportunisticTlsConnectionInterface
199
+
200
+ The ` OpportunisticTlsConnectionInterface ` extends the [ ` ConnectionInterface ` ] ( #connectioninterface ) and adds the ability of
201
+ enabling the TLS encryption on the connection when desired.
202
+
203
+ #### enableEncryption
204
+
205
+ When negotiated with the server when to start encrypting traffic using TLS you enable it by calling
206
+ ` enableEncryption() ` which returns a promise that resolve with a ` OpportunisticTlsConnectionInterface ` connection but now all
207
+ traffic back and forth will be encrypted.
208
+
209
+ In the following example we ask the server if they want to encrypt the connection, and when it responds with ` yes ` we
210
+ enable the encryption:
211
+
212
+ ``` php
213
+ $connector = new React\Socket\Connector();
214
+ $connector->connect('opportunistic+tls://example.com:5432/')->then(function (React\Socket\OpportunisticTlsConnectionInterface $startTlsConnection) {
215
+ $connection->write('let\'s encrypt?');
216
+
217
+ return React\Promise\Stream\first($connection)->then(function ($data) use ($connection) {
218
+ if ($data === 'yes') {
219
+ return $connection->enableEncryption();
220
+ }
221
+
222
+ return $stream;
223
+ });
224
+ })->then(function (React\Socket\ConnectionInterface $connection) {
225
+ $connection->write('Hello!');
226
+ });
227
+ ```
228
+
229
+ The ` enableEncryption ` function resolves with itself. As such you can't see the data encrypted when you hook into the
230
+ events before enabling, as shown below:
231
+
232
+ ``` php
233
+ $connector = new React\Socket\Connector();
234
+ $connector->connect('opportunistic+tls://example.com:5432/')->then(function (React\Socket\OpportunisticTlsConnectionInterface $startTlsConnection) {
235
+ $connection->on('data', function ($data) {
236
+ echo 'Raw: ', $data, PHP_EOL;
237
+ });
238
+
239
+ return $connection->enableEncryption();
240
+ })->then(function (React\Socket\ConnectionInterface $connection) {
241
+ $connection->on('data', function ($data) {
242
+ echo 'TLS: ', $data, PHP_EOL;
243
+ });
244
+ });
245
+ ```
246
+
247
+ When the other side send ` Hello World! ` over the encrypted connection, the output will be the following:
248
+
249
+ ```
250
+ Raw: Hello World!
251
+ TLS: Hello World!
252
+ ```
253
+
196
254
## Server usage
197
255
198
256
### ServerInterface
@@ -253,10 +311,10 @@ If the address can not be determined or is unknown at this time (such as
253
311
after the socket has been closed), it MAY return a ` NULL ` value instead.
254
312
255
313
Otherwise, it will return the full address (URI) as a string value, such
256
- as ` tcp://127.0.0.1:8080 ` , ` tcp://[::1]:80 ` , ` tls://127.0.0.1:443 `
257
- ` unix://example.sock ` or ` unix:///path/to/example.sock ` .
258
- Note that individual URI components are application specific and depend
259
- on the underlying transport protocol.
314
+ as ` tcp://127.0.0.1:8080 ` , ` tcp://[::1]:80 ` , ` tls://127.0.0.1:443 ` ,
315
+ ` unix://example.sock ` , ` unix:///path/to/example.sock ` , or
316
+ ` opportunistic+tls://127.0.0.1:443 ` . Note that individual URI components
317
+ are application specific and depend on the underlying transport protocol.
260
318
261
319
If this is a TCP/IP based server and you only want the local port, you may
262
320
use something like this:
@@ -478,6 +536,22 @@ $socket = new React\Socket\SocketServer('tls://127.0.0.1:8000', array(
478
536
));
479
537
```
480
538
539
+ To start a server with opportunistic TLS support use ` opportunistic+tls:// ` as the scheme instead of ` tls:// ` :
540
+
541
+ ``` php
542
+ $socket = new React\Socket\SocketServer('opportunistic+tls://127.0.0.1:8000', array(
543
+ 'tls' => array(
544
+ 'local_cert' => 'server.pem',
545
+ 'crypto_method' => STREAM_CRYPTO_METHOD_TLSv1_2_SERVER
546
+ )
547
+ ));
548
+ $server->on('connection', static function (OpportunisticTlsConnectionInterface $connection) use ($server) {
549
+ return $connection->enableEncryption();
550
+ });
551
+ ```
552
+
553
+ See also the [ examples] ( examples ) .
554
+
481
555
> Note that available [ TLS context options] ( https://www.php.net/manual/en/context.ssl.php ) ,
482
556
their defaults and effects of changing these may vary depending on your system
483
557
and/or PHP version.
@@ -697,6 +771,21 @@ here in order to use the [default loop](https://github.com/reactphp/event-loop#l
697
771
This value SHOULD NOT be given unless you're sure you want to explicitly use a
698
772
given event loop instance.
699
773
774
+ Opportunistic TLS is supported by the secure server by passing true in as 4th constructor
775
+ parameter. This, when a client connects, emits a
776
+ [ ` OpportunisticTlsConnectionInterface ` ] ( #opportunistictlsconnectioninterface ) instead
777
+ of the default [ ` ConnectionInterface ` ] ( #connectioninterface ) and won't be TLS encrypted
778
+ from the start so you can enable the TLS encryption on the connection after negotiating
779
+ with the client.
780
+
781
+ ``` php
782
+ $server = new React\Socket\TcpServer(8000);
783
+ $server = new React\Socket\SecureServer($server, null, array(
784
+ 'local_cert' => 'server.pem',
785
+ 'passphrase' => 'secret'
786
+ ), true);
787
+ ```
788
+
700
789
> Advanced usage: Despite allowing any ` ServerInterface ` as first parameter,
701
790
you SHOULD pass a ` TcpServer ` instance as first parameter, unless you
702
791
know what you're doing.
@@ -1389,6 +1478,20 @@ $secureConnector = new React\Socket\SecureConnector($dnsConnector, null, array(
1389
1478
));
1390
1479
```
1391
1480
1481
+ Opportunistic TLS is supported by the secure connector by using ` opportunistic-tls:// ` as scheme instead of ` tls:// ` . This, when
1482
+ connected, returns a [ ` OpportunisticTlsConnectionInterface ` ] ( #opportunistictlsconnectioninterface ) instead of the default
1483
+ [ ` ConnectionInterface ` ] ( #connectioninterface ) and won't be TLS encrypted from the start so you can enable the TLS
1484
+ encryption on the connection after negotiating with the server.
1485
+
1486
+ ``` php
1487
+ $secureConnector = new React\Socket\SecureConnector($dnsConnector);
1488
+ $secureConnector->connect('opportunistic-tls://example.com:5432')->then(function (OpportunisticTlsConnectionInterface $connection) {
1489
+ return $connection->enableEncryption();
1490
+ })->then(function (OpportunisticTlsConnectionInterface $connection) {
1491
+ $connection->write('Encrypted hi!');
1492
+ });
1493
+ ```
1494
+
1392
1495
> Advanced usage: Internally, the ` SecureConnector ` relies on setting up the
1393
1496
required * context options* on the underlying stream resource.
1394
1497
It should therefor be used with a ` TcpConnector ` somewhere in the connector
0 commit comments