You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

209 lines
6.9 KiB

/* test_udp_secure.c - Unit test for UDP secure channel with async library */
#include "sc_lib.h"
#include "u_async.h"
#include <tinycrypt/ecc.h>
#include <tinycrypt/ecc_platform_specific.h>
#include <tinycrypt/constants.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <time.h>
#define TEST_ASSERT(cond, msg) \
do { \
if (!(cond)) { \
printf("FAIL: %s (line %d)\n", msg, __LINE__); \
exit(1); \
} else { \
printf("PASS: %s\n", msg); \
} \
} while(0)
#define PORT_A 12345
#define PORT_B 12346
#define LOCALHOST "127.0.0.1"
typedef struct {
sc_context_t ctx;
int sockfd;
struct sockaddr_in addr;
struct sockaddr_in peer_addr;
uint8_t rx_buffer[1024];
size_t rx_len;
uint8_t tx_buffer[1024];
size_t tx_len;
int received;
int sent;
} client_state_t;
static client_state_t client_a, client_b;
static volatile int test_complete = 0;
static volatile int test_failed = 0;
static void timeout_callback(void* arg) {
(void)arg;
printf("ERROR: Test timeout\n");
test_failed = 1;
exit(1);
}
static void client_a_read_callback(int fd, void* arg) {
client_state_t* state = (client_state_t*)arg;
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0,
(struct sockaddr*)&from, &fromlen);
if (n < 0) {
perror("recvfrom");
return;
}
printf("Client A received %zd bytes\n", n);
// In this test, client A is not expecting data
// but we can handle it if needed
}
static void client_b_read_callback(int fd, void* arg) {
client_state_t* state = (client_state_t*)arg;
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
ssize_t n = recvfrom(fd, state->rx_buffer, sizeof(state->rx_buffer), 0,
(struct sockaddr*)&from, &fromlen);
if (n < 0) {
perror("recvfrom");
return;
}
printf("Client B received %zd bytes\n", n);
// Expect encrypted message (ciphertext + tag + crc32)
size_t ciphertext_len = n;
if (ciphertext_len <= SC_MAX_OVERHEAD || ciphertext_len > sizeof(state->rx_buffer)) {
printf("ERROR: Invalid received length\n");
test_failed = 1;
return;
}
uint8_t* ciphertext = state->rx_buffer;
uint8_t decrypted[1024];
size_t decrypted_len;
const char* expected = "Hello from client A over UDP!";
size_t expected_len = strlen(expected) + 1;
sc_status_t status = sc_decrypt(&state->ctx, ciphertext, ciphertext_len, decrypted, &decrypted_len);
TEST_ASSERT(status == SC_OK, "decryption of received message");
TEST_ASSERT(decrypted_len == expected_len, "decrypted length matches original");
TEST_ASSERT(memcmp(decrypted, expected, decrypted_len) == 0,
"decrypted matches expected plaintext");
printf("Client B successfully decrypted message: %s\n", (char*)decrypted);
test_complete = 1;
exit(0);
}
static int create_udp_socket(int port, struct sockaddr_in* addr) {
int sock = socket(AF_INET, SOCK_DGRAM, 0);
TEST_ASSERT(sock >= 0, "socket creation");
int flags = fcntl(sock, F_GETFL, 0);
TEST_ASSERT(flags >= 0, "get socket flags");
TEST_ASSERT(fcntl(sock, F_SETFL, flags | O_NONBLOCK) == 0, "set non-blocking");
memset(addr, 0, sizeof(*addr));
addr->sin_family = AF_INET;
addr->sin_port = htons(port);
addr->sin_addr.s_addr = inet_addr(LOCALHOST);
TEST_ASSERT(bind(sock, (struct sockaddr*)addr, sizeof(*addr)) == 0, "bind socket");
return sock;
}
static void generate_keys(client_state_t* client) {
memset(&client->ctx, 0, sizeof(client->ctx));
sc_status_t status = sc_generate_keypair(&client->ctx);
TEST_ASSERT(status == SC_OK, "key generation");
}
static void send_encrypted_message(client_state_t* src, client_state_t* dst) {
const char* plaintext = "Hello from client A over UDP!";
size_t plaintext_len = strlen(plaintext) + 1;
size_t ciphertext_len;
uint8_t ciphertext[plaintext_len + SC_MAX_OVERHEAD];
sc_status_t status = sc_encrypt(&src->ctx, (const uint8_t*)plaintext, plaintext_len,
ciphertext, &ciphertext_len);
TEST_ASSERT(status == SC_OK, "encryption for sending");
TEST_ASSERT(ciphertext_len == plaintext_len + SC_MAX_OVERHEAD, "ciphertext length includes overhead");
// Send ciphertext (already includes tag + crc32)
memcpy(src->tx_buffer, ciphertext, ciphertext_len);
size_t packet_len = ciphertext_len;
ssize_t sent = sendto(src->sockfd, src->tx_buffer, packet_len, 0,
(struct sockaddr*)&dst->addr, sizeof(dst->addr));
TEST_ASSERT(sent == (ssize_t)packet_len, "sendto");
printf("Client A sent encrypted message (%zd bytes)\n", sent);
}
int main(void) {
printf("=== UDP Secure Channel Test with Async Library ===\n");
// Initialize TinyCrypt RNG
uECC_set_rng(&default_CSPRNG);
// Initialize async library
uasync_t* ua = uasync_create();
if (!ua) {
fprintf(stderr, "Failed to create uasync instance\n");
return 1;
}
uasync_init_instance(ua);
// Create UDP sockets
client_a.sockfd = create_udp_socket(PORT_A, &client_a.addr);
client_b.sockfd = create_udp_socket(PORT_B, &client_b.addr);
// Set peer addresses for sending
client_a.peer_addr = client_b.addr;
client_b.peer_addr = client_a.addr;
// Generate key pairs for both clients
generate_keys(&client_a);
generate_keys(&client_b);
// Exchange public keys
sc_status_t status = sc_set_peer_public_key(&client_a.ctx, client_b.ctx.public_key);
TEST_ASSERT(status == SC_OK, "client A set peer key");
status = sc_set_peer_public_key(&client_b.ctx, client_a.ctx.public_key);
TEST_ASSERT(status == SC_OK, "client B set peer key");
// Verify session keys match
TEST_ASSERT(memcmp(client_a.ctx.session_key, client_b.ctx.session_key,
SC_SESSION_KEY_SIZE) == 0,
"session keys match");
// Register sockets with async library
uasync_add_socket(ua, client_a.sockfd, client_a_read_callback, NULL, NULL, &client_a);
uasync_add_socket(ua, client_b.sockfd, client_b_read_callback, NULL, NULL, &client_b);
// Set timeout for test completion (2 seconds)
uasync_set_timeout(ua, 20000, NULL, timeout_callback); // timebase 0.1 ms, 20000 = 2 sec
// Send encrypted message from A to B
send_encrypted_message(&client_a, &client_b);
// Run async mainloop (will exit via callback or timeout)
printf("Starting async mainloop...\n");
uasync_mainloop(ua); // This will not return
// Should not reach here
return 1;
}