当没有通过 Twisted TLSConnection 发送数据时 SSL 握手失败

发布于 2024-10-16 07:00:44 字数 2758 浏览 4 评论 0原文

我开始考虑通过扩展当前的 Twisted FTP 来实现显式 FTP。

大部分代码都很简单,实现 AUTH、PBSZ、PROT 很容易,我得到了一个有效的安全控制通道。

我的问题是数据通道。

客户端错误是:SSL例程','SSL3_READ_BYTES','ssl握手失败'

看起来只有当通过数据通道发送一些数据时才会调用SSL握手和关闭。 这会影响发送空文件或列出空文件夹时的情况,因为在关闭连接之前,客户端将调用 SSL shutdown。

我正在寻找一些关于在没有发送数据时如何以及在何处搜索修复 Twisted TLS 的 TLS 握手的建议。

此代码在列出不为空的文件夹时有效...但如果该文件夹不包含文件或文件夹,则会失败。

非常感谢!

def getDTPPort(self, factory):
    """
    Return a port for passive access, using C{self.passivePortRange}
    attribute.
    """
    for portn in self.passivePortRange:
        try:
            if self.protected_data:
                dtpPort = reactor.listenSSL(
                    port=portn, factory=factory,
                    contextFactory=self.ssl_context)
            else:
                dtpPort = self.listenFactory(portn, factory)

        except error.CannotListenError:
            continue
        else:
            return dtpPort
    raise error.CannotListenError('', portn,
        "No port available in range %s" %
        (self.passivePortRange,))

更新 1

我将更新此文本,因为注释格式不正确:

所以我最终得到:

def getDTPPort(self, factory):
    """
    Return a port for passive access, using C{self.passivePortRange}
    attribute.
    """
    for portn in self.passivePortRange:
        try:
            if self.protected_data:
                tls_factory = TLSMemoryBIOFactory(
                    contextFactory=self.ssl_context,
                    isClient=False,
                    wrappedFactory=factory)
                dtpPort = reactor.listenTCP(
                    port=portn, factory=tls_factory)
            else:
                dtpPort = self.listenFactory(portn, factory)

        except error.CannotListenError:
            continue
        else:
            return dtpPort
    raise error.CannotListenError('', portn,
        "No port available in range %s" %
        (self.passivePortRange,))

更新 2

问题是由于握手仍在运行时连接已关闭这一事实引起的。 我不知道如何检查 SSL 握手已完成的空连接。

所以我最终得到了这个愚蠢的代码

def loseConnection(self):
    """
    Send a TLS close alert and close the underlying connection.
    """
    self.disconnecting = True

    def close_connection():
        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.1, close_connection)
    else:
        close_connection()

I start looking at implementing explicit FTP by extending the current Twisted FTP.

Most of the code was straight forward and implementing AUTH, PBSZ, PROT was easy and I got a working secured control channel.

My problem is with the data channel.

The client side error is : SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure'

It looks like SSL handshake and shutdown are called only when some data was send over the data channel.
This affect the case when sending empty files or listing empty folders, since before closing the connection, the client will call the SSL shutdown.

I am looking after some suggestion for how and where I should search for fixing the TLS handshake from Twisted TLS when no data is sent.

This code works when listing folders that are not empty... but will fail if the folder contains no files or folders.

Many thanks!

def getDTPPort(self, factory):
    """
    Return a port for passive access, using C{self.passivePortRange}
    attribute.
    """
    for portn in self.passivePortRange:
        try:
            if self.protected_data:
                dtpPort = reactor.listenSSL(
                    port=portn, factory=factory,
                    contextFactory=self.ssl_context)
            else:
                dtpPort = self.listenFactory(portn, factory)

        except error.CannotListenError:
            continue
        else:
            return dtpPort
    raise error.CannotListenError('', portn,
        "No port available in range %s" %
        (self.passivePortRange,))

Update 1

I will update this text since comments are not well formated:

So I ended up with:

def getDTPPort(self, factory):
    """
    Return a port for passive access, using C{self.passivePortRange}
    attribute.
    """
    for portn in self.passivePortRange:
        try:
            if self.protected_data:
                tls_factory = TLSMemoryBIOFactory(
                    contextFactory=self.ssl_context,
                    isClient=False,
                    wrappedFactory=factory)
                dtpPort = reactor.listenTCP(
                    port=portn, factory=tls_factory)
            else:
                dtpPort = self.listenFactory(portn, factory)

        except error.CannotListenError:
            continue
        else:
            return dtpPort
    raise error.CannotListenError('', portn,
        "No port available in range %s" %
        (self.passivePortRange,))

Update 2

The problem is caused by the fact that the connection is closed while the handshake is still running.
I don't know how check on an empty connection that the SSL handshake was done.

So I ended up with this stupid code

def loseConnection(self):
    """
    Send a TLS close alert and close the underlying connection.
    """
    self.disconnecting = True

    def close_connection():
        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.1, close_connection)
    else:
        close_connection()

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

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

发布评论

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

评论(1

浮生未歇 2024-10-23 07:00:44

SSL 握手由 pyOpenSSL do_handshake 方法发起>连接对象。它还可以通过 sendrecv 调用隐式启动。由 reactor.connectSSLreactor.listenSSL 设置的传输依赖于后者。所以你的结论是正确的 - 如果没有通过连接发送数据,则永远不会执行握手。

但是,twisted.protocols.tls 连接建立后立即调用do_handshake。如果您使用该 API 设置 SSL 服务器,我想您会看到问题得到解决。

还有一个计划使用后者重新实现前者,因为后者似乎在以下方面工作得更好一般的。

The SSL handshake is initiated by the do_handshake method of the pyOpenSSL Connection object. It can also be initiated implicitly by a send or recv call. The transport set up by reactor.connectSSL and reactor.listenSSL relies on the latter. So your conclusion is correct - the handshake is never performed if no data is sent over the connection.

However, twisted.protocols.tls calls do_handshake as soon as the connection is made. If you set up your SSL server with that API instead, I think you'll see your problem resolved.

There is also a plan to reimplement the former using the latter, since the latter seems to work better in general.

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