From b38e0bc616f3389e9f2bca42c54d244ba494c23c Mon Sep 17 00:00:00 2001 From: shr3dd3r Date: Tue, 4 Jul 2023 06:30:55 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D1=83=20=D1=87=D0=BE,=20=D1=82=D0=B5?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D1=8C=20=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D0=BC?= =?UTF-8?q?=20=D0=B1=D0=BE=D0=BB=D0=B5=D0=B5=20=D0=B6=D0=B8=D1=80=D0=BD?= =?UTF-8?q?=D1=83=D1=8E=20=D1=82=D0=B5=D0=BC=D1=83.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Error/HandshakeFailed.md | 39 ------- HANDSHAKE.md | 88 ++++++++++++++ Handshake/Accepted.md | 30 ----- Handshake/Request.md | 45 -------- OVERVIEW.md | 114 +++++++++++-------- method_format_example.md | 39 ------- moveToAnotherRepo/1.md | 15 +++ {Error => moveToAnotherRepo/Error}/README.md | 0 moveToAnotherRepo/METHOD FORMAT EXAMPLE.md | 41 +++++++ 9 files changed, 208 insertions(+), 203 deletions(-) delete mode 100644 Error/HandshakeFailed.md create mode 100644 HANDSHAKE.md delete mode 100644 Handshake/Accepted.md delete mode 100644 Handshake/Request.md delete mode 100644 method_format_example.md create mode 100644 moveToAnotherRepo/1.md rename {Error => moveToAnotherRepo/Error}/README.md (100%) create mode 100644 moveToAnotherRepo/METHOD FORMAT EXAMPLE.md diff --git a/Error/HandshakeFailed.md b/Error/HandshakeFailed.md deleted file mode 100644 index c567308..0000000 --- a/Error/HandshakeFailed.md +++ /dev/null @@ -1,39 +0,0 @@ -# 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/HANDSHAKE.md b/HANDSHAKE.md new file mode 100644 index 0000000..a4ba065 --- /dev/null +++ b/HANDSHAKE.md @@ -0,0 +1,88 @@ +# Handshake + +После успешной установки защищённого соединения, происходит обмен характеристиками обоих сторон, AKA "рукопожатие". Запрашивающий соединение отправляет пакет следующего формата: + +`[magic number: 8B][protocol version: 4B][sizes: 1B][reconnection flags: 2B]` + +- Магическое число + - _Тип:_ `uint64_t` + - Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. См. раздел "Магическое число" для справки. +- Версия протокола + - _Тип:_ `uint32_t` + - Поддерживаемая запрашивающим версия протокола. +- Размерности частей пакета + - _Тип:_ `uint8_t` + - Описывает некоторые параметры пакетов. + - Маска `0b11000000`: выделено под размерности типа событий + - `0b00`: резерв + - `0b01`: категория и подкатегория это `uint8_t` (каждая) + - `0b10`: категория - `uint8_t`, подкатегория - `uint16_t` + - `0b11`: категория и подкатегория это `int16_t` (каждая) + - Маска `0b00110000`: выделено под размерность ключа в ячейке полезной нагрузки + - `0b00`: резерв + - `0b01`: ключ это `uint8_t` + - `0b10`: ключ это `uint16_t` + - `0b11`: ключ это `int32_t` + - Маска `0b00001100`: выделено под размерность данных в ячейке + - `0b00`: резерв + - `0b01`: размер данных это `uint8_t` + - `0b10`: размер данных это `uint16_t` + - `0b11`: размер данных это `uint64_t` +- Флаги переподключения + - _Тип:_ `uint16_t` + - Описывает параметры нового подключения: + - `0b0000000000000000`: оставить текущее подключение + - `0b0000000000000001`: переподключиться к тому-же порту + - `0b0000000000000010`: запросить новый порт для подключения + - `0b0000000000000100`: использовать TCP + - `0b0000000000001000`: использовать TLS + - `0b0000111111110000`: резерв под расширение + - `0b1111000000000000`: резерв под под нужды сторонних реализаций + +На что целевой сервер отвечает пакетом либо с согласием, либо ошибкой. Пакет с согласием имеет следующий формат: + +`[magic number: 8B][0x00][reconnection port: 2B]` + +- Магическое число + - _Тип:_ `uint64_t` + - См. выше. +- `0x00` + - _Тип:_ `uint8_t` + - Байт с фиксированным нулевым значением, свидетельствующий об успешном подключении и принятии целевым сервером обозначенных условий. +- Порт для переподключения + - _Тип:_ `uint8_t` + - К указанному порту целевой сервер предлагает подключиться запрашиваемому, если тот запросил его. Значение должно быть нулём, если порт не был запрошен. + +Пакет с ошибкой имеет следующий формат: + +`[magic number: 8B][error code: 1B][error description: ~B, zero-terminated]` + +- Магическое число + - _Тип:_ `uint64_t` + - См. выше. +- Код ошибки + - _Тип:_ `uint8_t` + - Код, описывающий ошибку конкретнее. + - 0x01: магическое число ложно. + - 0x02: неподдерживаемая версия протокола. + - 0x03: невозможно выделить новый порт для подключения. + - 0x04: указанный транспортный протокол не поддерживается. + - 0x05: указанная конфигурация размерностей не поддерживается. +- Описание ошибки + - _Тип:_ `uint8_t` + - Текстовое описание ошибки. Является строкой в кодировке ASCII, оканчивающейся нулевым байтом. + +Если цель не поддерживает указанную при рукопожатии версию протокола, запрашивающий может попробовать установить соединение снова, указав более низкую и поддерживаемую им версию протокола. + +Если при хэндшейке запрашивающим был указан новый способ подключения и получен валидный ответ с согласием от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое. + +## Магическое число + +Магическим числом протокола является следующая последовательность байт: + +``` +HEX: 0x4d 0x61 0x72 0x61 0x66 0x6f 0x6e 0x50 +DEC: 77 97 114 97 102 111 110 80 +``` + +Что соответствует строке "MarafonP" в кодировке ASCII. \ No newline at end of file diff --git a/Handshake/Accepted.md b/Handshake/Accepted.md deleted file mode 100644 index 2b8d65f..0000000 --- a/Handshake/Accepted.md +++ /dev/null @@ -1,30 +0,0 @@ -# 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 deleted file mode 100644 index dc2bd05..0000000 --- a/Handshake/Request.md +++ /dev/null @@ -1,45 +0,0 @@ -# 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 24cf2c8..82dc82c 100644 --- a/OVERVIEW.md +++ b/OVERVIEW.md @@ -1,8 +1,12 @@ # Спецификация Marafon Protocol (MFP) v1.0 -Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP (в будущем будет добавлена поддержка UDP и QUIC). Основной фокус при работе над оным идёт на: +Marafon Protocol это протокол логического уровня общего назначения и работает поверх любого транспортного. Также является базой для одноимённого ("Marafon") полнофункционального мессенджера. -- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.). +_Здесь описана спецификация базового протокола; спецификация версии протокола используемая в мессенджере будет размещена в другом репозитории._ + +Основной фокус при работе над сим проектом идёт на: + +- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр. (Reject HTML+JSON, return to binary.)). - Устойчивость к цензуре. - Федеративность. - Поддержка сквозного шифрования. @@ -17,15 +21,19 @@ Marafon Protocol это протокол для одноимённого пол Сервер **обязан**: -1. Оповещать клиент и сервера в федерации о всех ошибках, кроме: +1. Оповещать клиент о всех ошибках, возникших во время его запроса, кроме: + - Связанных с безопасностью +2. Оповещать сервер в федерации о всех ошибках, возникших во время его запроса, кроме: - Связанных с безопасностью - Связанных с внутренними неполадками -2. Отдавать предпочтение данным других серверов, нежели клиентов. -3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты). +3. По умолчанию отклонять все события, содержащие ложную подпись. +4. Отдавать предпочтение данным других серверов, нежели клиентов. +5. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты). Клиент **обязан**: -1. Хранить тишину о всех ошибках. +1. Не сообщать серверу ни о каких ошибках на своей (клиентской) стороне. +2. По умолчанию блокировать до решения юзера все события, содержащие ложную подпись. 2. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию. @@ -35,77 +43,83 @@ Marafon Protocol это протокол для одноимённого пол Существует три уровня категорий событий: 1. **Надкатегория:** Client2Server, Server2Client, Server2Server. -2. **Категория:** Authentication, User, Message, т.д. -3. **Подкатегория:** Login, Create, Delete, т.д. +2. **Категория:** например "Authentication", "User", "Message", т.д. +3. **Подкатегория:** например "Login", "Create", "Delete", т.д. -Надкатегория никак не указывается в пакете, зависит от контекста и при упоминании - чаще всего опускается. Она также определяет структуру некоторых событий, которая может меняться в конкретных случаях. Остальные две занимают по одному байту соответственно. +Надкатегория никак не указывается в пакете, зависит от контекста и при упоминании - чаще всего опускается. Она также определяет структуру некоторых событий, которая может меняться в конкретных случаях. Остальные две являются шестнадцатеричными числами размерности указанной при хэндшейке. -Все категории вместе являются типом события. Значение типа - это число, которое указывается в начале пакета. +Все категории вместе являются типом события. Значение типа - это шестнадцатеричное число, которое указывается в начале пакета. -События всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака (`uint64_t`). +Пакеты с событиями всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака (`uint32_t`). -События всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента. +Пакеты с событиями всех категорий из надкатегории Client2Server, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи клиента. -Данные (AKA "полезная нагрузка") являются расположенными последовательно парами "ключ-значение" и могут быть расположены в пакете относительно друг-друга в произвольном порядке. Одна пара имеет следующий формат: +Пакеты с событиями всех категорий, кроме явно оговорённых, содержат формат полезной нагрузки, занимающий ровно 1 байт (`uint8_t`): -`[1b: key][2b: data length][>0 b: data]` +- 0x01: фиксированная схема. +- 0x02: "ячеистая" структура. + +- Остальные значения зарезервированы. -Все пакеты размером ниже установленного дополняются псевдослучайной последовательностью байт. (???) +Данные (AKA "полезная нагрузка") могут быть представлены в формате фиксированной схемы или в виде ячеек, которые являются расположенными последовательно парами "ключ-значение" и могут быть расположены в произвольном порядке относительно друг-друга. Все неизвестные ключи при парсинге игнорируются. Одна пара (AKA "ячейка") имеет следующий вид: - +`[key][data length][data]` + +Следовательно, полезная нагрузка в данном формате имеет вид: + +`[cell_1][cell_2][cell_3]...[cell_n]` + +Ключ и длинна данных являются шестнадцатеричными числами, размерность которых задаётся на этапе хэндшейка. Полезная нагрузка не может отсутствовать полностью (кроме особо-оговорённых случаев), а ключ не может являться нулём. Если значение конкретной пары пусто, то его длинна должна быть нулём. Исходя из всего вышеописанного, итоговая примерная структура пакета выглядит следующим образом: -`[1b: category][1b: subcategory][4b: server session][?b: payload hash][>0b: payload][~b: random bytes]` +`[category][subcategory][server session: 4B][payload hash: ?B][payload type: 1B][payload: >0B]` -Размер пакета определяется запросом клиента на этапе обмена характеристиками, но не может быть больше, чем 65535 байт или меньше 128 байт. До этого этапа (включительно) размер пакета составляет 512 байт. +Размер пакета не нормирован и ответственность за его менеджмент остаётся на транспортном уровне. (Эталонная реализация MFP будет использовать общий универсальный интерфейс, который, в свою очередь, заворачивает все данные в релевантный протокол транспортного уровня) -Магическим числом протокола является следующая последовательность байт: +### Зарезервированные события -``` -HEX: 0x4d 0x61 0x72 0x61 0x66 0x6f 0x6e 0x50 -DEC: 77 97 114 97 102 111 110 80 -``` +Некоторые категории событий зарезервированы под нужды базового протокола или просто для событий определённого рода. Второе носит рекомендательный характер; вы также можете использовать другие диапазоны для тех-же целей. -Что соответствует строке "MarafonP" в кодировке ASCII. +Все из зарезервированных типов помещаются в минимальную размерность типа события (т.е. по одному байту на категорию и подкатегорию). Ниже приведены диапазоны зарезервированных значений. + +Зарезервировано для нужд протокола и запрещено к использованию в частных реализациях: + +- Категория `0x01` + - Все субкатегории: выделены для событий общей направленности. +- Категория `0x11` + - Все субкатегории: выделены для событий ошибок и предупреждений протокольного уровня. + +Рекомендуется к использованию при определённых случаях: + +- Категории `0x12-0x1F` (включительно) + - Все субкатегории: для событий ошибок и предупреждений. + + + +### Зарезервированные ключи ячеек + +Скоро. + + ## Соединение, аутентификация и сессии -Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. Данная версия протокола подразумевает поддержку пока лишь двух способов подключения: напрямую (без шифрования) и с использованием TLS-over-TCP. +Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. ### Рукопожатие -После успешной установки защищённого соединения, происходит обмен характеристиками, AKA "рукопожатие". Клиент отправляет событие типа `Handshake.Request`, на что сервер отвечает либо ошибкой, либо событием типа `Handshake.Accepted`. +См. файл `HANDSHAKE.md`. - +### Аутентификация -Сервер отвечает ошибкой `Error.HandshakeFailed` и разрывает соединение, если: +Описываемый протокол предполагает наличие базовых механизмов аутентификации. Все они сводятся к проверке как цели, так и запрашивающего на предмет релевантного доступа. -- При обмене данными клиент или сервер обнаруживают несоответствие магических чисел. -- Сервер не поддерживает указанную клиентом версию протокола. -- Невозможно выделить новый порт для подключения. -- Указанный транспортный протокол не поддерживается. -- Размер пакета не попадает в рамки жёсткого лимита сервера. + -Если при хэндшейке клиентом был указан новый способ подключения и получен валидный ответ от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое. - -### Регистрация - -При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его. - -### Вход в учётную запись - -Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться. - -Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте. - -Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение. - -При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера. - -### Пользовательские сессии и подпись +### Сессии и подпись Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте. diff --git a/method_format_example.md b/method_format_example.md deleted file mode 100644 index 01b739e..0000000 --- a/method_format_example.md +++ /dev/null @@ -1,39 +0,0 @@ -# Категория.Субкатегория - -**Значение: 0xBA98** - -## Client2Server - -Какое-то описание метода. - -**Ячейки:** - -- Ячейка_1 - - _Ключ:_ 0xAB - - _Тип:_ `char[]` - - Описание данных. -- Ячейка_2 - - _Ключ:_ 0x12 - - _Тип:_ `uint64_t` - - Тоже описание данных. - - - -## Server2Client - -**Фиксированная схема:** - -- Какая-то ячейка - - _Размер:_ 8 байт - - _Тип:_ `uint64_t` - - Описание, ага. -- Тоже ячейка - - _Размер:_ 2 байта - - _Тип:_ `wchar_t` - - Точно описание. - - - -## Server2Server - -_Также как и Client2Server._ \ No newline at end of file diff --git a/moveToAnotherRepo/1.md b/moveToAnotherRepo/1.md new file mode 100644 index 0000000..1c1b5a9 --- /dev/null +++ b/moveToAnotherRepo/1.md @@ -0,0 +1,15 @@ +### Регистрация + +При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его. + + + +### Вход в учётную запись + +Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться. + +Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте. + +Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение. + +При успешном входе в учётную запись, сервер генерирует четырёхбайтное целое без знака (`uint32_t`), являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера. \ No newline at end of file diff --git a/Error/README.md b/moveToAnotherRepo/Error/README.md similarity index 100% rename from Error/README.md rename to moveToAnotherRepo/Error/README.md diff --git a/moveToAnotherRepo/METHOD FORMAT EXAMPLE.md b/moveToAnotherRepo/METHOD FORMAT EXAMPLE.md new file mode 100644 index 0000000..7f2604e --- /dev/null +++ b/moveToAnotherRepo/METHOD FORMAT EXAMPLE.md @@ -0,0 +1,41 @@ +# Категория.Субкатегория + +**Значение типа: 0xBA98** + +## Client2Server + +Какое-то описание метода. На данный момент, "оффициально" поддерживается два формата, в которых могут быть представлены данные: ячейки (пары "ключ-значение", с указанием длинны значения) и фиксированная схема. Тут представлен пример в формате ячеек. + +**Ячейки:** + +- Код кредитки + - _Ключ:_ 0x01 + - _Тип:_ `uint16_t` + - CVV-код от кредитной карты разработчика. Может быть представлен 12-ю битами, но данные выровнены по сетке в 8 бит. +- ФИ + - _Ключ:_ 0x02 + - _Тип:_ `char[]` + - Имя и фамилия разработчика. Так как он предпочитает никнеймы вписывающиеся в кодировку ASCII - может быть представлено в виде обычного однобайтового массива. + + + +## Server2Client + +Какие-то пояснении об отличии этого метода от C2S-шной версии. Тут представлен пример в формате фиксированной схемы. + +**Фиксированная схема:** + +- Место жительства разработчика + - _Размер:_ 7 байт + - _Тип:_ `char[]` + - Название региона, в котором проживает разработчик. Пишется латиницей, в кодировке ASCII. +- Возраст Жака Фреско + - _Размер:_ 1 байт + - _Тип:_ `uint8_t` + - Возраст разработчика. + + + +## Server2Server + +_Также как и Client2Server._ \ No newline at end of file