4

I've been trying to get Node.JS to work with SSL and client certificates. Originally, I had tried to get it to work with restify (see my question here). When I couldn't get that to work, I backed up and tried to find an example that illustrated what I was trying to accomplish. I tried this one, and I'm receiving an odd error.

Code is as follows:

Server:

var sys = require("sys");
var fs = require("fs");
var https = require("https");

var options = {
  key: fs.readFileSync("../certs/server.key"),
  cert: fs.readFileSync("../certs/server.crt"),
  ca: fs.readFileSync("../certs/ca.crt"),
  requestCert: true,
  rejectUnauthorized: true
};

https.createServer(options, function (req, res) {
  console.log(req);
  res.writeHead(200);
  sys.puts("request from: " + req.connection.getPeerCertificate().subject.CN);
  res.end("Hello World, " + req.connection.getPeerCertificate().subject.CN + "\n");
}).listen(8080);

sys.puts("server started");

Client:

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

var options = {
    host: 'localhost',
    port: 8080,
    path: '/hello',
    method: 'GET',
    key: fs.readFileSync("../certs/user.key"),
    cert: fs.readFileSync("../certs/user.crt"),
    ca: fs.readFileSync("../certs/ca.crt"),
    passphrase: 'thepassphrase'
};

var req = https.request(options, function(res) {
    console.log("statusCode: ", res.statusCode);
    console.log("headers: ", res.headers);

    res.on('data', function(d) {
        process.stdout.write(d);
    });
});

req.end();

req.on('error', function(e) {
    console.error(e);
});

Running test-client.js yields this:

{ [Error: socket hang up] code: 'ECONNRESET' }

Attempting the same sort of thing with curl:

curl -k -v --key user.key --cert user.crt:thepassphrase --cacert ca.crt https://localhost:8080/hello

yields:

* About to connect() to localhost port 8080 (#0)
*   Trying 127.0.0.1... connected
* successfully set certificate verify locations:
*   CAfile: ca.crt
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Request CERT (13):
* SSLv3, TLS handshake, Server finished (14):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS handshake, Client key exchange (16):
* SSLv3, TLS handshake, CERT verify (15):
* SSLv3, TLS change cipher, Client hello (1):
* SSLv3, TLS handshake, Finished (20):
* Unknown SSL protocol error in connection to localhost:8080 
* Closing connection #0
curl: (35) Unknown SSL protocol error in connection to localhost:8080

If I want to go the extra step to require a client certificate, how would I go about it?

Community
  • 1
  • 1
Chris
  • 1,013
  • 1
  • 15
  • 35

2 Answers2

3

How about putting this server behind an nginx?

This might sound complicated, or add a lot of overhead, but I promise you it's REALLY simple, and nginx's SSL handling is easy.

Look for proxying with nginx (example).

P.S
Both apps can, and probably, reside in the same server machine.

Poni
  • 11,061
  • 25
  • 80
  • 121
  • That's an intriguing answer. Can nginx pass information about the user certificate on to the ultimate destination url? Possibly by adding some parameters to the url? – Chris Oct 24 '12 at 16:03
  • Glad to hear! How did you go about it eventually, in regard to certificate forwarding through nginx? I'm just curious – Poni Nov 13 '12 at 05:55
  • 1
    I didn't forward the cert through nginx, @Poni, I authenticated with a cert against nginx, and just continued on with regular-no-client-cert https the rest of the way. Theory being that nginx wont pass the conversation along unless everything matches up. – Chris Mar 06 '13 at 03:05
  • dunno.. wasn't me. I would assume the downvote was because while the answer was useful to me, it didn't really answer the question. – Chris Apr 30 '13 at 21:29
  • 2
    @Poni, I have the same issue. However, are there any ideas for a solution that does not involve nginx and works directly with node? – psiphi75 Jun 30 '13 at 21:07
  • @psiphi75 see my alternative solution below – michielbdejong Mar 09 '16 at 16:12
2

Add rejectUnauthorized: false in both the server options and the client options.

That tells nodejs to accept self-signed certs. See also https://github.com/vanjakom/JavaScriptPlayground/pull/3.

michielbdejong
  • 1,077
  • 9
  • 14