Closed jaddison closed 10 years ago
Sadly, this is unrelated to the issue you identified, and entirely down to the crappy OpenSSL that OS X ships with by default. Version 0.9.8y has some real problems with performing SSL handshakes, and some servers don't tolerate it well. Using Python 3 on my OS X box (therefore using a newer OpenSSL) reveals that there's no problem.
You have two options:
env ARCHFLAGS="-arch x86_64" LDFLAGS="-L/usr/local/opt/openssl/lib" CFLAGS="-I/usr/local/opt/openssl/include" pip install PyOpenSSL
.Ah, looks like I was following a red herring then - I don't plan on deploying anything on OSX anyhow. Looks like I'll move my testing to a linux virtualbox. Apologies for this long-winded issue!
No need to apologise, asking that question was the right thing to do: it's bizarrely specific knowledge to know that OS X has this problem. =)
Ok, this is a bummer. I created an Ubuntu 14.04 server 32bit Virtualbox image via Vagrant and this is all still happening except for the SSLv2 case, where it fails because the protocol isn't included in the OpenSSL version in Ubuntu 14.04 (by design, I believe - SSLv2 is old and outdated).
Versions: Ubuntu 14.04 32bit (via Vagrant/Virtualbox combo) Python 2.7.6 requests==2.2.1 requests-toolbelt==0.2.0 urllib3==1.8.2
EDIT: forgot the OpenSSL version...
python -c "import ssl; print ssl.OPENSSL_VERSION" OpenSSL 1.0.1f 6 Jan 2014
TLSv1:
>>> import requests
>>> from requests_toolbelt import SSLAdapter
>>> adapter = SSLAdapter('TLSv1')
>>> s = requests.Session()
>>> s.mount('https://', adapter)
>>> s.get('https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
SSLError: [Errno 1] _ssl.c:510: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
SSLv2:
>>> import requests
>>> from requests_toolbelt import SSLAdapter
>>> adapter = SSLAdapter('SSLv3')
>>> s = requests.Session()
>>> s.mount('https://', adapter)
>>> s.get('https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
SSLError: [Errno 1] _ssl.c:510: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
SSLv23:
>>> import requests
>>> from requests_toolbelt import SSLAdapter
>>> adapter = SSLAdapter('SSLv23')
>>> s = requests.Session()
>>> s.mount('https://', adapter)
>>> s.get('https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/home/vagrant/.virtualenvs/techtown/local/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
SSLError: [Errno 1] _ssl.c:510: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
Perhaps this is a cipher list issue then? Or is the OpenSSL version used here still problematic?
I am absolutely willing to put in some time to help debug this if necessary... provided you guys give me some direction.
VM is downloading. I can't reproduce this on ArchLinux. The stacktraces indicate this but I'd like to be sure: You are not using PyOpenSSL but only the stdlib?
@t-8ch Thanks for taking a look at this, I'm a bit confused. OpenSSL makes my life really hard =(
@t-8ch I haven't installed PyOpenSSL if that's what you're asking?
I would have assumed (perhaps incorrectly) that pip install requests
should give me everything I need to successfully call requests.get('...')
on an HTTPS page. Which, of course, it works for the most part, just not for this site for some reason.
@jaddison It mostly does. Unfortunately, Python 2.7s standard library sucks hard and doesn't support some features, such as SNI.
I wonder if this is SNI...
@jaddison There are two different codepaths behind the scenes. You shouldn't have to care about those, but it helps to know when debugging.
However I can now reproduce this on ubuntu. But only o Py2. On Py3 everything is fine. I suspect @Lukasa is right and the server fails when the client is not using SNI.
It bothers me that an absence of SNI fails in multiple different ways depending on the server in question.
I did notice this change between OpenSSL 1.0.1f and 1.0.1g (https://www.openssl.org/news/openssl-1.0.1-notes.html):
Add TLS padding extension workaround for broken servers.
EDIT: Ahh, nevermind - the bug shouldn't vary between Py 2 and 3, I'd think.
@jaddison To test whether this is SNI, you'll need to install the SNI requirements for Python 2.
@Lukasa was right. Compare:
$ openssl s_client -connect docs.apitools.com:443
CONNECTED(00000003)
139846853338768:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:762:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 517 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
---
$ openssl s_client -connect docs.apitools.com:443 -servername docs.apitools.com
... happy handshake here
To elaborate: The second command enables the SNI functionality of openssl s_client
.
You can a) switch to python3 b) install extra dependencies. The stdlib has at the moment no way to do SNI.
Thanks for the quick feedback. Seeing as there is no bug, I'll close this... again.
Hey, thank you guys !! I installed python3 on my mac and boom, it works.
Just want to chime in and say that I experienced this issue on OS X 10.9.5, Python 2.7.7 and OpenSSL 0.9.8zc.
I was able to fix my handshaking issue by:
brew install OpenSSL
cryptography
package linked against the new OpenSSL (env ARCHFLAGS="-arch x86_64" LDFLAGS="-L/usr/local/opt/openssl/lib" CFLAGS="-I/usr/local/opt/openssl/include" pip install cryptography
) pip install requests[security]
Thanks, @Microserf. I'm pretty much running the same specs (10.9.5, Python 2.7.6 installed via Homebrew but compiled with system provided OpenSSL 0.9.8zg) and this was my entire process for getting requests
up and running for Django:
brew install openssl
Install requests
with a bunch of SNI stuff, compiled against our new install of OpenSSL. The [security]
option simply installs pyopenssl ndg-httpsclient pyasn1
env ARCHFLAGS="-arch x86_64" LDFLAGS="-L/usr/local/opt/openssl/lib" CFLAGS="-I/usr/local/opt/openssl/include" pip install requests[security] urllib3
And we're good to go:
"""
This may or may not be needed. See:
https://urllib3.readthedocs.org/en/latest/security.html#openssl-pyopenssl
"""
# from urllib3.contrib import pyopenssl
# pyopenssl.inject_into_urllib3()
import requests
# r = requests.get(...)
Is there a definitive answer on how to get this working on ubuntu? I'm running into this issue, and it looks like the only answer here concerns how to get this working on a Mac. Upgrading our entire codebase to python 3 is not an option.
OK, I may have just answered my own question. What I did boils down to:
sudo apt-get install libffi-dev
pip install pyOpenSSL ndg-httpsclient pyasn1
@lsemel thank you, that just saved me a bunch of time
@lsemel Are your sure? I tried it on Ubuntu 15.10 and it still doesn't work with Python 2.7.10.
It works with Python 2.7 on Travis CI: https://travis-ci.org/playing-se/swish-python
Got it to work now! I simply uninstalled pyOpenSSL:
pip uninstall pyOpenSSL
Maybe we should only pyopenssl.inject_into_urllib3() if Python version is less than 2.7.9? pyOpenSSL seems to break stuff on Ubuntu and Windows if Python version is 2.7.10.
PyOpenSSL should not be breaking anything. If it does, that's a bug that should be reported.
I will have to look into this, but is there any good reason to inject pyopenssl into urllib3 if Python version is 2.7.9 or newer?
I am thinking of something like this:
# Check if Modern SSL with SNI support
try:
from ssl import SSLContext
from ssl import HAS_SNI
except ImportError:
# Attempt to enable urllib3's SNI support, if possible
try:
from .packages.urllib3.contrib import pyopenssl
pyopenssl.inject_into_urllib3()
except ImportError:
pass
Yeah, frequently there is. For example, on OS X most Pythons link against the system OpenSSL, which is version 0.9.8zg. PyOpenSSL, however, will link against a much newer OpenSSL (1.0.2). That makes using PyOpenSSL a substantial security improvement.
Additionally, PyOpenSSL gives us much better access to OpenSSL, allowing us to secure it more effectively.
OK, I have played around with this a little now.
It WORKS with pyopenssl BUT not if ndg-httpsclient is installed.
However, I can get it work with ndg-httpsclient if I uninstall pyasn1 giving me these warnings:
/usr/lib/python2.7/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled. Import error is: No module named pyasn1.type
warnings.warn(import_error_msg)
/usr/lib/python2.7/dist-packages/ndg/httpsclient/ssl_peer_verification.py:25: UserWarning: SubjectAltName support is disabled - check pyasn1 package installation to enable
warnings.warn(SUBJ_ALT_NAME_SUPPORT_MSG)
/usr/lib/python2.7/dist-packages/ndg/httpsclient/subj_alt_name.py:22: UserWarning: Error importing pyasn1, subjectAltName check for SSL peer verification will be disabled. Import error is: No module named pyasn1.type
warnings.warn(import_error_msg)
Same behavior on Ubuntu 15.10 and Windows 10 with Python 2.7.10 installed.
That's because without ndg-httpsclient the PyOpenSSL support isn't used.
Yes, I will have to dig into why it works if SubjectAltName is disabled. Any idea?
Almost certainly the problem is that you're using different OpenSSLs in each case.
I had the same issue on my Ubuntu 14.04 box and Python 2.7.11
It's from SNI
What worked for me was this:
install requests
I think there was an installation-time check on urllib3 or requests which kept things from working without the uninstall
@jvanasco what are you using to install those packages? I assume pip. Why are you installing urllib3 and requests separately?
Well I needed urllib3 in the virtualenv... but I installed it to try and get the requirements installed by pip and easy_install. (I used both)
I have a web indexer and a few urls broke. I wrote a quick script to try the broken ones, and kept reinstalling/delete+installing the packages in the urllib3 instructions on ssl issues until they worked.
On May 31, 2016, at 7:25 PM, Ian Cordasco notifications@github.com wrote:
@jvanasco what are you using to install those packages? I assume pip. Why are you installing urllib3 and requests separately?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
I'm still seeing this issue and i've tried the suggested work arounds. I updated my python version to 2.7.11 I installed the 3 additional packages.
I tried the uninstall/install sequence @jvanasco suggested and still got the SSLError Also using Ubuntu 14.04 unfortunately there's no OpenSSL update so i have to use the workarounds posted here and i'm having no luck.
Any extra steps you guys possibly took?
Thanks
@Lekinho I found that making a short test-script that tested the domain I was having problems with helped.
it was just:
import requests
r = requests.get(bad_url)
print r.__dict__
@Lekinho You can extract pyopenssl from requests in your code:
try:
from requests.packages.urllib3.contrib import pyopenssl
pyopenssl.extract_from_urllib3()
except ImportError:
pass
@Lekinho If you're still encountering this problem with Python 2.7.11 it's highly likely that the remote server doesn't support the TLS settings being used by requests. Is the server in question available on the public internet? If so, can you provide me with the URL?
i've tried the pyopenssl import as suggested. Unfortunately this is not accessible publicly. However I have the exact details of what openSSL version the server has. Basically, we run on a redhat virtual machine, I had this openSSL when everything was working : openssl-1.0.1e-42.el6_7.4.x86_64
Then we did a redhat upgrade and there was an update for openssl : openssl-1.0.1e-48.el6_8.1.x86_64
This version always has the bad handshake issue when using openssl on ubuntu 14.04.
Do you guys have any public URLs i can try with, to see if the work arounds helped resolve the issue and its just this unique combination that I have that's the problem?
The same machine is fine when REST requests are sent through the browser(i.e. without the ubuntu openssl )
Thanks
Can you provide the output of rpm -q --changelog openssl
, please?
[admin@leke-2-2-8-11 ~]$ rpm -q --changelog openssl
It looks like @Lekinho deleted their github account? For the next person who has issues - it's possible that their upgrade of OpenSsl or Python broke some compiled c bindings. Whenever I have an upgrade like that, I trash my virtualenv or all packages and then build a new one.
@jvanasco i'm still here. I was wondering, do you have a public URL i could test this with? I want to see if the workaround actually resolves the issue for confirmed cases ( this will mean I didnt screw something up while trying to do it)
@Lukasa
subset of changeset between working version and updated version :+1: Mon May 02 2016 Tomáš Mráz tmraz@redhat.com 1.0.1e-48.1 fix CVE-2016-2105 - possible overflow in base64 encoding fix CVE-2016-2106 - possible overflow in EVP_EncryptUpdate() fix CVE-2016-2107 - padding oracle in stitched AES-NI CBC-MAC fix CVE-2016-2108 - memory corruption in ASN.1 encoder fix CVE-2016-2109 - possible DoS when reading ASN.1 data from BIO fix CVE-2016-0799 - memory issues in BIO_printf
Wed Feb 24 2016 Tomáš Mráz tmraz@redhat.com 1.0.1e-48
fix CVE-2016-0702 - side channel attack on modular exponentiation fix CVE-2016-0705 - double-free in DSA private key parsing fix CVE-2016-0797 - heap corruption in BN_hex2bn and BN_dec2bn
Tue Feb 16 2016 Tomáš Mráz tmraz@redhat.com 1.0.1e-47
fix CVE-2015-3197 - SSLv2 ciphersuite enforcement disable SSLv2 in the generic TLS method
Fri Jan 15 2016 Tomáš Mráz tmraz@redhat.com 1.0.1e-46
fix 1-byte memory leak in pkcs12 parse (#1229871) document some options of the speed command (#1197095)
Thu Jan 14 2016 Tomáš Mráz tmraz@redhat.com 1.0.1e-45
fix high-precision timestamps in timestamping authority
Mon Dec 21 2015 Tomáš Mráz tmraz@redhat.com 1.0.1e-44
fix CVE-2015-7575 - disallow use of MD5 in TLS1.2
Fri Dec 04 2015 Tomáš Mráz tmraz@redhat.com 1.0.1e-43
fix CVE-2015-3194 - certificate verify crash with missing PSS parameter fix CVE-2015-3195 - X509_ATTRIBUTE memory leak fix CVE-2015-3196 - race condition when handling PSK identity hint
Tue Jun 23 2015 Tomáš Mráz tmraz@redhat.com 1.0.1e-42
Update : So I found a work around for this. Basically a colleague was reading up on the issue and saw some posts about RHEL openssl support for ECC/ECDH cipher not being 100% for whatever reason.
We tried out the request to the URL by explicitly disabling ECDH ciphers (adding the negation from openssl script itself i.e. openssl s_client -connect 10.85.103.218:8443 -cipher 'DEFAULT:!ECDH')
We were able to successfully connect.
Here's the default cipher list for the openssl on ubuntu 14.04 ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:!eNULL:!MD5
So with that knowlege, I used pyopenssl to print out my default SSL ciphers and explicitly removed every ECDH cipher from the string. Did this right in the block to import urllib3 from requests package (i.e. before starting to make any actual requests) here's something similar : https://github.com/kennethreitz/requests/issues/1308
I realize there may be security risks for this action but at least this gets us going and sheds more light on it.
Why those particular ciphers appear to be an issue for the RHEL, I have no idea.
I will try when i have more time to see what particular RHEL changes may have introduced this and read up on the purpose more.
Anyone know more about ciphers generally?
Have the same issue... ARG...
@lukas-gitl frustration will not help you solve the problem. Providing us with information about your environment (preferably some - if not all - of the information that we asked Lekinho above) will help.
@sigmavirus24 Apologies. I meant to provide more information and then got side tracked (since I had no time for this). I'm using Ubuntu 14.04, python 2.7.6 and the latest requests version on pip. This happens when I try to access as API Gateway endpoint (they might be quite restrictive).
I tried removing the virtualenv and regenerating it but unfortunately that didn't solve it.
Let me know what else you need. I switched to nodejs for the time but would be happy to help with a resolution.
@lukas-gitl It's highly likely that the server you're contacting requires ciphers you aren't offering, or TLS versions you aren't offering. This can be related to the OpenSSL you have installed. You should also try running pip install requests[security]
: you may be encountering problems with SNI.
Related to #1083, perhaps. Standard
requests.get()
for this particular site/pagehttps://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html
results in:Using
request-toolbelt
'sSSLAdapter
to try various ssl versions, they all fail, it would seem... see following tracebacks.TLSv1:
SSLv3:
SSLv2:
Note the last one gives a
Connection reset by peer
error, which differs from the others, but I'm pretty sure SSLv2 isn't supported by the server anyhow.For fun, I tried to pass through some more appropriate headers through on the last request as well:
No dice there either. Here's what the HTTPS connection info in Chrome on Mac looks like:
I'm not positive, but some googling indicates it's likely a cipher list issue, which is more urllib3, I think?
I tried to modify
DEFAULT_CIPHER_LIST
inpyopenssl
, but started running into import errors. At this point it seemed like things were just broken, and there wasn't really a proper way to approach fixing this yet.Version information: OSX Mavericks Python 2.7.5 OpenSSL 0.9.8y 5 Feb 2013 - (from
python -c "import ssl; print ssl.OPENSSL_VERSION"
) requests 2.2.1 requests-toolbelt 0.2.0 urllib3 1.8