-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
gh-137197: Add SSLContext.set_ciphersuites to set TLS 1.3 ciphers #137198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@@ -3595,12 +3595,27 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist) | |||
{ | |||
int ret = SSL_CTX_set_cipher_list(self->ctx, cipherlist); | |||
if (ret == 0) { | |||
/* Clearing the error queue is necessary on some OpenSSL versions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't remove this without understanding which OpenSSL versions it was referring to and whether they are still in use by CPython builds (1.1.x-ish API'd AWS-LC at a minimum, otherwise OpenSSL 3.0+).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The clearing of the error queue is still happening here. I just took advantage of an existing helper function setSSLError
to take care of this:
static PyObject *
_setSSLError (_sslmodulestate *state, const char *errstr, int errcode, const char *filename, int lineno)
{
if (errstr == NULL)
errcode = ERR_peek_last_error();
else
errcode = 0;
fill_and_set_sslerror(state, NULL, state->PySSLErrorObject, errcode, errstr, lineno, errcode);
ERR_clear_error();
return NULL;
}
Doc/whatsnew/3.15.rst
Outdated
* Added new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3 | ||
ciphers and updated the documentation on :meth:`ssl.SSLContext.set_ciphers` | ||
to mention that it only applies to TLS 1.2 and earlier and that this new | ||
method must be used to set TLS 1.3 cipher suites. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Added new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3 | |
ciphers and updated the documentation on :meth:`ssl.SSLContext.set_ciphers` | |
to mention that it only applies to TLS 1.2 and earlier and that this new | |
method must be used to set TLS 1.3 cipher suites. | |
* Added new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3 | |
ciphers. For TLS 1.2 or earlier, use :meth:`ssl.SSLContext.set_ciphers` instead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about changing the text here to something like:
* Added new method :meth:`ssl.SSLContext.set_ciphersuites` for setting TLS 1.3
ciphers. For TLS 1.2 or earlier, :meth:`ssl.SSLContext.set_ciphers` should
continue to be used. Both calls can be made on the same context and the
selected cipher suite will depend on the TLS version negotiated when a
connection is made.
I wanted to somehow capture that these calls aren't mutually exclusive if you don't know in advance what version of TLS will end up being used. The existing call only affects cipher suites chosen when TLS 1.2 or earlier is negotiated, and the new call only affects cipher suites chosen when TLS 1.3 is negotiated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@picnixz, are you ok with this new wording?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've checked in the new wording I proposed. Let me know if you want any changes here.
I think this change may be ready to go if there are no other review comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I forgot about this PR and I missed the notification I think. Let me have a look again.
Clarify when to use the original set_ciphers (TLS 1.2 and earlier) vs. the new set_ciphersuites (TLS 1.3) methods and that both can be used at once.
f2cda88
to
d3375f1
Compare
<https://docs.openssl.org/master/man1/ciphers/>`_. | ||
If no cipher can be selected (because compile-time options or other | ||
Set the allowed ciphers for sockets created with this context when | ||
connecting using TLS 1.2 and earlier. It should be a string in the `OpenSSL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
connecting using TLS 1.2 and earlier. It should be a string in the `OpenSSL | |
connecting using TLS 1.2 and earlier. *ciphers* should be a string in the `OpenSSL |
I think it's better to say what's "it" is. I personally understand but removing any possible ambiguity would be better anyway. Up to you though. Same for ciphersuites below
To set allowed TLS 1.3 ciphers, use :meth:`SSLContext.set_ciphersuites`. | ||
below. If no cipher can be selected (because compile-time options or other |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To set allowed TLS 1.3 ciphers, use :meth:`SSLContext.set_ciphersuites`. | |
below. If no cipher can be selected (because compile-time options or other | |
To set allowed TLS 1.3 ciphers, use :meth:`SSLContext.set_ciphersuites`. | |
If no cipher can be selected (because compile-time options or other |
configuration forbids use of all the specified ciphers), an | ||
:class:`SSLError` will be raised. | ||
|
||
.. note:: | ||
when connected, the :meth:`SSLSocket.cipher` method of SSL sockets will | ||
give the currently selected cipher. | ||
return the negotiated cipher and associated TLS version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The docstring actually says:
"""Return the currently selected cipher as a 3-tuple ``(name,
ssl_version, secret_bits)``."""
So it's not a pair but a triplet that is being returned (that's how it's implemented in C). I suggest that we make this doc change in a separate PR.
cert_reqs=ssl.CERT_NONE, ca_certs=None, | ||
ciphers=None, certfile=None, keyfile=None, | ||
**kwargs): | ||
def test_wrap_socket(sock, *, cert_reqs=ssl.CERT_NONE, ca_certs=None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe revert the linebreak changes (namely keep sock, *
on its own line) and just add ciphersuites
and min_version
after ciphers
, and put certfile
and keyfile
on their own lines as well.
min_version=ssl.TLSVersion.TLSv1_3) as s: | ||
s.connect(self.server_addr) | ||
self.assertEqual(s.cipher()[1], "TLSv1.3") | ||
with test_wrap_socket(socket.socket(socket.AF_INET), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about builds that don't support TLS 1.3?
@@ -2109,6 +2112,28 @@ def test_ciphers(self): | |||
cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") | |||
s.connect(self.server_addr) | |||
|
|||
def test_ciphersuites(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we ensure that this test is run for builds with TLS 1.3?
s.connect(self.server_addr) | ||
self.assertEqual(s.cipher(), | ||
("TLS_AES_256_GCM_SHA384", "TLSv1.3", 256)) | ||
# Error checking can happen at instantiation or when connecting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When does it happen upon instantiation and when does it happen while connecting? is it possible to only raise when we do s.connect
or only raise when we create the socket?
This commit adds a new method SSLContext.set_ciphersuites which can be used to set TLS 1.3 cipher suites. It also updates the documentation, unit tests, and "what's new" text. A NEWS blurb will be added shortly.
📚 Documentation preview 📚: https://cpython-previews--137198.org.readthedocs.build/