From acc9eb1e4d707c7951ba48384469c903737f8a3b Mon Sep 17 00:00:00 2001 From: Davanum Srinivas Date: Sun, 8 Nov 2015 11:28:21 -0500 Subject: [PATCH] Support for SSL protocol and cipher controls Add ability to explicitly specify SSL/TLS protocol version and ciphers. We add 2 string options and do not specify any default for backward compatability. If the values are not specified explicitly we fall back to the python defaults as we did before. DocImpact Closes-Bug: #1513581 Change-Id: I149cf569e1e5277f30e89203d20731d4482509d4 --- oslo_service/_options.py | 10 ++++++++++ oslo_service/sslutils.py | 29 +++++++++++++++++++++++++++++ oslo_service/tests/test_sslutils.py | 25 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/oslo_service/_options.py b/oslo_service/_options.py index a673697a..ea192635 100644 --- a/oslo_service/_options.py +++ b/oslo_service/_options.py @@ -97,4 +97,14 @@ ssl_opts = [ "the server securely.", deprecated_group='DEFAULT', deprecated_name='ssl_key_file'), + cfg.StrOpt('version', + help='SSL version to use (valid only if SSL enabled). ' + 'Valid values are TLSv1 and SSLv23. SSLv2, SSLv3, ' + 'TLSv1_1, and TLSv1_2 may be available on some ' + 'distributions.' + ), + cfg.StrOpt('ciphers', + help='Sets the list of available ciphers. value should be a ' + 'string in the OpenSSL cipher list format.' + ), ] diff --git a/oslo_service/sslutils.py b/oslo_service/sslutils.py index 50e75287..8be5da97 100644 --- a/oslo_service/sslutils.py +++ b/oslo_service/sslutils.py @@ -22,6 +22,24 @@ from oslo_service import _options config_section = 'ssl' +_SSL_PROTOCOLS = { + "tlsv1": ssl.PROTOCOL_TLSv1, + "sslv23": ssl.PROTOCOL_SSLv23 +} + +_OPTIONAL_PROTOCOLS = { + 'sslv2': 'PROTOCOL_SSLv2', + 'sslv3': 'PROTOCOL_SSLv3', + 'tlsv1_1': 'PROTOCOL_TLSv1_1', + 'tlsv1_2': 'PROTOCOL_TLSv1_2', +} +for protocol in _OPTIONAL_PROTOCOLS: + try: + _SSL_PROTOCOLS[protocol] = getattr(ssl, + _OPTIONAL_PROTOCOLS[protocol]) + except AttributeError: + pass + def list_opts(): """Entry point for oslo-config-generator.""" @@ -70,4 +88,15 @@ def wrap(conf, sock): ssl_kwargs['ca_certs'] = conf.ssl.ca_file ssl_kwargs['cert_reqs'] = ssl.CERT_REQUIRED + if conf.ssl.version: + key = conf.ssl.version.lower() + try: + ssl_kwargs['ssl_version'] = _SSL_PROTOCOLS[key] + except KeyError: + raise RuntimeError( + _("Invalid SSL version : %s") % conf.ssl.version) + + if conf.ssl.ciphers: + ssl_kwargs['ciphers'] = conf.ssl.ciphers + return ssl.wrap_socket(sock, **ssl_kwargs) diff --git a/oslo_service/tests/test_sslutils.py b/oslo_service/tests/test_sslutils.py index 1cc5ec07..6dd7bf42 100644 --- a/oslo_service/tests/test_sslutils.py +++ b/oslo_service/tests/test_sslutils.py @@ -107,3 +107,28 @@ class SslutilsTestCase(base.ServiceBaseTestCase): 'cert_reqs': ssl.CERT_REQUIRED } self._test_wrap(**ssl_kwargs) + + def test_wrap_ciphers(self): + self.conf.set_default("ca_file", self.ca_file_name, + group=sslutils.config_section) + 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' + ) + self.conf.set_default("ciphers", ciphers, + group=sslutils.config_section) + ssl_kwargs = {'ca_certs': self.conf.ssl.ca_file, + 'cert_reqs': ssl.CERT_REQUIRED, + 'ciphers': ciphers} + self._test_wrap(**ssl_kwargs) + + def test_wrap_ssl_version(self): + self.conf.set_default("ca_file", self.ca_file_name, + group=sslutils.config_section) + self.conf.set_default("version", "tlsv1", + group=sslutils.config_section) + ssl_kwargs = {'ca_certs': self.conf.ssl.ca_file, + 'cert_reqs': ssl.CERT_REQUIRED, + 'ssl_version': ssl.PROTOCOL_TLSv1} + self._test_wrap(**ssl_kwargs)