Самозаверяющий сертификат с сокетом Python SSL - PullRequest
0 голосов
/ 19 апреля 2020

Я использую самоподписанный сертификат, сгенерированный с помощью следующей команды:

sudo make-ssl-cert generate-default-snakeoil 

И скопировал его в мой домашний каталог. Если я выполню следующее на стороне сервера:

from socket import socket, AF_INET, SOCK_STREAM
import ssl

def main():
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.verify_mode = ssl.CERT_REQUIRED
    context.load_cert_chain('/home/hfurmans/ssl-cert-snakeoil.pem', '/home/hfurmans/ssl-cert-snakeoil.key')

    host = "myipaddress"
    port = 5432
    my_socket = socket(AF_INET, SOCK_STREAM)
    my_socket.bind((host, port))
    my_socket.listen(1)
    my_socket = context.wrap_socket(my_socket, server_side=True)
    conn, addr = my_socket.accept()
    print("Connection from: " + str(addr))
    data = conn.recv(1024).decode()
    print(data)
    print("from connected user: " + str(data))
    data = str(data).upper()
    print("sending: " + str(data))
    conn.send(data.encode())
    conn.close()

if __name__ == "__main__":
    main()

Я заменил свой IP-адрес. Но они одинаковы на сервере и клиенте. Вот код клиента:

import socket
import ssl

hostname = "myipaddress"
context = ssl.create_default_context()

sock = socket.create_connection((hostname, 5432))
ssock = context.wrap_socket(sock, server_hostname=hostname)
print(ssock.version())
ssock.send("test")

Если я запускаю оба сценария, я получаю следующую ошибку. Это ошибка клиента:

bash-3.2$ python3 client.py 
Traceback (most recent call last):
  File "client.py", line 8, in <module>
    ssock = context.wrap_socket(sock, server_hostname=hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1108)

А вот ошибка сервера:

Traceback (most recent call last):
  File "server.py", line 27, in <module>
    main()
  File "server.py", line 16, in main
    conn, addr = my_socket.accept()
  File "/usr/lib/python3.6/ssl.py", line 1125, in accept
    server_side=True)
  File "/usr/lib/python3.6/ssl.py", line 407, in wrap_socket
    _context=self, _session=session)
  File "/usr/lib/python3.6/ssl.py", line 817, in __init__
    self.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 1077, in do_handshake
    self._sslobj.do_handshake()
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:852)

1 Ответ

1 голос
/ 19 апреля 2020

Самозаверяющий сертификат - это уловка, притворяющаяся, что ЦС является самим сертификатом. Поэтому мы должны заранее предоставить клиенту этот сертификат, чтобы доверять ему, когда он встретится.

На клиенте после создания контекста SSL я попытался сделать что-то похожее на

* 1004. *

, и это сработало.
(https://docs.python.org/3/library/ssl.html#ssl .SSLContext.load_verify_locations )

Мне пришлось удалить только context.verify_mode = ssl.CERT_REQUIRED на сервере, потому что я не предоставил свой клиент с собственным сертификатом, но это не та проблема, о которой сообщалось в вашем вопросе.


Конечно, чтобы все это работало, ваш сертификат должен иметь правильное общее имя.
Если клиент подключается к myipaddress (в качестве имени хоста), тогда общее имя сертификата также должно быть myipaddress.

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