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