-
Notifications
You must be signed in to change notification settings - Fork 354
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359)) #627
Comments
Same problem on Android 6/7 |
Same with Huawei Android 7 |
Same problem here since the 30th of September for our android 6/7 devices. Is it related to this: internet-disconnect-sept-30? Has this problem a solution without allowing all the certificates on our app requests (because this is a development patch, not a production solution)? |
Definitely related to the expiration of issuer certificate from Digital Signature Trust (DST Root CA X3) which expired on Sept. 30, 2021 (which LetsEncrypt certificates were using as one of the signers on the trust chain). If I'm understanding the situation correctly, Android 7 was before LetsEncrypt had their own Certificate Authority (Internet Security Research Group - ISRG Root X1) that was well accepted and distributed their own CA certificate. So Android 7 doesn't have ISRG_Root_X1.pem certificate in Trusted credentials (Settings > Security > Certificate Management > Trusted credentials). If you check your device, this cert should be missing. We can add User credentials to install that missing ISRG_Root_X1.pem certificate, but Flutter/http.Client won't use that. I guessing one possible solution is to create a custom http client using IOClient from this package & HttpClient from dart:io which can take a SecurityContext which can include a custom trusted certificate authority (i.e. ISRG Root X1). That guess is coming from response from Nate Bosch: |
I just hit this without any Android device involvement. Just one Dart app on Linux talking to another. The workaround I've put in place it to delete the final cert in LetsEncrypt fullchain.pem which is signed by the expired DST Root CA X3. e.g. if I take my original fullchain.pem:
it has 3 certs in it:
That last cert seems to be causing the problem, as it's signed by DST Root CA X3, which expired on 30 Sep 2021. Once it's deleted then Dart uses the ISRG Root CA X1 (self signed) that's in cacerts, and all is happy again. I think (in this case at least) the root cause is a LetsEncrypt/certbot issue - why they're still adding a cert that's been signed by an expired CA is a mystery. Edited to add... Certbot has a flag to deal with this, so Also the reason they're adding the ISRG X1 signed by DST X3 is for compatibility with older Android builds :/ Lessons From An Internet Outage - Issues Caused By Let’s Encrypt DST Root CA X3 Expiration provides a good rundown of the issues at hand. Edited some more... We're using an alternative workaround of removing the expired DST CA Root X3 from our cacerts, and thankfully it seems that Dart is smart enough to walk back up the cert chain to find a root CA that's valid. |
@cpswan Thanks for the detailed post. Does your Android device have the ISRG Root X1 CA certificate installed as a Trusted credential? For my Android 7 test device, the deletion of the DST Root CA X3 from fullchain.pem on my web host only changed the details of the CERTIFICATE_VERIFY_FAILED error from "certificate has expired" to "local certificate not found". Which makes sense if the Android device does not have ISRG Root X1 certificate installed. (Which would be common for Android devices below 7.1.x). I did have some success testing when supplying an ISRG Root X1 certificate & using But, this will only solve https communications that are done with that customized Dart http client. Using Chrome on an Android 7 device (that does not have ISRG Root X1 trusted cert) to visit a domain with a Let's Encrypt SSL certificate with either ISRG Root X1 or DST Root CA X3 will still result in a certificate could not be found or expired error. Let's Encrypt has talked about how Android 7 can ignore the expiration of the DST Root CA X3 expiration in this post, but that's not what I'm seeing on an actual Android 7 device. |
@ben-xx my stuff isn't using Android (though it's a set of services that might have Android clients and we're now braced for any issues croping up with Android 6/7). We've been cut by the other edge of the Letsencrypt compromise by continuing to sign their root CA with the expired DST X3 CA. It's not a panacea for early Android compatibility, and it's causing collateral damage to other apps that are picky about chains of trust. |
I have the same error on flutter windows application. even when using HttpClient from |
I tried solving the problem but still getting the same error. you can check it at this issue . |
@DiaaEddin |
@ben-xx |
@DiaaEddin I wonder if the systems where you're still seeing the issue are using OpenSSL 1.0.2, which will always use the expired trust chain & thus will always fail, as described in this post, in Workaround 3 (which is linked from this LE post). I'm definitely no expert in this, so please take this with a grain (or heap) of salt, but I think one of the solutions to that particular issue is to simply remove the DST Root X3 certificate from the fullchain.pem file from the hosting server's Let's Encrypt SSL cert bundle. Normally there would be three sets of certificates in fullchain.pem, with the third (bottom) one being the DST cert. Doing this (as far as I understand) removes the expired DST cert from the chain so even on systems using OpenSSL 1.0.2, the trust chain is no longer "expired". Maybe? I'm unsure whether you need to also remove the expired DST Root X3 certificate from the hosting OS. For my Linux based servers, I did, just to be safe. (As described here and here.) |
@ben-xx |
BTW, On my server I am using nginxproxy/nginx-proxy docker image to automatically request and update my certificates. do you have any resources on how to implement that server side workaround in this case? |
@ben-xx |
@DiaaEddin So, the only thing I needed to do (client-side) was supply the ISRG Root X1 cert for use by Flutter's HttpClient (since the underlying Android device is old, doesn't get updates & doesn't have that cert). I did not need to remove (i.e. turn off) the DST Root X3 (expired) cert from the Android device's Trusted Credentials list. I did not need to do anything on the nginx-proxy sites. They're still using the Let's Encrypt SSL certs with the expired cross-sign DST cert in their fullchain.pem. I'm assuming this doesn't affect my setup because none of my servers are using openssl version 1.0.2, so the client & server are both able to use the short trust chain of just ISRG Root X1 and they both just ignore the long trust chain which includes the DST Root X3 (expired). |
@ben-xx |
@ben-xx |
i had the same issue on an android 6 device. |
@CritterAlert |
the browsers on the old devices didn't fail, they worked against the same URL. |
@CritterAlert |
BTW, if your are going to use a paid service what certificate issuer would you recommend? |
I've been in the IT profession for 30 years, you don't code your way out of a problem unless you have no control over the environment around you, especially if it can be resolved at the source. Reading one article, one company have 4 apps that started failing on the 30th Sept, the instant solution was to make the problem go away without having open up an application, by going to another SSL provider. This one article i found, they say the same thing.. fix it at the server (in their conclusion), as it was the certificate on the server that was the cause of this issue, to resolve it, resolve it there (which was dump letsencrypt). There is argument of PWA over native apps, if you rollout a change via PWA, everyone gets it on the next reload, you don't with native, there is no guarantee when and if phones will get the updates. I've met users who've run out of space and apps haven't been updated in months (failing due to insufficient space (they fill them with photos and don't update to the cloud and don't delete the device copy)), they're still using the old buggy apps. Resolving on the server is taking the same approach, restart and everyone affected gets the fix. The point is, 3 hours (10,800 seconds) reading and trying what was being recommended and nothing worked.. and i thought.. enough.. under 600 seconds later my problem (letsencrypt) went away. All certificates will expire eventually, some have 2035 on their expiration date. |
cheapsslsecurity offer rapid sll or comodo postive ssl for up to 6 years (with reissues).. no more 90 day refresh (sometimes i need to reboot the server because nginx fails to restart). They start from a few bucks a year if bought for 6 years. Get a trial first and test it (often via the sites directly, not the reseller). You'll find these CA's are likely on the old devices, i read the older devices don't get CA updates, these providers have been around a long time. |
Yes you are absolutely right from business point of view. in production you should opt for the quick fix whenever you can.
Also after checking ZeroSSL they seems to me like a better alternative to letsencypt when using acme client, and they have paid plans so I know how they make their money, this is another reason to consider moving to their service.
I checked cheapsslsecurity, to me their site feels a bit distracting and cheap, I do not feel comfortable buying from them. and their prices are very expensive comparing to ZeroSSL premium plan, especially when buying certificates for multiple domains.
that is why I try to use nginx-proxy/acme-companion whenever I can, the default configurations uses letsencrypt but they have a ZeroSSL page on their wiki. |
I switched my servers away from letsencrypt last night, not just the development server.
From ZeroSSL's website you only have 3 single domain's (sub domain is counted as a single domain issue) per 90 days, if you revoke one it counts as one. It solved my problem pretty much instantly. After a bit of further digging i found their ACME partner scripts allow a lot more directly. Their ZeroSSL Bot ACME script doesn't appear from their reference to give you control over multi domain & it appears to wrap around letsencrypt when i tried it, i couldn't find much on configuring it for ZeroSSL (you'd think out of the box would work), like their website, they don't appear to offer multiple sub domain certificates. I switched to their one of their trusted ACME partner scripts where i can get get multi sub domain per certificate issue: https://github.com/acmesh-official/acme.sh Out of the box it worked. A bit of trial and error, it likes to create everything under ~/.acme.sh/ including certificates. To put certs under a specific location i used: --cert-home /etc/nginx/ssl (had to create an ssl directory) or alternative /etc/ssl
the first listed -d becomes the the directory name under the --cert-home path. The problem is, without spending too much time looking for a solution, you have to stop nginx and restart (like letsencrypt)... then a quick check, 3 issued domains under one certificate. Then i manually modified my nginx conf files to point to:
I kept the original options-ssl-nginx.conf
Checked my browser, 2029 & 2030 appear to be their expiration dates in the full chain, that's breathing space for another 8/9 years. ssllabs test gave an A and flutter app now connects and returns data without an error.
They are cheap, they're a broker for getting them at a fraction of a price rather than going directly and paying full price. I used them for years before i discovered SSL for free. I didn't have the issues I've faced with free. I've had reissues via them when there was a call to do so. never had an issue with cheapsslsecurity, all certificates are issued behind the scenes by the providers they're fronting for, they're all valid. |
Since this thread has taken a turn towards alternatives to LetsEncrypt, my 2¢... The issues I noted above happened in our CI environment where we use vanilla Certbot with LetsEncrypt. Our other environments weren't affected, as we use ZeroSSL in them. In the past we've generated certs on ZeroSSL using Certbot, but it's too slow for our needs, so we've switched to using ZeroSSL's REST API. As I was finding my way around the API I wished there were some examples, which is why I wrote ZeroSSL API – The missing examples. |
Upgrade to latest beta dart\flutter helped. |
Above workaround is not safe for production use. |
it's what i did with zero code change, dump letsencrypt SSL in favour of a paid certificate or free ZeroSSL which i switched to without error. |
Ended up validating the problematic host names manually. If that helps. |
Can you expand a bit onto this? I would appreciate it. |
Hey sorry for the late response, used an answer along these lines: https://stackoverflow.com/a/61120486/8568263 Instead of returning just true, you compare the host parameter to the domain you need or if you many you can put them in a list and test the containment then return true if it fulfills the condition. |
Is there any update on this issue? |
I faced the same error, in my case i was testing my code on localhost, so i just removed https and replaced it with just http which just resolved the error for me.. |
any update on this issue? |
I Used http:// instead of https://. And it worked
Get Outlook for Android<https://aka.ms/AAb9ysg>
…________________________________
From: hussamDana92 ***@***.***>
Sent: Thursday, July 28, 2022 1:53:59 PM
To: dart-lang/http ***@***.***>
Cc: Muhammad Ali Haider ***@***.***>; Comment ***@***.***>
Subject: Re: [dart-lang/http] HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359)) (#627)
any update on this issue?
—
Reply to this email directly, view it on GitHub<#627 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AHIBJJHFTW6DSDLUG4SZRQTVWJDCPANCNFSM5FHWY2VQ>.
You are receiving this because you commented.Message ID: ***@***.***>
|
I am also faced this issue. It's due to ssl certificate. Try to make upgrade or change the ssl certificate from backend side. After ssl changes from backend side its worked for me. |
I am having this problem only on my android devices (8 + 10 + 11) but not on iPhones. |
The simplest solution was to do nothing on the code side (not code work around hacks) and dump letsencrpyt in favour of an another SSL provider, i've been using the free ZeroSSL option since without any issue. My problem instantly went away when i switched SSL vendor, i use the apps and website via the same domain SSL (supports multiple subdomain). |
Any Solution? |
My issue was due to the wifi I was connected to messing with the handshake process, though I'm not exactly sure how. It may have been reporting an incorrect clock time to my OS. If you're seeing this, try a different connection before digging too deep. I was going nuts trying to solve this. |
This helped me in solving it. In my case, disabling VPN worked. |
So to sum it up:
Future<void> loadCerts() async {
final certs = [
'assets/ca/lets-encrypt-r3.pem'
];
for (var cert in certs) {
final certBytes = await PlatformAssetBundle().load(cert);
SecurityContext.defaultContext.setTrustedCertificatesBytes(certBytes.buffer.asUint8List());
}
}
class MyHttpOverrides extends HttpOverrides {
@override
HttpClient createHttpClient(SecurityContext context) {
return super.createHttpClient(context)
..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
}
} |
Please try the below final ioc = new HttpClient(); |
|
It adds the |
HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:359))
I have 4 apps live on Google Play Store from last few months , yesterday all stopped working because of above error.
I did not understand the cause of above error and no solution found til now.
Could anybody suggest. I am using http: ^0.13.3 in my one of the app , It comes in http.post method.
The text was updated successfully, but these errors were encountered: