electron: [Bug]: Let's Encrypt root CA isn't working properly

Preflight Checklist

Electron Version

15.0.0 Reproduced on Electron 12, 13, 14

What operating system are you using?

Other Linux

Operating System Version

Arch Linux rolling

What arch are you using?

x64

Last Known Working Electron version

No response

Expected Behavior

The request to https://letsencrypt.org (or any Let’s Encrypt secured website) should work in the main process as the certificate chain seems valid.

Actual Behavior

It doesn’t work in the main process. However, it works in the renderer (with standard Fetch API) or in Node 16.5 REPL (also with Axios).

Testcase Gist URL

https://gist.github.com/fc9cc8d91df7d02f211698f9aceb0087

Additional Information

I think it’s probably related to the recent expiry of DST Root CA X3 but strangely enough, it’s working properly on the renderer and in a single Node app?

My understanding is that by default, Node.js uses a capture of the Mozilla trust CA, could it be that the Electron one is unsynced?

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 63
  • Comments: 58 (5 by maintainers)

Commits related to this issue

Most upvoted comments

We (Postman.com) have a potential fix. Running some further tests and sending a PR if it all goes fine.

Follow up on my prior message, the proposed approach there has worked properly with two modifications: removing the = in the --preferred-chain argument and doing a hard restart of nginx (rather than a reload) to force the new certificate live (I don’t know why reload did not work in this case).

sudo certbot certonly --nginx -d <domain> --preferred-chain "ISRG Root X1"
sudo service nginx restart

Hope this solution helps others to obtain a valid shortened certificate chain until the long term issue is resolved at the Electron level.

Well, this is a particularly disastrous bug. Certificate chain is completely valid by every metric and using every client… except Electron. Problem is the same in 16.0.0-alpha.2 even. Node client is fine, all browsers we’ve tried on Windows and Mac, OpenSSL, every SSL checker I’ve run it through reports all is healthy and good across the certificate chain. All certificates freshly re-generated.

We’re pretty much dead in the water at the moment.

Although this has been closed, we still need to backport the original PR to ~5 branches and ship 5 new releases (12, 13, 14, 15, 16). You can monitor those as we kick them off at https://releases.electronjs.org

They should be out (if nothing goes wrong) in ~3 hours.

If u use axios for requests temporary workaround might be just to disable SSL temporary, works fine for us as a temporary solution until fix

const agent = new https.Agent({
  rejectUnauthorized: false,
});

axios.defaults.httpsAgent = agent;

P.S. same problem with certs on electron@11.4.3 UPD also problem with another app on electron@8.2.5 cert 100% valid & also reproduces with https://letsencrypt.org

@popod Basically all LE certs have the following chain:

Website (cert that you use on your server) --> R3 (the main cert LE uses) --> ISRG Root X1 (the new and valid root) --> DST Root CA X3 (the old one that expired).

The DST root is still in the chain because of backwards compatibility (since certificates need to be provided to a device with an update, which old devices don’t get anymore).

There is a flag in OpenSSL called X509_V_FLAG_TRUSTED_FIRST. If that flag is not set, OpenSSL will follow the full chain and attempt to verify every certificate in the chain. It will encounter the DST root and detect (correctly) that it’s not valid anymore. If the flag is set, however, this instructs OpenSSL to stop checking once it encounters a correct and valid root cert.

This flag is set on most implementations, but for Electron it has been missed. The linked PR that includes the fix simply sets this flag.

I solved the problem by buying a $15 certificate after two and a half hours of fruitless searching. Users of my application have been blocked for too long… Now i can wait one year for a fix !

Not only Electron is affected.

Here is a dirty workaround for Node apps which stopped getting correct response from servers with buggy Let’s Encrypt certificates:

process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

add it before any network request to such servers.

I place this here due to this thread is in the top of Google search results by “nodejs letsencrypt” keywords.

FYI If you’re using Caddy the following worked for me:

domain.com {
    reverse_proxy localhost:3000
    tls {
        issuer acme {
            preferred_chains {
                root_common_name "ISRG Root X1"
            }
        }
    }
}

I had to remove my current certificates, and restart caddy.

As suggested here, removing the last certificate present in fullchain and reloading/restarting the webserver seems to work as a quick’n’dirty fix. Tested on Apache and Nginx.

For those who still have the problem.

We were using the fullchain.cer containing the certificate, the R3 and the new ISRG Root X1

We just removed the X1 from the fullchain.cer and like pure magic electron is back on again 😃

Hope it helps

Hello, I’m experiencing the exact same problem. This seems to be an urgent issue.

Please don’t suggest process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; without explaining that it will completely disable TLS certificate validation. This means that any TLS connection you make is insecure, which may be fine only in very specific circumstances. (Many people will just copy whatever workaround they find mentioned in the comments without finding out what the implications are.)

Hi,

Exact same problem since the DST Root CA X3 expiration today.

For those that have this problem and control of the server, you might want to change to your certificate for one that is still valid. If your acme client allows you to change CA, you can try ZeroSSL ACME Certs to replace your current LetsEncrypt. Since ZeroSSL signing certificate has not changed, it might work where your current LetsEncrypt one won’t (Note that I did not test this).

You can skip it with process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; (not recommended but perhaps temporary)

This is what worked for me:

  • sudo apt purge certbot python3-certbot-nginx
  • comment out all certificate lines in the nginx conf files of your websites
  • sudo nginx -t
  • sudo service nginx restart && sudo service nginx status

Then you need to install the dreadful snap and certbot, and then generate a new certificate with the preferred-chain option, which is only available on the new versions of certbot

sudo apt install snap
sudo snap install core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx --preferred-chain "ISRG Root X1"

Now electron understands letsencrypt certificates.

Here is the official Let’s Encrypt statement: https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/

I tried using this solution…

Follow up on my prior message, the proposed approach there has worked properly with two modifications: removing the = in the --preferred-chain argument and doing a hard restart of nginx (rather than a reload) to force the new certificate live (I don’t know why reload did not work in this case).

sudo certbot certonly --nginx -d <domain> --preferred-chain "ISRG Root X1"
sudo service nginx restart

Hope this solution helps others to obtain a valid shortened certificate chain until the long term issue is resolved at the Electron level.

… but my version of certbot (0.31.0) does not support the --preferred-chain option. Since I am running debian 10, 0.31.0 is the latest version.

  1. update the certbot to the last version using snap (certbot instructions)
$ sudo snap install core
$ sudo snap refresh core
$ sudo apt-get remove certbot
$ sudo snap install --classic certbot
$ sudo ln -s /snap/bin/certbot /usr/bin/certbot
  1. renew & replace the certificate
certbot certonly --apache -d www.yourdomain.com --preferred-chain "ISRG Root X1"
service apache2 reload

Here is the official Let’s Encrypt statement: https://letsencrypt.org/docs/dst-root-ca-x3-expiration-september-2021/

I tried using this solution…

Follow up on my prior message, the proposed approach there has worked properly with two modifications: removing the = in the --preferred-chain argument and doing a hard restart of nginx (rather than a reload) to force the new certificate live (I don’t know why reload did not work in this case).

sudo certbot certonly --nginx -d <domain> --preferred-chain "ISRG Root X1"
sudo service nginx restart

Hope this solution helps others to obtain a valid shortened certificate chain until the long term issue is resolved at the Electron level.

… but my version of certbot (0.31.0) does not support the --preferred-chain option. Since I am running debian 10, 0.31.0 is the latest version.

@s-a : electron 15.1.2 works for me. Did you try to remove node_modules dir and npm install? @TitanRob16 : you’ll need to install the newest certbot version on your system. But beware: when you use this workaround (or the other one just deleting the last cert in the keychain.pem) older android devices and operating systems will instead have a certificate error!

IMHO the best solution is using temporarly trustSSL (they have also a free 30 day cert, with quick email validation), fix the electron app and return to let’s encrypt. HTH

Thank you for this fix!

As @guldil and to fix the problem as soon as possible for our users, we’ve bought another certificate and this fix this cert validation error! We will release an update of our application in a near future to completely get rid of this.

But could someone explain to me why a Let’s Encrypt certificate which seems to be valid and works when accessed from a browser is not trusted with electron ? (why electron was not ready for that planned expiration? Is this a bug in electron or does electron using an older version of OpenSSL which seems to have a bug with certificate validation? or else… ?)

I know that perhaps this is not the good place to ask for explanations, but I think that this could be useful for others.

Thanks in advance for the explanations!

@datacosmos Yes, but nevertheless you are right! I am stupid. Thanks for confirmation 😅

btw I reinstalled all certs with chain forced to X1, cleared cache and reset ssl statement but it’s the same…

Follow up on my prior message, the proposed approach there has worked properly with two modifications: removing the = in the --preferred-chain argument and doing a hard restart of nginx (rather than a reload) to force the new certificate live (I don’t know why reload did not work in this case).

sudo certbot certonly --nginx -d <domain> --preferred-chain "ISRG Root X1"
sudo service nginx restart

Hope this solution helps others to obtain a valid shortened certificate chain until the long term issue is resolved at the Electron level.

If you are using the acme.sh client like I am, it also supports the preferred chain option in recent versions, see here for how to set it up: https://github.com/acmesh-official/acme.sh/wiki/Preferred-Chain

Setting “ISRG Root X1” as the preferred chain and restarting nginx allowed the Atom editor to connect to my service again.

Here is the PR: https://github.com/electron/electron/pull/31213. It seems to work fine for us but if you could also give it a spin, that would be great!