SSLV3_ALERT_HANDSHAKE_FAILURE SNI 在 Python 2.9.10 中使用 Tornado 4.2

SSLV3_ALERT_HANDSHAKE_FAILURE with SNI using Tornado 4.2 in Python 2.9.10

我在 Python 2.7.10 中使用 ssl.SSLContext 正确设置 SNI 标志时遇到问题,握手每次都失败,我不知道为什么。

我是这样尝试的:

import ssl
import socket

if ssl.HAS_SNI:
    print "SNI is available"
print(ssl.OPENSSL_VERSION)

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
context.load_cert_chain('cacrt.pem', 'cakey.pem', 'password')

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock = context.wrap_socket(sock, server_hostname='virtServer')
sock.connect(('ip.to.the.server', 443))

http_client = tornado.httpclient.HTTPClient()
http_client.fetch('https://ip.to.the.server/some_url', method='GET',  ssl_options=context)

这是我得到的输出:

SNI is available
OpenSSL 0.9.8zd 8 Jan 2015
Traceback (most recent call last):
  File "test/steps/test.py", line 37, in <module>
    sock.connect(('10.59.71.242', 443))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 844, in connect
    self._real_connect(addr, False)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 835, in _real_connect
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 808, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:590)

我做错了什么导致了这个错误?我怎样才能更改我的代码来解决这个问题?

任何 ideas/help 对此将不胜感激。

谢谢, 问候, 亚罗

没有关于服务器的矿石信息很难判断,但我会尝试:

OpenSSL 0.9.8zd 8 Jan 2015

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

您正在将协议限制为 TLS 1.0。可能是服务器需要 TLS 1.2 或 TLS 1.1 或 SSL 3.0。请注意,您使用的 OpenSSL 版本不支持 TLS 1.1+。也可能是服务器没有共享密码。

尝试连接浏览器并查看使用的是哪个 TLS 版本和使用的密码。如果这可行但需要 TLS 1.1+,请尝试使用 curl 或 wget 创建连接。如果这是 public URL 使用 SSLLabs 检查支持的协议和密码。

http_client.fetch('https://ip.to.the.server/some_url', method='GET',  ssl_options=context)

如果你真的在这里使用IP地址,也可能是服务器不接受IP地址作为SNI名称的问题。如果给定的名称与配置不匹配,有些服务器会导致握手失败,而其他服务器只是 return 默认证书。除此之外,URL 中的主机名必须与证书中的名称相匹配,以便证书验证能够成功。

谢谢 Steffen,你的建议最终让我找到了解决方案。 问题不在于 TLS 版本或 OpenSSL,而是因为我没有指定密码并且必要的密码 (RC4-SHA) 不在 Python 2.7.10 的默认列表中。

context.set_ciphers('RC4-SHA')

此外,我无法将创建的上下文与 Tornado 一起使用,因为我需要提供一个特定的 server_hostname 形式,我所看到的只能在套接字对象上完成:

sock = context.wrap_socket(sock, server_hostname='virtServer')

相反,我使用了 sock.write('...') 和 sock.recv() 来发出请求并且一切正常。