pythonRcpp
pythonRcpp

Reputation: 2146

python ssl error violation of protocols

I'm trying to use python to login and download some files, using the code:

import sys
import urllib
import urllib2
import httplib, ssl, socket
class HTTPSConnectionV3(httplib.HTTPSConnection):
    def __init__(self, *args, **kwargs):
        httplib.HTTPSConnection.__init__(self, *args, **kwargs)

    def connect(self):
        sock = socket.create_connection((self.host, self.port), self.timeout)
        if self._tunnel_host:
            self.sock = sock
            self._tunnel()
        try:
            self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv3)
        except ssl.SSLError, e:
            print("Trying SSLv3.")
            #self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1)
            self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23)

class HTTPSHandlerV3(urllib2.HTTPSHandler):
    def https_open(self, req):
        return self.do_open(HTTPSConnectionV3, req)
# install opener
urllib2.install_opener(urllib2.build_opener(HTTPSHandlerV3()))
if __name__ == "__main__":
    ##fill the login form
    query={}
    query['username']='USER'
    query['password']='007'
    query['submit']='Submit'
    if len(sys.argv) != 2:
                    print >> sys.stderr, "missing date"
                    sys.exit()
    #submit the form
    #http_req = urllib2.Request(url='https://www.connect2nse.com/iislNet', data=urllib.urlencode(query))
    http_req = urllib2.Request(url='https://www.connect2nse.com/iislNet/Login.jsp', data=urllib.urlencode(query))
    #http_req = urllib2.Request(url='https://www.connect2nse.com/iislNet/index.html', data=urllib.urlencode(query))
    webpage = urllib2.urlopen(http_req)
    webpage_headers = webpage.info()
    #extract the cookie
    cookie = webpage_headers['Set-Cookie'].split(';', 1)[0]
    print >> sys.stderr, "Set-Cookie:", cookie
    http_req = urllib2.Request(url='https://connect2nse.com/iislNet/MY.jsp', headers={'Cookie': cookie})
    webpage = urllib2.urlopen(http_req)

I get the following error

Trying SSLv3.
Traceback (most recent call last):
  File "MYSCRIPT.py", line 51, in <module>
    webpage = urllib2.urlopen(http_req)
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "MYSCRIPT.py", line 27, in https_open
    return self.do_open(HTTPSConnectionV3, req)
  File "/usr/lib/python2.7/urllib2.py", line 1177, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [Errno 8] _ssl.c:504: EOF occurred in violation of protocol>

Although this was working fine till last month but now it gives the above error

I have already tried This link but to no avail. Using the requests in python I use r = requests.get('https://www.connect2nse.com/iislNet/Login.jsp', auth=('USER', '007')) r.status_code 401 But I'm not sure how to proceed using requests also. Trying @Antti Haapala's solution doesnt work for me, tried it on 2.7.3&6

try: 
# self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23) 
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1) 
except ssl.SSLError, e: 
print("Trying SSLv3.",e) 
# self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=5) 
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_SSLv23)

TLSv1 and SSLv23 both give similar errors.

error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure' and
error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure'

@J.F. Sebastian , thanks but I'm 100% sure that login and password are correct, because I use the same while using in chrome. When I use TLSv1_2, I get the below error

 python MYSCRIPT.py 090315
Trying SSLv3.
Traceback (most recent call last):
  File "MYSCRIPT.py", line 51, in <module>
    webpage = urllib2.urlopen(http_req)
  File "/usr/lib/python2.7/urllib2.py", line 126, in urlopen
    return _opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 400, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 418, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
    result = func(*args)
  File "MYSCRIPT.py", line 27, in https_open
    return self.do_open(HTTPSConnectionV3, req)
  File "/usr/lib/python2.7/urllib2.py", line 1174, in do_open
    h.request(req.get_method(), req.get_selector(), req.data, headers)
  File "/usr/lib/python2.7/httplib.py", line 958, in request
    self._send_request(method, url, body, headers)
  File "/usr/lib/python2.7/httplib.py", line 992, in _send_request
    self.endheaders(body)
  File "/usr/lib/python2.7/httplib.py", line 954, in endheaders
    self._send_output(message_body)
  File "/usr/lib/python2.7/httplib.py", line 814, in _send_output
    self.send(msg)
  File "/usr/lib/python2.7/httplib.py", line 776, in send
    self.connect()
  File "MYSCRIPT.py", line 22, in connect
    self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1_2)
AttributeError: 'module' object has no attribute 'PROTOCOL_TLSv1_2'

The site published a notification of compatible browser settings, after which the script started malfunctioning this link shows compatibility, you need to click on NEW SSL DOC

Upvotes: 2

Views: 6821

Answers (1)

Your code forces the connection to use SSL 3 protocol always, SSL 3 has been superseded in the last millennium by TLSv1.

In Pythons < 2.7.9 (2.7.8), you should choose ssl.PROTOCOL_SSLv23, which will support the highest possible TLS number supported by the OpenSSL library. It specifically in current OpenSSL versions means that SSLv3, TLSv1, TLSv1.1, and TLSv1.2 are supported. Unlike the flag says, SSLv2 will not be accepted with recent versions of OpenSSL.

Thus we get:

def connect(self):
    sock = socket.create_connection((self.host, self.port), self.timeout)
    if self._tunnel_host:
        self.sock = sock
        self._tunnel()

    self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
                                ssl_version=ssl.PROTOCOL_SSLv23)

If requests connects, then you might want to use that instead. Your authorization should be sent as form values, and as a POST request:

data = {}
data['username']='USER'
data['password']='007'
data['submit']='Submit'
r = requests.post("https://www.connect2nse.com/iislNet/Login.jsp", data=data)

ssl.PROTOCOL_TLSv1_2 appeared in Python 2.7.9 and 3.4, but is also available some backports even before that version number.

However, if PROTOCOL_TLSv1_2 is not in ssl module, it also means that TLS 1.2 only cannot be used in Python even with the hardcoded protocol constant (5) - The reason is quite obvious from the _ssl source code - the integer is only meaningful to the Python extension module, and it is used to choose the actual constructor method.


In Python 2.7.9 there will be a SSLContext object that can be used to set flags on for SSL socket creation; in there one can at least try to monkey_patch to be future proof, but it is not possible with versions that do not also have the TLSv1.2 patch.

An example code on 2.7.9 on how to disable SSL 2 and 3, TLSv1.0, TLSv1.1, TLSv1.2, forcing to use the hypothetical TLSv1.3(?):

ssl_sock = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_SSLv23)
ssl_sock.context.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 \
   | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 | ssl.OP_NO_TLSv1_2

Upvotes: 5

Related Questions