Стандартная библиотека Python ssl load_cert_chain - не удается загрузить цепочку сертификатов PEM - PullRequest
1 голос
/ 13 апреля 2019

Запуск Python3.6.

У меня есть комплект сертификатов в формате pem , то есть сертификат сервера и его CA-сертификат. контекст ssl load_cert_chain ('aws-bundle.pem') выдает ошибку SSL. Другие библиотеки, такие как urllib, испытывают проблемы при проверке сертификата из транзакции HTTPS.

Вот как выглядит этот пакетный файл (без пропущенных строк):

-----BEGIN CERTIFICATE----- 
MIIESTCCAzGgAwIBAgITBn+UV4WH6Kx33rJTMlu8mYtWDTANBgkqhkiG9w0BAQsF
. . .
yLyKQXhw2W2Xs0qLeC1etA+jTGDK4UfLeC0SF7FSi8o5LL21L8IzApar2pR/
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- 
MIIEkjCCA3qgAwIBAgITBn+USionzfP6wq4rAfkI7rnExjANBgkqhkiG9w0BAQsF
. . . 
akcjMS9cmvqtmg5iUaQqqcT5NJ0hGA==
-----END CERTIFICATE-----

Вот выдержки из моего транскрипта ipython:

In [33]: import ssl

In [34]: context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

In [35]: context.load_cert_chain('aws-bundle.pem')
---------------------------------------------------------------------------
SSLError                                  Traceback (most recent call last)
<ipython-input-38-c955611be04f> in <module>
----> 1 context.load_cert_chain('aws-bundle.pem')

SSLError: [SSL] PEM lib (_ssl.c:3520)

Кстати, инструмент командной строки openssl может отлично работать с этим пакетом - выводить метаданные в виде текста.

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

1 Ответ

2 голосов
/ 13 апреля 2019

Возможно, вам нужно использовать load_verify_locations вместо load_cert_chain.

Посмотрите документацию:

 SSLContext.load_cert_chain(certfile, keyfile=None, password=None)

Загрузить закрытый ключ и соответствующий сертификат. Строка certfile должна быть путем к одному файлу в формате PEM содержащий сертификат, а также любое количество сертификатов CA необходимо установить подлинность сертификата. Ключевой файл строка, если имеется, должна указывать на файл, содержащий закрытый ключ in. В противном случае закрытый ключ также будет взят из certfile. Увидеть обсуждение сертификатов для получения дополнительной информации о том, как сертификат хранится в сертификате.

Внимательно обратите внимание на: Загрузите закрытый ключ и соответствующий сертификат.

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

Кстати, вы можете смешивать load_cert_chain с load_verify_locations. load_cert_chain предназначен для загрузки ВАШЕГО сертификата (с прикрепленными к нему дополнительными сертификатами СА) и связанного с ним закрытого ключа, НЕ для загрузки СА / промежуточных сертификатов, это делается с помощью load_verify_locations.

Ваш "комплект" не является вашим сертификатом или не содержит личного ключа. Судя по названию, на самом деле это сертификаты CA / промежуточные, а не ваш сертификат, поэтому я думаю, что вы смешали два разных метода.

Предыдущий диагноз внутри _ssl.c, чтобы понять ошибку

Глядя на источники Python 3.6.8, строка 3520 _ssl.c (https://github.com/python/cpython/blob/3c6b436a57893dd1fae4e072768f41a199076252/Modules/_ssl.c) полностью соответствует ошибке:

 _setSSLError(NULL, 0, __FILE__, __LINE__);

(почему это так загадочно, без каких-либо подробностей, просто уклоняется от меня).

Если вы перепроверете, вы, скорее всего, находитесь в подходящем месте в отношении вашего вызова, поскольку функция, в которой это появляется, - _ssl__SSLContext_load_cert_chain_impl.

Теперь, если вы изучите приведенный выше код, ведущий к этой строке, вы придете к:

r = SSL_CTX_use_PrivateKey_file(self->ctx,
    PyBytes_AS_STRING(keyfile ? keyfile_bytes : certfile_bytes), SSL_FILETYPE_PEM);

И здесь что-то не получилось. Так что просто по названию (SSL_CTX_use_PrivateKey_file) я полагаю, что проблема связана с вашим личным ключом, прикрепленным к сертификату, поэтому вы можете перестать смотреть на содержимое пакета сертификатов!

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

  • путь к нему ок
  • разрешения для файла ok
  • это нормально содержание

Почему это там делается? Вероятно, потому что код позже делает:

 r = SSL_CTX_check_private_key(self->ctx);

следовательно, он гарантирует, что закрытый ключ соответствует вашему сертификату.

И если у вас действительно возникла проблема с файлом комплекта, это делается выше:

r = SSL_CTX_use_certificate_chain_file(self->ctx, PyBytes_AS_STRING(certfile_bytes));

Если это не удастся, это вызовет ошибку в строке 3499, и, следовательно, вы, вероятно, вместо этого будете иметь вместо этого в трассировке стека:

SSLError: [SSL] PEM lib (_ssl.c:3499)

Опять же, это полностью ускользает от меня, почему разработчики этих библиотек и оболочек поверх библиотек просто решают создавать столь загадочные сообщения об ошибках, кроме как для того, чтобы принести страдания всем пользователям. В основном без изучения исходного кода невозможно понять, что происходит ... И даже в этом случае в исходном коде нет абсолютно никаких комментариев, но в любом случае он мог быть сгенерирован автоматически.

...