Что означает "SSLError: [SSL] PEM lib (_ssl.c: 2532)" означает использование библиотеки ssl Python?

Я пытаюсь использовать подключение к другой стороне с использованием асинхронного модуля Python 3 и получить эту ошибку:

     36     sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
---> 37     sslcontext.load_cert_chain(cert, keyfile=ca_cert)
     38

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

Вопрос в том, что означает ошибка. Мой сертификат верен, файл ключей (CA-сертификат) может не совпадать.

Ответ 1

Предполагая, что используется версия 3.4:

Смотрите: https://github.com/python/cpython/blob/3.4/Modules/_ssl.c#L2529-L2535

 PySSL_BEGIN_ALLOW_THREADS_S(pw_info.thread_state);
 r = SSL_CTX_check_private_key(self->ctx);
 PySSL_END_ALLOW_THREADS_S(pw_info.thread_state);
 if (r != 1) { 
    _setSSLError(NULL, 0, __FILE__, __LINE__);
    goto error;
 }

Говорят, что SSL_CTX_check_private_key не удалось; таким образом, закрытый ключ неверен.

Ответ 2

В вашем коде вы вызываете:

sslcontext.load_cert_chain(cert, keyfile=ca_cert)

Из документации:

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

Основываясь на имени аргументов в вашем примере, похоже, что вы передаете сертификат CA в аргумент keyfile. Это неверно, вам нужно передать закрытый ключ, который использовался для создания локального сертификата (иначе клиент не может использовать ваш сертификат). Файл закрытого ключа будет выглядеть примерно так:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,9BA4973008F0A0B36FBE1426C198DD1B

...data...
-----END RSA PRIVATE KEY-----

Вам нужен только сертификат ЦС, если вы пытаетесь проверить достоверность сертификатов SSL, подписанных этим сертификатом. В этом случае вы, вероятно, используете SSLContext.load_verify_locations() для загрузки сертификата ЦС (хотя я недавно не работал с модулем SSL, поэтому не задумывайтесь об этом).