]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-138252: Add support in SSL module for getting and setting TLS signature algorithms...
authorRon Frederick <ronf@timeheart.net>
Mon, 8 Sep 2025 08:36:12 +0000 (01:36 -0700)
committerGitHub <noreply@github.com>
Mon, 8 Sep 2025 08:36:12 +0000 (08:36 +0000)
The signature algorithms allowed for certificate-based client authentication or
for the server to complete the TLS handshake can be defined on a SSL context via
`ctx.set_client_sigalgs()` and `ctx.set_server_sigalgs()`.

With OpenSSL 3.4 or later, the list of available TLS algorithms can be retrieved
by `ssl.get_sigalgs()`.

With OpenSSL 3.5 or later, the selected signature algorithms can be retrieved from
SSL sockets via `socket.client_sigalg()` and `socket.server_sigalg()`.

This commit also partially amends 377b78761814e7d848361e642d376881739d5a29
by using `PyUnicode_DecodeFSDefault` instead of `PyUnicode_DecodeASCII` in
`_ssl._SSLContext.get_groups`, so that functions consistently decode strings
obtained from OpenSSL.

---------

Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
Doc/library/ssl.rst
Doc/whatsnew/3.15.rst
Lib/ssl.py
Lib/test/test_ssl.py
Misc/NEWS.d/next/Library/2025-08-30-17-58-04.gh-issue-138252.CDiEby.rst [new file with mode: 0644]
Modules/_ssl.c
Modules/clinic/_ssl.c.h

index 42fcd38cc7d3dffcd0ad878518893dbfd94415ff..74b354845b2643584ff6a8c6dcd1709d6abe5325 100644 (file)
@@ -215,6 +215,25 @@ purposes.
       :data:`VERIFY_X509_STRICT` in its default verify flags.
 
 
+Signature algorithms
+^^^^^^^^^^^^^^^^^^^^
+
+.. function:: get_sigalgs()
+
+   Return a list of available TLS signature algorithm names used
+   by servers to complete the TLS handshake or clients requesting
+   certificate-based authentication. For example::
+
+       >>> ssl.get_sigalgs()  # doctest: +SKIP
+       ['ecdsa_secp256r1_sha256', 'ecdsa_secp384r1_sha384', ...]
+
+   These names can be used when building string values to pass to the
+   :meth:`SSLContext.set_client_sigalgs` and
+   :meth:`SSLContext.set_server_sigalgs` methods.
+
+   .. versionadded:: next
+
+
 Exceptions
 ^^^^^^^^^^
 
@@ -1297,6 +1316,22 @@ SSL sockets also have the following additional methods and attributes:
 
    .. versionadded:: next
 
+.. method:: SSLSocket.client_sigalg()
+
+   Return the signature algorithm used for performing certificate-based client
+   authentication on this connection, or ``None`` if no connection has been
+   established or client authentication didn't occur.
+
+   .. versionadded:: next
+
+.. method:: SSLSocket.server_sigalg()
+
+   Return the signature algorithm used by the server to complete the TLS
+   handshake on this connection, or ``None`` if no connection has been
+   established or the cipher suite has no signature.
+
+   .. versionadded:: next
+
 .. method:: SSLSocket.compression()
 
    Return the compression algorithm being used as a string, or ``None``
@@ -1725,6 +1760,35 @@ to speed up repeated connections from the same clients.
 
    .. versionadded:: next
 
+.. method:: SSLContext.set_client_sigalgs(sigalgs)
+
+   Set the signature algorithms allowed for certificate-based client
+   authentication. It should be a string in the `OpenSSL client sigalgs
+   list format
+   <https://docs.openssl.org/master/man3/SSL_CTX_set1_client_sigalgs_list/>`_.
+
+   .. note::
+
+      When connected, the :meth:`SSLSocket.client_sigalg` method of SSL
+      sockets will return the signature algorithm used for performing
+      certificate-based client authentication on that connection.
+
+   .. versionadded:: next
+
+.. method:: SSLContext.set_server_sigalgs(sigalgs)
+
+   Set the signature algorithms allowed for the server to complete the TLS
+   handshake. It should be a string in the `OpenSSL sigalgs list format
+   <https://docs.openssl.org/master/man3/SSL_CTX_set1_sigalgs_list/>`_.
+
+   .. note::
+
+      When connected, the :meth:`SSLSocket.server_sigalg` method of SSL
+      sockets will return the signature algorithm used by the server to
+      complete the TLS handshake on that connection.
+
+   .. versionadded:: next
+
 .. method:: SSLContext.set_alpn_protocols(protocols)
 
    Specify which protocols the socket should advertise during the SSL/TLS
@@ -2876,7 +2940,7 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available.
   process certificate requests while they send or receive application data
   from the server.
 - TLS 1.3 features like early data, deferred TLS client cert request,
-  signature algorithm configuration, and rekeying are not supported yet.
+  and rekeying are not supported yet.
 
 
 .. seealso::
index 3236213de5aaa21b454552e2f08098392d6d7500..b98ee202ec6db6aca5747b7d948f18743fdaf2b7 100644 (file)
@@ -442,6 +442,23 @@ ssl
   connection is made.
   (Contributed by Ron Frederick in :gh:`137197`.)
 
+* Added new methods for managing signature algorithms:
+
+  * :func:`ssl.get_sigalgs` returns a list of all available TLS signature
+    algorithms. This call requires OpenSSL 3.4 or later.
+  * :meth:`ssl.SSLContext.set_client_sigalgs` sets the signature algorithms
+    allowed for certificate-based client authentication.
+  * :meth:`ssl.SSLContext.set_server_sigalgs` sets the signature algorithms
+    allowed for the server to complete the TLS handshake.
+  * :meth:`ssl.SSLSocket.client_sigalg` returns the signature algorithm
+    selected for client authentication on the current connection. This call
+    requires OpenSSL 3.5 or later.
+  * :meth:`ssl.SSLSocket.server_sigalg` returns the signature algorithm
+    selected for the server to complete the TLS handshake on the current
+    connection. This call requires OpenSSL 3.5 or later.
+
+   (Contributed by Ron Frederick in :gh:`138252`.)
+
 
 tarfile
 -------
index 5b8762bcdc25d151a21629fa9f74f8e1c383c8f6..493ea901d9332440da7f21d492e4f940745bd1f2 100644 (file)
@@ -13,6 +13,9 @@ Exceptions:
 
 Functions:
 
+  get_sigalgs          -- return a list of all available TLS signature
+                          algorithms (requires OpenSSL 3.4 or later)
+
   cert_time_to_seconds -- convert time string used for certificate
                           notBefore and notAfter functions to integer
                           seconds past the Epoch (the time values
@@ -112,6 +115,7 @@ try:
 except ImportError:
     # RAND_egd is not supported on some platforms
     pass
+from _ssl import get_sigalgs
 
 
 from _ssl import (
@@ -935,6 +939,14 @@ class SSLObject:
         """Return the currently selected key agreement group name."""
         return self._sslobj.group()
 
+    def client_sigalg(self):
+        """Return the selected client authentication signature algorithm."""
+        return self._sslobj.client_sigalg()
+
+    def server_sigalg(self):
+        """Return the selected server handshake signature algorithm."""
+        return self._sslobj.server_sigalg()
+
     def shared_ciphers(self):
         """Return a list of ciphers shared by the client during the handshake or
         None if this is not a valid server connection.
@@ -1222,6 +1234,22 @@ class SSLSocket(socket):
         else:
             return self._sslobj.group()
 
+    @_sslcopydoc
+    def client_sigalg(self):
+        self._checkClosed()
+        if self._sslobj is None:
+            return None
+        else:
+            return self._sslobj.client_sigalg()
+
+    @_sslcopydoc
+    def server_sigalg(self):
+        self._checkClosed()
+        if self._sslobj is None:
+            return None
+        else:
+            return self._sslobj.server_sigalg()
+
     @_sslcopydoc
     def shared_ciphers(self):
         self._checkClosed()
index b05c7bb059e76d582687747de722898908a1e924..d6e06445d53179aa68a788a0ed2d37b8a184d917 100644 (file)
@@ -51,6 +51,10 @@ IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
 CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2)
 CAN_IGNORE_UNKNOWN_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 3)
 CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5)
+CAN_GET_AVAILABLE_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 4)
+CAN_SET_CLIENT_SIGALGS = "AWS-LC" not in ssl.OPENSSL_VERSION
+CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 3)
+CAN_GET_SELECTED_OPENSSL_SIGALG = ssl.OPENSSL_VERSION_INFO >= (3, 5)
 PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
 
 PROTOCOL_TO_TLS_VERSION = {}
@@ -294,7 +298,8 @@ def test_wrap_socket(sock, *,
 USE_SAME_TEST_CONTEXT = False
 _TEST_CONTEXT = None
 
-def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
+def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True,
+                    client_cert=None):
     """Create context
 
     client_context, server_context, hostname = testing_context()
@@ -321,6 +326,10 @@ def testing_context(server_cert=SIGNED_CERTFILE, *, server_chain=True):
     if server_chain:
         server_context.load_verify_locations(SIGNING_CA)
 
+    if client_cert:
+        client_context.load_cert_chain(client_cert)
+        server_context.verify_mode = ssl.CERT_REQUIRED
+
     if USE_SAME_TEST_CONTEXT:
         if _TEST_CONTEXT is not None:
             _TEST_CONTEXT = client_context, server_context, hostname
@@ -990,6 +999,37 @@ class ContextTests(unittest.TestCase):
         self.assertNotIn('P-256', ctx.get_groups())
         self.assertIn('P-256', ctx.get_groups(include_aliases=True))
 
+    @unittest.skipUnless(CAN_GET_AVAILABLE_OPENSSL_SIGALGS,
+                         "SSL library doesn't support getting sigalgs")
+    def test_get_sigalgs(self):
+        self.assertIn('rsa_pss_rsae_sha256', ssl.get_sigalgs())
+
+    @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS,
+                         "SSL library doesn't support setting client sigalgs")
+    def test_set_client_sigalgs(self):
+        ctx = ssl.create_default_context()
+
+        self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256'))
+
+        self.assertRaises(ssl.SSLError, ctx.set_client_sigalgs,
+                          'rsa_pss_rsae_sha256:foo')
+
+        # Ignoring unknown sigalgs is only supported since OpenSSL 3.3.
+        if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS:
+            self.assertIsNone(ctx.set_client_sigalgs('rsa_pss_rsae_sha256:?foo'))
+
+    def test_set_server_sigalgs(self):
+        ctx = ssl.create_default_context()
+
+        self.assertIsNone(ctx.set_server_sigalgs('rsa_pss_rsae_sha256'))
+
+        self.assertRaises(ssl.SSLError, ctx.set_server_sigalgs,
+                          'rsa_pss_rsae_sha256:foo')
+
+        # Ignoring unknown sigalgs is only supported since OpenSSL 3.3.
+        if CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS:
+            self.assertIsNone(ctx.set_server_sigalgs('rsa_pss_rsae_sha256:?foo'))
+
     def test_options(self):
         # Test default SSLContext options
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
@@ -2814,6 +2854,9 @@ def server_params_test(client_context, server_context, indata=b"FOO\n",
             })
             if CAN_GET_SELECTED_OPENSSL_GROUP:
                 stats.update({'group': s.group()})
+            if CAN_GET_SELECTED_OPENSSL_SIGALG:
+                stats.update({'client_sigalg': s.client_sigalg()})
+                stats.update({'server_sigalg': s.server_sigalg()})
             s.close()
         stats['server_alpn_protocols'] = server.selected_alpn_protocols
         stats['server_shared_ciphers'] = server.shared_ciphers
@@ -4273,6 +4316,71 @@ class ThreadedTests(unittest.TestCase):
                                chatty=True, connectionchatty=True,
                                sni_name=hostname)
 
+    @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS,
+                         "SSL library doesn't support setting client sigalgs")
+    def test_client_sigalgs(self):
+        # no mutual auth, so cient_sigalg should be None
+        client_context, server_context, hostname = testing_context()
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_SIGALG:
+            self.assertIsNone(stats['client_sigalg'])
+
+        # server auto, client rsa_pss_rsae_sha384
+        sigalg = "rsa_pss_rsae_sha384"
+        client_context, server_context, hostname = \
+            testing_context(client_cert=SIGNED_CERTFILE)
+        client_context.set_client_sigalgs(sigalg)
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_SIGALG:
+            self.assertEqual(stats['client_sigalg'], sigalg)
+
+    @unittest.skipUnless(CAN_SET_CLIENT_SIGALGS,
+                         "SSL library doesn't support setting client sigalgs")
+    def test_client_sigalgs_mismatch(self):
+        client_context, server_context, hostname = \
+            testing_context(client_cert=SIGNED_CERTFILE)
+        client_context.set_client_sigalgs("rsa_pss_rsae_sha256")
+        server_context.set_client_sigalgs("rsa_pss_rsae_sha384")
+
+        # Some systems return ConnectionResetError on handshake failures
+        with self.assertRaises((ssl.SSLError, ConnectionResetError)):
+            server_params_test(client_context, server_context,
+                               chatty=True, connectionchatty=True,
+                               sni_name=hostname)
+
+    def test_server_sigalgs(self):
+        # server rsa_pss_rsae_sha384, client auto
+        sigalg = "rsa_pss_rsae_sha384"
+        client_context, server_context, hostname = testing_context()
+        server_context.set_server_sigalgs(sigalg)
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_SIGALG:
+            self.assertEqual(stats['server_sigalg'], sigalg)
+
+        # server auto, client rsa_pss_rsae_sha384
+        client_context, server_context, hostname = testing_context()
+        client_context.set_server_sigalgs(sigalg)
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_SIGALG:
+            self.assertEqual(stats['server_sigalg'], sigalg)
+
+    def test_server_sigalgs_mismatch(self):
+        client_context, server_context, hostname = testing_context()
+        client_context.set_server_sigalgs("rsa_pss_rsae_sha256")
+        server_context.set_server_sigalgs("rsa_pss_rsae_sha384")
+        with self.assertRaises(ssl.SSLError):
+            server_params_test(client_context, server_context,
+                               chatty=True, connectionchatty=True,
+                               sni_name=hostname)
+
     def test_selected_alpn_protocol(self):
         # selected_alpn_protocol() is None unless ALPN is used.
         client_context, server_context, hostname = testing_context()
diff --git a/Misc/NEWS.d/next/Library/2025-08-30-17-58-04.gh-issue-138252.CDiEby.rst b/Misc/NEWS.d/next/Library/2025-08-30-17-58-04.gh-issue-138252.CDiEby.rst
new file mode 100644 (file)
index 0000000..95420ce
--- /dev/null
@@ -0,0 +1,4 @@
+:mod:`ssl`: :class:`~ssl.SSLContext` objects can now set client and server
+TLS signature algorithms. If Python has been built with OpenSSL 3.5 or later,
+:class:`~ssl.SSLSocket` objects can return the signature algorithms selected
+on a connection.
index 048e640283638b5a6524c903bd4c52824fbb5a75..0f1d007e47de2a13c2ae019415139c1d50be3418 100644 (file)
@@ -2200,6 +2200,56 @@ _ssl__SSLSocket_group_impl(PySSLSocket *self)
 #endif
 }
 
+static PyObject *
+ssl_socket_signame_impl(PySSLSocket *socket,
+                        enum py_ssl_server_or_client self_socket_type)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30500000L
+    int ret;
+    const char *sigalg;
+
+    if (socket->ssl == NULL) {
+        Py_RETURN_NONE;
+    }
+    ret = (socket->socket_type == self_socket_type)
+        ? SSL_get0_signature_name(socket->ssl, &sigalg)
+        : SSL_get0_peer_signature_name(socket->ssl, &sigalg);
+    if (ret == 0) {
+        Py_RETURN_NONE;
+    }
+    assert(sigalg != NULL);
+    return PyUnicode_DecodeFSDefault(sigalg);
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "Getting sig algorithms requires OpenSSL 3.5 or later.");
+    return NULL;
+#endif
+}
+
+/*[clinic input]
+@critical_section
+_ssl._SSLSocket.client_sigalg
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_client_sigalg_impl(PySSLSocket *self)
+/*[clinic end generated code: output=499dd7fbf021a47b input=a0d9696b5414c627]*/
+{
+    return ssl_socket_signame_impl(self, PY_SSL_CLIENT);
+}
+
+/*[clinic input]
+@critical_section
+_ssl._SSLSocket.server_sigalg
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_server_sigalg_impl(PySSLSocket *self)
+/*[clinic end generated code: output=c508a766a8e275dc input=9063e562a1e6b946]*/
+{
+    return ssl_socket_signame_impl(self, PY_SSL_SERVER);
+}
+
 /*[clinic input]
 @critical_section
 _ssl._SSLSocket.version
@@ -3276,6 +3326,8 @@ static PyMethodDef PySSLMethods[] = {
     _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF
     _SSL__SSLSOCKET_CIPHER_METHODDEF
     _SSL__SSLSOCKET_GROUP_METHODDEF
+    _SSL__SSLSOCKET_CLIENT_SIGALG_METHODDEF
+    _SSL__SSLSOCKET_SERVER_SIGALG_METHODDEF
     _SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF
     _SSL__SSLSOCKET_VERSION_METHODDEF
     _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
@@ -3727,7 +3779,6 @@ _ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases)
     num = sk_OPENSSL_CSTRING_num(groups);
     result = PyList_New(num);
     if (result == NULL) {
-        _setSSLError(get_state_ctx(self), "Can't allocate list", 0, __FILE__, __LINE__);
         goto error;
     }
 
@@ -3739,9 +3790,7 @@ _ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases)
         // Group names are plain ASCII, so there's no chance of a decoding
         // error here. However, an allocation failure could occur when
         // constructing the Unicode version of the names.
-        item = PyUnicode_DecodeASCII(group, strlen(group), "strict");
-        if (item == NULL) {
-            _setSSLError(get_state_ctx(self), "Can't allocate group name", 0, __FILE__, __LINE__);
+        if ((item = PyUnicode_DecodeFSDefault(group)) == NULL) {
             goto error;
         }
 
@@ -3761,6 +3810,49 @@ error:
 #endif
 }
 
+/*[clinic input]
+@critical_section
+_ssl._SSLContext.set_client_sigalgs
+    sigalgslist: str
+    /
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self,
+                                         const char *sigalgslist)
+/*[clinic end generated code: output=f4f5be160a29c7d6 input=500d853ce9fd94ff]*/
+{
+#ifdef OPENSSL_IS_AWSLC
+    _setSSLError(get_state_ctx(self), "can't set client sigalgs on AWS-LC", 0, __FILE__, __LINE__);
+    return NULL;
+#else
+    if (!SSL_CTX_set1_client_sigalgs_list(self->ctx, sigalgslist)) {
+        _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__);
+        return NULL;
+    }
+    Py_RETURN_NONE;
+#endif
+}
+
+/*[clinic input]
+@critical_section
+_ssl._SSLContext.set_server_sigalgs
+    sigalgslist: str
+    /
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self,
+                                         const char *sigalgslist)
+/*[clinic end generated code: output=31ecb1d310285644 input=653b752e4f8d801b]*/
+{
+    if (!SSL_CTX_set1_sigalgs_list(self->ctx, sigalgslist)) {
+        _setSSLError(get_state_ctx(self), "unrecognized signature algorithm", 0, __FILE__, __LINE__);
+        return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
 static int
 do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen,
                       const unsigned char *server_protocols, unsigned int server_protocols_len,
@@ -5616,6 +5708,8 @@ static struct PyMethodDef context_methods[] = {
     _SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF
     _SSL__SSLCONTEXT_SET_CIPHERSUITES_METHODDEF
     _SSL__SSLCONTEXT_SET_GROUPS_METHODDEF
+    _SSL__SSLCONTEXT_SET_CLIENT_SIGALGS_METHODDEF
+    _SSL__SSLCONTEXT_SET_SERVER_SIGALGS_METHODDEF
     _SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF
     _SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF
     _SSL__SSLCONTEXT_LOAD_DH_PARAMS_METHODDEF
@@ -6234,6 +6328,39 @@ _ssl_get_default_verify_paths_impl(PyObject *module)
     return NULL;
 }
 
+/*[clinic input]
+_ssl.get_sigalgs
+[clinic start generated code]*/
+
+static PyObject *
+_ssl_get_sigalgs_impl(PyObject *module)
+/*[clinic end generated code: output=ab0791b63856854b input=d96dd6cefec3f86b]*/
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30400000L
+    const char *sigalgs;
+    PyObject *sigalgs_str, *sigalgs_list;
+
+    if ((sigalgs = SSL_get1_builtin_sigalgs(NULL)) == NULL) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+
+    if ((sigalgs_str = PyUnicode_DecodeFSDefault(sigalgs)) == NULL) {
+        OPENSSL_free((void *)sigalgs);
+        return NULL;
+    }
+
+    OPENSSL_free((void *)sigalgs);
+    sigalgs_list = PyUnicode_Split(sigalgs_str, _Py_LATIN1_CHR(':'), -1);
+    Py_DECREF(sigalgs_str);
+    return sigalgs_list;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "Getting signature algorithms requires OpenSSL 3.4 or later.");
+    return NULL;
+#endif
+}
+
 static PyObject*
 asn1obj2py(_sslmodulestate *state, ASN1_OBJECT *obj)
 {
@@ -6637,6 +6764,7 @@ static PyMethodDef PySSL_methods[] = {
     _SSL_RAND_BYTES_METHODDEF
     _SSL_RAND_STATUS_METHODDEF
     _SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF
+    _SSL_GET_SIGALGS_METHODDEF
     _SSL_ENUM_CERTIFICATES_METHODDEF
     _SSL_ENUM_CRLS_METHODDEF
     _SSL_TXT2OBJ_METHODDEF
index e8b51c1f1e326d9cf72e2e320a3ef15804174d46..0e8e4a7c8a73c73ab5c10f5fb2163a565a9519f8 100644 (file)
@@ -219,6 +219,52 @@ _ssl__SSLSocket_group(PyObject *self, PyObject *Py_UNUSED(ignored))
     return return_value;
 }
 
+PyDoc_STRVAR(_ssl__SSLSocket_client_sigalg__doc__,
+"client_sigalg($self, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLSOCKET_CLIENT_SIGALG_METHODDEF    \
+    {"client_sigalg", (PyCFunction)_ssl__SSLSocket_client_sigalg, METH_NOARGS, _ssl__SSLSocket_client_sigalg__doc__},
+
+static PyObject *
+_ssl__SSLSocket_client_sigalg_impl(PySSLSocket *self);
+
+static PyObject *
+_ssl__SSLSocket_client_sigalg(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLSocket_client_sigalg_impl((PySSLSocket *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
+PyDoc_STRVAR(_ssl__SSLSocket_server_sigalg__doc__,
+"server_sigalg($self, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLSOCKET_SERVER_SIGALG_METHODDEF    \
+    {"server_sigalg", (PyCFunction)_ssl__SSLSocket_server_sigalg, METH_NOARGS, _ssl__SSLSocket_server_sigalg__doc__},
+
+static PyObject *
+_ssl__SSLSocket_server_sigalg_impl(PySSLSocket *self);
+
+static PyObject *
+_ssl__SSLSocket_server_sigalg(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLSocket_server_sigalg_impl((PySSLSocket *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(_ssl__SSLSocket_version__doc__,
 "version($self, /)\n"
 "--\n"
@@ -1136,6 +1182,84 @@ exit:
     return return_value;
 }
 
+PyDoc_STRVAR(_ssl__SSLContext_set_client_sigalgs__doc__,
+"set_client_sigalgs($self, sigalgslist, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLCONTEXT_SET_CLIENT_SIGALGS_METHODDEF    \
+    {"set_client_sigalgs", (PyCFunction)_ssl__SSLContext_set_client_sigalgs, METH_O, _ssl__SSLContext_set_client_sigalgs__doc__},
+
+static PyObject *
+_ssl__SSLContext_set_client_sigalgs_impl(PySSLContext *self,
+                                         const char *sigalgslist);
+
+static PyObject *
+_ssl__SSLContext_set_client_sigalgs(PyObject *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    const char *sigalgslist;
+
+    if (!PyUnicode_Check(arg)) {
+        _PyArg_BadArgument("set_client_sigalgs", "argument", "str", arg);
+        goto exit;
+    }
+    Py_ssize_t sigalgslist_length;
+    sigalgslist = PyUnicode_AsUTF8AndSize(arg, &sigalgslist_length);
+    if (sigalgslist == NULL) {
+        goto exit;
+    }
+    if (strlen(sigalgslist) != (size_t)sigalgslist_length) {
+        PyErr_SetString(PyExc_ValueError, "embedded null character");
+        goto exit;
+    }
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLContext_set_client_sigalgs_impl((PySSLContext *)self, sigalgslist);
+    Py_END_CRITICAL_SECTION();
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_ssl__SSLContext_set_server_sigalgs__doc__,
+"set_server_sigalgs($self, sigalgslist, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLCONTEXT_SET_SERVER_SIGALGS_METHODDEF    \
+    {"set_server_sigalgs", (PyCFunction)_ssl__SSLContext_set_server_sigalgs, METH_O, _ssl__SSLContext_set_server_sigalgs__doc__},
+
+static PyObject *
+_ssl__SSLContext_set_server_sigalgs_impl(PySSLContext *self,
+                                         const char *sigalgslist);
+
+static PyObject *
+_ssl__SSLContext_set_server_sigalgs(PyObject *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    const char *sigalgslist;
+
+    if (!PyUnicode_Check(arg)) {
+        _PyArg_BadArgument("set_server_sigalgs", "argument", "str", arg);
+        goto exit;
+    }
+    Py_ssize_t sigalgslist_length;
+    sigalgslist = PyUnicode_AsUTF8AndSize(arg, &sigalgslist_length);
+    if (sigalgslist == NULL) {
+        goto exit;
+    }
+    if (strlen(sigalgslist) != (size_t)sigalgslist_length) {
+        PyErr_SetString(PyExc_ValueError, "embedded null character");
+        goto exit;
+    }
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLContext_set_server_sigalgs_impl((PySSLContext *)self, sigalgslist);
+    Py_END_CRITICAL_SECTION();
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_ssl__SSLContext__set_alpn_protocols__doc__,
 "_set_alpn_protocols($self, protos, /)\n"
 "--\n"
@@ -2892,6 +3016,23 @@ _ssl_get_default_verify_paths(PyObject *module, PyObject *Py_UNUSED(ignored))
     return return_value;
 }
 
+PyDoc_STRVAR(_ssl_get_sigalgs__doc__,
+"get_sigalgs($module, /)\n"
+"--\n"
+"\n");
+
+#define _SSL_GET_SIGALGS_METHODDEF    \
+    {"get_sigalgs", (PyCFunction)_ssl_get_sigalgs, METH_NOARGS, _ssl_get_sigalgs__doc__},
+
+static PyObject *
+_ssl_get_sigalgs_impl(PyObject *module);
+
+static PyObject *
+_ssl_get_sigalgs(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+    return _ssl_get_sigalgs_impl(module);
+}
+
 PyDoc_STRVAR(_ssl_txt2obj__doc__,
 "txt2obj($module, /, txt, name=False)\n"
 "--\n"
@@ -3181,4 +3322,4 @@ exit:
 #ifndef _SSL_ENUM_CRLS_METHODDEF
     #define _SSL_ENUM_CRLS_METHODDEF
 #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
-/*[clinic end generated code: output=4e35d2ea2fc46023 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=5a630a1e83927d47 input=a9049054013a1b77]*/