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.

This is overridable per client by setting tls_version_min and/or
tls_version_max.

https://fedorahosted.org/freeipa/ticket/4653

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Rob Crittenden 2014-10-30 11:52:14 -04:00 committed by Jan Cholasta
parent aa9ecb253a
commit 5c0ad221e8
5 changed files with 27 additions and 5 deletions

View File

@ -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

View File

@ -122,6 +122,10 @@ DEFAULT_CONFIG = (
('rpc_protocol', 'jsonrpc'),
# Define an inclusive range of SSL/TLS version support
('tls_version_min', 'tls1.0'),
('tls_version_max', 'tls1.2'),
# Time to wait for a service to start, in seconds
('startup_timeout', 300),

View File

@ -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,9 @@ 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,
tls_version_min=api.env.tls_version_min,
tls_version_max=api.env.tls_version_max)
self.dbdir=dbdir
conn.connect()

View File

@ -236,7 +236,9 @@ 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,
tls_version_min=api.env.tls_version_min,
tls_version_max=api.env.tls_version_max)
conn.set_debuglevel(0)
conn.connect()
conn.sock.set_client_auth_data_callback(

View File

@ -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,
tls_version_min='tls1.1', tls_version_max='tls1.2'):
"""
:param host: the server to connect to
:param port: the port to use (default is set in HTTPConnection)
@ -183,6 +184,8 @@ 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 tls_min_version: mininum version of SSL/TLS supported
:param tls_max_version: maximum version of SSL/TLS supported.
"""
httplib.HTTPConnection.__init__(self, host, port, strict)
NSSAddressFamilyFallback.__init__(self, family)
@ -210,6 +213,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
ssl.set_domestic_policy()
nss.set_password_callback(self.password_callback)
self.tls_version_min = str(tls_version_min)
self.tls_version_max = str(tls_version_max)
def _create_socket(self):
# TODO: remove the try block once python-nss is guaranteed to contain
@ -229,6 +234,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.tls_version_min, self.tls_version_max)
except NSPRError, e:
root_logger.error('Failed to set TLS range to %s, %s' % (self.tls_version_min, self.tls_version_max))
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 +257,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)