From ef24af7d24bd244b9d3cce2a37cae3dceb827097 Mon Sep 17 00:00:00 2001 From: Evgeny Date: Wed, 15 Jul 2026 23:13:29 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BB=D1=8E=D1=87=D0=B8:=20node=5Fid=20?= =?UTF-8?q?=D0=B8=D0=B7=20SHA-256(privkey)=20=D1=87=D0=B5=D1=80=D0=B5?= =?UTF-8?q?=D0=B7=20=D0=B2=D0=B5=D1=81=D1=8C=20=D0=BA=D0=BE=D0=BD=D1=84?= =?UTF-8?q?=D0=B8=D0=B3;=20=D0=BF=D1=80=D0=B8=D0=BE=D1=80=D0=B8=D1=82?= =?UTF-8?q?=D0=B5=D1=82=20privkey=20=E2=80=94=20pubkey/node=5Fid=20=D0=B2?= =?UTF-8?q?=D1=81=D0=B5=D0=B3=D0=B4=D0=B0=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4?= =?UTF-8?q?=D1=8F=D1=82=D1=81=D1=8F=20=D0=B8=D0=B7=20=D0=BD=D0=B5=D0=B3?= =?UTF-8?q?=D0=BE;=20CHANNEL=5FINFO=5FRESP:=20=D0=B2=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D1=84=D0=B8=D0=BA=D0=B0=D1=86=D0=B8=D1=8F=20inviter=5Fjoin=5Fs?= =?UTF-8?q?ig=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20ETCP-=D0=BA=D0=BB=D1=8E?= =?UTF-8?q?=D1=87=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/config_updater.c | 107 +++++++++++++--------------- src/utun_instance.c | 15 +++- tools/chatgui/transport/chat_sync.c | 24 +++---- 3 files changed, 74 insertions(+), 72 deletions(-) diff --git a/src/config_updater.c b/src/config_updater.c index b37b6d9f..69a58b56 100644 --- a/src/config_updater.c +++ b/src/config_updater.c @@ -5,6 +5,7 @@ #include "secure_channel.h" #include "debug_config.h" #include "../lib/platform_compat.h" +#include "../lib/sha256.h" #include #include #include @@ -278,91 +279,80 @@ int config_ensure_keys_and_node_id(const char *filename) { global->my_public_key_hex[0] ? strlen(global->my_public_key_hex) : 0, (unsigned long long)global->my_node_id); - // Check if we need to generate anything int need_priv_key = !is_valid_priv_key(global->my_private_key_hex); + int need_pub_key = 0; + int need_node_id = 0; - int need_pub_key = !is_valid_pub_key(global->my_public_key_hex); - - int need_node_id = !is_valid_node_id(global->my_node_id); - - - DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Validation results - need_priv_key=%d, need_pub_key=%d, need_node_id=%d", - need_priv_key, need_pub_key, need_node_id); - - - if (!need_priv_key && !need_pub_key && !need_node_id) { - free_config(config); - - return 0; - } - // Generate keys if needed char new_priv_key[PRIV_HEXKEY_LEN] = {0}; char new_pub_key[PUB_HEXKEY_LEN] = {0}; uint64_t new_node_id = 0; - + uint8_t priv_bin[SC_PRIVKEY_SIZE]; + + // ── Step 1: ensure valid privkey ── if (need_priv_key) { - // Generate new keypair if private key is invalid DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Generating NEW keypair — private key was invalid/missing in %s", filename); struct SC_MYKEYS mykeys; if (sc_generate_keypair(&mykeys) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate keypair"); - free_config(config); - return -1; } bytes_to_hex(mykeys.private_key, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); - - bytes_to_hex(mykeys.public_key, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); - - } else if (need_pub_key) { - // Compute public key from existing private key - DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Computing public key from existing private key (pubkey was invalid/missing in %s)", filename); - uint8_t priv_bin[SC_PRIVKEY_SIZE]; - uint8_t pub_bin[SC_PUBKEY_SIZE]; - - // Convert private key from hex to binary + memcpy(priv_bin, mykeys.private_key, SC_PRIVKEY_SIZE); + } else { + // Convert existing privkey hex → binary for (int i = 0; i < SC_PRIVKEY_SIZE; i++) { unsigned int byte; if (sscanf(global->my_private_key_hex + i * 2, "%2x", &byte) != 1) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid private key hex format"); - free_config(config); - return -1; } priv_bin[i] = (uint8_t)byte; } - - // Compute public key - if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to compute public key from private key"); - - free_config(config); - - return -1; - } - - // Convert to hex bytes_to_hex(priv_bin, SC_PRIVKEY_SIZE, new_priv_key, sizeof(new_priv_key)); + } - bytes_to_hex(pub_bin, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); + // ── Step 2: derive pubkey from privkey (always check) ── + uint8_t pub_bin[SC_PUBKEY_SIZE]; + if (sc_compute_public_key_from_private(priv_bin, pub_bin) != SC_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to compute public key from private key"); + free_config(config); + return -1; + } + bytes_to_hex(pub_bin, SC_PUBKEY_SIZE, new_pub_key, sizeof(new_pub_key)); + if (!is_valid_pub_key(global->my_public_key_hex) || strcmp(global->my_public_key_hex, new_pub_key) != 0) { + need_pub_key = 1; + DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Pubkey mismatch (or missing), fixing: config=%s derived=%s", + global->my_public_key_hex[0] ? global->my_public_key_hex : "NULL", new_pub_key); + } + // ── Step 3: derive node_id from privkey via SHA-256 ── + { + uint8_t sha_hash[32]; + SC_SHA256_CTX ctx; + sc_sha256_init(&ctx); + sc_sha256_update(&ctx, priv_bin, SC_PRIVKEY_SIZE); + sc_sha256_final(&ctx, sha_hash); + memcpy(&new_node_id, sha_hash, 8); + new_node_id &= 0x7FFFFFFFFFFFFFFFULL; } - - if (need_node_id) { - if (random_bytes((uint8_t*)&new_node_id, sizeof(new_node_id)) != 0) { - DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Failed to generate random node_id"); - free_config(config); - return -1; - } - new_node_id &= 0x7FFFFFFFFFFFFFFF; - DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Generating NEW random node_id=%016llx (old=%016llx). WARNING: existing invites will break! file=%s", - (unsigned long long)new_node_id, (unsigned long long)global->my_node_id, filename); + if (!is_valid_node_id(global->my_node_id) || global->my_node_id != new_node_id) { + need_node_id = 1; + DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Node_id mismatch (or missing), fixing: config=%016llx derived=%016llx file=%s", + (unsigned long long)global->my_node_id, (unsigned long long)new_node_id, filename); } - + + DEBUG_DEBUG(DEBUG_CATEGORY_CONFIG, "Validation results - need_priv_key=%d, need_pub_key=%d, need_node_id=%d", + need_priv_key, need_pub_key, need_node_id); + + if (!need_priv_key && !need_pub_key && !need_node_id) { + free_config(config); + return 0; + } + free_config(config); @@ -389,7 +379,8 @@ int config_ensure_keys_and_node_id(const char *filename) { size_t work_len = file_size; int ret = 0; - + int write_keys = (need_priv_key || need_pub_key || need_node_id); + if (need_node_id) { char node_id_hex[HEXNODEID_LEN + 1]; snprintf(node_id_hex, sizeof(node_id_hex), "%016llx", (unsigned long long)new_node_id); @@ -400,14 +391,14 @@ int config_ensure_keys_and_node_id(const char *filename) { } } - if (need_priv_key && ret == 0) { + if (write_keys && ret == 0) { DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Writing my_private_key to %s", filename); if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_private_key", new_priv_key) < 0) { ret = -1; } } - if (need_pub_key && ret == 0) { + if (write_keys && ret == 0) { DEBUG_WARN(DEBUG_CATEGORY_CONFIG, "Writing my_public_key to %s", filename); if (insert_or_replace_option(&work_buf, &work_len, &buf_capacity, "my_public_key", new_pub_key) < 0) { ret = -1; diff --git a/src/utun_instance.c b/src/utun_instance.c index 54025db6..2cd4f851 100644 --- a/src/utun_instance.c +++ b/src/utun_instance.c @@ -18,6 +18,7 @@ #include "msg_transport.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" +#include "../lib/sha256.h" #include #include #include @@ -82,12 +83,24 @@ static int instance_init_common(struct UTUN_INSTANCE* instance, struct UASYNC* u // Set node_id from config instance->node_id = config->global.my_node_id; - + // Set my keys if (sc_init_local_keys(&instance->my_keys, config->global.my_public_key_hex, config->global.my_private_key_hex) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to initialize local keys"); return -1; } + + // Derive node_id from privkey if not set in config + if (!instance->node_id) { + uint8_t sha_hash[32]; + SC_SHA256_CTX ctx; + sc_sha256_init(&ctx); + sc_sha256_update(&ctx, instance->my_keys.private_key, SC_PRIVKEY_SIZE); + sc_sha256_final(&ctx, sha_hash); + memcpy(&instance->node_id, sha_hash, 8); + instance->node_id &= 0x7FFFFFFFFFFFFFFFULL; + DEBUG_INFO(DEBUG_CATEGORY_CONFIG, "node_id derived from privkey: %016llx", (unsigned long long)instance->node_id); + } if (sc_derive_ed25519_pubkey(instance->my_keys.private_key, instance->my_ed25519_pubkey) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "Failed to derive Ed25519 pubkey"); diff --git a/tools/chatgui/transport/chat_sync.c b/tools/chatgui/transport/chat_sync.c index d361ca82..f0affd03 100644 --- a/tools/chatgui/transport/chat_sync.c +++ b/tools/chatgui/transport/chat_sync.c @@ -853,25 +853,23 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer, ch_id, name, (int)is_dm, owner, x25519, NULL, ed_pub, NULL, ch_sig); chat_core_ensure_channel_ready(ch_id); - /* verify inviter's join_sig */ - { sqlite3* vdb = cs->inst->topo_groups->topo_sqlite_db; - /* read inviter's Ed25519 pubkey */ - uint8_t inv_ed[32] = {0}; - sqlite3_stmt* es = NULL; - sqlite3_prepare_v2(vdb, "SELECT ed25519_pubkey FROM nodes WHERE node_id=?", -1, &es, NULL); - if (es) { sqlite3_bind_int64(es, 1, (sqlite3_int64)peer); - if (sqlite3_step(es) == SQLITE_ROW) memcpy(inv_ed, sqlite3_column_blob(es, 0), 32); - sqlite3_finalize(es); } - /* verify */ + /* verify inviter's join_sig using ETCP-authenticated keys */ + { struct ETCP_CONN* inv_conn = cs_find_conn_for_node(cs->inst, peer); + if (!inv_conn) { + DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: CHANNEL_INFO_RESP no ETCP conn for inviter peer=%016llx", CS_ID, (unsigned long long)peer); + return; + } + const uint8_t* inv_x25519 = inv_conn->crypto_ctx.peer_public_key; + const uint8_t* inv_ed = inv_conn->peer_ed25519_pubkey; uint8_t ivmsg[256]; size_t ilen = 0; ilen += snprintf((char*)ivmsg + ilen, sizeof(ivmsg) - ilen, "%s", ch_id) + 1; memcpy(ivmsg + ilen, &peer, 8); ilen += 8; - memcpy(ivmsg + ilen, x25519, 32); ilen += 32; - { char nnm[64] = ""; _get_node_name(vdb, peer, nnm, sizeof(nnm)); + memcpy(ivmsg + ilen, inv_x25519, 32); ilen += 32; + { char nnm[64] = ""; _get_node_name(cs->inst->topo_groups->topo_sqlite_db, peer, nnm, sizeof(nnm)); size_t nl = strlen(nnm); memcpy(ivmsg + ilen, nnm, nl); ilen += nl; ivmsg[ilen++] = '\0'; if (cs_ed25519_verify(inv_ed, ivmsg, ilen, inviter_join_sig) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONNECTIVITY, "%s: CHANNEL_INFO_RESP invalid inviter_join_sig peer=%016llx x25519=%016llx inv_ed=%016llx name=%s", - CS_ID, (unsigned long long)peer, *(const uint64_t*)x25519, *(const uint64_t*)inv_ed, nnm); + CS_ID, (unsigned long long)peer, *(const uint64_t*)inv_x25519, *(const uint64_t*)inv_ed, nnm); } } }