How to Resolve Certificate Errors in a Node.js App with SSL Calls

Sunny Sun lol
A practical guide to resolving SSL certificate errors

In a non-production environment, setting up a NodeJS App with HTTPS and a Server Certificate is relatively straightforward. In a production environment, if your Node/Express App sits behind a reverse proxy like Nginx which serves certificates, and it does not need to call other external services, then HTTPS and a Server Certificate are not required.

However, in reality, your Node app will need to call various back-end services protected by HTTPS. By default, NodeJs is built with a bundle of commonly used CA root certificates . Even with these certificates, we still may be bashed with HTTPS-related errors if your back-end services are hosted with self-signed certificates (i.e. company-specific private CA).

Some of these errors include:

UNABLE_TO_GET_ISSUER_CERT_LOCALLY
UNABLE_TO_VERIFY_LEAF_SIGNATURE
DEPTH_ZERO_SELF_SIGNED_CERT

We need to understand these errors before they can be resolved.

Let’s dive deep into these errors.

SSL Handshake

These errors originate from the SSL handshake process. When a client begins to establish a connection to the server, a TLS handshake happens. It is a series of messages exchanged between the client and server. In these messages, they agree with the version of the TLS and cipher suites to use, verify the identity of the server, and generate the session keys.

In step 2 of the above diagram, the server sends a message containing the server’s SSL certificate. Then the client verifies the certificate with the CA (Certificate authority) that issued it. This step confirms that the server is who it says it is, and the client is interacting with the actual owner of the domain.

The above SSL errors are thrown because the client is not able to verify the trust chain of the self-signed server certificate sent in step 2.

TLS handshake is a complex process, you may like to read the article below for more details.
Deep Dive Into TLS Handshake
TLS 1.2 Handshake process explained step by steplevelup.gitconnected.com

Quick and Dirty Fix: rejectUnauthorized

The easiest solution to resolve these errors is to use the “rejectUnauthorized” option as below.

https.request({ 
      ....,
      rejectUnauthorized: false,
    },
...)

or set it as an environment variable

NODE_TLS_REJECT_UNAUTHORIZED=0

However, this method is unsafe because it disables the server certificate verification, making the Node app open to MITM attack. Thus, it is strongly recommended only to disable certificate verification in a development environment, and never apply this approach in production.

Use CA Option

A safer way is to specify the CA certificate that is expected from the server. In other words, the common name of the certificate needs to match the server certificate.

request({ 
   ca: [fs.readFileSync([certificate path])],
   rejectUnauthorized: true,
}

As you can see, the ca option is an array, thus you can set multiple certificate files if required. Hardcoding the certificate files in the code can make it difficult to update or rotate the certificates as needed. To avoid these issues, consider using a configuration management tool to handle the installation and updates of certificates.

NODE_EXTRA_CA_CERTS

From Node version 7.3.0, NODE_EXTRA_CA_CERTS environment variable is introduced to specify the location of any additional certificate authority (CA) certificates that are needed. This allows the “root” CAs to be extended with the extra certificates in the file. The file should consist of one or more trusted certificates in **PEM **format.

To use the NODE_EXTRA_CA_CERTS environment variable, you can specify the path to the certificate file when starting your Node.js app. For example, you could use the following command :

NODE_EXTRA_CA_CERTS=path/to/ca/certificates.pem node app.js

This command sets the NODE_EXTRA_CA_CERTS variable and then starts the app.js Node.js app. The Node.js app will then use the CA certificates when making SSL calls, which will help to resolve the certificate errors.

Please note that the extra certificates won’t be effective if the ca options property is explicitly specified for an HTTPS client or server.

How to troubleshoot?

If you have used either the ca option or the NODE_EXTRA_CA_CERTS, but still, receive the same errors. It is normally caused by the incorrect certificate being used.

Firstly, let’s check the certificate chain to make sure that all of the necessary intermediate certificates are included in the certificate chain. The certificate chain should include the server certificate, the intermediate CA certificate, and the root CA certificate.

For the ca option or the extra certs to work, we need to get the full CA Chain or at least the Root CA certificate.

You can use OpenSSL to retrieve the Full CA Chain as follows:

openssl s_client -connect ${REMHOST}:${REMPORT}

An example of the certificate chain is shown below.

Google CA Certificate ChainGoogle CA Certificate Chain

Please note that the *showcerts *command may not work if the command is executed behind a proxy or the remote server uses SNI .

If the error still persists, below are other things to check

  • Check the certificate path to ensure the certificate path is correct and readable by the app.

  • Verify the certificate is in the correct format (normally PEM or DER). You can use openssl command to convert the certificate to the required format.

Summary

In this article, We discuss how to resolve the certificate errors in NodeJs App in detail. If you still can’t fix the error after trying everything, then StackOverflow is your best friend :).

If you are not already a paid Medium member, **you can do so by visiting this link **. You’ll get unlimited full access to every story on Medium. I’ll receive a portion of your membership fees as a referral.

Thanks for reading, and happy programming!