From e0dcc1a1414282b8f9038b3881e7d8494cd0ba2c Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Fri, 25 Sep 2020 12:55:50 +0200 Subject: [PATCH] SecureConnector: add optional TlsPeer, this... ...allows to capture your peer certificate and/or it's chain --- README.md | 27 ++++++++++ src/Connection.php | 28 ++++++++++ src/SecureConnector.php | 8 ++- src/TlsPeer.php | 111 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 src/TlsPeer.php diff --git a/README.md b/README.md index fafc66f8..5b65becb 100644 --- a/README.md +++ b/README.md @@ -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:443')->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: diff --git a/src/Connection.php b/src/Connection.php index 5e3b00d9..fad8f723 100644 --- a/src/Connection.php +++ b/src/Connection.php @@ -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 @@ -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) { diff --git a/src/SecureConnector.php b/src/SecureConnector.php index e5ebc73e..970a383a 100644 --- a/src/SecureConnector.php +++ b/src/SecureConnector.php @@ -56,7 +56,13 @@ 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( + TlsPeer::fromContextOptions(\stream_context_get_options($connection->stream)) + ); + + return $connection; + }, function ($error) use ($connection, $uri) { // establishing encryption failed => close invalid connection and return error $connection->close(); diff --git a/src/TlsPeer.php b/src/TlsPeer.php new file mode 100644 index 00000000..38cfad10 --- /dev/null +++ b/src/TlsPeer.php @@ -0,0 +1,111 @@ +peerCertificate = $peerCertificate; + } + if ($peerCertificateChain !== null) { + foreach ($peerCertificateChain as $resource) { + static::assertX509Resource($resource); + } + $this->peerCertificateChain = $peerCertificateChain; + } + } + + public static function fromContextOptions($options) + { + if (isset($options['ssl']['peer_certificate'])) { + $peerCertificate = $options['ssl']['peer_certificate']; + } else { + $peerCertificate = null; + } + if (isset($options['ssl']['peer_certificate_chain'])) { + $peerCertificateChain = $options['ssl']['peer_certificate_chain']; + } else { + $peerCertificateChain = null; + } + + return new static($peerCertificate, $peerCertificateChain); + } + + protected static function assertX509Resource($resource) + { + if (! \is_resource($resource)) { + throw new \InvalidArgumentException(\sprintf( + 'Resource expected, got "%s"', + \gettype($resource) + )); + } + if (\get_resource_type($resource) !== 'OpenSSL X.509') { + throw new \InvalidArgumentException(\sprintf( + 'Resource of type "OpenSSL X.509" expected, got "%s"', + \get_resource_type($resource) + )); + } + } + + /** + * @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(); + } +} 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