11

Notes:

versions

Python 2.7.11 and my requests version is '2.10.0'
'OpenSSL 1.0.2d 9 Jul 2015'
Please read the below comment by Martijn Pieters before reproducing 

Initially I tried to get pdf from https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx using code as below

code1:

>>> import requests
>>> requests.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx",verify=False)

Error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\api.py", line 67, in get
    return request('get', url, params=params, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\api.py", line 53, in request
    return session.request(method=method, url=url, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\adapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESE
T')",)

After googling and searching I found that you have use SSL verification and using session with adapters can solve the problem. But I still got error's please find the code and error's below

Code2:

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
import ssl
import traceback

class MyAdapter(HTTPAdapter):
    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       ssl_version=ssl.PROTOCOL_TLSv1)


s = requests.Session()
s.mount('https://', MyAdapter())
print "Mounted    "
r = s.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx", stream=True, timeout=120)

Error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 480, in get
    return self.request('GET', url, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 468, in request
    resp = self.send(prep, **send_kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\sessions.py", line 576, in send
    r = adapter.send(request, **kwargs)
  File "C:\Users\mob140003207\AppData\Local\Enthought\Canopy\User\lib\site-packa
ges\requests\adapters.py", line 447, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: SysCallError(10054, 'WSAECONNRESET')",)
Szabolcs Dombi
  • 5,493
  • 3
  • 39
  • 71
The6thSense
  • 8,103
  • 8
  • 31
  • 65
  • 1
    Can you specify which versions of requests you're using and perhaps the exact version of Python as well? I managed to run your second code sample without issue in Python 3.5 with requests 2.10.0. Could you also take a look at [this](http://stackoverflow.com/a/24166498/3165737) answer which suggests monkey patching `ssl.wrap_socket()` – DocZerø Aug 08 '16 at 10:03
  • 1
    What version of openssl are you using? – Padraic Cunningham Aug 08 '16 at 10:05
  • @Kristof I am using Python 2.7.11 and my requests version is '2.10.0' I am currently looking at the link you provided to me will let you know if it works mate. – The6thSense Aug 08 '16 at 10:45
  • @PadraicCunningham I am using 'OpenSSL 1.0.2d 9 Jul 2015' – The6thSense Aug 08 '16 at 10:45
  • website https://www.neco.navy.mil/ is not available – waki Aug 08 '16 at 11:01
  • @waki it is available if needed I can provide you an image? – The6thSense Aug 08 '16 at 11:25
  • @Kristof the link you provided worked. Either you could write a detailed answer then I could mark it as accepted or I can mark this as a duplicate question – The6thSense Aug 08 '16 at 13:42
  • 1
    I'd love the bounty, but I as I didn't come up with the answer, it'd only be fair to mark it as a duplicate. – DocZerø Aug 08 '16 at 13:47
  • Unfortunately I cannot connect (possibly closed from other countries)? $ curl -iv https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx * Trying 205.85.2.133... * connect to 205.85.2.133 port 443 failed: Operation timed out * Failed to connect to www.neco.navy.mil port 443: Operation timed out * Closing connection 0 curl: (7) Failed to connect to www.neco.navy.mil port 443: Operation timed out Have you tried to debug it with OpenSSL tools like this: – Eugene Lisitsky Aug 08 '16 at 14:03
  • openssl s_client -connect www.neco.navy.mil:443 -servername www.neco.navy.mil -debug connect: Operation timed out connect:errno=60 – Eugene Lisitsky Aug 08 '16 at 14:04
  • Looks like it uses some outdated protocol or violates it. Here's some information how to use old SSL with requests: https://github.com/kennethreitz/requests/issues/2022 – Eugene Lisitsky Aug 08 '16 at 14:05
  • I can't reproduce the error. However, the certificate from that server (neco.navy.mil) is not signed by a trusted authority and it used a deprecated signature hash (SHA1). Possibly these cause the issue. If that were the case, though, I'd expect to see something like "`requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed`" – J Richard Snape Aug 08 '16 at 14:30
  • 5
    **Important note to those trying to reproduce**: Python 2.7.9 and newer have *significantly* upgraded Python's SSL capabilities. See [PEP 466](https://www.python.org/dev/peps/pep-0466/). If you want to help reproduce and find a solution, you'll have to use a version at *least that new*. (On OS X, use a Homebrew-built Python as [Apple's system Python uses an outdated OpenSSL version](https://github.com/Homebrew/homebrew-core/issues/3541)). – Martijn Pieters Aug 09 '16 at 06:33
  • Can you try and reproduce this issue on a different OS or network segment? It looks as if you are using Enthought Canopy, but I can't reproduce your issue at all using Canopy 64bit 1.7.4 for Mac OS X. The issue may be Windows specific, or *network* specific, in that some other device on your network (like a firewall) is interfering with the connection. – Martijn Pieters Aug 09 '16 at 08:39
  • Just a sense check - can you browse to that URI and download the document on the same machine using a standard web browser? – J Richard Snape Aug 09 '16 at 10:28
  • @JRichardSnape I able to browse to URL and dowload using a US sever which is where the script is running but using my sample script there I get error like the one you pointed `requests.exceptions.SSLError: [Errno 1] _ssl.c:510: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed` – The6thSense Aug 09 '16 at 10:50
  • @MartijnPieters I can reproduce the issue in windows system and python version2.7.11 in different locations other than US in US I am getting the error as Richard pointed. I don't have a linux or mac system to test in other platform – The6thSense Aug 09 '16 at 10:52
  • 1
    @The6thSense That makes sense. From your Windows box, I suggest Martijn is probably right and you have a firewall issue (maybe even Windows firewall), as [that error](https://msdn.microsoft.com/en-gb/library/windows/desktop/ms740668(v=vs.85).aspx#wsaeconnreset) means that the socket was disconnected by the peer. When you run on the server and see the "certificate verify failed" error, it's likely because of the problems with the certificate on the far end - which you can't do much about except for ignoring it. – J Richard Snape Aug 09 '16 at 13:22
  • @JRichardSnape Ooh that makes a lot sense. – The6thSense Aug 09 '16 at 13:46
  • 1
    Also possibly interest in why the Windows box shows one error while the server shows another - does your Windows box possibly have McAfee installed? See this knowledge base article: https://support.microsoft.com/en-us/kb/981344 – J Richard Snape Aug 10 '16 at 12:49
  • 1
    I hope that this would help! http://docs.python-requests.org/en/master/ –  Aug 10 '16 at 18:50

3 Answers3

9

First of all, I confirm that the host, www.neco.navy.mil, is not accessible from everywhere. From some networks (geography) it works*, from others connection just hangs:

$ curl www.neco.navy.mil
curl: (7) couldn't connect to host
$ curl https://www.neco.navy.mil
curl: (7) couldn't connect to host

Second, when connection can be established there is an certificate problem:

$ curl -v https://www.neco.navy.mil
* Rebuilt URL to: https://www.neco.navy.mil/
* Hostname was NOT found in DNS cache
*   Trying 205.85.2.133...
* Connected to www.neco.navy.mil (205.85.2.133) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* SSLv3, TLS handshake, Client hello (1):
* SSLv3, TLS handshake, Server hello (2):
* SSLv3, TLS handshake, CERT (11):
* SSLv3, TLS alert, Server hello (2):
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 0
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: http://curl.haxx.se/docs/sslcerts.html

curl performs SSL certificate verification by default, using a "bundle"
 of Certificate Authority (CA) public keys (CA certs). If the default
 bundle file isn't adequate, you can specify an alternate file
 using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
 the bundle, the certificate verification probably failed due to a
 problem with the certificate (it might be expired, or the name might
 not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
 the -k (or --insecure) option.

To make sure, you just feed it to Qualys SSL tester: enter image description here

The CA (DoD Root CA 2) is not trusted. Moreover it's not in the chain. Note that OpenSSL validation process needs whole chain:

Firstly a certificate chain is built up starting from the supplied certificate and ending in the root CA. It is an error if the whole chain cannot be built up.

But there's only www.neco.navy.mil -> DODCA-28. It may be related to the TLD and extra security measure, but C grade alone isn't much anyway ;-)

On they Python side it won't be much different. If you don't have access to the CA, you can only disable certificate validation entirely (after you have connectivity problem solved, of course). If you have it, you can use cafile.

#!/usr/bin/env python
# -*- coding: utf-8 -*-


import urllib2
import ssl


ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

r = urllib2.urlopen('https://www.neco.navy.mil/'
  'necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx', 
  timeout = 5, context = ctx)
print(len(r.read()))

r = urllib2.urlopen('https://www.neco.navy.mil/'
  'necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx', 
  timeout = 5, cafile = '/path/to/DODCA-28_and_DoD_Root_CA_2.pem')
print(len(r.read()))

To reproduce with certain version of Python, use simple Dockerfile like follows:

FROM python:2.7.11

WORKDIR /opt
ADD . ./

CMD dpkg -s openssl | grep Version && ./app.py

Then run:

docker build -t ssl-test .
docker run --rm ssl-test
saaj
  • 23,253
  • 3
  • 104
  • 105
1

This snippet works for me (py2.7.11 64bits + requests==2.10.0) on windows7:

import requests
import ssl
import traceback
import shutil
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager


class MyAdapter(HTTPAdapter):

    def init_poolmanager(self, connections, maxsize, block=False):
        self.poolmanager = PoolManager(num_pools=connections,
                                       maxsize=maxsize,
                                       block=block,
                                       ssl_version=ssl.PROTOCOL_TLSv1)


if __name__ == "__main__":
    s = requests.Session()
    s.mount('https://', MyAdapter())
    print "Mounted    "
    filename = "N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx"
    r = s.get(
        "https://www.neco.navy.mil/necoattach/{0}".format(filename), verify=False, stream=True, timeout=120)

    if r.status_code == 200:
        with open(filename, 'wb') as f:
            r.raw.decode_content = True
            shutil.copyfileobj(r.raw, f)
BPL
  • 9,632
  • 9
  • 59
  • 117
0

I use python 2.7.6 and this simple example still working on my ubuntu 14.04

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

with open('out.docx', 'wb') as h :
    r = requests.get("https://www.neco.navy.mil/necoattach/N6945016R0626_2016-06-20__INFO_NAS_Pensacola_Base_Access.docx", verify=False, stream=True)

    for block in r.iter_content(1024):
        h.write(block)
vatay
  • 387
  • 2
  • 9
  • 1
    It is not working following error is thrown `EOF occurred in violation of protocol (_ssl.c:590)` – The6thSense Aug 08 '16 at 11:28
  • This works for me (even without the warnings disable). I see the docx and it is openable with a list of instructions. – J Richard Snape Aug 08 '16 at 14:29
  • @JRichardSnape I don't know why but it is throwing EOF error for me – The6thSense Aug 09 '16 at 05:47
  • Versions of Python 2.7 before 2.7.9 do expose enough OpenSSL functionality to properly verify SSL certificates. With the OP using 2.7.11, you'll *have* to upgrade to a newer Python version if you want to even begin to prove you can make it work. – Martijn Pieters Aug 09 '16 at 06:27
  • @JRichardSnape: what version of Python? Please do try and use 2.7.9 or newer here. – Martijn Pieters Aug 09 '16 at 06:27