From 5ceb920bd69b2abbe125be44a3b46e82d3494a93 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Wed, 11 Jan 2017 20:47:27 +0100 Subject: [PATCH] TLS tuning - allow TLS > 1.0 with python >= 2.7.9 - tune ssl_context with python >= 2.7.9 --- src/class_receiveDataThread.py | 14 +++++++++++--- src/network/tls.py | 15 +++++++++++++-- src/protocol.py | 24 ++++++++++++++---------- 3 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/class_receiveDataThread.py b/src/class_receiveDataThread.py index 3112575a..3ce3b35e 100644 --- a/src/class_receiveDataThread.py +++ b/src/class_receiveDataThread.py @@ -293,9 +293,17 @@ class receiveDataThread(threading.Thread): if ((self.services & protocol.NODE_SSL == protocol.NODE_SSL) and protocol.haveSSL(not self.initiatedConnection)): logger.debug("Initialising TLS") - self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=ssl.PROTOCOL_TLSv1, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') - if hasattr(self.sslSock, "context"): - self.sslSock.context.set_ecdh_curve("secp256k1") + if sys.version_info >= (2,7,9): + context = ssl.create_default_context(purpose = ssl.Purpose.CLIENT_AUTH if self.initiatedConnection else ssl.Purpose.SERVER_AUTH) + context.set_ciphers("AECDH-AES256-SHA") + context.set_ecdh_curve("secp256k1") + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + # also exclude TLSv1 and TLSv1.1 in the future + context.options |= ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 + self.sslSock = context.wrap_socket(self.sock, server_side = not self.initiatedConnection, do_handshake_on_connect=False) + else: + self.sslSock = ssl.wrap_socket(self.sock, keyfile = os.path.join(paths.codePath(), 'sslkeys', 'key.pem'), certfile = os.path.join(paths.codePath(), 'sslkeys', 'cert.pem'), server_side = not self.initiatedConnection, ssl_version=protocol.sslProtocolVersion, do_handshake_on_connect=False, ciphers='AECDH-AES256-SHA') while True: try: self.sslSock.do_handshake() diff --git a/src/network/tls.py b/src/network/tls.py index f690acc9..855bcd93 100644 --- a/src/network/tls.py +++ b/src/network/tls.py @@ -6,6 +6,7 @@ import asyncore import socket import ssl +import protocol class TLSHandshake(asyncore.dispatcher): """ @@ -42,9 +43,19 @@ class TLSHandshake(asyncore.dispatcher): def handle_connect(self): # Once the connection has been established, it's safe to wrap the # socket. - self.sslSocket = ssl.wrap_socket(self.socket, + if sys.version_info >= (2,7,9): + context = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH if self.server_side else ssl.Purpose.CLIENT_AUTH) + context.set_ciphers(ciphers) + # context.set_ecdh_curve("secp256k1") + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + # also exclude TLSv1 and TLSv1.1 in the future + context.options |= ssl.OP_NOSSLv2 | ssl.OP_NOSSLv3 + self.sslSock = context.wrap_socket(self.sock, server_side = self.server_side, do_handshake_on_connect=False) + else: + self.sslSocket = ssl.wrap_socket(self.socket, server_side=self.server_side, - ssl_version=ssl.PROTOCOL_TLSv1, + ssl_version=protocol.sslProtocolVersion, certfile=self.certfile, keyfile=self.keyfile, ciphers=self.ciphers, diff --git a/src/protocol.py b/src/protocol.py index 970b63b0..da0cd3aa 100644 --- a/src/protocol.py +++ b/src/protocol.py @@ -77,16 +77,6 @@ def haveSSL(server = False): return True return False -def sslProtocolVersion(): - if sys.version_info >= (2,7,13): - # in the future once TLS is mandatory, change this to ssl.PROTOCOL_TLS1.2 - return ssl.PROTOCOL_TLS - elif sys.version_info >= (2,7,9): - # once TLS is mandatory, add "ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1.1" - return ssl.PROTOCOL_SSLv23 | ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 - else: - return ssl.PROTOCOL_TLS1 - def checkSocksIP(host): try: if state.socksIP is None or not state.socksIP: @@ -483,3 +473,17 @@ def broadcastToSendDataQueues(data): # logger.debug('running broadcastToSendDataQueues') for q in state.sendDataQueues: q.put(data) + +# sslProtocolVersion +if sys.version_info >= (2,7,13): + # this means TLSv1 or higher + # in the future change to + # ssl.PROTOCOL_TLS1.2 + sslProtocolVersion = ssl.PROTOCOL_TLS +elif sys.version_info >= (2,7,9): + # this means any SSL/TLS. SSLv2 and 3 are excluded with an option after context is created + sslProtocolVersion = ssl.PROTOCOL_SSLv23 +else: + # this means TLSv1, there is no way to set "TLSv1 or higher" or + # "TLSv1.2" in < 2.7.9 + sslProtocolVersion = ssl.PROTOCOL_TLSv1