How to block SSL protocols in favor of TLS?

How to block SSL protocols in PyOpenSSL in favor of TLS ? I am using CentOS 7 and have the following versions:

 pyOpenSSL-0.13.1-3.el7.x86_64 openssl-1.0.1e-34.el7_0.7.x86_64 

In my configuration file (this is for the CherryPy application):

 'server.ssl_module': 'pyopenssl', 
+4
source share
2 answers

This is a really good question for CherryPy today. This month, we started discussing SSL issues and the general maintainability of CherryPy wrappers over py2.6 + ssl and pyOpenSSL in the CherryPy user group . I plan a topic about SSL issues there, so you can subscribe to the group to get more details later.

So far, thatโ€™s whatโ€™s possible. I had Debian Wheezy, Python 2.7.3-4 + deb7u1, OpenSSL 1.0.1e-2 + deb7u16. I installed CherryPy from the repo (3.6 broke SSL) and pyOpenSSL 0.14. I tried to override both CherryPy SSL adapters to get some points in the Qualys SSL test labs. This is very useful, and I highly recommend that you test its deployment (regardless of your interface, CherryPy or not).

As a result, the ssl adapter still has vulnerabilities that I donโ€™t see a workaround for in py2 <2.7.9 (mass SSL update) and py3 <3.3. Since the CherryPy ssl adapter was written long before these changes, it needs to be rewritten to support both old and new methods (mainly SSL Contexts ). On the other hand, with the subclassified pyOpenSSL, it adapted mostly perfectly, except:

Here is the code.

 #!/usr/bin/env python # -*- coding: utf-8 -*- import os import sys import ssl import cherrypy from cherrypy.wsgiserver.ssl_builtin import BuiltinSSLAdapter from cherrypy.wsgiserver.ssl_pyopenssl import pyOpenSSLAdapter from cherrypy import wsgiserver if sys.version_info < (3, 0): from cherrypy.wsgiserver.wsgiserver2 import ssl_adapters else: from cherrypy.wsgiserver.wsgiserver3 import ssl_adapters try: from OpenSSL import SSL except ImportError: pass ciphers = ( '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:!DSS:!RC4:!SSLv2' ) bundle = os.path.join(os.path.dirname(cherrypy.__file__), 'test', 'test.pem') config = { 'global' : { 'server.socket_host' : '127.0.0.1', 'server.socket_port' : 8443, 'server.thread_pool' : 8, 'server.ssl_module' : 'custom-pyopenssl', 'server.ssl_certificate' : bundle, 'server.ssl_private_key' : bundle, } } class BuiltinSsl(BuiltinSSLAdapter): '''Vulnerable, on py2 < 2.7.9, py3 < 3.3: * POODLE (SSLv3), adding ``!SSLv3`` to cipher list makes it very incompatible * can't disable TLS compression (CRIME) * supports Secure Client-Initiated Renegotiation (DOS) * no Forward Secrecy Also session caching doesn't work. Some tweaks are posslbe, but don't really change much. For example, it possible to use ssl.PROTOCOL_TLSv1 instead of ssl.PROTOCOL_SSLv23 with little worse compatiblity. ''' def wrap(self, sock): """Wrap and return the given socket, plus WSGI environ entries.""" try: s = ssl.wrap_socket( sock, ciphers = ciphers, # the override is for this line do_handshake_on_connect = True, server_side = True, certfile = self.certificate, keyfile = self.private_key, ssl_version = ssl.PROTOCOL_SSLv23 ) except ssl.SSLError: e = sys.exc_info()[1] if e.errno == ssl.SSL_ERROR_EOF: # This is almost certainly due to the cherrypy engine # 'pinging' the socket to assert it connectable; # the 'ping' isn't SSL. return None, {} elif e.errno == ssl.SSL_ERROR_SSL: if e.args[1].endswith('http request'): # The client is speaking HTTP to an HTTPS server. raise wsgiserver.NoSSLError elif e.args[1].endswith('unknown protocol'): # The client is speaking some non-HTTP protocol. # Drop the conn. return None, {} raise return s, self.get_environ(s) ssl_adapters['custom-ssl'] = BuiltinSsl class Pyopenssl(pyOpenSSLAdapter): '''Mostly fine, except: * Secure Client-Initiated Renegotiation * no Forward Secrecy, SSL.OP_SINGLE_DH_USE could have helped but it didn't ''' def get_context(self): """Return an SSL.Context from self attributes.""" c = SSL.Context(SSL.SSLv23_METHOD) # override: c.set_options(SSL.OP_NO_COMPRESSION | SSL.OP_SINGLE_DH_USE | SSL.OP_NO_SSLv2 | SSL.OP_NO_SSLv3) c.set_cipher_list(ciphers) c.use_privatekey_file(self.private_key) if self.certificate_chain: c.load_verify_locations(self.certificate_chain) c.use_certificate_file(self.certificate) return c ssl_adapters['custom-pyopenssl'] = Pyopenssl class App: @cherrypy.expose def index(self): return '<em>Is this secure?</em>' if __name__ == '__main__': cherrypy.quickstart(App(), '/', config) 

Update

Here's an article and discussion where the future of CherryPy SSL support needs to be addressed.

+1
source

There are two ways to do this, I know. One of them is configuration parameters, and the other is a run-time parameter.

Configuration option

The configuration parameter is used when building OpenSSL. It is great for all applications because it applies your administrative policy and addresses applications that do not take into account SSL / TLS related issues.

For this parameter, simply configure OpenSSL with no-ssl2 no-ssl3 . no-comp also often used because compression can leak information.

 ./Configure no-ssl2 no-ssl3 <other opts> 

Other OpenSSL options are available, and you might want to visit the "Compile and Install" on the OpenSSL wiki.

Execution option

In C, you need (1) to use the 2/3 method to obtain SSL 2/3 and higher; and then (2) call SSL_CTX_set_options (or SSL_set_options ) and (3) delete the SSL protocols. This leaves the TLS protocols:

 SSL_CTX* ctx = SSL_CTX_new(SSLv23_method()); const long flags = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION; SSL_CTX_set_options(ctx, flags); 

In Python, you do this using OpenSSL.SSL.Context.set_options .

0
source

Source: https://habr.com/ru/post/985117/


All Articles