Browse Source

Ed25519 self-signature in NODEINFO + fix sync sequence and zero-key bug

Add x25519_self_sig[64] to TOPOMSG_NODE/TOPO_NODE:
- topo_node.h: add field to both structs (wire format + memory)
- topo_node.c: compute Ed25519_sign(ed25519_privkey, x25519_pubkey) for own node
- topo_node.c: serialize/deserialize x25519_self_sig
- topo_group.c: verify Ed25519 self-sig on NODEINFO receive, reject forgery

Fix Ed25519 pubkey zero-key bug:
- topo_node_sqlite.c: get_ed25519_pubkey rejects all-zero key (MUST be non-zero)

Delay db_sync until Ed25519 key is available:
- db_sync.c: db_sync_on_conn_up checks db_get_ed25519_pubkey before starting
- db_sync.c: db_sync_peer_check_cb also checks Ed25519 key availability
- This prevents sync starting before NODEINFO with verified Ed25519 arrives
topo_upd
Evgeny 2 months ago
parent
commit
85269d1da3
  1. 16
      src/db_sync.c
  2. 13
      src/routing_layer/topo_group.c
  3. 3
      src/routing_layer/topo_node.c
  4. 4
      src/routing_layer/topo_node.h
  5. 2
      src/routing_layer/topo_node_sqlite.c

16
src/db_sync.c

@ -1165,7 +1165,7 @@ static void db_sync_on_conn_up(struct ETCP_CONN* conn, void* arg)
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "peer=%016llx init=%d links=%d", (unsigned long long)pid, conn->initialized, conn->links_up);
db->last_connected_tb = get_time_tb();
int synced = 0, skipped_state = 0, skipped_not_ready = 0;
int synced = 0, skipped_state = 0, skipped_not_ready = 0, skipped_no_edkey = 0;
for (int i = 0; i < db->instance_count; i++) {
struct DB_SYNC_INSTANCE* si = &db->instances[i];
if (!si->enabled) continue;
@ -1173,14 +1173,15 @@ static void db_sync_on_conn_up(struct ETCP_CONN* conn, void* arg)
if (!p) continue;
if (p->sync_state != 0) { skipped_state++; continue; }
if (!conn->initialized || !conn->links_up) { skipped_not_ready++; continue; }
{ uint8_t ek[32]; if (db_get_ed25519_pubkey(db, pid, ek) != 0) { skipped_no_edkey++; continue; } }
p->sync_state = 1; p->sync_retry_count = 0;
db_sync_initiate_sync(si, pid);
synced++;
}
DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC,
"conn_up peer=%016llx init=%d links=%d instances=%d synced=%d skipped_state=%d skipped_not_ready=%d tbls=[%s]",
"conn_up peer=%016llx init=%d links=%d instances=%d synced=%d skipped_state=%d skipped_not_ready=%d skipped_no_edkey=%d tbls=[%s]",
(unsigned long long)pid, conn->initialized, conn->links_up,
db->instance_count, synced, skipped_state, skipped_not_ready,
db->instance_count, synced, skipped_state, skipped_not_ready, skipped_no_edkey,
(synced > 0 && db->instance_count > 0) ? db->instances[0].table_name : "none");
}
@ -1308,7 +1309,14 @@ static void db_sync_peer_check_cb(void* arg)
best = &si->peers[j];
}
}
if (best) { best->sync_state = 1; db_sync_initiate_sync(si, best->node_id); total_synced++; }
if (best) {
uint8_t ek[32];
if (db_get_ed25519_pubkey(db, best->node_id, ek) == 0) {
best->sync_state = 1; db_sync_initiate_sync(si, best->node_id); total_synced++;
} else {
best = NULL; total_skipped++;
}
}
else { total_skipped++; }
}

13
src/routing_layer/topo_group.c

@ -602,6 +602,19 @@ int topo_group_process_nodeinfo(struct TOPO_GROUP* group, struct ETCP_CONN* from
return -1;
}
/* verify Ed25519 self-signature: Ed25519_pubkey must sign X25519_pubkey */
{
uint64_t ekchk; memcpy(&ekchk, new_ni->ed25519_public_key, 8);
if (ekchk != 0 && sc_ed25519_verify(new_ni->ed25519_public_key, new_ni->public_key, SC_PUBKEY_SIZE, new_ni->x25519_self_sig) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "NODEINFO x25519_self_sig VERIFY FAIL node=%016llx ed_pubkey=%016llx... from=%s — rejecting as forgery",
(unsigned long long)node_id, ekchk, from->log_name);
topo_node_free_raw(group->instance->topo_groups, new_ni);
u_free(new_subnets); u_free(new_tranzit); u_free(new_hop_list);
if (nodeinfo1) { queue_remove_data(group->nodes, &nodeinfo1->ll); queue_free(paths); queue_entry_free(&nodeinfo1->ll); }
return -1;
}
}
if (nodeinfo1) {
nodeinfo1->node = topo_node_registry_acquire(group->instance->topo_groups, new_ni);
nodeinfo1->hash_node_id = nodeinfo1->node ? nodeinfo1->node->node_id : 0;

3
src/routing_layer/topo_node.c

@ -151,6 +151,7 @@ int topo_node_serialize(struct TOPO_GROUP* group, struct TOPO_NODEQ* nq, uint8_t
msg.ver = ni->ver;
memcpy(msg.public_key, ni->public_key, SC_PUBKEY_SIZE);
memcpy(msg.ed25519_public_key, ni->ed25519_public_key, SC_PUBKEY_SIZE);
memcpy(msg.x25519_self_sig, ni->x25519_self_sig, 64);
msg.node_name_len = ni->node_name ? (uint8_t)strlen(ni->node_name) : 0;
msg.local_v4_sockets = topo_list_count((struct _topo_head*)ni->v4_sock_meta);
msg.local_v4_addrs = topo_list_count((struct _topo_head*)ni->v4_addrs);
@ -230,6 +231,7 @@ int topo_node_deserialize(struct TOPO_GROUP* group, const uint8_t* data, size_t
ni->ver = msg->ver;
memcpy(ni->public_key, msg->public_key, SC_PUBKEY_SIZE);
memcpy(ni->ed25519_public_key, msg->ed25519_public_key, SC_PUBKEY_SIZE);
memcpy(ni->x25519_self_sig, msg->x25519_self_sig, 64);
const uint8_t* dp = data + TOPOMSG_NODE_HDR_SIZE;
@ -664,6 +666,7 @@ int topo_group_update_my_nodeinfo(struct UTUN_INSTANCE* instance, struct TOPO_GR
ni->ver = (old_ver % 255) + 1;
memcpy(ni->public_key, instance->my_keys.public_key, SC_PUBKEY_SIZE);
memcpy(ni->ed25519_public_key, group->ed25519_public_key, SC_PUBKEY_SIZE);
sc_ed25519_sign(instance->my_ed25519_privkey, instance->my_keys.public_key, SC_PUBKEY_SIZE, ni->x25519_self_sig);
if (name_len) { ni->node_name = u_malloc(name_len + 1); if (ni->node_name) { memcpy(ni->node_name, instance->name, name_len); ni->node_name[name_len] = 0; } }
lq->node = topo_node_registry_acquire(instance->topo_groups, ni);

4
src/routing_layer/topo_node.h

@ -165,6 +165,7 @@ struct TOPOMSG_NODE {
uint8_t ver;
uint8_t public_key[SC_PUBKEY_SIZE];
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
uint8_t x25519_self_sig[64]; // Ed25519_sign(ed25519_privkey, x25519_pubkey, 32)
uint8_t node_name_len;
uint8_t local_v4_sockets;
uint8_t local_v4_addrs;
@ -206,7 +207,8 @@ struct TOPO_NODE {
uint8_t ver;
uint8_t public_key[SC_PUBKEY_SIZE];
uint8_t ed25519_public_key[SC_PUBKEY_SIZE];
char* node_name; // отдельный u_strdup/u_free
uint8_t x25519_self_sig[64]; // Ed25519_sign(ed25519_privkey, x25519_pubkey, 32)
char* node_name; // отдельный u_strdup/u_free
struct TOPO_SOCKMETA4* v4_sock_meta; // linked list head
struct TOPO_ADDR4* v4_addrs; // linked list head
struct TOPO_SOCKMETA6* v6_sock_meta;

2
src/routing_layer/topo_node_sqlite.c

@ -555,7 +555,7 @@ int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t p
if (sqlite3_step(stmt) == SQLITE_ROW) {
const void* b = sqlite3_column_blob(stmt, 0);
int bytes = sqlite3_column_bytes(stmt, 0);
if (b && bytes >= 32) { memcpy(pubkey_out, b, 32); rc = 0; }
if (b && bytes >= 32) { uint64_t chk; memcpy(&chk, b, 8); if (chk != 0) { memcpy(pubkey_out, b, 32); rc = 0; } }
}
sqlite3_finalize(stmt);
return rc;

Loading…
Cancel
Save