Use new capability in python-nss-0.16 to use the NSS protocol range setter. This lets us enable TLSv1.1 and TLSv1.2 for client connections.
I made this configurable via tls_protocol_range in case somebody wants to override it. There isn't a whole ton of error handling on bad input but there is enough, I think, to point the user in the the right direction. Added a couple more lines of debug output to include the negotiated protocol and cipher. rob
>From 599ff6072d4775becc49f2bbe3fd65e171f6db65 Mon Sep 17 00:00:00 2001 From: Rob Crittenden <rcrit...@redhat.com> Date: Thu, 30 Oct 2014 11:52:14 -0400 Subject: [PATCH] Use NSS protocol range API to set available TLS protocols Protocols are configured as an inclusive range from SSLv3 through TLSv1.2. The allowed values in the range are ssl3, tls1.0, tls1.1 and tls1.2. If only a single value is provided then it represents both the min and max. This is overridable per client by setting tls_protocol_range. https://fedorahosted.org/freeipa/ticket/4653 --- freeipa.spec.in | 2 +- ipalib/constants.py | 2 ++ ipalib/rpc.py | 4 +++- ipapython/dogtag.py | 3 ++- ipapython/nsslib.py | 18 ++++++++++++++++-- 5 files changed, 24 insertions(+), 5 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index 703ef9e1988c2171b815a680ad126793b2fef82d..7149066b8b6c55424843fe5a3515c92cfc92c850 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -279,7 +279,7 @@ Requires: gnupg Requires: iproute Requires: keyutils Requires: pyOpenSSL -Requires: python-nss >= 0.15 +Requires: python-nss >= 0.16 Requires: python-lxml Requires: python-netaddr Requires: libipa_hbac-python diff --git a/ipalib/constants.py b/ipalib/constants.py index 325414b64fdacd4d8df261588cfc9b7481923be1..c50a806b4a0d275525a2bc2850116a05dd01d97e 100644 --- a/ipalib/constants.py +++ b/ipalib/constants.py @@ -122,6 +122,8 @@ DEFAULT_CONFIG = ( ('rpc_protocol', 'jsonrpc'), + ('tls_protocol_range', 'tls1.0,tls1.2'), + # Time to wait for a service to start, in seconds ('startup_timeout', 300), diff --git a/ipalib/rpc.py b/ipalib/rpc.py index 001b7f1ca06edadfc7aad635d9d564e517008a63..5e1eaf1db1f6d5539c604b748a876a7a33c0e009 100644 --- a/ipalib/rpc.py +++ b/ipalib/rpc.py @@ -69,6 +69,7 @@ from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, KRB5_REALM_CANT_RESOLVE from ipapython.dn import DN from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES +from ipalib import api COOKIE_NAME = 'ipa_session' KEYRING_COOKIE_NAME = '%s_cookie:%%s' % COOKIE_NAME @@ -492,7 +493,8 @@ class SSLTransport(LanguageAwareTransport): if sys.version_info < (2, 7): conn = NSSHTTPS(host, 443, dbdir=dbdir, no_init=no_init) else: - conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init) + conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init, + protocol_range=api.env.tls_protocol_range) self.dbdir=dbdir conn.connect() diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py index bd92fe65c7780e4f73a6f3c0edfb5dd46e704a4f..e6a0f5d8498d5c785bfcb3e1d2782814e2a7256e 100644 --- a/ipapython/dogtag.py +++ b/ipapython/dogtag.py @@ -236,7 +236,8 @@ def https_request(host, port, url, secdir, password, nickname, **kw): """ def connection_factory(host, port): - conn = nsslib.NSSConnection(host, port, dbdir=secdir) + conn = nsslib.NSSConnection(host, port, dbdir=secdir, + protocol_range=api.env.tls_protocol_range) conn.set_debuglevel(0) conn.connect() conn.sock.set_client_auth_data_callback( diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py index 1452a2a5844a5fb017d4408aadf56f7fcfc7fa25..f874ac425b0c5ab201b6661c012c142c7510d345 100644 --- a/ipapython/nsslib.py +++ b/ipapython/nsslib.py @@ -174,7 +174,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): default_port = httplib.HTTPSConnection.default_port def __init__(self, host, port=None, strict=None, - dbdir=None, family=socket.AF_UNSPEC, no_init=False): + dbdir=None, family=socket.AF_UNSPEC, no_init=False, + protocol_range='tls1.1,tls1.2'): """ :param host: the server to connect to :param port: the port to use (default is set in HTTPConnection) @@ -183,6 +184,7 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): :param no_init: do not initialize the NSS database. This requires that the database has already been initialized or the request will fail. + :param protocol_range: min and max SSL/TLS protocol range supported. """ httplib.HTTPConnection.__init__(self, host, port, strict) NSSAddressFamilyFallback.__init__(self, family) @@ -210,6 +212,10 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): ssl.set_domestic_policy() nss.set_password_callback(self.password_callback) + protocol_range = str(protocol_range.replace(' ', '')) + (self.range_low, comma, self.range_high) = str(protocol_range).partition(',') + if self.range_high == '': + self.range_high = self.range_low def _create_socket(self): # TODO: remove the try block once python-nss is guaranteed to contain @@ -229,6 +235,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): self.sock = ssl.SSLSocket(family=self.family) self.sock.set_ssl_option(ssl.SSL_SECURITY, True) self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True) + try: + self.sock.set_ssl_version_range(self.range_low, self.range_high) + except NSPRError, e: + root_logger.error('Failed to set TLS range to %s, %s' % (self.range_low, self.range_high)) + raise self.sock.set_ssl_option(ssl_require_safe_negotiation, False) self.sock.set_ssl_option(ssl_enable_renegotiation, ssl_renegotiate_requires_xtn) # Provide a callback which notifies us when the SSL handshake is complete @@ -247,8 +258,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): """ Verify callback. If we get here then the certificate is ok. """ + channel = sock.get_ssl_channel_info() + suite = ssl.get_cipher_suite_info(channel.cipher_suite) root_logger.debug("handshake complete, peer = %s", sock.get_peer_name()) - pass + root_logger.debug('Protocol: %s' % channel.protocol_version_str.upper()) + root_logger.debug('Cipher: %s' % suite.cipher_suite_name) def connect(self): self.connect_socket(self.host, self.port) -- 1.9.3
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel