-
Notifications
You must be signed in to change notification settings - Fork 450
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1624 from pbiering/ssl-config
SSL socket protocol + ciphersuite option
- Loading branch information
Showing
7 changed files
with
188 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
# Copyright © 2014 Jean-Marc Martins | ||
# Copyright © 2012-2017 Guillaume Ayoub | ||
# Copyright © 2017-2018 Unrud <[email protected]> | ||
# Copyright © 2024-2024 Peter Bieringer <[email protected]> | ||
# | ||
# 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 | ||
|
@@ -16,6 +17,7 @@ | |
# You should have received a copy of the GNU General Public License | ||
# along with Radicale. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
import ssl | ||
from importlib import import_module, metadata | ||
from typing import Callable, Sequence, Type, TypeVar, Union | ||
|
||
|
@@ -47,3 +49,129 @@ 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.warning("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: | ||
raise RuntimeError("SSL protocol config contains unsupported entry '%s'" % (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 = ssl.TLSVersion.SSLv3 # default | ||
if ((ssl_context_options & ssl.OP_NO_SSLv3) and (ssl_context_minimum_version == ssl.TLSVersion.SSLv3)): | ||
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_options & ssl.OP_NO_TLSv1_3) and (ssl_context_minimum_version == ssl.TLSVersion.TLSv1_3)): | ||
ssl_context_minimum_version = 0 # all disabled | ||
|
||
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_context_maximum_version_by_options(ssl_context_options): | ||
logger.debug("SSL calculate maximum version by context options: '0x%x'", ssl_context_options) | ||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_3 # default | ||
if ((ssl_context_options & ssl.OP_NO_TLSv1_3) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_3)): | ||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_2 | ||
if ((ssl_context_options & ssl.OP_NO_TLSv1_2) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_2)): | ||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1_1 | ||
if ((ssl_context_options & ssl.OP_NO_TLSv1_1) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1_1)): | ||
ssl_context_maximum_version = ssl.TLSVersion.TLSv1 | ||
if ((ssl_context_options & ssl.OP_NO_TLSv1) and (ssl_context_maximum_version == ssl.TLSVersion.TLSv1)): | ||
ssl_context_maximum_version = ssl.TLSVersion.SSLv3 | ||
if ((ssl_context_options & ssl.OP_NO_SSLv3) and (ssl_context_maximum_version == ssl.TLSVersion.SSLv3)): | ||
ssl_context_maximum_version = 0 | ||
|
||
logger.debug("SSL context options: '0x%x' results in maximum version: %s", ssl_context_options, ssl_context_maximum_version) | ||
return ssl_context_maximum_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) and (context.maximum_version >= ssl.TLSVersion.TLSv1): | ||
protocols.append("TLSv1") | ||
if not (context.options & ssl.OP_NO_TLSv1_1): | ||
if (context.minimum_version < ssl.TLSVersion.TLSv1_2) and (context.maximum_version >= ssl.TLSVersion.TLSv1_1): | ||
protocols.append("TLSv1.1") | ||
if not (context.options & ssl.OP_NO_TLSv1_2): | ||
if (context.minimum_version <= ssl.TLSVersion.TLSv1_2) and (context.maximum_version >= ssl.TLSVersion.TLSv1_2): | ||
protocols.append("TLSv1.2") | ||
if not (context.options & ssl.OP_NO_TLSv1_3): | ||
if (context.minimum_version <= ssl.TLSVersion.TLSv1_3) and (context.maximum_version >= ssl.TLSVersion.TLSv1_3): | ||
protocols.append("TLSv1.3") | ||
return protocols |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters