101 lines
9.7 KiB
Plaintext
101 lines
9.7 KiB
Plaintext
JOIN нового участника через BLE INVITE
|
||
====================================
|
||
|
||
Назначение
|
||
----------
|
||
Для двух ещё незнакомых узлов доставка utun:// не даёт транспорта обычному JOIN:
|
||
ETCP на BLE требует известный ключ участника. Начальный обмен переносится на
|
||
существующую INVITE-характеристику, без временного ETCP_CONN и временного членства.
|
||
Обычная передача ссылки и её ACK остаются самостоятельной операцией; получение
|
||
ссылки не запускает JOIN. Пользователь запускает тот же chat_sync_join_link.
|
||
|
||
Разделение ответственности
|
||
-------------------------
|
||
chat_sync остаётся единственным владельцем состояний JOIN, проверки приглашения,
|
||
подписей, записи SQLite, ожидания Merkle, результата UI и отмены. INFO_REQ/RESP,
|
||
REQUEST, READY и ERROR используют общие обработчики с обычным ETCP-путём.
|
||
BLE-драйвер реализует только ограниченный аутентифицированный транспорт этих
|
||
сообщений. Ядро не включает BLE/Qt/JNI и не зависит от адресов платформенного API.
|
||
Borrowed provider хранится у instance; unregister отменяет связанные JOIN и waiters
|
||
до освобождения драйвера. Все вызовы и события сериализованы в uasync.
|
||
|
||
Маршрут обмена
|
||
-------------
|
||
Маршрут содержит подтверждённый X25519-ключ пира и непрозрачный handle сессии.
|
||
Для ETCP ключ берётся из аутентифицированного соединения, для BLE — после CCM
|
||
и проверки свежего challenge. Ответ направляется по маршруту запроса; отложенный
|
||
READY хранит этот маршрут вместе с channel/peer/attempt. По одному node_id ответный
|
||
транспорт не выбирается. Клиент принимает ответы только совпадающей попытки и пути.
|
||
|
||
Если ETCP уже UP, сохраняется обычный путь. Иначе доступный BLE peer используется
|
||
для JOIN; при отсутствии BLE применяется прежний NCD/IP. Одновременно одну попытку
|
||
по двум транспортам не запускаем. Узел подключения должен совпадать с pubkey ссылки;
|
||
получение ссылки от другого nearby-узла само по себе не делает его connection-узлом.
|
||
|
||
Аутентификация до членства
|
||
-------------------------
|
||
Каждый пакет bootstrap содержит версию/тип и публичный X25519-ключ отправителя;
|
||
AES-128-CCM выполняет штатный secure_channel. Зашифрованное тело содержит отдельный
|
||
идентификатор протокола, sender/receiver node_id, случайные nonce обоих участников,
|
||
счётчик направления и разрешённое сообщение JOIN. Секреты приглашения не логируются.
|
||
Клиент закрепляет ключ connection-узла из принятой ссылки. Сервер проверяет
|
||
node_id=derive(X25519); успешный CCM доказывает владение соответствующим private key.
|
||
Это аутентификация личности, а не признание ключа членом группы.
|
||
|
||
HELLO несёт случайный nonce инициатора. Ответ возвращает его и свежий nonce сервера.
|
||
INFO_REQ подтверждает оба nonce; каждое следующее сообщение связано с той же парой
|
||
и строго возрастающим счётчиком. Старый HELLO не заменяет уже выбранную сессию;
|
||
старые пакеты другой сессии/направления, повторы, чужие ключи и посторонние типы
|
||
не передаются chat_sync. Одного сохранённого ciphertext недостаточно для нового JOIN.
|
||
HELLO повторяется до ответа с периодом не меньше500ms. Замена ещё не доказанного
|
||
challenge сохраняет исходный deadline; после завершения новая попытка получает новые nonce.
|
||
Зашифрованный CANCEL освобождает другую сторону при ошибке/отмене.
|
||
|
||
Разрешены только INFO_REQ, INFO_RESP, REQUEST, READY, ERROR. Произвольные сервисы,
|
||
CHANNEL_INVITE, серверный add_key, маршрутизация и история через bootstrap не доступны.
|
||
Получение INFO_REQ по-прежнему требует зарегистрированный действующий join_key.
|
||
Настройка показа входящих ссылок не заменяет проверку права вступления.
|
||
|
||
Ограничения и владение
|
||
---------------------
|
||
Одна криптографическая сессия на физический BLE-link, не более BLE_LINKS_MAX.
|
||
Очередь bootstrap ограничена четырьмя целыми сообщениями на link. Её backpressure
|
||
не создаёт неограниченной очереди; отказ завершает попытку с диагностикой.
|
||
DATA сохраняет предел1500; INVITE получает отдельный предел2304, достаточный для
|
||
максимального JOIN_INFO_RESP и криптографического envelope. Фрагментация остаётся
|
||
единственной, в ble_transport; собственный фрагментатор bootstrap не добавляется.
|
||
Сообщения ядра ограничены2048байт, остальные длины проверяются до копирования.
|
||
Ожидание открытия/фазы BLE ограничено20s, вся bootstrap-сессия —60s. Повторы и
|
||
keepalive не продлевают срок. Закрытие GATT отменяет JOIN и связанные waiters.
|
||
|
||
Переход к ETCP
|
||
-------------
|
||
Пока идёт bootstrap, появление записи connection-узла у joiner после INFO_RESP
|
||
не включает DATA раньше окончания JOIN. Сервер разрешает повышение после commit
|
||
мембера и отправки READY; клиент — после проверки READY. Принятые сообщения INVITE
|
||
должны быть отправлены до освобождения удержания. Повышение использует прежний
|
||
GATT, но выполняет обычный аутентифицированный handshake ETCP и повторную проверку
|
||
known-key. BGP/READY группы следуют существующему контракту. При отмене/таймауте
|
||
уже сохранённые и подписанные записи не откатываются.
|
||
|
||
Проверки
|
||
--------
|
||
Два настоящих ядра с fake GATT, без IP-пути: незнакомые ключи, доставленная ссылка,
|
||
обычный JOIN, сохранённый мембер, повышение и передача ETCP. Обе роли инициатора
|
||
GATT, MTU23/517, максимальный профиль, неверный/истёкший ключ, неподходящий pubkey,
|
||
повтор/подмена/неверный тип, разрыв и stop на каждой фазе. Отдельно — прежние JOIN
|
||
по IP, отложенный READY через Merkle и независимость доставки ссылки от JOIN.
|
||
После сборки — физический Linux/SM-A525F с логами обеих сторон: доставка, JOIN,
|
||
commit, известный ключ, ETCP UP и групповое согласование.
|
||
|
||
Результаты 30–31.10.2026
|
||
-----------------------
|
||
test_ble_etcp: MTU23/517, оба направления GATT, профиль1024 байта, неверный ключ,
|
||
повтор после отказа, отмена при занятом GATT, подписанное членство, ETCP и групповое READY — PASS.
|
||
test_ble_join: CCM tamper, подмена ключа, reflection/replay, старый handle, новый challenge,
|
||
сохранение deadline, whitelist, предел очереди, CANCEL и освобождение ресурсов — PASS.
|
||
Linux→SM-A525F23:43:55/01:43:56: INFO_REQ/RESP, REQUEST, READY result=0 через INVITE,
|
||
после него BLE ETCP и Merkle; сообщения в обе стороны подтверждены интерфейсом/БД.
|
||
Полный прогон ядра229/232: прежние test_call_admission/test_conn_mgr_phases/test_call_headless
|
||
падают так же, как до изменения. BlueZ private-bus, transport, desktop BLE и WinRT проверки — PASS.
|