带有TLSv1.2和转发保密性的Python粘贴SSL服务器 [英] Python Paste SSL server with TLSv1.2 and Forward Secrecy

查看:140
本文介绍了带有TLSv1.2和转发保密性的Python粘贴SSL服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于Mac OS X上的Python应用程序,我需要设置一个具有TLSv1.2,正向保密和不带RC4密码的HTTPS服务器.使用Paste和pyOpenSSL,我编写了以下代码:

for a Python app on Mac OS X, I need to setup an HTTPS server with TLSv1.2, Forward Secrecy, and without RC4 ciphers. Using Paste and pyOpenSSL I have write the following code:

from paste import httpserver
from OpenSSL import SSL

context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file("/Path/to/my/private.key")
context.use_certificate_chain_file("/Path/to/my/chain-cert.pem")
context.set_options(SSL.OP_NO_SSLv2)
context.set_options(SSL.OP_NO_SSLv3)
context.set_options(SSL.OP_SINGLE_DH_USE)
context.set_cipher_list("EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4")
logger.debug("OPENSSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION))

httpserver.serve(app_logged, host=http_host, port=http_port, server_version=server_version, ssl_context=context, use_threadpool=True, threadpool_workers=15, request_queue_size=5)

但是Safari,Chrome和OpenSSL客户端无法连接到我的服务器,并显示错误"没有共享密码".那么,我做错了什么?

But Safari, Chrome and OpenSSL client failed to connect to my server with the error "no shared cipher". So, what did I do wrong?

注意:默认的OS X版本的Python(2.7.6)和OpenSSL(0.9.8)与TLSv1.2不兼容,因此我不得不编译OpenSSL 1.0.2和Python 2.7 .10来源.

Note: Default OS X versions of Python (2.7.6) and OpenSSL (0.9.8) are not compatible with TLSv1.2, so I had to compile OpenSSL 1.0.2 and Python 2.7.10 from sources.

如果我检查自己的OpenSSL密码列表,它会给我以下信息:

If I check my OpenSSL ciphers list, it give me this:

$ /usr/local/bin/openssl ciphers -V 'EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4'
0xC0,0x2C - ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(256) Mac=AEAD
0xC0,0x2B - ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AESGCM(128) Mac=AEAD
0xC0,0x30 - ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(256) Mac=AEAD
0xC0,0x2F - ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AESGCM(128) Mac=AEAD
0xC0,0x24 - ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA384
0xC0,0x23 - ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA256
0xC0,0x28 - ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA384
0xC0,0x27 - ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA256
0xC0,0x14 - ECDHE-RSA-AES256-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(256)  Mac=SHA1
0xC0,0x0A - ECDHE-ECDSA-AES256-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(256)  Mac=SHA1
0xC0,0x13 - ECDHE-RSA-AES128-SHA    SSLv3 Kx=ECDH     Au=RSA  Enc=AES(128)  Mac=SHA1
0xC0,0x09 - ECDHE-ECDSA-AES128-SHA  SSLv3 Kx=ECDH     Au=ECDSA Enc=AES(128)  Mac=SHA1
0x00,0x9F - DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(256) Mac=AEAD
0x00,0x6B - DHE-RSA-AES256-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA256
0x00,0x39 - DHE-RSA-AES256-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(256)  Mac=SHA1
0x00,0x88 - DHE-RSA-CAMELLIA256-SHA SSLv3 Kx=DH       Au=RSA  Enc=Camellia(256) Mac=SHA1
0x00,0x9E - DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH       Au=RSA  Enc=AESGCM(128) Mac=AEAD
0x00,0x67 - DHE-RSA-AES128-SHA256   TLSv1.2 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA256
0x00,0x33 - DHE-RSA-AES128-SHA      SSLv3 Kx=DH       Au=RSA  Enc=AES(128)  Mac=SHA1
0x00,0x9A - DHE-RSA-SEED-SHA        SSLv3 Kx=DH       Au=RSA  Enc=SEED(128) Mac=SHA1
0x00,0x45 - DHE-RSA-CAMELLIA128-SHA SSLv3 Kx=DH       Au=RSA  Enc=Camellia(128) Mac=SHA1

例如,我知道Safari 8与密码"ECDHE-RSA-AES128-SHA256"兼容,那么为什么会有无共享密码"错误?

and I know that Safari 8 is compatible with cipher "ECDHE-RSA-AES128-SHA256" for example, so why I have a 'no shared cipher' error?

$ /usr/local/bin/openssl s_client -connect 192.168.0.17:4443 -tls1_2
CONNECTED(00000003)
140735274361680:error:14094410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:s3_pkt.c:1472:SSL alert number 40
140735274361680:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:656:
---
no peer certificate available
---
No client certificate CA names sent
---
SSL handshake has read 7 bytes and written 0 bytes
---
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
Protocol  : TLSv1.2
Cipher    : 0000
Session-ID:
Session-ID-ctx:
Master-Key:
Key-Arg   : None
PSK identity: None
PSK identity hint: None
SRP username: None
Start Time: 1439975452
Timeout   : 7200 (sec)
Verify return code: 0 (ok)
---

替代:如果我将密码列表更改为

Alternative: If I change my cipher list to

context.set_cipher_list("HIGH:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:@STRENGTH")

它可以正常工作,浏览器和openssl客户端能够与基于协议TLSv1.2的密码"AES256-GCM-SHA384"建立安全连接,但它不是ECDHE密码(因此没有前向保密性).

It works, browsers and openssl client are able to establish a secured connection with cipher 'AES256-GCM-SHA384' on protocol TLSv1.2, but it is not an ECDHE cipher (therefore no Forward Secrecy).

编辑正确答案:

对于DH密码,您需要使用PEM格式的DH参数文件,可以使用以下命令生成一个:

For the DH ciphers, you need a DH parameters file in PEM format, you can generate one with the following command:

$ /usr/local/bin/openssl dhparam 2048 -out dhparams.pem

对于ECDHE密码,您将需要为SSL上下文设置一条椭圆曲线.您可以使用pyOpenSSL检索系统上的可用曲线:

For the ECDHE ciphers, you will need to set an elliptic curve for the SSL context. You can retrieve the available curves on your system with pyOpenSSL:

OpenSSL.crypto.get_elliptic_curves()

请给我们正确的以下python代码:

Which give us the correct following python code:

from paste import httpserver
from OpenSSL import SSL
from OpenSSL import crypto

context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file("/Path/to/my/private.key")
context.use_certificate_chain_file("/Path/to/my/chain-cert.pem")
context.load_tmp_dh("/Path/to/my/dhparams.pem")
context.set_tmp_ecdh(crypto.get_elliptic_curve("prime256v1"))
context.set_options(SSL.OP_NO_SSLv2)
context.set_options(SSL.OP_NO_SSLv3)
context.set_options(SSL.OP_SINGLE_DH_USE)
context.set_cipher_list("EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4")
logger.debug("OPENSSL version: %s" % SSL.SSLeay_version(SSL.SSLEAY_VERSION))

httpserver.serve(app_logged, host=http_host, port=http_port, server_version=server_version, ssl_context=context, use_threadpool=True, threadpool_workers=15, request_queue_size=5)

推荐答案

要支持DH密码(DHE-RSA -...),您需要具有DH params文件并指定它:

To have support for DH ciphers (DHE-RSA-...) you need to have a DH params file and specify it:

 context.load_tmp_dh("dhparams.pem")

要创建此类文件,您可以使用OpenSSL

To create such file you might use OpenSSL

 openssl dhparam -out dhparams.pem 2048

要支持ECDH密码,您需要指定应使用的曲线.我没有支持它的pyOpenSSL版本,但是根据文档应该是

To support ECDH ciphers you need to specify which curve should be used. I don't have a pyOpenSSL version which supports it but according to the documentation it should be

context.set_tmp_ecdh( OpenSSL.crypto.get_elliptic_curve( "prime256v1" ))

这篇关于带有TLSv1.2和转发保密性的Python粘贴SSL服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆