Skip to content

Commit

Permalink
fix tls_(min|max)_version having no effect on openssl 1.1.0g or lower (
Browse files Browse the repository at this point in the history
  • Loading branch information
graingert authored Jun 15, 2022
1 parent 344868a commit 085f300
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 3 deletions.
63 changes: 60 additions & 3 deletions distributed/security.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,68 @@
from __future__ import annotations

import datetime
import os
import sys
import tempfile
import warnings

try:
import ssl
except ImportError:
ssl = None # type: ignore

try:
from ssl import OPENSSL_VERSION_INFO as _OPENSSL_VERSION_INFO
except ImportError:
_OPENSSL_VERSION_INFO = (0, 0, 0, 0, 0)

import dask
from dask.widgets import get_template

__all__ = ("Security",)


if sys.version_info >= (3, 10) or _OPENSSL_VERSION_INFO >= (1, 1, 0, 7):
# The OP_NO_SSL* and OP_NO_TLS* become deprecated in favor of
# 'SSLContext.minimum_version' from Python 3.7 onwards, however
# this attribute is not available unless the ssl module is compiled
# with OpenSSL 1.1.0g or newer.
# https://docs.python.org/3.10/library/ssl.html#ssl.SSLContext.minimum_version
# https://docs.python.org/3.7/library/ssl.html#ssl.SSLContext.minimum_version

# these _set_mimimun_version and _set_maximum_version depend on the validation
# already performed in `Security._set_tls_version_field`,
# and that they only apply to freshly created ssl.SSLContext instances in
# _get_tls_context
def _set_minimum_version(ctx: ssl.SSLContext, version: ssl.TLSVersion) -> None:
ctx.minimum_version = version

def _set_maximum_version(ctx: ssl.SSLContext, version: ssl.TLSVersion) -> None:
ctx.maximum_version = version

else:

def _set_minimum_version(ctx: ssl.SSLContext, version: ssl.TLSVersion) -> None:
# if the ctx.maximum_version attribute is unsupported then we can infer
# that TLS 1.3 is not supported.
# _set_tls_version_field enforces that version is TLSVersion.TLSv1_2,
# or TLSVersion.TLSv1_3
if version is not ssl.TLSVersion.TLSv1_2:
raise ValueError(f"Unsupported TLS/SSL version: {version!r}")
ctx.options |= (
ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3 | ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1
)

def _set_maximum_version(ctx: ssl.SSLContext, version: ssl.TLSVersion) -> None:
# if the ctx.maximum_version attribute is unsupported then we can infer
# that TLSv1_3 is not supported.
# _set_tls_version_field enforces that version is TLSVersion.TLSv1_2,
# TLSVersion.TLSv1_3, or None
# _get_tls_context enforces that version is not None
if version is not ssl.TLSVersion.TLSv1_2:
raise ValueError(f"Unsupported TLS/SSL version: {version!r}")


class Security:
"""Security configuration for a Dask cluster.
Expand Down Expand Up @@ -71,6 +121,12 @@ class Security:
)

def __init__(self, require_encryption=None, **kwargs):
if _OPENSSL_VERSION_INFO < (1, 1, 1):
warnings.warn(
f"support for {ssl.OPENSSL_VERSION} is deprecated,"
" and will be removed in a future release",
DeprecationWarning,
)
extra = set(kwargs).difference(self.__slots__)
if extra:
raise TypeError("Unknown parameters: %r" % sorted(extra))
Expand Down Expand Up @@ -251,10 +307,11 @@ def _get_tls_context(self, tls, purpose):
else:
ctx = ssl.create_default_context(purpose=purpose, cafile=ca)

if self.tls_min_version is not None:
ctx.minimum_version = self.tls_min_version
# the _set_tls_version_field method enforces that
# self.tls_min_version is TLSv1_2, or TLSv1_3
_set_minimum_version(ctx, self.tls_min_version)
if self.tls_max_version is not None:
ctx.maximum_version = self.tls_max_version
_set_maximum_version(ctx, self.tls_max_version)

cert_in_memory = "\n" in cert
key_in_memory = key is not None and "\n" in key
Expand Down
8 changes: 8 additions & 0 deletions distributed/tests/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@ def test_min_max_version_config_errors(field):
sec = Security()


def test_invalid_min_version_from_config_errors():
with dask.config.set({"distributed.comm.tls.min-version": None}):
with pytest.raises(
ValueError, match=r"tls_min_version=.* is not supported, expected one of .*"
):
Security(tls_min_version=ssl.TLSVersion.MINIMUM_SUPPORTED)


def test_kwargs():
c = {
"distributed.comm.tls.ca-file": "ca.pem",
Expand Down

0 comments on commit 085f300

Please sign in to comment.