Давай по новой (c)

This commit is contained in:
Shr3dd3r 2023-11-20 05:25:05 +03:00
parent 75630f92cf
commit acae23fe35
18 changed files with 362 additions and 549 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
Data types/DATA TYPES.md
SPX/
_something.md
Sessions.md
LBM.md
Reserved LBM keys.md
Reserved events/

24
Common behavior.md Normal file
View File

@ -0,0 +1,24 @@
# Общие принципы поведения узлов
## Обязанности узла
1. Оповещать об ошибке, возникшей во время обработки _события_ другого _узла_, но только если ошибка связана с его некорректной формой.
2. По умолчанию отклонять все _события_ с ложной подписью в _подписанном соединении_.
## Обязанности сервера
1. Оповещать _узел_ (будь то _клиент_ или _сервер_ в федерации) о всех ошибках, возникших во время обработки его _события_, кроме связанных с безопасностью. <!--TODO: сформулировать точнее-->
2. Отдавать предпочтение данным других _серверов_ в федерации, нежели _клиентов_.
3. Отдавать предпочтение сетевым настройкам входящих соединений, нежели локальным (не считая лимиты).
## Обязанности клиента
1. Не сообщать _серверу_ ни о каких ошибках на своей стороне.
2. По умолчанию блокировать до решения юзера обработку любых _событий_, содержащих ложную подпись. <!--TODO: это скорее про фронтенд-->
3. Явно уведомлять юзера при возникновении проблем с безопасностью, как минимум по умолчанию.

View File

@ -1,122 +0,0 @@
# Типы данных
Сия спецификация, помимо всего прочего, также определяет некоторые необходимые типы и структуры данных. В данном файле вы найдёте их описание и декларации.
#### CryptoAlgoType
Перечисление всех допустимых к использованию в базовом протоколе алгоритмов вычисления хэшей, контрольных сумм, симметричного и ассиметричного шифрования.
```C++
enum CryptoAlgoType: uint8_t {
Reserved = 0,
// Checksums
CRC_16 = 11,
CRC_32,
CRC_64,
fletcher_8,
fletcher_16,
fletcher_32,
Adler_32,
// Non-crypto hashes
Murmur64A = 31,
Murmur3_32,
Murmur3_128,
Spooky_128,
// Cryptographic hashes
BLAKE2b = 61,
BLAKE3,
GOST,
HAS160,
HAVAL,
MD2,
MD5,
RIPEMD,
SHA1,
SHA2,
SHAKE128,
SHAKE256,
Skein,
Snefru,
Streebog,
Tiger,
Whirlpool,
// Symmetric key block ciphers
Blowfish = 131,
Twofish,
TripleDES_CBC,
AES_GCM, // AKA Rijndael
AES_CBC,
AES_CTR,
Camellia,
Salsa20,
CAST5,
CAST6,
Kuznyechik,
MESH,
Akelarre,
RC6,
// TODO
};
```
<!-- TODO: RSA, YAK, CramerShoup system, Paillier cryptosystem, curves (25519 & 448), ElGamal, etc. -->
#### CryptoAlgo
Структура, определяющая криптографический алгоритм и размерность. Для шифров это размер ключа, а для хэшей - размер выходных данных (если применимо). Для хэш-функций и симметричных шифров размер ключа вычисляется по формуле `Size << 4`, а для ассиметричных по формуле `Size << 8`. Размерность опускается для контрольных сумм и не-криптографических функций.
```C++
struct CryptoAlgo {
CryptoAlgoType Type;
uint8_t Size;
};
```
#### ServerDescriptor
Дескриптор сервера, представляющий из себя хэш открытого ключа серверной подписи и использующийся алгоритм. Длинна хэша может варьироваться, но всегда не более 512 бит.
```C++
struct ServerDescriptor {
char[64] Hash;
CryptoAlgo Type;
};
```
#### LocID
Идентификатор локального для конкретного сервера объекта.
```C++
typedef uint64_t LocID;
```
#### GlobID
Идентификатор глобального объекта.
```C++
struct GlobID {
uint64_t Object;
ServerDescriptor Server;
};
```
#### Power
Права доступа к какому-либо объекту. Представляет из себя набор следующих флагов:
- `0b00000000000000000000000000000001`: чтение
- `0b00000000000000000000000000000010`: запись
- `0b00000000000000000000000000000100`: удаление
- `0b10000000000000000000000000000000`: изменение прав доступа
- `0b01111111111111111111111111111000`: нераспределено
Нераспределённые флаги могут быть использованы в расширениях протокола.
```C++
typedef uint32_t Power;
```

39
Events.md Normal file
View File

@ -0,0 +1,39 @@
# События
## Категории и типы
Существует три уровня категорий _событий_:
**Надкатегория** описывает типы взаимодействующих _узлов_. Не указывается и зависит от контекста. Варианты: _Client2Server_ (_событие_ сгенерированное _клиентом_ для _сервера_), _Server2Client_ (_событие_ сгенерированное _сервером_ для _клиента_), _Peer2Peer_ (_событие_ сгенерированное _узлом_ для другого _узла_ того-же ранга, в том числе это касается _серверов_ в федерации).
**Категория** описывает _события_ одного класса. Является однобайтовым числом без знака. Всегда больше нуля. Например: _Authentication_, _Object_, т.п.
**Подкатегория** описывает конкретное _событие_ из класса, соответствующего категории. Является однобайтовым числом без знака. Всегда больше нуля. Например: _Login_, _GetContents_, т.п.
Все категории вместе - являются типом _события_. Информацию про зарезервированные типы вы можете найти в [Reserved events.md](Reserved%20events.md).
## Содержание и структура
_События_ всех типов содержат хэш полезной нагрузки размером равно или более 16 байт, зашифрованный с помощью закрытого ключа подписи отправляющего. Этот подписанный хэш гарантирует достоверность полезной нагрузки на уровне прямого подключения между двумя _узлами_. Используемый алгоритм хэширования определяется на этапе рукопожатия.
Идентификатор серверной сессии является четырёхбайтным целым числом без знака. Подробнее про сессии - в [Sessions.md](Sessions.md).
Идентификатор _события_ является двухбайтным целым числом без знака и предназначен для определения отношения запросов к ответам при асинхронном обмене _событиями_.
Данная версия протокола не накладывает ограничений на формат полезной нагрузки, за исключением базовых событий, которые представлены данными в формате _LBM_. Описание всех предопределённых в базовом протоколе ключей ячеек _LBM_ доступно в [Reserved LBM keys.md](Reserved%20LBM%20keys.md). Неизвестные ключи при обработке полезной нагрузки игнорируются. Если полезная нагрузка отсутствует, то она заменяется на один нулевой байт.
<!--TODO: разные виды сериализации, в зависимости от транспорта?-->
Исходя из всего вышеописанного, минимальный размер сериализованного в бинарный вид _события_ составляет 25 байт, а его итоговая структура выглядит следующим образом:
`[category: 1B][subcategory: 1B][session id: 4B][event async id: 2B][payload hash: >16B][payload: >0B]`
Максимальный размер _события_ не нормирован и ответственность за его менеджмент остаётся на транспортном уровне. Максимальный размер полезной нагрузки _события_ определяется на этапе рукопожатия.
### Событие в шифрованном соединении
В _шифрованном соединении_ _события_ сериализуются в бинарное представление и зашифровываются с помощью утверждённого симметричного ключа сессии.

View File

@ -1,103 +0,0 @@
# Handshake
## Protocol-level handshake
После успешной установки соединения происходит обмен характеристиками обоих сторон, AKA "рукопожатие протокольного уровня". Запрашивающий соединение отправляет пакет следующего формата:
<!--`[magic number: 8B][protocol version: 4B][sizes: 1B][crypto params: 6B][reconnection flags: 4B]`-->
`[magic number: 8B][protocol version: 4B][crypto params: 8B][reconnection flags: 4B]`
- Магическое число
- _Тип:_ `uint64_t`
- Магическое число протокола, по которому определяется совместимость цели с протоколом Stadium. См. раздел "Магическое число" для справки.
- Версия протокола
- _Тип:_ `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`
- Маска `0b00000011`: резерв-->
- Параметры криптографии
- _Тип:_ `CryptoAlgo[4]`
- Описывает используемые криптографические алгоритмы на уровне прямого подключения (т.е. "сервер-сервер" или "сервер-клиент"). Первый элемент выделен под хэш-функцию; второй для ассиметричной функции подписи; третий для ассиметричной функции шифрования; четвёртый для симметричной функции.
- Если равно нулю, то используются опции данной версии протокола по умолчанию (SHA256, RSA-2048, AES-192).
- Флаги переподключения
- _Тип:_ `uint32_t`
- Описывает параметры нового подключения:
- `0b00000000000000000000000000000000`: оставить текущее подключение
- `0b00000000000000000000000000000001`: переподключиться к тому-же порту
- `0b00000000000000000000000000000010`: запросить новый порт для подключения
- `0b00000000000000000000000000000100`: использовать TCP
- `0b00000000000000000000000000010000`: использовать TLS
- `0b00001111111111111111111111101000`: резерв под расширение
- `0b11110000000000000000000000000000`: резерв под под нужды сторонних реализаций
На что целевой сервер отвечает пакетом либо с согласием, либо ошибкой.
Пакет с согласием имеет следующий формат:
`[magic number: 8B][0x00][reconnection port: 2B][event payload max size: 2B]`
- Магическое число
- _Тип:_ `uint64_t`
- См. выше.
- `0x00`
- _Тип:_ `uint8_t`
- Байт с фиксированным нулевым значением, свидетельствующий об успешном подключении и принятии целевым сервером обозначенных условий.
- Порт для переподключения
- _Тип:_ `uint16_t`
- К указанному порту целевой сервер предлагает подключиться запрашиваемому, если тот запросил его. Значение должно быть нулём, если порт не был запрошен.
- Максимальный размер полезной нагрузки
- _Тип:_ `uint16_t`
- Всегда больше нуля. Запрашивающий должен соблюдать размерность полезной нагрузки в событии и она всегда должна быть равна или меньше этого значения.
Пакет с ошибкой имеет следующий формат:
`[magic number: 8B][error code: 1B][error description: ~B, zero-terminated]`
- Магическое число
- _Тип:_ `uint64_t`
- См. выше.
- Код ошибки
- _Тип:_ `uint8_t`
- Код, описывающий ошибку конкретнее.
- 0x01: магическое число ложно.
- 0x02: неподдерживаемая версия протокола.
- 0x03: невозможно выделить новый порт для подключения.
- 0x04: указанный транспортный протокол не поддерживается.
- 0x05: указанная конфигурация размерностей не поддерживается.
- 0x06: недопустимые параметры криптографии.
- 0x07: один из указанных криптографических алгоритмов отключён на сервере.
- Описание ошибки
- _Тип:_ `uint8_t`
- Текстовое описание ошибки. Является строкой в кодировке ASCII, оканчивающейся нулевым байтом.
Если цель не поддерживает указанные при рукопожатии параметры, запрашивающий может попробовать установить соединение снова, с иными значениями.
Если при хэндшейке запрашивающим был указан новый способ подключения и получен валидный ответ с согласием от сервера - то они обязаны разорвать текущее соединение, затем, спустя случайное количество времени, от 10 мс до 500 мс, создать новое.
## Магическое число
Магическим числом протокола является следующая последовательность байт:
```
HEX: 0x53 0x74 0x61 0x64 0x69 0x75 0x6d 0x50
DEC: 83 116 97 100 105 117 109 80
```
Что соответствует строке "StadiumP" в кодировке ASCII.

125
Handshakes.md Normal file
View File

@ -0,0 +1,125 @@
# Рукопожатие
<!--TODO: переделать-->
## Протокольного уровня
После успешного подключения к целевому _узлу_ через избранный транспорт - происходит обмен параметрами обоих сторон, AKA "рукопожатие протокольного уровня". Инициирующий соединение _узел_ отправляет пакет следующего формата:
`[magic number: 8B][protocol version: 4B][crypto params: 8B][noise params: 1B][reconnection flags: 4B]`
- Магическое число
- _Тип:_ `uint64_t`
- Магическое число протокола, по которому определяется совместимость цели с протоколом Stadium. См. раздел "Магическое число" для справки.
- Версия протокола
- _Тип:_ `uint32_t`
- Поддерживаемая запрашивающим версия протокола.
- Параметры криптографии
- _Тип:_ `CryptoAlgo[4]`
- Описывает используемые криптографические алгоритмы на уровне прямого подключения (т.е. "узел-узел"). Первый элемент выделен под хэш-функцию; второй для ассиметричной функции подписи; третий для ассиметричной функции шифрования; четвёртый для симметричной функции.
- Если равно нулю, то используются опции данной версии протокола по умолчанию (SHA-384, RSA-3072, AES-256).
- Параметры генерации шума в соединении
- _Тип:_ `uint8_t`
- Описывает прочие параметры соединения:
- `0b11100000`: выделено под настройки количества _шумовых пакетов_
- `0b000`: отсутствие _шумовых пакетов_
- `0b001`: количество задаётся по усмотрению целевого _узла_ <!--TODO: звучит странно-->
- `0b010`: соотношение умовых пакетов_ к реальным - 1:8
- `0b011`: соотношение - 1:4
- `0b100`: 1:2
- `0b101`: 1:1
- `0b110`: 2:1
- `0b111`: 4:1
- `0b00011000`: выделено под настройки размера _шумовых пакетов_
- `0b00`: по усмотрению целевого _узла_ <!--TODO: звучит странно-->
- `0b01`: случайный размер, в пределах от минимального _пакета_ с нулевой полезной нагрузкой, до размера _пакета_ с полезной нагрузкой размерности, которую должен передать целевой _узел_ при одобрении рукопожатия
- `0b10`: случайный размер, в пределах от минимального, до максимального / 2
- `0b11`: случайный размер, на основе среднего размера передаваемого пакета +- 25% (но всегда меньше максимального)
- `0b00000111`: выделено под настройки размера умовых данных_ в обычных _пакетах_
- `0b000`: без шумовых данных
- `0b001`: заполнение шумовыми данными до лимита полезной нагрузки
- `0b010`: заполнение шумовыми данными в случайном количестве, от нуля, до лимита полезной нагрузки
- Диапазон `0b011`-`0b111`: зарезервировано <!--TODO: ещё варианты сделать-->
- Флаги переподключения <!--TODO: сделать енам с перечислением доступных транспортов и их параметров-->
- _Тип:_ `uint32_t`
- Описывает параметры нового подключения:
- `0b00000000000000000000000000000000`: оставить текущее подключение
- `0b00000000000000000000000000000001`: запросить новый транспорт для подключения
- `0b00000000000000000000000000000100`: использовать TCP
- `0b00000000000000000000000000010000`: использовать TLS
- `0b00001111111111111111111111101010`: резерв под расширение
- `0b11110000000000000000000000000000`: резерв под под нужды сторонних реализаций
На это целевой _узел_ отвечает пакетом либо с согласием, либо с ошибкой.
Пакет с согласием имеет следующий формат:
`[magic number: 8B][0x00][reconnection port: 2B][event payload max size: 2B]`
- Магическое число
- _Тип:_ `uint64_t`
- См. выше.
- `0x00`
- _Тип:_ `uint8_t`
- Байт с фиксированным нулевым значением, свидетельствующий об успешном подключении и принятии целевым _узлом_ обозначенных условий.
- Порт для переподключения
- _Тип:_ `uint16_t`
- К указанному порту целевой _узел_ предлагает подключиться запрашиваемому, если тот запросил его. Значение должно быть нулём, если порт не был запрошен.
- Максимальный размер полезной нагрузки
- _Тип:_ `uint16_t`
- Всегда больше нуля. Запрашивающий должен соблюдать размерность полезной нагрузки в событии и она всегда должна быть равна или меньше этого значения.
Пакет с ошибкой имеет следующий формат:
`[magic number: 8B][error code: 1B][error description: ~B, zero-terminated]`
- Магическое число
- _Тип:_ `uint64_t`
- См. выше.
- Код ошибки
- _Тип:_ `uint8_t`
- Код, описывающий ошибку конкретнее.
- `0x01`: магическое число ложно.
- `0x02`: неподдерживаемая версия протокола.
- `0x03`: невозможно выделить новый порт для подключения.
- `0x04`: указанный транспортный протокол не поддерживается.
- `0x05`: указанная конфигурация размерностей не поддерживается.
- `0x06`: недопустимые (несуществующие) параметры криптографии.
- `0x07`: один из указанных криптографических алгоритмов отключён на _узле_.
- Описание ошибки
- _Тип:_ `uint8_t`
- Текстовое описание ошибки. Является строкой в кодировке ASCII, оканчивающейся нулевым байтом.
Если цель не поддерживает указанные при рукопожатии параметры, запрашивающий может попробовать установить соединение снова, с иными значениями.
Если при хэндшейке запрашивающим был указан новый способ подключения и получен валидный ответ с согласием от целевого _узла_ - то они обязаны разорвать текущее соединение, затем, спустя разумное случайное количество времени, создать новое.
## Магическое число
Магическим числом протокола является следующая последовательность байт:
```
HEX: 0x53 0x74 0x61 0x64 0x69 0x75 0x6d 0x50
DEC: 83 116 97 100 105 117 109 80
```
Что соответствует строке "StadiumP" в кодировке ASCII.

View File

@ -1,62 +0,0 @@
# Список зарезервированных ключей ячеек
<!-- TODO: сделать папку и там разместить подробное описание некоторых ключей -->
Перечисленные здесь значения являются либо совсем базовыми, либо предназначены для использования сервером. Все данные транзитных пакетов (т.е. тех, которые предназначены для кого-то кроме сервера подключённого напрямую), для которых критична подлинность, должны передаваться в ячейке `Data` и быть подписанными с помощью ячейки `SignedDataHash`.
## Базовые примитивы
- Data
- _Значение:_ `0x01`
- _Тип:_ не имеет значения
- Основные передаваемые данные.
- ObjectID
- _Значение:_ `0x02`
- _Тип:_ `LocID || GlobID`
- ID объекта в локальном контексте. Например, ID канала для отправки сообщения.
- SrcEventAuthor
- _Значение:_ `0x03`
- _Тип:_ `GlobID`
- Источник (автор) оригинального события.
- PrevEvent
- _Значение:_ `0x04`
- _Тип:_ `LocID`
- Предыдущее событие, логически связанное с текущим.
- NextEvent
- _Значение:_ `0x05`
- _Тип:_ `LocID`
- Следующее событие, логически связанное с текущим.
- BatchNumber
- _Значение:_ `0x06`
- _Тип:_ `uint32_t`
- Последовательный номер события в цепочке.
- Path
- _Значение:_ `0x07`
- _Тип:_ `char[]`
- Путь к запрашиваемому/загружаемому ресурсу.
- Power
- _Значение:_ `0x08`
- _Тип:_ `Power`
- Права доступа к конкретному объекту.
<!--- ServerSession
- _Значение:_ `0x09`
- _Тип:_ `uint32_t`
- Идентификатор серверной сессии. В случае с аутентифицированным соединением, его присутствие обязательно.-->
## Криптография
- CryptoAlgos
- _Значение:_ `0x11`
- _Тип:_ `CryptoAlgo[4]`
- Используемые криптографические алгоритмы. Предназначено для использования конечной целью, а не промежуточным узлом (сервером). Первый элемент выделен под хэш-функцию; второй для ассиметричной функции подписи; третий для ассиметричной функции шифрования; четвёртый для симметричной функции.
- CryptoKeyID
- _Значение:_ `0x12`
- _Тип:_ `uint32_t`
- Идентификатор используемого криптографического ключа для шифрования данных.
- SignedDataHash
- _Значение:_ `0x13`
- _Тип:_ не имеет значения
- Хэш основных передаваемых данных, зашифрованный закрытым ключом отправителя.

View File

@ -1,155 +0,0 @@
# Спецификация протокола 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)
- Механизм пользовательских сессий, клиентские подписи и базовая аутентификация
- Механизм синхронизации ключей для сквозного шифрования между юзерами
- Манипуляции с файлами (скачивание/загрузка)
- Стриминг аудио и видео

123
Overview.md Normal file
View File

@ -0,0 +1,123 @@
# Обзор
## Терминология
Здесь перечислены используемые в данной документации термины, значение которых может быть не очевидно и/или не соответствует тому, которое подразумевается обычно.
### Узел
Любая машина, способная выполнять коммуникацию по протоколу Stadium. Обычно используется в контексте коммуникации двух машин одного ранга или когда ранг не имеет значения.
### Сервер
Выполняющий роль сервера _узел_ в многоранговой сети.
### Клиент
Выполняющий роль клиента _узел_ в многоранговой сети.
### Подписанное соединение/сессия
Соединение между двумя _узлами_, все _события_ в котором подписаны с помощью оговорённого ассиметричного алгоритма и приватного ключа отправителя.
### Шифрованное соединение/сессия
Соединение между двумя _узлами_, все _события_ в котором шифруется с помощью оговорённого симметричного алгоритма и ключа. Требует _подписанное соединение_ для установки.
### Событие
Структура данных, обладающая конкретными семантическими свойствами в зависимости от типа и содержащая дополнительные поля, требуемые для верного отображения и интерпретации самой структуры. Проще говоря - то, чем обмениваются и что обрабатывают _узлы_ во время коммуникации между собой.
### Шумовое событие
_Событие_ предопределённой категории, имеющее случайно-сгенерированные поля.
### LBM
Аббревиатура наименования способа форматирования данных, используемого для полезной нагрузки _события_, которая расшифровывается как "Linear Binary Map". Подробнее - в [LBM.md](LBM.md).
### Шумовые данные
Случайно-сгенерированные данные, помещённые в ячейку полезной нагрузки _события_.
## Пример коммуникации двух узлов
Допустим, что у нас есть два неизвестных друг-другу _узла_ - `p1` и `p2`. Тогда полная коммуникация по шагам (от подключения неизвестного для `p2` _узла_ - до "правильного" уничтожения сессии и закрытия соединения) будет выглядеть так: <!--TODO: предстоит переделать, ввиду предстоящих нововведений-->
1. `p1` подключается с помощью соответствующего транспорта к `p2`
2. `p1` запрашивает рукопожатие с какими-то параметрами подключения
3. `p2` отвечает принятием со своей частью параметров подключения
4. `p1` запрашивает публичный ключ подписи у `p2`\*
5. `p2` отвечает своим публичным ключом и данными об использующемся алгоритме
6. `p1` сохраняет публичный ключ сервера в своём хранилище
7. `p1` отправляет _событие_ с запросом установки публичного ключа сессионной подписи, подписанное с помощью публичного ключа `p2`\*\*
8. `p2` принимает запрос и устанавливает полученный ключ в качестве сессионного для подключения `p1`, если подпись валидна
9. `p2` отвечает _событием_ с кодом успешности операции. С этого момента установлено _подписанное соединение_, т.е. узлы **обязаны** подписывать каждое _событие_ и отклонять любые неподписанные/с ложной подписью
10. `p1` отправляет _событие_ с запросом _шифрованного соединения_, симметричным ключом, зашифрованным с помощью публичного ключа сервера, и используемым алгоритмом шифрования\*\*\*
11. `p2` принимает запрос и устанавливает текущий симметричный ключ сессии
12. `p2` отвечает _событием_ с кодом успешности операции. С этого момента установлено _шифрованное соединение_, т.е. узлы **должны** шифровать _события_ с использованием обозначенного ключа
13. `p1` отправляет зашифрованное _событие_ с запросом какого-то объекта
14. `p2` отвечает зашифрованным _событием_, содержащее этот объект
15. `p1` отправляет _событие_ с сообщением о намерении уничтожить сессию и ждёт в течении n времени, по истечению которого может разорвать соединение "насильно"
16. `p2` принимает запрос и прекращает любой параллельный обмен данными
17. `p2` отвечает _событием_ с кодом успешности операции
18. `p2` закрывает соединение
И в виде схемы:
```
Handshake:
[p1] --------[transport connect]------> [p2]
[p1] --------[handshake request]------> [p2]
[p1] <-------[handshake accept]-------- [p2]
Get p2's public key:
[p1] ----[request public sign key]----> [p2]
[p1] <-[public key and crypto params]-- [p2]
[p1]: saves p2's public key at local storage
Make signed connection:
[p1]: sign event
[p1] --------[set session sign]-------> [p2]
[p2]: check event signature
[p2]: associates p1's public key with this connection
[p2]: sign event
[p1] <--------[status code OK]--------- [p2]
[p1]: check event signature
Make encrypted connection:
[p1]: sign event
[p1] ---[set session symmetric key]---> [p2]
[p2]: check event signature
[p2]: associates symmetric key with this connection
[p2]: sign and encrypt event
[p1] <--------[status code OK]--------- [p2]
[p1]: decrypt and check event signature
Request some object:
[p1]: sign and encrypt event
[p1] ------[request some object]------> [p2]
[p2]: decrypt and check event signature
[p2]: sign and encrypt event
[p1] <-------[some object data]-------- [p2]
[p1]: decrypt and check event signature
Close session:
[p1]: sign and encrypt event
[p1] ---------[close session]---------> [p2]
[p2]: decrypt and check event signature
[p2]: sign and encrypt event
[p1] <--------[status code OK]--------- [p2]
[p2]: close connection
[p1]: decrypt and check event signature
```
\* - _стоит уточнить, что в реальных сценариях использования этот публичный ключ должен быть уже известен <!--(см. `TODO`)-->, либо коммуникация должна производиться через транспорт, гарантирующий достоверность передаваемых данных._
\*\* - _это может быть публичный ключ подписи `p1`, а может быть и сгенерированный отдельно, в зависимости от сценария использования._
\*\*\* - _установка шифрованного соединения полностью опциональна и его отсутствие не накладывает каких-либо ограничений, в рамках этой версии протокола. Формат события в таком соединении см. в [Events.md](Events.md)._

View File

@ -1,6 +1,19 @@
# Stadium Protocol # Спецификация протокола Stadium версии 1.0
Stadium это протокол для безопасной коммуникации общего назначения, работающий поверх обширного перечня транспорта. Данная спецификация описывает базу, на основе которой могут быть реализованы расширения (_SPX - Stadium Protocol eXtension_) для более конкретных нужд. Помимо прочего, данный протокол служит основой для полнофункционального мессенджера Marafon<!--, спецификация расширения которого находится в папке `SPX/Marafon/`-->.
Основной фокус при работе над сим проектом идёт на:
- Возможность функционирования в условиях низкой пропускной способности канала;
- Устойчивость к цензуре;
- Поддержка широкого спектра транспортных протоколов;
- Построение децентрализованных (федеративных и P2P) сетей;
- Гибкое сквозное шифрование;
- Расширяемость и возможность подстраивания под конкретные задачи.
<!--В сей спецификации вы можете встретить примеры кода и упоминание типов данных языка C++.-->
Спецификация протокола Stadium и его официального расширения для нашего мессенджера - Marafon SPX.
**ПРОЕКТ В АКТИВНОЙ РАЗРАБОТКЕ/PROJECT UNDER ACTIVE DEVELOPMENT** **ПРОЕКТ В АКТИВНОЙ РАЗРАБОТКЕ/PROJECT UNDER ACTIVE DEVELOPMENT**

29
Reserved events.md Normal file
View File

@ -0,0 +1,29 @@
# Зарезервированные типы событий
Некоторые категории _событий_ зарезервированы под нужды базового протокола или просто для _событий_ определённого класса. Второе носит рекомендательный характер; вы также можете использовать иные диапазоны для тех-же целей. Ниже приведены диапазоны зарезервированных значений в виде шестнадцатеричных чисел. Конкретный перечень всех зарезервированных событий, описание их структуры - есть в папке `Reserved events/`.
Зарезервировано для нужд протокола и запрещено к использованию в сторонних расширениях:
1. Категория и субкатегория `0x00`
- Запрещены к использованию.
2. Категория `0x01`
- Все субкатегории: выделены для базовых _событий_, связанных с менджментом сессии.
3. Категория `0x02`
- Все субкатегории: выделены для базовых _событий_, которые могут быть приняты _узлом_ вне _подписанного соединения_.
4. Категория `0x11`
- Все субкатегории: выделены для базовых кодов ответа, ошибок и предупреждений.
Рекомендуется к использованию расширениями в конкретных ситуациях:
1. Категории `0x12`-`0x1F` (включительно)
- Все субкатегории: для кодов ответа, ошибок и предупреждений сторонних реализаций.
2. Категории `0x20`-`0x2F` (включительно)
- Все субкатегории: для _событий_, которые могут быть приняты _узлом_ вне _подписанного соединения_.
<!-- TODO: событие запроса всех сервисов на сервере -->

View File

@ -1,61 +0,0 @@
# Сессии и все-все-все
## Подпись
### Серверная подпись
Сервер обязан заведомо иметь пару ключей своей подписи, прежде чем коммуницировать с кем-либо в принципе. Генерировать их желательно вручную, на этапе установки/настройки серверного ПО.
### Обмен пакетами в неаутентифицированом соединении типа клиент-сервер
До выполнения аутентификации, сервер может, но не обязан, подписывать каждый свой пакет. Клиент не должен подписывать свои пакеты и должен устанавливать хэш полезной нагрузки в нулевое значение.
Сервер должен не проверять подпись пакетов клиента. Клиент должен проверять подпись только в случае наличия у него открытого ключа сервера.
### Регистрация
Перед инициированием процедуры регистрации, клиент запрашивает открытый ключ подписи сервера и тот отвечает событием, с открытым ключом в качестве основных данных и подписанным закрытым ключом хэшем полезной нагрузки. Клиент должен проверить подпись этого события с помощью публичного ключа из него-же.
<!-- TODO: оговорка про способы регистрации? -->
В случае успешной регистрации, клиент генерирует публичный и приватный ключи подписи, после чего отправляет событие с публичным ключом в качестве основных данных и подписанным закрытым ключом хэшем полезной нагрузки на сервер. Сервер должен проверить подпись этого события с помощью публичного ключа из него-же.
<!-- TODO: оговорка про способы аутентификации? -->
### Обмен пакетами в аутентифицированном соединении
Каждый принятый сервером пакет, содержащий хэш полезной нагрузки, должен проверяться на соответствие подписи, путём расшифровки этого хэша открытом ключом подписи и последующего сравнения с реальным хэшем полезной нагрузки. Если сервер обнаруживает, что подпись неверна - сервер отвечает ошибкой, добавляет запись об инциденте в журнал, а обрабатываемый пакет игнорируется.
Каждый принятый клиентом пакет, содержащий хэш полезной нагрузки, должен быть проверен на соответствие подписи. Если клиент обнаруживает, что подпись неверна - он уведомляет об этом пользователя, а обрабатываемый пакет игнорируется.
### Наглядные примеры работы с подписями
#### Отправка подписанного пакета
При отправке сообщения клиентом A клиенту Б, оно проходит следующую цепочку:
1. Клиент А посылает пакет с подписанным хэшем полезной нагрузки (далее - ХПН) и подписанными основными данными (как часть содержания полезной нагрузки), на свой хоумсервер (место, где клиент А аутентифицирован, далее - ХС А).
2. ХС A проверяет ХПН на валидность. Допустим, что подпись верна.
3. ХС А совершает релевантные действия, исходя из содержания и типа события.
4. ХС А переподписывает ХПН с использованием свой подписи.
5. ХС А отправляет переподписанный пакет хоумсерверу клиента Б (далее - ХС Б).
6. ХС Б проверяет ХПН на валидность. Допустим, что подпись верна.
7. ХС Б совершает релевантные действия, исходя из содержания и типа пакета.
8. ХС Б переподписывает пакет с использованием своей подписи.
9. ХС Б отправляет переподписанный пакет клиенту Б.
10. Клиент Б проверяет ХПН на валидность. Допустим, что подпись верна.
11. Клиент Б проверяет подпись основных данных, на предмет соответствия подписи клиента А и совершает релевантные действия.
<!-- TODO: решить: как и нужно-ли, чтобы сервер являлся средой нулевого доверия в плане передачи подписей пользователей (скорее всего "Да.") -->
## Серверные сессии и их идентификаторы
При подключении клиента к серверу, сервер генерирует и отправляет клиенту уникальный идентификатор серверной сессии, который также ассоциирует с параметрами подключения, установленных на этапе рукопожатия. Клиент и сервер обязаны прилагать назначенный ID серверной сессии к каждому пакету.
Если при проверке ID серверной сессии в пакете обнаруживается её отсутствие среди пулла серверных сессий - сервер отвечает ошибкой, соединение разрывается.
Идентификатор серверной сессии всегда уникален, по отношению к другим активным сессиям, и никогда не равен нулю.
Если у клиента есть несколько подключений, то все они должны быть снабжены единым серверным идентификатором.

View File

@ -1 +0,0 @@
У всех событий из этой категории, ячейка базового примитива `Data` обязана содержать подробное описание ошибки.

View File

@ -1,43 +0,0 @@
# Категория.Субкатегория
**Значение типа: 0xBA98**
**Требует аутентификации: нет**
## Client2Server
Какое-то описание метода. На данный момент, "официально" поддерживается два формата, в которых могут быть представлены данные: KLDR (расположенные последовательно "ключ-длина-значение") и фиксированная схема. Тут представлен пример в формате KLDR.
**Ячейки:**
- Код кредитки
- _Ключ:_ 0x01
- _Тип:_ `uint16_t`
- CVV-код от кредитной карты разработчика. Может быть представлен 12-ю битами, но мир несправедлив и поэтому данные выровнены по сетке в 8 бит.
- ФИ
- _Ключ:_ 0x02
- _Тип:_ `char[]`
- Имя и фамилия разработчика. Так как он предпочитает никнеймы вписывающиеся в кодировку ASCII - может быть представлено в виде обычного однобайтового массива.
## Server2Client
Какие-то пояснении об отличии этого метода от C2S-шной версии. Тут представлен пример в формате фиксированной схемы.
**Фиксированная схема:**
- Место жительства разработчика
- _Размер:_ 7 байт
- _Тип:_ `char[]`
- Название региона, в котором проживает разработчик. Пишется латиницей, в кодировке ASCII.
- Возраст Жака Фреско
- _Размер:_ 1 байт
- _Тип:_ `uint8_t`
- Возраст разработчика.
## Server2Server
_См. Client2Server._