Skip to content

Commit

Permalink
SecureConnector: add optional TlsPeer, this...
Browse files Browse the repository at this point in the history
...allows to capture your peer certificate and/or it's chain
  • Loading branch information
Thomas-Gelf committed Sep 25, 2020
1 parent 28fac70 commit 313ca21
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 1 deletion.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,33 @@ $secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
));
```

In case you want to retrieve your peers certificate or certificate chain,
you can use the related context options:

```php
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
'capture_peer_cert' => true,
'capture_peer_cert_chain' => true,
));
```

To show the peer certificate for every new connection this can be done as
follows:

```php
$secureConnector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
assert($connection instanceof React\Socket\Connection);
if ($connection->hasTlsPeer()) {
$peer = $connection->getTlsPeer();
if ($peer && $peer->hasPeerCertificate()) {
$peerCert = $peer->getPeerCertificate();
openssl_x509_export($peerCert, $cert);
echo $cert;
}
}
});
```

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:
Expand Down
28 changes: 28 additions & 0 deletions src/Connection.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ class Connection extends EventEmitter implements ConnectionInterface

private $input;

/** @var TlsPeer|null */
private $tlsPeer;

public function __construct($resource, LoopInterface $loop)
{
// PHP < 7.3.3 (and PHP < 7.2.15) suffers from a bug where feof() might
Expand Down Expand Up @@ -154,6 +157,31 @@ public function getLocalAddress()
return $this->parseAddress(\stream_socket_get_name($this->stream, false));
}

/**
* @param TlsPeer $peer
* @internal
*/
public function setTlsPeer(TlsPeer $peer = null)
{
$this->tlsPeer = $peer;
}

/**
* @return bool
*/
public function hasTlsPeer()
{
return $this->tlsPeer !== null;
}

/**
* @return TlsPeer|null
*/
public function getTlsPeer()
{
return $this->tlsPeer;
}

private function parseAddress($address)
{
if ($address === false) {
Expand Down
6 changes: 5 additions & 1 deletion src/SecureConnector.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ public function connect($uri)
}

// try to enable encryption
return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
return $promise = $encryption->enable($connection)->then(function () use ($connection) {
$connection->setTlsPeer(new TlsPeer(\stream_context_get_params($connection->stream)));

return $connection;
}, function ($error) use ($connection, $uri) {
// establishing encryption failed => close invalid connection and return error
$connection->close();

Expand Down
70 changes: 70 additions & 0 deletions src/TlsPeer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?php

namespace React\Socket;

class TlsPeer
{
private $peerCertificate;
private $peerCertificateChain;

public function __construct($context)
{
if (isset($context['options']['ssl']['peer_certificate'])) {
$this->peerCertificate = $context['options']['ssl']['peer_certificate'];
}
if (isset($context['options']['ssl']['peer_certificate_chain'])) {
$this->peerCertificateChain = $context['options']['ssl']['peer_certificate_chain'];
}
}

/**
* @return bool
*/
public function hasPeerCertificate()
{
return $this->peerCertificate !== null;
}

/**
* @return null|resource (OpenSSL x509)
*/
public function getPeerCertificate()
{
return $this->peerCertificate;
}

/**
* @return bool
*/
public function hasPeerCertificateChain()
{
return $this->peerCertificateChain !== null;
}

/**
* @return null|array of OpenSSL x509 resources
*/
public function getPeerCertificateChain()
{
return $this->peerCertificateChain;
}

protected function free()
{
if ($this->peerCertificate) {
\openssl_x509_free($this->peerCertificate);
$this->peerCertificate = null;
}
if (\is_array($this->peerCertificateChain)) {
foreach ($this->peerCertificateChain as $cert) {
\openssl_x509_free($cert);
}
$this->peerCertificateChain = null;
}
}

public function __destruct()
{
$this->free();
}
}

0 comments on commit 313ca21

Please sign in to comment.