在python 2.7.8到2.7.9升级中,ssl模块由using改为
_DEFAULT_CIPHERS = 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
到
_DEFAULT_CIPHERS = (
'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:ECDH+RC4:'
'DH+RC4:RSA+RC4:!aNULL:!eNULL:!MD5'
)
我想知道这如何影响在与我在 Windows 上安装的 python 建立 SSL/TLS 连接时使用的实际“有序 SSL 密码首选项列表”。
例如,为了弄清楚密码列表扩展到什么“有序 SSL 密码首选项列表”,我通常会使用 openssl ciphers
命令行(参见 man page ),例如使用 openssl v1 .0.1k 我可以看到默认的 python 2.7.8 密码列表扩展为:
$ openssl ciphers -v 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2'
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA SSLv3 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES256-SHA SSLv3 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
SRP-DSS-AES-256-CBC-SHA SSLv3 Kx=SRP Au=DSS Enc=AES(256) Mac=SHA1
SRP-RSA-AES-256-CBC-SHA SSLv3 Kx=SRP Au=RSA Enc=AES(256) Mac=SHA1
...
snip!
在 Linux 上,python 动态加载 openssl ciphers
使用的相同 OpenSSL 库时效果很好:
$ ldd /usr/lib/python2.7/lib-dynload/_ssl.x86_64-linux-gnu.so | grep libssl
libssl.so.1.0.0 => /lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007ff75d6bf000)
$ ldd /usr/bin/openssl | grep libssl
libssl.so.1.0.0 => /lib/x86_64-linux-gnu/libssl.so.1.0.0 (0x00007fa48f0fe000)
但是,在 Windows 上,Python 构建似乎静态链接 OpenSSL 库。这意味着 openssl ciphers
命令无法帮助我,因为它使用了不同版本的库,它可能支持与 python 内置库不同的密码。
我可以很容易地找出分别使用哪个版本的 OpenSSL 来构建这两个 python 版本:
$ python-2.7.8/python -c 'import ssl; print ssl.OPENSSL_VERSION'
OpenSSL 1.0.1h 5 Jun 2014
$ python-2.7.9/python -c 'import ssl; print ssl.OPENSSL_VERSION'
OpenSSL 1.0.1j 15 Oct 2014
但即使我可以找到并下载 1.0.1h 和 1.0.1j 版本的 openssl
命令行版本,我也不能确定它们是使用与以下版本相同的选项编译的内置于 python 中的库,来自 man page我们知道
Some compiled versions of OpenSSL may not include all the ciphers listed here because some ciphers were excluded at compile time.
那么,有没有办法让 python 的 ssl 模块为我提供类似于 openssl ciphers -v
命令的输出?
最佳答案
您可能想查看 openssl cipher
的源代码位于 https://github.com/openssl/openssl/blob/master/apps/ciphers.c
关键的步骤似乎是:
-
meth = SSLv23_server_method();
-
ctx = SSL_CTX_new(meth);
-
SSL_CTX_set_cipher_list(ctx, ciphers)
,而ciphers
是你的字符串 -
ssl = SSL_new(ctx);
-
sk = SSL_get1_supported_ciphers(ssl);
-
for (i = 0; i < sk_SSL_CIPHER_num(sk); i++) { print SSL_CIPHER_get_name(sk_SSL_CIPHER_value(sk, i)); }
SSL_CTX_set_cipher_list
在 _ssl 的 set_ciphers
中的 Python 3.4 中调用函数上下文的方法。您可以使用以下方法实现相同的效果:
import socket
from ssl import SSLSocket
sslsock = SSLSocket(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
sslsock.context.set_ciphers('DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2')
下一步将调用 SSL_get1_supported_ciphers()
不幸的是,它没有在 Python 的 _ssl.c
中使用。 .您可以获得的最接近的是 shared_ciphers()
SSLSocket
的方法|实例。 (当前)实现是
static PyObject *PySSL_shared_ciphers(PySSLSocket *self)
{
[...]
ciphers = sess->ciphers;
res = PyList_New(sk_SSL_CIPHER_num(ciphers));
for (i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
PyObject *tup = cipher_to_tuple(sk_SSL_CIPHER_value(ciphers, i));
[...]
PyList_SET_ITEM(res, i, tup);
}
return res;
}
也就是说,这个循环与 ciphers.c
中的非常相似上面的实现,并返回一个 Python 密码列表,顺序与 ciphers.c
中的循环相同会的。
继续sslsock = SSLSocket(...)
上面的示例,您不能调用 sslsock.shared_ciphers()
在连接 socket 之前。否则,Python 的 _ssl 模块不会创建读取密码所需的低级 OpenSSL SSL 对象。这与 ciphers.c
中的实现不同,它创建一个低级别的 SSL 对象而不需要连接。
这就是我的进展,希望对您有所帮助,也许您可以根据这些发现找出您需要什么。
关于python - 如何列出静态链接的 python 版本中可用的所有 openssl 密码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28332448/