https://github.com/python/cpython/commit/377b78761814e7d848361e642d376881739d5a29
commit: 377b78761814e7d848361e642d376881739d5a29
branch: main
author: Ron Frederick <r...@timeheart.net>
committer: picnixz <10796600+picn...@users.noreply.github.com>
date: 2025-07-28T19:33:31+02:00
summary:

gh-136306: Add support for getting and setting SSL groups (#136307)

Add support for getting and setting groups used for key agreement.

* `ssl.SSLSocket.group()` returns the name of the group used
  for the key agreement of the current session establishment.
  This feature requires Python to be built with OpenSSL 3.2 or later.

* `ssl.SSLContext.get_groups()` returns the list of names of groups
  that are compatible with the TLS version of the current context.
  This feature requires Python to be built with OpenSSL 3.5 or later.

* `ssl.SSLContext.set_groups()` sets the groups allowed for key agreement
  for sockets created with this context. This feature is always supported.

files:
A Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst
M Doc/library/ssl.rst
M Doc/whatsnew/3.15.rst
M Include/internal/pycore_global_objects_fini_generated.h
M Include/internal/pycore_global_strings.h
M Include/internal/pycore_runtime_init_generated.h
M Include/internal/pycore_unicodeobject_generated.h
M Lib/ssl.py
M Lib/test/test_ssl.py
M Modules/_ssl.c
M Modules/clinic/_ssl.c.h

diff --git a/Doc/library/ssl.rst b/Doc/library/ssl.rst
index a9930183f9a400..ff6053cb7e94d9 100644
--- a/Doc/library/ssl.rst
+++ b/Doc/library/ssl.rst
@@ -1290,6 +1290,13 @@ SSL sockets also have the following additional methods 
and attributes:
 
    .. versionadded:: 3.5
 
+.. method:: SSLSocket.group()
+
+   Return the group used for doing key agreement on this connection. If no
+   connection has been established, returns ``None``.
+
+   .. versionadded:: next
+
 .. method:: SSLSocket.compression()
 
    Return the compression algorithm being used as a string, or ``None``
@@ -1647,6 +1654,25 @@ to speed up repeated connections from the same clients.
 
    .. versionadded:: 3.6
 
+.. method:: SSLContext.get_groups(*, include_aliases=False)
+
+   Get a list of groups implemented for key agreement, taking into
+   account the current TLS :attr:`~SSLContext.minimum_version` and
+   :attr:`~SSLContext.maximum_version` values.  For example::
+
+       >>> ctx = ssl.create_default_context()
+       >>> ctx.minimum_version = ssl.TLSVersion.TLSv1_3
+       >>> ctx.maximum_version = ssl.TLSVersion.TLSv1_3
+       >>> ctx.get_groups()  # doctest: +SKIP
+       ['secp256r1', 'secp384r1', 'secp521r1', 'x25519', 'x448', ...]
+
+   By default, this method returns only the preferred IANA names for the
+   available groups. However, if the ``include_aliases`` parameter is set to
+   :const:`True` this method will also return any associated aliases such as
+   the ECDH curve names supported in older versions of OpenSSL.
+
+   .. versionadded:: next
+
 .. method:: SSLContext.set_default_verify_paths()
 
    Load a set of default "certification authority" (CA) certificates from
@@ -1672,6 +1698,19 @@ to speed up repeated connections from the same clients.
       TLS 1.3 cipher suites cannot be disabled with
       :meth:`~SSLContext.set_ciphers`.
 
+.. method:: SSLContext.set_groups(groups)
+
+   Set the groups allowed for key agreement for sockets created with this
+   context.  It should be a string in the `OpenSSL group list format
+   <https://docs.openssl.org/master/man3/SSL_CTX_set1_groups_list/>`_.
+
+   .. note::
+
+      When connected, the :meth:`SSLSocket.group` method of SSL sockets will
+      return the group used for key agreement on that connection.
+
+   .. versionadded:: next
+
 .. method:: SSLContext.set_alpn_protocols(protocols)
 
    Specify which protocols the socket should advertise during the SSL/TLS
diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst
index 1128da875a8847..d89260b32dfb82 100644
--- a/Doc/whatsnew/3.15.rst
+++ b/Doc/whatsnew/3.15.rst
@@ -300,6 +300,24 @@ ssl
   supports "External PSKs" in TLSv1.3, as described in RFC 9258.
   (Contributed by Will Childs-Klein in :gh:`133624`.)
 
+* Added new methods for managing groups used for SSL key agreement
+
+   * :meth:`ssl.SSLContext.set_groups` sets the groups allowed for doing
+     key agreement, extending the previous
+     :meth:`ssl.SSLContext.set_ecdh_curve` method.
+     This new API provides the ability to list multiple groups and
+     supports fixed-field and post-quantum groups in addition to ECDH
+     curves. This method can also be used to control what key shares
+     are sent in the TLS handshake.
+   * :meth:`ssl.SSLSocket.group` returns the group selected for doing key
+     agreement on the current connection after the TLS handshake completes.
+     This call requires OpenSSL 3.2 or later.
+   * :meth:`ssl.SSLContext.get_groups` returns a list of all available key
+     agreement groups compatible with the minimum and maximum TLS versions
+     currently set in the context. This call requires OpenSSL 3.5 or later.
+
+   (Contributed by Ron Frederick in :gh:`136306`)
+
 
 tarfile
 -------
diff --git a/Include/internal/pycore_global_objects_fini_generated.h 
b/Include/internal/pycore_global_objects_fini_generated.h
index 493377b4c25040..5e7dda3a3715a1 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -1005,6 +1005,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(imag));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(in_fd));
+    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(include_aliases));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(incoming));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(index));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(indexgroup));
diff --git a/Include/internal/pycore_global_strings.h 
b/Include/internal/pycore_global_strings.h
index 5dfea2f479d5fe..6908cbf78f349e 100644
--- a/Include/internal/pycore_global_strings.h
+++ b/Include/internal/pycore_global_strings.h
@@ -496,6 +496,7 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(imag)
         STRUCT_FOR_ID(importlib)
         STRUCT_FOR_ID(in_fd)
+        STRUCT_FOR_ID(include_aliases)
         STRUCT_FOR_ID(incoming)
         STRUCT_FOR_ID(index)
         STRUCT_FOR_ID(indexgroup)
diff --git a/Include/internal/pycore_runtime_init_generated.h 
b/Include/internal/pycore_runtime_init_generated.h
index 85ced09d29d338..da2ed7422c9deb 100644
--- a/Include/internal/pycore_runtime_init_generated.h
+++ b/Include/internal/pycore_runtime_init_generated.h
@@ -1003,6 +1003,7 @@ extern "C" {
     INIT_ID(imag), \
     INIT_ID(importlib), \
     INIT_ID(in_fd), \
+    INIT_ID(include_aliases), \
     INIT_ID(incoming), \
     INIT_ID(index), \
     INIT_ID(indexgroup), \
diff --git a/Include/internal/pycore_unicodeobject_generated.h 
b/Include/internal/pycore_unicodeobject_generated.h
index 6018d98d156a65..b1f411945e7856 100644
--- a/Include/internal/pycore_unicodeobject_generated.h
+++ b/Include/internal/pycore_unicodeobject_generated.h
@@ -1772,6 +1772,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) 
{
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
+    string = &_Py_ID(include_aliases);
+    _PyUnicode_InternStatic(interp, &string);
+    assert(_PyUnicode_CheckConsistency(string, 1));
+    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(incoming);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
diff --git a/Lib/ssl.py b/Lib/ssl.py
index 86fb8990636692..5b8762bcdc25d1 100644
--- a/Lib/ssl.py
+++ b/Lib/ssl.py
@@ -931,6 +931,10 @@ def cipher(self):
         ssl_version, secret_bits)``."""
         return self._sslobj.cipher()
 
+    def group(self):
+        """Return the currently selected key agreement group name."""
+        return self._sslobj.group()
+
     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.
@@ -1210,6 +1214,14 @@ def cipher(self):
         else:
             return self._sslobj.cipher()
 
+    @_sslcopydoc
+    def group(self):
+        self._checkClosed()
+        if self._sslobj is None:
+            return None
+        else:
+            return self._sslobj.group()
+
     @_sslcopydoc
     def shared_ciphers(self):
         self._checkClosed()
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index 7a7a8c40d47d40..c8939383c75d6d 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -48,6 +48,8 @@
 PROTOCOLS = sorted(ssl._PROTOCOL_NAMES)
 HOST = socket_helper.HOST
 IS_OPENSSL_3_0_0 = ssl.OPENSSL_VERSION_INFO >= (3, 0, 0)
+CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2)
+CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5)
 PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS')
 
 PROTOCOL_TO_TLS_VERSION = {}
@@ -960,6 +962,19 @@ def test_get_ciphers(self):
             len(intersection), 2, f"\ngot: {sorted(names)}\nexpected: 
{sorted(expected)}"
         )
 
+    def test_set_groups(self):
+        ctx = ssl.create_default_context()
+        self.assertIsNone(ctx.set_groups('P-256:X25519'))
+        self.assertRaises(ssl.SSLError, ctx.set_groups, 'P-256:xxx')
+
+    @unittest.skipUnless(CAN_GET_AVAILABLE_OPENSSL_GROUPS,
+                         "OpenSSL version doesn't support getting groups")
+    def test_get_groups(self):
+        ctx = ssl.create_default_context()
+        # By default, only return official IANA names.
+        self.assertNotIn('P-256', ctx.get_groups())
+        self.assertIn('P-256', ctx.get_groups(include_aliases=True))
+
     def test_options(self):
         # Test default SSLContext options
         ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
@@ -2720,6 +2735,8 @@ def server_params_test(client_context, server_context, 
indata=b"FOO\n",
                 'session_reused': s.session_reused,
                 'session': s.session,
             })
+            if CAN_GET_SELECTED_OPENSSL_GROUP:
+                stats.update({'group': s.group()})
             s.close()
         stats['server_alpn_protocols'] = server.selected_alpn_protocols
         stats['server_shared_ciphers'] = server.shared_ciphers
@@ -3870,6 +3887,8 @@ def test_no_shared_ciphers(self):
                 with self.assertRaises(OSError):
                     s.connect((HOST, server.port))
         self.assertIn("NO_SHARED_CIPHER", server.conn_errors[0])
+        self.assertIsNone(s.cipher())
+        self.assertIsNone(s.group())
 
     def test_version_basic(self):
         """
@@ -4145,6 +4164,38 @@ def test_ecdh_curve(self):
                                chatty=True, connectionchatty=True,
                                sni_name=hostname)
 
+    def test_groups(self):
+        # server secp384r1, client auto
+        client_context, server_context, hostname = testing_context()
+
+        server_context.set_groups("secp384r1")
+        server_context.minimum_version = ssl.TLSVersion.TLSv1_3
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_GROUP:
+            self.assertEqual(stats['group'], "secp384r1")
+
+        # server auto, client secp384r1
+        client_context, server_context, hostname = testing_context()
+        client_context.set_groups("secp384r1")
+        server_context.minimum_version = ssl.TLSVersion.TLSv1_3
+        stats = server_params_test(client_context, server_context,
+                                   chatty=True, connectionchatty=True,
+                                   sni_name=hostname)
+        if CAN_GET_SELECTED_OPENSSL_GROUP:
+            self.assertEqual(stats['group'], "secp384r1")
+
+        # server / client curve mismatch
+        client_context, server_context, hostname = testing_context()
+        client_context.set_groups("prime256v1")
+        server_context.set_groups("secp384r1")
+        server_context.minimum_version = ssl.TLSVersion.TLSv1_3
+        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-07-04-23-45-00.gh-issue-136306.O1YLIU.rst 
b/Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst
new file mode 100644
index 00000000000000..5556c512681b78
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-07-04-23-45-00.gh-issue-136306.O1YLIU.rst
@@ -0,0 +1 @@
+:mod:`ssl` can now get and set groups used for key agreement.
diff --git a/Modules/_ssl.c b/Modules/_ssl.c
index 5887d380046b00..ab30258faf3f62 100644
--- a/Modules/_ssl.c
+++ b/Modules/_ssl.c
@@ -2176,6 +2176,33 @@ _ssl__SSLSocket_cipher_impl(PySSLSocket *self)
     return cipher_to_tuple(current);
 }
 
+/*[clinic input]
+@critical_section
+_ssl._SSLSocket.group
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLSocket_group_impl(PySSLSocket *self)
+/*[clinic end generated code: output=9c168ee877017b95 input=5f187d8bf0d433b7]*/
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30200000L
+    const char *group_name;
+
+    if (self->ssl == NULL) {
+        Py_RETURN_NONE;
+    }
+    group_name = SSL_get0_group_name(self->ssl);
+    if (group_name == NULL) {
+        Py_RETURN_NONE;
+    }
+    return PyUnicode_DecodeFSDefault(group_name);
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "Getting selected group requires OpenSSL 3.2 or later.");
+    return NULL;
+#endif
+}
+
 /*[clinic input]
 @critical_section
 _ssl._SSLSocket.version
@@ -3240,6 +3267,7 @@ static PyMethodDef PySSLMethods[] = {
     _SSL__SSLSOCKET_GETPEERCERT_METHODDEF
     _SSL__SSLSOCKET_GET_CHANNEL_BINDING_METHODDEF
     _SSL__SSLSOCKET_CIPHER_METHODDEF
+    _SSL__SSLSOCKET_GROUP_METHODDEF
     _SSL__SSLSOCKET_SHARED_CIPHERS_METHODDEF
     _SSL__SSLSOCKET_VERSION_METHODDEF
     _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
@@ -3622,6 +3650,89 @@ _ssl__SSLContext_get_ciphers_impl(PySSLContext *self)
 
 }
 
+/*[clinic input]
+@critical_section
+_ssl._SSLContext.set_groups
+    grouplist: str
+    /
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLContext_set_groups_impl(PySSLContext *self, const char *grouplist)
+/*[clinic end generated code: output=0b5d05dfd371ffd0 input=2cc64cef21930741]*/
+{
+    if (!SSL_CTX_set1_groups_list(self->ctx, grouplist)) {
+        _setSSLError(get_state_ctx(self), "unrecognized group", 0, __FILE__, 
__LINE__);
+        return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+/*[clinic input]
+@critical_section
+_ssl._SSLContext.get_groups
+    *
+    include_aliases: bool = False
+[clinic start generated code]*/
+
+static PyObject *
+_ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases)
+/*[clinic end generated code: output=6d6209dd1051529b input=3e8ee5deb277dcc5]*/
+{
+#if OPENSSL_VERSION_NUMBER >= 0x30500000L
+    STACK_OF(OPENSSL_CSTRING) *groups = NULL;
+    const char *group;
+    int i, num;
+    PyObject *item, *result = NULL;
+
+    // This "groups" object is dynamically allocated, but the strings inside
+    // it are internal constants which shouldn't ever be modified or freed.
+    if ((groups = sk_OPENSSL_CSTRING_new_null()) == NULL) {
+        _setSSLError(get_state_ctx(self), "Can't allocate stack", 0, __FILE__, 
__LINE__);
+        goto error;
+    }
+
+    if (!SSL_CTX_get0_implemented_groups(self->ctx, include_aliases, groups)) {
+        _setSSLError(get_state_ctx(self), "Can't get groups", 0, __FILE__, 
__LINE__);
+        goto error;
+    }
+
+    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;
+    }
+
+    for (i = 0; i < num; ++i) {
+        // There's no allocation here, so group won't ever be NULL.
+        group = sk_OPENSSL_CSTRING_value(groups, i);
+        assert(group != NULL);
+
+        // 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__);
+            goto error;
+        }
+
+        PyList_SET_ITEM(result, i, item);
+    }
+
+    sk_OPENSSL_CSTRING_free(groups);
+    return result;
+error:
+    Py_XDECREF(result);
+    sk_OPENSSL_CSTRING_free(groups);
+    return NULL;
+#else
+    PyErr_SetString(PyExc_NotImplementedError,
+                    "Getting implemented groups requires OpenSSL 3.5 or 
later.");
+    return NULL;
+#endif
+}
 
 static int
 do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen,
@@ -5472,6 +5583,7 @@ static struct PyMethodDef context_methods[] = {
     _SSL__SSLCONTEXT__WRAP_SOCKET_METHODDEF
     _SSL__SSLCONTEXT__WRAP_BIO_METHODDEF
     _SSL__SSLCONTEXT_SET_CIPHERS_METHODDEF
+    _SSL__SSLCONTEXT_SET_GROUPS_METHODDEF
     _SSL__SSLCONTEXT__SET_ALPN_PROTOCOLS_METHODDEF
     _SSL__SSLCONTEXT_LOAD_CERT_CHAIN_METHODDEF
     _SSL__SSLCONTEXT_LOAD_DH_PARAMS_METHODDEF
@@ -5482,6 +5594,7 @@ static struct PyMethodDef context_methods[] = {
     _SSL__SSLCONTEXT_CERT_STORE_STATS_METHODDEF
     _SSL__SSLCONTEXT_GET_CA_CERTS_METHODDEF
     _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF
+    _SSL__SSLCONTEXT_GET_GROUPS_METHODDEF
     _SSL__SSLCONTEXT_SET_PSK_CLIENT_CALLBACK_METHODDEF
     _SSL__SSLCONTEXT_SET_PSK_SERVER_CALLBACK_METHODDEF
     {NULL, NULL}        /* sentinel */
diff --git a/Modules/clinic/_ssl.c.h b/Modules/clinic/_ssl.c.h
index 7027d87379283d..5b80fab0abb45e 100644
--- a/Modules/clinic/_ssl.c.h
+++ b/Modules/clinic/_ssl.c.h
@@ -196,6 +196,29 @@ _ssl__SSLSocket_cipher(PyObject *self, PyObject 
*Py_UNUSED(ignored))
     return return_value;
 }
 
+PyDoc_STRVAR(_ssl__SSLSocket_group__doc__,
+"group($self, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLSOCKET_GROUP_METHODDEF    \
+    {"group", (PyCFunction)_ssl__SSLSocket_group, METH_NOARGS, 
_ssl__SSLSocket_group__doc__},
+
+static PyObject *
+_ssl__SSLSocket_group_impl(PySSLSocket *self);
+
+static PyObject *
+_ssl__SSLSocket_group(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+    PyObject *return_value = NULL;
+
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLSocket_group_impl((PySSLSocket *)self);
+    Py_END_CRITICAL_SECTION();
+
+    return return_value;
+}
+
 PyDoc_STRVAR(_ssl__SSLSocket_version__doc__,
 "version($self, /)\n"
 "--\n"
@@ -969,6 +992,111 @@ _ssl__SSLContext_get_ciphers(PyObject *self, PyObject 
*Py_UNUSED(ignored))
     return return_value;
 }
 
+PyDoc_STRVAR(_ssl__SSLContext_set_groups__doc__,
+"set_groups($self, grouplist, /)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLCONTEXT_SET_GROUPS_METHODDEF    \
+    {"set_groups", (PyCFunction)_ssl__SSLContext_set_groups, METH_O, 
_ssl__SSLContext_set_groups__doc__},
+
+static PyObject *
+_ssl__SSLContext_set_groups_impl(PySSLContext *self, const char *grouplist);
+
+static PyObject *
+_ssl__SSLContext_set_groups(PyObject *self, PyObject *arg)
+{
+    PyObject *return_value = NULL;
+    const char *grouplist;
+
+    if (!PyUnicode_Check(arg)) {
+        _PyArg_BadArgument("set_groups", "argument", "str", arg);
+        goto exit;
+    }
+    Py_ssize_t grouplist_length;
+    grouplist = PyUnicode_AsUTF8AndSize(arg, &grouplist_length);
+    if (grouplist == NULL) {
+        goto exit;
+    }
+    if (strlen(grouplist) != (size_t)grouplist_length) {
+        PyErr_SetString(PyExc_ValueError, "embedded null character");
+        goto exit;
+    }
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLContext_set_groups_impl((PySSLContext *)self, 
grouplist);
+    Py_END_CRITICAL_SECTION();
+
+exit:
+    return return_value;
+}
+
+PyDoc_STRVAR(_ssl__SSLContext_get_groups__doc__,
+"get_groups($self, /, *, include_aliases=False)\n"
+"--\n"
+"\n");
+
+#define _SSL__SSLCONTEXT_GET_GROUPS_METHODDEF    \
+    {"get_groups", _PyCFunction_CAST(_ssl__SSLContext_get_groups), 
METH_FASTCALL|METH_KEYWORDS, _ssl__SSLContext_get_groups__doc__},
+
+static PyObject *
+_ssl__SSLContext_get_groups_impl(PySSLContext *self, int include_aliases);
+
+static PyObject *
+_ssl__SSLContext_get_groups(PyObject *self, PyObject *const *args, Py_ssize_t 
nargs, PyObject *kwnames)
+{
+    PyObject *return_value = NULL;
+    #if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+    #define NUM_KEYWORDS 1
+    static struct {
+        PyGC_Head _this_is_not_used;
+        PyObject_VAR_HEAD
+        Py_hash_t ob_hash;
+        PyObject *ob_item[NUM_KEYWORDS];
+    } _kwtuple = {
+        .ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+        .ob_hash = -1,
+        .ob_item = { &_Py_ID(include_aliases), },
+    };
+    #undef NUM_KEYWORDS
+    #define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+    #else  // !Py_BUILD_CORE
+    #  define KWTUPLE NULL
+    #endif  // !Py_BUILD_CORE
+
+    static const char * const _keywords[] = {"include_aliases", NULL};
+    static _PyArg_Parser _parser = {
+        .keywords = _keywords,
+        .fname = "get_groups",
+        .kwtuple = KWTUPLE,
+    };
+    #undef KWTUPLE
+    PyObject *argsbuf[1];
+    Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 
0;
+    int include_aliases = 0;
+
+    args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser,
+            /*minpos*/ 0, /*maxpos*/ 0, /*minkw*/ 0, /*varpos*/ 0, argsbuf);
+    if (!args) {
+        goto exit;
+    }
+    if (!noptargs) {
+        goto skip_optional_kwonly;
+    }
+    include_aliases = PyObject_IsTrue(args[0]);
+    if (include_aliases < 0) {
+        goto exit;
+    }
+skip_optional_kwonly:
+    Py_BEGIN_CRITICAL_SECTION(self);
+    return_value = _ssl__SSLContext_get_groups_impl((PySSLContext *)self, 
include_aliases);
+    Py_END_CRITICAL_SECTION();
+
+exit:
+    return return_value;
+}
+
 PyDoc_STRVAR(_ssl__SSLContext__set_alpn_protocols__doc__,
 "_set_alpn_protocols($self, protos, /)\n"
 "--\n"
@@ -3014,4 +3142,4 @@ _ssl_enum_crls(PyObject *module, PyObject *const *args, 
Py_ssize_t nargs, PyObje
 #ifndef _SSL_ENUM_CRLS_METHODDEF
     #define _SSL_ENUM_CRLS_METHODDEF
 #endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
-/*[clinic end generated code: output=1adc3780d8ca682a input=a9049054013a1b77]*/
+/*[clinic end generated code: output=c409bdf3c123b28b input=a9049054013a1b77]*/

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: arch...@mail-archive.com

Reply via email to