From 10c52fe0efc6a7a4614997c694bbadcfc36d62eb Mon Sep 17 00:00:00 2001 From: Hinrich Harms Date: Wed, 9 Oct 2024 18:10:02 +0200 Subject: [PATCH 1/3] Create additional files that include only certificates with strong digest algorithms This prevents the "CA signature digest algorithm too weak" error thrown when trying to import certificates using SHA1WithRSA on newer environments --- README.md | 37 ++++++++++++++++++++++++------------- index.js | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index eb360b8..f06a643 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,9 @@ If you are trying to connect to a secure website via nodejs. Although, the site may work in the browser, you may run into errors such as -[CERT_UNTRUSTED](https://stackoverflow.com/questions/41390965/cert-untrusted-error-when-execute-https-request) - -[UNABLE_TO_VERIFY_LEAF_SIGNATURE](https://stackoverflow.com/questions/20082893/unable-to-verify-leaf-signature) - -[Unable to verify the first certificate](https://stackoverflow.com/questions/31673587/error-unable-to-verify-the-first-certificate-in-nodejs) +* [CERT_UNTRUSTED](https://stackoverflow.com/questions/41390965/cert-untrusted-error-when-execute-https-request) +* [UNABLE_TO_VERIFY_LEAF_SIGNATURE](https://stackoverflow.com/questions/20082893/unable-to-verify-leaf-signature) +* [Unable to verify the first certificate](https://stackoverflow.com/questions/31673587/error-unable-to-verify-the-first-certificate-in-nodejs) It may be due to a couple of reasons. The Root CA certificate is missing in nodejs @@ -14,6 +12,12 @@ Or the site does not correctly install the intermediate certificates. Typically you encounter these at the last minute, and usually, the server is not in your control; hence you cannot modify the certificate installation, and it is challenging to change code at that time. +Another possible error might be due to newer environments throwing an exception if certificates using a weak digest (SHA1WithRSA) are used: + +* [CA signature digest algorithm too weak](https://serverfault.com/questions/1143995/tls-1-0-broken-with-newer-debian-openssl) + +Instead of lowering the SECLEVEL from 1 to 0, there are also files generated that exclude certificates that use this weak digest. + ### Node js added an Environment variable to address this issue: ### [NODE_EXTRA_CA_CERTS](https://nodejs.org/api/cli.html#cli_node_extra_ca_certs_file) @@ -29,10 +33,17 @@ However, it is cumbersome to create the PEM file for missing certificates manual * https://wiki.mozilla.org/CA/Included_Certificates * https://wiki.mozilla.org/CA/Intermediate_Certificates -It generates three different bundles that can be used based on your needs: -* Intermediate certificates only bundle `ca_intermediate_bundle.pem` -* Root only certificates bundle `ca_root_bundle.pem` -* Intermediate and Root certificates bundle `ca_intermediate_root_bundle.pem` +It generates six different bundles that can be used based on your needs: + +#### All intermediate/root certificates +* Intermediate certificates only bundle: `ca_intermediate_bundle.pem` +* Root only certificates bundle: `ca_root_bundle.pem` +* Intermediate and Root certificates bundle: `ca_intermediate_root_bundle.pem` + +#### Only intermediate/root certificates with strong digests +* Intermediate certificates only bundle (no weak digests): `ca_intermediate_bundle.pem` +* Root only certificates bundle (no weak digests): `ca_root_bundle.pem` +* Intermediate and Root certificates bundle (no weak digests): `ca_intermediate_root_bundle.pem` You can use any of the above bundles with NODE_EXTRA_CA_CERTS. @@ -45,12 +56,12 @@ During the installation of the module, it downloads the latest certificates from You can launch your script while using the above certificates using: ``` -NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js +NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_root_bundle.pem node your_script.js ``` for Windows use: ``` -npx cross-env NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js +npx cross-env NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_root_bundle.pem node your_script.js ``` ### To use the PEM file in code @@ -58,7 +69,7 @@ This is useful when you want to run as root or listen on privilege port like 80. ``` const fs = require('fs'); const https = require('https'); -https.globalAgent.options.ca = fs.readFileSync('node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem'); +https.globalAgent.options.ca = fs.readFileSync('node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_root_bundle.pem'); ``` ### To include your custom PEM certificates in code along with this file @@ -67,6 +78,6 @@ If you want to include your custom certificate and still want to connect to othe ``` const fs = require('fs'); const https = require('https'); -https.globalAgent.options.ca = yourCertificatePEMcontent + fs.readFileSync('node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem'); +https.globalAgent.options.ca = yourCertificatePEMcontent + fs.readFileSync('node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_root_bundle.pem'); ``` diff --git a/index.js b/index.js index c1f0374..8cf7d05 100644 --- a/index.js +++ b/index.js @@ -2,9 +2,11 @@ const csvtojson = require('csvtojson'); const fs = require('fs'); const request = require('axios'); +// Create new files without certificates using weak hash algorithms, as this causes an +// exception on newer environments (CA signature digest algorithm too weak). +const weakHashList = [ 'SHA1WithRSA' ]; - -async function appendPEMFromUrl(url, individualFiles=false) { +async function appendPEMFromUrl(url, individualFiles=false, skipWeakHash=false) { console.log(`Downloading from URL ${url}`); const response = await request.get(url, { responseType: 'blob'}); console.log('Parsing csv file'); @@ -16,7 +18,13 @@ async function appendPEMFromUrl(url, individualFiles=false) { let certPem = entry['PEM Info'].slice(1, -1); const commonName = entry['Common Name or Certificate Name'] || entry['Certificate Subject Common Name']; const serialNumber = entry['Certificate Serial Number']; - const issuerOrg = entry['Certificate Issuer Organization'] + const issuerOrg = entry['Certificate Issuer Organization']; + const signatureHashAlgorithm = entry['Signature Hash Algorithm']; + + if (skipWeakHash && weakHashList.includes(signatureHashAlgorithm)) { + // Certificate uses a weak hash, skip + continue; + } // Remove empty lines in certPem some certificates were coming with blank line e.g. // Shopper SSL @@ -58,15 +66,33 @@ async function build() { fs.writeFileSync('ca_bundle/ca_root_bundle.pem', ca_root_bundle); fs.writeFileSync('ca_bundle/ca_intermediate_root_bundle.pem', ca_intermediate_bundle + ca_root_bundle); + // Add intermediate certificates, strong hashes only: + const ca_strong_intermediate_bundle = await appendPEMFromUrl('https://ccadb-public.secure.force.com/mozilla/PublicAllIntermediateCertsWithPEMCSV', false, true); + + // Add root certificates, strong hashes only: + const ca_strong_root_bundle = await appendPEMFromUrl('https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV', false, true); + + fs.writeFileSync('ca_bundle/ca_strong_intermediate_bundle.pem', ca_strong_intermediate_bundle); + fs.writeFileSync('ca_bundle/ca_strong_root_bundle.pem', ca_strong_root_bundle); + fs.writeFileSync('ca_bundle/ca_strong_intermediate_root_bundle.pem', ca_strong_intermediate_bundle + ca_strong_root_bundle); + + + console.log(); console.log('Intermediate and Root Certificate Bundles from Mozilla generated'); console.log('----------------------------------------------------------------'); + console.log('All certificates:') console.log('Intermediate certificates only bundle at ca_bundle/ca_intermediate_bundle.pem'); console.log('Root only certificates bundle at ca_bundle/ca_root_bundle.pem'); console.log('Intermediate and Root certificates bundle at ca_bundle/ca_intermediate_root_bundle.pem'); console.log(); - console.log('To run your Node script with the bundled certificate run:') - console.log('NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_intermediate_root_bundle.pem node your_script.js\n'); + console.log('Only certificates not using a weak signature digest algorithm:') + console.log('Intermediate certificates only bundle at ca_bundle/ca_strong_intermediate_bundle.pem'); + console.log('Root only certificates bundle at ca_bundle/ca_strong_root_bundle.pem'); + console.log('Intermediate and Root certificates bundle at ca_bundle/ca_strong_intermediate_root_bundle.pem'); + console.log(); + console.log('To run your Node script with the bundled strong intermediate certificates run:') + console.log('NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_bundle.pem node your_script.js\n'); } build(); \ No newline at end of file From 06dc5999412de7d35827dc13ce5db3b06e25b195 Mon Sep 17 00:00:00 2001 From: Hinrich Harms Date: Wed, 9 Oct 2024 18:12:12 +0200 Subject: [PATCH 2/3] Update package version to 1.0.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 974b09b..ab41706 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "node_extra_ca_certs_mozilla_bundle", - "version": "1.0.6", + "version": "1.0.7", "description": "", "main": "index.js", "scripts": { From 00e14ac0eea94dbe8e0303ef7f232c033fb68fdb Mon Sep 17 00:00:00 2001 From: xiic Date: Wed, 25 Jun 2025 12:39:18 +0200 Subject: [PATCH 3/3] Update certificate URLs (strong hashes only) --- index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index 8846f9b..0a06025 100644 --- a/index.js +++ b/index.js @@ -67,10 +67,10 @@ async function build() { fs.writeFileSync('ca_bundle/ca_intermediate_root_bundle.pem', ca_intermediate_bundle + ca_root_bundle); // Add intermediate certificates, strong hashes only: - const ca_strong_intermediate_bundle = await appendPEMFromUrl('https://ccadb-public.secure.force.com/mozilla/PublicAllIntermediateCertsWithPEMCSV', false, true); + const ca_strong_intermediate_bundle = await appendPEMFromUrl('https://ccadb.my.salesforce-sites.com/mozilla/PublicAllIntermediateCertsWithPEMCSV', false, true); // Add root certificates, strong hashes only: - const ca_strong_root_bundle = await appendPEMFromUrl('https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV', false, true); + const ca_strong_root_bundle = await appendPEMFromUrl('https://ccadb.my.salesforce-sites.com/mozilla/IncludedCACertificateReportPEMCSV', false, true); fs.writeFileSync('ca_bundle/ca_strong_intermediate_bundle.pem', ca_strong_intermediate_bundle); fs.writeFileSync('ca_bundle/ca_strong_root_bundle.pem', ca_strong_root_bundle); @@ -95,4 +95,4 @@ async function build() { console.log('NODE_EXTRA_CA_CERTS=node_modules/node_extra_ca_certs_mozilla_bundle/ca_bundle/ca_strong_intermediate_bundle.pem node your_script.js\n'); } -build(); \ No newline at end of file +build();