Browse Source

chat_join: верификация join-ключа на инвайтере (REQUEST_FWD)

Инвайтер добавлял мембера без проверки join-ключа — любой известный узел
мог самопригласиться в канал через REQUEST_FWD напрямую владельцу.
register_key теперь всегда хранит выданный ключ локально,
process_request отклоняет запрос с неизвестным/чужим ключом.
Тесты: unknown join_key rejected + регистрация ключа в t_process_request.
v2
evgeny 2 weeks ago
parent
commit
fc2262912a
  1. 13
      src/chat/chat_join.c
  2. 13
      tests/test_chat_join.c

13
src/chat/chat_join.c

@ -140,6 +140,14 @@ void chat_join_process_request(struct UTUN_INSTANCE* inst, uint64_t group_id,
char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)group_id); char ch_id[32]; snprintf(ch_id, sizeof(ch_id), "%llu", (unsigned long long)group_id);
sqlite3* db = inst->topo_sqlite_db; sqlite3* db = inst->topo_sqlite_db;
/* 0. верификация join-ключа: принимаем только выданные нами (инвайтером) ключи */
struct join_key_entry* ke = _keys_find(group_id, join_key);
if (!ke || ke->inviter_id != inst->node_id) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "%s: process_request invalid join key ch=%s from=%016llx key=%016llx — drop",
CJ_ID, ch_id, (unsigned long long)from_node, (unsigned long long)join_key);
return;
}
/* 1. привязка идентичности: node_id = derive(x25519) */ /* 1. привязка идентичности: node_id = derive(x25519) */
if (sc_derive_node_id_from_pubkey(m.x25519) != m.node_id) { if (sc_derive_node_id_from_pubkey(m.x25519) != m.node_id) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: process_request node_id/x25519 mismatch (forgery) nid=0x%016llx ch=%s", DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: process_request node_id/x25519 mismatch (forgery) nid=0x%016llx ch=%s",
@ -245,9 +253,10 @@ void chat_join_register_key(struct UTUN_INSTANCE* inst, uint64_t channel_id,
uint64_t target_node_id, uint64_t join_key) { uint64_t target_node_id, uint64_t join_key) {
if (!inst || channel_id == 0 || join_key == 0) return; if (!inst || channel_id == 0 || join_key == 0) return;
/* инвайтер всегда хранит выданный ключ локально — для верификации REQUEST_FWD */
_keys_put(channel_id, join_key, inst->node_id);
if (target_node_id == inst->node_id || target_node_id == 0) { if (target_node_id == inst->node_id || target_node_id == 0) {
/* инвайтер и есть connection-узел — храним ключ локально */
_keys_put(channel_id, join_key, inst->node_id);
return; return;
} }

13
tests/test_chat_join.c

@ -388,6 +388,18 @@ static void t_process_request(void) {
uint64_t group_id = strtoull(CH_COMP, NULL, 10); uint64_t group_id = strtoull(CH_COMP, NULL, 10);
/* 0. неизвестный join-ключ → отклонён (ключ ещё не зарегистрирован) */
TEST("process_request: unknown join_key rejected"); {
struct joiner j; make_joiner(&j, ch_x_pub, ch_ed_pub);
uint8_t buf[512]; size_t len = 0;
serialize_member(j.node_id, j.x_pub, j.ed_pub, j.join_sig, j.join_ts, buf, sizeof(buf), &len);
chat_join_process_request(inst, group_id, j.node_id, JOIN_KEY, buf, len);
if (!topo_node_sqlite_member_in_channel(db, CH_COMP, j.node_id)) OK(); else FAIL();
}
/* регистрируем ключ локально — дальше process_request его принимает */
chat_join_register_key(inst, group_id, inst->node_id, JOIN_KEY);
/* 1. валидный join_sig → мембер добавлен, signed_by=self, подпись валидна */ /* 1. валидный join_sig → мембер добавлен, signed_by=self, подпись валидна */
TEST("process_request: valid join_sig accepted"); { TEST("process_request: valid join_sig accepted"); {
struct joiner j; make_joiner(&j, ch_x_pub, ch_ed_pub); struct joiner j; make_joiner(&j, ch_x_pub, ch_ed_pub);
@ -456,6 +468,7 @@ static void t_validate_pubkey(void) {
uint64_t gid = strtoull("61616161616", NULL, 10); uint64_t gid = strtoull("61616161616", NULL, 10);
uint8_t buf[512]; size_t len = 0; uint8_t buf[512]; size_t len = 0;
serialize_member(j.node_id, j.x_pub, j.ed_pub, j.join_sig, j.join_ts, buf, sizeof(buf), &len); serialize_member(j.node_id, j.x_pub, j.ed_pub, j.join_sig, j.join_ts, buf, sizeof(buf), &len);
chat_join_register_key(inst, gid, inst->node_id, JOIN_KEY);
chat_join_process_request(inst, gid, j.node_id, JOIN_KEY, buf, len); chat_join_process_request(inst, gid, j.node_id, JOIN_KEY, buf, len);
TEST("validate_pubkey: member -> 1"); { TEST("validate_pubkey: member -> 1"); {

Loading…
Cancel
Save