简体   繁体   中英

Unable to connect socket.io in node.js with tls

I have googled and search in stackoverflow, any thread related to socket.io+tls, or node.js+tls, or ssl, an so on... but I cannot find any way of building what I need:

A node.js server connected to the client through socket.io and using tls (only server authentication is needed)

So far I have connect the server and the client without using tls.

When I create my node.js server (listening at port 3000) and using tls I can use the command:

openssl s_client -connect localhost:3000

and everthing seems to be ok, but went I try to connect my socket.io client I got always an error.

Here is my simple server code:

 var tls = require('tls');
 var fs = require('fs');

  var options = {
    key: fs.readFileSync('evServer-key.pem'),
    cert: fs.readFileSync('evServer-cert.pem'),
    requestCert: false,

  };

  var server = tls.createServer(options, function(cleartextStream) {
    console.log('server connected',
                cleartextStream.authorized ? 'authorized' : 'unauthorized');
    cleartextStream.write("welcome!\n");
    cleartextStream.setEncoding('utf8');
    cleartextStream.pipe(cleartextStream);
  });

  io = require('socket.io').listen(server);

  server.listen(3000, function() {
    console.log('server bound');
  });

  io.sockets.on('connection', function (socket) {

      // When new users join
    socket.on('join', function (data, fn) {
      console.log("User connected");
      socket.set('socketname', 'name', function () {
          socket.emit('Connection received')  ;  // for the current socket
      });
    });  
      // --------------- client events

    socket.on('clientjoin', function (data) {
          client_socket = socket;
          console.log("BT Client joined");
    });

    socket.on('hello', function (data) {
          client_socket = socket;
          console.log("Hello received");
          socket.emit('Hi there!');
    });

      // When a client disconnects
    socket.on('disconnect', function () {
          socket.get('nickname', function (err, nickname) {
          console.log(nickname + " logged out")
      });
    });
  });

and this is the connection in the client:

socket = new SocketIO("http://"+this.serverIpAddress+":3000/");

If I use:

http://localhost:3000

I get a connection refuse error:

02-22 15:37:41.702: W/System.err(621): io.socket.SocketIOException: Error while handshaking
02-22 15:37:41.702: W/System.err(621):  at io.socket.IOConnection.handshake(IOConnection.java:322)
02-22 15:37:41.702: W/System.err(621):  at io.socket.IOConnection.access$600(IOConnection.java:39)
02-22 15:37:41.702: W/System.err(621):  at io.socket.IOConnection$ConnectThread.run(IOConnection.java:199)
02-22 15:37:41.702: W/System.err(621): Caused by: java.net.ConnectException: localhost/127.0.0.1:3000 - Connection refused
02-22 15:37:41.702: W/System.err(621):  at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:207)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.net.PlainSocketImpl.connect(PlainSocketImpl.java:437)
02-22 15:37:41.712: W/System.err(621):  at java.net.Socket.connect(Socket.java:983)
02-22 15:37:41.712: W/System.err(621):  at  org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:75)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection.<init>(HttpConnection.java:48)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnection$Address.connect(HttpConnection.java:322)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpConnectionPool.get(HttpConnectionPool.java:89)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getHttpConnection(HttpURLConnectionImpl.java:285)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.makeConnection(HttpURLConnectionImpl.java:267)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.retrieveResponse(HttpURLConnectionImpl.java:1018)
02-22 15:37:41.712: W/System.err(621):  at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:512)
02-22 15:37:41.742: W/System.err(621):  at io.socket.IOConnection.handshake(IOConnection.java:313)
02-22 15:37:41.742: W/System.err(621):  ... 2 more
02-22 15:37:41.742: I/io.socket(621): Cleanup
02-22 15:55:57.352: I/dalvikvm(621): Jit: resizing JitTable from 512 to 1024
02-22 16:00:54.763: I/AsyncTask(621): onPreExecute
02-22 16:00:54.772: I/ClientActivity(621): C: Connecting...
02-22 16:00:54.782: I/AsyncTask(621): onPostExecute: Completed.
02-22 16:00:54.792: I/AsyncTask(621): an Error occured
02-22 16:00:54.792: W/System.err(621): io.socket.SocketIOException: Error while handshaking
.
.
.

and if I use

https://localhost:3000

I get this other null pointer error:

02-22 16:06:06.432: I/AsyncTask(666): onPreExecute
02-22 16:06:06.442: I/ClientActivity(666): C: Connecting...
02-22 16:06:06.503: I/AsyncTask(666): onPostExecute: Completed.
02-22 16:06:06.512: I/AsyncTask(666): an Error occured
02-22 16:06:06.512: W/System.err(666): io.socket.SocketIOException: Error while handshaking
02-22 16:06:06.512: W/System.err(666):  at io.socket.IOConnection.handshake(IOConnection.java:322)
02-22 16:06:06.512: W/System.err(666):  at io.socket.IOConnection.access$600(IOConnection.java:39)
02-22 16:06:06.512: W/System.err(666):  at io.socket.IOConnection$ConnectThread.run(IOConnection.java:199)
02-22 16:06:06.523: W/System.err(666): Caused by: java.lang.NullPointerException
02-22 16:06:06.523: W/System.err(666):  at io.socket.IOConnection.handshake(IOConnection.java:301)
02-22 16:06:06.523: W/System.err(666):  ... 2 more

I have tried also writing my external IP address instead of localhost or 127.0.0.1 but it still does not work, is it impossible what I want to do? any idea or advise?

Thank you in advance.


UPDATE:

I have been working on it but I do not achieve to connect client and server yet. What I have tried in the client side (android), as I am using Gottox's socket.io library and I could not use the solution proposed by user568109, is to add this to my client's code:

        CertificateFactory cf = CertificateFactory.getInstance("X.509"); 
        InputStream caInput = new BufferedInputStream(new FileInputStream("/sdcard/cacert.crt")); 
        Certificate ca; 
        try { 
            ca = cf.generateCertificate(caInput); 
        } finally { 
            caInput.close(); 
        } 

        // Create a KeyStore containing our trusted CAs 
        String keyStoreType = KeyStore.getDefaultType(); 
        KeyStore keyStore = KeyStore.getInstance(keyStoreType); 
        keyStore.load(null, null); 
        keyStore.setCertificateEntry("ca", ca); 



        SocketIO.setDefaultSSLSocketFactory(SSLContext.getInstance("SSL"));
        socket = new SocketIO("https://"+this.serverIpAddress+":3000/");

Where, cacert.crt is a certificate of a certification authority that I have created and that I have used to sign the key of the server.

I can connect with the web browser to my server through https without problem but my android application throws the following error:

02-26 16:39:18.420: I/AsyncTask(27913): onPreExecute
02-26 16:39:18.420: I/ClientActivity(27913): C: Connecting...
02-26 16:39:18.445: E/ClientActivity(27913): C: Error
02-26 16:39:18.445: E/ClientActivity(27913): java.security.cert.CertificateException: org.apache.harmony.security.asn1.ASN1Exception: ASN.1 sequence identifier expected at [0], got 43
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.provider.cert.X509CertImpl.<init>(X509CertImpl.java:106)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.provider.cert.X509CertFactoryImpl.getCertificate(X509CertFactoryImpl.java:656)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.provider.cert.X509CertFactoryImpl.engineGenerateCertificate(X509CertFactoryImpl.java:109)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:195)
02-26 16:39:18.445: E/ClientActivity(27913):    at com.android.locaalton.CommTask.doInBackground(CommTask.java:61)
02-26 16:39:18.445: E/ClientActivity(27913):    at com.android.locaalton.CommTask.doInBackground(CommTask.java:1)
02-26 16:39:18.445: E/ClientActivity(27913):    at android.os.AsyncTask$2.call(AsyncTask.java:287)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
02-26 16:39:18.445: E/ClientActivity(27913):    at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
02-26 16:39:18.445: E/ClientActivity(27913):    at java.lang.Thread.run(Thread.java:856)
02-26 16:39:18.445: E/ClientActivity(27913): Caused by: org.apache.harmony.security.asn1.ASN1Exception: ASN.1 sequence identifier expected at [0],  got 43
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.asn1.BerInputStream.expected(BerInputStream.java:464)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.asn1.BerInputStream.readSequence(BerInputStream.java:502)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.asn1.DerInputStream.readSequence(DerInputStream.java:105)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.asn1.ASN1Sequence.decode(ASN1Sequence.java:40)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.asn1.ASN1Type.decode(ASN1Type.java:91)
02-26 16:39:18.445: E/ClientActivity(27913):    at org.apache.harmony.security.provider.cert.X509CertImpl.<init>(X509CertImpl.java:101)
02-26 16:39:18.445: E/ClientActivity(27913):    ... 12 more

Any idea about this new issue?

Web sockets can be unencrypted ws:// or encrypted wss:// (ws+ssl). Socket.io allows to choose between the two using the secure option like this:

<script src="http://localhost:3000/socket.io/socket.io.js"></script>
socket = io.connect('http://localhost:3000', {secure:true});     //encrypted
socket = io.connect('http://localhost:3000', {secure:false});    //unencrypted 

This should do all your websocket encryption requirements. Whatever errors you are getting are because you are trying to use your tls server as http/https server. openssl s_client -connect localhost:3000 is the right way to access it. http://localhost:3000 will require http server running at that address, but your server is tls ( http://nodejs.org/api/tls.html#tls_tls_ssl ).

You should use it as https server. It is a subclass of tls.Server and emits events same as http.Server. http://nodejs.org/api/https.html#https_class_https_server

var https = require('https');   //tls changed to https
var server = https.createServer(options, function(cleartextStream) {
    console.log('server connected',

Your server is now https and your https://localhost:3000 should work. Try connecting to it using openssl s_client to check if it is working.

Update after comment

user1249517 you should specify the source of errors when asking the question. You tagged it under node.js ,ssl and socket.io but it should have been java, android and socket. socket.io is javascript library whereas you are using gottox java library for socket.io.

Anyways, when you use browser to view the site, the certificates are managed by browser itself, when you use java app, it should handle the certificates. The error that you are getting :

Caused by: org.apache.harmony.security.asn1.ASN1Exception: ASN.1 sequence identifier expected at [0],  got 43

ASN.1 is a encoding format for X.509 certificates. ASN.1 sequence identifier expected would mean that your certificate is corrupt/invalid ASN.1 format. You should not use your certificate directly but convert it to ASN.1 format with openssl . Try something like this .

openssl asn1parse -in mycert.pem

Specify the input format of the certficate and validate it before parsing. If all certificates are valid, then there is some error in the code.

The solution to my update is to create a certification authority, use it to sign the certificates of the server and also install the certificate in the android phone.

After solving that I had to face new problems, the ones treated here:

https://github.com/Gottox/socket.io-java-client/issues/14

The solution is also inside the link

Hope this helps someone!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM