requests: https GET request fails with "handshake failure"
Related to #1083, perhaps. Standard requests.get() for this particular site/page https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html results in:
>>> import requests
>>> requests.get('https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/api.py", line 55, in get
return request('get', url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/api.py", line 44, in request
return session.request(method=method, url=url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
Using request-toolbelt’s SSLAdapter to try various ssl versions, they all fail, it would seem… see following tracebacks.
TLSv1:
>>> 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 "<stdin>", line 1, in <module>
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
SSLv3:
>>> 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 "<stdin>", line 1, in <module>
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/adapters.py", line 385, in send
raise SSLError(e)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure
SSLv2:
>>> adapter = SSLAdapter('SSLv2')
>>> 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 "<stdin>", line 1, in <module>
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/adapters.py", line 378, in send
raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='docs.apitools.com', port=443): Max retries exceeded with url: /2014/04/24/a-small-router-for-openresty.html (Caused by <class 'socket.error'>: [Errno 54] Connection reset by peer)
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:
>>> headers = {
... 'Accept': u"text/html,application/xhtml+xml,application/xml",
... 'User-Agent': u"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36",
... 'Accept-Encoding': u"gzip,deflate",
... 'Accept-Language': u"en-US,en;q=0.8"
... }
>>> adapter = SSLAdapter('SSLv2')
>>> s = requests.Session()
>>> s.mount('https://', adapter)
>>> s.get('https://docs.apitools.com/2014/04/24/a-small-router-for-openresty.html', headers=headers)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 395, in get
return self.request('GET', url, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 383, in request
resp = self.send(prep, **send_kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/sessions.py", line 486, in send
r = adapter.send(request, **kwargs)
File "/Users/jaddison/.virtualenvs/techtown/lib/python2.7/site-packages/requests/adapters.py", line 378, in send
raise ConnectionError(e)
requests.exceptions.ConnectionError: HTTPSConnectionPool(host='docs.apitools.com', port=443): Max retries exceeded with url: /2014/04/24/a-small-router-for-openresty.html (Caused by <class 'socket.error'>: [Errno 54] Connection reset by peer)
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 in pyopenssl, 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
About this issue
- Original URL
- State: closed
- Created 10 years ago
- Comments: 76 (33 by maintainers)
Commits related to this issue
- Added URL/User/Passwd CLI params; added Python3 support — committed to seancummins/unisphere-rest-client by seancummins 9 years ago
- Added pyasn1 for Ubuntu 14.04LTS openssl support (see: https://github.com/kennethreitz/requests/issues/2022) — committed to userify/userify-server-tools by perpetual-hydrofoil 8 years ago
- avoid kennethreitz/requests/issues/2022 — committed to c5c86a/smscgateway-docker by deleted user 7 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.On ubuntu 14.04LTS I needed to do this:
sudo pip install ndg-httpsclient pyasn1 --upgradeNote that in Ubuntu it’s not possible to upgrade/remove
pyopensslas it’s owned by the OS.So I tried
pip install pyopenssl ndg-httpsclient pyasn1instead ofpip install requests[security]and that worked…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 OpenSSLcryptographypackage 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]OK, I may have just answered my own question. What I did boils down to:
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. =)
Got it to work now! I simply uninstalled pyOpenSSL:
pip uninstall pyOpenSSLmarkstrefford’s solution worked for me on mac os sierra too
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
requestsup and running for Django:Install
requestswith a bunch of SNI stuff, compiled against our new install of OpenSSL. The[security]option simply installspyopenssl ndg-httpsclient pyasn1And we’re good to go:
@t-8ch I haven’t installed PyOpenSSL if that’s what you’re asking?
I would have assumed (perhaps incorrectly) that
pip install requestsshould give me everything I need to successfully callrequests.get('...')on an HTTPS page. Which, of course, it works for the most part, just not for this site for some reason.@jschwinger23 Can you run
pip install pyopenssl ndg-httpsclient pyasn1as well please?Ah, damn. That explains a lot. Thank you very much for your help!
Aha, I suspect your pip is too old to handle the extras.
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:
uninstall requests
uninstall urllib3
install the various crypto dependencies
install urllib3
install urllib3[secure] # just to be safe
install requests
I think there was an installation-time check on urllib3 or requests which kept things from working without the uninstall
@Lukasa was right. Compare: