]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-112454: Disable TLS-PSK if OpenSSL was built without PSK support (#112491)
authorGrant Ramsay <grant.ramsay@hotmail.com>
Wed, 29 Nov 2023 00:15:39 +0000 (13:15 +1300)
committerGitHub <noreply@github.com>
Wed, 29 Nov 2023 00:15:39 +0000 (16:15 -0800)
If OpenSSL was built without PSK support, the python TLS-PSK
methods will raise "NotImplementedError" if called.

Add a constant "ssl.HAS_PSK" to check if TLS-PSK is supported

Doc/library/ssl.rst
Lib/ssl.py
Lib/test/test_ssl.py
Modules/_ssl.c

index 206294528e0016222702a7083298ef6d8ad1e852..0db233e2dde33c01d3c75e43b3242aac4510365c 100644 (file)
@@ -908,6 +908,12 @@ Constants
 
    .. versionadded:: 3.7
 
+.. data:: HAS_PSK
+
+   Whether the OpenSSL library has built-in support for TLS-PSK.
+
+   .. versionadded:: 3.13
+
 .. data:: CHANNEL_BINDING_TYPES
 
    List of supported TLS channel binding types.  Strings in this list
@@ -2050,6 +2056,9 @@ to speed up repeated connections from the same clients.
           return 'ClientId_1', psk_table.get(hint, b'')
       context.set_psk_client_callback(callback)
 
+   This method will raise :exc:`NotImplementedError` if :data:`HAS_PSK` is
+   ``False``.
+
    .. versionadded:: 3.13
 
 .. method:: SSLContext.set_psk_server_callback(callback, identity_hint=None)
@@ -2092,6 +2101,9 @@ to speed up repeated connections from the same clients.
           return psk_table.get(identity, b'')
       context.set_psk_server_callback(callback, 'ServerId_1')
 
+   This method will raise :exc:`NotImplementedError` if :data:`HAS_PSK` is
+   ``False``.
+
    .. versionadded:: 3.13
 
 .. index:: single: certificates
index 36fca9d4aa93d13f52ddfd0a55b54b7a4c6e382b..d01484964b68956f89ecb81aac44b613b1ea0655 100644 (file)
@@ -116,7 +116,7 @@ except ImportError:
 
 from _ssl import (
     HAS_SNI, HAS_ECDH, HAS_NPN, HAS_ALPN, HAS_SSLv2, HAS_SSLv3, HAS_TLSv1,
-    HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3
+    HAS_TLSv1_1, HAS_TLSv1_2, HAS_TLSv1_3, HAS_PSK
 )
 from _ssl import _DEFAULT_CIPHERS, _OPENSSL_API_VERSION
 
index aecba89cde1495b7310aa474cef99c942d5e6969..3fdfa2960503b8fc126845c7d05421556a5fd683 100644 (file)
@@ -4259,6 +4259,7 @@ class ThreadedTests(unittest.TestCase):
                                  'Session refers to a different SSLContext.')
 
     @requires_tls_version('TLSv1_2')
+    @unittest.skipUnless(ssl.HAS_PSK, 'TLS-PSK disabled on this OpenSSL build')
     def test_psk(self):
         psk = bytes.fromhex('deadbeef')
 
@@ -4326,6 +4327,7 @@ class ThreadedTests(unittest.TestCase):
                 s.connect((HOST, server.port))
 
     @requires_tls_version('TLSv1_3')
+    @unittest.skipUnless(ssl.HAS_PSK, 'TLS-PSK disabled on this OpenSSL build')
     def test_psk_tls1_3(self):
         psk = bytes.fromhex('deadbeef')
         identity_hint = 'identity-hint'
index 707e7ad9543acb679d9296b0d250040163677975..90b600f4b776a3c48836b12a3ebf1d44f24c3ff0 100644 (file)
@@ -301,8 +301,10 @@ typedef struct {
     BIO *keylog_bio;
     /* Cached module state, also used in SSLSocket and SSLSession code. */
     _sslmodulestate *state;
+#ifndef OPENSSL_NO_PSK
     PyObject *psk_client_callback;
     PyObject *psk_server_callback;
+#endif
 } PySSLContext;
 
 typedef struct {
@@ -3125,8 +3127,10 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
     self->alpn_protocols = NULL;
     self->set_sni_cb = NULL;
     self->state = get_ssl_state(module);
+#ifndef OPENSSL_NO_PSK
     self->psk_client_callback = NULL;
     self->psk_server_callback = NULL;
+#endif
 
     /* Don't check host name by default */
     if (proto_version == PY_SSL_VERSION_TLS_CLIENT) {
@@ -3239,8 +3243,10 @@ context_clear(PySSLContext *self)
     Py_CLEAR(self->set_sni_cb);
     Py_CLEAR(self->msg_cb);
     Py_CLEAR(self->keylog_filename);
+#ifndef OPENSSL_NO_PSK
     Py_CLEAR(self->psk_client_callback);
     Py_CLEAR(self->psk_server_callback);
+#endif
     if (self->keylog_bio != NULL) {
         PySSL_BEGIN_ALLOW_THREADS
         BIO_free_all(self->keylog_bio);
@@ -4668,6 +4674,7 @@ _ssl__SSLContext_get_ca_certs_impl(PySSLContext *self, int binary_form)
     return NULL;
 }
 
+#ifndef OPENSSL_NO_PSK
 static unsigned int psk_client_callback(SSL *s,
                                         const char *hint,
                                         char *identity,
@@ -4735,6 +4742,7 @@ error:
     PyGILState_Release(gstate);
     return 0;
 }
+#endif
 
 /*[clinic input]
 _ssl._SSLContext.set_psk_client_callback
@@ -4747,6 +4755,7 @@ _ssl__SSLContext_set_psk_client_callback_impl(PySSLContext *self,
                                               PyObject *callback)
 /*[clinic end generated code: output=0aba86f6ed75119e input=7627bae0e5ee7635]*/
 {
+#ifndef OPENSSL_NO_PSK
     if (self->protocol == PY_SSL_VERSION_TLS_SERVER) {
         _setSSLError(get_state_ctx(self),
                      "Cannot add PSK client callback to a "
@@ -4774,8 +4783,14 @@ _ssl__SSLContext_set_psk_client_callback_impl(PySSLContext *self,
     SSL_CTX_set_psk_client_callback(self->ctx, ssl_callback);
 
     Py_RETURN_NONE;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "TLS-PSK is not supported by your OpenSSL version.");
+    return NULL;
+#endif
 }
 
+#ifndef OPENSSL_NO_PSK
 static unsigned int psk_server_callback(SSL *s,
                                         const char *identity,
                                         unsigned char *psk,
@@ -4835,6 +4850,7 @@ error:
     PyGILState_Release(gstate);
     return 0;
 }
+#endif
 
 /*[clinic input]
 _ssl._SSLContext.set_psk_server_callback
@@ -4849,6 +4865,7 @@ _ssl__SSLContext_set_psk_server_callback_impl(PySSLContext *self,
                                               const char *identity_hint)
 /*[clinic end generated code: output=1f4d6a4e09a92b03 input=65d4b6022aa85ea3]*/
 {
+#ifndef OPENSSL_NO_PSK
     if (self->protocol == PY_SSL_VERSION_TLS_CLIENT) {
         _setSSLError(get_state_ctx(self),
                      "Cannot add PSK server callback to a "
@@ -4882,6 +4899,11 @@ _ssl__SSLContext_set_psk_server_callback_impl(PySSLContext *self,
     SSL_CTX_set_psk_server_callback(self->ctx, ssl_callback);
 
     Py_RETURN_NONE;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "TLS-PSK is not supported by your OpenSSL version.");
+    return NULL;
+#endif
 }
 
 
@@ -6243,6 +6265,12 @@ sslmodule_init_constants(PyObject *m)
     addbool(m, "HAS_TLSv1_3", 0);
 #endif
 
+#ifdef OPENSSL_NO_PSK
+    addbool(m, "HAS_PSK", 0);
+#else
+    addbool(m, "HAS_PSK", 1);
+#endif
+
 #undef addbool
 #undef ADD_INT_CONST