Socket.io: ECONNRESET with SSL client certificate

Created on 30 Jan 2016  Â·  6Comments  Â·  Source: socketio/socket.io

Hi.

I'm trying to connect a client websocket to an express server + socket.io. The server is HTTPS (self signed certificate — even if I know it's not supposed to work everywhere).

Here is how I create the server :

...
const app = express();
const server = https.createServer({
    key               : fs.readFileSync(key),
    cert              : fs.readFileSync(cert),
    ca                : fs.readFileSync(ca),
    requestCert       : true,
    rejectUnauthorized: false
}, app);
app.locals.server = server;

server.listen(config.port, () => ...);

app.locals.io = socketio(app.locals.server, {
    transports: ['websocket']
});
app.locals.io.on('connection', socket => {
    ...
});

Here is how my test looks like :

import io from 'socket.io-client';

describe('...', () => {
    it('...', done => {
        // Also tried with https, ws
        let client = io.connect('wss://localhost:3006/', {
            transports        : ['websocket'],
            secure            : true, // Tried this or not
            rejectUnauthorized: false, // Tried this or not
            verify            : false // Tried this or not
        });
        client.on('connect', () => done());
        client.on('connect_error', err => {
            console.log(err);
        });
    });
});

I disabled HTTP polling willingly (as it was interfering with my REST API

Edit :
The error is :

{ [Error: websocket error]
  type: 'TransportError',
  description: 
   { [Error: socket hang up]
     code: 'ECONNRESET',
     type: 'error',
     target: 
      WebSocket {
        domain: null,
        _events: [Object],
        _eventsCount: 4,
        _maxListeners: undefined,
        _socket: null,
        _ultron: null,
        _closeReceived: false,
        bytesReceived: 0,
        readyState: 0,
        supports: [Object],
        extensions: {},
        _isServer: false,
        url: 'wss://localhost:3006/socket.io/?EIO=3&transport=websocket',
        protocolVersion: 13,
        binaryType: 'buffer' } } }

Thanks :)

Most helpful comment

The RejectUnauthorized param must be set on the https agent.

This snippet works great for a self-signed https server :

// server.js
import express from 'express';
import https   from 'https';
import sio     from 'socket.io';
import fs      from 'fs';

const key  = fs.readFileSync('./ssl/test/server.key');
const cert = fs.readFileSync('./ssl/test/server.crt');
const ca   = fs.readFileSync('./ssl/test/ca.crt');
const opts = { key, cert, ca };

const app    = express();
const server = https.createServer(opts, app);
const io     = sio.listen(server);

server.listen(3006);

io.on('connection',  socket => {
    console.log('[OK] New connection');
});

For the client :

// client.js
import io    from 'socket.io-client';
import https from 'https';

https.globalAgent.options.rejectUnauthorized = false;
const socket = io.connect('https://localhost:3006/', { agent: https.globalAgent });

socket.on('connect', function() {
    console.log('[OK] Client connected');
});

Hope this helps :rocket:

All 6 comments

The RejectUnauthorized param must be set on the https agent.

This snippet works great for a self-signed https server :

// server.js
import express from 'express';
import https   from 'https';
import sio     from 'socket.io';
import fs      from 'fs';

const key  = fs.readFileSync('./ssl/test/server.key');
const cert = fs.readFileSync('./ssl/test/server.crt');
const ca   = fs.readFileSync('./ssl/test/ca.crt');
const opts = { key, cert, ca };

const app    = express();
const server = https.createServer(opts, app);
const io     = sio.listen(server);

server.listen(3006);

io.on('connection',  socket => {
    console.log('[OK] New connection');
});

For the client :

// client.js
import io    from 'socket.io-client';
import https from 'https';

https.globalAgent.options.rejectUnauthorized = false;
const socket = io.connect('https://localhost:3006/', { agent: https.globalAgent });

socket.on('connect', function() {
    console.log('[OK] Client connected');
});

Hope this helps :rocket:

@PymZoR This fixes my problem thanks :+1:

My client is in javascript in a html page. in that case will below code work?
the client.js which you are using is running in node js or from some html page ?
// client.js
import io from 'socket.io-client';
import https from 'https';

https.globalAgent.options.rejectUnauthorized = false;
const socket = io.connect('https://localhost:3006/', { agent: https.globalAgent });

socket.on('connect', function() {
console.log('[OK] Client connected');
});

@pmidalwan in a browser, you'll have to go to 'https://localhost:3006/ and authorize the domain to proceed. Example on Chrome:

image

In a Node.js environment, you can load the ca for the client too:

const socket = require('socket.io-client')('https://localhost:3000', {
  ca: fs.readFileSync('/path/to/cert.pem')
});

Please see https://github.com/socketio/socket.io-fiddle/tree/ssl-example for a complete example.

@darrachequesne
Thanks for your reply.

I am getting error in
const socket = require('socket.io-client')('https://localhost:3000', {
ca: fs.readFileSync('/path/to/cert.pem')
});

Error:
/usr/lib/node_modules/npm/client.js:5
e_modules/npm/node_modules/socket.io/node_modules/socket.io-client')('https://
^
TypeError: object is not a function
at Object. (/usr/lib/node_modules/npm/client.js:5:105)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3

Actually I am using old version of socket.io (0.8.7) due to some limitation I can not use latest version of node.

Do you have any idea how to resolve this ?

@darrachequesne
Hi... I modifyed the code as below and it compiled for me.

var fs = require('fs');
var io =require('/usr/lib/node_modules/npm/node_modules/socket.io/node_modules/socket.io-client');
var https= require('https');

const socket = io.connect('https://localhost:3000/', {rejectUnauthorized: true,
ca: fs.readFileSync('/mnt/readerconfig/ssl/server.crt')
});

socket.on('connect', function() {
console.log('[OK] Client connected');
});

socket.on('error', function(err) {
console.log('[OK] Client connected'+err);
});

but the issue is again same . With self signed certificate it returned with below error :

root@FX9600EF95C5:/usr/lib/node_modules/npm# node client.js
[OK] Client connectedError: self signed certificate
at Error (native)
at TLSSocket. (_tls_wrap.js:936:36)
at TLSSocket.emit (events.js:104:17)
at TLSSocket._finishInit (_tls_wrap.js:467:8)

Was this page helpful?
0 / 5 - 0 ratings