Requests allows setting path to a CA certificate bundle that should be used instead of the default system one using the following environment variables: REQUESTS_CA_BUNDLE and CURL_CA_BUNDLE.
https://github.com/kennethreitz/requests/blob/v2.8.1/requests/sessions.py#L621
Please make it also check SSL_CERT_FILE environment variable in the same way. This variable is recognized by OpenSSL and is documented in PEP 476 as a way to make Python standard library https clients use non-default CA bundle file:
https://www.python.org/dev/peps/pep-0476/#trust-database
It sounds reasonable to have a single environment variable that can be used for all Python scripts regardless of whether they are using requests or standard library httplib / urllib*.
In terms of the fix, a simple or os.environ.get('SSL_CERT_FILE') should do the trick.
This seems reasonable enough to me. I'd be happy to accept a patch that does this. We should also accept SSL_CERT_DIR.
This seems harmless enough.
Is this still an issue ? If so I would like to give it a shot.
@Keops92 The work has been done, sadly: see #2903.
Thanks !
What about adding a new keyword (I don't know, let's say verify_native ) and if set to True, requests would respect SSL_CERT_FILE and SSL_CERT_DIR as well as try to use platform-native certificate storage? This shouldn't break backwards compatibility.
The Requests team are _strongly_ opposed to adding new keyword arguments, especially if they are redundant with, overlap with, or can be set to contradictory values with a pre-existing keyword argument.
That makes sense.
Is there a plan to support system certificate storage in the next compatibility-breaking release?
@luv Currently the expectation is that a future urllib3 release will allow the passing of custom SSLContext objects to urllib3. That will allow construction of adapters that let you use the system certificate store on Linux. For OS X and Windows we have the beginnings of some code to do it, but it's a lot of very subtle work that needs a lot of bugs ironed out.
Thanks for answer.
Actually, are you sure you need custom SSLContext to use system certificate store on Unix/Linux? It should be enough to pass correct path to "verify" keyword and you are sorted, even with the current version of requests.
I realize it must be really PITA working on supporting OS X, Windows, Unix and Linux system certificate store transparently.
Btw. from your previous comment it was not clear if you plan to limit this functionality to OS X and Windows only (and leave it up to the end-user to support unix and linux system certificates with custom SSLContext) or if you plan to support system certificates on Linux (and *BSD and friends :) ) as well.
Thanks!
It should be enough to pass correct path to "verify" keyword and you are sorted, even with the current version of requests.
I wish, but it is not. There is no consistent "correct" path that works across all Unices. There is no consistent "correct" path that works across all Linux distributions. There is not even a guarantee that there's a consistent "correct" path that works across all _versions_ of the same distribution. The reason the SSLContext approach is preferred is simply that it allows you to defer that choice to the distribution-provided OpenSSL, which is hopefully correctly configured.
Btw. from your previous comment it was not clear if you plan to limit this functionality to OS X and Windows only (and leave it up to the end-user to support unix and linux system certificates with custom SSLContext) or if you plan to support system certificates on Linux (and *BSD and friends :) ) as well.
The ideal end goal will be that there's a urllib3 flag you can hit to change its verification logic, and that requests will make it available in some way. That will work for all platforms.
I see. Would you mind providing an example where curl's approach to finding the "correct path" does not work https://github.com/curl/curl/blob/master/acinclude.m4#L2627 ?
The reason the SSLContext approach is preferred is simply that it allows you to defer that choice to the distribution-provided OpenSSL, which is hopefully correctly configured.
Oh ... if this is going to depend on functions like X509_get_default_cert_dir - it might be, in the real world, more problematic than hard-coded paths :( ... http://lists.freebsd.org/pipermail/freebsd-python/2014-December/007809.html
Would you mind providing an example where curl's approach to finding the "correct path" does not work
Well, for one, in the FreeBSD post you just linked, which has the certs at /usr/local/etc/ssl/cert.pem and /usr/local/share/certs/ca-root-nss.crt, neither of which are in curl's list:
/etc/ssl/certs/ca-certificates.crt
/etc/pki/tls/certs/ca-bundle.crt
/usr/share/ssl/certs/ca-bundle.crt
/usr/local/share/certs/ca-root.crt
/etc/ssl/cert.pem
The general concerns here are the following set:
It's the wild west out here, with people dumping certs wherever the hell they want, and we need a system that doesn't mysteriously fail as much as possible.
If you believe the curl approach works for your software, then by all means, you may implement it in your own software. You could even create a third-party module like certifi that implements a similar API and also implements curl's logic. However, it's my belief that curl's logic is somewhat fragile and only works because it allows configuration overrides in the build scripts, which most distros take advantage of. Those same distros make equivalent changes in requests when shipped on their platform, so I see no reason to want to emulate curl in this case.
sounds good
@Lukasa /etc/ssl/cert.pem is now by default linked by the ca_root_nss port.
I have a more practical question: I am a Mac OS user which is forced to use custom CA certificates. Importing them in KeyChain works well for ALL browsers and even for curl. Even if I am unfortunate enough to have to install the alternative curl via brew I do still have the option to use SSL_CERT_FILE environment variable in order to workaround the fact that that one fails to load certs from the keychain.
Now, the big problem is how to convince requests to work? And when I say convince I mean that I need a solution that does NOT require me to patch any library that may be using requests.
Can't you use REQUESTS_CA_BUNDLE environment variable?
http://docs.python-requests.org/en/master/user/advanced/#ssl-cert-verification
As @luv suggested, that will work.
@luv Thanks, I can confirm that if I do export REQUESTS_CA_BUNDLE=$SSL_CERT_FILE i would be able to use requests the same way as other libraries. I dont really know why requests needs another environment variable instead of re-using the same one but I guess there were some reasons for that.
While I did this I observed something that looks like a bug: requests.certs.where() returns the same location even when you define REQUESTS_CA_BUNDLE, even if the library is using the ones from REQUESTS_CA_BUNDLE. Should I open a bug for this or is not really a bug?
I dont really know why requests needs another environment variable instead of re-using the same one but I guess there were some reasons for that.
Strictly, SSL_CERT_FILE is an OpenSSL environment variable. Requests doesn't use it because it does not ever check for it being set, and never trusts that OpenSSL will locate certs. In principle it could watch for this variable, though: the patch would be small.
Should I open a bug for this or is not really a bug?
It's not a bug. requests.certs.where is an implementation detail of Requests and doesn't claim to tell you where the cert bundle Requests will actually use is. This is partly because it can't: the location of the bundle can be changed by properties of the Session and arguments to the various request methods. All where() ever does is point to the _on-disk_ location of the Requests bundled certificates.
Can we close this? #2903 has already been merged into the proposed/3.0.0 branch.
@hobarrera thanks!
Most helpful comment
Well, for one, in the FreeBSD post you just linked, which has the certs at
/usr/local/etc/ssl/cert.pemand/usr/local/share/certs/ca-root-nss.crt, neither of which are in curl's list:The general concerns here are the following set:
It's the wild west out here, with people dumping certs wherever the hell they want, and we need a system that doesn't mysteriously fail as much as possible.
If you believe the curl approach works for your software, then by all means, you may implement it in your own software. You could even create a third-party module like certifi that implements a similar API and also implements curl's logic. However, it's my belief that curl's logic is somewhat fragile and only works because it allows configuration overrides in the build scripts, which most distros take advantage of. Those same distros make equivalent changes in requests when shipped on their platform, so I see no reason to want to emulate curl in this case.