Cristi Ghinea
Cristi Ghinea

Reputation: 484

How to connect with client side certificates using https module on Node.js

In production my website uses a Let's Encrypt certificate, so that the user can see in the browser the valid certificate lock. If the user navigates to route example.com/dashboard, I would like the login using client side certificate (and not username/password).

I have generated on a server using openssl private & public key. The public key stays on server and the private key is sent to the client.

Using this tutorial, I have created in server.js

const express = require('express')
const https = require('https')
const fs = require('fs')

const masterapp = express()   

var options = {
    key: fs.readFileSync('/etc/ssl/certs/sslforfree/private.key'),
    cert: fs.readFileSync('/etc/ssl/certs/sslforfree/certificate.crt'),
    requestCert: true, 
    rejectUnauthorized: false,
}

And then in the middleware

const cert = req.connection.getPeerCertificate()
    if (req.client.authorized) {
       if (cert.subject.CN === "Client123" && cert.fingerprint256 === "AA:BB:CC:DD:00..

On Mac OS it shows correctly the prompt in the browser where I select the key (key is stored in Keychain).

Problems:

  1. req.client.authorized is always false
  2. How can I securely check with Node.js that the private key corresponds to public key?
  3. Is it safer to have dashboard.example.com subdomain or route example.com/dashboard (express router)?

Upvotes: 1

Views: 3042

Answers (1)

gcochard
gcochard

Reputation: 11744

According to the medium article you referenced, you need to supply a ca property in the options object. This should be a list of client CAs that you trust:

Finally, we supply a list of CA certificates that we consider valid. For now, we sign client certificates with our own server key, so it will be the same as our server certificate.

, ca: [ fs.readFileSync('server_cert.pem') ]
             }

You should use the CA to sign the public key of the client's generated key. To do this, you'll have to generate a CSR with the private key, then sign the CSR with the CA you have in the list. Once you do this, you can send the private key and the resulting certificate to the client in a bundle, and they will be able to authenticate against your system.

  1. This is because you left off the ca property.
  2. This happens between the browser and your server automatically, once you have a trusted ca.
    1. To create a CA, you can use openssl to generate a self-signed certificate and private key.
  3. This depends, and is out of scope for stackoverflow. You might consider asking on serverfault.com or security.stackexchange.com.

Upvotes: 2

Related Questions