Python3 Программирование сокетов с ошибками SSL? - PullRequest
1 голос
/ 29 апреля 2020

Я только изучаю основы Python программирования сокетов и безопасной сети. Я подключил две виртуальные машины в своей сети и хочу увидеть разницу между зашифрованными и незашифрованными сообщениями в Wireshark. Итак, я следовал этим урокам https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309 и https://docs.python.org/2/library/ssl.html#server-Side-Operation и https://docs.python.org/3.8/library/ssl.html#server-Side-Operation , чтобы настроить некоторые сертификаты openSSL для моей серверной виртуальной машины, и я скопировал сертификат rootCA на свою клиентскую виртуальную машину.

Вот команды, которым я следовал, чтобы создать свои самозаверяющие сертификаты:

openssl genrsa -des3 -out rootCA.key 4096
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256

Когда он запросил общий Имя, я дал ему IP моего сервера, который является 172.25.1.5.

Однако, когда я пытаюсь запустить сервер и клиентские python сценарии, я получаю эти ошибки:

$ python3 server.py 
what is host? 172.25.1.5
server bound.
server listening
Accepted conn from: ('172.25.1.4', 59592)
Traceback (most recent call last):
  File "server.py", line 32, in <module>
    connstream = context.wrap_socket(conn,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)

На стороне клиента я вижу:

$ python3 client.py 
Traceback (most recent call last):
  File "client.py", line 19, in <module>
    s.connect((host,port))
  File "/usr/lib/python3.6/ssl.py", line 1109, in connect
    self._real_connect(addr, False)
  File "/usr/lib/python3.6/ssl.py", line 1100, in _real_connect
    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: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

Вот мой код для сервера и клиента:

import os, socket, ssl

# host and port
host = "172.25.1.5" # my VM ip
port = 1234
print("what is host? " + host)

# create context for socket (with ssl security)
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile="server.crt",keyfile="server.key")

# create socket and bind the socket to a tuple of host,port
s = socket.socket()
s.bind((host,port))
print("server bound.")

# listen for connections. The normal max is 5. The slides have 1.
print("server listening")
s.listen(1)

# accept connection
conn,address = s.accept()
print("Accepted conn from: " + str(address))

# give connection context
connstream = context.wrap_socket(conn,server_side=True)
#connstream = conn
print("wrapped socket.")

# receive data loop
# breaks if no data received
while True:
    data = connstream.recv(1024).decode()
    if not data:
        break
    print("received from client: " + str(data))
    # echo back
    connstream.send(data.encode())
connstream.shutdown(socket.SHUT_RDWR)
connstream.close()
conn.close()

А вот мой клиентский скрипт на другой виртуальной машине:

import os, socket, ssl

# get context
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
context.load_verify_locations("rootCA.crt")
# define host and port
host = "172.25.1.5" #ip of linked clone
port = 1234

# make socket and connect to tuple host,port. Wrap socket in context
s = context.wrap_socket(socket.socket(socket.AF_INET),server_hostname=host)
s.connect((host,port))

cert = s.getpeercert()
print("What is cert? " +str(cert))
print("\n\n")
# get input
msg = input("out: ")

# Receive msg loop and send loop
while msg.lower().strip() != '':
    s.send(msg.encode())
    data = s.recv(1024).decode()

    print("In: " + data)

    msg = input("Out: ")

s.close()

Я застрял. Я убедился, что мой код следует примерам. Как мне обойти эти ошибки? Я что-то упускаю?

Любая помощь или объяснение приветствуется. Я все еще только учусь.

1 Ответ

0 голосов
/ 29 апреля 2020

Следуя совету Патрика Мевзека в комментариях, я попытался изменить строку

context.load_cert_chain(certfile="server.crt",keyfile="server.key")

на

context.load_cert_chain(certfile="rootCA.crt",keyfile="rootCA.key")

Это сработало, и это сказало мне, что что-то пошло не так, когда я создал server.crt и server.key. Итак, я просто удалил server.key, server.csr и server.crt в виртуальной машине сервера и воссоздал их, используя

openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out server.crt -days 500 -sha256

После их воссоздания я мог бы использовать server.crt и server.key в качестве certfile и keyfile.

Использование моей фиктивной установки CA с server.crt или просто прямое использование rootCA для SSL работает для шифрования моих сообщений, и использование Wireshark также подтвердило это.

Я ценю помощь всех , и я надеюсь, что этот ответ поможет другим, кто сталкивается с этой проблемой, играя с программированием сокетов и SSL.

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