Skip to content

Commit 9ba6220

Browse files
committed
gh-137197: Add SSLContext.set_ciphersuites to set TLS 1.3 ciphers
1 parent 1150321 commit 9ba6220

File tree

5 files changed

+121
-22
lines changed

5 files changed

+121
-22
lines changed

Doc/library/ssl.rst

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,19 +1684,29 @@ to speed up repeated connections from the same clients.
16841684

16851685
.. method:: SSLContext.set_ciphers(ciphers)
16861686

1687-
Set the available ciphers for sockets created with this context.
1688-
It should be a string in the `OpenSSL cipher list format
1689-
<https://docs.openssl.org/master/man1/ciphers/>`_.
1690-
If no cipher can be selected (because compile-time options or other
1687+
Set the allowed ciphers for sockets created with this context when
1688+
connecting using TLS 1.2 and earlier. It should be a string in the `OpenSSL
1689+
cipher list format <https://docs.openssl.org/master/man1/ciphers/>`_.
1690+
To set allowed TLS 1.3 ciphers, use :meth:`SSHContext.set_ciphersuites`.
1691+
below. If no cipher can be selected (because compile-time options or other
16911692
configuration forbids use of all the specified ciphers), an
16921693
:class:`SSLError` will be raised.
16931694

16941695
.. note::
16951696
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
1696-
give the currently selected cipher.
1697+
return the negotiated cipher and associated TLS version.
16971698

1698-
TLS 1.3 cipher suites cannot be disabled with
1699-
:meth:`~SSLContext.set_ciphers`.
1699+
.. method:: SSLContext.set_ciphersuites(ciphersuites)
1700+
1701+
Set the allowed ciphers for sockets created with this context when
1702+
connecting using TLS 1.3. It should be a colon-separate string of TLS 1.3
1703+
cipher names. If no cipher can be selected (because compile-time options
1704+
or other configuration forbids use of all the specified ciphers), an
1705+
:class:`SSLError` will be raised.
1706+
1707+
.. note::
1708+
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will
1709+
return the negotiated cipher and associated TLS version.
17001710

17011711
.. method:: SSLContext.set_groups(groups)
17021712

@@ -2844,10 +2854,14 @@ TLS 1.3
28442854
The TLS 1.3 protocol behaves slightly differently than previous version
28452855
of TLS/SSL. Some new TLS 1.3 features are not yet available.
28462856

2847-
- TLS 1.3 uses a disjunct set of cipher suites. All AES-GCM and
2848-
ChaCha20 cipher suites are enabled by default. The method
2849-
:meth:`SSLContext.set_ciphers` cannot enable or disable any TLS 1.3
2850-
ciphers yet, but :meth:`SSLContext.get_ciphers` returns them.
2857+
- TLS 1.3 uses a disjunct set of cipher suites. All AES-GCM and ChaCha20
2858+
cipher suites are enabled by default. To restrict which TLS1.3 ciphers
2859+
are allowed, the method :meth:`SSLContext.set_ciphersuites` should be
2860+
called instead of :meth:`SSLContext.set_ciphers`, which only affects
2861+
ciphers in older TLS versions. The method :meth:`SSLContext.get_ciphers`
2862+
returns information about ciphers for both TLS 1.3 and earlier versions
2863+
and the method :meth:`SSLSocket.cipher` returns the negotiated cipher and
2864+
the associated TLS version once a connection is established.
28512865
- Session tickets are no longer sent as part of the initial handshake and
28522866
are handled differently. :attr:`SSLSocket.session` and :class:`SSLSession`
28532867
are not compatible with TLS 1.3.

Doc/whatsnew/3.15.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ ssl
318318

319319
(Contributed by Ron Frederick in :gh:`136306`)
320320

321+
* Added new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3
322+
ciphers and updated the documentation on :meth:`ssl.SSLContext.set_ciphers`
323+
to mention that it only applies to TLS 1.2 and earlier and that this new
324+
method must be used to set TLS 1.3 cipher suites.
325+
(Contributed by Ron Frederick in :gh:`137197`)
321326

322327
tarfile
323328
-------

Lib/test/test_ssl.py

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,9 @@ def utc_offset(): #NOTE: ignore issues like #1647654
260260
)
261261

262262

263-
def test_wrap_socket(sock, *,
264-
cert_reqs=ssl.CERT_NONE, ca_certs=None,
265-
ciphers=None, certfile=None, keyfile=None,
266-
**kwargs):
263+
def test_wrap_socket(sock, *, cert_reqs=ssl.CERT_NONE, ca_certs=None,
264+
ciphers=None, ciphersuites=None, min_version=None,
265+
certfile=None, keyfile=None, **kwargs):
267266
if not kwargs.get("server_side"):
268267
kwargs["server_hostname"] = SIGNED_CERTFILE_HOSTNAME
269268
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
@@ -279,6 +278,10 @@ def test_wrap_socket(sock, *,
279278
context.load_cert_chain(certfile, keyfile)
280279
if ciphers is not None:
281280
context.set_ciphers(ciphers)
281+
if ciphersuites is not None:
282+
context.set_ciphersuites(ciphersuites)
283+
if min_version is not None:
284+
context.minimum_version = min_version
282285
return context.wrap_socket(sock, **kwargs)
283286

284287

@@ -2102,6 +2105,28 @@ def test_ciphers(self):
21022105
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx")
21032106
s.connect(self.server_addr)
21042107

2108+
def test_ciphersuites(self):
2109+
with test_wrap_socket(socket.socket(socket.AF_INET),
2110+
cert_reqs=ssl.CERT_NONE,
2111+
min_version=ssl.TLSVersion.TLSv1_3) as s:
2112+
s.connect(self.server_addr)
2113+
self.assertEqual(s.cipher()[1], "TLSv1.3")
2114+
with test_wrap_socket(socket.socket(socket.AF_INET),
2115+
cert_reqs=ssl.CERT_NONE,
2116+
ciphersuites="TLS_AES_256_GCM_SHA384",
2117+
min_version=ssl.TLSVersion.TLSv1_3) as s:
2118+
s.connect(self.server_addr)
2119+
self.assertEqual(s.cipher(),
2120+
("TLS_AES_256_GCM_SHA384", "TLSv1.3", 256))
2121+
# Error checking can happen at instantiation or when connecting
2122+
with self.assertRaisesRegex(ssl.SSLError,
2123+
"No cipher suite can be selected"):
2124+
with socket.socket(socket.AF_INET) as sock:
2125+
s = test_wrap_socket(sock, cert_reqs=ssl.CERT_NONE,
2126+
ciphersuites="XXX",
2127+
min_version=ssl.TLSVersion.TLSv1_3)
2128+
s.connect(self.server_addr)
2129+
21052130
def test_get_ca_certs_capath(self):
21062131
# capath certs are loaded on request
21072132
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)

Modules/_ssl.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3595,12 +3595,27 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist)
35953595
{
35963596
int ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist);
35973597
if (ret == 0) {
3598-
/* Clearing the error queue is necessary on some OpenSSL versions,
3599-
otherwise the error will be reported again when another SSL call
3600-
is done. */
3601-
ERR_clear_error();
3602-
PyErr_SetString(get_state_ctx(self)->PySSLErrorObject,
3603-
"No cipher can be selected.");
3598+
_setSSLError(get_state_ctx(self), "No cipher can be selected.", 0, __FILE__, __LINE__);
3599+
return NULL;
3600+
}
3601+
Py_RETURN_NONE;
3602+
}
3603+
3604+
/*[clinic input]
3605+
@critical_section
3606+
_ssl._SSLContext.set_ciphersuites
3607+
ciphersuites: str
3608+
/
3609+
[clinic start generated code]*/
3610+
3611+
static PyObject *
3612+
_ssl__SSLContext_set_ciphersuites_impl(PySSLContext *self,
3613+
const char *ciphersuites)
3614+
/*[clinic end generated code: output=9915bec58e54d76d input=2afcc3693392be41]*/
3615+
{
3616+
int ret = SSL_CTX_set_ciphersuites(self->ctx, ciphersuites);
3617+
if (ret == 0) {
3618+
_setSSLError(get_state_ctx(self), "No cipher suite can be selected.", 0, __FILE__, __LINE__);
36043619
return NULL;
36053620
}
36063621
Py_RETURN_NONE;
@@ -5583,6 +5598,7 @@ static struct PyMethodDef context_methods[] = {
55835598
_SSL__SSLCONTEXT__WRAP_SOCKET_METHODDEF
55845599
_SSL__SSLCONTEXT__WRAP_BIO_METHODDEF
55855600
_SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF
5601+
_SSL__SSLCONTEXT_SET_CIPHERSUITES_METHODDEF
55865602
_SSL__SSLCONTEXT_SET_GROUPS_METHODDEF
55875603
_SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF
55885604
_SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF

Modules/clinic/_ssl.c.h

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)