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 a572181..0a06025 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.my.salesforce-sites.com/mozilla/PublicAllIntermediateCertsWithPEMCSV', false, true); + + // Add root certificates, strong hashes only: + 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); + 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 +build();