etcp_router: Ed25519 digital signature for service messages
- Add ed25519_public_key[32] to NODEINFO struct for pubkey distribution - Add ed25519_public_key[32] to ROUTE_BGP (derived from X25519 privkey at init) - Add ROUTER_FLAG_SIGNED (0x08) to SVC_ROUTE_HDR flags byte - router_send_one_flags: when is_signed, sign [hdr][payload] and append 64-byte sig - etcp_router_recv_cb: verify Ed25519 signature when ROUTER_FLAG_SIGNED set - New API: etcp_router_conn_send_signed() - Drop signed packets if sender node not in routing table or no Ed25519 key - 5 unit tests in test_etcp_router_unit.c covering OK/tampered/unknown/no-key/short
This commit is contained in:
1 parent
2bbdf8195f
commit
6717c863e7
47 files changed
+18845
-16
No files matched your search
@@ -5,6 +5,7 @@ check_PROGRAMS = \
|
||||
test_ll_queue \
|
||||
test_serialize \
|
||||
test_stream_cipher \
|
||||
test_stream_sign \
|
||||
test_etcp_transport \
|
||||
test_transport \
|
||||
test_stcp \
|
||||
@@ -91,6 +92,7 @@ ETCP_FULL_OBJS = \
|
||||
$(top_builddir)/src/utun-route_bgp.o \
|
||||
$(top_builddir)/src/utun-route_ping.o \
|
||||
$(top_builddir)/src/utun-route_node.o \
|
||||
$(top_builddir)/src/utun-route_node_lmdb.o \
|
||||
$(top_builddir)/src/utun-route_connectivity.o \
|
||||
$(top_builddir)/src/utun-routing.o \
|
||||
$(top_builddir)/src/utun-tun_if.o \
|
||||
@@ -140,6 +142,10 @@ test_stream_cipher_SOURCES = test_stream_cipher.c
|
||||
test_stream_cipher_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
test_stream_cipher_LDADD = $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_stream_sign_SOURCES = test_stream_sign.c
|
||||
test_stream_sign_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
test_stream_sign_LDADD = $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
test_transport_SOURCES = test_stcp_link.c
|
||||
test_transport_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/lib
|
||||
test_transport_LDADD = $(STCP_LINK_OBJS) $(SECURE_CHANNEL_OBJS) $(CRYPTO_LIBS) $(COMMON_LIBS)
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "../src/etcp.h"
|
||||
#include "../src/etcp_api.h"
|
||||
#include "../src/etcp_router.h"
|
||||
#include "../src/route_bgp.h"
|
||||
#include "../src/utun_instance.h"
|
||||
#include "../lib/u_async.h"
|
||||
#include "../lib/ll_queue.h"
|
||||
@@ -122,6 +123,85 @@ static int test_total = 0, test_passed = 0, test_failed = 0;
|
||||
#define PASS() do { puts("PASS"); test_passed++; } while(0)
|
||||
#define FAIL(msg) do { printf("FAIL: %s\n", msg); test_failed++; return -1; } while(0)
|
||||
|
||||
// ======================== Sign test infrastructure ========================
|
||||
static int g_sign_ready = 0;
|
||||
static struct SC_MYKEYS g_sign_keys;
|
||||
static sc_context_t g_sign_ctx;
|
||||
static uint8_t g_sign_ed25519_pubkey[SC_PUBKEY_SIZE];
|
||||
static const uint64_t SIGNER_NODE = 0xCCCC000000000001ULL;
|
||||
|
||||
static int setup_sign_keys(void) {
|
||||
if (g_sign_ready) return 0;
|
||||
if (sc_generate_keypair(&g_sign_keys) != SC_OK) { printf(" setup_sign_keys: generate_keypair failed\n"); return -1; }
|
||||
sc_init_ctx(&g_sign_ctx, &g_sign_keys);
|
||||
if (sc_derive_ed25519_pubkey(g_sign_keys.private_key, g_sign_ed25519_pubkey) != SC_OK) { printf(" setup_sign_keys: derive_ed25519_pubkey failed\n"); return -1; }
|
||||
g_sign_ready = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void setup_bgp_for_sign_test(struct UTUN_INSTANCE* inst, int with_ed25519_key) {
|
||||
struct ROUTE_BGP* bgp = u_calloc(1, sizeof(struct ROUTE_BGP));
|
||||
if (!bgp) { printf(" setup_bgp: u_calloc failed\n"); return; }
|
||||
bgp->instance = inst;
|
||||
bgp->nodes = queue_new(inst->ua, BGP_NODES_HASH_SIZE,
|
||||
offsetof(struct NODEINFO_Q, node.node_id) - sizeof(struct ll_entry), 8, "bgp_nodes_test");
|
||||
if (!bgp->nodes) { printf(" setup_bgp: queue_new failed\n"); u_free(bgp); return; }
|
||||
inst->bgp = bgp;
|
||||
|
||||
size_t dsize = sizeof(struct NODEINFO_Q) - sizeof(struct ll_entry);
|
||||
struct NODEINFO_Q* nq = (struct NODEINFO_Q*)queue_entry_new(dsize);
|
||||
if (!nq) { printf(" setup_bgp: queue_entry_new failed\n"); return; }
|
||||
memset(&nq->node, 0, sizeof(nq->node));
|
||||
nq->node.node_id = SIGNER_NODE;
|
||||
if (with_ed25519_key) memcpy(nq->node.ed25519_public_key, g_sign_ed25519_pubkey, SC_PUBKEY_SIZE);
|
||||
queue_data_put_with_index(bgp->nodes, &nq->ll);
|
||||
}
|
||||
|
||||
static void teardown_bgp_for_sign_test(struct UTUN_INSTANCE* inst) {
|
||||
if (!inst || !inst->bgp) return;
|
||||
if (inst->bgp->nodes) {
|
||||
struct ll_entry* e;
|
||||
while ((e = queue_data_get(inst->bgp->nodes)) != NULL) queue_entry_free(e);
|
||||
queue_free(inst->bgp->nodes);
|
||||
}
|
||||
u_free(inst->bgp);
|
||||
inst->bgp = NULL;
|
||||
}
|
||||
|
||||
static void inject_signed(etcp_recv_fn recv_cb, struct UTUN_INSTANCE* inst,
|
||||
uint64_t src, uint8_t svc_id, uint32_t seq,
|
||||
const uint8_t* pl, size_t pl_len, uint8_t flags,
|
||||
int tamper_sig) {
|
||||
size_t hdr_pl = SVC_ROUTE_HDR_SIZE + pl_len;
|
||||
size_t total = hdr_pl + SC_SIGN_SIZE;
|
||||
uint8_t* dgram = u_malloc(total);
|
||||
if (!dgram) { printf(" inject_signed: u_malloc failed\n"); return; }
|
||||
|
||||
struct SVC_ROUTE_HDR* hdr = (struct SVC_ROUTE_HDR*)dgram;
|
||||
memset(hdr, 0, SVC_ROUTE_HDR_SIZE);
|
||||
hdr->cmd = ETCP_ID_SVC_ROUTE;
|
||||
hdr->dst_node_id = inst->node_id;
|
||||
hdr->src_node_id = src;
|
||||
hdr->seq = seq;
|
||||
hdr->svc_id = svc_id;
|
||||
hdr->flags = flags | ROUTER_FLAG_SIGNED;
|
||||
if (pl_len > 0) memcpy(dgram + SVC_ROUTE_HDR_SIZE, pl, pl_len);
|
||||
|
||||
struct sc_stream_sign_state sign_state;
|
||||
if (sc_stream_sign_init(&g_sign_ctx, &sign_state) != SC_OK) { u_free(dgram); return; }
|
||||
if (sc_stream_sign_update(&sign_state, dgram, hdr_pl) != SC_OK) { sc_stream_sign_cleanup(&sign_state); u_free(dgram); return; }
|
||||
size_t sig_len = SC_SIGN_SIZE;
|
||||
if (sc_stream_sign_final(&sign_state, dgram + hdr_pl, &sig_len) != SC_OK) { u_free(dgram); return; }
|
||||
|
||||
if (tamper_sig) dgram[hdr_pl] ^= 0x01;
|
||||
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) { u_free(dgram); return; }
|
||||
e->dgram = dgram;
|
||||
e->len = total;
|
||||
recv_cb(&fake_conn, e);
|
||||
}
|
||||
|
||||
// ======================== Tests ========================
|
||||
|
||||
static int test_init_destroy(void) {
|
||||
@@ -688,6 +768,118 @@ static int test_server_reinit(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ======================== Signed message tests ========================
|
||||
|
||||
static int test_sign_verify_ok(void) {
|
||||
TEST("signed packet — verify OK, delivered to handler");
|
||||
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
|
||||
SETUP();
|
||||
setup_bgp_for_sign_test(&inst, 1);
|
||||
|
||||
rx_reset(0xF1);
|
||||
uint8_t data[] = { TEST_SVC_ID, 0xF1, 0 };
|
||||
inject_signed(recv_cb, &inst, SIGNER_NODE, TEST_SVC_ID, 0, data + 1, 2, 0, 0);
|
||||
|
||||
if (rx.delivered != 1) FAIL("signed packet not delivered");
|
||||
if (rx.errors != 0) FAIL("data mismatch on signed packet");
|
||||
|
||||
teardown_bgp_for_sign_test(&inst);
|
||||
TEARDOWN();
|
||||
PASS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sign_bad_signature(void) {
|
||||
TEST("signed packet — tampered signature → dropped");
|
||||
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
|
||||
SETUP();
|
||||
setup_bgp_for_sign_test(&inst, 1);
|
||||
|
||||
rx_reset(0xF2);
|
||||
uint8_t data[] = { TEST_SVC_ID, 0xF2, 0 };
|
||||
inject_signed(recv_cb, &inst, SIGNER_NODE, TEST_SVC_ID, 0, data + 1, 2, 0, 1 /*tamper*/);
|
||||
|
||||
if (rx.delivered != 0) FAIL("tampered signed packet should be dropped");
|
||||
if (rx.errors != 0) FAIL("handler should not be called for bad signature");
|
||||
|
||||
teardown_bgp_for_sign_test(&inst);
|
||||
TEARDOWN();
|
||||
PASS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sign_unknown_node(void) {
|
||||
TEST("signed packet — sender not in routing table → dropped");
|
||||
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
|
||||
SETUP();
|
||||
setup_bgp_for_sign_test(&inst, 1);
|
||||
|
||||
rx_reset(0xF3);
|
||||
uint8_t data[] = { TEST_SVC_ID, 0xF3, 0 };
|
||||
uint64_t unknown = 0xDEAD000000000001ULL;
|
||||
inject_signed(recv_cb, &inst, unknown, TEST_SVC_ID, 0, data + 1, 2, 0, 0);
|
||||
|
||||
if (rx.delivered != 0) FAIL("packet from unknown node should be dropped");
|
||||
if (rx.errors != 0) FAIL("handler not called for unknown node");
|
||||
|
||||
teardown_bgp_for_sign_test(&inst);
|
||||
TEARDOWN();
|
||||
PASS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sign_no_ed25519_key(void) {
|
||||
TEST("signed packet — node in table but no Ed25519 key → dropped");
|
||||
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
|
||||
SETUP();
|
||||
setup_bgp_for_sign_test(&inst, 0 /*zero ed25519 key*/);
|
||||
|
||||
rx_reset(0xF4);
|
||||
uint8_t data[] = { TEST_SVC_ID, 0xF4, 0 };
|
||||
inject_signed(recv_cb, &inst, SIGNER_NODE, TEST_SVC_ID, 0, data + 1, 2, 0, 0);
|
||||
|
||||
if (rx.delivered != 0) FAIL("packet with zero ed25519 key should be dropped");
|
||||
|
||||
teardown_bgp_for_sign_test(&inst);
|
||||
TEARDOWN();
|
||||
PASS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_sign_too_short(void) {
|
||||
TEST("signed packet — SIGNED flag but no signature bytes → dropped");
|
||||
struct UASYNC* ua; struct UTUN_INSTANCE inst; etcp_recv_fn recv_cb;
|
||||
SETUP();
|
||||
setup_bgp_for_sign_test(&inst, 1);
|
||||
|
||||
rx_reset(0xF5);
|
||||
struct SVC_ROUTE_HDR hdr;
|
||||
memset(&hdr, 0, sizeof(hdr));
|
||||
hdr.cmd = ETCP_ID_SVC_ROUTE;
|
||||
hdr.dst_node_id = inst.node_id;
|
||||
hdr.src_node_id = SIGNER_NODE;
|
||||
hdr.seq = 0;
|
||||
hdr.svc_id = TEST_SVC_ID;
|
||||
hdr.flags = ROUTER_FLAG_SIGNED;
|
||||
uint8_t payload[] = { TEST_SVC_ID, 0xF5, 0 };
|
||||
size_t total = SVC_ROUTE_HDR_SIZE + sizeof(payload);
|
||||
struct ll_entry* e = queue_entry_new(0);
|
||||
if (!e) FAIL("queue_entry_new");
|
||||
e->dgram = u_malloc(total);
|
||||
if (!e->dgram) { queue_entry_free(e); FAIL("u_malloc"); }
|
||||
memcpy(e->dgram, &hdr, SVC_ROUTE_HDR_SIZE);
|
||||
memcpy(e->dgram + SVC_ROUTE_HDR_SIZE, payload, sizeof(payload));
|
||||
e->len = total;
|
||||
recv_cb(&fake_conn, e);
|
||||
|
||||
if (rx.delivered != 0) FAIL("too-short signed packet should be dropped");
|
||||
|
||||
teardown_bgp_for_sign_test(&inst);
|
||||
TEARDOWN();
|
||||
PASS();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ======================== Main ========================
|
||||
int main(void) {
|
||||
// Run all tests
|
||||
@@ -715,6 +907,15 @@ int main(void) {
|
||||
test_sess_id_wrap();
|
||||
test_server_reinit();
|
||||
|
||||
if (setup_sign_keys() != 0) { printf(" SKIP signed tests — crypto init failed\n"); }
|
||||
else {
|
||||
test_sign_verify_ok();
|
||||
test_sign_bad_signature();
|
||||
test_sign_unknown_node();
|
||||
test_sign_no_ed25519_key();
|
||||
test_sign_too_short();
|
||||
}
|
||||
|
||||
printf("\n=== Results: %d/%d passed, %d failed ===\n", test_passed, test_total, test_failed);
|
||||
return test_failed > 0 ? 1 : 0;
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
// test_stream_sign.c — tests for streaming Ed25519 signature
|
||||
#include "../src/secure_channel.h"
|
||||
#include "../lib/debug_config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static int test_failed = 0;
|
||||
|
||||
#define CHECK(expr, msg) do { \
|
||||
if (!(expr)) { \
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "FAIL: %s", msg); \
|
||||
test_failed = 1; \
|
||||
} else { \
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "PASS: %s", msg); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
int main(void) {
|
||||
debug_config_init();
|
||||
debug_set_level(DEBUG_LEVEL_INFO);
|
||||
debug_set_categories(DEBUG_CATEGORY_CRYPTO);
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "=== Streaming Sign Test ===");
|
||||
|
||||
struct SC_MYKEYS keys_a;
|
||||
CHECK(sc_generate_keypair(&keys_a) == SC_OK, "generate keypair A");
|
||||
|
||||
sc_context_t ctx_a;
|
||||
CHECK(sc_init_ctx(&ctx_a, &keys_a) == SC_OK, "init ctx A");
|
||||
|
||||
uint8_t ed25519_pubkey_a[SC_PUBKEY_SIZE];
|
||||
CHECK(sc_derive_ed25519_pubkey(keys_a.private_key, ed25519_pubkey_a) == SC_OK, "derive ed25519 pubkey from x25519");
|
||||
|
||||
// ==========================================
|
||||
// Test 1: basic sign/verify — single chunk
|
||||
// ==========================================
|
||||
{
|
||||
uint8_t data[1024];
|
||||
for (int i = 0; i < (int)sizeof(data); i++) data[i] = (uint8_t)(i * 7 + 31);
|
||||
|
||||
struct sc_stream_sign_state signer, verifier;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "sign_init");
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, ed25519_pubkey_a) == SC_OK, "verify_init");
|
||||
|
||||
CHECK(sc_stream_sign_update(&signer, data, sizeof(data)) == SC_OK, "sign_update 1024B");
|
||||
CHECK(sc_stream_sign_update(&verifier, data, sizeof(data)) == SC_OK, "verify_update 1024B");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "sign_final");
|
||||
CHECK(sig_len == SC_SIGN_SIZE, "signature size 64");
|
||||
|
||||
CHECK(sc_stream_sign_verify(&verifier, sig, sig_len) == SC_OK, "verify OK");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 2: incremental update — many small chunks
|
||||
// ==========================================
|
||||
{
|
||||
uint8_t data[2048];
|
||||
for (int i = 0; i < (int)sizeof(data); i++) data[i] = (uint8_t)(i * 3 + 17);
|
||||
|
||||
struct sc_stream_sign_state signer, verifier;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "inc: sign_init");
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, ed25519_pubkey_a) == SC_OK, "inc: verify_init");
|
||||
|
||||
for (int i = 0; i < (int)sizeof(data); i += 7) {
|
||||
int chunk = ((int)sizeof(data) - i < 7) ? ((int)sizeof(data) - i) : 7;
|
||||
CHECK(sc_stream_sign_update(&signer, data + i, chunk) == SC_OK, "inc: sign_update");
|
||||
CHECK(sc_stream_sign_update(&verifier, data + i, chunk) == SC_OK, "inc: verify_update");
|
||||
}
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "inc: sign_final");
|
||||
|
||||
CHECK(sc_stream_sign_verify(&verifier, sig, sig_len) == SC_OK, "inc: verify OK");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 3: tampered data — verify MUST fail
|
||||
// ==========================================
|
||||
{
|
||||
uint8_t data[512];
|
||||
for (int i = 0; i < (int)sizeof(data); i++) data[i] = (uint8_t)(i * 5 + 7);
|
||||
|
||||
struct sc_stream_sign_state signer, verifier;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "tamper: sign_init");
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, ed25519_pubkey_a) == SC_OK, "tamper: verify_init");
|
||||
|
||||
CHECK(sc_stream_sign_update(&signer, data, sizeof(data)) == SC_OK, "tamper: sign_update");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "tamper: sign_final");
|
||||
|
||||
data[0] ^= 0x01;
|
||||
CHECK(sc_stream_sign_update(&verifier, data, sizeof(data)) == SC_OK, "tamper: verify_update (modified)");
|
||||
CHECK(sc_stream_sign_verify(&verifier, sig, sig_len) == SC_ERR_AUTH_FAILED, "tamper: verify FAIL (expected)");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 4: wrong public key — verify MUST fail
|
||||
// ==========================================
|
||||
{
|
||||
struct SC_MYKEYS keys_b;
|
||||
CHECK(sc_generate_keypair(&keys_b) == SC_OK, "generate keypair B");
|
||||
uint8_t pubkey_b[SC_PUBKEY_SIZE];
|
||||
CHECK(sc_derive_ed25519_pubkey(keys_b.private_key, pubkey_b) == SC_OK, "derive pubkey B");
|
||||
|
||||
uint8_t data[256];
|
||||
for (int i = 0; i < (int)sizeof(data); i++) data[i] = (uint8_t)i;
|
||||
|
||||
struct sc_stream_sign_state signer, verifier;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "wrongkey: sign_init (A)");
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, pubkey_b) == SC_OK, "wrongkey: verify_init (B's key)");
|
||||
|
||||
CHECK(sc_stream_sign_update(&signer, data, sizeof(data)) == SC_OK, "wrongkey: sign_update");
|
||||
CHECK(sc_stream_sign_update(&verifier, data, sizeof(data)) == SC_OK, "wrongkey: verify_update");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "wrongkey: sign_final");
|
||||
|
||||
CHECK(sc_stream_sign_verify(&verifier, sig, sig_len) == SC_ERR_AUTH_FAILED, "wrongkey: verify FAIL (expected)");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 5: empty data — sign/verify empty message
|
||||
// ==========================================
|
||||
{
|
||||
struct sc_stream_sign_state signer, verifier;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "empty: sign_init");
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, ed25519_pubkey_a) == SC_OK, "empty: verify_init");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "empty: sign_final (no data)");
|
||||
|
||||
CHECK(sc_stream_sign_verify(&verifier, sig, sig_len) == SC_OK, "empty: verify OK");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 6: update with len=0 — should be no-op
|
||||
// ==========================================
|
||||
{
|
||||
uint8_t data[64];
|
||||
for (int i = 0; i < (int)sizeof(data); i++) data[i] = (uint8_t)(i * 11);
|
||||
|
||||
struct sc_stream_sign_state signer;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "zerolen: sign_init");
|
||||
CHECK(sc_stream_sign_update(&signer, NULL, 0) == SC_OK, "zerolen: NULL+0 OK");
|
||||
CHECK(sc_stream_sign_update(&signer, data, 0) == SC_OK, "zerolen: data+0 OK");
|
||||
CHECK(sc_stream_sign_update(&signer, data, sizeof(data)) == SC_OK, "zerolen: sign_update 64B");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE];
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&signer, sig, &sig_len) == SC_OK, "zerolen: sign_final");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 7: error handling — init
|
||||
// ==========================================
|
||||
{
|
||||
struct sc_stream_sign_state state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
CHECK(sc_stream_sign_init(NULL, &state) == SC_ERR_INVALID_ARG, "err: init NULL ctx");
|
||||
CHECK(sc_stream_sign_init(&ctx_a, NULL) == SC_ERR_INVALID_ARG, "err: init NULL state");
|
||||
|
||||
sc_context_t no_pk_ctx;
|
||||
memset(&no_pk_ctx, 0, sizeof(no_pk_ctx));
|
||||
CHECK(sc_stream_sign_init(&no_pk_ctx, &state) == SC_ERR_NOT_INITIALIZED, "err: init uninitialized ctx");
|
||||
|
||||
CHECK(sc_stream_sign_verify_init(NULL, ed25519_pubkey_a) == SC_ERR_INVALID_ARG, "err: verify_init NULL state");
|
||||
CHECK(sc_stream_sign_verify_init(&state, NULL) == SC_ERR_INVALID_ARG, "err: verify_init NULL pubkey");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 8: error handling — update
|
||||
// ==========================================
|
||||
{
|
||||
struct sc_stream_sign_state state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
CHECK(sc_stream_sign_update(NULL, (uint8_t*)"x", 1) == SC_ERR_INVALID_ARG, "err: update NULL state");
|
||||
CHECK(sc_stream_sign_update(&state, NULL, 1) == SC_ERR_INVALID_ARG, "err: update NULL data");
|
||||
CHECK(sc_stream_sign_update(&state, (uint8_t*)"x", 1) == SC_ERR_NOT_INITIALIZED, "err: update not init");
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 9: error handling — final/verify on wrong init
|
||||
// ==========================================
|
||||
{
|
||||
struct sc_stream_sign_state verifier;
|
||||
CHECK(sc_stream_sign_verify_init(&verifier, ed25519_pubkey_a) == SC_OK, "err: verify_init for final test");
|
||||
|
||||
uint8_t sig[SC_SIGN_SIZE] = {0};
|
||||
size_t sig_len = sizeof(sig);
|
||||
CHECK(sc_stream_sign_final(&verifier, sig, &sig_len) == SC_ERR_NOT_INITIALIZED, "err: final on verify state");
|
||||
sc_stream_sign_cleanup(&verifier);
|
||||
}
|
||||
{
|
||||
struct sc_stream_sign_state signer;
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &signer) == SC_OK, "err: sign_init for verify test");
|
||||
uint8_t sig[SC_SIGN_SIZE] = {0};
|
||||
CHECK(sc_stream_sign_verify(&signer, sig, SC_SIGN_SIZE) == SC_ERR_NOT_INITIALIZED, "err: verify on sign state");
|
||||
sc_stream_sign_cleanup(&signer);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Test 10: cleanup
|
||||
// ==========================================
|
||||
{
|
||||
struct sc_stream_sign_state state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
sc_stream_sign_cleanup(&state); // uninitialized — no crash
|
||||
sc_stream_sign_cleanup(NULL); // NULL — no crash
|
||||
|
||||
CHECK(sc_stream_sign_init(&ctx_a, &state) == SC_OK, "cleanup: init");
|
||||
sc_stream_sign_cleanup(&state);
|
||||
CHECK(state.initialized == 0, "cleanup: initialized cleared");
|
||||
}
|
||||
|
||||
if (test_failed) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "=== Streaming Sign Test: FAILED ===");
|
||||
return 1;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "=== Streaming Sign Test: PASSED ===");
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user