|
|
@@ -2,6 +2,7 @@
|
|
|
# Copyright © 2014 Jean-Marc Martins
|
|
|
# Copyright © 2012-2017 Guillaume Ayoub
|
|
|
# Copyright © 2017-2018 Unrud <unrud@outlook.com>
|
|
|
+# Copyright © 2024-2024 Peter Bieringer <pb@bieringer.de>
|
|
|
#
|
|
|
# This library is free software: you can redistribute it and/or modify
|
|
|
# it under the terms of the GNU General Public License as published by
|
|
|
@@ -18,6 +19,7 @@
|
|
|
|
|
|
from importlib import import_module, metadata
|
|
|
from typing import Callable, Sequence, Type, TypeVar, Union
|
|
|
+import ssl
|
|
|
|
|
|
from radicale import config
|
|
|
from radicale.log import logger
|
|
|
@@ -47,3 +49,110 @@ def load_plugin(internal_types: Sequence[str], module_name: str,
|
|
|
|
|
|
def package_version(name):
|
|
|
return metadata.version(name)
|
|
|
+
|
|
|
+
|
|
|
+def ssl_context_options_by_protocol(protocol: str, ssl_context_options):
|
|
|
+ logger.debug("SSL protocol string: '%s' and current SSL context options: '0x%x'", protocol, ssl_context_options)
|
|
|
+ # disable any protocol by default
|
|
|
+ logger.debug("SSL context options, disable ALL by default")
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv2
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv3
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_1
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_2
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_3
|
|
|
+ logger.debug("SSL cleared SSL context options: '0x%x'", ssl_context_options)
|
|
|
+ for entry in protocol.split():
|
|
|
+ entry = entry.strip('+') # remove trailing '+'
|
|
|
+ if entry == "ALL":
|
|
|
+ logger.debug("SSL context options, enable ALL (some maybe not supported by underlying OpenSSL, SSLv2 not enabled at all)")
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_SSLv3
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_1
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_2
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_3
|
|
|
+ elif entry == "SSLv2":
|
|
|
+ logger.notice("SSL context options, ignore SSLv2 (totally insecure)")
|
|
|
+ elif entry == "SSLv3":
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_SSLv3
|
|
|
+ logger.debug("SSL context options, enable SSLv3 (maybe not supported by underlying OpenSSL)")
|
|
|
+ elif entry == "TLSv1":
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1
|
|
|
+ logger.debug("SSL context options, enable TLSv1 (maybe not supported by underlying OpenSSL)")
|
|
|
+ elif entry == "TLSv1.1":
|
|
|
+ logger.debug("SSL context options, enable TLSv1.1 (maybe not supported by underlying OpenSSL)")
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_1
|
|
|
+ elif entry == "TLSv1.2":
|
|
|
+ logger.debug("SSL context options, enable TLSv1.2")
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_2
|
|
|
+ elif entry == "TLSv1.3":
|
|
|
+ logger.debug("SSL context options, enable TLSv1.3")
|
|
|
+ ssl_context_options &= ~ssl.OP_NO_TLSv1_3
|
|
|
+ elif entry == "-ALL":
|
|
|
+ logger.debug("SSL context options, disable ALL")
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv2
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv3
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_1
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_2
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_3
|
|
|
+ elif entry == "-SSLv2":
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv2
|
|
|
+ logger.debug("SSL context options, disable SSLv2")
|
|
|
+ elif entry == "-SSLv3":
|
|
|
+ ssl_context_options |= ssl.OP_NO_SSLv3
|
|
|
+ logger.debug("SSL context options, disable SSLv3")
|
|
|
+ elif entry == "-TLSv1":
|
|
|
+ logger.debug("SSL context options, disable TLSv1")
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1
|
|
|
+ elif entry == "-TLSv1.1":
|
|
|
+ logger.debug("SSL context options, disable TLSv1.1")
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_1
|
|
|
+ elif entry == "-TLSv1.2":
|
|
|
+ logger.debug("SSL context options, disable TLSv1.2")
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_2
|
|
|
+ elif entry == "-TLSv1.3":
|
|
|
+ logger.debug("SSL context options, disable TLSv1.3")
|
|
|
+ ssl_context_options |= ssl.OP_NO_TLSv1_3
|
|
|
+ else:
|
|
|
+ logger.error("SSL protocol string: '%s' contain unsupported entry: '%s'", protocol, entry)
|
|
|
+
|
|
|
+ logger.debug("SSL resulting context options: '0x%x'", ssl_context_options)
|
|
|
+ return ssl_context_options
|
|
|
+
|
|
|
+
|
|
|
+def ssl_context_minimum_version_by_options(ssl_context_options):
|
|
|
+ logger.debug("SSL calculate minimum version by context options: '0x%x'", ssl_context_options)
|
|
|
+ ssl_context_minimum_version = 0 # default
|
|
|
+ if ((ssl_context_options & ssl.OP_NO_SSLv3) and (ssl_context_minimum_version == 0)):
|
|
|
+ ssl_context_minimum_version = ssl.TLSVersion.TLSv1
|
|
|
+ if ((ssl_context_options & ssl.OP_NO_TLSv1) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1)):
|
|
|
+ ssl_context_minimum_version = ssl.TLSVersion.TLSv1_1
|
|
|
+ if ((ssl_context_options & ssl.OP_NO_TLSv1_1) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_1)):
|
|
|
+ ssl_context_minimum_version = ssl.TLSVersion.TLSv1_2
|
|
|
+ if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_2)):
|
|
|
+ ssl_context_minimum_version = ssl.TLSVersion.TLSv1_3
|
|
|
+ if (ssl_context_minimum_version == 0):
|
|
|
+ ssl_context_minimum_version = ssl.TLSVersion.SSLv3 # default
|
|
|
+
|
|
|
+ logger.debug("SSL context options: '0x%x' results in minimum version: %s", ssl_context_options, ssl_context_minimum_version)
|
|
|
+ return ssl_context_minimum_version
|
|
|
+
|
|
|
+
|
|
|
+def ssl_get_protocols(context):
|
|
|
+ protocols = []
|
|
|
+ if not (context.options & ssl.OP_NO_SSLv3):
|
|
|
+ if (context.minimum_version < ssl.TLSVersion.TLSv1):
|
|
|
+ protocols.append("SSLv3")
|
|
|
+ if not (context.options & ssl.OP_NO_TLSv1):
|
|
|
+ if (context.minimum_version < ssl.TLSVersion.TLSv1_1):
|
|
|
+ protocols.append("TLSv1")
|
|
|
+ if not (context.options & ssl.OP_NO_TLSv1_1):
|
|
|
+ if (context.minimum_version < ssl.TLSVersion.TLSv1_2):
|
|
|
+ protocols.append("TLSv1.1")
|
|
|
+ if not (context.options & ssl.OP_NO_TLSv1_2):
|
|
|
+ if (context.minimum_version < ssl.TLSVersion.TLSv1_3):
|
|
|
+ protocols.append("TLSv1.2")
|
|
|
+ if not (context.options & ssl.OP_NO_TLSv1_3):
|
|
|
+ protocols.append("TLSv1.3")
|
|
|
+ return protocols
|