【问题标题】:How to check that TLS handshake was finalize in Twisted如何检查 Twisted 中的 TLS 握手是否已完成
【发布时间】:2011-06-24 15:58:28
【问题描述】:

这是这个问题的后续: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

【问题讨论】:

    标签: openssl twisted ssl pyopenssl


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 你可以这样做:ctx.set_info_callback(lambda conn,where,ret: self.infoCallback(conn,where,ret)) 然后你的 infoCallbackself 对象上的一个真正的方法,然后可以随意使用它。
      【解决方案3】:

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

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

      详情请参阅pyOpenSSL set_info_callback documentationOpenSSL SSL_CTX_set_info_callback documentation

      【讨论】:

      • 非常非常感谢:)。从 pyOpenSSL 文档看来 Context.set_info_callback 正在将 Connection 对象传递给回调...我想我可以挂钩此回调以在连接上设置 handshake_in_progress 和 handshake_done 标志。
      • @Adi - 你找到办法了吗?我已经验证 info_callback 为您提供 OpenSSL.SSL.Connection 实例,您可以测试 where 标志以确定握手已完成,但我没有看到任何从 Connection 实例获取 Twisted Protocol 实例的现成方法。
      • @Von 我添加了我当前的脏解决方案。我试图查看 set_info_callback 值,但无法找到正确的值来查看握手是否完成。
      • 来自 openssl.org/docs/ssl/SSL_CTX_set_info_callback.html>:SSL_CB_HANDSHAKE_DONE 0x20。这有帮助吗?
      • @Adi - 谢谢。有效,但对我正在尝试做的事情没有帮助,即在没有 OpenSSL 实际验证的情况下获得对等证书。我会把我学到的东西放在另一个答案中。
      猜你喜欢
      • 1970-01-01
      • 2021-01-02
      • 2017-11-13
      • 2014-07-22
      • 1970-01-01
      • 2019-04-26
      • 2021-08-21
      • 1970-01-01
      • 2015-08-14
      相关资源
      最近更新 更多