Thomas Yamakaitis
Thomas Yamakaitis

Reputation: 463

Using a Self-Signed CA Certificate for WebSocket (ws) in Node JS

I need to use the ws client in Node JS to connect to a separate WebSocket server.

I am able to connect using a sample program in my Chrome since I installed my Self-Signed Root CA in the Trusted Root Certification Authorities Store on my machine.

I know that Node JS uses a hard coded list of Root CAs (stupid), but I was hoping there was some way I could import my own.

I tried:

        export NODE_EXTRA_CA_CERTS=C:\\Users\\IT1\\Documents\\security\\rootCA.pem
        // Using just ca
        var test = new WebSocket(uri, {
            ca: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.pem")
        });

        // Using cert and key
        var test = new WebSocket(uri, {
            cert: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.crt"),
            key: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.key")
        });

        // Using ca, cert and key
        var test = new WebSocket(uri, {
            ca: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.pem"),
            cert: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.crt"),
            key: fs.readFileSync("C:\\Users\\IT1\\Documents\\security\\rootCA.key")
        });

And NO MATTER WHAT, I always get the following error message:

events.js:200
      throw er; // Unhandled 'error' event
      ^

Error: unable to verify the first certificate
    at TLSSocket.onConnectSecure (_tls_wrap.js:1321:34)
    at TLSSocket.emit (events.js:223:5)
    at TLSSocket._finishInit (_tls_wrap.js:794:8)
    at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:608:12)
Emitted 'error' event on WebSocket instance at:
    at ClientRequest.<anonymous> (C:\Users\IT1\source\repos\WebSocketTest\WebSocketTest\node_modules\ws\lib\websocket.js:554:15)
    at ClientRequest.emit (events.js:223:5)
    at TLSSocket.socketErrorListener (_http_client.js:406:9)
    at TLSSocket.emit (events.js:223:5)
    at emitErrorNT (internal/streams/destroy.js:92:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
    at processTicksAndRejections (internal/process/task_queues.js:81:21) {
  code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE'
}

Also, I cannot use rejectUnauthorized: true. I need it to be authorized, so please don't suggest that as a solution.

Please help, I'm really scratching my head on this one.

Upvotes: 3

Views: 6400

Answers (1)

Thomas Yamakaitis
Thomas Yamakaitis

Reputation: 463

After almost a day or two of scratching my head, I decided to verify the certificates in OpenSSL. It turned out that the certificate was using a different encryption algorithm (SHA 256 vs. DES3 or something like that). The reason that it worked fine in the browser is because I already installed a different certificate for that domain earlier.

Moral of the story:

  1. ALWAYS test your SSL certificates with OpenSSL before trying to use them in your code. OpenSSL will always present a LOT more information about why your certificate isn't working than NodeJS, Java or any runtime environment.
  2. Remove all certificates for a domain from your trusted root store before testing a Root Certificate.
  3. I was following tutorials online about generating a Self-Signed Root CA in Windows, and the tutorials I found did not offer a lot of information about what I was doing, more so "this is how you do it". This is where I went wrong because I was following a couple of tutorials and combining the info to find a solution. This meant I generated a root certificate and private key using one tutorial and then signed other certificates using another tutorial (which specified a different algorithm, but did NOT explain that the algorithms must match for the root CA and the signed certificate).
  4. It helps to have a decent understanding of how SSL and Root Certificates work before diving into making a Self-Signed root CA. Not from a technical perspective, but from the perspective of why there are Root CAs, how they're used in the real world, and how it applies to your application as a developer. I found this article extremely helpful.

Upvotes: 3

Related Questions