# Спецификация протокола Stadium v1.0 Протокол Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх любого поддерживаемого транспорта. Данная спецификация описывает лишь базу, поверх которой может быть реализованы расширения (SPX - Stadium Protocol eXtension) для более конкретных нужд. Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon, спецификация расширения которого находится в папке `Marafon SPX`. _Здесь описана спецификация базового протокола; документация касательно версии протокола используемой в мессенджере размещена в другом репозитории._ Основной фокус при работе над сим проектом идёт на: - Снижение оверхэдов, по сравнению с классическими решениями (Matrix, Discord, WhatsApp, пр. (Reject HTML+JSON, return to binary.)). - Устойчивость к цензуре. - Федеративность. - Поддержка сквозного шифрования. - Совместимость со всеми мажорными оверлейными сетями (Tor, I2P и yggdrasil). - Расширяемость. В сей спецификации вы иногда сможете встретить примеры кода и упоминание типов данных языка C++, так как без них обойтись моментами сложно. ## Поведение сервера и клиента Сервер **обязан**: 1. Оповещать клиент о всех ошибках, возникших во время его запроса, кроме связанных с безопасностью. 2. Оповещать сервер в федерации о всех ошибках, возникших во время его запроса, кроме: - Связанных с безопасностью - Связанных с внутренними неполадками 3. По умолчанию отклонять все события, содержащие ложную подпись. 4. Отдавать предпочтение данным других серверов, нежели клиентов. 5. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты). Клиент **обязан**: 1. Не сообщать серверу ни о каких ошибках на своей (клиентской) стороне. 2. По умолчанию блокировать до решения юзера все события, содержащие ложную подпись. 2. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию. ## События, пакеты и их структура Существует три уровня категорий событий: 1. **Надкатегория:** Client2Server, Server2Client, Server2Server. 2. **Категория:** например "Authentication", "User", "Message", т.д. 3. **Подкатегория:** например "Login", "Create", "Delete", т.д. Надкатегория никак не указывается в пакете, зависит от контекста и при упоминании - чаще всего опускается. Она также определяет структуру некоторых событий, которая может меняться в конкретных случаях. Остальные две являются шестнадцатеричными числами размерности указанной при хэндшейке. Все категории вместе являются типом события. Значение типа - это шестнадцатеричное число, которое указывается в начале пакета. Пакеты с событиями всех категорий, кроме явно оговорённых или принадлежащих к надкатегории Server2Client, содержат идентификатор серверной сессии, являющийся четырёхбайтным числом без знака (`uint32_t`). Пакеты с событиями всех категорий, кроме явно оговорённых, содержат хэш полезной нагрузки, зашифрованный с помощью закрытого ключа подписи отправляющего. Этот подписанный хэш гарантирует достоверность полезной нагрузки на уровне прямого подключения ("клиент-сервер" или "сервер-сервер"). Данные (AKA "полезная нагрузка") могут быть представлены в формате фиксированной схемы или в формате KLDR ("Key-Length-Data-Repeat"), которые являются расположенными последовательно парами "ключ-значение" и могут быть расположены в произвольном порядке относительно друг-друга. Применяемый формат зависит от типа события, но чаще всего это KLDR. Все неизвестные ключи при его парсинге игнорируются. Одна пара (AKA "ячейка") имеет следующий вид: `[key][data length][data]` Следовательно, полезная нагрузка в данном формате имеет вид: `[cell_1][cell_2][cell_3]...[cell_n]` Ключ и длинна данных являются шестнадцатеричными числами, размерность которых задаётся на этапе хэндшейка. Полезная нагрузка не может отсутствовать полностью (кроме особо-оговорённых случаев), а ключ не может являться нулём. Если значение конкретной пары пусто, то длинна данных должна быть нулём. Исходя из всего вышеописанного, итоговая примерная структура пакета выглядит следующим образом: `[category][subcategory][server session: 4B][payload hash: ~B][payload: >0B]` Размер пакета не нормирован и ответственность за его менеджмент остаётся на транспортном уровне. (Эталонная реализация Stadium будет использовать общий универсальный интерфейс, который, в свою очередь, заворачивать все данные в релевантный протокол транспортного уровня) ### Зарезервированные события Некоторые категории событий зарезервированы под нужды базового протокола или просто для событий определённого рода. Второе носит рекомендательный характер; вы также можете использовать иные диапазоны для тех-же целей. Все из зарезервированных типов помещаются в минимальную размерность типа события (т.е. по одному байту на категорию и подкатегорию). Ниже приведены диапазоны зарезервированных значений. Зарезервировано для нужд протокола и запрещено к использованию в частных реализациях (см. также файлы в директории `reserved/` для конкретных примеров): - Категория `0x01` - Все субкатегории: выделены для событий общей направленности. - Категория `0x11` - Все субкатегории: выделены для событий ошибок и предупреждений протокольного уровня. Рекомендуется к использованию в конкретных ситуациях: - Категории `0x12-0x1F` (включительно) - Все субкатегории: для событий ошибок и предупреждений. ### Зарезервированные ключи ячеек У данных в формате KLDR также существуют зарезервированные ключи, которые аналогичным образом помещаются в минимальную размерность ключа: - `0x00` - Запрещено к использованию. - `0x01-0x10` (включительно) - Базовые примитивы. - `0x11-0x1F` (включительно) - Для нужд криптографии. Подробное описание зарезервированных ключей есть в файле `KLDR RESERVED KEYS.md`. ## Соединение, аутентификация и сессии Первичное подключение к серверу может выполнятся разными способами, в том числе подразумевающими маскировку траффика под существующие протоколы, но при использовании вне локальных сетей - должно сводиться к установке защищённого соединения. ### Рукопожатие См. файл `HANDSHAKE.md`. ### Аутентификация Описываемый протокол предполагает наличие базовых механизмов аутентификации. Все они сводятся к проверке как цели, так и запрашивающего на предмет релевантного доступа. ### Сессии и подпись Пример работы подписи; при отправке сообщения клиентом другому клиенту, оно проходит следующую цепочку: 1. Клиент-отправитель посылает пакет с подписанной полезной нагрузкой (далее - ППН) и подписанными основными данными (как часть содержания ППН), на свой хоумсервер (далее - ХС; место, где клиент аутентифицирован). 2. ХС проверяет подпись ППН на валидность. Допустим, что подпись верна. 3. ХС совершает релевантные действия, исходя из содержания и типа события. 4. ХС переподписывает пакет с использованием свой подписи. 5. ХС отправляет переподписанный пакет целевому серверу (далее - ЦС). 6. ЦС проверяет подпись ППН на валидность. Допустим, что подпись верна. 7. ЦС совершает релевантные действия, исходя из содержания и типа пакета. 8. ЦС переподписывает пакет с использованием своей подписи. 9. ЦС отправляет переподписанный пакет целевому клиенту (далее - ЦК). 10. ЦК проверяет подпись ППН на валидность. Допустим, что подпись верна. 11. ЦК проверяет подпись основных данных, на предмет соответствия подписи клиента-отправителя и совершает релевантные действия. Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи, путём расшифровки этого хэша открытом ключом подписи и последующего сравнения с реальным хэшем полезной нагрузки. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, добавляет запись в журнал об инциденте, а обрабатываемый пакет игнорируется. Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, должен быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он уведомляет об этом пользователя, а обрабатываемый пакет игнорируется. Если при проверке ID серверной сессии обнаруживается несоответствие - сервер отвечает ошибкой, соединение разрывается. ## Система идентификаторов Практически каждый объект в Stadium имеет свой уникальный идентификатор, по которому к нему (объекту) следует обращаться. Идентификаторы делятся на два типа: локальные и федеративные. Первый тип является восьмибайтным числом без знака (`uint64_t`). Валидный объект не может иметь ID равный нулю. Второй тип является структурой из двух восьмибайтных чисел без знака, кои являют из себя ID объекта и ID федерируемого сервера соответственно. ID федерируемого сервера определяется сервером при первой попытке коммуникации и ассоциировано с его подписью, списком доменов и IP-адресов. Сервер должен проверять идентификатор на валидность и отвергать его, если он не валиден в текущем контексте. ## Список ToDo (To Document) - Механизм пользовательских сессий, клиентские подписи и базовая аутентификация - Механизм синхронизации ключей для сквозного шифрования между юзерами - Манипуляции с файлами (скачивание/загрузка) - Стриминг аудио и видео