Проверка клиентских сертификатов в PyOpenSSL - PullRequest
16 голосов
/ 01 февраля 2012

Я пишу приложение, для которого требуется установить сертификат в браузере клиента.Я нашел это в документации PyOpenSSL для объекта «Контекст», но я не вижу ничего о том, как обратный вызов должен проверять сертификат, только то, что он должен каким-то образом.

   set_verify(mode, callback)
      Set the verification flags for this Context object to mode and
      specify that callback should be used for verification callbacks.
      mode should be one of VERIFY_NONE and VERIFY_PEER. If
      VERIFY_PEER is used, mode can be OR:ed with
      VERIFY_FAIL_IF_NO_PEER_CERT and VERIFY_CLIENT_ONCE to further
      control the behaviour. callback should take five arguments: A
      Connection object, an X509 object, and three integer variables,
      which are in turn potential error number, error depth and return
      code. callback should return true if verification passes and
      false otherwise.

IЯ говорю объекту Context, где мои (самозаверяющие) ключи (см. ниже), поэтому, я думаю, я не понимаю, почему для библиотеки недостаточно проверить, является ли сертификат, представленный клиентом, действительным.Что нужно делать в этой функции обратного вызова?

class SecureAJAXServer(PlainAJAXServer):
    def __init__(self, server_address, HandlerClass):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = SSL.Context(SSL.SSLv23_METHOD)
        ctx.use_privatekey_file ('keys/server.key')
        ctx.use_certificate_file('keys/server.crt')
        ctx.set_session_id("My_experimental_AJAX_Server")
        ctx.set_verify( SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT | SSL.VERIFY_CLIENT_ONCE, callback_func )
        self.socket = SSL.Connection(ctx, socket.socket(self.address_family, self.socket_type))
        self.server_bind()
        self.server_activate()

Предостережение: здесь код для удовольствия, не для профессионалов, поэтому, если мой Q показывает мою общую хромоту, наивность и / или фундаментальное отсутствие понимания, когда дело доходит доSSL, пожалуйста, не будь слишком грубым!

Спасибо:)

Роджер

1 Ответ

6 голосов
/ 02 февраля 2012

В документации OpenSSL для set_verify() ключ, который вас волнует, - это код возврата :

, который должен принимать пять аргументов:Объект Connection, объект X509 и три целочисленные переменные, которые в свою очередь представляют собой номер потенциальной ошибки, глубину ошибки и код возврата .обратный вызов должен возвращать true, если проверка прошла успешно, и false в противном случае.

Существует полный рабочий пример, который более или менее показывает, что вы хотите сделать: Когда проверяются клиентские сертификаты?

По сути, вы можете игнорировать первые 4 аргумента и просто проверить значение кода возврата в пятом аргументе следующим образом:

from OpenSSL.SSL import Context, Connection, SSLv23_METHOD
from OpenSSL.SSL import VERIFY_PEER, VERIFY_FAIL_IF_NO_PEER_CERT, VERIFY_CLIENT_ONCE

class SecureAJAXServer(BaseServer):
    def verify_callback(connection, x509, errnum, errdepth, ok):
        if not ok:
            print "Bad Certs"
        else:
            print "Certs are fine"
        return ok

    def __init__(self, server_address, HandlerClass):
        BaseServer.__init__(self, server_address, HandlerClass)
        ctx = Context(SSLv23_METHOD)
        ctx.use_privatekey_file ('keys/server.key')
        ctx.use_certificate_file('keys/server.crt')
        ctx.set_session_id("My_experimental_AJAX_Server")
        ctx.set_verify( VERIFY_PEER | VERIFY_FAIL_IF_NO_PEER_CERT | VERIFY_CLIENT_ONCE, verify_callback )
        self.socket = Connection(ctx, socket.socket(self.address_family, self.socket_type))
        self.server_bind()
        self.server_activate()

Примечание: я сделал еще одно изменение, которое from OpenSSL.SSL import ...немного упростить ваш код во время его тестирования, чтобы у вас не было префикса SSL. перед каждым символом импорта.

...