2

I am trying to create a TLS/SSL connection using node.js v0.10.5 and the einaros/ws (WebSockets) module, but I get the following error:

Error: SELF_SIGNED_CERT_IN_CHAIN

I get my cert from my own CA, which is an EJBCA server, Version : EJBCA 4.0.15 (r16671) and I am using the following code in my client:

define(["ws", "fs"], function (WebSocket, fs) {
"use strict";
return function (jsonRequest) {
    var response,
        error,
        successCallback,
        errorCallback,
        HB_PFX = "server.domain.com.p12",
        HB_CA = "certs/my-ca.pem";

    var secureOptions = {
        passphrase: "the-passphrase",
        pfx: fs.readFileSync(HB_PFX),
        ca : [fs.readFileSync(HB_CA)]
    };

    var sendRequest = function () {
        var client = new WebSocket("wss://server.domain.com:8080/draft", secureOptions);

        client.on("open", function () {
            client.send(jsonRequest);
        });
            client.on("error", function (e) {
            error = e.toString();
            console.log(error);
            if (errorCallback) {
                errorCallback(error);
            }
        });

        client.on("message", function (message) {
            response = message;
            if (successCallback) {
                successCallback(message);
            }
        });

        client.on("close", function (code) {
            console.log("Connection closed with code: " + code);
        });
    };

    return {
        send: function (callback) {
            if (response && !error) {
                callback(response);
            } else {
                successCallback = callback;
            }

            sendRequest();

            return this;
        },
        ifError: function (callback) {
            if (error) {
                callback(response);
            } else {
                errorCallback = callback;
            }

            return this;
        }
    };
};

});

The p12 store (PKCS12) is generated by the CA, and it includes the key, my server certificate, and the CA certificate.

I can connect to the server with a browser with no problems, I just get prompted to accept the certificate on first connection. But when I try to connect with my client, I always get that error. I am connecting to the server using its FQDN, not an IP address.

If I try to use a self-signed certificate (a cert generated in my local machine and used instead of the p12 file), I get a DEPTH_ZERO_SELF_SIGNED_CERT error.

I am running on Mac OS X 10.8.4.

I have tried almost every permutation, even exporting the key and certificates from the PKCS12 file to PEM files, but I get the exact same error. I have also added the CA certificate to all the cacert files that I could find in my computer, which are the following:

    /Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/lib/security/cacerts
    /Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts
    /Library/Java/JavaVirtualMachines/jdk1.7.0_21.jdk/Contents/Home/jre/lib/security/cacerts
    /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/cacerts
    /System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts
    /System/Library/Java/Support/Deploy.bundle/Contents/Home/lib/security/cacerts

Does anybody know how to solve this error and create secure connections in node?

aherrera
  • 21
  • 1
  • 3

3 Answers3

0

Does anybody know how to solve this error and create secure connections in node?

For the case of Mac OS X, you need to put the root certificate (self signed, used for signing) in your Keychain.

jww
  • 97,681
  • 90
  • 411
  • 885
0

check with this

npm config set ca ""

more info here https://github.com/gootyfer/simple-ws-bradcast-server

0

The following is the https_server and client which i created as sample, take a look if this helps you.

https_server.js

var https = require('https');
var fs = require('fs');
var url = require('url');

var options = {
  key: fs.readFileSync('privkey.pem'),
  cert: fs.readFileSync('cacert.pem')
};

https.createServer(options, function (request, response) {

  var url_parts = url.parse(request.url, true);
  var query = url_parts.query;
  console.log("----------------------------------");
  console.log(request.method + "  method" + " and " + " timeout is "+  query.timeout);
  setTimeout(function () {
  console.log(" Executing setTimeout Function ");
    if(request.method=='POST') {
        console.log(" Inside post " );
        var body='';
        request.on('data', function (data) {
            body +=data;
        });
        response.setHeader("keyPOST","ValuePair");
        response.writeHead(200, {"Content-Type": "text/html"});
        response.write("<b>Hello World</b>");
        response.end(); 
        request.on('end',function(){
          var POST =  qs.parse(body);
          console.log("on request end " +POST);
          console.log("----------------------------------");
        });

    }
    else if(request.method=='GET') {
         console.log(" Inside get" );
         console.log("Query sent to the server is :" +query.name);
         response.setHeader("keyGET","ValuePair");
         response.writeHead(200, {"Content-Type": "text/html"});
         response.write("<b>Hello User, Response sent at "+query.timeout+" milli seconds from server</b>");
         response.end();
         request.on('end',function(){
            console.log("on request end");
            console.log("----------------------------------");
        });
    }

}, query.timeout);
}).listen(8000, "127.0.0.1",function() {
    console.log(' Server has been started at '+(new Date()) +' and running in https://127.0.0.1:8000/');
});

https_client.js:

var https = require("https");
var fs = require("fs");
var querystring = require('querystring');
var data = querystring.stringify({
      name: "Arun",
      timeout:5000
    });

var options = {
  hostname: '127.0.0.1',
  port: 8000,
  path: '/saveText?name=Arun&timeout=5000',
  method: 'GET',
  key: fs.readFileSync('privkey.pem'),
  cert: fs.readFileSync('cacert.pem'),
  agent: false,
  rejectUnauthorized: false
};


var req = https.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});
// write data to request body
//req.write(data);
req.end();

create privkey.pem and cacert.pem using openssl :

1) command to create privkey.pem is : openssl genrsa  -out privkey.pem 2048
2) command to create cacert.pem is  : openssl req -new -x509 -key privkey.pem -out cacert.pem -days 1095 
 (or) if the second command shows unable to locate openssl.cnf error use -config {openssl.cnf file path} option along with second command.
BenMorel
  • 34,448
  • 50
  • 182
  • 322
user1570577
  • 134
  • 1
  • 6
  • 1
    You should not need the privkey.pem at the client level. If fact, at the client should only need to trust the CA. It should look like as follows: var options = { hostname: '127.0.0.1', port: 8000, path: '/saveText?name=Arun&timeout=5000', method: 'GET', ca: fs.readFileSync('cacert.pem'), agent: false, rejectUnauthorized: false }; –  Sep 08 '16 at 00:12