Почему я получаю [SSL: CERTIFICATE_VERIFY_FAILED] в Python, когда настройка ssl выглядит нормально? - PullRequest
0 голосов
/ 06 мая 2019

Я работаю над приложением Python для связи со службой, работающей на локальном хосте через защищенный протокол websocket.Вот пример кода:

import json
import asyncio
import websockets
import ssl
import certifi


ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
ssl_context.load_default_certs()

query =  {
    "jsonrpc": "2.0",
    "method": "queryHeadsets",
    "params": {},
    "id": 1
    }
json = json.dumps(query)

async def query(json):

    async with websockets.connect("wss://emotivcortex.com:54321") as ws:
        await ws.send(json)
        response = await ws.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(query(json))

Проблема в том, что ssl handsake продолжает сбой со следующей ошибкой:

ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

Я использую Windows 10, Python 3.7.3 64-бит

$pip list
Package    Version
---------- --------
certifi    2019.3.9
pip        19.0.3
setuptools 40.8.0
websockets 7.0

Я проверил сертификат, представленный службой.Кажется действительным и подписанным COMODO.Я попробовал:

ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
print(ssl.get_default_verify_paths())
print(ssl_context.cert_store_stats())
ssl_context.load_default_certs()
print(ssl_context.get_ca_certs())

и обнаружил, что есть несколько сертификатов COMODO CA, доступных для python.Тем не менее, я все еще получаю сообщение об ошибке.

Вот полное сообщение об ошибке, если оно помогает:

SSL handshake failed on verifying the certificate
protocol: <asyncio.sslproto.SSLProtocol object at 0x0000020C11283048>
transport: <_SelectorSocketTransport fd=508 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 625, in _on_handshake_complete
    raise handshake_exc
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
SSL error in data received
protocol: <asyncio.sslproto.SSLProtocol object at 0x0000020C11283048>
transport: <_SelectorSocketTransport closing fd=508 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 526, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
Traceback (most recent call last):
  File "test.py", line 37, in <module>
    asyncio.get_event_loop().run_until_complete(query(json))
  File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 584, in run_until_complete
    return future.result()
  File "test.py", line 32, in query
    async with websockets.connect("wss://emotivcortex.com:54321") as ws:
  File "C:\Users\Matyas2\Python\lib\site-packages\websockets\py35\client.py", line 2, in __aenter__
    return await self
  File "C:\Users\Matyas2\Python\lib\site-packages\websockets\py35\client.py", line 12, in __await_impl__
    transport, protocol = await self._creating_connection
  File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 986, in create_connection
    ssl_handshake_timeout=ssl_handshake_timeout)
  File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 1014, in _create_connection_transport
    await waiter
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 526, in data_received
    ssldata, appdata = self._sslpipe.feed_ssldata(data)
  File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
    self._sslobj.do_handshake()
  File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)

Подключение SSL к серверам в Интернете работает нормально.Что мне не хватает?Что я делаю не так?

Я с удовольствием предоставлю дополнительную информацию, если это необходимо.

РЕДАКТИРОВАТЬ: Сертификат предназначен для emotivcortex.com и выдан COMODO RSA Проверка домена БезопасныйСервер CA, поэтому я предполагаю, что это не самозаверяющий сертификат.OpenSSL:

$python -c "import ssl; print(ssl.OPENSSL_VERSION)"
OpenSSL 1.1.0j  20 Nov 2018

1 Ответ

0 голосов
/ 07 мая 2019

Проблема вызвана отсутствием промежуточного сертификата ЦС.

Изучив сертификат, представленный службой в OpenSSL, я обнаружил, что сертификат был выдан «CA CA COMODO RSA Validation Secure Server».Сертификат CA этого конкретного органа фактически не присутствует в комплекте CA пакета python certifi (существуют разные сертификаты COMODO ...).

Решение

Вручную загрузите отсутствующий сертификат в формате PEM с веб-страницы CA и добавьте его в комплект CA, используемый в вашем коде.

Также в коде приложения есть ошибка: при вызове функции websockets.connect(), передайте аргумент ключевого слова ssl=ssl_context, чтобы указанный ранее CA-пакет действительно использовался.Правильный код выглядит следующим образом:

import json
import asyncio
import websockets
import ssl
import certifi


ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())


query =  {
    "jsonrpc": "2.0",
    "method": "queryHeadsets",
    "params": {},
    "id": 1
    }
json = json.dumps(query)

async def query(json):

    async with websockets.connect("wss://emotivcortex.com:54321", ssl=ssl_context) as ws:
        await ws.send(json)
        response = await ws.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(query(json))

Большое спасибо ларкам и Штеффену Ульриху за указание в правильном направлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...