Проверка сертификатов клиентов в PyOpenSSL
Я пишу приложение, которое требует, чтобы сертификат был установлен в клиентском браузере. Я нашел это в документах 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.
Я рассказываю объект 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
В документации OpenSSL для set_verify()
ключ, который вам нужен, это код возврата:
Обратный вызов должен принимать пять аргументов: Объект соединения, 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.
.