November 23, 2016 · ucspython ucsmsdk

Python and state of SSL/TLS

Python 2.7.9 introduces a ssl.SSLContext object to make selecting SSL version easier.

Since using SSLv2 or SSLv3 is a crime, most systems rely on TLSv1, TLSv1.1 or TLSv1.2. The SSLContext obect makes it easier to define the generic subset of protocol one desires and then individually turnoff some of them.

The below code relies only on TLSv1, TLSv1.1, TLSv1.2 and not use SSLv2 or SSLv3

ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
ssl_context.options |= ssl.OP_NO_SSLv2
ssl_context.options |= ssl.OP_NO_SSLv3

So, How can this be used in the larger context.
We use urllib2 and so the above needs to fit into one of the handlers.

opener = urllib2.build_opener(TLSHandler)
response = opener.open(url)

class TLSHandler(urllib2.HTTPSHandler):                                         
    """Like HTTPSHandler but more specific"""                                   
                                                                                
    def __init__(self):                                                         
    ¦   urllib2.HTTPSHandler.__init__(self)                                     
                                                                                
    def https_open(self, req):                                                  
    ¦   return self.do_open(TLSConnection, req) 

class TLSConnection(httplib.HTTPSConnection):                                   
    """Like HTTPSConnection but more specific"""                                
                                                                                
    def __init__(self, host, **kwargs):                                         
    ¦   httplib.HTTPSConnection.__init__(self, host, **kwargs)                  
                                                                                
    def connect(self):                                                          
    ¦   """Overrides HTTPSConnection.connect to specify TLS version"""          
    ¦   # Standard implementation from HTTPSConnection, which is not            
    ¦   # designed for extension, unfortunately                                 
    ¦   sock = socket.create_connection((self.host, self.port),             
    ¦   ¦   ¦   self.timeout, self.source_address)  
                                                                                            
    ¦   if getattr(self, '_tunnel_host', None):                                 
    ¦   ¦   self.sock = sock                                                    
    ¦   ¦   self._tunnel()                                                      
                                                                                
    ¦   # Since python 2.7.9, tls 1.1 and 1.2 are supported via 
    ¦   # SSLContext                                                        
    ¦   ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)                   
    ¦   ssl_context.options |= ssl.OP_NO_SSLv2                              
    ¦   ssl_context.options |= ssl.OP_NO_SSLv3                              
    ¦   ssl_context.load_cert_chain(keyfile, certfile)            
    ¦   self.sock = ssl_context.wrap_socket(sock)  

This would produce a SSL_UNSUPPORTED_VERSION error when the server does not support TLSv1/1.1/1.2

note: TLSv1.1 and TLSv1.2 are supported only since Openssl version 1.0.1. And so, you might have Python >= 2.7.9 and still not see PROTOCOL_TLSv1_1 and PROTOCOL_TLSv1_2 unless the openssl version is correct.

TLS 1.2 handshake fails in some clients, because of a TLV length padding issue. In such cases, we should fallback to TLSv1.

  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket