amphp / socket

Non-blocking socket and TLS functionality for PHP based on Amp.

Home Page:https://amphp.org/socket

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

"SNI_server_certs array requires string host name keys"

rask opened this issue · comments

I'm attempting to start a TLS encrypted socket server with amphp/amp and amphp/socket.

I create a \Amp\Socket\Certificate using a self-signed certificate and pass that into a \Amp\Socket\ServerTlsContext, which is then passed into \Amp\Socket\listen().

After a client connects I have yield $socket->enableCrypto() to enable TLS.

When I try to connect with a client I receive the following:

PHP Warning: stream_socket_enable_crypto():
        SNI_server_certs array requires string host name keys
        in /foo/bar/vendor/amphp/socket/lib/Internal/functions.php on line 95
PHP Fatal error: Uncaught Amp\Socket\CryptoException:
        Crypto negotation failed: stream_socket_enable_crypto(): SNI_server_certs array requires string host name keys
        in /foo/bar/vendor/amphp/socket/lib/Internal/functions.php on line 101
<stacktrace here>

The only documentation I could find about enabling TLS for sockets is inside the docblock for \Amp\Socket\listen():

If you want to accept TLS connections, you have to use yield $socket->enableCrypto() after accepting new clients.

Is the SNI_server_certs a bug or am I doing something wrong? Are there any good guides on how to use TLS with Amp sockets?

My PHP version is 7.1.9 and I'm running the application on Ubuntu 14.04. The TLS cert I'm attempting to use is a single-domain self-signed certificate which I created with OpenSSL tooling.

To explain better here is the main gist of what my application code is doing in terms of sockets and TLS and clients:

<?php

$cert = new \Amp\Socket\Certificate('/path/to/cert.crt');

$tls_context = (new \Amp\Socket\ServerTlsContext())->withCertificate($cert);

\Amp\Loop::run(function () use ($tls_context) {
    $socket_server = \Amp\Socket\listen('host.app:8080', null, $tls_context);

    \Amp\asyncCall(function () use ($socket_server) {
        
        while ($socket = yield $socket_server->accept()) {
            yield $socket->enableCrypto();

            \Amp\asyncCall(function () use ($socket) {
                
                while (null !== $chunk = yield $socket->read()) {
                    $socket->write('you said : ' . $chunk);
                }
                
            });
        }
        
    });
});

I checked the code for stream context options relating to SNI_server_certs and the array is created with 0-based integer indices from what I'm seeing. Should they be hostname based indices or not?

You're correct, it requires a hostname there, but I also had to look that up in the tests. I'll add a check to catch it.

We could theoretically infer the names from the certificate, but that might work or not depending on the set of certificates.

Fixed via fb3f25d.

I've also added documentation to ServerTlsContext. 👍

Documentation is now available at https://amphp.org/socket/server#tls.

Nice, many thanks! I'll get testing as soon as possible. :)