Skip to content

Instantly share code, notes, and snippets.

@hellc2
Forked from pcan/README.md
Last active June 26, 2019 16:01
Show Gist options
  • Save hellc2/e627dd19653bd3fcb82a4c3fed99f6f1 to your computer and use it in GitHub Desktop.
Save hellc2/e627dd19653bd3fcb82a4c3fed99f6f1 to your computer and use it in GitHub Desktop.
Node.js plain TLS Client & Server, 2-way Cert Auth

Node.js TLS plain TLS sockets

This guide shows how to set up a bidirectional client/server authentication for plain TLS sockets.

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');
});

PEM (.pem, .crt, .cer) to PFX

openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt -certfile more.crt

Breaking down the command:

openssl – the command for executing OpenSSL
pkcs12 – the file utility for PKCS#12 files in OpenSSL
-export -out certificate.pfx – export and save the PFX file as certificate.pfx
-inkey privateKey.key – use the private key file privateKey.key as the private key to combine with the certificate.
-in certificate.crt – use certificate.crt as the certificate the private key will be combined with.
-certfile more.crt – This is optional, this is if you have any additional certificates you would like to include in the PFX file.

Credits

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