Перейти к содержимому
Fingercomp

TLS сокеты

Рекомендуемые сообщения

Не так давно @LeshaInc выкладывал свою программку, фтп клиент-то, и кто-то сказал про ssh. Это, конечно, задача интересная, но речь не об этом. Уже тогда на протяжении дней трёх я изучал вот этот документец. И с тех пор, добавив более 4 тысяч, удалив более двух тысяч строк кода, перечитав этот RFC вдоль и поперёк, исписав 22 страницы моего настольно-напольного блокнота, погуглив 183 запроса про тлс (надо же, гугловская статистика иногда бывает полезна для себя), чуть не потратив 2500 рублей на 12 страниц, описывающих формат десятичных чисел ( :facepalm: ) и даже найдя один баг в Computronics, который мне не давал покоя часов двенадцать, а то и больше, в общем случае... Я наварил TLS сокеты в OpenComputers.

 

Что такое TLS? В нашей ирке спрашивавшим я отвечал так: это такая штука, из-за которой появляется замочек в адресной строке браузера. Фактически, это корректно, и им этого достаточно, но позволю немного поглубже объяснить.

В девяностых годах компания Netscape разработала концепцию и реализацию безопасной передачи данных через недоверенное соединение. Назвалось это чудо SSL, что означает Secure Sockets Layer — слой безопасных сокетов, и выпущено было две версии: 2.0 и 3.0. Версия 1.0 была настолько дырявой, что даже не была никогда выпущена в публичный доступ. Но и, как это неудивительно, ни 2.0, ни 3.0 сейчас мало того, что не считаются безопасными, их поддержку уже исключают из всяких популярных подуктов типа Firefox или Chrome.

Netscape, впрочем, недолго держала это изобретение. Ребята из Internet Engineering Task Force (IETF) в 1999 году выпустили свою, 3.1 версию SSL, которая хоть и имела некоторую совместимость с прошлой версией, но имела много нового и исправляла некоторые проблемы безопасности в прошлом протоколе. Версия SSL от IETF с тех пор называется TLS.

Все версии, для справки:

  • ?: SSL 1.0
  • 1992: SSL 2.0
  • 1995: SSL 3.0
  • 1999: SSL 3.1 // TLS 1.0
  • 2006: SSL 3.2 // TLS 1.1
  • 2008: SSL 3.3 // TLS 1.2

И хоть сейчас SSL и TLS используются взаимозаменяемо, правильнее, всё же, говорить TLS.

 

И всё же, что это за штука такая?

TLS и его предшественник, SSL, — это протокол-прослойка между слоем данных приложений и слоем TCP. Как-то так:

  • Слой данных приложений [Application Data].
  • Слой безопасности [Transport Layer Security, TLS].
  • Слой протокола контроля передачи данных [TCP].

Таким образом, переход на TLS не требует огромных изменений в код, достаточно заменить обычную имплементацию сокетов на защищённую и сгенерировать ключи.

Данные с верхнего слоя шифруются и передаются по низшему слою к адресату, где данные снова расшифровываются, сверяются и обрабатываются.

 

Как работает TLS.

Перед тем, как передавать данные, неплохо было бы договориться с другим концом соединения, какой набор шифрования использовать, передать некоторые дополнительные данные, подтвердить подлинность сервера (для защиты от встраивания в соединение) и, конечно, обменяться ключами, которыми будет шифроваться информация. Для этого предназначена процедура рукопожатия — Handshake. Клиентом генерируется рандомная информация, шифруется асимметричным шифратором (ECDH-RSA или RSA) и передаётся серверу. Перед этим сервер предоставляет цепочку сертификатов, каждый последующий сертификат которого подтверждает предыдущий. В конце цепочки получается самоподписанный сертификат, которому надо доверять (есть целые списки таких корневых сертификатов). После того, как рандомные байты переданы, сервер и клиент из них генерируют ключи: два ключа проверки валидности информации (на сервер и клиент отдельно для защиты от атаки), два ключа симметричного шифрования данных и, если того требует шифратор, два инициализирующих вектора.

В конце рукопожатия отправляют финальное сообщение, которое уже шифруется. Оно содержит хэш всех сообщений рукопожатия, чтобы предотвратить перехват трафика.

 

Каждое шифрованное сообщение имеет специальный код авторизации (MAC), который включает хэш пересылаемых данных и номер последовательности, который имеется отдельно для приёма и отдачи, начинается с 0 и увеличивается на 1 с каждым отосланным сообщением. Таким образом, если сообщение было перехвачено и позже отослано, или трафик был перепутан, то и сервер, и клиент после проверки кода авторизации закрывают соединение.

 

 

Как видно, протокол этот отнюдь не простой, а потому я ещё больше ценю свою программку. Она не полностью соответствует стандартам, в ней нет проверки сертификата, да и сиферы пока только с RSA, но уже позволяет создать соединение с GitHub, Google, да и другими HTTPS-сайтами.

 

d7K3vqv.png

 

Оно работает для меня как-то нестойко, шатко, долго, в общем, неустойчиво. Но ведь работает! На скрине выше успешно была получена информация длиной в 27763 байта.

 


 

Библиотека предоставляет таблицу с одной функцией: tlsSocket(host: string[, port: number]). Возвращает она обёрнутый сокет: таблицу с функциями:

  • socket.write(data: string) — посылает данные на сервер.
  • socket.read(): string or nil, string — читает данные с сокета.
  • socket.close() — закрывает сокет (делает это правильным способом, оповещая сервер).
  • socket.id(): string — возвращает ID сокета.
  • socket.isClosed(): boolean — говорит, закрыт ли сокет.
  • socket.setTimeout(to: number) — устанавливает предельное время ожидания данных с сокета, в общем, таймаут соединения.

Все функции вызываются с ., не с :!

 

Зависимости:

  • Компоненты
    • Карта данных второго уровня. Она предоставляет получение рандомных данных и HMAC.
    • Улучшенный шифратор (Advanced Cipher Block) из Computronics. RSA шифрование.
    • Интернет-карта, чтобы, очевидно, посылать запросы.
  • Библиотеки
    • libder-decoder — моя собственная библиотека, которая парсит сертификаты.
    • libbigint — либа БОЛЬШИХ чисел (сначала была библиотека от @Zer0Galaxy, но работала она жутчайше медленно: более минуты против пары секунд).
    • lua-lockbox — либа с криптофункциями. К сожалению, не все они работают на Lua 5.3, но есть рабочий AES-128 шифратор.
  • Lua 5.3. На прошлой версии работать не будет!
  • OpenOS 1.6.
  • OpenComputers 1.6.

Установка из OPPM: oppm install libtls. Исходный код.

 

P. S. Прошло достаточно много времени, и теперь уже на дворе (с 2018) выкачен TLS 1.3, который как-то слишком разительно отличается от TLS 1.2, который я изучал и имплементировал. Но 1.2 должен пока (минимум ещё годов 4-5) работать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Прекрасное начало! Какие планы по добавлению функционала? Приложений на основе этой библы?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Ну, надо прикрутить обёртку уже имеющегося сокета, добавить передачу ключа через ECDH-RSA (в карте данных вроде-то что-то было с эллиптическими кривыми и диффихеллманом, не уверен), и, может быть, если очень захочется мне вдруг, проверку валидности сертификатов. Кроме того, хочется как-нибудь ускорить библиотеку — к гитхабу подключался я 10 секунд, а считывал 27 килобайт минуту. Пока что не смотрел, что там так долго пыхтит.

Какие делать программки, я пока не знаю. Может быть, сделать библиотеку HTTPS, но пока что не особо хочется с ней возиться.

 

Тыкаю @LeshaInc, чтобы в свой фтп-клиент прикрутил сфтп.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

 

 

Тыкаю LeshaInc, чтобы в свой фтп-клиент прикрутил сфтп.

было бы неплохо лучше для начала туда прикрутить удобное отображение списка файлов вместо эпического прогресбарчика и считалки аптайма времени загрузки однокилобайтного файлика. Ведь там же были мысли о удобном закачивании "большого" количества файлов . Но его пока там же, по идее, нет, судя по скринам. Если в папке больше чем 25(или сколько там) файликов, то все же улетит при листинге на мониторе 2 тира. И как узнать, что там? Нужно или как-то постранично дать возможность выводить или скролл. Или как-то еще.

И есть ли там возможность скачать сразу папку со всем содержимым рекурсивно? Там сам клиентский функционал еще есть куда пилить и пилить.

TLS там может и обождать :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Крутая библиотека, и титанический труд!

Поздравляю с успешным завершением.

 

P.S. Через точку, а не через двоеточие - то есть, одновременно может быть открыт только один такой сокет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Крутая библиотека, и титанический труд!

Поздравляю с успешным завершением.

 

P.S. Через точку, а не через двоеточие - то есть, одновременно может быть открыт только один такой сокет?

Нет. Просто сам сокет хранится в локальной переменной функции, которая возвращает обёртку. Таблица функций создаётся в функции, и получается, что имеет доступ к сокету в переменной.

Дело в том, что в OC обычные сокеты тоже работают через точку, и чтобы не ломать ничего, я сделал так же.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Обёртка сокетов. Piece of cake, а не задача. Уже доступно. Вот затравочная картинка с ГУГОЛЕМ:

 

Z2deGcM.png

D:

 

 

 

, мало того, что сам себя спалил, так ведь сами ж сказали, что замочкопредставления вам достаточно. ¯\(ツ)/¯

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Увеличил скорость чтения в 1⅓, а соединения — в 2.5 раза. Подключил возможность задавать собственные расширения, ибо без этого, например, не работает HTTPS. В общем, пользоваться либой уже можно. :yahoo:

Изменено пользователем Fingercomp

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Неожиданно для себя! Напилил HTTP/HTTPS 1.1 (во второй версии разбираться лень) либу. Работает она абсолютно идентично функции component.request(), вот только поддерживает HTTPS и принимает четвёртый параметр: метод запроса (GET по умолчанию, если не посылается тело запроса, и POST в противном случае). Кроме того, она превращает все хедеры в формат Train-Case, так что можно спокойно получать данные хедеров в своих программах. Однако всё это делается за счёт меньшей производительности, так что лучше использовать стандартные функции, если ничего из вышеперечисленного не требуется.

Библиотека возвращает функцию отправки запроса:

  • http(url: string[, body: string[, headers: table[, method: string]]]): table — посылает запрос на сервер.
  • http(url: string, kwargs: table): table — делает то же самое, но принимает таблицу с аргументами, чтобы не путаться.

В таблице аргументов все параметры опциональны. Вот пример полной таблички:

{
  body = "Hello here\n",
  headers = {
    connection = "close"
  },
  method = "PUT"
}

Возвращают обе функцию таблицу с теми же функциями, что у компонента (и да, тут не надо ставить двоеточие, как и в OC'шном реквесте):

  • response.read([n: number]): string or nil — прочесть некоторое количество данных. Вообще, вся информация читается сразу же, но можно ограничить вывод аргументом. Можно отдать math.huge (или вообще не указывать аргумент), и тогда возвратится все данные полученные.
  • response.close() — закрыть соединение.
  • response.finishConnect(): boolean — возвращает, открыто ли соединение (в стандартном OC немного по-другому работает, там не буля, а nil с причиной, ну и ладно).
  • response.response(): number, string, table — возвращает код статуса (204 или 404, например), текстовое описание статуса ("No Content", "Not Found") и хедеры таблицей таблиц (ибо хедеров одинаковых может быть несколько).

Вот так может выглядеть выхлоп response.response():

200     "OK"    {["Content-Length"]={"12"},
 ["Content-Type"]={"application/octet-stream"},
 Date={"Fri, 05 Aug 2016 15:35:34 GMT"},
 ["Last-Modified"]={"Fri, 05 Aug 2016 14:56:08 GMT"}
 Server={"SimpleHTTP/0.6 Python/2.7.12"}}

Установка из OPPM: oppm install libhttp. Ну и исходный код.

Изменено пользователем Fingercomp

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в тему...

×   Вы вставили отформатированное содержимое.   Удалить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.


×
×
  • Создать...