mirror of https://github.com/python/cpython
Issue #27866: Add SSLContext.get_ciphers() method to get a list of all enabled ciphers.
This commit is contained in:
parent
dffa3949c7
commit
25bfcd5d9e
|
@ -1259,6 +1259,62 @@ to speed up repeated connections from the same clients.
|
|||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. method:: SSLContext.get_ciphers()
|
||||
|
||||
Get a list of enabled ciphers. The list is in order of cipher priority.
|
||||
See :meth:`SSLContext.set_ciphers`.
|
||||
|
||||
Example::
|
||||
|
||||
>>> ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
|
||||
>>> ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
|
||||
>>> ctx.get_ciphers() # OpenSSL 1.0.x
|
||||
[{'alg_bits': 256,
|
||||
'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA '
|
||||
'Enc=AESGCM(256) Mac=AEAD',
|
||||
'id': 50380848,
|
||||
'name': 'ECDHE-RSA-AES256-GCM-SHA384',
|
||||
'protocol': 'TLSv1/SSLv3',
|
||||
'strength_bits': 256},
|
||||
{'alg_bits': 128,
|
||||
'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA '
|
||||
'Enc=AESGCM(128) Mac=AEAD',
|
||||
'id': 50380847,
|
||||
'name': 'ECDHE-RSA-AES128-GCM-SHA256',
|
||||
'protocol': 'TLSv1/SSLv3',
|
||||
'strength_bits': 128}]
|
||||
|
||||
On OpenSSL 1.1 and newer the cipher dict contains additional fields::
|
||||
>>> ctx.get_ciphers() # OpenSSL 1.1+
|
||||
[{'aead': True,
|
||||
'alg_bits': 256,
|
||||
'auth': 'auth-rsa',
|
||||
'description': 'ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA '
|
||||
'Enc=AESGCM(256) Mac=AEAD',
|
||||
'digest': None,
|
||||
'id': 50380848,
|
||||
'kea': 'kx-ecdhe',
|
||||
'name': 'ECDHE-RSA-AES256-GCM-SHA384',
|
||||
'protocol': 'TLSv1.2',
|
||||
'strength_bits': 256,
|
||||
'symmetric': 'aes-256-gcm'},
|
||||
{'aead': True,
|
||||
'alg_bits': 128,
|
||||
'auth': 'auth-rsa',
|
||||
'description': 'ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA '
|
||||
'Enc=AESGCM(128) Mac=AEAD',
|
||||
'digest': None,
|
||||
'id': 50380847,
|
||||
'kea': 'kx-ecdhe',
|
||||
'name': 'ECDHE-RSA-AES128-GCM-SHA256',
|
||||
'protocol': 'TLSv1.2',
|
||||
'strength_bits': 128,
|
||||
'symmetric': 'aes-128-gcm'}]
|
||||
|
||||
Availability: OpenSSL 1.0.2+
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. method:: SSLContext.set_default_verify_paths()
|
||||
|
||||
Load a set of default "certification authority" (CA) certificates from
|
||||
|
|
|
@ -834,6 +834,15 @@ class ContextTests(unittest.TestCase):
|
|||
with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"):
|
||||
ctx.set_ciphers("^$:,;?*'dorothyx")
|
||||
|
||||
@unittest.skipIf(ssl.OPENSSL_VERSION_INFO < (1, 0, 2, 0, 0), 'OpenSSL too old')
|
||||
def test_get_ciphers(self):
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
ctx.set_ciphers('ECDHE+AESGCM:!ECDSA')
|
||||
names = set(d['name'] for d in ctx.get_ciphers())
|
||||
self.assertEqual(names,
|
||||
{'ECDHE-RSA-AES256-GCM-SHA384',
|
||||
'ECDHE-RSA-AES128-GCM-SHA256'})
|
||||
|
||||
@skip_if_broken_ubuntu_ssl
|
||||
def test_options(self):
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
|
||||
|
|
|
@ -77,6 +77,9 @@ Core and Builtins
|
|||
Library
|
||||
-------
|
||||
|
||||
- Issue #27866: Add SSLContext.get_ciphers() method to get a list of all
|
||||
enabled ciphers.
|
||||
|
||||
- Issue #27744: Add AF_ALG (Linux Kernel crypto) to socket module.
|
||||
|
||||
- Issue #26470: Port ssl and hashlib module to OpenSSL 1.1.0.
|
||||
|
|
117
Modules/_ssl.c
117
Modules/_ssl.c
|
@ -1519,6 +1519,76 @@ cipher_to_tuple(const SSL_CIPHER *cipher)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000UL
|
||||
static PyObject *
|
||||
cipher_to_dict(const SSL_CIPHER *cipher)
|
||||
{
|
||||
const char *cipher_name, *cipher_protocol;
|
||||
|
||||
unsigned long cipher_id;
|
||||
int alg_bits, strength_bits, len;
|
||||
char buf[512] = {0};
|
||||
#if OPENSSL_VERSION_1_1
|
||||
int aead, nid;
|
||||
const char *skcipher = NULL, *digest = NULL, *kx = NULL, *auth = NULL;
|
||||
#endif
|
||||
PyObject *retval;
|
||||
|
||||
retval = PyDict_New();
|
||||
if (retval == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* can be NULL */
|
||||
cipher_name = SSL_CIPHER_get_name(cipher);
|
||||
cipher_protocol = SSL_CIPHER_get_version(cipher);
|
||||
cipher_id = SSL_CIPHER_get_id(cipher);
|
||||
SSL_CIPHER_description(cipher, buf, sizeof(buf) - 1);
|
||||
len = strlen(buf);
|
||||
if (len > 1 && buf[len-1] == '\n')
|
||||
buf[len-1] = '\0';
|
||||
strength_bits = SSL_CIPHER_get_bits(cipher, &alg_bits);
|
||||
|
||||
#if OPENSSL_VERSION_1_1
|
||||
aead = SSL_CIPHER_is_aead(cipher);
|
||||
nid = SSL_CIPHER_get_cipher_nid(cipher);
|
||||
skcipher = nid != NID_undef ? OBJ_nid2ln(nid) : NULL;
|
||||
nid = SSL_CIPHER_get_digest_nid(cipher);
|
||||
digest = nid != NID_undef ? OBJ_nid2ln(nid) : NULL;
|
||||
nid = SSL_CIPHER_get_kx_nid(cipher);
|
||||
kx = nid != NID_undef ? OBJ_nid2ln(nid) : NULL;
|
||||
nid = SSL_CIPHER_get_auth_nid(cipher);
|
||||
auth = nid != NID_undef ? OBJ_nid2ln(nid) : NULL;
|
||||
#endif
|
||||
|
||||
retval = Py_BuildValue(
|
||||
"{sksssssssisi"
|
||||
#if OPENSSL_VERSION_1_1
|
||||
"sOssssssss"
|
||||
#endif
|
||||
"}",
|
||||
"id", cipher_id,
|
||||
"name", cipher_name,
|
||||
"protocol", cipher_protocol,
|
||||
"description", buf,
|
||||
"strength_bits", strength_bits,
|
||||
"alg_bits", alg_bits
|
||||
#if OPENSSL_VERSION_1_1
|
||||
,"aead", aead ? Py_True : Py_False,
|
||||
"symmetric", skcipher,
|
||||
"digest", digest,
|
||||
"kea", kx,
|
||||
"auth", auth
|
||||
#endif
|
||||
);
|
||||
return retval;
|
||||
|
||||
error:
|
||||
Py_XDECREF(retval);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*[clinic input]
|
||||
_ssl._SSLSocket.shared_ciphers
|
||||
[clinic start generated code]*/
|
||||
|
@ -2478,6 +2548,52 @@ _ssl__SSLContext_set_ciphers_impl(PySSLContext *self, const char *cipherlist)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000UL
|
||||
/*[clinic input]
|
||||
_ssl._SSLContext.get_ciphers
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
_ssl__SSLContext_get_ciphers_impl(PySSLContext *self)
|
||||
/*[clinic end generated code: output=a56e4d68a406dfc4 input=a2aadc9af89b79c5]*/
|
||||
{
|
||||
SSL *ssl = NULL;
|
||||
STACK_OF(SSL_CIPHER) *sk = NULL;
|
||||
SSL_CIPHER *cipher;
|
||||
int i=0;
|
||||
PyObject *result = NULL, *dct;
|
||||
|
||||
ssl = SSL_new(self->ctx);
|
||||
if (ssl == NULL) {
|
||||
_setSSLError(NULL, 0, __FILE__, __LINE__);
|
||||
goto exit;
|
||||
}
|
||||
sk = SSL_get_ciphers(ssl);
|
||||
|
||||
result = PyList_New(sk_SSL_CIPHER_num(sk));
|
||||
if (result == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) {
|
||||
cipher = sk_SSL_CIPHER_value(sk, i);
|
||||
dct = cipher_to_dict(cipher);
|
||||
if (dct == NULL) {
|
||||
Py_CLEAR(result);
|
||||
goto exit;
|
||||
}
|
||||
PyList_SET_ITEM(result, i, dct);
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ssl != NULL)
|
||||
SSL_free(ssl);
|
||||
return result;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
static int
|
||||
do_protocol_selection(int alpn, unsigned char **out, unsigned char *outlen,
|
||||
|
@ -3645,6 +3761,7 @@ static struct PyMethodDef context_methods[] = {
|
|||
_SSL__SSLCONTEXT_SET_SERVERNAME_CALLBACK_METHODDEF
|
||||
_SSL__SSLCONTEXT_CERT_STORE_STATS_METHODDEF
|
||||
_SSL__SSLCONTEXT_GET_CA_CERTS_METHODDEF
|
||||
_SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
@ -378,6 +378,27 @@ exit:
|
|||
return return_value;
|
||||
}
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER >= 0x10002000UL)
|
||||
|
||||
PyDoc_STRVAR(_ssl__SSLContext_get_ciphers__doc__,
|
||||
"get_ciphers($self, /)\n"
|
||||
"--\n"
|
||||
"\n");
|
||||
|
||||
#define _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF \
|
||||
{"get_ciphers", (PyCFunction)_ssl__SSLContext_get_ciphers, METH_NOARGS, _ssl__SSLContext_get_ciphers__doc__},
|
||||
|
||||
static PyObject *
|
||||
_ssl__SSLContext_get_ciphers_impl(PySSLContext *self);
|
||||
|
||||
static PyObject *
|
||||
_ssl__SSLContext_get_ciphers(PySSLContext *self, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
return _ssl__SSLContext_get_ciphers_impl(self);
|
||||
}
|
||||
|
||||
#endif /* (OPENSSL_VERSION_NUMBER >= 0x10002000UL) */
|
||||
|
||||
PyDoc_STRVAR(_ssl__SSLContext__set_npn_protocols__doc__,
|
||||
"_set_npn_protocols($self, protos, /)\n"
|
||||
"--\n"
|
||||
|
@ -1128,6 +1149,10 @@ exit:
|
|||
#define _SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF
|
||||
#endif /* !defined(_SSL__SSLSOCKET_SELECTED_ALPN_PROTOCOL_METHODDEF) */
|
||||
|
||||
#ifndef _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF
|
||||
#define _SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF
|
||||
#endif /* !defined(_SSL__SSLCONTEXT_GET_CIPHERS_METHODDEF) */
|
||||
|
||||
#ifndef _SSL__SSLCONTEXT_SET_ECDH_CURVE_METHODDEF
|
||||
#define _SSL__SSLCONTEXT_SET_ECDH_CURVE_METHODDEF
|
||||
#endif /* !defined(_SSL__SSLCONTEXT_SET_ECDH_CURVE_METHODDEF) */
|
||||
|
@ -1143,4 +1168,4 @@ exit:
|
|||
#ifndef _SSL_ENUM_CRLS_METHODDEF
|
||||
#define _SSL_ENUM_CRLS_METHODDEF
|
||||
#endif /* !defined(_SSL_ENUM_CRLS_METHODDEF) */
|
||||
/*[clinic end generated code: output=6057f95343369849 input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=2e7907a7d8f97ccf input=a9049054013a1b77]*/
|
||||
|
|
Loading…
Reference in New Issue