-
-
Notifications
You must be signed in to change notification settings - Fork 157
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Opportunistic TLS implementation
- Loading branch information
1 parent
936546b
commit c45aa34
Showing
10 changed files
with
431 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?php | ||
|
||
// Opportunistic TLS example showing a basic negotiation before enabling the encryption. It starts out as an | ||
// unencrypted TCP connection. After both parties agreed to encrypt the connection they both enable the encryption. | ||
// After which any communication over the line is encrypted. | ||
// | ||
// This example is design to show both sides in one go, as such the server stops listening for new connection after | ||
// the first, this makes sure the loop shuts down after the example connection has closed. | ||
// | ||
// $ php examples/31-opportunistic-tls.php | ||
|
||
use React\EventLoop\Loop; | ||
use React\Socket\ConnectionInterface; | ||
use React\Socket\Connector; | ||
use React\Socket\OpportunisticTlsConnectionInterface; | ||
use React\Socket\SocketServer; | ||
|
||
require __DIR__ . '/../vendor/autoload.php'; | ||
|
||
$server = new SocketServer('opportunistic+tls://127.0.0.1:0', array( | ||
'tls' => array( | ||
'local_cert' => __DIR__ . '/localhost.pem', | ||
) | ||
)); | ||
$server->on('connection', static function (OpportunisticTlsConnectionInterface $connection) use ($server) { | ||
$server->close(); | ||
|
||
$connection->on('data', function ($data) { | ||
echo 'From Client: ', $data, PHP_EOL; | ||
}); | ||
React\Promise\Stream\first($connection)->then(function ($data) use ($connection) { | ||
if ($data === 'Let\'s encrypt?') { | ||
$connection->write('yes'); | ||
return $connection->enableEncryption(); | ||
} | ||
|
||
return $connection; | ||
})->then(static function (ConnectionInterface $connection) { | ||
$connection->write('Encryption enabled!'); | ||
})->done(); | ||
}); | ||
|
||
$client = new Connector(array( | ||
'tls' => array( | ||
'verify_peer' => false, | ||
'verify_peer_name' => false, | ||
'allow_self_signed' => true, | ||
), | ||
)); | ||
$client->connect($server->getAddress())->then(static function (OpportunisticTlsConnectionInterface $connection) { | ||
$connection->on('data', function ($data) { | ||
echo 'From Server: ', $data, PHP_EOL; | ||
}); | ||
$connection->write('Let\'s encrypt?'); | ||
|
||
return React\Promise\Stream\first($connection)->then(function ($data) use ($connection) { | ||
if ($data === 'yes') { | ||
return $connection->enableEncryption(); | ||
} | ||
|
||
return $connection; | ||
}); | ||
})->then(function (ConnectionInterface $connection) { | ||
$connection->write('Encryption enabled!'); | ||
Loop::addTimer(1, static function () use ($connection) { | ||
$connection->end('Cool! Bye!'); | ||
}); | ||
})->done(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
<?php | ||
|
||
namespace React\Socket; | ||
|
||
use Evenement\EventEmitter; | ||
use React\EventLoop\LoopInterface; | ||
use React\Promise\PromiseInterface; | ||
use React\Stream\DuplexResourceStream; | ||
use React\Stream\Util; | ||
use React\Stream\WritableResourceStream; | ||
use React\Stream\WritableStreamInterface; | ||
|
||
/** | ||
* The actual connection implementation for StartTlsConnectionInterface | ||
* | ||
* This class should only be used internally, see StartTlsConnectionInterface instead. | ||
* | ||
* @see OpportunisticTlsConnectionInterface | ||
* @internal | ||
*/ | ||
class OpportunisticTlsConnection extends EventEmitter implements OpportunisticTlsConnectionInterface | ||
{ | ||
/** @var Connection */ | ||
private $connection; | ||
|
||
/** @var StreamEncryption */ | ||
private $streamEncryption; | ||
|
||
/** @var string */ | ||
private $uri; | ||
|
||
public function __construct(Connection $connection, StreamEncryption $streamEncryption, $uri) | ||
{ | ||
$this->connection = $connection; | ||
$this->streamEncryption = $streamEncryption; | ||
$this->uri = $uri; | ||
|
||
Util::forwardEvents($connection, $this, array('data', 'end', 'error', 'close')); | ||
} | ||
|
||
public function getRemoteAddress() | ||
{ | ||
return $this->connection->getRemoteAddress(); | ||
} | ||
|
||
public function getLocalAddress() | ||
{ | ||
return $this->connection->getLocalAddress(); | ||
} | ||
|
||
public function isReadable() | ||
{ | ||
return $this->connection->isReadable(); | ||
} | ||
|
||
public function pause() | ||
{ | ||
$this->connection->pause(); | ||
} | ||
|
||
public function resume() | ||
{ | ||
$this->connection->resume(); | ||
} | ||
|
||
public function pipe(WritableStreamInterface $dest, array $options = array()) | ||
{ | ||
return $this->connection->pipe($dest, $options); | ||
} | ||
|
||
public function close() | ||
{ | ||
$this->connection->close(); | ||
} | ||
|
||
public function enableEncryption() | ||
{ | ||
$that = $this; | ||
$connection = $this->connection; | ||
$uri = $this->uri; | ||
|
||
return $this->streamEncryption->enable($connection)->then(function () use ($that) { | ||
return $that; | ||
}, function ($error) use ($connection, $uri) { | ||
// establishing encryption failed => close invalid connection and return error | ||
$connection->close(); | ||
|
||
throw new \RuntimeException( | ||
'Connection to ' . $uri . ' failed during TLS handshake: ' . $error->getMessage(), | ||
$error->getCode() | ||
); | ||
}); | ||
} | ||
|
||
public function isWritable() | ||
{ | ||
return $this->connection->isWritable(); | ||
} | ||
|
||
public function write($data) | ||
{ | ||
return $this->connection->write($data); | ||
} | ||
|
||
public function end($data = null) | ||
{ | ||
$this->connection->end($data); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<?php | ||
|
||
namespace React\Socket; | ||
|
||
use React\Promise\PromiseInterface; | ||
|
||
/** | ||
* @see DuplexStreamInterface | ||
* @see ServerInterface | ||
* @see ConnectionInterface | ||
*/ | ||
interface OpportunisticTlsConnectionInterface extends ConnectionInterface | ||
{ | ||
/** | ||
* @return PromiseInterface<OpportunisticTlsConnectionInterface> | ||
*/ | ||
public function enableEncryption(); | ||
} |
Oops, something went wrong.