Skip to content
bobby_dreamer

Testing mutual TLS using NodeJS

notes, nodejs, security1 min read

In Mutual TLS both Client and Server have a certificate and both sides authenticate using their public/private key pair. Below are the handshake steps in simplistic way.

  • Client connects to server
  • Server presents its TLS certificate
  • Client verifies the server's certificate
  • Client presents its TLS certificate
  • Server verifies the client's certificate
  • Server grants access
  • Client and server exchange information over encrypted TLS connection

Mutual TLS

Below are the steps and commands


Generate Server Certificate

Server Details

  • Organization Name: Bobby Dreamer Inc.,
  • Organizational Unit Name: Crypto

Generate Certification Authority (CA) certificate for server

  • Password: super
  • Common Name(CN): localhost
1openssl req -new -x509 -days 365 -keyout server-ca-key.pem -out server-ca-crt.pem
2
3# Output
4Generating a RSA private key
5....+++++
6.............................................+++++
7writing new private key to 'server-ca-key.pem'
8Enter PEM pass phrase:
9Verifying - Enter PEM pass phrase:
10-----
11You are about to be asked to enter information that will be incorporated
12into your certificate request.
13What you are about to enter is what is called a Distinguished Name or a DN.
14There are quite a few fields but you can leave some blank
15For some fields there will be a default value,
16If you enter '.', the field will be left blank.
17-----
18Country Name (2 letter code) [AU]:IN
19State or Province Name (full name) [Some-State]:TN
20Locality Name (eg, city) []:Chennai
21Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bobby Dreamer Inc.,
22Organizational Unit Name (eg, section) []:Crypto
23Common Name (e.g. server FQDN or YOUR name) []:localhost
24Email Address []:

Generating a private key

1openssl genrsa -out server-key.pem 4096
2
3# Output
4Generating RSA private key, 4096 bit long modulus (2 primes)
5.............................++++
6..............................++++
7e is 65537 (0x010001)

Generate Certificate Signing Request (CSR)

  • Common Name(CN): server.localhost
  • do not insert the challenge password
1openssl req -new -sha256 -key server-key.pem -out server-csr.pem
2
3# Output
4You are about to be asked to enter information that will be incorporated
5into your certificate request.
6What you are about to enter is what is called a Distinguished Name or a DN.
7There are quite a few fields but you can leave some blank
8For some fields there will be a default value,
9If you enter '.', the field will be left blank.
10-----
11Country Name (2 letter code) [AU]:IN
12State or Province Name (full name) [Some-State]:TN
13Locality Name (eg, city) []:Chennai
14Organization Name (eg, company) [Internet Widgits Pty Ltd]:Bobby Dreamer Inc.,
15Organizational Unit Name (eg, section) []:Crypto
16Common Name (e.g. server FQDN or YOUR name) []:server.localhost
17Email Address []:
18
19Please enter the following 'extra' attributes
20to be sent with your certificate request
21A challenge password []:
22An optional company name []:

Generate the server certificate from CSR

  • Type in the CA Password:super
1openssl x509 -req -days 365 -in server-csr.pem -CA server-ca-crt.pem -CAkey server-ca-key.pem -CAcreateserial -out server-crt.pem
2
3# Output
4Signature ok
5subject=C = IN, ST = TN, L = Chennai, O = "Bobby Dreamer Inc., ", OU = Crypto, CN = server.localhost
6Getting CA Private Key
7Enter pass phrase for server-ca-key.pem:

Verify certificate signature

Using the below command you can verify the certificate signature against the CA

1openssl verify -CAfile server-ca-crt.pem server-crt.pem
2
3# Output
4server-crt.pem: OK

Generate Client Certificate

Client details

  • Organization Name: Browsers Inc.,
  • Organizational Unit Name: Security

Generate Certification Authority (CA) certificate for client

  • Password: client
  • Common Name(CN): browser.com
1openssl req -new -x509 -days 365 -keyout client-ca-key.pem -out client-ca-crt.pem
2
3# Output
4Generating a RSA private key
5......+++++
6............+++++
7writing new private key to 'client-ca-key.pem'
8Enter PEM pass phrase:
9Verifying - Enter PEM pass phrase:
10-----
11You are about to be asked to enter information that will be incorporated
12into your certificate request.
13What you are about to enter is what is called a Distinguished Name or a DN.
14There are quite a few fields but you can leave some blank
15For some fields there will be a default value,
16If you enter '.', the field will be left blank.
17-----
18Country Name (2 letter code) [AU]:IN
19State or Province Name (full name) [Some-State]:TN
20Locality Name (eg, city) []:Chennai
21Organization Name (eg, company) [Internet Widgits Pty Ltd]:Browsers Inc.,
22Organizational Unit Name (eg, section) []:Security
23Common Name (e.g. server FQDN or YOUR name) []:browser.com
24Email Address []:

Generate a private key

1openssl genrsa -out client-key.pem 4096
2
3# Output
4Generating RSA private key, 4096 bit long modulus (2 primes)
5...............................................................................................................................++++
6..............................++++
7e is 65537 (0x010001)

Generate Certificate Signing Request (CSR)

  • Common Name(CN): client.browser.com
  • do not insert the challenge password
1openssl req -new -sha256 -key client-key.pem -out client-csr.pem
2
3# Output
4You are about to be asked to enter information that will be incorporated
5into your certificate request.
6What you are about to enter is what is called a Distinguished Name or a DN.
7There are quite a few fields but you can leave some blank
8For some fields there will be a default value,
9If you enter '.', the field will be left blank.
10-----
11Country Name (2 letter code) [AU]:IN
12State or Province Name (full name) [Some-State]:TN
13Locality Name (eg, city) []:Chennai
14Organization Name (eg, company) [Internet Widgits Pty Ltd]:Browsers Inc.,
15Organizational Unit Name (eg, section) []:Security
16Common Name (e.g. server FQDN or YOUR name) []:client.browser.com
17Email Address []:
18
19Please enter the following 'extra' attributes
20to be sent with your certificate request
21A challenge password []:
22An optional company name []:

Generate client certificate from CSR

  • Type in the CA Password:client
1openssl x509 -req -days 365 -in client-csr.pem -CA client-ca-crt.pem -CAkey client-ca-key.pem -CAcreateserial -out client-crt.pem
2
3# Output
4Signature ok
5subject=C = IN, ST = TN, L = Chennai, O = "Browsers Inc.,", OU = Security, CN = client.browser.com
6Getting CA Private Key
7Enter pass phrase for client-ca-key.pem:

Verify certificate signature

1openssl verify -CAfile client-ca-crt.pem client-crt.pem
2
3# Output
4client-crt.pem: OK

Test

Code is available here in Github

  • Start the server.js script node server.js
  • In another terminal window, start the node client.js

Errors you might get

1D:\BigData\14.Nodejs\17.Certificates\b.client-server_certificate2>node client.js
2TLS Socket ERROR (Error: getaddrinfo ENOTFOUND server.localhost)

Solution

In Windows, go to C:\Windows\System32\drivers\etc

  • Backup the existing hosts file
  • Edit the file and add the below two lines
1127.0.0.1 server.localhost
2127.0.0.1 client.browser.com

It should look like below Mutual TLS

Rerun the client script node client.js

1D:\BigData\14.Nodejs\17.Certificates\b.client-server_certificate2>node client.js
2TLS Connection established successfully!
3Response statusCode: 200
4Response headers: {
5 date: 'Mon, 30 Aug 2021 15:25:24 GMT',
6 connection: 'close',
7 'transfer-encoding': 'chunked'
8}
9Server Host Name: server.localhost
10Received message: OK!
11
12TLS Connection closed!

In the server side, you will get response like below,

1D:\BigData\14.Nodejs\17.Certificates\b.client-server_certificate2>node server.js
2Mon Aug 30 2021 20:55:23 GMT+0530 (India Standard Time) ::ffff:127.0.0.1 GET /

CURL

Tried to connect to server using CURL it did not work. Did not attempt to do any further investigating as it looks like another whole subject to learn.

1curl -k https://127.0.0.1:8888 -v --cacert ./certs/server-ca-crt.pem --key ./certs/client-key.pem --cert ./certs/client-crt.pem
2
3# Output
4* Rebuilt URL to: https://127.0.0.1:8888/
5* Trying 127.0.0.1...
6* TCP_NODELAY set
7* Connected to 127.0.0.1 (127.0.0.1) port 8888 (#0)
8* schannel: SSL/TLS connection with 127.0.0.1 port 8888 (step 1/3)
9* schannel: disabled server certificate revocation checks
10* schannel: verifyhost setting prevents Schannel from comparing the supplied target name with the subject names in server certificates.
11* schannel: using IP address, SNI is not supported by OS.
12* schannel: sending initial handshake data: sending 153 bytes...
13* schannel: sent initial handshake data: sent 153 bytes
14* schannel: SSL/TLS connection with 127.0.0.1 port 8888 (step 2/3)
15* schannel: failed to receive handshake, need more data
16* schannel: SSL/TLS connection with 127.0.0.1 port 8888 (step 2/3)
17* schannel: encrypted data got 1970
18* schannel: encrypted data buffer: offset 1970 length 4096
19* schannel: a client certificate has been requested
20* schannel: SSL/TLS connection with 127.0.0.1 port 8888 (step 2/3)
21* schannel: encrypted data buffer: offset 1970 length 4096
22* schannel: sending next handshake data: sending 100 bytes...
23* schannel: SSL/TLS connection with 127.0.0.1 port 8888 (step 2/3)
24* schannel: encrypted data got 7
25* schannel: encrypted data buffer: offset 7 length 4096
26* schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.
27* Closing connection 0
28* schannel: shutting down SSL/TLS connection with 127.0.0.1 port 8888
29* schannel: clear security context handle
30curl: (35) schannel: next InitializeSecurityContext failed: SEC_E_ILLEGAL_MESSAGE (0x80090326) - This error usually occurs when a fatal SSL/TLS alert is received (e.g. handshake failed). More detail may be available in the Windows System event log.

References