From 3458f2e5193f4cdadfc02ed0a2302915d73ddde3 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Thu, 11 Apr 2024 20:24:17 +0000 Subject: [PATCH 1/6] Only reference PHA functions ifndef OPENSSL_NO_PHA --- Modules/_ssl.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 9d50b576ba337f..076dcd42ae4704 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -187,6 +187,11 @@ extern const SSL_METHOD *TLSv1_2_method(void); #endif +#if defined(OPENSSL_NO_PHA) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) + #define PY_SSL_NO_POST_HS_AUTH +#endif + + enum py_ssl_error { /* these mirror ssl.h */ PY_SSL_ERROR_NONE, @@ -231,7 +236,7 @@ enum py_proto_version { PY_PROTO_TLSv1 = TLS1_VERSION, PY_PROTO_TLSv1_1 = TLS1_1_VERSION, PY_PROTO_TLSv1_2 = TLS1_2_VERSION, -#ifdef TLS1_3_VERSION +#if defined(TLS1_3_VERSION) PY_PROTO_TLSv1_3 = TLS1_3_VERSION, #else PY_PROTO_TLSv1_3 = 0x304, @@ -293,7 +298,7 @@ typedef struct { */ unsigned int hostflags; int protocol; -#ifdef TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) int post_handshake_auth; #endif PyObject *msg_cb; @@ -873,7 +878,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, SSL_set_mode(self->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); -#ifdef TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) if (sslctx->post_handshake_auth == 1) { if (socket_type == PY_SSL_SERVER) { /* bpo-37428: OpenSSL does not ignore SSL_VERIFY_POST_HANDSHAKE. @@ -1016,6 +1021,7 @@ _ssl__SSLSocket_do_handshake_impl(PySSLSocket *self) } while (err.ssl == SSL_ERROR_WANT_READ || err.ssl == SSL_ERROR_WANT_WRITE); Py_XDECREF(sock); + if (ret < 1) return PySSL_SetError(self, __FILE__, __LINE__); if (PySSL_ChainExceptions(self) < 0) @@ -2775,7 +2781,7 @@ static PyObject * _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) /*[clinic end generated code: output=532147f3b1341425 input=6bfa874810a3d889]*/ { -#ifdef TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) int err = SSL_verify_client_post_handshake(self->ssl); if (err == 0) return _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); @@ -3198,7 +3204,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_TRUSTED_FIRST); X509_VERIFY_PARAM_set_hostflags(params, self->hostflags); -#ifdef TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) self->post_handshake_auth = 0; SSL_CTX_set_post_handshake_auth(self->ctx, self->post_handshake_auth); #endif @@ -3576,7 +3582,7 @@ set_maximum_version(PySSLContext *self, PyObject *arg, void *c) return set_min_max_proto_version(self, arg, 1); } -#ifdef TLS1_3_VERSION +#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) static PyObject * get_num_tickets(PySSLContext *self, void *c) { @@ -3607,7 +3613,7 @@ set_num_tickets(PySSLContext *self, PyObject *arg, void *c) PyDoc_STRVAR(PySSLContext_num_tickets_doc, "Control the number of TLSv1.3 session tickets"); -#endif /* TLS1_3_VERSION */ +#endif /* defined(TLS1_3_VERSION) */ static PyObject * get_security_level(PySSLContext *self, void *c) @@ -3710,14 +3716,14 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c) static PyObject * get_post_handshake_auth(PySSLContext *self, void *c) { -#if TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) return PyBool_FromLong(self->post_handshake_auth); #else Py_RETURN_NONE; #endif } -#if TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) static int set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) { if (arg == NULL) { @@ -4959,14 +4965,14 @@ static PyGetSetDef context_getsetlist[] = { (setter) _PySSLContext_set_msg_callback, NULL}, {"sni_callback", (getter) get_sni_callback, (setter) set_sni_callback, PySSLContext_sni_callback_doc}, -#ifdef TLS1_3_VERSION +#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) {"num_tickets", (getter) get_num_tickets, (setter) set_num_tickets, PySSLContext_num_tickets_doc}, #endif {"options", (getter) get_options, (setter) set_options, NULL}, {"post_handshake_auth", (getter) get_post_handshake_auth, -#ifdef TLS1_3_VERSION +#if !defined(PY_SSL_NO_POST_HS_AUTH) (setter) set_post_handshake_auth, #else NULL, From fdfa6dfcc3cc457665a97782c54dfd7bf45759f1 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Thu, 11 Apr 2024 21:48:33 +0000 Subject: [PATCH 2/6] Adjust PSK tests to use testing_context() --- Lib/test/test_ssl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 6ec010d13f9e7e..47813381bb3529 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -4364,14 +4364,14 @@ def test_session_handling(self): def test_psk(self): psk = bytes.fromhex('deadbeef') - client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_context, server_context, _ = testing_context() + client_context.check_hostname = False client_context.verify_mode = ssl.CERT_NONE client_context.maximum_version = ssl.TLSVersion.TLSv1_2 client_context.set_ciphers('PSK') client_context.set_psk_client_callback(lambda hint: (None, psk)) - server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context.maximum_version = ssl.TLSVersion.TLSv1_2 server_context.set_ciphers('PSK') server_context.set_psk_server_callback(lambda identity: psk) @@ -4443,14 +4443,14 @@ def server_callback(identity): self.assertEqual(identity, client_identity) return psk - client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_context, server_context, _ = testing_context() + client_context.check_hostname = False client_context.verify_mode = ssl.CERT_NONE client_context.minimum_version = ssl.TLSVersion.TLSv1_3 client_context.set_ciphers('PSK') client_context.set_psk_client_callback(client_callback) - server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context.minimum_version = ssl.TLSVersion.TLSv1_3 server_context.set_ciphers('PSK') server_context.set_psk_server_callback(server_callback, identity_hint) From 3909fe46481e0c2ed110fb3818f9c0a11bf9d640 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Wed, 17 Apr 2024 23:56:53 +0000 Subject: [PATCH 3/6] Rename OPENSSL_NO_PHA to OPENSSL_NO_TLS_PHA --- Modules/_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 076dcd42ae4704..154feab60d2ffd 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -187,7 +187,7 @@ extern const SSL_METHOD *TLSv1_2_method(void); #endif -#if defined(OPENSSL_NO_PHA) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) +#if defined(OPENSSL_NO_TLS_PHA) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) #define PY_SSL_NO_POST_HS_AUTH #endif From 6743dc085004fd03c47ecab895a329516016d011 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Wed, 26 Jun 2024 14:52:26 +0000 Subject: [PATCH 4/6] Replace OPENSSL_NO_TLS_PHA with SSL_VERIFY_POST_HANDSHAKE --- Modules/_ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 154feab60d2ffd..24a9e1d2ff4f8d 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -187,7 +187,7 @@ extern const SSL_METHOD *TLSv1_2_method(void); #endif -#if defined(OPENSSL_NO_TLS_PHA) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) +#if !defined(SSL_VERIFY_POST_HANDSHAKE) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) #define PY_SSL_NO_POST_HS_AUTH #endif From 57b4d6d7ac8ebd5d6f44107e430a7dbe5b1f2cda Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Wed, 26 Jun 2024 17:00:40 +0000 Subject: [PATCH 5/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst diff --git a/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst b/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst new file mode 100644 index 00000000000000..3f576eebc9a85d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-06-26-17-00-39.gh-issue-117784.inCtAV.rst @@ -0,0 +1 @@ +CPython now detects whether its linked TLS library supports TLSv1.3 post-handshake authentication and disables that feature if support is lacking. From 082e7d6192ad1c3c06ef362f0b263f68087452f9 Mon Sep 17 00:00:00 2001 From: WillChilds-Klein Date: Fri, 28 Jun 2024 22:14:38 +0000 Subject: [PATCH 6/6] Address PR feedback --- Lib/test/test_ssl.py | 8 ++++---- Modules/_ssl.c | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py index 47813381bb3529..6ec010d13f9e7e 100644 --- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -4364,14 +4364,14 @@ def test_session_handling(self): def test_psk(self): psk = bytes.fromhex('deadbeef') - client_context, server_context, _ = testing_context() - + client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) client_context.check_hostname = False client_context.verify_mode = ssl.CERT_NONE client_context.maximum_version = ssl.TLSVersion.TLSv1_2 client_context.set_ciphers('PSK') client_context.set_psk_client_callback(lambda hint: (None, psk)) + server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context.maximum_version = ssl.TLSVersion.TLSv1_2 server_context.set_ciphers('PSK') server_context.set_psk_server_callback(lambda identity: psk) @@ -4443,14 +4443,14 @@ def server_callback(identity): self.assertEqual(identity, client_identity) return psk - client_context, server_context, _ = testing_context() - + client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) client_context.check_hostname = False client_context.verify_mode = ssl.CERT_NONE client_context.minimum_version = ssl.TLSVersion.TLSv1_3 client_context.set_ciphers('PSK') client_context.set_psk_client_callback(client_callback) + server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) server_context.minimum_version = ssl.TLSVersion.TLSv1_3 server_context.set_ciphers('PSK') server_context.set_psk_server_callback(server_callback, identity_hint) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index 24a9e1d2ff4f8d..ffe29673d0929e 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -187,8 +187,8 @@ extern const SSL_METHOD *TLSv1_2_method(void); #endif -#if !defined(SSL_VERIFY_POST_HANDSHAKE) || !defined(TLS1_3_VERSION) || defined(OPENSSL_NO_TLS1_3) - #define PY_SSL_NO_POST_HS_AUTH +#if defined(SSL_VERIFY_POST_HANDSHAKE) && defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3) + #define PySSL_HAVE_POST_HS_AUTH #endif @@ -298,7 +298,7 @@ typedef struct { */ unsigned int hostflags; int protocol; -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) int post_handshake_auth; #endif PyObject *msg_cb; @@ -878,7 +878,7 @@ newPySSLSocket(PySSLContext *sslctx, PySocketSockObject *sock, SSL_set_mode(self->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_AUTO_RETRY); -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) if (sslctx->post_handshake_auth == 1) { if (socket_type == PY_SSL_SERVER) { /* bpo-37428: OpenSSL does not ignore SSL_VERIFY_POST_HANDSHAKE. @@ -2781,7 +2781,7 @@ static PyObject * _ssl__SSLSocket_verify_client_post_handshake_impl(PySSLSocket *self) /*[clinic end generated code: output=532147f3b1341425 input=6bfa874810a3d889]*/ { -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) int err = SSL_verify_client_post_handshake(self->ssl); if (err == 0) return _setSSLError(get_state_sock(self), NULL, 0, __FILE__, __LINE__); @@ -3204,7 +3204,7 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version) X509_VERIFY_PARAM_set_flags(params, X509_V_FLAG_TRUSTED_FIRST); X509_VERIFY_PARAM_set_hostflags(params, self->hostflags); -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) self->post_handshake_auth = 0; SSL_CTX_set_post_handshake_auth(self->ctx, self->post_handshake_auth); #endif @@ -3716,14 +3716,14 @@ set_check_hostname(PySSLContext *self, PyObject *arg, void *c) static PyObject * get_post_handshake_auth(PySSLContext *self, void *c) { -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) return PyBool_FromLong(self->post_handshake_auth); #else Py_RETURN_NONE; #endif } -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) static int set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) { if (arg == NULL) { @@ -4972,7 +4972,7 @@ static PyGetSetDef context_getsetlist[] = { {"options", (getter) get_options, (setter) set_options, NULL}, {"post_handshake_auth", (getter) get_post_handshake_auth, -#if !defined(PY_SSL_NO_POST_HS_AUTH) +#if defined(PySSL_HAVE_POST_HS_AUTH) (setter) set_post_handshake_auth, #else NULL,