From 39218cf88f69107be32d226e843d6a7754496c25 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 15 Jul 2025 12:34:50 +0200 Subject: [PATCH] Add ability to TLS 1.3 cipher suites on SSL Context --- CHANGELOG.rst | 13 +++++++++++++ src/OpenSSL/SSL.py | 26 ++++++++++++++++++++++++++ tests/test_ssl.py | 14 ++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d98901f3..6505e879 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -3,6 +3,19 @@ Changelog Versions are year-based with a strict backward-compatibility policy. The third digit is only for regressions. +UNRELEASED +---------- + +Backward-incompatible changes: +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Deprecations: +^^^^^^^^^^^^^ + +Changes: +^^^^^^^^ + +- Added ``OpenSSL.SSL.Context.set_tls13_ciphersuites`` that allows the allowed TLS 1.3 ciphers. 25.1.0 (2025-05-17) ------------------- diff --git a/src/OpenSSL/SSL.py b/src/OpenSSL/SSL.py index 81774c85..b4aa78c8 100644 --- a/src/OpenSSL/SSL.py +++ b/src/OpenSSL/SSL.py @@ -1469,6 +1469,9 @@ def set_cipher_list(self, cipher_list: bytes) -> None: See the OpenSSL manual for more information (e.g. :manpage:`ciphers(1)`). + Note this API does not change the cipher suites used in TLS 1.3 + Use `set_tls13_ciphersuites` for that. + :param bytes cipher_list: An OpenSSL cipher string. :return: None """ @@ -1501,6 +1504,29 @@ def set_cipher_list(self, cipher_list: bytes) -> None: ], ) + @_require_not_used + def set_tls13_ciphersuites(self, ciphersuites: bytes) -> None: + """ + Set the list of TLS 1.3 ciphers to be used in this context. + OpenSSL maintains a separate list of TLS 1.3+ ciphers to + ciphers for TLS 1.2 and lowers. + + See the OpenSSL manual for more information (e.g. + :manpage:`ciphers(1)`). + + :param bytes ciphersuites: An OpenSSL cipher string containing + TLS 1.3+ ciphersuites. + :return: None + + .. versionadded:: 25.2.0 + """ + if not isinstance(ciphersuites, bytes): + raise TypeError("ciphersuites must be a byte string.") + + _openssl_assert( + _lib.SSL_CTX_set_ciphersuites(self._context, ciphersuites) == 1 + ) + @_require_not_used def set_client_ca_list( self, certificate_authorities: Sequence[X509Name] diff --git a/tests/test_ssl.py b/tests/test_ssl.py index bcad6d96..4059618b 100644 --- a/tests/test_ssl.py +++ b/tests/test_ssl.py @@ -512,6 +512,20 @@ def test_set_cipher_list( assert "AES128-SHA" in conn.get_cipher_list() + def test_set_tls13_ciphersuites(self, context: Context) -> None: + """ + `Context.set_tls13_ciphersuites` accepts both byte and unicode strings + for naming the ciphers which connections created with the context + object will be able to choose from. + """ + context.set_tls13_ciphersuites(b"TLS_AES_128_GCM_SHA256") + conn = Connection(context, None) + + # OpenSSL has different APIs for *setting* TLS <=1.2 and >= 1.3 + # but only one API for retrieving them + assert "TLS_AES_128_GCM_SHA256" in conn.get_cipher_list() + assert "TLS_AES_256_GCM_SHA384" not in conn.get_cipher_list() + def test_set_cipher_list_wrong_type(self, context: Context) -> None: """ `Context.set_cipher_list` raises `TypeError` when passed a non-string