Explicitly remove support of SSLv2/3

It was possible to set tls_version_min/max to 'ssl2' or 'ssl3',
even though newer versions of NSS will fail to set this as a valid
TLS version. This patch explicitly checks for deprecated TLS versions
prior to creating a TLS connection.

Also, we don't allow tls_version_min/max to be set to a random
string anymore.

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

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
Reviewed-By: Tomas Krizek <tkrizek@redhat.com>
This commit is contained in:
Stanislav Laznicka 2017-01-13 12:31:29 +01:00 committed by Martin Basti
parent d0642bfa55
commit ac6f573a30
3 changed files with 94 additions and 4 deletions

View File

@ -41,8 +41,11 @@ from six.moves.configparser import RawConfigParser, ParsingError
from ipapython.dn import DN
from ipalib.base import check_name
from ipalib.constants import CONFIG_SECTION
from ipalib.constants import OVERRIDE_ERROR, SET_ERROR, DEL_ERROR
from ipalib.constants import (
CONFIG_SECTION,
OVERRIDE_ERROR, SET_ERROR, DEL_ERROR,
TLS_VERSIONS
)
from ipalib import errors
if six.PY3:
@ -578,6 +581,26 @@ class Env(object):
self._merge(**defaults)
# set the best known TLS version if min/max versions are not set
if 'tls_version_min' not in self:
self.tls_version_min = TLS_VERSIONS[-1]
elif self.tls_version_min not in TLS_VERSIONS:
raise errors.EnvironmentError(
"Unknown TLS version '{ver}' set in tls_version_min."
.format(ver=self.tls_version_min))
if 'tls_version_max' not in self:
self.tls_version_max = TLS_VERSIONS[-1]
elif self.tls_version_max not in TLS_VERSIONS:
raise errors.EnvironmentError(
"Unknown TLS version '{ver}' set in tls_version_max."
.format(ver=self.tls_version_max))
if self.tls_version_max < self.tls_version_min:
raise errors.EnvironmentError(
"tls_version_min is set to a higher TLS version than "
"tls_version_max.")
def _finalize(self, **lastchance):
"""
Finalize and lock environment.

View File

@ -283,3 +283,13 @@ ANON_USER = 'WELLKNOWN/ANONYMOUS'
# IPA API Framework user
IPAAPI_USER = 'ipaapi'
IPAAPI_GROUP = 'ipaapi'
# TLS related constants
TLS_VERSIONS = [
"ssl2",
"ssl3",
"tls1.0",
"tls1.1",
"tls1.2"
]
TLS_VERSION_MINIMAL = "tls1.0"

View File

@ -23,6 +23,8 @@ from __future__ import print_function
import getpass
import socket
from ipapython.ipa_log_manager import root_logger
from ipapython.ipa_log_manager import log_mgr
from ipalib.constants import TLS_VERSIONS, TLS_VERSION_MINIMAL
from nss.error import NSPRError
import nss.io as io
@ -38,6 +40,9 @@ except ImportError:
# pylint: disable=import-error
import http.client as httplib
# get a logger for this module
logger = log_mgr.get_logger(__name__)
# NSS database currently open
current_dbdir = None
@ -129,6 +134,56 @@ _af_dict = {
socket.AF_UNSPEC: io.PR_AF_UNSPEC
}
def get_proper_tls_version_span(tls_version_min, tls_version_max):
"""
This function checks whether the given TLS versions are known in FreeIPA
and that these versions fulfill the requirements for minimal TLS version
(see `ipalib.constants: TLS_VERSIONS, TLS_VERSION_MINIMAL`).
:param tls_version_min:
the lower value in the TLS min-max span, raised to the lowest allowed
value if too low
:param tls_version_max:
the higher value in the TLS min-max span, raised to tls_version_min
if lower than TLS_VERSION_MINIMAL
:raises: ValueError
"""
min_allowed_idx = TLS_VERSIONS.index(TLS_VERSION_MINIMAL)
try:
min_version_idx = TLS_VERSIONS.index(tls_version_min)
except ValueError:
raise ValueError("tls_version_min ('{val}') is not a known "
"TLS version.".format(val=tls_version_min))
try:
max_version_idx = TLS_VERSIONS.index(tls_version_max)
except ValueError:
raise ValueError("tls_version_max ('{val}') is not a known "
"TLS version.".format(val=tls_version_max))
if min_version_idx > max_version_idx:
raise ValueError("tls_version_min is higher than "
"tls_version_max.")
if min_version_idx < min_allowed_idx:
min_version_idx = min_allowed_idx
logger.warning("tls_version_min set too low ('{old}'),"
"using '{new}' instead"
.format(old=tls_version_min,
new=TLS_VERSIONS[min_version_idx]))
if max_version_idx < min_allowed_idx:
max_version_idx = min_version_idx
logger.warning("tls_version_max set too low ('{old}'),"
"using '{new}' instead"
.format(old=tls_version_max,
new=TLS_VERSIONS[max_version_idx]))
return TLS_VERSIONS[min_version_idx:max_version_idx+1]
class NSSAddressFamilyFallback(object):
def __init__(self, family):
self.sock_family = family
@ -217,8 +272,10 @@ 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)
tls_versions = get_proper_tls_version_span(
tls_version_min, tls_version_max)
self.tls_version_min = tls_versions[0]
self.tls_version_max = tls_versions[-1]
def _create_socket(self):
ssl_enable_renegotiation = getattr(