feat: mutual Realm peer handshake over TCP (0.9.11)
Exchange enrolled certificates and Ed25519 challenge signatures so same-Realm instances can authenticate each other after discovery. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+2
-1
@@ -123,6 +123,7 @@ set(CST_CORE_SOURCES
|
|||||||
src/worktree.c
|
src/worktree.c
|
||||||
src/realm.c
|
src/realm.c
|
||||||
src/discover.c
|
src/discover.c
|
||||||
|
src/peer_auth.c
|
||||||
src/attach.c
|
src/attach.c
|
||||||
src/clipboard.c
|
src/clipboard.c
|
||||||
src/pdf_text.c
|
src/pdf_text.c
|
||||||
@@ -388,7 +389,7 @@ set(_CST_CORE_TESTS test_llm_body test_prefix_stable test_sse_decode
|
|||||||
test_undo test_config test_models test_model_registry test_sandbox
|
test_undo test_config test_models test_model_registry test_sandbox
|
||||||
test_keymap test_shell_compact test_skills
|
test_keymap test_shell_compact test_skills
|
||||||
test_plugins test_mcp test_subagent test_runtime test_realm test_discover
|
test_plugins test_mcp test_subagent test_runtime test_realm test_discover
|
||||||
test_lowil
|
test_peer_auth test_lowil
|
||||||
test_win_utf8 test_os_dir test_tmpdir
|
test_win_utf8 test_os_dir test_tmpdir
|
||||||
test_tool_meta test_embed)
|
test_tool_meta test_embed)
|
||||||
if(CST_BUILD_WEBUI)
|
if(CST_BUILD_WEBUI)
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ CORE_SRC = \
|
|||||||
src/extensions.c src/plugins.c src/mcp.c src/subagent.c src/attach.c src/clipboard.c \
|
src/extensions.c src/plugins.c src/mcp.c src/subagent.c src/attach.c src/clipboard.c \
|
||||||
src/pdf_text.c \
|
src/pdf_text.c \
|
||||||
src/session.c src/runtime.c src/worktree.c src/realm.c src/discover.c \
|
src/session.c src/runtime.c src/worktree.c src/realm.c src/discover.c \
|
||||||
|
src/peer_auth.c \
|
||||||
src/tools/tools.c \
|
src/tools/tools.c \
|
||||||
src/tools/patch.c \
|
src/tools/patch.c \
|
||||||
src/tools/registry.c \
|
src/tools/registry.c \
|
||||||
@@ -175,6 +176,7 @@ TESTS = \
|
|||||||
tests/test_runtime \
|
tests/test_runtime \
|
||||||
tests/test_realm \
|
tests/test_realm \
|
||||||
tests/test_discover \
|
tests/test_discover \
|
||||||
|
tests/test_peer_auth \
|
||||||
tests/test_lowil \
|
tests/test_lowil \
|
||||||
tests/test_win_utf8 \
|
tests/test_win_utf8 \
|
||||||
tests/test_os_dir \
|
tests/test_os_dir \
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef CST_PEER_H
|
||||||
|
#define CST_PEER_H
|
||||||
|
|
||||||
|
#include "cst_realm.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Mutual Realm certificate challenge over TCP (cleartext for now; TLS wrap
|
||||||
|
* is the next slice). Same Realm public key required on both sides. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
cst_realm_cert_t remote;
|
||||||
|
char host[64];
|
||||||
|
int port;
|
||||||
|
} cst_peer_session_t;
|
||||||
|
|
||||||
|
/* Dial host:port, prove our cert, verify theirs. 0 on success. */
|
||||||
|
int cst_peer_dial(const char *host, int port, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64], const uint8_t realm_pk[32],
|
||||||
|
int timeout_ms, cst_peer_session_t *out, char *err,
|
||||||
|
size_t err_sz);
|
||||||
|
|
||||||
|
/* Accept one connection on listening socket (from os_net_listen). */
|
||||||
|
int cst_peer_accept(intptr_t listen_sock, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64], const uint8_t realm_pk[32],
|
||||||
|
int timeout_ms, cst_peer_session_t *out, char *err,
|
||||||
|
size_t err_sz);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#define CST_VERSION_MAJOR 0
|
#define CST_VERSION_MAJOR 0
|
||||||
#define CST_VERSION_MINOR 9
|
#define CST_VERSION_MINOR 9
|
||||||
#define CST_VERSION_PATCH 10
|
#define CST_VERSION_PATCH 11
|
||||||
|
|
||||||
#define CST_VERSION_STR_(x) #x
|
#define CST_VERSION_STR_(x) #x
|
||||||
#define CST_VERSION_STR(x) CST_VERSION_STR_(x)
|
#define CST_VERSION_STR(x) CST_VERSION_STR_(x)
|
||||||
|
|||||||
+334
@@ -0,0 +1,334 @@
|
|||||||
|
#ifndef _DEFAULT_SOURCE
|
||||||
|
#define _DEFAULT_SOURCE
|
||||||
|
#endif
|
||||||
|
#include "cst_peer.h"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "cst_net.h"
|
||||||
|
#include "cst_util.h"
|
||||||
|
#include "monocypher.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
static void hex_encode(const uint8_t *in, size_t n, char *out) {
|
||||||
|
static const char *H = "0123456789abcdef";
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
out[i * 2] = H[in[i] >> 4];
|
||||||
|
out[i * 2 + 1] = H[in[i] & 15];
|
||||||
|
}
|
||||||
|
out[n * 2] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hex_nibble(int c) {
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 10;
|
||||||
|
if (c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hex_decode(const char *s, uint8_t *out, size_t n) {
|
||||||
|
if (!s || strlen(s) != n * 2)
|
||||||
|
return -1;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
int a = hex_nibble(s[i * 2]), b = hex_nibble(s[i * 2 + 1]);
|
||||||
|
if (a < 0 || b < 0)
|
||||||
|
return -1;
|
||||||
|
out[i] = (uint8_t)((a << 4) | b);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int fill_random(uint8_t *buf, size_t n) {
|
||||||
|
FILE *f = fopen("/dev/urandom", "rb");
|
||||||
|
if (!f)
|
||||||
|
return -1;
|
||||||
|
size_t got = fread(buf, 1, n, f);
|
||||||
|
fclose(f);
|
||||||
|
return got == n ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_line(os_socket_t s, const char *line, int timeout_ms) {
|
||||||
|
size_t n = strlen(line);
|
||||||
|
cst_buf_t b = {0};
|
||||||
|
if (cst_buf_append(&b, line, n) || cst_buf_puts(&b, "\n")) {
|
||||||
|
cst_buf_free(&b);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int rc = os_net_send_all(s, b.buf, b.len, timeout_ms);
|
||||||
|
cst_buf_free(&b);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *recv_line(os_socket_t s, int timeout_ms) {
|
||||||
|
cst_buf_t b = {0};
|
||||||
|
char ch;
|
||||||
|
for (;;) {
|
||||||
|
long r = os_net_recv(s, &ch, 1, timeout_ms);
|
||||||
|
if (r <= 0) {
|
||||||
|
cst_buf_free(&b);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (ch == '\n')
|
||||||
|
break;
|
||||||
|
if (ch != '\r')
|
||||||
|
cst_buf_append(&b, &ch, 1);
|
||||||
|
if (b.len > 65536) {
|
||||||
|
cst_buf_free(&b);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!b.buf)
|
||||||
|
cst_buf_puts(&b, "");
|
||||||
|
return cst_buf_steal(&b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_hello(os_socket_t s, const cst_realm_cert_t *self, int timeout_ms) {
|
||||||
|
char *cert = cst_realm_cert_to_json(self);
|
||||||
|
if (!cert)
|
||||||
|
return -1;
|
||||||
|
cJSON *o = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(o, "v", 1);
|
||||||
|
cJSON_AddStringToObject(o, "op", "hello");
|
||||||
|
cJSON *c = cJSON_Parse(cert);
|
||||||
|
free(cert);
|
||||||
|
if (!c) {
|
||||||
|
cJSON_Delete(o);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cJSON_AddItemToObject(o, "cert", c);
|
||||||
|
char *line = cJSON_PrintUnformatted(o);
|
||||||
|
cJSON_Delete(o);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
int rc = send_line(s, line, timeout_ms);
|
||||||
|
free(line);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_hello(os_socket_t s, const uint8_t realm_pk[32], int timeout_ms,
|
||||||
|
cst_realm_cert_t *remote) {
|
||||||
|
char *line = recv_line(s, timeout_ms);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
cJSON *o = cJSON_Parse(line);
|
||||||
|
free(line);
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
const cJSON *op = cJSON_GetObjectItemCaseSensitive(o, "op");
|
||||||
|
const cJSON *cert = cJSON_GetObjectItemCaseSensitive(o, "cert");
|
||||||
|
int ok = 0;
|
||||||
|
if (cJSON_IsString(op) && !strcmp(op->valuestring, "hello") && cert) {
|
||||||
|
char *js = cJSON_PrintUnformatted(cert);
|
||||||
|
if (js && cst_realm_cert_from_json(js, remote) == 0 &&
|
||||||
|
cst_realm_verify_cert(realm_pk, remote, (int64_t)time(NULL)) == 0)
|
||||||
|
ok = 1;
|
||||||
|
free(js);
|
||||||
|
}
|
||||||
|
cJSON_Delete(o);
|
||||||
|
return ok ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_chal(os_socket_t s, const uint8_t nonce[32], int timeout_ms) {
|
||||||
|
char hx[65];
|
||||||
|
hex_encode(nonce, 32, hx);
|
||||||
|
cJSON *o = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(o, "v", 1);
|
||||||
|
cJSON_AddStringToObject(o, "op", "chal");
|
||||||
|
cJSON_AddStringToObject(o, "nonce", hx);
|
||||||
|
char *line = cJSON_PrintUnformatted(o);
|
||||||
|
cJSON_Delete(o);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
int rc = send_line(s, line, timeout_ms);
|
||||||
|
free(line);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_chal(os_socket_t s, int timeout_ms, uint8_t nonce[32]) {
|
||||||
|
char *line = recv_line(s, timeout_ms);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
cJSON *o = cJSON_Parse(line);
|
||||||
|
free(line);
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
const cJSON *op = cJSON_GetObjectItemCaseSensitive(o, "op");
|
||||||
|
const cJSON *n = cJSON_GetObjectItemCaseSensitive(o, "nonce");
|
||||||
|
int ok = cJSON_IsString(op) && !strcmp(op->valuestring, "chal") &&
|
||||||
|
cJSON_IsString(n) && hex_decode(n->valuestring, nonce, 32) == 0;
|
||||||
|
cJSON_Delete(o);
|
||||||
|
return ok ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_auth(os_socket_t s, const uint8_t sk[64], const uint8_t nonce[32],
|
||||||
|
int timeout_ms) {
|
||||||
|
uint8_t sig[64];
|
||||||
|
if (cst_realm_challenge_sign(sk, nonce, 32, sig) != 0)
|
||||||
|
return -1;
|
||||||
|
char hx[129];
|
||||||
|
hex_encode(sig, 64, hx);
|
||||||
|
cJSON *o = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(o, "v", 1);
|
||||||
|
cJSON_AddStringToObject(o, "op", "auth");
|
||||||
|
cJSON_AddStringToObject(o, "sig", hx);
|
||||||
|
char *line = cJSON_PrintUnformatted(o);
|
||||||
|
cJSON_Delete(o);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
int rc = send_line(s, line, timeout_ms);
|
||||||
|
free(line);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_auth(os_socket_t s, const cst_realm_cert_t *remote,
|
||||||
|
const uint8_t nonce[32], int timeout_ms) {
|
||||||
|
char *line = recv_line(s, timeout_ms);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
cJSON *o = cJSON_Parse(line);
|
||||||
|
free(line);
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
const cJSON *op = cJSON_GetObjectItemCaseSensitive(o, "op");
|
||||||
|
const cJSON *sig = cJSON_GetObjectItemCaseSensitive(o, "sig");
|
||||||
|
uint8_t raw[64];
|
||||||
|
int ok = cJSON_IsString(op) && !strcmp(op->valuestring, "auth") &&
|
||||||
|
cJSON_IsString(sig) && hex_decode(sig->valuestring, raw, 64) == 0 &&
|
||||||
|
cst_realm_challenge_check(remote, nonce, 32, raw) == 0;
|
||||||
|
cJSON_Delete(o);
|
||||||
|
return ok ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int send_ok(os_socket_t s, int timeout_ms) {
|
||||||
|
return send_line(s, "{\"v\":1,\"op\":\"ok\"}", timeout_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_ok(os_socket_t s, int timeout_ms) {
|
||||||
|
char *line = recv_line(s, timeout_ms);
|
||||||
|
if (!line)
|
||||||
|
return -1;
|
||||||
|
cJSON *o = cJSON_Parse(line);
|
||||||
|
free(line);
|
||||||
|
if (!o)
|
||||||
|
return -1;
|
||||||
|
const cJSON *op = cJSON_GetObjectItemCaseSensitive(o, "op");
|
||||||
|
int ok = cJSON_IsString(op) && !strcmp(op->valuestring, "ok");
|
||||||
|
cJSON_Delete(o);
|
||||||
|
return ok ? 0 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handshake_as_client(os_socket_t s, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64],
|
||||||
|
const uint8_t realm_pk[32], int timeout_ms,
|
||||||
|
cst_realm_cert_t *remote) {
|
||||||
|
if (send_hello(s, self, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
uint8_t nonce[32];
|
||||||
|
if (read_chal(s, timeout_ms, nonce) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_auth(s, self_sk, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (read_hello(s, realm_pk, timeout_ms, remote) != 0)
|
||||||
|
return -1;
|
||||||
|
if (fill_random(nonce, 32) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_chal(s, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (read_auth(s, remote, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_ok(s, timeout_ms) != 0 || read_ok(s, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handshake_as_server(os_socket_t s, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64],
|
||||||
|
const uint8_t realm_pk[32], int timeout_ms,
|
||||||
|
cst_realm_cert_t *remote) {
|
||||||
|
if (read_hello(s, realm_pk, timeout_ms, remote) != 0)
|
||||||
|
return -1;
|
||||||
|
uint8_t nonce[32];
|
||||||
|
if (fill_random(nonce, 32) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_chal(s, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (read_auth(s, remote, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_hello(s, self, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (read_chal(s, timeout_ms, nonce) != 0)
|
||||||
|
return -1;
|
||||||
|
if (send_auth(s, self_sk, nonce, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
if (read_ok(s, timeout_ms) != 0 || send_ok(s, timeout_ms) != 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cst_peer_dial(const char *host, int port, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64], const uint8_t realm_pk[32],
|
||||||
|
int timeout_ms, cst_peer_session_t *out, char *err,
|
||||||
|
size_t err_sz) {
|
||||||
|
if (err && err_sz)
|
||||||
|
err[0] = 0;
|
||||||
|
if (!host || !self || !self_sk || !realm_pk || !out)
|
||||||
|
return -1;
|
||||||
|
os_net_init();
|
||||||
|
os_socket_t s = os_net_connect(host, port, timeout_ms);
|
||||||
|
if (s == OS_SOCKET_BAD) {
|
||||||
|
if (err && err_sz)
|
||||||
|
snprintf(err, err_sz, "connect failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cst_realm_cert_t remote;
|
||||||
|
if (handshake_as_client(s, self, self_sk, realm_pk, timeout_ms, &remote) !=
|
||||||
|
0) {
|
||||||
|
if (err && err_sz)
|
||||||
|
snprintf(err, err_sz, "peer handshake failed");
|
||||||
|
os_net_close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
out->remote = remote;
|
||||||
|
snprintf(out->host, sizeof(out->host), "%s", host);
|
||||||
|
out->port = port;
|
||||||
|
os_net_close(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cst_peer_accept(intptr_t listen_sock, const cst_realm_cert_t *self,
|
||||||
|
const uint8_t self_sk[64], const uint8_t realm_pk[32],
|
||||||
|
int timeout_ms, cst_peer_session_t *out, char *err,
|
||||||
|
size_t err_sz) {
|
||||||
|
if (err && err_sz)
|
||||||
|
err[0] = 0;
|
||||||
|
if (!self || !self_sk || !realm_pk || !out)
|
||||||
|
return -1;
|
||||||
|
int timed = 0;
|
||||||
|
os_socket_t s = os_net_accept((os_socket_t)listen_sock, timeout_ms, &timed);
|
||||||
|
if (s == OS_SOCKET_BAD) {
|
||||||
|
if (err && err_sz)
|
||||||
|
snprintf(err, err_sz, timed ? "accept timeout" : "accept failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
cst_realm_cert_t remote;
|
||||||
|
if (handshake_as_server(s, self, self_sk, realm_pk, timeout_ms, &remote) !=
|
||||||
|
0) {
|
||||||
|
if (err && err_sz)
|
||||||
|
snprintf(err, err_sz, "peer handshake failed");
|
||||||
|
os_net_close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
memset(out, 0, sizeof(*out));
|
||||||
|
out->remote = remote;
|
||||||
|
os_net_peer(s, out->host, sizeof(out->host));
|
||||||
|
out->port = 0;
|
||||||
|
os_net_close(s);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "cst_net.h"
|
||||||
|
#include "cst_peer.h"
|
||||||
|
#include "cst_realm.h"
|
||||||
|
#include "cst_test_util.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
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];
|
||||||
|
} 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);
|
||||||
|
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"));
|
||||||
|
pthread_join(th, NULL);
|
||||||
|
assert(srv.ok);
|
||||||
|
assert(!strcmp(srv.remote_id, "peer-a"));
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
os_net_close(ls);
|
||||||
|
os_net_close(ls2);
|
||||||
|
os_net_cleanup();
|
||||||
|
puts("test_peer_auth: OK");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user