Проверка клиентских сертификатов в PyOpenSSL
Я пишу приложение, которое требует, чтобы сертификат был установлен в браузере клиента. Я нашел это в документации PyOpenSSL для объекта "Контекст", но я не вижу ничего о том, как обратный вызов должен проверять сертификат, только то, что он должен каким-то образом.
set_verify (режим, обратный вызов) Установите флажки проверки для этого объекта контекста в режим и укажите, что обратный вызов должен использоваться для проверочных обратных вызовов. режим должен быть одним из VERIFY_NONE и VERIFY_PEER. Если VERIFY_PEER используется, режим может быть ИЛИ: редактировать с VERIFY_FAIL_IF_NO_PEER_CERT и VERIFY_CLIENT_ONCE для дальнейшего контролировать поведение. обратный вызов должен принимать пять аргументов: A Объект подключения, объект X509 и три целочисленные переменные, которые в свою очередь являются номером потенциальной ошибки, глубиной ошибки и возвратом код. обратный вызов должен вернуть истину, если проверка прошла и ложь в противном случае.
Я говорю объекту 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.
префикс перед каждым символом импорта.