Search code examples
phpnginxsslwebsocket

Wss Webserver not working properly with self signed key


I have created a PHP secure websocket (wss) server using php React and Ratchet. I only have a self signed certificate, because I am currently only trying to use my server as a backend for an app, and so I don't need a domain name, as it's only for the app to access, not for people to access directly, and so it seems a waste of money to have to subscribe to a domain name just for that, and I would need a domain name before getting a trusted ssl certificate, and I own the server anyway. That being said, here is my code in

secure-socket-server.php:

<?php

use React\Socket\SecureServer;

require dirname(__DIR__) . '/vendor/autoload.php';
require 'Pool.php';

$loop = React\EventLoop\Factory::create();
$webSock = new React\Socket\Server('0.0.0.0:<my_port>', $loop);
$webSock = new React\Socket\SecureServer($webSock, $loop, [
    'local_cert'        => '<my_ssl_cert_path>.pem',
    'local_pk'          => '<my_ssl_cert_key>.key',
    'allow_self_signed' => TRUE,
    'verify_peer' => TRUE,
    'allow_self_signed' => TRUE
]);

$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            new Pool()
        )
    ),
    $webSock,
    $loop
);

$webServer->run();

I run

php secure-web-socket.php

And I tried to connect to it from Android, and I got "handshake failed"

Also, when I ran

./testssl.sh <my_host_ip>:<my_port>

I get:

<my_host_ip>:<my_port> doesn't seem to be a TLS/SSL enabled server

If I use:

 ./testssl.sh <my_host_ip>:443

I actually get results showing it is a TLS/SSL enabled server.

In my nginx file, I have:

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        # SSL configuration
        #
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;

        include snippets/<my_certificate_config_file>.conf;

        root /usr/share/nginx/html;

        # Add index.php to the list if you are using PHP
        index index.php index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        # pass PHP scripts to FastCGI server
        #
        location ~ \.php$ {
                include snippets/fastcgi-php.conf;

                fastcgi_pass unix:/var/run/php5-fpm.sock;
        }
}

I did try adding this to my nginx file:

server {
    listen <my_port> ssl;
    listen [::]:<my_port> ssl;
    server_name <my_host_ip>;

    # Add index.php to the list if you are using PHP
    #index index.html index.htm index.nginx-debian.html;
    include snippets/<my_certificate_config_file>.conf

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
}

And restarted nginx, but this led to my webpages under https://my_host_ip/ being unable to connect. And, plus that solution, even if it worked, would only allow me to run my socket server securely on only one port, instead of any port that is available.

How do I get this working?

Update:

I got passed those problems, but am now dealing with android getting a "Expected 101, received: 500"


Solution

  • So, I managed to get it all working. First of all, as for the part with the handshake failing, I might have had the wrong paths for:

     'local_cert'        => '<my_ssl_cert_path>.pem',
     'local_pk'          => '<my_ssl_cert_key>.key',
    

    Because I made a new certificate and key and used those, and I got passed the "handshake failed" error in the tech.gusavila92.websocketclient.WebSocketClient` class that I am using on the android client side.

    After that, I had, the error "Expected 101, got 500" error in the WebSocket class. I did some digging around, and discovered it's because I can't use new WebSocketClient("wss://ip-address:port");, but I have to use new WebSocketClient("wss://ip-address:port/");, notice the extra slash.

    Here's the reasoing. So apparently the first line of the header is built by using "GET raw_url 1.1", and if you have no slash, you get "GET HTTP/1.1", but PHP Guzzle wants to see "GET / HTTP/1.1", not "GET HTTP/1.1", or it throws an exception while parsing the header. And the raw_url is everything after :port in this case, so if you put no "/", you get a blank raw_url, so you get "GET HTTP/1.1", but if you put a slash after, you get "GET / HTTP/1.1"