Exercise failed root signing during channel creation against committed SQLite

This commit is contained in:
evgeny committed 2026-10-27 04:12:58 +01:00
1 parent 1c5faaffc3
commit a4dd4a10d5
2 files changed
+74

No files matched your search

+4
View File
@@ -301,6 +301,7 @@ if OS_LINUX
test_socket_monitor_LDFLAGS += -Wl,--wrap=recvfrom -Wl,--wrap=__recvfrom_chk
check_PROGRAMS += test_config_parser
check_PROGRAMS += test_chat_setting
check_PROGRAMS += test_chat_channel
check_PROGRAMS += test_instance_contract
test_instance_contract_SOURCES = test_instance_contract.c
test_instance_contract_LDADD = $(LIBUTUN) $(COMMON_LIBS)
@@ -311,6 +312,9 @@ test_config_parser_LDFLAGS = -Wl,--wrap=u_calloc_impl -Wl,--wrap=u_realloc_impl
test_chat_setting_SOURCES = test_chat_setting.c
test_chat_setting_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_chat_setting_LDFLAGS = -Wl,--wrap=chat_local_apply_settings
test_chat_channel_SOURCES = test_chat_channel.c
test_chat_channel_LDADD = $(LIBUTUN) $(COMMON_LIBS)
test_chat_channel_LDFLAGS = -Wl,--wrap=EVP_DigestSign
else
test_socket_monitor_LDFLAGS += -Wl,--wrap=read
endif
+70
View File
@@ -0,0 +1,70 @@
/* Создание канала: настоящие ключи/подписи/SQLite; отказ не публикует незавершённый канал. */
#define _GNU_SOURCE
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "../src/utun_instance.h"
#include "../src/chat/chat_core.h"
#include "../src/chat/chat_core_priv.h"
#include "../src/chat/chat_event.h"
#include "../src/chat/member_sync.h"
#include "../src/routing_layer/topo_node_sqlite.h"
#include "../lib/platform_compat.h"
#include "../lib/debug_config.h"
#include "../lib/mem.h"
static unsigned fail_sign_number, channel_events;
static sqlite3* reader;
extern int __real_EVP_DigestSign(EVP_MD_CTX*, unsigned char*, size_t*, const unsigned char*, size_t);
int __wrap_EVP_DigestSign(EVP_MD_CTX* ctx, unsigned char* signature, size_t* length, const unsigned char* data, size_t size) {
if (fail_sign_number && !--fail_sign_number) {
DEBUG_WARN(DEBUG_CATEGORY_CHAT_SYNC, "channel test: injected signature failure bytes=%zu", size); return 0;
}
return __real_EVP_DigestSign(ctx, signature, length, data, size);
}
static int channels(void) {
sqlite3_stmt* st = NULL;
assert(sqlite3_prepare_v2(reader, "SELECT count(*) FROM channels", -1, &st, NULL) == SQLITE_OK && sqlite3_step(st) == SQLITE_ROW);
int count = sqlite3_column_int(st, 0); assert(sqlite3_finalize(st) == SQLITE_OK); return count;
}
/* Обработчик видит канал и проверенного участника уже после commit. */
static void event(struct UTUN_INSTANCE* inst, int type, const uint8_t* data, int size) {
if (type != CHAT_EVT_CHANNEL_UPDATED) return;
assert(sqlite3_get_autocommit(inst->topo_sqlite_db) && size == data[0] + 1 && data[0] < 20);
char channel[20]; memcpy(channel, data + 1, data[0]); channel[data[0]] = 0;
sqlite3_stmt* st = NULL;
assert(sqlite3_prepare_v2(reader, "SELECT owner_node_id,length(x25519_pubkey),length(x25519_privkey),"
"length(ed25519_pubkey),length(ed25519_privkey),length(signature) FROM channels WHERE channel_id=?", -1, &st, NULL) == SQLITE_OK);
assert(sqlite3_bind_text(st, 1, channel, -1, SQLITE_STATIC) == SQLITE_OK && sqlite3_step(st) == SQLITE_ROW);
assert((uint64_t)sqlite3_column_int64(st, 0) == inst->node_id);
for (int i = 1; i <= 5; i++) assert(sqlite3_column_int(st, i) == (i == 5 ? 64 : 32));
assert(sqlite3_finalize(st) == SQLITE_OK);
uint8_t key[32]; assert(member_sync_author_key(inst, channel, inst->node_id, key) == MS_AUTHOR_ACTIVE);
assert(!memcmp(key, inst->my_ed25519_pubkey, 32)); channel_events++;
}
int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); size_t baseline = u_get_allocated_count();
utun_instance_set_tun_init_enabled(0);
char directory[] = "/tmp/utun-channel-create-XXXXXX"; assert(mkdtemp(directory));
char config[512], database[256];
snprintf(config, sizeof(config), "[global]\ndb_path=%s\n[ntp]\nenabled=no\n"
"[chatserver]\ngroup_autoconnect=0\nstorage_autoload=0\n", directory);
struct UASYNC* ua = uasync_create(); assert(ua);
struct UTUN_INSTANCE* inst = utun_instance_create_from_str(ua, config);
assert(inst && !utun_core_start(inst) && !chat_service_start(inst));
snprintf(database, sizeof(database), "%s/chats.db", directory);
assert(sqlite3_open_v2(database, &reader, SQLITE_OPEN_READONLY, NULL) == SQLITE_OK);
chat_event_set_handler(inst, event); assert(!channels());
fail_sign_number = 2; chat_core_create_channel_auto(inst, "root signature failure");
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "channel test: after signature fault channels=%d events=%u", channels(), channel_events);
assert(!fail_sign_number && !channels() && !channel_events);
chat_core_create_channel_auto(inst, "successful retry"); assert(channels() == 1 && channel_events == 1);
utun_instance_destroy(inst); assert(channels() == 1 && sqlite3_close(reader) == SQLITE_OK); reader = NULL;
uasync_poll(ua, 0); uasync_destroy(ua, 0); assert(u_get_allocated_count() == baseline);
DEBUG_INFO(DEBUG_CATEGORY_CHAT_SYNC, "PASS channel creation: failed root signature leaves no channel/event; retry publishes valid membership after commit");
return 0;
}