如何检查 TLS 握手是否已在 Twisted 中完成

发布于 2024-10-16 18:06:23 字数 2231 浏览 4 评论 0原文

这是这个问题的后续:SSL握手失败当没有数据通过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

This is a follow up of this question: SSL handshake failures when no data was sent over Twisted TLSConnection

I have implemented a simple SSL server that closes the connection as soon as the client is connected.

I am testing it with openssl and I got this handshake failure:

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

The problem is that TLS.Connection.loseConnection does not wait for the ongoing handshake to be done and just disconnects the client.

A callback attached to OpenSSL.SSL.Connection.do_handshake would have been great... but unfortunately I don't know if this can be done... or how to do it.

Any hints in how I could test that a TLS handshake was done is much appreciated. Many thanks!

Here is the code

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)

For now I solve this really dirty and not 100% valid.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

双手揣兜 2024-10-23 18:06:23

我提供了实现让-保罗答案的代码。

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 握手后在我的协议实例上调用回调,这样我就可以在继续之前确保证书验证符合我的喜好。

I'm providing code that implements Jean-Paul's answer.

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

The problem I ran into inside of infoCallback() is that I have no idea how to get from the SSL.Connection back to the associated Twisted Protocol instance.

What I'd like to do is invoke a callback on my Protocol instance after the connection has been made and the TLS handshake has been completed so I can be sure the certificate validation is to my liking before I proceed.

↙厌世 2024-10-23 18:06:23

SSL 上下文对象可以使用“信息回调”进行配置 - Context.set_info_callback。这是 SSL_CTX_set_info_callback 的包装。不幸的是,pyOpenSSL 没有公开稍微方便一点(在本例中)的用于为单个连接指定回调的 SSL_set_info_callback 。

除此之外,握手完成时会调用信息回调。通过一些技巧,您应该能够将此通知转换为延迟或协议上的其他回调。

请参阅 pyOpenSSL set_info_callback 文档OpenSSL SSL_CTX_set_info_callback 文档了解详细信息。

The SSL context object can be configured with an "info callback" - Context.set_info_callback. This is a wrapper around SSL_CTX_set_info_callback. The slightly more convenient (in this case) SSL_set_info_callback for specifying a callback for a single connection is not exposed by pyOpenSSL, unfortunately.

Amongst other things, the info callback is invoked when the handshake completes. With a few acrobatics, you should be able to turn this notification into a Deferred or some other callback onto the protocol.

See the pyOpenSSL set_info_callback documentation and the OpenSSL SSL_CTX_set_info_callback documentation for details.

深府石板幽径 2024-10-23 18:06:23

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

I found using loseConnection() unreliable because of the handshaking issue. It's possible to call it and the connection is never fully disconnected. So, for TLS I always use abortConnection() instead. It will make sure the connection is closed regardless of the state of the handshake.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文