2011-02-10 3 views
4

Это следование этого вопроса: SSL handshake failures when no data was sent over Twisted TLSConnectionКак проверить, что TLS рукопожатие было завершить в Twisted

я реализовал простой сервер 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 

ответ

4

Объект контекста SSL может быть сконфигурирован с помощью «информационного обратного вызова» - Context.set_info_callback. Это оболочка вокруг SSL_CTX_set_info_callback. К сожалению, немного более удобный (в данном случае) SSL_set_info_callback для указания обратного вызова для одного соединения не обнаружен pyOpenSSL.

Помимо всего прочего, обратный вызов информации вызывается, когда рукопожатие завершается. С несколькими акробатиками вы должны будете превратить это уведомление в Отложенный или какой-либо другой обратный вызов в протокол.

Для получения более подробной информации см. pyOpenSSL set_info_callback documentation и OpenSSL SSL_CTX_set_info_callback documentation.

+1

Спасибо, очень много :). Из документации pyOpenSSL выглядит, что Context.set_info_callback передает объект Connection в обратный вызов ... Я предполагаю, что могу подключить этот обратный вызов, чтобы установить флаги handshake_in_progress и handshake_done в соединении. –

+0

@Adi - Вы выяснили способ сделать это? Я проверил, что info_callback получает OpenSSL.SSL.Экземпляр подключения и вы можете проверить, где флажки, чтобы определить, что рукопожатие уже выполнено, но я не вижу никакого готового способа получить экземпляр Twisted Protocol из экземпляра Connection. – Von

+0

@ Von Я добавил свое текущее грязное решение. Я попытался посмотреть значения set_info_callback, но не смог определить правильное значение, чтобы проверить, выполнено ли рукопожатие. –

5

Я предоставляю код, который реализует ответ Жан-Поля.

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 протокола.

То, что я хотел бы сделать, это вызвать обратный вызов моего экземпляра протокола после того, как соединение было выполнено, и квитирование TLS завершено, поэтому я могу быть уверен, что проверка сертификата мне по душе, прежде чем продолжить.

+0

Вы можете сделать: 'ctx.set_info_callback (lambda conn, где, ret: self.infoCallback (conn, where, ret))', а затем ваш 'infoCallback' является истинным методом для объекта' self' и может затем использовать его как пожелает. –

0

Я нашел, используя loseConnection() ненадежный из-за проблемы со связями. Его можно вызвать, и соединение никогда не будет полностью отключено. Итак, для TLS я всегда использую abortConnection(). Он будет следить за тем, чтобы соединение было закрыто независимо от состояния рукопожатия.

Смежные вопросы