Trevor Bill
Trevor Bill

Reputation: 43

Handshake failure in ExpressJS Node app with Let's Encrypt SSL certificates

I'm having an issue setting up a node server with let's encrypt certificates. I'm using Express to create https server like this:

var fs = require('fs');
var app = require('express')();
var https = require('https');

var server = https.createServer({ 
key: 
fs.readFileSync('/etc/letsencrypt/live/mydomain.com/privkey.pem'), 
cert: fs.readFileSync('/etc/letsencrypt/live/mydomain.com/cert.pem'), 
ca: fs.readFileSync('/etc/letsencrypt/live/mydomain.com/chain.pem'), 
requestCert: true, 
rejectUnauthorized: true},app);

app.get("/express", function(request, response){
response.end("Express Response");
});
server.listen(8082);

I want to set rejectUnauthorized: true because I've read that disabling it makes the client/server communication vulnerable to MITM attack. For the client side i'm using the request module to make the https GET request like this:

var path = require('path');
var requests = require('request');
var fileSystem = require('fs');

var checkRequestOpts = {
    url: "https://example.com:8082/express",
    agentOtions: {
        ca: fileSystem.readFileSync(__dirname + '/chain1.pem')
    },
    method: 'GET',
    json: true,
    formData: {
        'x': 100,
        'y': 500,
        'z': 97    
    }
};

requests(checkRequestOpts, function(err, sr, rb)
{
    if(err)
        console.log('Error occured' + err);
    else
    {
        console.log('Response: ' + rb);
    }
});

However, when I run the client side app it crashes with error

Error occuredError: write EPROTO 140593052855168:error:14094410:SSL 
routines:ssl3_read_bytes:sslv3 alert handshake 
failure:../ssl/record/rec_layer_s3.c:1399:SSL alert number 40

The server does not have to provide content to a broswer it just needs to work with the client node app. It works when I set rejectUnauthorized: false but not when it is set to true. I'd be really thankful if someone could help me out on this or give any leads to a possible solution. Thanks!

Upvotes: 2

Views: 2273

Answers (2)

menya
menya

Reputation: 1525

You should set client's cert if you use self-signed SSL certificates. It is not required to set this when use Let's Encrypt certificates, it has already stored in your browser or system.

Upvotes: 0

coolaj86
coolaj86

Reputation: 77092

The naming isn't what you think it is.

Essentially, you've mixed up ca, cert, and key, which is a very common mistake.

Here's a few resources to take a look at:

Solution

  • key refers to privkey.pem
  • cert refers to the concatenation of cert.pem AND chain.pem (aka fullchain.pem)

You should ignore ca because ca refers to Certificate Authority and is where you would put root.pem if you were using enterprise or military peer certificate validation.

  • rejectUnauthorized: true IS disabling the security checks. You DO NOT want this. You want rejectUnauthorized: false (the default).
  • requestCert: true is only used for peer-certificate validation. You DO NOT want this.

Try Greenlock Too

Also, you might prefer to use greenlock-express.js (Let's Encrypt / ACME client for node.js/express.js) so that you don't have to do any manual work in the first place.

Upvotes: 1

Related Questions