#define _POSIX_C_SOURCE 200809L #include "cst_net.h" #include "cst_peer.h" #include "cst_realm.h" #include "cst_test_util.h" #include #include #include #include #include #include typedef struct { os_socket_t listen; cst_realm_cert_t cert; uint8_t sk[64]; uint8_t realm_pk[32]; int ok; char remote_id[64]; unsigned long got_rev; char got_ctx[128]; } srv_t; static void *server_main(void *p) { srv_t *s = p; cst_peer_session_t sess; char err[128]; s->ok = cst_peer_accept((intptr_t)s->listen, &s->cert, s->sk, s->realm_pk, 5000, &sess, err, sizeof(err)) == 0; if (s->ok) { snprintf(s->remote_id, sizeof(s->remote_id), "%s", sess.remote.instance_id); assert(sess.sealed); cst_peer_sync_bundle_t local = {0}; local.revision = 1; snprintf(local.parliament_id, sizeof(local.parliament_id), "parl-s"); snprintf(local.project_id, sizeof(local.project_id), "proj"); snprintf(local.chair_instance, sizeof(local.chair_instance), "peer-b"); local.context = strdup("server-old"); assert(cst_peer_sync(&sess, &local, 5000, err, sizeof(err)) == 0); s->got_rev = local.revision; snprintf(s->got_ctx, sizeof(s->got_ctx), "%s", local.context ? local.context : ""); free(local.context); cst_peer_close(&sess); } return NULL; } int main(void) { os_net_init(); cst_realm_keys_t realm; assert(cst_realm_generate(&realm) == 0); cst_realm_cert_t ca, cb; uint8_t sa[32], ska[64], sb[32], skb[64]; assert(cst_realm_enroll(&realm, "peer-a", "A", 0, &ca, sa, ska) == 0); assert(cst_realm_enroll(&realm, "peer-b", "B", 0, &cb, sb, skb) == 0); char err[128]; os_socket_t ls = os_net_listen("127.0.0.1", 0, err, sizeof(err)); assert(ls != OS_SOCKET_BAD); int port = os_net_port(ls); assert(port > 0); srv_t srv = {.listen = ls, .cert = cb}; memcpy(srv.sk, skb, 64); memcpy(srv.realm_pk, realm.pk, 32); pthread_t th; assert(pthread_create(&th, NULL, server_main, &srv) == 0); cst_peer_session_t sess; assert(cst_peer_dial("127.0.0.1", port, &ca, ska, realm.pk, 5000, &sess, err, sizeof(err)) == 0); assert(!strcmp(sess.remote.instance_id, "peer-b")); assert(sess.sealed); cst_peer_sync_bundle_t local = {0}; local.revision = 9; snprintf(local.parliament_id, sizeof(local.parliament_id), "parl-c"); snprintf(local.project_id, sizeof(local.project_id), "proj"); snprintf(local.chair_instance, sizeof(local.chair_instance), "peer-a"); local.context = strdup("client-wins-secret"); assert(cst_peer_sync(&sess, &local, 5000, err, sizeof(err)) == 0); /* Client already has higher rev; stays. */ assert(local.revision == 9); assert(strstr(local.context, "client-wins-secret")); free(local.context); cst_peer_close(&sess); pthread_join(th, NULL); assert(srv.ok); assert(!strcmp(srv.remote_id, "peer-a")); assert(srv.got_rev == 9); assert(strstr(srv.got_ctx, "client-wins-secret")); /* Foreign realm must fail. */ cst_realm_keys_t other; assert(cst_realm_generate(&other) == 0); cst_realm_cert_t cf; uint8_t sf[32], skf[64]; assert(cst_realm_enroll(&other, "peer-f", "F", 0, &cf, sf, skf) == 0); os_socket_t ls2 = os_net_listen("127.0.0.1", 0, err, sizeof(err)); assert(ls2 != OS_SOCKET_BAD); int port2 = os_net_port(ls2); srv_t srv2 = {.listen = ls2, .cert = cb}; memcpy(srv2.sk, skb, 64); memcpy(srv2.realm_pk, realm.pk, 32); assert(pthread_create(&th, NULL, server_main, &srv2) == 0); assert(cst_peer_dial("127.0.0.1", port2, &cf, skf, other.pk, 3000, &sess, err, sizeof(err)) != 0); pthread_join(th, NULL); assert(!srv2.ok); /* Wall-clock dial budget: listener that never accepts must fail fast. */ os_socket_t ls3 = os_net_listen("127.0.0.1", 0, err, sizeof(err)); assert(ls3 != OS_SOCKET_BAD); int port3 = os_net_port(ls3); struct timespec t0, t1; clock_gettime(CLOCK_MONOTONIC, &t0); assert(cst_peer_dial("127.0.0.1", port3, &ca, ska, realm.pk, 800, &sess, err, sizeof(err)) != 0); clock_gettime(CLOCK_MONOTONIC, &t1); long ms = (long)((t1.tv_sec - t0.tv_sec) * 1000 + (t1.tv_nsec - t0.tv_nsec) / 1000000); assert(ms >= 400 && ms < 2500); os_net_close(ls); os_net_close(ls2); os_net_close(ls3); os_net_cleanup(); puts("test_peer_auth: OK"); return 0; }