Как проверить, что рукопожатие TLS было завершено в Twisted
Это продолжение этого вопроса: сбои 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
3 ответа:
Объект контекста SSL можно настроить с помощью" info callback " - Context.set_info_callback. Это оболочка вокруг SSL_CTX_set_info_callback. Несколько более удобный (в данном случае) SSL_set_info_callback для указания обратного вызова для одного соединения не предоставляется pyOpenSSL, к сожалению.
Помимо прочего, информационный обратный вызов вызывается после завершения рукопожатия. С помощью нескольких акробатических трюков вы сможете превратить это уведомление в отложенное или какой - то другой обратный вызов по протоколу.
Смотрите документациюpyOpenSSL set_info_callback и документациюOpenSSL SSL_CTX_set_info_callback .
Я предоставляю код, который реализует ответ Жан-Поля.
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.Подключение обратно к соответствующему экземпляру скрученного протокола.
Что я хотел бы сделать, так это вызвать обратный вызов на моем экземпляре протокола после того, как соединение было сделано, и рукопожатие TLS было завершено, чтобы я мог быть уверен, что проверка сертификата мне нравится, прежде чем я продолжу.