当没有通过 Twisted TLSConnection 发送数据时 SSL 握手失败
我开始考虑通过扩展当前的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
SSL 握手由 pyOpenSSL
的
对象。它还可以通过do_handshake
方法发起>连接send
或recv
调用隐式启动。由reactor.connectSSL
和reactor.listenSSL
设置的传输依赖于后者。所以你的结论是正确的 - 如果没有通过连接发送数据,则永远不会执行握手。但是,
twisted.protocols.tls
连接建立后立即调用do_handshake
。如果您使用该 API 设置 SSL 服务器,我想您会看到问题得到解决。还有一个计划使用后者重新实现前者,因为后者似乎在以下方面工作得更好一般的。
The SSL handshake is initiated by the
do_handshake
method of the pyOpenSSLConnection
object. It can also be initiated implicitly by asend
orrecv
call. The transport set up byreactor.connectSSL
andreactor.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
callsdo_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.