Как проверить сертификат SSL на python?
Мне нужно проверить, что сертификат был подписан моим пользовательским ЦС. Используя утилиты командной строки OpenSSL, это легко сделать:
# Custom CA file: ca-cert.pem
# Cert signed by above CA: bob.cert
$ openssl verify -CAfile test-ca-cert.pem bob.cert
bob.cert: OK
Но мне нужно сделать то же самое в Python, и я действительно не хочу обращаться к утилитам командной строки. Насколько мне известно, M2Crypto является "самой полной" оболочкой python для OpenSSL, но я не могу понять, как выполнить то, что делает утилита командной строки!
Направляя этот вопрос для того, как выполнить эту же задачу в коде на C, мне удалось добраться примерно на полпути. Имена переменных, которые я выбрал, являются теми же, что и в исходном коде для командной строки командной строки openssl, см. openssl-xxx/apps/verify.c
.
import M2Crypto as m2
# Load the certificates
cacert = m2.X509.load_cert('test-ca-cert.pem') # Create cert object from CA cert file
bobcert = m2.X509.load_cert('bob.cert') # Create cert object from Bob cert file
cert_ctx = m2.X509.X509_Store() # Step 1 from referenced C code steps
csc = m2.X509.X509_Store_Context(cert_ctx) # Step 2 & 5
cert_ctx.add_cert(cacert) # Step 3
cert_ctx.add_cert(bobcert) # ditto
# Skip step 4 (no CRLs to add)
# Step 5 is combined with step 2...I think. (X509_STORE_CTX_init: Python creates and
# initialises an object in the same step)
# Skip step 6? (can't find anything corresponding to
# X509_STORE_CTX_set_purpose, not sure if we need to anyway???)
#
# It all falls apart at this point, as steps 7 and 8 don't have any corresponding
# functions in M2Crypto -- I even grepped the entire source code of M2Crypto, and
# neither of the following functions are present in it:
# Step 7: X509_STORE_CTX_set_cert - Tell the context which certificate to validate.
# Step 8: X509_verify_cert - Finally, validate it
Итак, я на полпути, но, похоже, я не могу получить подтверждение! Я что-то упускаю? Есть ли какая-то другая функция, которую я должен использовать из M2Crypto? Должен ли я искать совершенно другую оболочку python OpenSSL? Как я могу выполнить эту задачу в python!?!?
Обратите внимание, что я использую сертификаты для шифрования/дешифрования FILES, поэтому мне неинтересно использовать проверку однорангового сертификата на основе SSL-соединения (на который уже ответил), потому что у меня нет SSL-соединений.
Ответы
Ответ 1
Вы не можете сделать это с помощью простого M2Crypto, так как он не переносит некоторые из необходимых функций. Хорошая новость заключается в том, что если у вас установлен SWIG, вы можете обернуть их сами и использовать с кодом M2Crypto. Некоторое время назад я создал модуль с некоторыми дополнительными функциями и решил опубликовать его сейчас, поскольку он выполняет такую проверку. Вы можете проверить это здесь: https://github.com/abbot/m2ext. Это пример проверки сертификата с помощью этого модуля:
import sys
from m2ext import SSL
from M2Crypto import X509
print "Validating certificate %s using CApath %s" % (sys.argv[1], sys.argv[2])
cert = X509.load_cert(sys.argv[1])
ctx = SSL.Context()
ctx.load_verify_locations(capath=sys.argv[2])
if ctx.validate_certificate(cert):
print "valid"
else:
print "invalid"
К сожалению, разработка M2Crypto, похоже, застопорена (никаких закрытых проблем в отслеживании ошибок в течение последних двух лет), и сопровождающий игнорировал мои ошибки и сообщения электронной почты с этими и некоторыми другими исправлениями...
Ответ 2
Вы можете использовать, к сожалению, недокументированный метод X509.verify
, чтобы проверить, был ли сертификат подписан с закрытым ключом CA. Поскольку это вызывает OpenSSL x509_verify
в фоновом режиме, я уверен, что это также проверяет все параметры (например, истечение) правильно:
from M2Crypto X509
cert = X509.load_cert("certificate-filename")
caCertificate = X509.load_cert("trusted-ca-filename")
caPublic = caCertificate.get_pubkey()
if cert.verify(caPublic) == 1:
# Certificate is okay!
else:
# not okay
Ответ 3
Как вы сказали,
OpenSSL требует подключения
M2Crypto не имеет хорошей проверки
Как насчет этой гениальной идеи:
import os
os.system('openssl verify -CAfile ../ca-cert.pem bob.cert')
Его уродливый, но он работает!