Skip to content

Commit 313ca21

Browse files
committed
SecureConnector: add optional TlsPeer, this...
...allows to capture your peer certificate and/or it's chain
1 parent 28fac70 commit 313ca21

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed

README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1322,6 +1322,33 @@ $secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
13221322
));
13231323
```
13241324

1325+
In case you want to retrieve your peers certificate or certificate chain,
1326+
you can use the related context options:
1327+
1328+
```php
1329+
$secureConnector = new React\Socket\SecureConnector($dnsConnector, $loop, array(
1330+
'capture_peer_cert' => true,
1331+
'capture_peer_cert_chain' => true,
1332+
));
1333+
```
1334+
1335+
To show the peer certificate for every new connection this can be done as
1336+
follows:
1337+
1338+
```php
1339+
$secureConnector->connect('www.google.com:80')->then(function (React\Socket\ConnectionInterface $connection) {
1340+
assert($connection instanceof React\Socket\Connection);
1341+
if ($connection->hasTlsPeer()) {
1342+
$peer = $connection->getTlsPeer();
1343+
if ($peer && $peer->hasPeerCertificate()) {
1344+
$peerCert = $peer->getPeerCertificate();
1345+
openssl_x509_export($peerCert, $cert);
1346+
echo $cert;
1347+
}
1348+
}
1349+
});
1350+
```
1351+
13251352
By default, this connector supports TLSv1.0+ and excludes support for legacy
13261353
SSLv2/SSLv3. As of PHP 5.6+ you can also explicitly choose the TLS version you
13271354
want to negotiate with the remote side:

src/Connection.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ class Connection extends EventEmitter implements ConnectionInterface
4141

4242
private $input;
4343

44+
/** @var TlsPeer|null */
45+
private $tlsPeer;
46+
4447
public function __construct($resource, LoopInterface $loop)
4548
{
4649
// PHP < 7.3.3 (and PHP < 7.2.15) suffers from a bug where feof() might
@@ -154,6 +157,31 @@ public function getLocalAddress()
154157
return $this->parseAddress(\stream_socket_get_name($this->stream, false));
155158
}
156159

160+
/**
161+
* @param TlsPeer $peer
162+
* @internal
163+
*/
164+
public function setTlsPeer(TlsPeer $peer = null)
165+
{
166+
$this->tlsPeer = $peer;
167+
}
168+
169+
/**
170+
* @return bool
171+
*/
172+
public function hasTlsPeer()
173+
{
174+
return $this->tlsPeer !== null;
175+
}
176+
177+
/**
178+
* @return TlsPeer|null
179+
*/
180+
public function getTlsPeer()
181+
{
182+
return $this->tlsPeer;
183+
}
184+
157185
private function parseAddress($address)
158186
{
159187
if ($address === false) {

src/SecureConnector.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@ public function connect($uri)
5656
}
5757

5858
// try to enable encryption
59-
return $promise = $encryption->enable($connection)->then(null, function ($error) use ($connection, $uri) {
59+
return $promise = $encryption->enable($connection)->then(function () use ($connection) {
60+
$connection->setTlsPeer(new TlsPeer(\stream_context_get_params($connection->stream)));
61+
62+
return $connection;
63+
}, function ($error) use ($connection, $uri) {
6064
// establishing encryption failed => close invalid connection and return error
6165
$connection->close();
6266

src/TlsPeer.php

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
namespace React\Socket;
4+
5+
class TlsPeer
6+
{
7+
private $peerCertificate;
8+
private $peerCertificateChain;
9+
10+
public function __construct($context)
11+
{
12+
if (isset($context['options']['ssl']['peer_certificate'])) {
13+
$this->peerCertificate = $context['options']['ssl']['peer_certificate'];
14+
}
15+
if (isset($context['options']['ssl']['peer_certificate_chain'])) {
16+
$this->peerCertificateChain = $context['options']['ssl']['peer_certificate_chain'];
17+
}
18+
}
19+
20+
/**
21+
* @return bool
22+
*/
23+
public function hasPeerCertificate()
24+
{
25+
return $this->peerCertificate !== null;
26+
}
27+
28+
/**
29+
* @return null|resource (OpenSSL x509)
30+
*/
31+
public function getPeerCertificate()
32+
{
33+
return $this->peerCertificate;
34+
}
35+
36+
/**
37+
* @return bool
38+
*/
39+
public function hasPeerCertificateChain()
40+
{
41+
return $this->peerCertificateChain !== null;
42+
}
43+
44+
/**
45+
* @return null|array of OpenSSL x509 resources
46+
*/
47+
public function getPeerCertificateChain()
48+
{
49+
return $this->peerCertificateChain;
50+
}
51+
52+
protected function free()
53+
{
54+
if ($this->peerCertificate) {
55+
\openssl_x509_free($this->peerCertificate);
56+
$this->peerCertificate = null;
57+
}
58+
if (\is_array($this->peerCertificateChain)) {
59+
foreach ($this->peerCertificateChain as $cert) {
60+
\openssl_x509_free($cert);
61+
}
62+
$this->peerCertificateChain = null;
63+
}
64+
}
65+
66+
public function __destruct()
67+
{
68+
$this->free();
69+
}
70+
}

0 commit comments

Comments
 (0)