|
|
e3ffab |
From 8c544d9583c4172634f3180d6f90e6d4f37595ed Mon Sep 17 00:00:00 2001
|
|
|
e3ffab |
From: Rob Crittenden <rcritten@redhat.com>
|
|
|
e3ffab |
Date: Thu, 30 Oct 2014 11:52:14 -0400
|
|
|
e3ffab |
Subject: [PATCH] Use NSS protocol range API to set available TLS protocols
|
|
|
e3ffab |
|
|
|
e3ffab |
Protocols are configured as an inclusive range from SSLv3 through
|
|
|
e3ffab |
TLSv1.2. The allowed values in the range are ssl3, tls1.0,
|
|
|
e3ffab |
tls1.1 and tls1.2.
|
|
|
e3ffab |
|
|
|
e3ffab |
This is overridable per client by setting tls_version_min and/or
|
|
|
e3ffab |
tls_version_max.
|
|
|
e3ffab |
|
|
|
e3ffab |
https://fedorahosted.org/freeipa/ticket/4653
|
|
|
e3ffab |
|
|
|
e3ffab |
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
|
|
|
e3ffab |
---
|
|
|
e3ffab |
freeipa.spec.in | 2 +-
|
|
|
e3ffab |
ipalib/constants.py | 4 ++++
|
|
|
e3ffab |
ipalib/rpc.py | 5 ++++-
|
|
|
e3ffab |
ipapython/dogtag.py | 4 +++-
|
|
|
e3ffab |
ipapython/nsslib.py | 17 +++++++++++++++--
|
|
|
e3ffab |
5 files changed, 27 insertions(+), 5 deletions(-)
|
|
|
e3ffab |
|
|
|
e3ffab |
diff --git a/freeipa.spec.in b/freeipa.spec.in
|
|
|
e3ffab |
index e29f77de0db89035d15008c6be2da0ae7e96158a..1c975b3912d0a7470a32f1b7e314cfde74446e85 100644
|
|
|
e3ffab |
--- a/freeipa.spec.in
|
|
|
e3ffab |
+++ b/freeipa.spec.in
|
|
|
e3ffab |
@@ -271,7 +271,7 @@ Requires: gnupg
|
|
|
e3ffab |
Requires: iproute
|
|
|
e3ffab |
Requires: keyutils
|
|
|
e3ffab |
Requires: pyOpenSSL
|
|
|
e3ffab |
-Requires: python-nss >= 0.15
|
|
|
e3ffab |
+Requires: python-nss >= 0.16
|
|
|
e3ffab |
Requires: python-lxml
|
|
|
e3ffab |
Requires: python-netaddr
|
|
|
e3ffab |
Requires: libipa_hbac-python
|
|
|
e3ffab |
diff --git a/ipalib/constants.py b/ipalib/constants.py
|
|
|
e3ffab |
index 1eed7ca6ad0e5920318dadc68ed36fff6cf889f2..111bafe5ed0c3d2df58a1b6839feedc58a14fcc4 100644
|
|
|
e3ffab |
--- a/ipalib/constants.py
|
|
|
e3ffab |
+++ b/ipalib/constants.py
|
|
|
e3ffab |
@@ -122,6 +122,10 @@ DEFAULT_CONFIG = (
|
|
|
e3ffab |
|
|
|
e3ffab |
('rpc_protocol', 'jsonrpc'),
|
|
|
e3ffab |
|
|
|
e3ffab |
+ # Define an inclusive range of SSL/TLS version support
|
|
|
e3ffab |
+ ('tls_version_min', 'tls1.0'),
|
|
|
e3ffab |
+ ('tls_version_max', 'tls1.2'),
|
|
|
e3ffab |
+
|
|
|
e3ffab |
# Time to wait for a service to start, in seconds
|
|
|
e3ffab |
('startup_timeout', 300),
|
|
|
e3ffab |
|
|
|
e3ffab |
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
|
|
|
e3ffab |
index 5934f0c26e4b7c0a44adbab978c1f9b319d72e9f..806f6bb9adf004660c9cb285cf31b09a988afa93 100644
|
|
|
e3ffab |
--- a/ipalib/rpc.py
|
|
|
e3ffab |
+++ b/ipalib/rpc.py
|
|
|
e3ffab |
@@ -68,6 +68,7 @@ from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT
|
|
|
e3ffab |
KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, KRB5_REALM_CANT_RESOLVE
|
|
|
e3ffab |
from ipapython.dn import DN
|
|
|
e3ffab |
from ipalib.capabilities import VERSION_WITHOUT_CAPABILITIES
|
|
|
e3ffab |
+from ipalib import api
|
|
|
e3ffab |
|
|
|
e3ffab |
COOKIE_NAME = 'ipa_session'
|
|
|
e3ffab |
KEYRING_COOKIE_NAME = '%s_cookie:%%s' % COOKIE_NAME
|
|
|
e3ffab |
@@ -488,7 +489,9 @@ class SSLTransport(LanguageAwareTransport):
|
|
|
e3ffab |
if sys.version_info < (2, 7):
|
|
|
e3ffab |
conn = NSSHTTPS(host, 443, dbdir=dbdir, no_init=no_init)
|
|
|
e3ffab |
else:
|
|
|
e3ffab |
- conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init)
|
|
|
e3ffab |
+ conn = NSSConnection(host, 443, dbdir=dbdir, no_init=no_init,
|
|
|
e3ffab |
+ tls_version_min=api.env.tls_version_min,
|
|
|
e3ffab |
+ tls_version_max=api.env.tls_version_max)
|
|
|
e3ffab |
self.dbdir=dbdir
|
|
|
e3ffab |
|
|
|
e3ffab |
conn.connect()
|
|
|
e3ffab |
diff --git a/ipapython/dogtag.py b/ipapython/dogtag.py
|
|
|
e3ffab |
index 14824b99431e85dd73613befd72e500d370cfe2c..0e0aacca798377517244075ed6b07dff63e87358 100644
|
|
|
e3ffab |
--- a/ipapython/dogtag.py
|
|
|
e3ffab |
+++ b/ipapython/dogtag.py
|
|
|
e3ffab |
@@ -234,7 +234,9 @@ def https_request(host, port, url, secdir, password, nickname, **kw):
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
|
|
|
e3ffab |
def connection_factory(host, port):
|
|
|
e3ffab |
- conn = nsslib.NSSConnection(host, port, dbdir=secdir)
|
|
|
e3ffab |
+ conn = nsslib.NSSConnection(host, port, dbdir=secdir,
|
|
|
e3ffab |
+ tls_version_min=api.env.tls_version_min,
|
|
|
e3ffab |
+ tls_version_max=api.env.tls_version_max)
|
|
|
e3ffab |
conn.set_debuglevel(0)
|
|
|
e3ffab |
conn.connect()
|
|
|
e3ffab |
conn.sock.set_client_auth_data_callback(
|
|
|
e3ffab |
diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py
|
|
|
e3ffab |
index 93b0c56fcff4fc69841a6823aae8f694c1f76ff0..57fa3ff4fa5a044577f21fe43c2c0b0596c2e4f8 100644
|
|
|
e3ffab |
--- a/ipapython/nsslib.py
|
|
|
e3ffab |
+++ b/ipapython/nsslib.py
|
|
|
e3ffab |
@@ -171,7 +171,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
|
|
|
e3ffab |
default_port = httplib.HTTPSConnection.default_port
|
|
|
e3ffab |
|
|
|
e3ffab |
def __init__(self, host, port=None, strict=None,
|
|
|
e3ffab |
- dbdir=None, family=socket.AF_UNSPEC, no_init=False):
|
|
|
e3ffab |
+ dbdir=None, family=socket.AF_UNSPEC, no_init=False,
|
|
|
e3ffab |
+ tls_version_min='tls1.1', tls_version_max='tls1.2'):
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
:param host: the server to connect to
|
|
|
e3ffab |
:param port: the port to use (default is set in HTTPConnection)
|
|
|
e3ffab |
@@ -180,6 +181,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
|
|
|
e3ffab |
:param no_init: do not initialize the NSS database. This requires
|
|
|
e3ffab |
that the database has already been initialized or
|
|
|
e3ffab |
the request will fail.
|
|
|
e3ffab |
+ :param tls_min_version: mininum version of SSL/TLS supported
|
|
|
e3ffab |
+ :param tls_max_version: maximum version of SSL/TLS supported.
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
httplib.HTTPConnection.__init__(self, host, port, strict)
|
|
|
e3ffab |
NSSAddressFamilyFallback.__init__(self, family)
|
|
|
e3ffab |
@@ -199,6 +202,8 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
|
|
|
e3ffab |
nss.nss_init(dbdir)
|
|
|
e3ffab |
ssl.set_domestic_policy()
|
|
|
e3ffab |
nss.set_password_callback(self.password_callback)
|
|
|
e3ffab |
+ self.tls_version_min = str(tls_version_min)
|
|
|
e3ffab |
+ self.tls_version_max = str(tls_version_max)
|
|
|
e3ffab |
|
|
|
e3ffab |
def _create_socket(self):
|
|
|
e3ffab |
# TODO: remove the try block once python-nss is guaranteed to contain
|
|
|
e3ffab |
@@ -218,6 +223,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
|
|
|
e3ffab |
self.sock = ssl.SSLSocket(family=self.family)
|
|
|
e3ffab |
self.sock.set_ssl_option(ssl.SSL_SECURITY, True)
|
|
|
e3ffab |
self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True)
|
|
|
e3ffab |
+ try:
|
|
|
e3ffab |
+ self.sock.set_ssl_version_range(self.tls_version_min, self.tls_version_max)
|
|
|
e3ffab |
+ except NSPRError, e:
|
|
|
e3ffab |
+ root_logger.error('Failed to set TLS range to %s, %s' % (self.tls_version_min, self.tls_version_max))
|
|
|
e3ffab |
+ raise
|
|
|
e3ffab |
self.sock.set_ssl_option(ssl_require_safe_negotiation, False)
|
|
|
e3ffab |
self.sock.set_ssl_option(ssl_enable_renegotiation, ssl_renegotiate_requires_xtn)
|
|
|
e3ffab |
# Provide a callback which notifies us when the SSL handshake is complete
|
|
|
e3ffab |
@@ -236,8 +246,11 @@ class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback):
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
Verify callback. If we get here then the certificate is ok.
|
|
|
e3ffab |
"""
|
|
|
e3ffab |
+ channel = sock.get_ssl_channel_info()
|
|
|
e3ffab |
+ suite = ssl.get_cipher_suite_info(channel.cipher_suite)
|
|
|
e3ffab |
root_logger.debug("handshake complete, peer = %s", sock.get_peer_name())
|
|
|
e3ffab |
- pass
|
|
|
e3ffab |
+ root_logger.debug('Protocol: %s' % channel.protocol_version_str.upper())
|
|
|
e3ffab |
+ root_logger.debug('Cipher: %s' % suite.cipher_suite_name)
|
|
|
e3ffab |
|
|
|
e3ffab |
def connect(self):
|
|
|
e3ffab |
self.connect_socket(self.host, self.port)
|
|
|
e3ffab |
--
|
|
|
e3ffab |
2.1.0
|
|
|
e3ffab |
|