5

这是这个问题的后续:SSL handshake failures when no data was sent over Twisted TLSConnection

我已经实现了一个简单的 SSL 服务器,它会在客户端连接后立即关闭连接。

我正在使用 openssl 对其进行测试,但我遇到了握手失败:

$ openssl s_client -connect localhost:12345                             
CONNECTED(00000003) 2329:error:140790E5:SSL routines:SSL23_WRITE
:ssl handshake failure:s23_lib.c:188: 

问题是它TLS.Connection.loseConnection不等待正在进行的握手完成,而只是断开客户端。

附加到的回调OpenSSL.SSL.Connection.do_handshake会很棒......但不幸的是,我不知道这是否可以完成......或者如何做到这一点。

非常感谢我如何测试 TLS 握手已完成的任何提示。非常感谢!

这是代码

class ApplicationProtocol(Protocol):
        '''Protocol that closes the connection when connection is made.'''
        def connectionMade(self):
            self.transport.loseConnection()

# Here is a barebone TLS Server
serverFactory = ServerFactory()
serverFactory.protocol = ApplicationProtocol
server_cert_path = 'server.pem'
serverContextFactory = DefaultOpenSSLContextFactory(
            privateKeyFileName = server_cert_path,
            certificateFileName = server_cert_path,
            sslmethod=SSL.SSLv23_METHOD)

tlsFactory = TLSMemoryBIOFactory(serverContextFactory, False, serverFactory)
reactor.listenTCP(12345, tlsFactory)
#reactor.listenSSL(12345, serverFactory, serverContextFactory)

现在我解决了这个非常肮脏的问题,而且不是 100% 有效。

def tls_lose_connection(self):
    """
    Monkey patching for TLSMemoryBIOProtocol to wait for handshake to end,
    before closing the connection.

    Send a TLS close alert and close the underlying connection.
    """

    def close_connection():
        self.disconnecting = True
        if not self._writeBlockedOnRead:
            self._tlsConnection.shutdown()
            self._flushSendBIO()
            self.transport.loseConnection()

    # If we don't know if the handshake was done, we wait for a bit
    # and the close the connection.
    # This is done to avoid closing the connection in the middle of a
    # handshake.
    if not self._handshakeDone:
        reactor.callLater(0.5, close_connection)
    else:
        close_connection()


TLSMemoryBIOProtocol.loseConnection = tls_lose_connection
4

3 回答 3

6

我正在提供实现 Jean-Paul 答案的代码。

class ProxyClientTLSContextFactory(ssl.ClientContextFactory):
    isClient = 1

def getContext(self):
    ctx = SSL.Context(SSL.TLSv1_METHOD)
    logger = logging.GetLogger()
    def infoCallback(conn, where, ret):
        # conn is a OpenSSL.SSL.Connection
        # where is a set of flags telling where in the handshake we are
        # See http://www.openssl.org/docs/ssl/SSL_CTX_set_info_callback.html
        logger.debug("infoCallback %s %d %d" % (conn, where, ret))
        if where & SSL.SSL_CB_HANDSHAKE_START:
            logger.debug("Handshake started")
        if where & SSL.SSL_CB_HANDSHAKE_DONE:
            logger.debug("Handshake done")
    ctx.set_info_callback(infoCallback)
    return ctx

我在 infoCallback() 中遇到的问题是我不知道如何从 SSL.Connection 回到相关的 Twisted Protocol 实例。

我想做的是在建立连接并完成 TLS 握手之后在我的协议实例上调用回调,以便在继续之前确保证书验证符合我的喜好。

于 2011-09-11T02:38:33.643 回答
4

SSL 上下文对象可以配置一个“信息回调”——Context.set_info_callback。这是 SSL_CTX_set_info_callback 的包装器。不幸的是,pyOpenSSL 没有公开稍微方便(在这种情况下)为单个连接指定回调的 SSL_set_info_callback。

除其他事项外,当握手完成时会调用 info 回调。通过一些杂技,您应该能够将此通知转换为延迟或其他协议回调。

有关详细信息,请参阅pyOpenSSL set_info_callback 文档OpenSSL SSL_CTX_set_info_callback 文档。

于 2011-02-10T14:01:31.343 回答
0

loseConnection()由于握手问题,我发现使用不可靠。可以调用它,并且连接永远不会完全断开。因此,对于 TLS,我总是使用它abortConnection()。无论握手状态如何,它将确保连接关闭。

于 2015-03-27T13:33:15.260 回答