Closed Sirfanas closed 4 years ago
Have you tried adding certifi
to your requirements?
Yes it's in the requirements list in buildozer's config
Oh yes I overlooked that then I don't know. I know it's not the first time I saw such report, I would be looking into the existing report see if it help https://github.com/search?q=org%3Akivy+CERTIFICATE_VERIFY_FAILED&type=Issues
Yeah I already look all report on kivy, buildozer and python for Android, of course on Google but problems comes from compilation (not my case as it build without problem) or people give the bypass ssl verification, but I "can't" do it cause I don't want to do it everytime I use something calling an URL with HTTPs, and I'll have to use it frequently So if there's no way I will do it but if there's a better solution I would take it I'm okay to bypass ssl verification but I'd like it global and not do it everytime Thank's
Well it's a pretty unsatisfying (and risky) solution to me, but yes you could try to put it to your top level __init__.py
so you don't have to call it every time.
Also could you please share the output of he following command:
find .buildozer/ -name "certifi*"
Hi, So I try to put this ugly monster in my top level init but it didn't fix the problem...
So I execute the command and here is the output:
user@f2b3ca0a45cf:~/hostcwd$ find .buildozer/ -name "certifi*"
.buildozer/android/platform/build/dists/kydoo/_python_bundle/_python_bundle/site-packages/certifi
.buildozer/android/platform/build/dists/kydoo/_python_bundle/_python_bundle/site-packages/certifi-2019.3.9.dist-info
.buildozer/android/platform/build/build/python-installs/kydoo/certifi
.buildozer/android/platform/build/build/python-installs/kydoo/certifi-2019.3.9.dist-info
.buildozer/android/platform/build/build/venv/lib/python3.6/site-packages/pip/_vendor/certifi
.buildozer/android/platform/build/build/other_builds/openssl/armeabi-v7a__ndk_target_21/openssl1.1/doc/HOWTO/certificates.txt
Hope it will help you !
Oh so you're running in the "official" Docker image are you? That may help reproducing the issue eventually.
Also I see something weird, on the buildozer.spec
you shared we have package.name = myapp
which seems to be different from what I see here in the paths kydoo
.
Maybe it's worth cleaning/rebuilding via a rm -rf .buildozer/
.
Then other things to consider to help with debugging. Make the simplest reproduction case possible, e.g. see if it's also failing using the requests library:
import requests
response = requests.get('https://i.goopics.net/27Odx.png')
print(response.status_code)
So the idea here is to see if the problem comes from the way it's implemented in Kivy.
Then I would also try with a most known domain such as google.com. Here it's too see if it fails with authority, google.com is signed by Google Internet Authority which is signed by GlobalSign Root CA. And goopics.net is Let's Encrypt Authority which is signed by Builtin Object Token.
If both test fail, then we would have to dig a bit deeper and see how is requests interacting with certifi. The idea would be to see at which point the code execution take different branches on your device where it's not working vs on your laptop. One thing I can think of is the certifi/cacert.pem
couldn't not be found on device somehow.
Hi, I make a really simple test: I get the content of https://www.google.com/ Then I try to open an Image (https://media.makeameme.org/created/its-working-oyy433.jpg) with Async image Works perfectly on computer, still have SSL issues on Android Here is the code: https://github.com/Sirfanas/kivy-ssl
Maybe it can be easier for you to find the problem with that ?
Thank's !
I am having the exact same problem. I'm using Linux (Ubuntu 18.04) for development and compilation, and the app works perfectly fine in the normal environment, however when run from a mobile phone, the CA bundle cannot be found.
Adding certifi to the requirements list was the first thing I tried, however it had no effect.
I was able to solve the issue for normal UrlRequest by adding the "ca_file" parameter and actually forcing the "certifi.where()" bundle to be added there, and it worked nicely: https://stackoverflow.com/questions/55816099/kivy-urlrequest-with-https
Unfortunately, "AsyncImage" doesn't have a similar "ca_file" option (or is there such a mechanism available?) and requests fail with the same error:
python : urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1051)>
Being unable to use HTTPS properly in Python3 has been the main reason for me not using Kivy seriously until now, and with the latest changes which finally made it a first-class citizen (deprecating Crystax), I was looking forward to picking this up again... Is there any way we can fix this, other than disabling CA validation which is not really an option?
Hi,
I finally fix it ! The think is that putting certifi requirements did install it, but don't make usage of it. So we have to manually precise to Python we want it to use the certifi CA file. The only think to do is put that code in main.py :
import certifi
import os
# Here's all the magic !
os.environ['SSL_CERT_FILE'] = certifi.where()
Why SSL_CERT_FILE ? Because ssl use this env to get the CA file, by default it's None on Android, so manually put it let us use the certifi CA file.
And most of all, this is global to all our app ! We don't need to override any method or to call previous code again !
You can give a look here : https://github.com/Sirfanas/kivy-ssl It's a little sample of how to solve SSL Certification problem.
Hope it help you !
Not closing it now, maybe it can be great to put it in documenation ?
Nice investigation and findings :clap: I agree let's not close until we can make a clean fix. If we don't find a way to fix yes documenting it is also a way. I haven't spent time yet trying to reproduce. However I'm already using the requests library for some of my apps without any issue. Let's hope I can reproduce with the example you shared so I can compare why it's working in certain cases. Again well done for digging into it and sharing your findings :+1:
Good news, I could reproduce with your code example :tada: @Sirfanas do you mind if I pull request to your repository to make the reproduction case a bit cleaner? Basically I want to change it to a unit test proving the point and cleaning a couple of things. Then we could tag a release and use it for reference until we fix it and add a unit test in our code base
Hi, Yeah do everything you need ! If it can help it's good !
So I dug a bit further and now it all makes sense.
So I've never seen this issue before because I've always used the requests
module.
Not only the requests module can use certifi, but it also ships (until version v2.15.1) its own cert an can fallback to it.
See requests/certs.py.
Another thing is by default openssl will look for certs in the OPENSSLDIR
which is set at configure/compile time.
See include/internal/cryptlib.h.
However since we don't define it in our recipe, it seems to default to /usr/local/ssl/
.
This can verified with:
import ssl; ssl.get_default_verify_paths()
Which returns the following on Android:
DefaultVerifyPaths(cafile=None, capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/local/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/local/ssl/certs')
So I though we could fix it at recipe level by simply pointing to Android shipped certs. But apparently we can't because the certs shipped are not in a format expected by openssl. See https://stackoverflow.com/questions/15375577/how-to-point-openssl-to-the-root-certificates-on-an-android-device
Then maybe we could try make the recipe hooks to certifi by default somehow. For instance by linking to it at configure time or by patching the module to set this environment variable like you did.
Well, make some search, seems not to be too big different format, this link seem to convert Android CA file format (jks ?) to openssl format (pem) : https://www.example-code.com/python/jks_to_pem.asp
I don't know what's the best between using certifi's CA files or convert existing Android CA files.
Both works but second option may be harder than just set an environment variable. The main think is did it change anything to use certifi CA files instead of Android's one ?
Is it possible to preset the environment variable so we don't have to do it in code like I did ? And how to do it when using Buildozer ?
If it's not possible I think it can be really interesting to have the possibility to put environment variable in buidlozer's config !
Yes I saw some examples to convert it, but it could be a bit cumbersome.
The easiest option I can think of is eventually patching from p4a and injecting the SSL_CERT_FILE
environment variable. Like you did, but at p4a level.
So for instance we could patch the Python ssl module to:
SSL_CERT_FILE
is defined in the env and if notcertifi
is available and if so inject with:os.environ['SSL_CERT_FILE'] = certifi.where()
Something like that I guess
Hello @Sirfanas, thank you very much for the investigation and the provided workaround!
I can confirm that adding "_os.environ['SSL_CERTFILE'] = certifi.where()" to the initialisation section of the app solved the issue nicely, HTTPS works now on devices and in the simulators I've tried (on Android).
For now this is a good solution, if there would be a way to have this done by default then of course all the better.
I had a similar problem and the solution on this thread worked for me too. A UrlRequest to https://blahblah worked fine on Windows, but would return "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain" on Android. I had tried ca_file=certifi.where() as an argument to UrlRequest, that did not solve it (strange...); but, setting the env var as above did solve it! So, thanks all for your work on this!
I have integrated the solution into the kivy framework, and will be submitting for acceptance.
Solving the issues for both Urlrequest and AsyncImage Android deployments.
This still isn't fixed as far as I know. I am so glad I found Sirfanas's comment. Well I am using buildozer 1.2.0
It seems that still didn't fix. Have to use Sirfanas's comment to fix this problem.
Not working for me
Not working for me ?
Also has no effect for me.
Versions
Description
Try to open HTTPS Url Failed with urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate Actually happening on Async Image I use like that:
Work perfectly on Windows, not on Android
buildozer.spec
Command:
Spec file:
Logs
I actually found a """solution""" using:
But using that in my main.py don't fix AsyncImage or any call in other py file
Any ideas ? Thank's