Browse Source

Verify root formation and invitation certificate replication

master
evgeny 2 weeks ago
parent
commit
9299c95f10
  1. 15
      src/chat/chat_channel.c
  2. 57
      tests/test_member_adapter.c

15
src/chat/chat_channel.c

@ -122,13 +122,18 @@ void chat_core_create_channel(struct UTUN_INSTANCE* inst, struct chat_channel_cr
uint64_t myid = inst->node_id;
uint64_t join_ts = (uint64_t)ntp_time_get_seconds(inst);
uint8_t join_sig[64];
channel_sign_join(req->x25519_pubkey, req->ed25519_pubkey,
myid, inst->my_keys.public_key,
join_ts, inst->my_ed25519_privkey, join_sig);
if (channel_sign_join(req->x25519_pubkey, req->ed25519_pubkey, myid, inst->my_keys.public_key,
join_ts, inst->my_ed25519_privkey, join_sig) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: root join signing failed ch=%s", CC_ID, req->channel_id); return;
}
/* корень дерева приглашений: подписан ключом группы (канальный ed25519) */
uint8_t root_sig[64]; memset(root_sig, 0, 64);
member_sync_sign_pubkey(req->ed25519_privkey, inst->my_keys.public_key, root_sig);
uint8_t root_sig[64];
struct ms_member_rec root = { .node_id = myid, .x25519 = inst->my_keys.public_key, .signature = root_sig };
if (member_sync_sign_pubkey(req->ed25519_privkey, inst->my_keys.public_key, root_sig) < 0
|| member_sync_verify_signature(cc->db, req->channel_id, &root) != 1) {
DEBUG_ERROR(DEBUG_CATEGORY_CHAT_SYNC, "%s: root invitation signing failed ch=%s", CC_ID, req->channel_id); return;
}
int mrc = member_sync_put(inst, req->channel_id, myid,
inst->my_keys.public_key, inst->my_ed25519_pubkey,
join_sig, join_ts, NULL, 0, "{}", NULL, NULL, 0, 0, root_sig);

57
tests/test_member_adapter.c

@ -25,6 +25,62 @@ static void public_key(const uint8_t priv[32], uint8_t pub[32]) {
size_t len = 32; assert(EVP_PKEY_get_raw_public_key(pk, pub, &len) == 1); EVP_PKEY_free(pk);
}
/* Подтверждение корня доставляется независимо от версии профиля и переживает нулевой блок на проводе. */
static void test_invitation_certificate(struct UASYNC* ua) {
struct UTUN_INSTANCE source, target; setup(&source, ua); setup(&target, ua);
uint8_t x[32] = {9}, priv[32] = {7}, pub[32], owner_priv[32] = {8}, owner_pub[32], zero[64] = {0};
public_key(priv, pub); public_key(owner_priv, owner_pub);
struct UTUN_INSTANCE* nodes[] = { &source, &target };
for (unsigned i = 0; i < 2; i++) {
assert(topo_node_sqlite_channel_delete(nodes[i]->topo_sqlite_db, "1001") == 0);
assert(topo_node_sqlite_channel_put(nodes[i]->topo_sqlite_db, "1001", "root", 1, x, NULL, owner_pub, NULL, zero) == 0);
}
uint64_t nid = sc_derive_node_id_from_pubkey(x); uint8_t join[64], tree[64], update[64], body[256];
int len = member_sync_build_join_msg(x, owner_pub, nid, x, 1, body, sizeof(body)); assert(len == 112);
assert(sc_ed25519_sign(priv, body, len, join) == SC_OK && member_sync_sign_pubkey(owner_priv, x, tree) == 0);
struct ms_member_rec rec = { .node_id = nid, .x25519 = x, .ed25519 = pub, .join_sig = join, .join_ts = 1,
.update_sig = update, .update_ts = 2, .userinfo = "{\"name\":\"profile\"}", .signature = tree };
len = member_sync_build_update_msg(join, rec.update_ts, rec.userinfo, body, sizeof(body)); assert(len > 0);
assert(sc_ed25519_sign(priv, body, len, update) == SC_OK);
assert(member_sync_apply_record(&source, "1001", source.node_id, &rec) & MS_APPLY_CHANGED);
rec.signature = zero;
assert(member_sync_apply_record(&target, "1001", target.node_id, &rec) & MS_APPLY_CHANGED);
assert(member_sync_verify_signature(target.topo_sqlite_db, "1001", &rec) == 0);
rec.signature = tree;
assert(member_sync_apply_record(&target, "1001", source.node_id + 1, &rec) & MS_APPLY_CHANGED);
uint8_t expected[32], actual[32], stored[64]; uint64_t parent;
root(&source, expected); root(&target, actual); assert(!memcmp(expected, actual, 32));
assert(topo_node_sqlite_member_get_sign(target.topo_sqlite_db, "1001", nid, &parent, stored) == 0);
assert(parent == 0 && !memcmp(tree, stored, 64));
assert(member_sync_apply_record(&target, "1001", source.node_id + 1, &rec) == 0);
tree[0] ^= 1;
assert(member_sync_apply_record(&target, "1001", source.node_id + 1, &rec) < 0);
root(&target, actual); assert(!memcmp(expected, actual, 32)); tree[0] ^= 1;
/* Более свежий подписанный профиль с нулевой подписью приглашения сохраняет сертификат. */
rec.update_ts = 3; rec.userinfo = "{\"name\":\"new profile\"}";
len = member_sync_build_update_msg(join, rec.update_ts, rec.userinfo, body, sizeof(body)); assert(len > 0);
assert(sc_ed25519_sign(priv, body, len, update) == SC_OK);
assert(member_sync_apply_record(&source, "1001", source.node_id, &rec) & MS_APPLY_CHANGED);
rec.signature = zero;
assert(member_sync_apply_record(&target, "1001", source.node_id + 1, &rec) & MS_APPLY_CHANGED);
assert(topo_node_sqlite_member_get_sign(target.topo_sqlite_db, "1001", nid, &parent, stored) == 0);
assert(parent == 0 && !memcmp(tree, stored, 64));
root(&source, expected); root(&target, actual); assert(!memcmp(expected, actual, 32));
/* Старый профиль может донести подтверждение, сохранив более свежие userinfo/update_ts. */
assert(sqlite3_exec(target.topo_sqlite_db, "UPDATE peers_1001 SET signature=zeroblob(64)", NULL, NULL, NULL) == SQLITE_OK);
assert(merkle_sync_recompute_path(&target, MT_DATA_MEMBERS, "1001", nid) == 1);
rec.update_ts = 2; rec.userinfo = "{\"name\":\"old profile\"}"; rec.signature = tree;
len = member_sync_build_update_msg(join, rec.update_ts, rec.userinfo, body, sizeof(body)); assert(len > 0);
assert(sc_ed25519_sign(priv, body, len, update) == SC_OK);
int result = member_sync_apply_record(&target, "1001", source.node_id + 1, &rec);
assert((result & MS_APPLY_CHANGED) && (result & MS_APPLY_STALE));
root(&target, actual); assert(!memcmp(expected, actual, 32));
puts("PASS: root certificate validates with channel key; equal/stale profile versions do not block confirmation; empty wire signature preserves it");
for (unsigned i = 0; i < 2; i++) { member_sync_destroy(nodes[i]); assert(sqlite3_close(nodes[i]->topo_sqlite_db) == SQLITE_OK); }
}
static void test_owner_sizes(struct UASYNC* ua) {
struct UTUN_INSTANCE source, target; setup(&source, ua); setup(&target, ua);
uint8_t x[32] = {9}, priv[32] = {7}, pub[32], owner_priv[32] = {8}, owner_pub[32], zero[64] = {0};
@ -138,6 +194,7 @@ int main(void) {
debug_config_init(); debug_set_level(DEBUG_LEVEL_ERROR);
size_t baseline = u_get_allocated_count();
struct UASYNC* ua = uasync_create(); assert(ua);
test_invitation_certificate(ua);
test_owner_sizes(ua);
struct UTUN_INSTANCE source, target;
setup(&source, ua); setup(&target, ua);

Loading…
Cancel
Save