@ -10,6 +10,7 @@
# include "../../../src/conn_mgr.h"
# include "../../../src/conn_mgr.h"
# include "../../../src/topo_group.h"
# include "../../../src/topo_group.h"
# include "../../../src/secure_channel.h"
# include "../../../src/secure_channel.h"
# include "../../../src/ntp_time.h"
# include "../../../lib/u_async.h"
# include "../../../lib/u_async.h"
# include "../../../lib/ll_queue.h"
# include "../../../lib/ll_queue.h"
# include "../../../lib/debug_config.h"
# include "../../../lib/debug_config.h"
@ -791,17 +792,34 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
if ( memcmp ( cs - > inst - > my_keys . public_key , x25519 , 32 ) ! = 0 )
if ( memcmp ( cs - > inst - > my_keys . public_key , x25519 , 32 ) ! = 0 )
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP pubkey MISMATCH: my=%016llx ch=%016llx — channel was created with DIFFERENT keys! " ,
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP pubkey MISMATCH: my=%016llx ch=%016llx — channel was created with DIFFERENT keys! " ,
CS_ID , * ( const uint64_t * ) cs - > inst - > my_keys . public_key , * ( const uint64_t * ) x25519 ) ;
CS_ID , * ( const uint64_t * ) cs - > inst - > my_keys . public_key , * ( const uint64_t * ) x25519 ) ;
uint8_t my_join_sig [ 64 ] = { 0 } ;
/* load or create join_sig */
uint8_t my_join_sig [ 64 ] = { 0 } ; uint64_t my_join_ts = 0 ;
{
sqlite3 * vdb = cs - > inst - > topo_groups - > topo_sqlite_db ;
if ( topo_node_sqlite_member_get_join ( vdb , ch_id , myid , my_join_sig , & my_join_ts ) ! = 0 ) {
uint8_t join_msg [ 256 ] ; size_t mlen = 0 ;
uint8_t join_msg [ 256 ] ; size_t mlen = 0 ;
mlen + = snprintf ( ( char * ) join_msg + mlen , sizeof ( join_msg ) - mlen , " %s " , ch_id ) + 1 ;
mlen + = snprintf ( ( char * ) join_msg + mlen , sizeof ( join_msg ) - mlen , " %s " , ch_id ) + 1 ;
memcpy ( join_msg + mlen , & myid , 8 ) ; mlen + = 8 ;
memcpy ( join_msg + mlen , & myid , 8 ) ; mlen + = 8 ;
memcpy ( join_msg + mlen , cs - > inst - > my_keys . public_key , 32 ) ; mlen + = 32 ;
memcpy ( join_msg + mlen , cs - > inst - > my_keys . public_key , 32 ) ; mlen + = 32 ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
my_join_ts = ( uint64_t ) ntp_time_get_seconds ( cs - > inst ) ;
size_t nl = strlen ( nm ) ; memcpy ( join_msg + mlen , nm , nl ) ; mlen + = nl ; join_msg [ mlen + + ] = ' \0 ' ; }
memcpy ( join_msg + mlen , & my_join_ts , 8 ) ; mlen + = 8 ;
cs_ed25519_sign ( cs - > inst - > my_ed25519_privkey , join_msg , mlen , my_join_sig ) ;
cs_ed25519_sign ( cs - > inst - > my_ed25519_privkey , join_msg , mlen , my_join_sig ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_DEBUG , " %s: CHANNEL_INFO_RESP signed my_join_sig: myid=%016llx my_pub=%016llx ch_pub=%016llx name=%s " ,
DEBUG_DEBUG ( DEBUG_CATEGORY_DEBUG , " %s: CHANNEL_INFO_RESP created NEW join_sig: myid=%016llx ts=%llu " ,
CS_ID , ( unsigned long long ) myid , * ( const uint64_t * ) cs - > inst - > my_keys . public_key ,
CS_ID , ( unsigned long long ) myid , ( unsigned long long ) my_join_ts ) ;
* ( const uint64_t * ) x25519 , cs - > inst - > name ) ;
}
}
/* generate update_sig */
uint8_t my_update_sig [ 64 ] = { 0 } ; uint64_t my_update_ts ;
{
uint8_t umsg [ 256 ] ; size_t ulen = 0 ;
ulen + = snprintf ( ( char * ) umsg + ulen , sizeof ( umsg ) - ulen , " %s " , ch_id ) + 1 ;
memcpy ( umsg + ulen , & myid , 8 ) ; ulen + = 8 ;
memcpy ( umsg + ulen , cs - > inst - > my_keys . public_key , 32 ) ; ulen + = 32 ;
my_update_ts = ( uint64_t ) ntp_time_get_seconds ( cs - > inst ) ;
memcpy ( umsg + ulen , & my_update_ts , 8 ) ; ulen + = 8 ;
memcpy ( umsg + ulen , my_join_sig , 64 ) ; ulen + = 64 ;
cs_ed25519_sign ( cs - > inst - > my_ed25519_privkey , umsg , ulen , my_update_sig ) ;
}
uint8_t buf [ 1024 ] ; size_t boff = 0 ;
uint8_t buf [ 1024 ] ; size_t boff = 0 ;
buf [ boff + + ] = CS_MSG_CHANNEL_INFO_RESP ;
buf [ boff + + ] = CS_MSG_CHANNEL_INFO_RESP ;
@ -812,7 +830,14 @@ static void cs_handle_channel_info_req(struct chat_sync* cs, uint64_t peer,
memcpy ( buf + boff , x25519 , 32 ) ; boff + = 32 ;
memcpy ( buf + boff , x25519 , 32 ) ; boff + = 32 ;
memcpy ( buf + boff , ed_pub , 32 ) ; boff + = 32 ;
memcpy ( buf + boff , ed_pub , 32 ) ; boff + = 32 ;
memcpy ( buf + boff , ch_sig , 64 ) ; boff + = 64 ;
memcpy ( buf + boff , ch_sig , 64 ) ; boff + = 64 ;
uint8_t inv_flags = ( my_join_sig [ 0 ] | | my_join_ts ) ? PEERS_FLAG_HAS_JOIN : 0 ;
buf [ boff + + ] = inv_flags ;
if ( inv_flags & PEERS_FLAG_HAS_JOIN ) {
memcpy ( buf + boff , my_join_sig , 64 ) ; boff + = 64 ;
memcpy ( buf + boff , my_join_sig , 64 ) ; boff + = 64 ;
memcpy ( buf + boff , & my_join_ts , 8 ) ; boff + = 8 ;
}
memcpy ( buf + boff , my_update_sig , 64 ) ; boff + = 64 ;
memcpy ( buf + boff , & my_update_ts , 8 ) ; boff + = 8 ;
{ const char * iname = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
{ const char * iname = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
uint8_t il = ( uint8_t ) strlen ( iname ) ;
uint8_t il = ( uint8_t ) strlen ( iname ) ;
buf [ boff + + ] = il ; memcpy ( buf + boff , iname , il ) ; boff + = il ; }
buf [ boff + + ] = il ; memcpy ( buf + boff , iname , il ) ; boff + = il ; }
@ -826,7 +851,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
if ( cs - > info_req_timer ) { uasync_cancel_timeout ( cs - > inst - > ua , cs - > info_req_timer ) ; cs - > info_req_timer = NULL ; }
if ( cs - > info_req_timer ) { uasync_cancel_timeout ( cs - > inst - > ua , cs - > info_req_timer ) ; cs - > info_req_timer = NULL ; }
if ( len < 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
if ( len < 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
uint8_t nl = pl [ 0 ] ;
uint8_t nl = pl [ 0 ] ;
if ( 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 + 1 > len ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP truncated len=%zu min=%d " , CS_ID , len , 1 + nl + 8 + 1 + 32 + 32 + 64 + 64 + 1 ) ; return ; }
if ( 1 + nl + 8 + 1 + 32 + 32 + 64 + 1 + 64 + 8 + 1 > len ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP truncated len=%zu " , CS_ID , len ) ; return ; }
const uint8_t * p = pl + 1 ;
const uint8_t * p = pl + 1 ;
char name [ 128 ] ; memcpy ( name , p , nl ) ; name [ nl ] = ' \0 ' ; p + = nl ;
char name [ 128 ] ; memcpy ( name , p , nl ) ; name [ nl ] = ' \0 ' ; p + = nl ;
uint64_t owner ; memcpy ( & owner , p , 8 ) ; p + = 8 ;
uint64_t owner ; memcpy ( & owner , p , 8 ) ; p + = 8 ;
@ -834,7 +859,12 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ch_sig = p ; p + = 64 ;
const uint8_t * ch_sig = p ; p + = 64 ;
const uint8_t * inviter_join_sig = p ; p + = 64 ;
uint8_t inv_flags = * p + + ;
const uint8_t * inviter_join_sig = NULL ; uint64_t inviter_join_ts = 0 ;
if ( inv_flags & PEERS_FLAG_HAS_JOIN ) {
if ( p + 72 > pl + len ) return ; inviter_join_sig = p ; p + = 64 ; memcpy ( & inviter_join_ts , p , 8 ) ; p + = 8 ; }
const uint8_t * inviter_update_sig = p ; p + = 64 ; uint64_t inviter_update_ts ;
memcpy ( & inviter_update_ts , p , 8 ) ; p + = 8 ;
uint8_t inv_name_len = * p + + ;
uint8_t inv_name_len = * p + + ;
char inv_name [ 128 ] = " " ;
char inv_name [ 128 ] = " " ;
if ( p + inv_name_len < = pl + len ) { memcpy ( inv_name , p , inv_name_len ) ; inv_name [ inv_name_len ] = ' \0 ' ; }
if ( p + inv_name_len < = pl + len ) { memcpy ( inv_name , p , inv_name_len ) ; inv_name [ inv_name_len ] = ' \0 ' ; }
@ -872,12 +902,14 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
ilen + = snprintf ( ( char * ) ivmsg + ilen , sizeof ( ivmsg ) - ilen , " %s " , ch_id ) + 1 ;
ilen + = snprintf ( ( char * ) ivmsg + ilen , sizeof ( ivmsg ) - ilen , " %s " , ch_id ) + 1 ;
memcpy ( ivmsg + ilen , & peer , 8 ) ; ilen + = 8 ;
memcpy ( ivmsg + ilen , & peer , 8 ) ; ilen + = 8 ;
memcpy ( ivmsg + ilen , inv_x25519 , 32 ) ; ilen + = 32 ;
memcpy ( ivmsg + ilen , inv_x25519 , 32 ) ; ilen + = 32 ;
memcpy ( ivmsg + ilen , & inviter_update_ts , 8 ) ; ilen + = 8 ;
{ const char * nm = inv_name [ 0 ] ? inv_name : " " ;
{ const char * nm = inv_name [ 0 ] ? inv_name : " " ;
size_t nl2 = strlen ( nm ) ; memcpy ( ivmsg + ilen , nm , nl2 ) ; ilen + = nl2 ; ivmsg [ ilen + + ] = ' \0 ' ;
size_t nl2 = strlen ( nm ) ; ( void ) nl2 ; }
if ( cs_ed25519_verify ( inv_ed , ivmsg , ilen , inviter_join_sig ) ! = 0 ) {
if ( inviter_join_sig ) memcpy ( ivmsg + ilen , inviter_join_sig , 64 ) ; else memset ( ivmsg + ilen , 0 , 64 ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP invalid inviter_join_sig peer=%016llx x25519=%016llx inv_ed=%016llx inv_name=%s " ,
ilen + = 64 ;
CS_ID , ( unsigned long long ) peer , * ( const uint64_t * ) inv_x25519 , * ( const uint64_t * ) inv_ed , nm ) ;
if ( cs_ed25519_verify ( inv_ed , ivmsg , ilen , inviter_update_sig ) ! = 0 ) {
}
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_INFO_RESP invalid inviter_update_sig peer=%016llx ts=%llu " ,
CS_ID , ( unsigned long long ) peer , ( unsigned long long ) inviter_update_ts ) ;
}
}
/* save inviter node_info to local DB */
/* save inviter node_info to local DB */
sqlite3 * vdb = cs - > inst - > topo_groups - > topo_sqlite_db ;
sqlite3 * vdb = cs - > inst - > topo_groups - > topo_sqlite_db ;
@ -911,17 +943,15 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
lk = lk - > next ;
lk = lk - > next ;
}
}
}
}
topo_node_sqlite_member_put ( vdb , ch_id , peer , inviter_join_sig , inviter_join_ts , inviter_update_sig , inviter_update_ts , inv_x25519 , inv_ed , inv_name , inviter_join_sig ) ;
topo_node_sqlite_node_update_verified ( vdb , peer , inv_name , inv_x25519 , inv_ed , inviter_join_ts ) ;
}
}
/* save inviter as node and member */
topo_node_sqlite_member_put ( cs - > inst - > topo_groups - > topo_sqlite_db , ch_id , peer ,
inviter_join_sig , inviter_join_sig ) ;
/* generate our own join_sig */
/* generate our own join_sig */
uint64_t myid = cs - > inst - > node_id ;
uint64_t myid = cs - > inst - > node_id ;
uint8_t my_x25519 [ 32 ] ;
uint8_t my_x25519 [ 32 ] ;
memcpy ( my_x25519 , cs - > inst - > my_keys . public_key , 32 ) ;
memcpy ( my_x25519 , cs - > inst - > my_keys . public_key , 32 ) ;
uint8_t join_sig [ 64 ] ;
uint8_t join_sig [ 64 ] ; uint64_t join_ts ;
{
{
uint8_t msg [ 256 ] ; size_t mlen = 0 ;
uint8_t msg [ 256 ] ; size_t mlen = 0 ;
mlen + = snprintf ( ( char * ) msg + mlen , sizeof ( msg ) - mlen , " %s " , ch_id ) + 1 ;
mlen + = snprintf ( ( char * ) msg + mlen , sizeof ( msg ) - mlen , " %s " , ch_id ) + 1 ;
@ -929,6 +959,8 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
memcpy ( msg + mlen , my_x25519 , 32 ) ; mlen + = 32 ;
memcpy ( msg + mlen , my_x25519 , 32 ) ; mlen + = 32 ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
size_t nl = strlen ( nm ) ; memcpy ( msg + mlen , nm , nl ) ; mlen + = nl ; msg [ mlen + + ] = ' \0 ' ; }
size_t nl = strlen ( nm ) ; memcpy ( msg + mlen , nm , nl ) ; mlen + = nl ; msg [ mlen + + ] = ' \0 ' ; }
join_ts = ( uint64_t ) ntp_time_get_seconds ( cs - > inst ) ;
memcpy ( msg + mlen , & join_ts , 8 ) ; mlen + = 8 ;
cs_ed25519_sign ( cs - > inst - > my_ed25519_privkey , msg , mlen , join_sig ) ;
cs_ed25519_sign ( cs - > inst - > my_ed25519_privkey , msg , mlen , join_sig ) ;
}
}
@ -939,6 +971,7 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
memcpy ( jbuf + joff , my_x25519 , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , my_x25519 , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , cs - > inst - > my_ed25519_pubkey , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , cs - > inst - > my_ed25519_pubkey , 32 ) ; joff + = 32 ;
memcpy ( jbuf + joff , join_sig , 64 ) ; joff + = 64 ;
memcpy ( jbuf + joff , join_sig , 64 ) ; joff + = 64 ;
memcpy ( jbuf + joff , & join_ts , 8 ) ; joff + = 8 ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
{ const char * nm = cs - > inst - > name [ 0 ] ? cs - > inst - > name : " " ;
uint8_t nml = ( uint8_t ) strlen ( nm ) ;
uint8_t nml = ( uint8_t ) strlen ( nm ) ;
jbuf [ joff + + ] = nml ; memcpy ( jbuf + joff , nm , nml ) ; joff + = nml ; }
jbuf [ joff + + ] = nml ; memcpy ( jbuf + joff , nm , nml ) ; joff + = nml ; }
@ -984,12 +1017,13 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
static void cs_handle_channel_join ( struct chat_sync * cs , uint64_t peer ,
static void cs_handle_channel_join ( struct chat_sync * cs , uint64_t peer ,
const char * ch_id , const uint8_t * pl , size_t len ) {
const char * ch_id , const uint8_t * pl , size_t len ) {
if ( len < 8 + 32 + 32 + 64 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_JOIN too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
if ( len < 8 + 32 + 32 + 64 + 8 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: CHANNEL_JOIN too short len=%zu peer=%016llx " , CS_ID , len , ( unsigned long long ) peer ) ; return ; }
const uint8_t * p = pl ;
const uint8_t * p = pl ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * join_sig = p ; p + = 64 ;
const uint8_t * join_sig = p ; p + = 64 ;
uint64_t join_ts ; memcpy ( & join_ts , p , 8 ) ; p + = 8 ;
uint8_t name_len = * p + + ;
uint8_t name_len = * p + + ;
char joiner_name [ 128 ] = " " ;
char joiner_name [ 128 ] = " " ;
if ( p + name_len < = pl + len ) { memcpy ( joiner_name , p , name_len ) ; joiner_name [ name_len ] = ' \0 ' ; p + = name_len ; }
if ( p + name_len < = pl + len ) { memcpy ( joiner_name , p , name_len ) ; joiner_name [ name_len ] = ' \0 ' ; p + = name_len ; }
@ -1002,15 +1036,17 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
{ const char * nm = joiner_name [ 0 ] ? joiner_name : " " ;
{ const char * nm = joiner_name [ 0 ] ? joiner_name : " " ;
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
memcpy ( vmsg + vlen , & join_ts , 8 ) ; vlen + = 8 ;
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx name=%s) " , CS_ID ,
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: JOIN invalid sig node=0x%016llx ch=%s — signed(node=%016llx x25519=%016llx ed=%016llx name=%s ts=%llu ) " , CS_ID ,
( unsigned long long ) node_id , ch_id ,
( unsigned long long ) node_id , ch_id ,
( unsigned long long ) node_id , * ( const uint64_t * ) x25519 , * ( const uint64_t * ) ed_pub , joiner_name ) ;
( unsigned long long ) node_id , * ( const uint64_t * ) x25519 , * ( const uint64_t * ) ed_pub , joiner_name , ( unsigned long long ) join_ts ) ;
return ;
return ;
}
}
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , NULL ) ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , join_ts , NULL , 0 , x25519 , ed_pub , joiner_name , NULL ) ;
topo_node_sqlite_node_update_verified ( db , node_id , joiner_name , x25519 , ed_pub , join_ts ) ;
/* save joiner node_info to local DB */
/* save joiner node_info to local DB */
if ( db & & joiner_name [ 0 ] ) {
if ( db & & joiner_name [ 0 ] ) {
sqlite3_stmt * ns = NULL ;
sqlite3_stmt * ns = NULL ;
@ -1065,12 +1101,13 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
memcpy ( ubuf + uoff , x25519 , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , x25519 , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , ed_pub , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , ed_pub , 32 ) ; uoff + = 32 ;
memcpy ( ubuf + uoff , join_sig , 64 ) ; uoff + = 64 ;
memcpy ( ubuf + uoff , join_sig , 64 ) ; uoff + = 64 ;
memcpy ( ubuf + uoff , & join_ts , 8 ) ; uoff + = 8 ;
ubuf [ uoff + + ] = name_len ;
ubuf [ uoff + + ] = name_len ;
memcpy ( ubuf + uoff , joiner_name , name_len ) ; uoff + = name_len ;
memcpy ( ubuf + uoff , joiner_name , name_len ) ; uoff + = name_len ;
ubuf [ uoff + + ] = addr_cnt ;
ubuf [ uoff + + ] = addr_cnt ;
size_t addr_data_sz = ( size_t ) ( p - ( pl + 8 + 32 + 32 + 64 + 1 + name_len + 1 ) ) ;
size_t addr_data_sz = ( size_t ) ( p - ( pl + 8 + 32 + 32 + 64 + 8 + 1 + name_len + 1 ) ) ;
if ( uoff + addr_data_sz < = sizeof ( ubuf ) ) {
if ( uoff + addr_data_sz < = sizeof ( ubuf ) ) {
memcpy ( ubuf + uoff , pl + 8 + 32 + 32 + 64 + 1 + name_len + 1 , addr_data_sz ) ;
memcpy ( ubuf + uoff , pl + 8 + 32 + 32 + 64 + 8 + 1 + name_len + 1 , addr_data_sz ) ;
uoff + = addr_data_sz ;
uoff + = addr_data_sz ;
}
}
cs_propagate ( cs , ch_id , peer , ubuf , uoff ) ;
cs_propagate ( cs , ch_id , peer , ubuf , uoff ) ;
@ -1107,14 +1144,40 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
const uint8_t * p = pl ;
const uint8_t * p = pl ;
uint16_t pc ; memcpy ( & pc , p , 2 ) ; p + = 2 ;
uint16_t pc ; memcpy ( & pc , p , 2 ) ; p + = 2 ;
for ( uint16_t i = 0 ; i < pc ; i + + ) {
for ( uint16_t i = 0 ; i < pc ; i + + ) {
if ( ( size_t ) ( p - pl ) + 8 + 32 + 32 + 64 + 1 > len ) break ;
if ( ( size_t ) ( p - pl ) + 8 + 32 + 32 + 64 + 8 + 1 + 1 > len ) break ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * join_sig = p ; p + = 64 ;
const uint8_t * join_sig = p ; p + = 64 ;
uint64_t join_ts ; memcpy ( & join_ts , p , 8 ) ; p + = 8 ;
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 + + ;
uint8_t ac = * p + + ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , NULL ) ;
/* 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_CONNECTIVITY , " %s: WELCOME invalid join_sig node=0x%016llx " , CS_ID , ( unsigned long long ) node_id ) ;
EVP_MD_CTX_free ( ver ) ;
}
EVP_PKEY_free ( pkey ) ;
}
}
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , join_ts , NULL , 0 , x25519 , ed_pub , peer_name , NULL ) ;
topo_node_sqlite_node_update_verified ( db , node_id , peer_name , x25519 , ed_pub , join_ts ) ;
for ( uint8_t j = 0 ; j < ac ; j + + ) {
for ( uint8_t j = 0 ; j < ac ; j + + ) {
if ( p + 1 > pl + len ) break ;
if ( p + 1 > pl + len ) break ;
@ -1157,12 +1220,13 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
static void cs_handle_peer_upsert ( struct chat_sync * cs , uint64_t peer ,
static void cs_handle_peer_upsert ( struct chat_sync * cs , uint64_t peer ,
const char * ch_id , const uint8_t * pl , size_t len ) {
const char * ch_id , const uint8_t * pl , size_t len ) {
if ( len < 8 + 32 + 32 + 64 + 1 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT too short len=%zu " , CS_ID , len ) ; return ; }
if ( len < 8 + 32 + 32 + 64 + 8 + 1 + 1 + 1 ) { DEBUG_WARN ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT too short len=%zu " , CS_ID , len ) ; return ; }
const uint8_t * p = pl ;
const uint8_t * p = pl ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
uint64_t node_id ; memcpy ( & node_id , p , 8 ) ; p + = 8 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * x25519 = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * ed_pub = p ; p + = 32 ;
const uint8_t * join_sig = p ; p + = 64 ;
const uint8_t * join_sig = p ; p + = 64 ;
uint64_t join_ts ; memcpy ( & join_ts , p , 8 ) ; p + = 8 ;
uint8_t name_len = * p + + ;
uint8_t name_len = * p + + ;
char peer_name [ 128 ] = " " ;
char peer_name [ 128 ] = " " ;
if ( p + name_len < = pl + len ) { memcpy ( peer_name , p , name_len ) ; peer_name [ name_len ] = ' \0 ' ; p + = name_len ; }
if ( p + name_len < = pl + len ) { memcpy ( peer_name , p , name_len ) ; peer_name [ name_len ] = ' \0 ' ; p + = name_len ; }
@ -1175,6 +1239,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
memcpy ( vmsg + vlen , x25519 , 32 ) ; vlen + = 32 ;
{ const char * nm = peer_name [ 0 ] ? peer_name : " " ;
{ const char * nm = peer_name [ 0 ] ? peer_name : " " ;
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
size_t nl = strlen ( nm ) ; memcpy ( vmsg + vlen , nm , nl ) ; vlen + = nl ; vmsg [ vlen + + ] = ' \0 ' ; }
memcpy ( vmsg + vlen , & join_ts , 8 ) ; vlen + = 8 ;
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
if ( cs_ed25519_verify ( ed_pub , vmsg , vlen , join_sig ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT invalid sig node=0x%016llx " , CS_ID ,
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTIVITY , " %s: PEER_UPSERT invalid sig node=0x%016llx " , CS_ID ,
( unsigned long long ) node_id ) ;
( unsigned long long ) node_id ) ;
@ -1183,7 +1248,8 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
sqlite3 * db = cs - > inst - > topo_groups - > topo_sqlite_db ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , NULL ) ;
topo_node_sqlite_member_put ( db , ch_id , node_id , join_sig , join_ts , NULL , 0 , x25519 , ed_pub , peer_name , NULL ) ;
topo_node_sqlite_node_update_verified ( db , node_id , peer_name , x25519 , ed_pub , join_ts ) ;
if ( db & & peer_name [ 0 ] ) {
if ( db & & peer_name [ 0 ] ) {
sqlite3_stmt * ns = NULL ;
sqlite3_stmt * ns = NULL ;
sqlite3_prepare_v2 ( db , " INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?) " , - 1 , & ns , NULL ) ;
sqlite3_prepare_v2 ( db , " INSERT OR REPLACE INTO nodes(node_id,name,x25519_pubkey,ed25519_pubkey) VALUES(?,?,?,?) " , - 1 , & ns , NULL ) ;