|
|
|
|
@ -1258,36 +1258,48 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
uint16_t pc; memcpy(&pc, p, 2); p += 2; |
|
|
|
|
DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME ch=%s from=%016llx peers=%u", CS_ID, ch_id, (unsigned long long)peer, pc); |
|
|
|
|
for (uint16_t i = 0; i < pc; i++) { |
|
|
|
|
if ((size_t)(p - pl) + 8 + 32 + 32 + 64 + 8 + 1 + 1 > len) break; |
|
|
|
|
if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) break; /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */ |
|
|
|
|
uint64_t node_id; memcpy(&node_id, p, 8); p += 8; |
|
|
|
|
const uint8_t* x25519 = p; p += 32; |
|
|
|
|
const uint8_t* ed_pub = p; p += 32; |
|
|
|
|
const uint8_t* join_sig = p; p += 64; |
|
|
|
|
uint64_t join_ts; memcpy(&join_ts, p, 8); p += 8; |
|
|
|
|
uint8_t flags = *p++; |
|
|
|
|
const uint8_t* join_sig = NULL; uint64_t join_ts = 0; |
|
|
|
|
if (flags & PEERS_FLAG_HAS_JOIN) { |
|
|
|
|
if (p + 64 + 8 > pl + len) break; |
|
|
|
|
join_sig = p; p += 64; |
|
|
|
|
memcpy(&join_ts, p, 8); p += 8; |
|
|
|
|
} |
|
|
|
|
const uint8_t* update_sig = p; p += 64; |
|
|
|
|
uint64_t update_ts; memcpy(&update_ts, p, 8); p += 8; |
|
|
|
|
(void)update_sig; (void)update_ts; |
|
|
|
|
uint8_t nl = *p++; |
|
|
|
|
char peer_name[256] = ""; |
|
|
|
|
if (nl && p + nl <= pl + len) { memcpy(peer_name, p, nl); peer_name[nl] = '\0'; p += nl; } |
|
|
|
|
uint8_t ac = *p++; |
|
|
|
|
|
|
|
|
|
/* verify join_sig — all fields present in WELCOME wire */ |
|
|
|
|
uint8_t vmsg[256]; size_t vlen = 0; |
|
|
|
|
vlen += snprintf((char*)vmsg + vlen, sizeof(vmsg) - vlen, "%s", ch_id) + 1; |
|
|
|
|
memcpy(vmsg + vlen, &node_id, 8); vlen += 8; |
|
|
|
|
memcpy(vmsg + vlen, x25519, 32); vlen += 32; |
|
|
|
|
{ const char* nm = peer_name[0] ? peer_name : ""; |
|
|
|
|
size_t nls = strlen(nm); memcpy(vmsg + vlen, nm, nls); vlen += nls; vmsg[vlen++] = '\0'; } |
|
|
|
|
memcpy(vmsg + vlen, &join_ts, 8); vlen += 8; |
|
|
|
|
{ EVP_PKEY* pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, ed_pub, 32); |
|
|
|
|
if (pkey) { |
|
|
|
|
EVP_MD_CTX* ver = EVP_MD_CTX_new(); |
|
|
|
|
if (ver) { |
|
|
|
|
if (EVP_DigestVerifyInit(ver, NULL, NULL, NULL, pkey) != 1 |
|
|
|
|
|| EVP_DigestVerify(ver, join_sig, 64, vmsg, vlen) != 1) |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME invalid join_sig node=0x%016llx", CS_ID, (unsigned long long)node_id); |
|
|
|
|
EVP_MD_CTX_free(ver); |
|
|
|
|
/* verify join_sig if present */ |
|
|
|
|
if (join_sig) { |
|
|
|
|
uint8_t vmsg[256]; size_t vlen = 0; |
|
|
|
|
vlen += snprintf((char*)vmsg + vlen, sizeof(vmsg) - vlen, "%s", ch_id) + 1; |
|
|
|
|
memcpy(vmsg + vlen, &node_id, 8); vlen += 8; |
|
|
|
|
memcpy(vmsg + vlen, x25519, 32); vlen += 32; |
|
|
|
|
{ const char* nm = peer_name[0] ? peer_name : ""; |
|
|
|
|
size_t nls = strlen(nm); memcpy(vmsg + vlen, nm, nls); vlen += nls; vmsg[vlen++] = '\0'; } |
|
|
|
|
memcpy(vmsg + vlen, &join_ts, 8); vlen += 8; |
|
|
|
|
EVP_PKEY* pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, ed_pub, 32); |
|
|
|
|
if (pkey) { |
|
|
|
|
EVP_MD_CTX* ver = EVP_MD_CTX_new(); |
|
|
|
|
if (ver) { |
|
|
|
|
if (EVP_DigestVerifyInit(ver, NULL, NULL, NULL, pkey) != 1 |
|
|
|
|
|| EVP_DigestVerify(ver, join_sig, 64, vmsg, vlen) != 1) { |
|
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME invalid join_sig node=0x%016llx — skipping", CS_ID, (unsigned long long)node_id); |
|
|
|
|
EVP_MD_CTX_free(ver); EVP_PKEY_free(pkey); |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
EVP_MD_CTX_free(ver); |
|
|
|
|
} |
|
|
|
|
EVP_PKEY_free(pkey); |
|
|
|
|
} |
|
|
|
|
EVP_PKEY_free(pkey); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int rc = topo_node_sqlite_member_put(db, ch_id, node_id, join_sig, join_ts, NULL, 0, x25519, ed_pub, peer_name, NULL); |
|
|
|
|
@ -1323,8 +1335,8 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME INSERT v6 node=0x%016llx sock=%d port=%d", |
|
|
|
|
CS_ID, (unsigned long long)node_id, sid, port); |
|
|
|
|
} |
|
|
|
|
member_sync_cancel(g_cs->inst, peer, ch_id); |
|
|
|
|
member_sync_set_online(g_cs->inst, peer, 0); |
|
|
|
|
member_sync_cancel(g_cs->inst, node_id, ch_id); |
|
|
|
|
member_sync_set_online(g_cs->inst, node_id, 0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cs_refresh_channels(cs); |
|
|
|
|
|