问题描述
在python 2.7.8到2.7.9升级中,ssl模块已从使用更改为
In the python 2.7.8 to 2.7.9 upgrade, the ssl module changed from 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
命令行(请参阅),例如,使用openssl v1.0.1k,我可以看到默认的python 2.7.8密码列表扩展为什么:
For example, to figure out what "ordered SSL cipher preference list" a cipher list expands to, I'd normally use the openssl ciphers
command line (see man page) e.g with openssl v1.0.1k I can see what that default python 2.7.8 cipher list expands to:
$ 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!
当在python动态加载openssl ciphers
使用的相同OpenSSL库的Linux上运行时效果很好.
That works great when on Linux where python is dynamically loading the same OpenSSL library that openssl ciphers
uses:
$ 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内置库不同的密码.
However, on Windows the Python build appears to statically link the OpenSSL library. This means that the openssl ciphers
command cannot help me, because it uses a different version of the library, which may have support for different ciphers than the library built into python.
我可以很容易地找出使用哪个版本的OpenSSL轻松构建两个python版本:
I can find out what version of OpenSSL was used to build each of the two python releases easily enough:
$ 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中的lib相同的选项进行编译,并且从手册页中我们知道
But even if I could find and download a build of the openssl
command line for both the 1.0.1h and 1.0.1j releases, I cannot be sure that they were compiled with the same options as the lib built into python, and from the man page we know that
那么,有没有办法让python的ssl模块为我提供类似于openssl ciphers -v
命令的输出?
So, is there a way to get python's ssl module to give me output similar to that from the openssl ciphers -v
command?
推荐答案
您可能想在 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)); }
meth = SSLv23_server_method();
ctx = SSL_CTX_new(meth);
SSL_CTX_set_cipher_list(ctx, ciphers)
, whereasciphers
is your stringssl = 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)); }
在Python 3.4中,_ssl的set_ciphers
方法中为上下文调用了SSL_CTX_set_cipher_list
函数.您可以使用以下方法实现相同的目的:
The SSL_CTX_set_cipher_list
function is called in Python 3.4 in _ssl's set_ciphers
method for contexts. You can achieve the same using:
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()
,不幸的是,该SSL_get1_supported_ciphers()
在Python的 _ssl.c
.您可以获得的最接近的是SSLSocket
实例的shared_ciphers()
方法. (当前的)实现是
The next step would be calling SSL_get1_supported_ciphers()
which, unfortunately, is not used in Python's _ssl.c
. The closest you can get is the shared_ciphers()
method of SSLSocket
instances. The (current) implementation is
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
实现中的循环非常相似,并以与ciphers.c
中的循环相同的顺序返回Python密码列表.
That is, this loop is very similar as in the ciphers.c
implementation above, and returns a Python list of ciphers, in the same order as the loop in ciphers.c
would.
继续上面的sslsock = SSLSocket(...)
示例,您不能在连接套接字之前调用sslsock.shared_ciphers()
.否则,Python的_ssl模块不会创建读取密码所需的低级OpenSSL SSL对象.这与ciphers.c
中的实现不同,该实现无需连接即可创建低级SSL对象.
Continuing with the sslsock = SSLSocket(...)
example from above, you cannot call sslsock.shared_ciphers()
before the socket is connected. Otherwise, Python's _ssl module does not create a low-level OpenSSL SSL object, which is needed to read the ciphers. That is different from the implementation in ciphers.c
, which creates a low level SSL object without requiring a connection.
那是我走了多远,希望对您有所帮助,也许您可以根据这些发现来弄清楚您的需求.
That is how far I got, I hope that helps, and maybe you can figure out what you need based on these findings.
这篇关于如何列出静态链接的python版本中可用的所有openssl密码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!