From 72bfaea76d9a71d3349caad06782148c81cbbbeb Mon Sep 17 00:00:00 2001 From: shr3dd3r Date: Sat, 1 Jul 2023 05:31:44 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BD=D0=BE=D0=B6=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B5=D0=BD=D0=BD=D1=8B=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8=20+3=20=D1=81=D0=BE?= =?UTF-8?q?=D0=B1=D1=8B=D1=82=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Error/HandshakeFailed.md | 39 ++++++++++++++++++ Error/README.md | 16 ++++++++ Handshake/Accepted.md | 30 ++++++++++++++ Handshake/Request.md | 45 ++++++++++++++++++++ OVERVIEW.md | 88 +++++++++++++++++++++++++++++----------- method_format_example.md | 31 ++++++++++---- 6 files changed, 219 insertions(+), 30 deletions(-) create mode 100644 Error/HandshakeFailed.md create mode 100644 Error/README.md create mode 100644 Handshake/Accepted.md create mode 100644 Handshake/Request.md diff --git a/Error/HandshakeFailed.md b/Error/HandshakeFailed.md new file mode 100644 index 0000000..c567308 --- /dev/null +++ b/Error/HandshakeFailed.md @@ -0,0 +1,39 @@ +# Error.HandshakeFailed + +**Значение: 0x0501** + +## Client2Server + +_Не применимо._ + + + +## Server2Client + +Отрицательный ответ на инициирование рукопожатия. Сообщает о произошедшей проблеме. + +**Ячейки:** + +- Код ошибки + - _Ключ:_ 0x01 + - _Тип:_ `uint8_t` + - Код, описывающий ошибку конкретнее. + - 0x01: магическое число неверно. + - 0x02: неподдерживаемая версия протокола. + - 0x03: невозможно выделить новый порт для подключения. + - 0x04: указанный транспортный протокол не поддерживается. + - 0x05: указанный размер пакета недопустим. +- Подробные данные + - _Ключ:_ 0x02 + - _Тип:_ `char[]` + - Бинарное описание ошибки или сопровождающая информация. +- Текстовое описание + - _Ключ:_ 0x03 + - _Тип:_ `char[]` + - Текстовое описание ошибки. + + + +## Server2Server + +_Также как и Server2Client._ \ No newline at end of file diff --git a/Error/README.md b/Error/README.md new file mode 100644 index 0000000..d4f1783 --- /dev/null +++ b/Error/README.md @@ -0,0 +1,16 @@ +Все ошибки без исключения должны иметь следующий формат: + +- Код ошибки + - _Ключ:_ 0x01 + - _Тип:_ `uint8_t` + - Код, описывающий ошибку конкретнее. +- Подробные данные + - _Ключ:_ 0x02 + - _Тип:_ `char[]` + - Бинарное описание ошибки. +- Текстовое описание + - _Ключ:_ 0x03 + - _Тип:_ `char[]` + - Текстовое описание ошибки. + +Различия допустимы только в интепретации кода ошибки. \ No newline at end of file diff --git a/Handshake/Accepted.md b/Handshake/Accepted.md new file mode 100644 index 0000000..2b8d65f --- /dev/null +++ b/Handshake/Accepted.md @@ -0,0 +1,30 @@ +# Handshake.Accepted + +**Значение: 0x1002** + +## Client2Server + +_Не применимо._ + + + +## Server2Client + +Положительный ответ на инициирование рукопожатия. Передаёт все ключевые данные для осуществления дальнейшей коммуникации. + +**Фиксированная схема:** + +- Магическое число + - _Размер:_ 8 байт + - _Тип:_ `uint64_t` + - Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. Являет из себя строку "MarafonP" в кодировке ASCII. +- Порт для переподключения + - _Размер:_ 2 байта + - _Тип:_ `uint16_t` + - Предоставляет номер порта для переподключения. Установлен в 0, если не требуется. + + + +## Server2Server + +_Также как и Server2Client._ \ No newline at end of file diff --git a/Handshake/Request.md b/Handshake/Request.md new file mode 100644 index 0000000..dc2bd05 --- /dev/null +++ b/Handshake/Request.md @@ -0,0 +1,45 @@ +# Handshake.Request + +**Значение: 0x1001** + +## Client2Server + +Инициирующее рукопожатие событие. Передаёт все ключевые данные для осуществления дальнейшей коммуникации. + +**Фиксированная схема:** + +- Магическое число + - _Размер:_ 8 байт + - _Тип:_ `uint64_t` + - Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. Являет из себя строку "MarafonP" в кодировке ASCII. +- Версия протокола + - _Размер:_ 4 байта + - _Тип:_ `uint8_t[4]` + - Максимальная поддерживаемая запрашивающим версия протокола. +- Флаги переподключения + - _Размер:_ 2 байта + - _Тип:_ `uint16_t` + - Описывает параметры нового подключения: + - 0b0000000000000000: оставить текущее подключение + - 0b0000000000000001: переподключиться к тому-же порту + - 0b0000000000000010: запросить новый порт для подключения + - 0b0000000000000100: использовать TCP + - 0b0000000000001000: использовать TLS + - 0b0000111111110000: резерв под расширение + - 0b1111000000000000: резерв под под нужды сторонних реализаций +- Размер пакета + - _Размер:_ 4 байта + - _Тип:_ `uint32_t` + - Устанавливает используемый при коммуникации размер пакета. + + + +## Server2Client + +_Не применимо._ + + + +## Server2Server + +_Также как и Client2Server._ \ No newline at end of file diff --git a/OVERVIEW.md b/OVERVIEW.md index b27dbce..24cf2c8 100644 --- a/OVERVIEW.md +++ b/OVERVIEW.md @@ -1,6 +1,6 @@ # Спецификация Marafon Protocol (MFP) v1.0 -Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP. Основной фокус при работе над оным идёт на: +Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP (в будущем будет добавлена поддержка UDP и QUIC). Основной фокус при работе над оным идёт на: - Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.). - Устойчивость к цензуре. @@ -13,29 +13,52 @@ Marafon Protocol это протокол для одноимённого пол -## Пакеты +## Поведение сервера и клиента -Существует три уровня категорий пакетов: +Сервер **обязан**: + +1. Оповещать клиент и сервера в федерации о всех ошибках, кроме: + - Связанных с безопасностью + - Связанных с внутренними неполадками +2. Отдавать предпочтение данным других серверов, нежели клиентов. +3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты). + +Клиент **обязан**: + +1. Хранить тишину о всех ошибках. +2. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию. + + + +## События, пакеты и их структура + +Существует три уровня категорий событий: 1. **Надкатегория:** Client2Server, Server2Client, Server2Server. 2. **Категория:** Authentication, User, Message, т.д. 3. **Подкатегория:** Login, Create, Delete, т.д. -Надкатегория никак не указывается в пакете и зависит от контекста. Он-же определяет структуру некоторых пакетов, которая может менятся в конкретных случаях. Остальные две занимают по одному байту соответственно. +Надкатегория никак не указывается в пакете, зависит от контекста и при упоминании - чаще всего опускается. Она также определяет структуру некоторых событий, которая может меняться в конкретных случаях. Остальные две занимают по одному байту соответственно. -Пакеты всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака. +Все категории вместе являются типом события. Значение типа - это число, которое указывается в начале пакета. -Пакеты всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента. +События всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака (`uint64_t`). -Данные (AKA "полезная нагрузка") являются расположенными последовательно парами "ключ-значение" и могут быть расположены относительно друг-друга в произвольном порядке. Они следующий формат: +События всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента. -`[2b: key][2b: data length][>0 b: data]` +Данные (AKA "полезная нагрузка") являются расположенными последовательно парами "ключ-значение" и могут быть расположены в пакете относительно друг-друга в произвольном порядке. Одна пара имеет следующий формат: + +`[1b: key][2b: data length][>0 b: data]` + +Все пакеты размером ниже установленного дополняются псевдослучайной последовательностью байт. (???) + + Исходя из всего вышеописанного, итоговая примерная структура пакета выглядит следующим образом: -`[1b: category][1b: subcategory][4b: server session][>0 b: payload]` +`[1b: category][1b: subcategory][4b: server session][?b: payload hash][>0b: payload][~b: random bytes]` -Размер пакета определяется ответом сервера на этапе обмена характеристиками, но не может быть больше, чем 65535 байт. До этого этапа размер пакета составляет 512 байт. +Размер пакета определяется запросом клиента на этапе обмена характеристиками, но не может быть больше, чем 65535 байт или меньше 128 байт. До этого этапа (включительно) размер пакета составляет 512 байт. Магическим числом протокола является следующая последовательность байт: @@ -48,29 +71,48 @@ DEC: 77 97 114 97 102 111 110 80 -## Сессии, аутентификация и соединение +## Соединение, аутентификация и сессии -После успешной установки защищённого TLS соединения начинается этап обмена характеристиками. Клиент отправляет некоторые метаданные, в числе которых: +Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. Данная версия протокола подразумевает поддержку пока лишь двух способов подключения: напрямую (без шифрования) и с использованием TLS-over-TCP. -- Магическое число: 8 байт -- Версия протокола: 4 байта -- ID серверной сессии: 4 байта (0 если нет; на случай, если соединение надо восстановить, а не создать с нуля) +### Рукопожатие -На что сервер отвечает своим набором метаданных: - -- Магическое число: 8 байт -- Интервал обновления: 2 байта (x * 0.01 = интервал в секундах) +После успешной установки защищённого соединения, происходит обмен характеристиками, AKA "рукопожатие". Клиент отправляет событие типа `Handshake.Request`, на что сервер отвечает либо ошибкой, либо событием типа `Handshake.Accepted`. -Если при обмене метаданными клиент или сервер обнаруживают несоответствие магических чисел, то они разрывают соединение. Если сервер не поддерживает указанную клиентом версию протокола - он отвечает ошибкой и разрывает соединение. Если при попытке восстановить соединение клиентом, ID серверной сессии не существует в списке недавно-разорванных, то он отвечает ошибкой и разрывает соединение. +Сервер отвечает ошибкой `Error.HandshakeFailed` и разрывает соединение, если: + +- При обмене данными клиент или сервер обнаруживают несоответствие магических чисел. +- Сервер не поддерживает указанную клиентом версию протокола. +- Невозможно выделить новый порт для подключения. +- Указанный транспортный протокол не поддерживается. +- Размер пакета не попадает в рамки жёсткого лимита сервера. + +Если при хэндшейке клиентом был указан новый способ подключения и получен валидный ответ от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое. + +### Регистрация При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его. +### Вход в учётную запись + +Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться. + +Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте. + +Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение. + При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера. -Если при проверке хэша полезной нагрузки пакета обнаруживается, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инцеденте. +### Пользовательские сессии и подпись -Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается. +Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте. -Каждые n секунд клиент отправляет запрос на обновление статуса аккаунта. Если спустя указанное на этапе обмена характеристиками время нет ни одного пакета от клиента - сервер разрывает соединение. \ No newline at end of file +Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, может быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он должен оповестить пользователя. + + + +Полезная нагрузка пакета может быть проверена на целостность сервером или клиентом с использованием подписанного хеша, но данная проверка может быть отключена, по усмотрению владельца сервера или пользователя клиента. + +Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается. \ No newline at end of file diff --git a/method_format_example.md b/method_format_example.md index f752b8c..01b739e 100644 --- a/method_format_example.md +++ b/method_format_example.md @@ -1,22 +1,39 @@ -# Category.Subcategory +# Категория.Субкатегория + +**Значение: 0xBA98** ## Client2Server -Some description. +Какое-то описание метода. -**Fields:** +**Ячейки:** -- Field_1: 0xabcd; description of data. -- Field_2: 0x1234; description of data too. +- Ячейка_1 + - _Ключ:_ 0xAB + - _Тип:_ `char[]` + - Описание данных. +- Ячейка_2 + - _Ключ:_ 0x12 + - _Тип:_ `uint64_t` + - Тоже описание данных. ## Server2Client -_Same as for Client2Server._ +**Фиксированная схема:** + +- Какая-то ячейка + - _Размер:_ 8 байт + - _Тип:_ `uint64_t` + - Описание, ага. +- Тоже ячейка + - _Размер:_ 2 байта + - _Тип:_ `wchar_t` + - Точно описание. ## Server2Server -_Same as for Client2Server._ \ No newline at end of file +_Также как и Client2Server._ \ No newline at end of file