0

I'm attempting to build a simple client/server application in C++ using the IXWebsocket library, using the example code as an example, as shown on this page - https://machinezone.github.io/IXWebSocket/usage/

The code works fine when using an unsecured connection (as denoted by a ws:// url), but I can't get it working at all when using a secured connection (as denoted by a wss:// url).

The website states under the "TLS Support and configuration" section that

Then, secure sockets are automatically used when connecting to a wss://* url. Additional TLS options can be configured by passing a ix::SocketTLSOptions instance to the setTLSOptions on ix::WebSocket (or ix::WebSocketServer or ix::HttpServer)

This implies to me that simply changing the ws:// url to a wss:// url is enough to instruct the application to secure the connection, however this does not work.

When I attempt to connect using a wss:// url, the server returns the following WebSocketServer::handleConnection() HTTP status: 400 error: Error reading HTTP request line

The website goes on to say that

Additional TLS options can be configured by passing a ix::SocketTLSOptions instance to the setTLSOptions on ix::WebSocket (or ix::WebSocketServer or ix::HttpServer)

and...

Specifying certFile and keyFile configures the certificate that will be used to communicate with TLS peers. On a client, this is only necessary for connecting to servers that require a client certificate. On a server, this is necessary for TLS support.

This implies to me that for the server to support TLS, I must provide a cert file, and a key file.

The github repo includes the script generate_certs.sh which produces a series of certificates in pem format, which should be enough to get things working. Included among them are selfsigned-client-crt.pem and selfsigned-client-key.pem, which seem like obvious candidates, however they specifically state client in the names, which suggests that they should not be used in the server application, rather they belong in the client.

The website also includes the example snippet:

webSocket.setTLSOptions({
    .certFile = "path/to/cert/file.pem",
    .keyFile = "path/to/key/file.pem",
    .caFile = "path/to/trust/bundle/file.pem", // as a file, or in memory buffer in PEM format
    .tls = true // required in server mode
});

I have attempted to populate the certFile and keyFile properties, and specified "NONE" for the caFile property as explained in the example, however this results in the server application printing SocketServer::run() tls accept failed: error in handshake : SSL - The connection indicated an EOF to the console.

What's more, the example snippet listed above states "path/to/cert/file.pem" and "path/to/key/file.pem" but doesn't explicitly state whether those should be client, or server usage.

The example doesn't come with a complete runnable implementation, and doesn't explain clearly what is needed to make TLS work in this particular form, and I'm at a bit of a loss now. There is an example application in the github repo, however it includes a number of different variations, all of which are far more complicated than this trivial example, and it is this trivial example that I need to get working so I can understand how to implement this further.

In my server application, I have implemented the following for the TLS options:

int port = 8443;

ix::WebSocketServer server(port);
ix::SocketTLSOptions tlsOptions;
tlsOptions.certFile = "certs/selfsigned-client-crt.pem";
tlsOptions.keyFile = "certs/selfsigned-client-key.pem";
tlsOptions.caFile = "NONE";
tlsOptions.tls = true;    //Required for TLS

server.setTLSOptions(tlsOptions);

I am pretty sure that the issue in in how I've set up the key and cert files. I have used the client files here, but I also tried generating and signing a server cert and key, which also did not work.

I have even tried using the trusted key and cert for both the client and server applications, and still did not get a working TLS connection (the following files were generated by the generate_cert.sh script - selfsigned-client-crt.pem, selfsigned-client-key.pem, trusted-ca-crt.pem, trusted-ca-key.pem, trusted-client-crt.pem, trusted-client-key.pem, trusted-server-crt.pem, trusted-server-key.pem, untrusted-ca-crt.pem, untrusted-ca-key.pem, untrusted-client-crt.pem, untrusted-client-key.pem

... none of which is a self signed server cert. What I can gather from the example page is that I need to do the following to get this working.

  1. Generate a server cert and key
  2. Self sign the cert
  3. Specify the cert and key file in the tlsOptions on the server
  4. Set the tls property in tlsOptions to true on the server
  5. Set the caFile property in tlsOptions on the server to "NONE"
  6. Set the url in the client to a wss:// url

But this did not work when I tried it, so there's clearly something I've missed.

All I'm aiming to do for the moment is to use self signed certs so that I can test my client and server, both running on localhost.

If anybody can steer me in the right direction, I'd be immensely grateful. I've been on this for 4 days now and I'm really lost.

Many thanks

Alex
  • 1,643
  • 1
  • 14
  • 32

2 Answers2

1

Check this file https://github.com/machinezone/IXWebSocket/blob/master/ws/test_ws.sh / it does a full client + server encrypted exchange.

Note that on macOS there are limitations, but on windows or linux, using mbedtls and openssl everything should work fine.

ps: You will need to supply the same set of certs on the client and on the server.

bsergean
  • 81
  • 2
  • Thank you, however you actually already answered this for me on the github page, and you were (as you are now), absolutely right! – Alex Mar 31 '23 at 18:04
1

https://machinezone.github.io/IXWebSocket/build/

-DUSE_TLS=1 will enable TLS support

so I do the following :

mkdir build

cd build

cmake -DUSE_TLS=1 -DUSE_WS=1 ..

works for me

barfatchen
  • 1,630
  • 2
  • 24
  • 48