From 3d3e1c82a2377848f1a4a892517106c8255bc58d Mon Sep 17 00:00:00 2001 From: Toshio Kuratomi Date: Wed, 15 Jul 2015 13:17:00 -0700 Subject: [PATCH] Have openssl autonegotiate tls protocol on python < 2.7.9 This allows usage of tls-1.1 and tls-1.2 if the underlying openssl library supports it. Unfortunately it also allows sslv2 and sslv3 if the server is only configured to support those. In this day and age, that's probably something that the server administrator should fix anyhow. --- lib/ansible/module_utils/urls.py | 33 +++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/lib/ansible/module_utils/urls.py b/lib/ansible/module_utils/urls.py index 2ba19b629f7..6530ba81e81 100644 --- a/lib/ansible/module_utils/urls.py +++ b/lib/ansible/module_utils/urls.py @@ -106,6 +106,33 @@ try: except ImportError: HAS_SSLCONTEXT = False +# Select a protocol that includes all secure tls protocols +# Exclude insecure ssl protocols if possible + +# If we can't find extra tls methods, ssl.PROTOCOL_TLSv1 is sufficient +PROTOCOL = ssl.PROTOCOL_TLSv1 +if not HAS_SSLCONTEXT and HAS_SSL: + try: + import ctypes, ctypes.util + except ImportError: + # python 2.4 (likely rhel5 which doesn't have tls1.1 support in its openssl) + pass + else: + libssl_name = ctypes.util.find_library('ssl') + libssl = ctypes.CDLL(libssl_name) + for method in ('TLSv1_1_method', 'TLSv1_2_method'): + try: + libssl[method] + # Found something - we'll let openssl autonegotiate and hope + # the server has disabled sslv2 and 3. best we can do. + PROTOCOL = ssl.PROTOCOL_SSLv23 + break + except AttributeError: + pass + del libssl + + + HAS_MATCH_HOSTNAME = True try: from ssl import match_hostname, CertificateError @@ -304,7 +331,7 @@ class CustomHTTPSConnection(httplib.HTTPSConnection): if HAS_SSLCONTEXT: self.sock = self.context.wrap_socket(sock, server_hostname=self.host) else: - self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=ssl.PROTOCOL_TLSv1) + self.sock = ssl.wrap_socket(sock, keyfile=self.key_file, certfile=self.cert_file, ssl_version=PROTOCOL) class CustomHTTPSHandler(urllib2.HTTPSHandler): @@ -514,7 +541,7 @@ class SSLValidationHandler(urllib2.BaseHandler): if context: ssl_s = context.wrap_socket(s, server_hostname=proxy_parts.get('hostname')) else: - ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1) + ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL) match_hostname(ssl_s.getpeercert(), self.hostname) else: raise ProxyError('Unsupported proxy scheme: %s. Currently ansible only supports HTTP proxies.' % proxy_parts.get('scheme')) @@ -523,7 +550,7 @@ class SSLValidationHandler(urllib2.BaseHandler): if context: ssl_s = context.wrap_socket(s, server_hostname=self.hostname) else: - ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLSv1) + ssl_s = ssl.wrap_socket(s, ca_certs=tmp_ca_cert_path, cert_reqs=ssl.CERT_REQUIRED, ssl_version=PROTOCOL) match_hostname(ssl_s.getpeercert(), self.hostname) # close the ssl connection #ssl_s.unwrap()