Error: unable to verify the first certificate in nodejs

In this tutorial, we will see how to fix the Error: unable to verify the first certificate in nodejs.

I’m trying to download a file from a Jira server using a URL in my NodeJS application, but I’m running into a problem.

The error message I’m getting is:

Error: unable to verify the first certificate in nodejs

at Error (native)
    at TLSSocket.<anonymous> (_tls_wrap.js:929:36)
   
  at TLSSocket.emit (events.js:104:17)

at TLSSocket._finishInit (_tls_wrap.js:460:8)

When this error occurs

When you connect to a web server and encounter the “unable to verify the first certificate” error, it implies that the server’s certificate chain is incomplete. This usually happens because the server is not configured correctly and fails to include the intermediate certificate in the chain sent to your application.

Certificate Chain Explained

  • Server Certificate: This holds a certificate signed by an intermediate authority.
  • Intermediate Certificate: This certificate is signed by the root authority.
  • Root Certificate: This is a self-signed certificate at the top of the certificate hierarchy.

For a successful SSL/TLS connection, the server should install both the server and intermediate certificates. Root certificates are generally embedded in software applications, browsers, and operating systems. The application serving the certificate must send the complete chain, which includes the server certificate and all intermediates. The root certificate is usually known by the client.

Now, here are the approaches below to fix the issue.

Complete the Certificate Chain

You need to complete the certificate chain yourself. You can do that by following the steps below.

Get the Missing Intermediate Certificate

Now follow the steps below to get the missing intermediate certificate.

Retrieve the Server’s Certificate Details

Use OpenSSL to save the server’s certificate details and identify the issuer (intermediate certificate).

Ensure you have OpenSSL installed (available with Git for Windows).

openssl s_client -connect incomplete-chain.badssl.com:443 -servername incomplete-chain.badssl.com | tee logcertfile

Identify the issuer of the server certificate

The issuer of the server certificate is typically the intermediate certificate.

To find it, run the below command.

openssl x509 -in logcertfile -noout -text | grep -i "issuer"

This command will display the issuer’s details, including the URL of the intermediate certificate.

Download the Intermediate Certificate

Use the URL obtained in the previous step to download the intermediate certificate.

curl --output intermediate.crt http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

Convert the Certificate to .pem Format

Finally, convert the downloaded certificate to the .pem format using the below command.

openssl x509 -inform DER -in intermediate.crt -out intermediate.pem -text

Follow these steps to successfully retrieve and prepare the intermediate certificate for use in your applications.

Extend Node’s Certificate Store

Use NODE_EXTRA_CA_CERTS to include the intermediate certificate in Node’s certificate store.

This can be set in your environment or in the package.json file.

"start": "cross-env NODE_EXTRA_CA_CERTS=\"path_to_intermediate.pem\" node index.js"

Use the ca Option

Overwrite Node’s built-in root CAs with your own certificate bundle. This requires using a module like ssl-root-cas to create a custom HTTPS agent configured with your certificate bundle.

You can then use this agent in your Axios requests.

const axios = require('axios');
const https = require('https');
const rootCas = require('ssl-root-cas').create();

rootCas.addFile('path_to_intermediate.pem');
const httpsAgent = new https.Agent({ ca: rootCas });

axios.get('https://incomplete-chain.badssl.com', { httpsAgent })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });

Alternatively, you can configure the HTTPS global agent to use this certificate bundle for all requests.

Add the certificate to your NodeJS application

Obtain the SSL certificate from the Jira server.

In your NodeJS application, you can use the https module and include the certificate in the options.

Here is an example of how you might do it:

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

const options = {
  hostname: 'your.jira.server',
  port: 443,
  path: '/path/to/resource',
  method: 'GET',
  ca: fs.readFileSync('path/to/certificate.crt') // Load the certificate
};

const req = https.request(options, (res) => {
  console.log('statusCode:', res.statusCode);
  console.log('headers:', res.headers);

  res.on('data', (d) => {
    process.stdout.write(d);
  });
});

req.on('error', (e) => {
  console.error(e);
});

req.end();

Use a custom agent with the request module

If you are using the request module, you can use a custom agent to include the SSL certificate.

Example

const request = require('request');
const fs = require('fs');
const https = require('https');

const agentOptions = {
  ca: fs.readFileSync('path/to/certificate.crt')
};

const agent = new https.Agent(agentOptions);

request({
  url: 'https://your.jira.server/path/to/resource',
  agent: agent
}, (error, response, body) => {
  if (error) {
    console.error('Error:', error);
  } else {
    console.log('Body:', body);
  }
});

Disable SSL validation (Not Recommended)

As a last resort, and only for development or if you are sure about the security implications, you can disable SSL/TLS certificate validation by setting the NODE_TLS_REJECT_UNAUTHORIZED environment variable to 0. However, this is generally not recommended as it makes your application vulnerable to MITM (Man-In-The-Middle) attacks.

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

Use this approach with caution and only if you understand the risks involved.

Remember, always ensure that your application is secure, especially when dealing with SSL/TLS and certificates. Disabling SSL certificate validation or using self-signed certificates should only be done in controlled environments where security is not a concern, like local testing.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top