Skip to content

Instantly share code, notes, and snippets.

@kenjikato
Forked from pcan/README.md
Last active April 15, 2022 10:48
Show Gist options
  • Select an option

  • Save kenjikato/1bd9fe69e0a115f8027ab89860101c09 to your computer and use it in GitHub Desktop.

Select an option

Save kenjikato/1bd9fe69e0a115f8027ab89860101c09 to your computer and use it in GitHub Desktop.
2-Way TLS Symmetric Client Server Cert Auth for Node.js and Nginx

Two-Way TLS or mTLS Symmetric Client Server Cert Auth for Node.js using plain TLS sockets and/or Nginx

This file describes how to set up a bidirectional client/server TLS authentication or mTLS (mutual-auth TLS) for plain TLS sockets using Node.js.

If you don't know why you would use a two-way TLS or mTLS auth mechaniusm it's worth checking out these videos to get a better understanding.

Newer versions of openssl are stricter about certificate purposes. Use extensions accordingly.

Prepare certificates

Generate a Certificate Authority:

openssl req -new -x509 -days 9999 -keyout ca-key.pem -out ca-crt.pem
  • Insert a CA Password
  • Specify a CA Common Name, like 'root.localhost' or 'ca.localhost'. This MUST be different from both server and client CN.

Server certificate

Generate Server Key:

openssl genrsa -out server-key.pem 4096

Generate Server certificate signing request:

openssl req -new -key server-key.pem -out server-csr.pem
  • Specify server Common Name, like 'localhost' or 'server.localhost'. The client will verify this, so make sure you have a vaild DNS name for this.
  • For this example, do not insert the challenge password.

Sign certificate using the CA:

openssl x509 -req -days 9999 -in server-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out server-crt.pem
  • insert CA Password

Verify server certificate:

openssl verify -CAfile ca-crt.pem server-crt.pem

Client certificate

Generate Client Key:

openssl genrsa -out client1-key.pem 4096

Generate Client certificate signing request:

openssl req -new -key client1-key.pem -out client1-csr.pem
  • Specify client Common Name, like 'client.localhost'. Server should not verify this, since it should not do reverse-dns lookup.
  • For this example, do not insert the challenge password.

Sign certificate using the CA:

openssl x509 -req -days 9999 -in client1-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out client1-crt.pem
  • insert CA Password

Verify client certificate:

openssl verify -CAfile ca-crt.pem client1-crt.pem

Server code

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

const options = { 
    key: fs.readFileSync('server-key.pem'), 
    cert: fs.readFileSync('server-crt.pem'), 
    ca: fs.readFileSync('ca-crt.pem'), 
    requestCert: true, 
    rejectUnauthorized: true
}; 

const server = tls.createServer(options, (socket) => {
    console.log('server connected', 
        socket.authorized ? 'authorized' : 'unauthorized');
    
    socket.on('error', (error) => {
        console.log(error);
    });
    
    socket.write('welcome!\n');
    socket.setEncoding('utf8');
    socket.pipe(process.stdout);
    socket.pipe(socket);
});

server.listen(8000, () => {
    console.log('server bound');
});

Client code

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

const options = {
    ca: fs.readFileSync('ca-crt.pem'),
    key: fs.readFileSync('client1-key.pem'),
    cert: fs.readFileSync('client1-crt.pem'),
    host: 'server.localhost',
    port: 8000,
    rejectUnauthorized:true,
    requestCert:true
};

const socket = tls.connect(options, () => {
    console.log('client connected', 
        socket.authorized ? 'authorized' : 'unauthorized');
    process.stdin.pipe(socket);
    process.stdin.resume();
});

socket.setEncoding('utf8');

socket.on('data', (data) => {
    console.log(data);
});

socket.on('error', (error) => {
    console.log(error);
});

socket.on('end', (data) => {
    console.log('Socket end event');
});

Credits

Forked from Pierantonio Cangianiello's README.md file for Node.js TLS plain TLS sockets, and modified for my implementation purposes.

Original Credits from forked README.md: See the original post by Anders Brownworth.

Thanks to this StackOverflow answer, too (I was using same CN for CA, Server and Client and I got the DEPTH_ZERO_SELF_SIGNED_CERT error).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment