Skip to content

Commit 2d47a6c

Browse files
committed
Add function to SSL module to get all available TLS signature algorithms
1 parent bc84599 commit 2d47a6c

File tree

6 files changed

+113
-1
lines changed

6 files changed

+113
-1
lines changed

Doc/library/ssl.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,25 @@ purposes.
215215
:data:`VERIFY_X509_STRICT` in its default verify flags.
216216

217217

218+
Signature algorithms
219+
^^^^^^^^^^^^^^^^^^^^
220+
221+
.. function: get_sigalgs()
222+
223+
Return a list of available TLS signature algorithm names used
224+
by servers to complete the TLS handshake or clients requesting
225+
certificate-based authentication. For example::
226+
227+
>>> ssl.get_sigalgs() # doctest: +SKIP
228+
['ecdsa_secp256r1_sha256', 'ecdsa_secp384r1_sha384', ...]
229+
230+
These names can be used when building string values to pass to the
231+
:meth:`SSLContext.set_client_sigalgs` and
232+
:meth:`SSLContext.set_server_sigalgs` methods.
233+
234+
.. versionadded:: next
235+
236+
218237
Exceptions
219238
^^^^^^^^^^
220239

Doc/whatsnew/3.15.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@ ssl
435435

436436
* Added new methods for managing signature algorithms:
437437

438+
* :func:`ssl.get_sigalgs` returns a list of all available TLS signature
439+
algorithms. This call requires OpenSSL 3.4 or later.
438440
* :meth:`ssl.SSLContext.set_client_sigalgs` sets the signature algorithms
439441
allowed for certificate-based client authentication.
440442
* :meth:`ssl.SSLContext.set_server_sigalgs` sets the signature algorithms

Lib/ssl.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@
112112
except ImportError:
113113
# RAND_egd is not supported on some platforms
114114
pass
115+
from _ssl import get_sigalgs
115116

116117

117118
from _ssl import (

Lib/test/test_ssl.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
CAN_GET_SELECTED_OPENSSL_GROUP = ssl.OPENSSL_VERSION_INFO >= (3, 2)
5252
CAN_IGNORE_UNKNOWN_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 3)
5353
CAN_GET_AVAILABLE_OPENSSL_GROUPS = ssl.OPENSSL_VERSION_INFO >= (3, 5)
54+
CAN_GET_AVAILABLE_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 4)
5455
CAN_SET_CLIENT_SIGALGS = "AWS-LC" not in ssl.OPENSSL_VERSION
5556
CAN_IGNORE_UNKNOWN_OPENSSL_SIGALGS = ssl.OPENSSL_VERSION_INFO >= (3, 3)
5657
CAN_GET_SELECTED_OPENSSL_SIGALG = ssl.OPENSSL_VERSION_INFO >= (3, 5)
@@ -998,6 +999,11 @@ def test_get_groups(self):
998999
self.assertNotIn('P-256', ctx.get_groups())
9991000
self.assertIn('P-256', ctx.get_groups(include_aliases=True))
10001001

1002+
@unittest.skipUnless(CAN_GET_AVAILABLE_OPENSSL_SIGALGS,
1003+
"SSL library doesn't support getting sigalgs")
1004+
def test_get_sigalgs(self):
1005+
self.assertIn('rsa_pss_rsae_sha256', ssl.get_sigalgs())
1006+
10011007
@unittest.skipUnless(CAN_SET_CLIENT_SIGALGS,
10021008
"SSL library doesn't support setting client sigalgs")
10031009
def test_set_client_sigalgs(self):

Modules/_ssl.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,6 +6338,66 @@ _ssl_get_default_verify_paths_impl(PyObject *module)
63386338
return NULL;
63396339
}
63406340

6341+
/*[clinic input]
6342+
@critical_section
6343+
_ssl.get_sigalgs
6344+
[clinic start generated code]*/
6345+
6346+
static PyObject *
6347+
_ssl_get_sigalgs_impl(PyObject *module)
6348+
/*[clinic end generated code: output=ab0791b63856854b input=bf74cdad3a19d29e]*/
6349+
{
6350+
#if OPENSSL_VERSION_NUMBER >= 0x30400000L
6351+
const char *sigalgs_list, *sigalg, *end;
6352+
PyObject *item, *result = NULL;
6353+
size_t len;
6354+
6355+
if ((sigalgs_list = SSL_get1_builtin_sigalgs(NULL)) == NULL) {
6356+
PyErr_NoMemory();
6357+
goto error;
6358+
}
6359+
6360+
result = PyList_New(0);
6361+
if (result == NULL) {
6362+
PyErr_NoMemory();
6363+
goto error;
6364+
}
6365+
6366+
sigalg = sigalgs_list;
6367+
while (sigalg) {
6368+
end = strchr(sigalg, ':');
6369+
len = end? end - sigalg : strlen(sigalg);
6370+
6371+
// Alg names are plain ASCII, so there's no chance of a decoding
6372+
// error here. However, an allocation failure could occur when
6373+
// constructing the Unicode version of the names.
6374+
item = PyUnicode_DecodeASCII(sigalg, len, "strict");
6375+
if (item == NULL) {
6376+
goto error;
6377+
}
6378+
6379+
if (PyList_Append(result, item) == -1) {
6380+
Py_DECREF(item);
6381+
goto error;
6382+
}
6383+
6384+
Py_DECREF(item);
6385+
sigalg = end? end + 1 : end;
6386+
}
6387+
6388+
OPENSSL_free((void *)sigalgs_list);
6389+
return result;
6390+
error:
6391+
OPENSSL_free((void *)sigalgs_list);
6392+
Py_XDECREF(result);
6393+
return NULL;
6394+
#else
6395+
PyErr_SetString(PyExc_NotImplementedError,
6396+
"Getting signature algorithms requires OpenSSL 3.4 or later.");
6397+
return NULL;
6398+
#endif
6399+
}
6400+
63416401
static PyObject*
63426402
asn1obj2py(_sslmodulestate *state, ASN1_OBJECT *obj)
63436403
{
@@ -6741,6 +6801,7 @@ static PyMethodDef PySSL_methods[] = {
67416801
_SSL_RAND_BYTES_METHODDEF
67426802
_SSL_RAND_STATUS_METHODDEF
67436803
_SSL_GET_DEFAULT_VERIFY_PATHS_METHODDEF
6804+
_SSL_GET_SIGALGS_METHODDEF
67446805
_SSL_ENUM_CERTIFICATES_METHODDEF
67456806
_SSL_ENUM_CRLS_METHODDEF
67466807
_SSL_TXT2OBJ_METHODDEF

Modules/clinic/_ssl.c.h

Lines changed: 24 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)