TCP-сервер через SSL с использованием SocketServer.TCPServer - PullRequest
4 голосов
/ 14 мая 2011

Я хочу добавить ssl-поддержку на существующий TCP-сервер, основанный на классе SocketServer.TCPServer.Поэтому я переопределил конструктор по умолчанию класса TCPServer и добавил вызов ssl.wrap_socket (...):

class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
        # See SocketServer.TCPServer.__init__
        # (added ssl-support):
        SocketServer.BaseServer.__init__(self, server_address,
                                                        RequestHandlerClass)
        self.socket = ssl.wrap_socket(
                    socket.socket(self.address_family, self.socket_type),
                    server_side=True,
                    certfile='cert.pem'
                    )

        if bind_and_activate:
            self.server_bind()
            self.server_activate()

При запуске сервера ошибок не возникает.Поэтому я изменил свой простой тест-клиент для поддержки ssl:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock = ssl.wrap_socket(s)
sock.connect(('192.168.1.1', 54321))

Снова никаких ошибок не происходит, но вызов соединения блокируется.При закрытии клиента с помощью Ctrl + C он показывает следующее:

Traceback (most recent call last):
  File "exampleClient.py", line 10, in <module>
    sock.do_handshake()
  File "/usr/lib/python2.6/ssl.py", line 293, in do_handshake
    self._sslobj.do_handshake()
KeyboardInterrupt

Таким образом, do_handshake блокируется при подключении.Кто-нибудь знает, как решить проблему?Я просто хочу использовать зашифрованное TCP-соединение:)

Ответы [ 3 ]

8 голосов
/ 20 сентября 2013

Рукопожатие блокируется, потому что вы оборачиваете сокет после привязки ; сокет ожидает новых подключений, клиент еще не принял ваши подключения.

Оберните сокет при принятии соединения вместо:

class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def get_request(self):
        (socket, addr) = SocketServer.TCPServer.get_request(self)
        return (ssl.wrap_socket(socket, server_side=True, certfile="cert.pem"),
                addr)

Теперь рукопожатие успешно, потому что на другой стороне есть клиент, который может пожать руку с .

Нет дополнительной работы, необходимой для обработчика потока; библиотека python ssl предоставляет вам объекты с тем же интерфейсом, что и socket.socket().

Вы также можете рано завернуть сокет, но откладывайте рукопожатие до тех пор, пока не примете соединение:

class MyTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    def server_bind(self):
        SocketServer.TCPServer.server_bind(self)
        self.socket = ssl.wrap_socket(
            self.socket, server_side=True, certfile="cert.pem",
            do_handshake_on_connect=False)

    def get_request(self):
        (socket, addr) = SocketServer.TCPServer.get_request(self)
        socket.do_handshake()
        return (socket, addr)
3 голосов
/ 17 мая 2011

Хорошо, я нашел решение. Теперь я использую что-то похожее на это с использованием OpenSSL-пакета:

Внутри MyTCPServer-Constructor:

SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass)
ctx = SSL.Context(SSL.SSLv23_METHOD)
cert = 'cert.pem'
ctx.use_privatekey_file(cert)
ctx.use_certificate_file(cert)
self.socket = SSL.Connection(ctx, socket.socket(self.address_family,
                                                        self.socket_type))
if bind_and_activate:
    self.server_bind()
    self.server_activate()

А в методе настройки StreamRequestHandler:

self.connection = self.request
self.rfile = socket._fileobject(self.request, "rb", self.rbufsize)
self.wfile = socket._fileobject(self.request, "wb", self.wbufsize)

Это, кажется, работает нормально: -)

0 голосов
/ 14 мая 2011

Это потому, что вы должны установить аргумент do_handshake_on_connect в вашем вызове ssl.wrap_socket:

Параметр do_handshake_on_connect указывает, нужно ли делать SSL рукопожатие автоматически после выполнения socket.connect (), или прикладная программа будет называть это явно, вызывая Метод SSLSocket.do_handshake (). Вызов SSLSocket.do_handshake () явно дает управление программой над блокирующим поведением сокет ввода / вывода участвует в рукопожатии.

Источник: http://docs.python.org/library/ssl.html

...