Ну чо, теперь делаем более жирную тему.

This commit is contained in:
Shr3dd3r 2023-07-04 06:30:55 +03:00
parent 72bfaea76d
commit b38e0bc616
9 changed files with 208 additions and 203 deletions

View File

@ -1,39 +0,0 @@
# Error.HandshakeFailed
**Значение: 0x0501**
## Client2Server
_Не применимо._
## Server2Client
Отрицательный ответ на инициирование рукопожатия. Сообщает о произошедшей проблеме.
**Ячейки:**
- Код ошибки
- _Ключ:_ 0x01
- _Тип:_ `uint8_t`
- Код, описывающий ошибку конкретнее.
- 0x01: магическое число неверно.
- 0x02: неподдерживаемая версия протокола.
- 0x03: невозможно выделить новый порт для подключения.
- 0x04: указанный транспортный протокол не поддерживается.
- 0x05: указанный размер пакета недопустим.
- Подробные данные
- _Ключ:_ 0x02
- _Тип:_ `char[]`
- Бинарное описание ошибки или сопровождающая информация.
- Текстовое описание
- _Ключ:_ 0x03
- _Тип:_ `char[]`
- Текстовое описание ошибки.
## Server2Server
_Также как и Server2Client._

88
HANDSHAKE.md Normal file
View File

@ -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.

View File

@ -1,30 +0,0 @@
# Handshake.Accepted
**Значение: 0x1002**
## Client2Server
_Не применимо._
## Server2Client
Положительный ответ на инициирование рукопожатия. Передаёт все ключевые данные для осуществления дальнейшей коммуникации.
**Фиксированная схема:**
- Магическое число
- _Размер:_ 8 байт
- _Тип:_ `uint64_t`
- Магическое число протокола, по которому определяется совместимость цели с протоколом MFP. Являет из себя строку "MarafonP" в кодировке ASCII.
- Порт для переподключения
- _Размер:_ 2 байта
- _Тип:_ `uint16_t`
- Предоставляет номер порта для переподключения. Установлен в 0, если не требуется.
## Server2Server
_Также как и Server2Client._

View File

@ -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._

View File

@ -1,8 +1,12 @@
# Спецификация Marafon Protocol (MFP) v1.0
Marafon Protocol это протокол для одноимённого полнофункционального мессенджера, работающего поверх TCP (в будущем будет добавлена поддержка UDP и QUIC). Основной фокус при работе над оным идёт на:
Marafon Protocol это протокол логического уровня общего назначения и работает поверх любого транспортного. Также является базой для одноимённого ("Marafon") полнофункционального мессенджера.
- Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр.).
_Здесь описана спецификация базового протокола; спецификация версии протокола используемая в мессенджере будет размещена в другом репозитории._ <!--за спецификацией протокола используемого в мессенджере - обратитесь к репозиторию с реализацией Marafon'а.-->
Основной фокус при работе над сим проектом идёт на:
- Снижение оверхэдов, по сравнению с классическими решениями (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: "ячеистая" структура.
<!-- - 0x03: вложенная "ячеистая" структура с зашифрованным содержимым -->
- Остальные значения зарезервированы.
Все пакеты размером ниже установленного дополняются псевдослучайной последовательностью байт. (???)
Данные (AKA "полезная нагрузка") могут быть представлены в формате фиксированной схемы или в виде ячеек, которые являются расположенными последовательно парами "ключ-значение" и могут быть расположены в произвольном порядке относительно друг-друга. Все неизвестные ключи при парсинге игнорируются. Одна пара (AKA "ячейка") имеет следующий вид:
<!-- ATTENTION: ^ под вопросом ^ -->
`[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` (включительно)
- Все субкатегории: для событий ошибок и предупреждений.
<!-- TODO? -->
### Зарезервированные ключи ячеек
Скоро.
<!-- TODO? -->
## Соединение, аутентификация и сессии
Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. Данная версия протокола подразумевает поддержку пока лишь двух способов подключения: напрямую (без шифрования) и с использованием TLS-over-TCP.
Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения.
### Рукопожатие
После успешной установки защищённого соединения, происходит обмен характеристиками, AKA "рукопожатие". Клиент отправляет событие типа `Handshake.Request`, на что сервер отвечает либо ошибкой, либо событием типа `Handshake.Accepted`.
См. файл `HANDSHAKE.md`.
<!-- TODO: надо ещё обдумать, какими данными обмениваться клиентосерверу -->
### Аутентификация
Сервер отвечает ошибкой `Error.HandshakeFailed` и разрывает соединение, если:
Описываемый протокол предполагает наличие базовых механизмов аутентификации. Все они сводятся к проверке как цели, так и запрашивающего на предмет релевантного доступа.
- При обмене данными клиент или сервер обнаруживают несоответствие магических чисел.
- Сервер не поддерживает указанную клиентом версию протокола.
- Невозможно выделить новый порт для подключения.
- Указанный транспортный протокол не поддерживается.
- Размер пакета не попадает в рамки жёсткого лимита сервера.
<!-- TODO -->
Если при хэндшейке клиентом был указан новый способ подключения и получен валидный ответ от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 50 мс до 500 мс, создать новое.
### Регистрация
При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его.
### Вход в учётную запись
Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться.
Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение.
При успешном входе в учётную запись, сервер генерирует `uint32_t`, являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.
### Пользовательские сессии и подпись
### Сессии и подпись
Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.

View File

@ -1,39 +0,0 @@
# Категория.Субкатегория
**Значение: 0xBA98**
## Client2Server
Какое-то описание метода.
**Ячейки:**
- Ячейка_1
- _Ключ:_ 0xAB
- _Тип:_ `char[]`
- Описание данных.
- Ячейка_2
- _Ключ:_ 0x12
- _Тип:_ `uint64_t`
- Тоже описание данных.
## Server2Client
**Фиксированная схема:**
- Какая-то ячейка
- _Размер:_ 8 байт
- _Тип:_ `uint64_t`
- Описание, ага.
- Тоже ячейка
- _Размер:_ 2 байта
- _Тип:_ `wchar_t`
- Точно описание.
## Server2Server
_Также как и Client2Server._

15
moveToAnotherRepo/1.md Normal file
View File

@ -0,0 +1,15 @@
### Регистрация
При успешной регистрации учётной записи, клиент генерирует пару ключей (открытый-закрытый) в качестве подписи, после чего открытый ключ отправляется серверу и тот сохраняет его.
<!-- TODO -->
### Вход в учётную запись
Вход в учётную запись происходит путём отправки логина и хэша пароля на сервер. При этом клиент может указать ID серверной сессии, если произошло непредвиденное отключение и ему необходимо переподключиться.
Если логин или пароль несовпадают - сервер отвечает ошибкой и разрывает соединение. Если полезная нагрузка подписана ложно - сервер отвечает ошибкой, соединение разрывается, а администратор сервера и владелец учётной записи уведомляются об инциденте.
Если ID серверной сессии нет в списке недавно-разорванных - сервер отвечает ошибкой и разрывает соединение.
При успешном входе в учётную запись, сервер генерирует четырёхбайтное целое без знака (`uint32_t`), являющийся идентификатором серверной сессии. Клиент обязан хранить его и прикреплять к каждому пакету (кроме особо-оговорённых случаев) до момента отключения от сервера.

View File

@ -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._