From ebb5dd32cbd0f7ec3a82ec935fe6159fa98d50c5 Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 9 Feb 2026 15:49:39 -0600 Subject: [PATCH 01/10] IPsec transport support, and misc cleanup. --- .github/workflows/linux.yml | 11 + .gitignore | 1 + Makefile | 42 +- README.md | 4 +- core.md | 79 +- src/port/raspberry-pico-usb-server/README.md | 2 +- src/test/ipfilter_logger.c | 5 +- src/test/tcp_echo.c | 1 - src/test/test_dhcp_dns.c | 6 +- src/test/test_esp.c | 629 +++++++++ src/test/test_eventloop.c | 7 +- src/test/test_httpd.c | 2 - src/test/test_native_wolfssl.c | 5 +- src/wolfesp.c | 1261 ++++++++++++++++++ src/wolfip.c | 269 +++- tools/ip-xfrm/README.md | 40 + tools/ip-xfrm/cbc_auth | 63 + tools/ip-xfrm/delete_all | 3 + tools/ip-xfrm/esp_sa.txt | 10 + tools/ip-xfrm/hmac_auth | 66 + tools/ip-xfrm/rfc4106 | 58 + tools/ip-xfrm/show | 7 + tools/ip-xfrm/watch_stat | 2 + wolfesp.h | 85 ++ wolfip.h | 78 +- 25 files changed, 2592 insertions(+), 144 deletions(-) create mode 100644 src/test/test_esp.c create mode 100644 src/wolfesp.c create mode 100644 tools/ip-xfrm/README.md create mode 100755 tools/ip-xfrm/cbc_auth create mode 100755 tools/ip-xfrm/delete_all create mode 100644 tools/ip-xfrm/esp_sa.txt create mode 100755 tools/ip-xfrm/hmac_auth create mode 100755 tools/ip-xfrm/rfc4106 create mode 100755 tools/ip-xfrm/show create mode 100755 tools/ip-xfrm/watch_stat create mode 100644 wolfesp.h diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3530cab..36ba19c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,6 +31,17 @@ jobs: sudo ./build/test-evloop sudo killall tcpdump || true + - name: Run standalone "IPsec esp" test + run: | + sudo ./tools/ip-xfrm/rfc4106 128 + sudo ./build/test-esp -m 0 + sudo killall tcpdump || true + sudo ./tools/ip-xfrm/delete_all + sudo ./tools/ip-xfrm/cbc_auth sha256 128 + sudo ./build/test-esp -m 1 + sudo killall tcpdump || true + sudo ./tools/ip-xfrm/delete_all + - name: Run standalone wolfssl test run: | sudo ./build/test-wolfssl diff --git a/.gitignore b/.gitignore index 3e93391..67816ac 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ *.dis *.uf2 *.bin +*.swp CMakeCache.txt CMakeFiles CMakeScripts diff --git a/Makefile b/Makefile index 4b062c3..753aab0 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,24 @@ CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE CFLAGS+=-g -ggdb -Wdeclaration-after-statement LDFLAGS+=-pthread +# +# Debug flags: +# tap debug: +# CFLAGS+=-DDEBUG_TAP +# +# print ethernet headers: +# CFLAGS+=-DDEBUG_ETH +# +# print ip headers: +# CFLAGS+=-DDEBUG_IP +# +# print tcp headers: +# CFLAGS+=-DDEBUG_TCP +# +# print esp header data: +# CFLAGS+=-DWOLFIP_DEBUG_ESP +# + UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) UNAME_LC:=$(shell echo $(UNAME_S) | tr 'A-Z' 'a-z') @@ -105,6 +123,9 @@ OBJ=build/wolfip.o \ IPFILTER_OBJ=build/ipfilter/wolfip.o \ $(TAP_OBJ) +ESP_OBJ=build/esp/wolfip.o \ + $(TAP_OBJ) + HAVE_WOLFSSL:=$(shell printf "#include \nint main(void){return 0;}\n" | $(CC) $(CFLAGS) -x c - -c -o /dev/null 2>/dev/null && echo 1) # Require wolfSSL unless the requested goals are wolfSSL-independent (unit/cppcheck/clean). @@ -124,7 +145,7 @@ endif EXE=build/tcpecho build/tcp_netcat_poll build/tcp_netcat_select \ build/test-evloop build/test-dns build/test-wolfssl-forwarding \ build/test-ttl-expired build/test-wolfssl build/test-httpd \ - build/ipfilter-logger + build/ipfilter-logger build/test-esp LIB=libwolfip.so PREFIX=/usr/local @@ -157,6 +178,11 @@ asan: $(EXE) $(LIB) asan:CFLAGS+=-fsanitize=address asan:LDFLAGS+=-static-libasan +ESP_CFLAGS = \ + -DWOLFIP_ESP \ + -DWOLFSSL_WOLFIP \ + -DDEBUG_IP \ + -DWOLFIP_DEBUG_ESP # Test @@ -212,6 +238,20 @@ build/ipfilter/wolfip.o: src/wolfip.c build/test/ipfilter_logger.o: CFLAGS+=-DCONFIG_IPFILTER=1 +# ipsec esp +build/esp/wolfip.o: src/wolfip.c + @mkdir -p `dirname $@` || true + @echo "[CC] $< (esp)" + @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ + +build/test/test_esp.o: src/test/test_esp.c + @echo "[CC] $@" + @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ + +build/test-esp: $(ESP_OBJ) build/test/test_esp.o + @echo "[LD] $@" + @$(CC) $(CFLAGS) $(ESP_CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) + build/test-wolfssl-forwarding: build/test/test_wolfssl_forwarding.o build/test/wolfip_forwarding.o $(TAP_OBJ) build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) diff --git a/README.md b/README.md index 691b733..719de63 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ ## Description and project goals -wolfIP is a TCP/IP stack with no dynamic memory allocations, designed to be +wolfIP is a TCP/IP stack with no dynamic memory allocations, designed to be used in resource-constrained embedded systems. -Endpoint only mode is supported, which means that wolfip can be used to +Endpoint only mode is supported, which means that wolfip can be used to establish network connections but it does not route traffic between different network interfaces. diff --git a/core.md b/core.md index c8fb7b0..d95e7e8 100644 --- a/core.md +++ b/core.md @@ -24,7 +24,7 @@ ``` +---------------------------------------------------------------------------------------------------------------------------+ -| +-----+---+----+-----+------------------+-----+---+----+-----+------------------+ | +| +-----+---+----+-----+------------------+-----+---+----+-----+------------------+ | | | De | E | IP | TCP | Payload | De | E | IP | TCP | Payload | | | | sc | T | | | | sc | T | | | | | |* FREE SPACE * | ri | H | | | | ri | H | | | | * FREE SPACE* | @@ -32,11 +32,11 @@ | | or | | | | | or | | | | | | | +-----+---+----+-----+------------------+-----+---+----+-----+------------------+ | +---------------------------------------------------------------------------------------------------------------------------+ - ^ ^ - | | - | | - | | - |Tail Head| + ^ ^ + | | + | | + | | + |Tail Head| ``` @@ -54,11 +54,11 @@ | || || | | |*------------------------------------------*| | +--------------+--------------------------------------------+---------------------------------------------------------------+ - ^ ^ - | | - | | - | | - |Tail Head| + ^ ^ + | | + | | + | | + |Tail Head| ``` @@ -71,37 +71,32 @@ +-------------+ |Main loop TX | +-------------+ - ^ -+----------------------------------+ | -| | +------+ -| TCP Socket | | -| | | -| | | -| | | -| +-----------------------+ -| +---------------+ | | ->DATA OUT==>>|socket send() |-->| TX buffer (fifo) | -| +---------------+ | | -| +-----------------------+ -| | -| | -| | -| +-----------------------+ -| +-------------+ | | -DATA OUT==>>|socket send() |-->| TX buffer (fifo) | +| +---------------+ | | +| +-----------------------+ +| | +| | +| | +| +-----------------------+ +| +-------------+ | | + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* wolfip includes */ +#include "config.h" +#include "wolfip.h" +#include "wolfesp.h" + +static void __attribute__((noreturn)) print_usage_and_die(void); + +#define TEST_SIZE (12 * 1024) +#define BUFFER_SIZE TEST_SIZE + +static int disable_ipsec = 0; +static int listen_fd = -1, client_fd = -1; +static int exit_ok = 0, exit_count = 0; +static uint8_t buf[TEST_SIZE]; +static int tot_sent = 0; +static int tot_recv = 0; +static int wolfIP_closing = 0; +static int closed = 0; +static int conn_fd = -1; +static int client_connected = 0; +/* "Test pattern - -" 16 chars without trailing null. */ +static const uint8_t test_pattern[16] = {0x54, 0x65, 0x73, 0x74, 0x20, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, + 0x20, 0x2d, 0x20, 0x2d}; +static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; +static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; +static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; +static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +/* 32 byte key + 4 byte nonce*/ +static uint8_t in_enc_key[36] = + {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t out_enc_key[36] = + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t in_auth_key[16] = + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; +static uint8_t out_auth_key[16] = + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + + +/* wolfIP: server side callback. */ +static void server_cb(int fd, uint16_t event, void *arg) +{ + int ret = 0; + if ((fd == listen_fd) && (event & CB_EVENT_READABLE) && (client_fd == -1)) { + client_fd = wolfIP_sock_accept((struct wolfIP *)arg, listen_fd, NULL, + NULL); + if (client_fd > 0) { + printf("accept: %04x\n", client_fd); + } + } + else if ((fd == client_fd) && (event & CB_EVENT_READABLE )) { + ret = wolfIP_sock_recvfrom((struct wolfIP *)arg, client_fd, buf, + sizeof(buf), 0, NULL, NULL); + if (ret != -EAGAIN) { + if (ret < 0) { + printf("Recv error: %d\n", ret); + wolfIP_sock_close((struct wolfIP *)arg, client_fd); + } + else if (ret == 0) { + printf("Client side closed the connection.\n"); + wolfIP_sock_close((struct wolfIP *)arg, client_fd); + printf("Server: Exiting.\n"); + exit_ok = 1; + } + else if (ret > 0) { + printf("recv: %d, echoing back\n", ret); + tot_recv += ret; + } + } + } + if ((event & CB_EVENT_WRITABLE) || ((ret > 0) && !closed)) { + int snd_ret; + if ((tot_sent >= 4096) && wolfIP_closing) { + wolfIP_sock_close((struct wolfIP *)arg, client_fd); + printf("Server: I closed the connection.\n"); + closed = 1; + exit_ok = 1; + } + if ((!closed) && (tot_sent < tot_recv)) { + snd_ret = wolfIP_sock_sendto((struct wolfIP *)arg, client_fd, + buf + tot_sent, tot_recv - tot_sent, + 0, NULL, 0); + if (snd_ret != -EAGAIN) { + if (snd_ret < 0) { + printf("Send error: %d\n", snd_ret); + wolfIP_sock_close((struct wolfIP *)arg, client_fd); + } + else { + tot_sent += snd_ret; + printf("sent %d bytes\n", snd_ret); + if (tot_recv == tot_sent) { + tot_sent = 0; + tot_recv = 0; + } + } + } + } + } + if (event & CB_EVENT_CLOSED) { + printf("Closing %d, client fd: %d\n", fd, client_fd); + } + if ((fd == client_fd) && (event & CB_EVENT_CLOSED)) { + printf("Client side closed the connection (EVENT_CLOSED)\n"); + wolfIP_sock_close((struct wolfIP *)arg, client_fd); + client_fd = -1; + printf("Server: Exiting.\n"); + exit_ok = 1; + } + (void)arg; +} + +/* Client-side callback. */ +static void client_cb(int fd, uint16_t event, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + uint32_t i; + int ret; + static unsigned int total_r = 0, total_w = 0; + if (fd == conn_fd) { + if ((event & CB_EVENT_WRITABLE) && (client_connected == 0)) { + printf("Client: connected\n"); + client_connected = 1; + } + } + if (total_w == 0) { + for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) { + memcpy(buf + i, test_pattern, sizeof(test_pattern)); + } + } + if (client_connected && (event & CB_EVENT_WRITABLE) && + (total_w < sizeof(buf))) { + ret = wolfIP_sock_sendto(s, fd, buf + total_w, sizeof(buf) - total_w, + 0, NULL, 0); + if (ret <= 0) { + printf("Test client write: %d\n", ret); + return; + } + total_w += ret; + } + + while ((total_r < total_w) && (event & CB_EVENT_READABLE)) { + ret = wolfIP_sock_recvfrom(s, fd, buf + total_r, sizeof(buf) - total_r, + 0, NULL, NULL); + if (ret < 0){ + if (ret != -EAGAIN) { + printf("Client read: %d\n", ret); + } + return; + } + if (ret == 0) { + printf("Client read: server has closed the connection.\n"); + return; + } + total_r += ret; + printf("Client RX total: %u\n", total_r); + } + if (total_r == sizeof(buf)) { + exit_ok = 1; + for (i = 0; i < sizeof(buf); i += sizeof(test_pattern)) { + if (memcmp(buf + i, test_pattern, sizeof(test_pattern))) { + printf("test client: pattern mismatch\n"); + printf("at position %u\n", i); + buf[i + 16] = 0; + printf("%s\n", &buf[i]); + return; + } + } + if (wolfIP_closing) { + wolfIP_sock_close(s, fd); + conn_fd = -1; + } + printf("Test client: success\n"); + } +} + +/* wolfIP side: main loop of the stack under test. */ +static int test_loop(struct wolfIP *s, int active_close) +{ + exit_ok = 0; + exit_count = 0; + tot_sent = 0; + wolfIP_closing = active_close; + closed = 0; + + while(1) { + uint32_t ms_next; + struct timeval tv; + gettimeofday(&tv, NULL); + ms_next = wolfIP_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000); + usleep(ms_next * 1000); + if (exit_ok > 0) { + if (exit_count++ < 1) + continue; + else break; + } + } + return 0; +} + +/* Test code (host side). + * Thread with client to test the echoserver. + */ +static void *pt_echoclient(void *arg) +{ + int fd, ret; + unsigned total_r = 0; + unsigned i; + uint8_t local_buf[BUFFER_SIZE]; + uint32_t *srv_addr = (uint32_t *)arg; + int old_flags = -1; + fd_set wfds, rfds; + struct timeval tv; + socklen_t errlen; + int err; + struct sockaddr_in remote_sock = { + .sin_family = AF_INET, + .sin_port = ntohs(8), /* Echo */ + }; + remote_sock.sin_addr.s_addr = *srv_addr; + fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0); + if (fd < 0) { + printf("test client socket: %d\n", fd); + return (void *)-1; + } + sleep(1); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); + printf("Connecting to echo server\n"); + old_flags = fcntl(fd, F_GETFL, 0); + if (old_flags < 0) { + perror("fcntl(F_GETFL)"); + close(fd); + return (void *)-1; + } + if (fcntl(fd, F_SETFL, old_flags | O_NONBLOCK) < 0) { + perror("fcntl(F_SETFL)"); + close(fd); + return (void *)-1; + } + ret = connect(fd, (struct sockaddr *)&remote_sock, sizeof(remote_sock)); + if (ret < 0) { + err = errno; + printf("test client connect returned %d, errno=%d (%s)\n", ret, err, + strerror(err)); + if (err != EINPROGRESS) { + perror("connect"); + close(fd); + return (void *)-1; + } + printf("Waiting for connect to complete...\n"); + while (1) { + tv.tv_sec = 5; + tv.tv_usec = 0; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_SET(fd, &rfds); + FD_SET(fd, &wfds); + ret = select(fd + 1, &rfds, &wfds, NULL, &tv); + if (ret <= 0) { + printf("select returned %d (timeout or error)\n", ret); + if (ret < 0) { + perror("select"); + close(fd); + return (void *)-1; + } + } + errlen = sizeof(err); + if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) < 0) { + perror("getsockopt(SO_ERROR)"); + close(fd); + return (void *)-1; + } + if (err == 0) { + printf("connect completed after select()\n"); + break; + } + if (ret == 0) { + printf("connect still in progress after timeout\n"); + continue; + } + if (err != EINPROGRESS && err != EALREADY && err != EWOULDBLOCK && + err != EAGAIN) { + printf("connect completed with error: %d (%s)\n", err, + strerror(err)); + close(fd); + return (void *)-1; + } + } + } + else { + printf("connect returned immediately\n"); + } + if (fcntl(fd, F_SETFL, old_flags) < 0) + perror("fcntl(restore)"); + printf("test client: connect succeeded\n"); + for (i = 0; i < sizeof(local_buf); i += sizeof(test_pattern)) { + memcpy(local_buf + i, test_pattern, sizeof(test_pattern)); + } + ret = write(fd, local_buf, sizeof(local_buf)); + if (ret < 0) { + int werr = errno; + printf("test client write: %d (errno=%d: %s)\n", ret, werr, + strerror(werr)); + perror("write"); + return (void *)-1; + } + printf("test client: wrote %d bytes\n", ret); + while (total_r < sizeof(local_buf)) { + ret = read(fd, local_buf + total_r, sizeof(local_buf) - total_r); + if (ret < 0) { + printf("failed test client read: %d\n", ret); + return (void *)-1; + } + if (ret == 0) { + printf("test client read: server has closed the connection.\n"); + if (wolfIP_closing) + return (void *)0; + else + return (void *)-1; + } + total_r += ret; + printf("test client: read %d bytes (total %u)\n", ret, total_r); + } + for (i = 0; i < sizeof(local_buf); i += sizeof(test_pattern)) { + if (memcmp(local_buf + i, test_pattern, sizeof(test_pattern))) { + printf("test client: pattern mismatch\n"); + printf("at position %u\n", i); + local_buf[i + 16] = 0; + printf("%s\n", &local_buf[i]); + return (void *)-1; + } + } + close(fd); + printf("Test client: success\n"); + return (void *)0; +} + +/* Test code (host side). + * Thread with echo server to test the client. + */ +static void *pt_echoserver(void *arg) +{ + int fd, ret; + unsigned total_r = 0; + uint8_t local_buf[BUFFER_SIZE]; + struct sockaddr_in local_sock = { + .sin_family = AF_INET, + .sin_port = ntohs(8), /* Echo */ + .sin_addr.s_addr = 0 + }; + wolfIP_closing = (uintptr_t)arg; + fd = socket(AF_INET, IPSTACK_SOCK_STREAM, 0); + if (fd < 0) { + printf("test server socket: %d\n", fd); + return (void *)-1; + } + local_sock.sin_addr.s_addr = inet_addr(HOST_STACK_IP); + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); + ret = bind(fd, (struct sockaddr *)&local_sock, sizeof(local_sock)); + if (ret < 0) { + printf("test server bind: %d (%s)\n", ret, strerror(errno)); + return (void *)-1; + } + ret = listen(fd, 1); + if (ret < 0) { + printf("test server listen: %d\n", ret); + return (void *)-1; + } + printf("Waiting for client\n"); + ret = accept(fd, NULL, NULL); + if (ret < 0) { + printf("test server accept: %d\n", ret); + return (void *)-1; + } + printf("test server: client %d connected\n", ret); + fd = ret; + while (1) { + ret = read(fd, local_buf + total_r, sizeof(local_buf) - total_r); + if (ret < 0) { + printf("failed test server read: %d (%s) \n", ret, strerror(errno)); + return (void *)-1; + } + if (ret == 0) { + printf("test server read: client has closed the connection.\n"); + if (wolfIP_closing) + return (void *)0; + else + return (void *)-1; + } + total_r += ret; + write(fd, local_buf + total_r - ret, ret); + } +} + +/* Catch-all function to initialize a new tap device as the network interface. + * This is defined in port/posix/bsd_socket.c + * */ +extern int tap_init(struct wolfIP_ll_dev *dev, const char *name, + uint32_t host_ip); + +/* Test cases */ + +static void test_wolfip_echoserver(struct wolfIP *s, uint32_t srv_ip) +{ + int ret, test_ret = 0; + pthread_t pt; + struct wolfIP_sockaddr_in local_sock = { + .sin_family = AF_INET, + .sin_port = ee16(8), /* Echo */ + .sin_addr.s_addr = 0 + }; + printf("TCP server tests\n"); + + listen_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + printf("socket: %04x\n", listen_fd); + wolfIP_register_callback(s, listen_fd, server_cb, s); + + pthread_create(&pt, NULL, pt_echoclient, &srv_ip); + printf("Starting test: echo server close-wait\n"); + ret = wolfIP_sock_bind(s, listen_fd, (struct wolfIP_sockaddr *)&local_sock, + sizeof(local_sock)); + printf("bind: %d\n", ret); + ret = wolfIP_sock_listen(s, listen_fd, 1); + printf("listen: %d\n", ret); + ret = test_loop(s, 0); + pthread_join(pt, (void **)&test_ret); + printf("Test echo server close-wait: %d\n", ret); + printf("Test host client: %d\n", test_ret); + sleep(1); + + pthread_create(&pt, NULL, pt_echoclient, &srv_ip); + printf("Starting test: echo server active close\n"); + ret = test_loop(s, 1); + printf("Test echo server close-wait: %d\n", ret); + pthread_join(pt, (void **)&test_ret); + printf("Test host client: %d\n", test_ret); + sleep(1); + + wolfIP_sock_close(s, listen_fd); +} + +static void test_wolfip_echoclient(struct wolfIP *s) +{ + int ret, test_ret = 0; + pthread_t pt; + struct wolfIP_sockaddr_in remote_sock; + /* Client side test: client is closing the connection */ + remote_sock.sin_family = AF_INET; + remote_sock.sin_port = ee16(8); + remote_sock.sin_addr.s_addr = inet_addr(HOST_STACK_IP); + printf("TCP client tests\n"); + conn_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + printf("client socket: %04x\n", conn_fd); + wolfIP_register_callback(s, conn_fd, client_cb, s); + printf("Connecting to %s:8\n", HOST_STACK_IP); + wolfIP_sock_connect(s, conn_fd, (struct wolfIP_sockaddr *)&remote_sock, + sizeof(remote_sock)); + pthread_create(&pt, NULL, pt_echoserver, (void*)1); + printf("Starting test: echo client active close\n"); + ret = test_loop(s, 1); + printf("Test echo client active close: %d\n", ret); + pthread_join(pt, (void **)&test_ret); + printf("Test host server: %d\n", test_ret); + + if (conn_fd >= 0) { + wolfIP_sock_close(s, conn_fd); + conn_fd = -1; + } +} + +/* Main test function. */ +int main(int argc, char **argv) +{ + struct wolfIP_ll_dev * tapdev = NULL; + struct wolfIP * s = NULL; + struct in_addr host_stack_ip; + uint32_t srv_ip = 0; + int err = 0; + int opt = 0; + int mode = 0; /* 0 aead example, 1 cbc-auth example*/ + + while ((opt = getopt(argc, argv, "pm:?")) != -1) { + switch (opt) { + case 'p': + disable_ipsec = 1; + break; + case 'm': + mode = atoi(optarg); + break; + case '?': + print_usage_and_die(); + break; + default: + break; + } + } + + if (!disable_ipsec) { + err = wolfIP_esp_init(); + if (err) { + perror("esp_init"); + return 2; + } + } + + wolfIP_init_static(&s); + tapdev = wolfIP_getdev(s); + if (!tapdev) { + perror("wolfIP_getdev"); + return 1; + } + + inet_aton(HOST_STACK_IP, &host_stack_ip); + if (tap_init(tapdev, "wtcp0", host_stack_ip.s_addr) < 0) { + perror("tap init"); + return 2; + } + { +#if !defined(__FreeBSD__) && !defined(__APPLE__) + char cmd[128]; + snprintf(cmd, sizeof(cmd), "tcpdump -i %s -w test.pcap &", + tapdev->ifname); + system(cmd); +#else + (void)tapdev; +#endif + } + + wolfIP_ipconfig_set(s, atoip4(WOLFIP_IP), atoip4("255.255.255.0"), + atoip4(HOST_STACK_IP)); + printf("IP: manually configured\n"); + inet_pton(AF_INET, WOLFIP_IP, &srv_ip); + + if (!disable_ipsec) { + switch (mode) { + case 0: + err = wolfIP_esp_sa_new_aead(1, in_sa_gcm, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key)); + + err = wolfIP_esp_sa_new_aead(0, out_sa_gcm, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key)); + break; + + case 1: + err = wolfIP_esp_sa_new_cbc_sha256(1, in_sa_cbc, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key) - 4, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); + + err = wolfIP_esp_sa_new_cbc_sha256(0, out_sa_cbc, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key) - 4, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); + break; + + default: + break; + } + } + + /* Server side test */ + test_wolfip_echoserver(s, srv_ip); + + /* Client side test */ + test_wolfip_echoclient(s); + +#if !defined(__FreeBSD__) && !defined(__APPLE__) + system("killall tcpdump"); +#endif + return 0; +} + +static void +print_usage_and_die(void) +{ + printf("./test-esp [-m ] [-p]\n"); + printf("\n"); + printf("options:\n"); + printf(" -p force plaintext (disable ipsec)\n"); + printf(" -m 0 aead (default), 1 cbc auth\n"); + exit(1); +} diff --git a/src/test/test_eventloop.c b/src/test/test_eventloop.c index d3eef06..dde8eb6 100644 --- a/src/test/test_eventloop.c +++ b/src/test/test_eventloop.c @@ -47,8 +47,10 @@ static int wolfIP_closing = 0; static int closed = 0; static int conn_fd = -1; static int client_connected = 0; -static const uint8_t test_pattern[16] = "Test pattern - -"; - +/* "Test pattern - -" 16 chars without trailing null. */ +static const uint8_t test_pattern[16] = {0x54, 0x65, 0x73, 0x74, 0x20, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, + 0x20, 0x2d, 0x20, 0x2d}; /* wolfIP: server side callback. */ @@ -176,7 +178,6 @@ static void client_cb(int fd, uint16_t event, void *arg) } } - /* wolfIP side: main loop of the stack under test. */ static int test_loop(struct wolfIP *s, int active_close) { diff --git a/src/test/test_httpd.c b/src/test/test_httpd.c index fc8058f..bae5e1b 100644 --- a/src/test/test_httpd.c +++ b/src/test/test_httpd.c @@ -41,8 +41,6 @@ static int wolfIP_closing = 0; static int closed = 0; - - /* wolfIP side: main loop of the stack under test. */ static int test_loop(struct wolfIP *s, int active_close) { diff --git a/src/test/test_native_wolfssl.c b/src/test/test_native_wolfssl.c index 7c5e993..41b8504 100644 --- a/src/test/test_native_wolfssl.c +++ b/src/test/test_native_wolfssl.c @@ -44,7 +44,10 @@ static int tot_sent = 0; static int tot_recv = 0; static int wolfIP_closing = 0; static int closed = 0; -static const uint8_t test_pattern[16] = "Test pattern - -"; +/* "Test pattern - -" 16 chars without trailing null. */ +static const uint8_t test_pattern[16] = {0x54, 0x65, 0x73, 0x74, 0x20, 0x70, + 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, + 0x20, 0x2d, 0x20, 0x2d}; static WOLFSSL_CTX *server_ctx = NULL; /* Used by wolfIP */ static WOLFSSL_CTX *client_ctx = NULL; /* Used by Linux */ diff --git a/src/wolfesp.c b/src/wolfesp.c new file mode 100644 index 0000000..1326bef --- /dev/null +++ b/src/wolfesp.c @@ -0,0 +1,1261 @@ +#if defined(WOLFIP_ESP) && !defined(WOLFESP_SRC) +#define WOLFESP_SRC +#include "wolfesp.h" +static WC_RNG wc_rng; +static volatile int rng_inited = 0; +/* security association static pool*/ +static wolfIP_esp_sa in_sa_list[WOLFIP_ESP_NUM_SA]; +static wolfIP_esp_sa out_sa_list[WOLFIP_ESP_NUM_SA]; +static uint16_t in_sa_num = WOLFIP_ESP_NUM_SA; +static uint16_t out_sa_num = WOLFIP_ESP_NUM_SA; + +int wolfIP_esp_init(void) +{ + int err = 0; + + memset(in_sa_list, 0, sizeof(in_sa_list)); + memset(out_sa_list, 0, sizeof(out_sa_list)); + + if (rng_inited == 0) { + err = wc_InitRng_ex(&wc_rng, NULL, INVALID_DEVID); + + if (err) { + printf("error: wc_InitRng_ex: %d\n", err); + } + else { + rng_inited = 1; + } + } + + return err; +} + +void wolfIP_esp_sa_del(void) +{ + memset(in_sa_list, 0, sizeof(in_sa_list)); + memset(out_sa_list, 0, sizeof(out_sa_list)); + return ; +} + +int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len) +{ + wolfIP_esp_sa * new_sa = NULL; + wolfIP_esp_sa * list = NULL; + size_t i = 0; + uint8_t empty_sa[4] = {0x00, 0x00, 0x00, 0x00}; + int err = 0; + + in = (in == 0 ? 0 : 1); + + if (in == 1) { + list = in_sa_list; + } + else { + list = out_sa_list; + } + + for (i = 0; i < WOLFIP_ESP_NUM_SA; ++i) { + if (memcmp(list[i].spi, empty_sa, ESP_SPI_LEN) == 0) { + new_sa = &list[i]; + break; + } + } + + if (new_sa == NULL) { + printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + return -1; + } + + memcpy(new_sa->spi, spi, ESP_SPI_LEN); + new_sa->src = src; + new_sa->dst = dst; + esp_replay_init(new_sa->replay); + new_sa->enc = ESP_ENC_GCM_RFC4106; + memcpy(new_sa->enc_key, enc_key, enc_key_len); + new_sa->enc_key_len = enc_key_len; + new_sa->auth = ESP_AUTH_GCM_RFC4106; + new_sa->icv_len = ESP_GCM_RFC4106_ICV_LEN; + + /* Generate pre-iv for gcm. */ + err = wc_RNG_GenerateBlock(&wc_rng, new_sa->pre_iv, + ESP_GCM_RFC4106_IV_LEN); + if (err) { + printf("error: wc_RNG_GenerateBlock: %d\n", err); + } + + if (err) { + memset(new_sa, 0, sizeof(*new_sa)); + err = -1; + } + + #ifdef WOLFIP_DEBUG_ESP + printf("info: esp_sa_new_aead: %s, %zu\n", in == 1 ? "in" : "out", + i); + #endif /* WOLFIP_DEBUG_ESP */ + + return err; +} + +int wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len, + uint8_t * auth_key, uint8_t auth_key_len, + uint8_t icv_len) +{ + wolfIP_esp_sa * new_sa = NULL; + wolfIP_esp_sa * list = NULL; + size_t i = 0; + uint8_t empty_sa[4] = {0x00, 0x00, 0x00, 0x00}; + int err = 0; + + in = (in == 0 ? 0 : 1); + + if (in == 1) { + list = in_sa_list; + } + else { + list = out_sa_list; + } + + for (i = 0; i < WOLFIP_ESP_NUM_SA; ++i) { + if (memcmp(list[i].spi, empty_sa, ESP_SPI_LEN) == 0) { + new_sa = &list[i]; + break; + } + } + + if (new_sa == NULL) { + printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + return -1; + } + + memcpy(new_sa->spi, spi, ESP_SPI_LEN); + new_sa->src = src; + new_sa->dst = dst; + esp_replay_init(new_sa->replay); + new_sa->enc = ESP_ENC_CBC_AES; + memcpy(new_sa->enc_key, enc_key, enc_key_len); + new_sa->enc_key_len = enc_key_len; + new_sa->auth = ESP_AUTH_SHA256_RFC4868; + memcpy(new_sa->auth_key, auth_key, auth_key_len); + new_sa->auth_key_len = auth_key_len; + new_sa->icv_len = icv_len; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: esp_sa_new_cbc_sha256: %s, %zu\n", in == 1 ? "in" : "out", + i); + #endif /* WOLFIP_DEBUG_ESP */ + + return err; +} + +static uint8_t +esp_block_len_from_enc(esp_enc_t enc) +{ + uint8_t block_len = 0; + + switch (enc) { + case ESP_ENC_NONE: + block_len = 0; + break; + case ESP_ENC_CBC_AES: + block_len = AES_BLOCK_SIZE; + break; + #ifndef NO_DES3 + case ESP_ENC_CBC_DES3: + block_len = DES_BLOCK_SIZE; + break; + #endif /* !NO_DES3 */ + case ESP_ENC_GCM_RFC4106: + case ESP_ENC_GCM_RFC4543: + default: + block_len = 0; + break; + } + + return block_len; +} + +static uint8_t +esp_iv_len_from_enc(esp_enc_t enc) +{ + uint8_t iv_len = 0; + + switch (enc) { + case ESP_ENC_CBC_AES: + iv_len = ESP_CBC_RFC3602_IV_LEN; + break; + + case ESP_ENC_GCM_RFC4106: + case ESP_ENC_GCM_RFC4543: + iv_len = ESP_GCM_RFC4106_IV_LEN; + break; + + case ESP_ENC_NONE: + default: + iv_len = 0; + break; + } + + return iv_len; +} + +#ifdef WOLFIP_DEBUG_ESP +#define esp_print_sep \ + printf("+------------------+\n") +#define esp_str_4hex \ + "| %02x %02x %02x %02x |" +#define esp_str_skip \ + "| .. .. .. .. |" +#define esp_pad_fld \ + "| %02x%02x | %02d | 0x%02x |" + +static inline void +esp_print_field(const char * fld, const uint8_t * val, + uint32_t val_len) +{ + esp_print_sep; + printf(esp_str_4hex " (%s, %d bytes)\n", + val[0], val[1], val[2], val[3], fld, val_len); + if (val_len > 4) { + for (size_t i = 4; i < val_len; i += 4) { + if (i > 16 || (i + 4) > val_len) { + printf(esp_str_skip "\n"); + break; + } + + printf(esp_str_4hex"\n", + val[0 + i], val[1 + i], val[2 + i], val[3 + i]); + } + } + return; +} + +/** + * Print an ESP packet. + * _______________________________________________ + * |orig IP hdr | ESP | UDP | | ESP | ESP | + * |(PROTO=50) | hdr | hdr | Data | Trailer | ICV | + * ----------------------------------------------- + * |<---- encrypted ----->| + * |<--- integrity checked ---->| + * */ +static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, + const uint8_t * esp_data, uint32_t esp_len, + uint8_t pad_len, uint8_t nxt_hdr) +{ + const uint8_t * spi = esp_data; + const uint8_t * seq = esp_data + ESP_SPI_LEN; + const uint8_t * payload = esp_data + ESP_SPI_LEN + ESP_SEQ_LEN; + const uint8_t * iv = NULL; + const uint8_t * icv = NULL; + uint8_t iv_len = 0; + const uint8_t * padding = NULL; + uint32_t payload_len = esp_len - ESP_SPI_LEN - ESP_SEQ_LEN + - pad_len - ESP_PADDING_LEN + - ESP_NEXT_HEADER_LEN ; + + iv_len = esp_iv_len_from_enc(esp_sa->enc); + + if (iv_len) { + iv = payload; + payload += iv_len; + payload_len -= iv_len; + } + + if (esp_sa->icv_len) { + icv = esp_data + esp_len - esp_sa->icv_len; + } + + /* last 2 bytes of padding */ + padding = esp_data + esp_len - esp_sa->icv_len - 4; + + printf("esp packet: (%d bytes)\n", esp_len); + + /** ESP header + * ______________ + * | SPI | Seq | + * | | Number | + * -------------- */ + esp_print_field("spi", spi, ESP_SPI_LEN); + esp_print_field("seq", seq, ESP_SEQ_LEN); + + /** + * ESP payload (includes IV). + * */ + if (iv) { + esp_print_field("iv", iv, iv_len); + } + + esp_print_field("payload", payload, payload_len); + + /** ESP trailer + * _____________________________________ + * | Padding | Pad | Next | + * | (variable length) | Length | Header | + * ------------------------------------- */ + esp_print_sep; + printf(esp_pad_fld " (padding last 2 bytes, pad len, nxt hdr)\n", + padding[0], padding[1], pad_len, nxt_hdr); + + if (icv) { + esp_print_field("icv", icv, esp_sa->icv_len); + } + + esp_print_sep; + + return; +} +#endif /* WOLFIP_DEBUG_ESP */ + +/* + * esp_data covers from start of ESP header to end of ESP trailer, but does not + * include the ESP ICV after trailer. + * */ +static int +esp_calc_icv_hmac(uint8_t * hash, const wolfIP_esp_sa * esp_sa, + const uint8_t * esp_data, uint32_t esp_len) +{ + /* SHA1 and MD5 have these digest sizes: + * - WC_SHA_DIGEST_SIZE 20 bytes + * - WC_MD5_DIGEST_SIZE 16 bytes + * */ + Hmac hmac; + int err = 0; + int type = 0; + uint32_t auth_len = esp_len; + + switch (esp_sa->auth) { + case ESP_AUTH_MD5_RFC2403: + type = WC_MD5; + break; + case ESP_AUTH_SHA1_RFC2404: + type = WC_SHA; + break; + case ESP_AUTH_SHA256_RFC4868: + type = WC_SHA256; + break; + case ESP_AUTH_NONE: + default: + printf("error: esp_calc_icv_hmac: invalid auth: %d\n", + esp_sa->auth); + return -1; + } + + /* the icv is not included in icv calculation. */ + auth_len = esp_len - esp_sa->icv_len; + + err = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + + if (err) { + printf("error: wc_HmacSetKey: %d\n", err); + goto calc_icv_hmac_end; + } + + err = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, + esp_sa->auth_key_len); + if (err) { + printf("error: wc_HmacSetKey: %d\n", err); + goto calc_icv_hmac_end; + } + + /* Now calculate the ICV. The ICV covers from SPI to Next Header, + * inclusive. */ + err = wc_HmacUpdate(&hmac, (const byte *)esp_data, auth_len); + if (err) { + printf("error: wc_HmacUpdate: %d\n", err); + goto calc_icv_hmac_end; + } + + err = wc_HmacFinal(&hmac, hash); + if (err) { + printf("error: wc_HmacFinal: %d\n", err); + goto calc_icv_hmac_end; + } + +calc_icv_hmac_end: + wc_HmacFree(&hmac); + + return err; +} + +/* From wolfcrypt misc.c */ +static int +esp_const_memcmp(const uint8_t * vec_a, const uint8_t * vec_b, uint32_t len) +{ + uint32_t i = 0; + int sum = 0; + + for (i = 0; i < len; i++) { + sum |= vec_a[i] ^ vec_b[i]; + } + + return sum; +} + +/** + * Get the encryption length for an ESP payload. + * */ +#define esp_enc_len(esp_len, iv_len, icv_len) \ + (esp_len) - ESP_SPI_LEN - ESP_SEQ_LEN \ + - (iv_len) - (icv_len) + +/** + * Get pointer to raw encryption ESP IV, skipping ESP header. + * */ +#define esp_enc_iv(data, iv_len) \ + (data) + ESP_SPI_LEN + ESP_SEQ_LEN + +/** + * Get pointer to raw encryption ESP ICV. + * */ +#define esp_enc_icv(data, esp_len, icv_len) \ + (data) + (esp_len) - (icv_len) + +/** + * Get pointer to raw encryption ESP payload, skipping ESP header and IV. + * */ +#define esp_enc_payload(data, iv_len) \ + (data) + ESP_SPI_LEN + ESP_SEQ_LEN + (iv_len) + +static int +esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Aes cbc_dec; + int ret = -1; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_CBC_RFC3602_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: aes cbc dec: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + + ret = wc_AesInit(&cbc_dec, NULL, INVALID_DEVID); + + if (ret != 0) { + printf("error: wc_AesInit returned: %d\n", ret); + goto aes_dec_out; + } + + inited = 1; + ret = wc_AesSetKey(&cbc_dec, esp_sa->enc_key, esp_sa->enc_key_len, + iv, AES_DECRYPTION); + + if (ret != 0) { + printf("error: wc_AesSetKey returned: %d\n", ret); + goto aes_dec_out; + } + + /* decrypt in place. */ + ret = wc_AesCbcDecrypt(&cbc_dec, enc_payload, enc_payload, enc_len); + + if (ret != 0) { + printf("error: wc_AesCbcDecrypt returned: %d\n", ret); + goto aes_dec_out; + } + +aes_dec_out: + if (inited) { + wc_AesFree(&cbc_dec); + inited = 0; + } + + return ret; +} + +static int +esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Aes cbc_enc; + int ret = -1; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_CBC_RFC3602_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: aes cbc enc: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + + /* Generate random iv block for cbc method. */ + ret = wc_RNG_GenerateBlock(&wc_rng, iv, iv_len); + + if (ret) { + printf("error: wc_RNG_GenerateBlock returned: %d\n", ret); + goto aes_enc_out; + } + + ret = wc_AesInit(&cbc_enc, NULL, INVALID_DEVID); + + if (ret != 0) { + printf("error: wc_AesInit returned: %d\n", ret); + goto aes_enc_out; + } + + inited = 1; + ret = wc_AesSetKey(&cbc_enc, esp_sa->enc_key, esp_sa->enc_key_len, + iv, AES_ENCRYPTION); + + if (ret != 0) { + printf("error: wc_AesSetKey returned: %d\n", ret); + goto aes_enc_out; + } + + ret = wc_AesCbcEncrypt(&cbc_enc, enc_payload, enc_payload, enc_len); + + if (ret != 0) { + printf("error: wc_AesCbcEncrypt returned: %d\n", ret); + goto aes_enc_out; + } + +aes_enc_out: + if (inited) { + wc_AesFree(&cbc_enc); + inited = 0; + } + + return ret; +} + +/** + * AES-GCM-ESP + * The KEYMAT requested for each AES-GCM key is N + 4 octets. The first + * N octets are the AES key, and the remaining four octets are used as the + * salt value in the nonce. + * */ +#define esp_rfc4106_salt(esp_sa) (esp_sa)->enc_key \ + + (esp_sa)->enc_key_len \ + - ESP_GCM_RFC4106_SALT_LEN + +static int +esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Aes gcm_dec; + int err = -1; + uint8_t * icv = NULL; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_GCM_RFC4106_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + uint8_t aad[ESP_SPI_LEN + ESP_SEQ_LEN]; + uint16_t aad_len = sizeof(aad); + const uint8_t * salt = NULL; + uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; + uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ + + #ifdef WOLFIP_DEBUG_ESP + printf("info: aes gcm dec: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + /* get enc payload, iv, and icv pointers. */ + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); + + /* Get the salt, aad, and construct nonce. */ + salt = esp_rfc4106_salt(esp_sa); + memcpy(aad, esp_data, sizeof(aad)); + memcpy(nonce, salt, salt_len); + memcpy(nonce + salt_len, iv, iv_len); + + err = wc_AesInit(&gcm_dec, NULL, INVALID_DEVID); + + if (err != 0) { + printf("error: wc_AesInit: %d\n", err); + goto rfc4106_dec_out; + } + + inited = 1; + + /* subtract 4 byte salt from enc_key_len */ + err = wc_AesGcmInit(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4, + nonce, sizeof(nonce)); + + if (err != 0) { + printf("error: wc_AesGcmInit: %d\n", err); + goto rfc4106_dec_out; + } + + err = wc_AesGcmSetKey(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4); + + if (err != 0) { + printf("error: wc_AesGcmSetKey: %d\n", err); + goto rfc4106_dec_out; + } + + err = wc_AesGcmDecrypt(&gcm_dec, enc_payload, enc_payload, enc_len, + nonce, sizeof(nonce), icv, icv_len, aad, aad_len); + + if (err != 0) { + printf("error: wc_AesGcmDecrypt: %d\n", err); + goto rfc4106_dec_out; + } + +rfc4106_dec_out: + if (inited) { + wc_AesFree(&gcm_dec); + inited = 0; + } + + return err; +} + +static int +esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Aes gcm_enc; + int err = -1; + uint8_t * icv = NULL; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_GCM_RFC4106_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + uint8_t aad[ESP_SPI_LEN + ESP_SEQ_LEN]; + uint16_t aad_len = sizeof(aad); + const uint8_t * salt = NULL; + uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; + uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ + + #ifdef WOLFIP_DEBUG_ESP + printf("info: aes gcm enc: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + /* get enc payload, iv, and icv pointers. */ + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); + + /* Get the salt, aad. */ + salt = esp_rfc4106_salt(esp_sa); + memcpy(aad, esp_data, sizeof(aad)); + + { + /* Deterministic iv construction using pre-iv salt and sequence number. + * NIST SP 800-38D, section 8.2.1 Deterministic Construction, using + * an integer counter. The sequence number is used as a counter, and + * xor'ed with pre-iv salt. Based on linux kernel crypto/seqiv.c. + * */ + uint32_t seq_num = 0; + uint8_t * seq_num_u8 = (uint8_t *) &seq_num; + + seq_num = ee32(esp_sa->replay.oseq); + + /* copy in the pre_iv. */ + memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); + + /* xor pre-iv salt with current sequence number. */ + for (size_t i = 0; i < sizeof(uint32_t); ++i) { + iv[i + sizeof(uint32_t)] ^= seq_num_u8[i]; + } + } + + memcpy(nonce, salt, salt_len); + memcpy(nonce + salt_len, iv, iv_len); + + err = wc_AesInit(&gcm_enc, NULL, INVALID_DEVID); + + if (err != 0) { + printf("error: wc_AesInit: %d\n", err); + goto rfc4106_enc_out; + } + + inited = 1; + + /* subtract 4 byte salt from enc_key_len */ + err = wc_AesGcmInit(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4, + nonce, sizeof(nonce)); + + if (err != 0) { + printf("error: wc_AesGcmInit: %d\n", err); + goto rfc4106_enc_out; + } + + err = wc_AesGcmSetKey(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4); + + if (err != 0) { + printf("error: wc_AesGcmSetKey: %d\n", err); + goto rfc4106_enc_out; + } + + err = wc_AesGcmEncrypt(&gcm_enc, enc_payload, enc_payload, enc_len, + nonce, sizeof(nonce), icv, icv_len, aad, aad_len); + + if (err != 0) { + printf("error: wc_AesGcmDecrypt: %d\n", err); + goto rfc4106_enc_out; + } + +rfc4106_enc_out: + if (inited) { + wc_AesFree(&gcm_enc); + inited = 0; + } + + return err; +} + +/** + * esp_data covers from start of ESP header to end of ESP trailer, but does not + * include the ESP ICV after trailer. + * */ +static int +esp_check_icv_hmac(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + /* SHA and MD5 have these digest sizes: + * - WC_MD5_DIGEST_SIZE 16 bytes + * - WC_SHA_DIGEST_SIZE 20 bytes + * - WC_SHA256_DIGEST_SIZE 32 bytes + * */ + int rc = 0; + const uint8_t * icv = NULL; + byte hash[WC_SHA256_DIGEST_SIZE]; + + rc = esp_calc_icv_hmac(hash, esp_sa, esp_data, esp_len); + if (rc) { + return rc; + } + + icv = esp_data + esp_len - esp_sa->icv_len; + + /* compare the first N bits depending on truncation type. */ + rc = esp_const_memcmp(icv, hash, esp_sa->icv_len); + return rc; +} + +/** + * Check sequence number against replay_t state. + * + * return 0 on success. + * */ +static int +esp_check_replay(struct replay_t * replay, uint32_t seq) +{ + #if !defined(ESP_REPLAY_WIN) + /* anti-replay service not enabled */ + (void)replay; + (void)seq; + #else + uint32_t diff = 0; + uint32_t bitn = 0; + uint32_t seq_low = replay->hi_seq - ESP_REPLAY_WIN; + + #if WOLFIP_DEBUG_ESP + printf("info: seq: %u\n", seq); + #endif + + if (seq == 0) { + return -1; + } + + if (seq < seq_low) { + printf("error: seq (%d) below window (%d)\n", seq, seq_low); + return -1; + } + + /* Simple 32 bit replay window: + * seq_low - - - - - - - seq - - - - - - hi_seq + * <------------ ESP_REPLAY_WIN --------------> + * */ + if (seq < replay->hi_seq) { + /* seq number within window. */ + bitn = 1U << (replay->hi_seq - seq); + + if ((replay->bitmap & bitn) != 0U) { + printf("error: seq replayed: %d, %d\n", bitn, seq); + return -1; + } + else { + #if WOLFIP_DEBUG_ESP + printf("info: new seq : %d\n", seq); + #endif + replay->bitmap |= bitn; + } + } + else { + /* seq number above window. */ + #if WOLFIP_DEBUG_ESP + printf("info: new hi_seq : %d, %d\n", replay->hi_seq, seq); + #endif + diff = seq - replay->hi_seq; + if (diff < ESP_REPLAY_WIN) { + /* within a window width, slide up. */ + replay->bitmap = replay->bitmap << diff; + } + else { + /* reset window. */ + replay->bitmap = 1; + } + + replay->hi_seq = seq; + } + #endif /* ESP_REPLAY_WIN */ + + return 0; +} + +/** + * Decapsulate an ipv4 ESP packet, transport mode. The packet is + * unwrapped in-place without extra copying. + * + * The ip.proto, ip.len, and frame_len are updated + * after unwrap. + * + * Transport Mode: + * before: + * _______________________________________________ + * |orig IP hdr | ESP | UDP | | ESP | ESP | + * |(PROTO=50) | hdr | hdr | Data | Trailer | ICV | + * ----------------------------------------------- + * |<---- encrypted ----->| + * |<--- integrity checked ---->| + * + * after: + * _________________________ + * |orig IP hdr | UDP | | + * |(PROTO=17) | hdr | Data | + * ------------------------- + * + * Returns 0 on success. + * Returns -1 on error. + * */ +static int +esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, + uint32_t * frame_len) +{ + uint8_t spi[ESP_SPI_LEN]; + uint32_t seq = 0; + wolfIP_esp_sa * esp_sa = NULL; + uint32_t esp_len = 0; + uint8_t pad_len = 0; + uint8_t nxt_hdr = 0; + uint8_t iv_len = 0; + int err = 0; + + memset(spi, 0, sizeof(spi)); + + if (*frame_len <= (ETH_HEADER_LEN + IP_HEADER_LEN)) { + #ifdef WOLFIP_DEBUG_ESP + printf("error: esp: malformed frame: %d\n", *frame_len); + #endif /* WOLFIP_DEBUG_ESP */ + return -1; + } + + esp_len = *frame_len - ETH_HEADER_LEN - IP_HEADER_LEN; + + /* If not at least SPI and sequence, something wrong. */ + if (esp_len < (ESP_SPI_LEN + ESP_SEQ_LEN)) { + #ifdef WOLFIP_DEBUG_ESP + printf("error: esp: malformed packet: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + return -1; + } + + /* First 4 bytes are the spi (Security Parameters Index). */ + memcpy(spi, ip->data, sizeof(spi)); + /* Next 4 bytes are the seq (Sequence Number).*/ + memcpy(&seq, ip->data + ESP_SPI_LEN, sizeof(seq)); + seq = ee32(seq); + + for (size_t i = 0; i < in_sa_num; ++i) { + if (memcmp(spi, in_sa_list[i].spi, sizeof(spi)) == 0) { + #ifdef WOLFIP_DEBUG_ESP + printf("info: found sa: 0x%02x%02x%02x%02x\n", + spi[0], spi[1], spi[2], spi[3]); + #endif /* WOLFIP_DEBUG_ESP */ + esp_sa = &in_sa_list[i]; + break; + } + } + + if (esp_sa == NULL) { + /* RFC4303: + * If no valid Security Association exists for this packet, the + * receiver MUST discard the packet; this is an auditable event. + * */ + printf("error: unknown spi: 0x%02x%02x%02x%02x\n", + spi[0], spi[1], spi[2], spi[3]); + return -1; + } + + err = esp_check_replay(&esp_sa->replay, seq); + if (err) { + return -1; + } + + iv_len = esp_iv_len_from_enc(esp_sa->enc); + + { + /* calculate min expected length based on the security association. */ + uint32_t min_len = 0; + + min_len = (ESP_SPI_LEN + ESP_SEQ_LEN + iv_len + + ESP_PADDING_LEN + ESP_NEXT_HEADER_LEN + esp_sa->icv_len); + + if (esp_len < min_len) { + printf("error: esp: got %d, expected >= %d frame len", esp_len, + min_len); + return -1; + } + } + + if (esp_sa->icv_len) { + switch (esp_sa->auth) { + case ESP_AUTH_MD5_RFC2403: + case ESP_AUTH_SHA1_RFC2404: + case ESP_AUTH_SHA256_RFC4868: + err = esp_check_icv_hmac(esp_sa, ip->data, esp_len); + break; + case ESP_AUTH_GCM_RFC4106: + case ESP_AUTH_GCM_RFC4543: + /* icv calculated during decrypt */ + err = 0; + break; + case ESP_AUTH_NONE: + default: + err = -1; + break; + } + + if (err) { + printf("error: icv check failed\n"); + return -1; + } + } + + /* icv check good, now finish unwrapping esp packet. */ + if (iv_len != 0) { + /* Decrypt the payload in place. */ + switch(esp_sa->enc) { + case ESP_ENC_CBC_AES: + err = esp_aes_rfc3602_dec(esp_sa, ip->data, esp_len); + break; + + case ESP_ENC_GCM_RFC4106: + err = esp_aes_rfc4106_dec(esp_sa, ip->data, esp_len); + break; + + case ESP_ENC_NONE: + default: + printf("error: decrypt: invalid enc: %d\n", esp_sa->enc); + err = -1; + break; + } + + if (err) { + printf("error: esp_decrypt(%02x) returned: %d\n", esp_sa->enc, + err); + return -1; + } + } + + /* Payload is now decrypted. We can now parse + * the ESP trailer for next header and padding. */ + pad_len = *(ip->data + esp_len - esp_sa->icv_len - ESP_NEXT_HEADER_LEN + - ESP_PADDING_LEN); + nxt_hdr = *(ip->data + esp_len - esp_sa->icv_len - ESP_NEXT_HEADER_LEN); + + #ifdef WOLFIP_DEBUG_ESP + wolfIP_print_esp(esp_sa, ip->data, esp_len, pad_len, nxt_hdr); + #endif /* WOLFIP_DEBUG_ESP */ + + /* move ip payload forward to hide ESP header (SPI, SEQ, IV). */ + memmove(ip->data, ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + iv_len, + esp_len - (ESP_SPI_LEN + ESP_SEQ_LEN + iv_len)); + + /* subtract ESP header from frame_len and ip.len. */ + *frame_len = *frame_len - (iv_len + ESP_SPI_LEN + ESP_SEQ_LEN); + ip->len = ee16(ip->len) - (iv_len + ESP_SPI_LEN + ESP_SEQ_LEN); + + /* subtract ESP trailer from frame_len and ip.len. */ + *frame_len = *frame_len - (pad_len + ESP_PADDING_LEN + + ESP_NEXT_HEADER_LEN + esp_sa->icv_len); + ip->len = ip->len - (pad_len + ESP_PADDING_LEN + + ESP_NEXT_HEADER_LEN + esp_sa->icv_len); + + /* update len, set proto to next header, recalculate iphdr checksum. */ + ip->len = ee16(ip->len); + ip->proto = nxt_hdr; + ip->csum = 0; + iphdr_set_checksum(ip); + + (void)s; + return 0; +} + +/** + * Encapsulate an ipv4 packet with ESP transport mode. + * + * Transport Mode: + * before: + * _________________________ + * |orig IP hdr | | | + * |(PROTO=17) | UDP | Data | + * ------------------------- + * + * after: + * _______________________________________________ + * |orig IP hdr | ESP | | | ESP | ESP | + * |(PROTO=50) | hdr | UDP | Data | Trailer | ICV | + * ----------------------------------------------- + * |<---- encrypted ----->| + * |<--- integrity checked ---->| + * + * Returns 0 on success. + * Returns -1 on error. + * Returns 1 if no ipsec policy found (send plaintext) + * */ +static int +esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) +{ + uint8_t block_len = 0; + uint16_t orig_ip_len = *ip_len; + uint16_t orig_payload_len = orig_ip_len - IP_HEADER_LEN; + uint16_t payload_len = 0; + uint8_t * payload = ip->data; + uint8_t pad_len = 0; + uint32_t seq_n = 0; /* sequence num in network order */ + uint16_t icv_offset = 0; + wolfIP_esp_sa * esp_sa = NULL; + uint8_t iv_len = 0; + + /* TODO: priority, tcp/udp port-filtering? currently this grabs + * the first dst match. */ + for (size_t i = 0; i < out_sa_num; ++i) { + if (ip->dst == ee32(out_sa_list[i].dst)) { + esp_sa = &out_sa_list[i]; + #ifdef WOLFIP_DEBUG_ESP + printf("info: found out sa: 0x%02x%02x%02x%02x\n", + esp_sa->spi[0], esp_sa->spi[1], esp_sa->spi[2], + esp_sa->spi[3]); + #endif /* WOLFIP_DEBUG_ESP */ + break; + } + } + + if (esp_sa == NULL) { + /* nothing to do */ + #ifdef WOLFIP_DEBUG_ESP + char ip_str[32]; + memset(ip_str, '\0', sizeof(ip_str)); + iptoa(ip->dst, ip_str); + printf("info: ip dst not found: %s\n", ip_str); + #endif /* WOLFIP_DEBUG_ESP */ + return 1; + } + + iv_len = esp_iv_len_from_enc(esp_sa->enc); + /* move ip payload back to make room for ESP header (SPI, SEQ) + IV. */ + memmove(ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + iv_len, + ip->data, orig_payload_len); + + /* Copy in SPI and sequence number fields. */ + memcpy(payload, esp_sa->spi, sizeof(esp_sa->spi)); + payload += ESP_SPI_LEN; + + seq_n = ee32(esp_sa->replay.oseq); + memcpy(payload, &seq_n, sizeof(seq_n)); + payload += ESP_SEQ_LEN; + esp_sa->replay.oseq++; + + if (iv_len) { + /* skip iv field, will generate later. */ + payload += iv_len; + } + + block_len = esp_block_len_from_enc(esp_sa->enc); + + if (block_len) { + /* Block cipher. Calculate padding and encrypted length, then + * icv_offset. */ + uint32_t enc_len = 0; + enc_len = iv_len + orig_payload_len + pad_len + + ESP_PADDING_LEN + ESP_NEXT_HEADER_LEN; + + /* Determine padding. This needs to be flexible for + * des3 (8 byte) or aes (16 byte) block sizes.*/ + if (enc_len % block_len) { + pad_len = block_len - (enc_len % block_len); + } + + icv_offset = ESP_SPI_LEN + ESP_SEQ_LEN + iv_len + + orig_payload_len + pad_len + ESP_PADDING_LEN + + ESP_NEXT_HEADER_LEN; + } + else { + /* Stream cipher or auth-only. Calculate the icv offset directly. */ + icv_offset = ESP_SPI_LEN + ESP_SEQ_LEN + iv_len + + orig_payload_len + pad_len + ESP_PADDING_LEN + + ESP_NEXT_HEADER_LEN; + + /* Determine padding. */ + if (icv_offset % ESP_ICV_ALIGNMENT) { + pad_len = ESP_ICV_ALIGNMENT - (icv_offset % ESP_ICV_ALIGNMENT); + icv_offset += pad_len; + } + } + + /* Skip past the original payload, add padding. */ + payload += orig_payload_len; + + if (pad_len) { + /* rfc4303: monotonic increasing sequence for padding. */ + uint8_t i = 0; + for (i = 0; i < pad_len; ++i) { + payload[i] = (i + 1); + } + + payload += pad_len; + } + + /* ESP trailer. Copy in padding len and next header fields. */ + memcpy(payload, &pad_len, ESP_PADDING_LEN); + payload += ESP_PADDING_LEN; + + memcpy(payload, &ip->proto, ESP_NEXT_HEADER_LEN); + payload += ESP_NEXT_HEADER_LEN; + + /* calculate final esp payload length. */ + payload_len = orig_ip_len - IP_HEADER_LEN; + payload_len += ESP_SPI_LEN + ESP_SEQ_LEN + iv_len + + pad_len + ESP_PADDING_LEN + ESP_NEXT_HEADER_LEN + + esp_sa->icv_len; + + /* encrypt from payload to end of ESP trailer. */ + if (iv_len) { + int err = -1; + + switch(esp_sa->enc) { + case ESP_ENC_CBC_AES: + err = esp_aes_rfc3602_enc(esp_sa, ip->data, payload_len); + break; + + case ESP_ENC_GCM_RFC4106: + err = esp_aes_rfc4106_enc(esp_sa, ip->data, payload_len); + break; + + case ESP_ENC_NONE: + default: + printf("error: encrypt: invalid enc: %d\n", esp_sa->enc); + err = -1; + break; + } + + if (err) { + printf("error: esp_encrypt(%02x) returned: %d\n", esp_sa->enc, + err); + return -1; + } + /* Payload is now encrypted. Now calculate ICV. */ + } + + if (esp_sa->icv_len) { + uint8_t * icv = NULL; + int err = 0; + + switch (esp_sa->auth) { + case ESP_AUTH_MD5_RFC2403: + case ESP_AUTH_SHA1_RFC2404: + case ESP_AUTH_SHA256_RFC4868: + icv = ip->data + icv_offset; + err = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); + break; + case ESP_AUTH_GCM_RFC4106: + case ESP_AUTH_GCM_RFC4543: + /* icv already calculated during encrypt */ + err = 0; + break; + case ESP_AUTH_NONE: + default: + err = -1; + break; + } + + if (err) { + printf("error: icv check failed\n"); + return -1; + } + } + + *ip_len = payload_len + IP_HEADER_LEN; + + #ifdef WOLFIP_DEBUG_ESP + wolfIP_print_esp(esp_sa, ip->data, payload_len, pad_len, ip->proto); + #endif /* WOLFIP_DEBUG_ESP */ + + return 0; +} + +/** + * Copy frame to new packet so we can expand and wrap in place + * without stepping on the fifo tcp circular buffer. + * + * A more intelligent way to do this would be to save extra scratch space + * in the fifo circular buffer for each tcp packet, so we can expand in place. + * */ +static int +esp_tcp_output(struct wolfIP_ll_dev * ll_dev, + const struct wolfIP_ip_packet *ip, + uint16_t len) +{ + /** + * 60 is reasonable max ESP overhead (for now), rounded up to 4 bytes. + * 8 bytes (esp header) + * + 16 bytes (iv, prepended to payload) + * + 15 bytes (max padding with block cipher) + * + 2 bytes (pad_len + nxt_hdr fields) + * + 16 bytes (icv) + * may need to increase depending on algs supported. + * */ + struct wolfIP_ip_packet * esp; + uint8_t frame[LINK_MTU + 60]; + uint16_t ip_final_len = len; + int esp_rc = 0; + + esp = (struct wolfIP_ip_packet *) frame; + memcpy(esp, ip, sizeof(struct wolfIP_ip_packet) + len); + + esp_rc = esp_transport_wrap(esp, &ip_final_len); + + if (esp_rc) { + #ifdef WOLFIP_DEBUG_ESP + printf("info: esp_wrap returned: %d\n", esp_rc); + #endif /* WOLFIP_DEBUG_ESP */ + return esp_rc; + } + + /* update len, set proto to ESP 0x32 (50), recalculate iphdr checksum. */ + esp->len = ee16(ip_final_len); + esp->proto = 0x32; + esp->csum = 0; + iphdr_set_checksum(esp); + + ll_dev->send(ll_dev, esp, ip_final_len + ETH_HEADER_LEN); + + return 0; +} +#endif /* WOLFIP_ESP && !WOLFESP_SRC */ diff --git a/src/wolfip.c b/src/wolfip.c index 9fcfdb2..feecdff 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -590,7 +590,10 @@ static uint32_t wolfIP_filter_mask_for_proto(uint16_t proto) } } -static int wolfIP_filter_dispatch(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const void *buffer, uint32_t length, const struct wolfIP_filter_metadata *meta) +static int wolfIP_filter_dispatch(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const void *buffer, uint32_t length, + const struct wolfIP_filter_metadata *meta) { struct wolfIP_filter_event event; int ret; @@ -625,7 +628,9 @@ static int wolfIP_filter_dispatch(enum wolfIP_filter_reason reason, struct wolfI } #ifdef ETHERNET -static int wolfIP_filter_notify_eth(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const struct wolfIP_eth_frame *eth, uint32_t len) +static int wolfIP_filter_notify_eth(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const struct wolfIP_eth_frame *eth, uint32_t len) { struct wolfIP_filter_metadata meta; @@ -641,7 +646,8 @@ static int wolfIP_filter_notify_eth(enum wolfIP_filter_reason reason, struct wol #define wolfIP_filter_notify_eth(...) (0) #endif -static void wolfIP_filter_fill_ip_metadata(struct wolfIP_filter_metadata *meta, const struct wolfIP_ip_packet *ip) +static void wolfIP_filter_fill_ip_metadata(struct wolfIP_filter_metadata *meta, + const struct wolfIP_ip_packet *ip) { meta->src_ip = ip->src; meta->dst_ip = ip->dst; @@ -656,7 +662,9 @@ static void wolfIP_filter_fill_ip_metadata(struct wolfIP_filter_metadata *meta, #endif } -static int wolfIP_filter_notify_ip(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const struct wolfIP_ip_packet *ip, uint32_t len) +static int wolfIP_filter_notify_ip(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const struct wolfIP_ip_packet *ip, uint32_t len) { struct wolfIP_filter_metadata meta; @@ -670,7 +678,9 @@ static int wolfIP_filter_notify_ip(enum wolfIP_filter_reason reason, struct wolf return wolfIP_filter_dispatch(reason, s, if_idx, ip, len, &meta); } -static int wolfIP_filter_notify_tcp(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const struct wolfIP_tcp_seg *tcp, uint32_t len) +static int wolfIP_filter_notify_tcp(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const struct wolfIP_tcp_seg *tcp, uint32_t len) { struct wolfIP_filter_metadata meta; @@ -684,7 +694,9 @@ static int wolfIP_filter_notify_tcp(enum wolfIP_filter_reason reason, struct wol return wolfIP_filter_dispatch(reason, s, if_idx, tcp, len, &meta); } -static int wolfIP_filter_notify_udp(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const struct wolfIP_udp_datagram *udp, uint32_t len) +static int wolfIP_filter_notify_udp(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const struct wolfIP_udp_datagram *udp, uint32_t len) { struct wolfIP_filter_metadata meta; @@ -697,7 +709,9 @@ static int wolfIP_filter_notify_udp(enum wolfIP_filter_reason reason, struct wol return wolfIP_filter_dispatch(reason, s, if_idx, udp, len, &meta); } -static int wolfIP_filter_notify_icmp(enum wolfIP_filter_reason reason, struct wolfIP *s, unsigned int if_idx, const struct wolfIP_icmp_packet *icmp, uint32_t len) +static int wolfIP_filter_notify_icmp(enum wolfIP_filter_reason reason, + struct wolfIP *s, unsigned int if_idx, + const struct wolfIP_icmp_packet *icmp, uint32_t len) { struct wolfIP_filter_metadata meta; @@ -823,7 +837,7 @@ struct tsocket { uint8_t last_pkt_ttl; uint8_t rxmem[RXBUF_SIZE]; uint8_t txmem[TXBUF_SIZE]; - void (*callback)(int sock_fd, uint16_t events, void *arg); + tsocket_cb callback; void *callback_arg; }; static void close_socket(struct tsocket *ts); @@ -858,8 +872,9 @@ struct arp_pending_entry { static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *mac); #if WOLFIP_ENABLE_FORWARDING -static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct wolfIP_ip_packet *ip, - uint32_t len, const uint8_t *mac, int broadcast); +static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, + struct wolfIP_ip_packet *ip, uint32_t len, + const uint8_t *mac, int broadcast); #endif #endif @@ -879,8 +894,8 @@ struct timers_binheap { uint32_t size; }; -struct wolfIP -{ +/* The main wolfip stack context structure. */ +struct wolfIP { struct wolfIP_ll_dev ll_dev[WOLFIP_MAX_INTERFACES]; struct ipconf ipconf[WOLFIP_MAX_INTERFACES]; unsigned int if_count; @@ -1114,8 +1129,9 @@ static unsigned int wolfIP_if_for_local_ip(struct wolfIP *s, ip4 local_ip, int * #ifdef ETHERNET static uint16_t icmp_checksum(struct wolfIP_icmp_packet *icmp, uint16_t len); static void iphdr_set_checksum(struct wolfIP_ip_packet *ip); -static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, - uint16_t type); +static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, + const uint8_t *dst, struct wolfIP_eth_frame *eth, + uint16_t type); #endif #if WOLFIP_ENABLE_FORWARDING && defined(ETHERNET) static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip); @@ -1123,7 +1139,8 @@ static int arp_lookup(struct wolfIP *s, unsigned int if_idx, ip4 ip, uint8_t *ma #endif #ifdef ETHERNET -static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) +static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, + struct wolfIP_ip_packet *orig) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); struct wolfIP_icmp_ttl_exceeded_packet icmp = {0}; @@ -1157,7 +1174,8 @@ static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, stru ll->send(ll, &icmp, sizeof(icmp)); } #else -static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *orig) +static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, + struct wolfIP_ip_packet *orig) { (void)s; (void)if_idx; @@ -1166,7 +1184,8 @@ static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, stru #endif /* User Callbacks */ -void wolfIP_register_callback(struct wolfIP *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg) +void wolfIP_register_callback(struct wolfIP *s, int sock_fd, tsocket_cb cb, + void *arg) { struct tsocket *t; if (sock_fd < 0) @@ -1284,7 +1303,8 @@ static struct tsocket *udp_new_socket(struct wolfIP *s) return NULL; } -static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_udp_datagram *udp, uint32_t frame_len) +static void udp_try_recv(struct wolfIP *s, unsigned int if_idx, + struct wolfIP_udp_datagram *udp, uint32_t frame_len) { struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); int i; @@ -1343,7 +1363,8 @@ static struct tsocket *icmp_new_socket(struct wolfIP *s) return NULL; } -static void icmp_try_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_icmp_packet *icmp, uint32_t frame_len) +static void icmp_try_recv(struct wolfIP *s, unsigned int if_idx, + struct wolfIP_icmp_packet *icmp, uint32_t frame_len) { int i; ip4 src_ip = ee32(icmp->ip.src); @@ -1642,7 +1663,8 @@ static void iphdr_set_checksum(struct wolfIP_ip_packet *ip) } #ifdef ETHERNET -static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const uint8_t *dst, struct wolfIP_eth_frame *eth, +static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, + const uint8_t *dst, struct wolfIP_eth_frame *eth, uint16_t type) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(S, if_idx); @@ -1661,8 +1683,13 @@ static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const ui } #endif +#ifdef WOLFIP_ESP +#include "src/wolfesp.c" +#endif /* WOLFIP_ESP */ + #if WOLFIP_ENABLE_FORWARDING -static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 dest, uint8_t *mac, int *broadcast) +static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, + ip4 dest, uint8_t *mac, int *broadcast) { #ifdef ETHERNET if (!broadcast || !mac) @@ -1693,7 +1720,9 @@ static int wolfIP_forward_prepare(struct wolfIP *s, unsigned int out_if, ip4 des #endif } -static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct wolfIP_ip_packet *ip, uint32_t len, const uint8_t *mac, int broadcast) +static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, + struct wolfIP_ip_packet *ip, uint32_t len, + const uint8_t *mac, int broadcast) { #ifdef ETHERNET struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, out_if); @@ -1705,11 +1734,14 @@ static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct else eth_output_add_header(s, out_if, mac, &ip->eth, ETH_TYPE_IP); if (ip->proto == WI_IPPROTO_TCP) - drop = wolfIP_filter_notify_tcp(WOLFIP_FILT_SENDING, s, out_if, (struct wolfIP_tcp_seg *)ip, len); + drop = wolfIP_filter_notify_tcp(WOLFIP_FILT_SENDING, s, out_if, + (struct wolfIP_tcp_seg *)ip, len); else if (ip->proto == WI_IPPROTO_UDP) - drop = wolfIP_filter_notify_udp(WOLFIP_FILT_SENDING, s, out_if, (struct wolfIP_udp_datagram *)ip, len); + drop = wolfIP_filter_notify_udp(WOLFIP_FILT_SENDING, s, out_if, + (struct wolfIP_udp_datagram *)ip, len); else if (ip->proto == WI_IPPROTO_ICMP) - drop = wolfIP_filter_notify_icmp(WOLFIP_FILT_SENDING, s, out_if, (struct wolfIP_icmp_packet *)ip, len); + drop = wolfIP_filter_notify_icmp(WOLFIP_FILT_SENDING, s, out_if, + (struct wolfIP_icmp_packet *)ip, len); if (drop != 0) return; if (wolfIP_filter_notify_ip(WOLFIP_FILT_SENDING, s, out_if, ip, len) != 0) @@ -1728,7 +1760,8 @@ static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, struct } #endif -static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, uint8_t proto, uint16_t len) +static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, + uint8_t proto, uint16_t len) { union transport_pseudo_header ph; unsigned int if_idx; @@ -1766,7 +1799,8 @@ static int ip_output_add_header(struct tsocket *t, struct wolfIP_ip_packet *ip, } #ifdef ETHERNET if_idx = wolfIP_socket_if_idx(t); - eth_output_add_header(t->S, if_idx, t->nexthop_mac, (struct wolfIP_eth_frame *)ip, ETH_TYPE_IP); + eth_output_add_header(t->S, if_idx, t->nexthop_mac, (struct wolfIP_eth_frame *)ip, + ETH_TYPE_IP); #else (void)if_idx; #endif @@ -1968,7 +2002,8 @@ static void tcp_ack(struct tsocket *t, const struct wolfIP_tcp_seg *tcp) } /* Preselect socket, parse options, manage handshakes, pass to application */ -static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_seg *tcp, uint32_t frame_len) +static void tcp_input(struct wolfIP *S, unsigned int if_idx, + struct wolfIP_tcp_seg *tcp, uint32_t frame_len) { int i; @@ -2142,7 +2177,8 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx, struct wolfIP_tcp_s } if (tcplen == 0) return; - if ((t->sock.tcp.state == TCP_LAST_ACK) || (t->sock.tcp.state == TCP_CLOSING) || (t->sock.tcp.state == TCP_CLOSED)) + if ((t->sock.tcp.state == TCP_LAST_ACK) || (t->sock.tcp.state == TCP_CLOSING) || + (t->sock.tcp.state == TCP_CLOSED)) return; tcp_recv(t, tcp); } @@ -2245,7 +2281,8 @@ int wolfIP_sock_socket(struct wolfIP *s, int domain, int type, int protocol) return -1; } -int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen) +int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, + socklen_t addrlen) { struct tsocket *ts; const struct wolfIP_sockaddr_in *sin; @@ -2715,7 +2752,8 @@ int wolfIP_sock_read(struct wolfIP *s, int sockfd, void *buf, size_t len) return wolfIP_sock_recvfrom(s, sockfd, buf, len, 0, NULL, 0); } -int wolfIP_sock_setsockopt(struct wolfIP *s, int sockfd, int level, int optname, const void *optval, socklen_t optlen) +int wolfIP_sock_setsockopt(struct wolfIP *s, int sockfd, int level, int optname, + const void *optval, socklen_t optlen) { struct tsocket *ts = wolfIP_socket_from_fd(s, sockfd); if (!ts) @@ -2743,7 +2781,8 @@ int wolfIP_sock_get_recv_ttl(struct wolfIP *s, int sockfd, int *ttl) return 1; } -int wolfIP_sock_getsockopt(struct wolfIP *s, int sockfd, int level, int optname, void *optval, socklen_t *optlen) +int wolfIP_sock_getsockopt(struct wolfIP *s, int sockfd, int level, int optname, + void *optval, socklen_t *optlen) { struct tsocket *ts = wolfIP_socket_from_fd(s, sockfd); if (!ts) @@ -2824,7 +2863,8 @@ int wolfIP_sock_close(struct wolfIP *s, int sockfd) return 0; } -int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen) +int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, + const socklen_t *addrlen) { struct tsocket *ts; struct wolfIP_sockaddr_in *sin; @@ -2864,7 +2904,8 @@ int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr return -1; } -int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen) +int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, + socklen_t addrlen) { struct tsocket *ts; ip4 bind_ip; @@ -3052,7 +3093,8 @@ int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog) return 0; } -int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen) +int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, + const socklen_t *addrlen) { struct tsocket *ts; struct wolfIP_sockaddr_in *sin = (struct wolfIP_sockaddr_in *)addr; @@ -3075,7 +3117,8 @@ int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr /* Reply to ICecho requests */ -static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) +static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, + uint32_t len) { struct wolfIP_icmp_packet *icmp = (struct wolfIP_icmp_packet *)ip; uint32_t tmp; @@ -3153,6 +3196,18 @@ static void dhcp_cancel_timer(struct wolfIP *s) } } +#define DHCP_OPT_data_to_u32(opt) \ + (opt)->data[0] | ((opt)->data[1] << 8) | \ + ((opt)->data[2] << 16) | ((opt)->data[3] << 24); + +#define DHCP_OPT_u32_to_data(opt, v) \ + do { \ + (opt)->data[0] = ((v) >> 24) & 0xFF; \ + (opt)->data[1] = ((v) >> 16) & 0xFF; \ + (opt)->data[2] = ((v) >> 8) & 0xFF; \ + (opt)->data[3] = ((v) >> 0) & 0xFF; \ + } while (0) + static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) { struct dhcp_option *opt = (struct dhcp_option *)(msg->options); @@ -3165,11 +3220,11 @@ static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) opt = (struct dhcp_option *)((uint8_t *)opt + 3); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) { - uint32_t data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24); + uint32_t data = DHCP_OPT_data_to_u32(opt); s->dhcp_server_ip = ee32(data); } if (opt->code == DHCP_OPTION_SUBNET_MASK) { - netmask = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24); + netmask = DHCP_OPT_data_to_u32(opt); } opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); @@ -3204,7 +3259,7 @@ static int dhcp_parse_ack(struct wolfIP *s, struct dhcp_msg *msg) if (opt->data[0] == DHCP_ACK) { uint32_t data; opt = (struct dhcp_option *)((uint8_t *)opt + 3); - data = opt->data[0] | (opt->data[1] << 8) | (opt->data[2] << 16) | (opt->data[3] << 24); + data = DHCP_OPT_data_to_u32(opt); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); @@ -3238,7 +3293,8 @@ static int dhcp_poll(struct wolfIP *s) struct dhcp_msg msg; int len; memset(&msg, 0xBB, sizeof(msg)); - len = wolfIP_sock_recvfrom(s, s->dhcp_udp_sd, &msg, sizeof(struct dhcp_msg), 0, (struct wolfIP_sockaddr *)&sin, &sl); + len = wolfIP_sock_recvfrom(s, s->dhcp_udp_sd, &msg, sizeof(struct dhcp_msg), 0, + (struct wolfIP_sockaddr *)&sin, &sl); if (len < 0) return -1; if ((s->dhcp_state == DHCP_DISCOVER_SENT) && (dhcp_parse_offer(s, &msg) == 0)) @@ -3296,18 +3352,12 @@ static int dhcp_send_request(struct wolfIP *s) opt = (struct dhcp_option *)((uint8_t *)opt + 5); opt->code = DHCP_OPTION_SERVER_ID; /* Server ID */ opt->len = 4; - opt->data[0] = (s->dhcp_server_ip >> 24) & 0xFF; - opt->data[1] = (s->dhcp_server_ip >> 16) & 0xFF; - opt->data[2] = (s->dhcp_server_ip >> 8) & 0xFF; - opt->data[3] = (s->dhcp_server_ip >> 0) & 0xFF; + DHCP_OPT_u32_to_data(opt, s->dhcp_server_ip); opt_sz += 6; opt = (struct dhcp_option *)((uint8_t *)opt + 6); opt->code = DHCP_OPTION_OFFER_IP; /* Requested IP */ opt->len = 4; - opt->data[0] = (s->dhcp_ip >> 24) & 0xFF; - opt->data[1] = (s->dhcp_ip >> 16) & 0xFF; - opt->data[2] = (s->dhcp_ip >> 8) & 0xFF; - opt->data[3] = (s->dhcp_ip >> 0) & 0xFF; + DHCP_OPT_u32_to_data(opt, s->dhcp_ip); opt_sz += 6; opt_sz++; @@ -3410,7 +3460,8 @@ int dhcp_client_init(struct wolfIP *s) memset(&sin, 0, sizeof(struct wolfIP_sockaddr_in)); sin.sin_family = AF_INET; sin.sin_port = ee16(DHCP_CLIENT_PORT); - if (wolfIP_sock_bind(s, s->dhcp_udp_sd, (struct wolfIP_sockaddr *)&sin, sizeof(struct wolfIP_sockaddr_in)) < 0) { + if (wolfIP_sock_bind(s, s->dhcp_udp_sd, (struct wolfIP_sockaddr *)&sin, + sizeof(struct wolfIP_sockaddr_in)) < 0) { s->dhcp_state = DHCP_OFF; return -1; } @@ -3490,7 +3541,8 @@ static void arp_flush_pending(struct wolfIP *s, unsigned int if_idx, ip4 ip) } #endif /* WOLFIP_ENABLE_FORWARDING */ -static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, const uint8_t *mac) +static void arp_store_neighbor(struct wolfIP *s, unsigned int if_idx, ip4 ip, + const uint8_t *mac) { int i; int stored = 0; @@ -3549,7 +3601,8 @@ static void arp_request(struct wolfIP *s, unsigned int if_idx, ip4 tip) memset(arp.tma, 0, 6); arp.tip = ee32(tip); if (ll->send) { - if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, s, if_idx, &arp.eth, sizeof(struct arp_packet)) != 0) + if (wolfIP_filter_notify_eth(WOLFIP_FILT_SENDING, s, if_idx, &arp.eth, + sizeof(struct arp_packet)) != 0) return; ll->send(ll, &arp, sizeof(struct arp_packet)); } @@ -3670,14 +3723,43 @@ size_t wolfIP_instance_size(void) return sizeof(struct wolfIP); } -static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, - uint32_t len) +#ifdef DEBUG_IP +static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) +{ + char src[32]; + char dst[32]; + memset(src, 0, sizeof(src)); + memset(dst, 0, sizeof(dst)); + iptoa(ee32(ip->src), src); + iptoa(ee32(ip->dst), dst); + + printf("ip hdr:\n"); + printf("+-----------------------------+\n"); + printf("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", + 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); + printf("+-----------------------------+\n"); + printf("| 0x%04x | 0x%04x | (id, flags_fo)\n", + ee16(ip->id), ee16(ip->flags_fo)); + printf("+-----------------------------+\n"); + printf("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", + ip->ttl, ip->proto, ee16(ip->csum)); + printf("+-----------------------------+\n"); + printf("| %15s | (src)\n", src); + printf("+-----------------------------+\n"); + printf("| %15s | (dst)\n", dst); + printf("+-----------------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_IP*/ + +static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, + struct wolfIP_ip_packet *ip, uint32_t len) { #if WOLFIP_ENABLE_FORWARDING unsigned int i; #endif /* validate minimum packet length - * (ethernet header+ ip header, with no options) */ + * (ethernet header + ip header, with no options) */ if (len < sizeof(struct wolfIP_ip_packet)) return; #if WOLFIP_ENABLE_LOOPBACK @@ -3729,7 +3811,25 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ } } } -#endif +#endif /* WOLFIP_ENABLE_FORWARDING */ + + #ifdef DEBUG_IP + wolfIP_print_ip(ip); + #endif /* DEBUG_IP*/ + + #ifdef WOLFIP_ESP + /* note: esp transport mode only handled here. + * ip forwarding would require esp tunnel mode. */ + if (ip->proto == 0x32) { + /* proto is ESP 0x32 (50), try to unwrap. */ + int err = esp_transport_unwrap(s, ip, &len); + if (err) { + printf("info: failed to unwrap esp packet, dropping.\n"); + return; + } + } + #endif /* WOLFIP_ESP */ + if (ip->ver_ihl == 0x45 && ip->proto == 0x06) { struct wolfIP_tcp_seg *tcp = (struct wolfIP_tcp_seg *)ip; tcp_input(s, if_idx, tcp, len); @@ -3737,11 +3837,37 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) { struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)ip; udp_try_recv(s, if_idx, udp, len); - } else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) { + } + else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) { icmp_input(s, if_idx, ip, len); } + #ifdef DEBUG_IP + else { + printf("info: dropping ip packet: 0x%02x\n", ip->proto); + } + #endif } +#ifdef DEBUG_ETH +static void wolfIP_print_eth(struct wolfIP_eth_frame * eth, uint32_t len) +{ + uint8_t * dst = eth->dst; + uint8_t * src = eth->src; + uint8_t * type = (uint8_t *) ð->type; + printf("eth hdr:\n"); + printf("+---------------------------------------+\n"); + printf("| %02x:%02x:%02x:%02x:%02x:%02x " + "| %02x:%02x:%02x:%02x:%02x:%02x | (src, dst) \n", + src[0], src[1], src[2], src[3], src[4], src[5], + dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]); + printf("+---------------------------------------+\n"); + printf("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", + type[0], type[1], (unsigned long)len); + printf("+---------------------------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_ETH */ + static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) { #ifdef ETHERNET @@ -3758,6 +3884,9 @@ static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uin if (!ll) return; eth = (struct wolfIP_eth_frame *)buf; + #ifdef DEBUG_ETH + wolfIP_print_eth(eth, len); + #endif /* DEBUG_ETH */ if (wolfIP_filter_notify_eth(WOLFIP_FILT_RECEIVING, s, if_idx, eth, len) != 0) return; if (eth->type == ee16(ETH_TYPE_IP)) { @@ -3897,7 +4026,8 @@ static int dns_skip_name(const uint8_t *buf, int len, int offset) return pos; } -static int dns_copy_name(const uint8_t *buf, int len, int offset, char *out, size_t out_len) +static int dns_copy_name(const uint8_t *buf, int len, int offset, char *out, + size_t out_len) { int pos = offset; size_t o = 0; @@ -4010,7 +4140,8 @@ void dns_callback(int dns_sd, uint16_t ev, void *arg) } } -static int dns_send_query(struct wolfIP *s, const char *dname, uint16_t *id, uint16_t qtype) +static int dns_send_query(struct wolfIP *s, const char *dname, uint16_t *id, + uint16_t qtype) { uint8_t buf[512]; struct dns_header *hdr; @@ -4158,6 +4289,9 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } /* Step 4: attempt to write any pending data */ + /** + * TCP + * */ for (i = 0; i < MAX_TCPSOCKETS; i++) { struct tsocket *ts = &s->tcpsockets[i]; uint32_t in_flight = ts->sock.tcp.bytes_in_flight; @@ -4220,7 +4354,16 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); if (ll && ll->send) { + #ifdef WOLFIP_ESP + int esp_err = esp_tcp_output(ll, (struct wolfIP_ip_packet *)tcp, size); + if (esp_err == 1) { + /* ipsec not configured on this interface. + * send plaintext. */ + ll->send(ll, tcp, desc->len); + } + #else ll->send(ll, tcp, desc->len); + #endif /* WOLFIP_ESP */ } } desc->flags |= PKT_FLAG_SENT; @@ -4248,6 +4391,10 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } } } + + /* + * UDP + * */ for (i = 0; i < MAX_UDPSOCKETS; i++) { struct tsocket *t = &s->udpsockets[i]; struct pkt_desc *desc = fifo_peek(&t->sock.udp.txbuf); @@ -4343,7 +4490,8 @@ void wolfIP_ipconfig_get(struct wolfIP *s, ip4 *ip, ip4 *mask, ip4 *gw) wolfIP_ipconfig_get_ex(s, WOLFIP_PRIMARY_IF_IDX, ip, mask, gw); } -void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 mask, ip4 gw) +void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, + ip4 mask, ip4 gw) { struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); if (!conf) @@ -4353,7 +4501,8 @@ void wolfIP_ipconfig_set_ex(struct wolfIP *s, unsigned int if_idx, ip4 ip, ip4 m conf->gw = gw; } -void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 *mask, ip4 *gw) +void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, + ip4 *mask, ip4 *gw) { struct ipconf *conf = wolfIP_ipconf_at(s, if_idx); if (!conf) diff --git a/tools/ip-xfrm/README.md b/tools/ip-xfrm/README.md new file mode 100644 index 0000000..611e5ea --- /dev/null +++ b/tools/ip-xfrm/README.md @@ -0,0 +1,40 @@ +# IPsec ESP and ip xfrm support + +Convenience scripts for testing IPsec with wolfIP: + +- `rfc4106` sets up rfc4106 aes-gcm xp frm state and policies. +- `delete_all` (deletes all ip xfrm state and policies) +- `hmac_auth` (set auth only state and policies) +- `show` (show ip xfrm state and policies) +- `esp_sa.txt` (ESP SA config to use in Wireshark) + +Copy `esp_sa.txt` to you wireshark config, and you can decrypt and inspect +ESP payloads, verify ESP ICV and TCP/IP checksums, etc: + +``` +cp tools/ip-xfrm/esp_sa.txt ~/.config/wireshark/esp_sa +wireshark test.pcap +``` + +## Testing + +Build wolfssl with: +```sh +./configure --enable-aesgcm-stream + make + sudo make install +``` + +Build wolfIP like normal: +```sh +make +``` + +Test rfc4106 gcm with wolfIP: +``` +./tools/ip-xfrm/rfc4106 128 +sudo LD_LIBRARY_PATH=/usr/local/lib ./build/test-esp +./tools/ip-xfrm/delete_all +cp tools/ip-xfrm/esp_sa.txt ~/.config/wireshark/esp_sa +wireshark test.pcap +``` diff --git a/tools/ip-xfrm/cbc_auth b/tools/ip-xfrm/cbc_auth new file mode 100755 index 0000000..3684019 --- /dev/null +++ b/tools/ip-xfrm/cbc_auth @@ -0,0 +1,63 @@ +#!/bin/bash +# +# aes-cbc (rfc3602) + hmac-[md5,sha1,sha256]-96,128 example. +# + +print_usage_and_die() { + echo "usage:" + echo " cbc_auth [auth]" + echo "" + echo " auth = md5, sha1, sha256" + echo "" + echo "examples:" + echo " ./tools/ip-xfrm/cbc_auth sha256 128" + echo " ./tools/ip-xfrm/cbc_auth sha256 96" + echo " ./tools/ip-xfrm/cbc_auth sha1" + echo " ./tools/ip-xfrm/cbc_auth md5" + exit 1 +} + +alg=sha1 +ip_proto=tcp +len=96 + +if [ $# -eq 0 ]; then + print_usage_and_die +fi + +if [ $# -eq 1 ]; then + alg=$1 +fi + +if [ $# -eq 2 ]; then + alg=$1 + len=$2 +fi + +# State +# ipv4 +sudo ip xfrm state add \ + src 10.10.10.1 dst 10.10.10.2 \ + proto esp \ + spi 0x03030303 \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x01010101010101010101010101010101 $len \ + enc aes 0x0303030303030303030303030303030303030303030303030303030303030303 \ + sel src 10.10.10.1 dst 10.10.10.2 + +sudo ip xfrm state add \ + src 10.10.10.2 dst 10.10.10.1 \ + proto esp \ + spi 0x04040404 \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x02020202020202020202020202020202 $len \ + enc aes 0x0404040404040404040404040404040404040404040404040404040404040404 \ + sel src 10.10.10.2 dst 10.10.10.1 + +# Policies +# ipv4 +sudo ip xfrm policy add \ + dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x03030303 mode transport + diff --git a/tools/ip-xfrm/delete_all b/tools/ip-xfrm/delete_all new file mode 100755 index 0000000..53fc91b --- /dev/null +++ b/tools/ip-xfrm/delete_all @@ -0,0 +1,3 @@ +#!/bin/bash +sudo ip xfrm policy deleteall +sudo ip xfrm state deleteall diff --git a/tools/ip-xfrm/esp_sa.txt b/tools/ip-xfrm/esp_sa.txt new file mode 100644 index 0000000..846c233 --- /dev/null +++ b/tools/ip-xfrm/esp_sa.txt @@ -0,0 +1,10 @@ +# This file is automatically generated. BE CAREFUL MODIFYING. +# You can add (but not modify or delete) records with the command line option: +# -o 'uat:esp_sa:"protocol","srcIP","dstIP","spi","encryption_algo","encryption_key_string","authentication_algo","authentication_key_string","sn_length","sn_upper"' +#"Protocol","Src IP","Dest IP","SPI","Encryption","Encryption Key","Authentication","Authentication Key","SN","ESN High Bits" +"IPv4","10.10.10.1","10.10.10.2","0x05050505","NULL","","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" +"IPv4","10.10.10.2","10.10.10.1","0x06060606","NULL","","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" +"IPv4","10.10.10.1","10.10.10.2","0x03030303","AES-CBC [RFC3602]","0x0303030303030303030303030303030303030303030303030303030303030303","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" +"IPv4","10.10.10.2","10.10.10.1","0x04040404","AES-CBC [RFC3602]","0x0404040404040404040404040404040404040404040404040404040404040404","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" +"IPv4","10.10.10.1","10.10.10.2","0x01010101","AES-GCM with 16 octet ICV [RFC4106]","0x03030303030303030303030303030303030303030303030303030303030303030a0b0c0d","NULL","","32-bit","0" +"IPv4","10.10.10.2","10.10.10.1","0x02020202","AES-GCM with 16 octet ICV [RFC4106]","0x04040404040404040404040404040404040404040404040404040404040404040a0b0c0d","NULL","","32-bit","0" diff --git a/tools/ip-xfrm/hmac_auth b/tools/ip-xfrm/hmac_auth new file mode 100755 index 0000000..2cdf6c2 --- /dev/null +++ b/tools/ip-xfrm/hmac_auth @@ -0,0 +1,66 @@ +#!/bin/bash +# +# hmac-[md5,sha1,sha256]-96,128 example. +# + +print_usage_and_die() { + echo "usage:" + echo " hmac_auth [auth]" + echo "" + echo " auth = md5, sha1, sha256" + echo "" + echo "examples:" + echo " ./tools/ip-xfrm/hmac_auth sha256 128" + echo " ./tools/ip-xfrm/hmac_auth sha256 96" + echo " ./tools/ip-xfrm/hmac_auth sha1" + echo " ./tools/ip-xfrm/hmac_auth md5" + exit 1 +} + +alg=sha1 +ip_proto=tcp +len=96 + +if [ $# -eq 0 ]; then + print_usage_and_die +fi + +if [ $# -eq 1 ]; then + alg=$1 +fi + +if [ $# -eq 2 ]; then + alg=$1 + len=$2 +fi + +# State +# ipv4 +sudo ip xfrm state add \ + src 10.10.10.1 dst 10.10.10.2 \ + proto esp \ + spi 0x2fa9d8c8 \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x01010101010101010101010101010101 $len \ + enc cipher_null "" \ + sel src 10.10.10.1 dst 10.10.10.2 + +sudo ip xfrm state add \ + src 10.10.10.2 dst 10.10.10.1 \ + proto esp \ + spi 0xf6e9b80d \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x02020202020202020202020202020202 $len \ + enc cipher_null "" \ + sel src 10.10.10.2 dst 10.10.10.1 + +# Policies +# ipv4 +sudo ip xfrm policy add \ + dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x2fa9d8c8 mode transport + +#sudo ip xfrm policy add \ +# dst 10.10.10.1 proto $ip_proto dir out tmpl proto esp spi 0xf6e9b80d mode transport + diff --git a/tools/ip-xfrm/rfc4106 b/tools/ip-xfrm/rfc4106 new file mode 100755 index 0000000..29e02e4 --- /dev/null +++ b/tools/ip-xfrm/rfc4106 @@ -0,0 +1,58 @@ +#!/bin/bash +# +# rfc4106(gcm(aes)) example: aes-gcm encryption + auth. +# +# The 4 byte nonce is placed at end of key, forming 20 bytes +# of key material. +# + +print_usage_and_die() { + echo "usage:" + echo " rfc4106 [icv_len]" + echo "" + echo " icv_len = 128" + echo "" + echo "examples:" + echo " ./tools/ip-xfrm/rfc4106 128" + echo " ./tools/ip-xfrm/rfc4106" + exit 1 +} + +alg="rfc4106(gcm(aes))" +nonce=0a0b0c0d +ip_proto=tcp +len=128 + +if [ $# -eq 0 ]; then + print_usage_and_die +fi + +if [ $# -eq 1 ]; then + len=$1 +fi + +# State +# ipv4 +sudo ip xfrm state add \ + src 10.10.10.1 dst 10.10.10.2 \ + proto esp \ + spi 0x01010101 \ + mode transport \ + replay-window 64 \ + aead $alg 0x0303030303030303030303030303030303030303030303030303030303030303$nonce $len \ + sel src 10.10.10.1 dst 10.10.10.2 + +sudo ip xfrm state add \ + src 10.10.10.2 dst 10.10.10.1 \ + proto esp \ + spi 0x02020202 \ + mode transport \ + replay-window 64 \ + aead $alg 0x0404040404040404040404040404040404040404040404040404040404040404$nonce $len \ + sel src 10.10.10.2 dst 10.10.10.1 + +# Policies +# ipv4 +sudo ip xfrm policy add \ + dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x01010101 mode transport + diff --git a/tools/ip-xfrm/show b/tools/ip-xfrm/show new file mode 100755 index 0000000..76267fd --- /dev/null +++ b/tools/ip-xfrm/show @@ -0,0 +1,7 @@ +#!/bin/bash +echo "ip xfrm policy show" +sudo ip xfrm policy show + +echo "" +echo "ip xfrm state show" +sudo ip xfrm state show diff --git a/tools/ip-xfrm/watch_stat b/tools/ip-xfrm/watch_stat new file mode 100755 index 0000000..dd03e0c --- /dev/null +++ b/tools/ip-xfrm/watch_stat @@ -0,0 +1,2 @@ +#!/bin/bash +watch cat /proc/net/xfrm_stat diff --git a/wolfesp.h b/wolfesp.h new file mode 100644 index 0000000..324b89d --- /dev/null +++ b/wolfesp.h @@ -0,0 +1,85 @@ +#ifndef WOLFESP_H +#define WOLFESP_H + +/* size of static pool */ +#define WOLFIP_ESP_NUM_SA 3 +/* ESP packet parameters */ +#define ESP_SPI_LEN 4 +#define ESP_SEQ_LEN 4 +#define ESP_PADDING_LEN 1 +#define ESP_NEXT_HEADER_LEN 1 +#define ESP_ICV_ALIGNMENT 4 +/* hmac-[sha256, sha1, md5]-96*/ +#define ESP_ICVLEN_HMAC_96 12 +#define ESP_ICVLEN_HMAC_128 16 +/* max key size */ +#define ESP_MAX_KEY_LEN (AES_MAX_KEY_SIZE / 8) +/* aes-cbc */ +#define ESP_CBC_RFC3602_IV_LEN 16 +/* aes-gcm */ +#define ESP_GCM_RFC4106_ICV_LEN 16 +#define ESP_GCM_RFC4106_SALT_LEN 4 +#define ESP_GCM_RFC4106_IV_LEN 8 +#define ESP_GCM_RFC4106_NONCE_LEN (ESP_GCM_RFC4106_SALT_LEN \ + + ESP_GCM_RFC4106_IV_LEN) + +typedef enum { + ESP_ENC_NONE = 0, + ESP_ENC_CBC_AES, + ESP_ENC_CBC_DES3, + ESP_ENC_GCM_RFC4106, + ESP_ENC_GCM_RFC4543, /* placeholder to indicate gmac auth. */ +} esp_enc_t; + +typedef enum { + ESP_AUTH_NONE = 0, + ESP_AUTH_MD5_RFC2403, /* hmac(md5)-96 */ + ESP_AUTH_SHA1_RFC2404, /* hmac(sha1)-96 */ + ESP_AUTH_SHA256_RFC4868, /* hmac(sha256)-N, N=96,128 */ + ESP_AUTH_GCM_RFC4106, /* placeholder to indicate gcm auth. */ + ESP_AUTH_GCM_RFC4543 /* rfc4543 gmac */ +} esp_auth_t; + +/* simple static 32 bit replay window */ +#define ESP_MAX_32_SEQ 0xffffffffUL +#define ESP_REPLAY_WIN 32U + +struct replay_t { + uint32_t bitmap; /* inbound sequence bitmap */ + uint32_t hi_seq; /* inbound high sequence number */ + uint32_t oseq; /* outbound sequence number */ +}; + +typedef struct replay_t replay_t; + +#define esp_replay_init(r) \ + (r).bitmap = 0U; (r).hi_seq = ESP_REPLAY_WIN; (r).oseq = 1U; \ + +/* Minimal ESP Security Association structure. + * Supports only transport mode. */ +struct wolfIP_esp_sa { + uint8_t spi[ESP_SPI_LEN]; /* security parameter index */ + ip4 src; /* ip src and dst in network byte order */ + ip4 dst; + replay_t replay; + esp_enc_t enc; + uint8_t enc_key[ESP_MAX_KEY_LEN + ESP_GCM_RFC4106_SALT_LEN]; + uint8_t enc_key_len; + esp_auth_t auth; + uint8_t auth_key[ESP_MAX_KEY_LEN]; + uint8_t auth_key_len; + uint8_t icv_len; + uint8_t pre_iv[ESP_GCM_RFC4106_IV_LEN]; /* unique salt that is xor'ed + * with oseq to generate iv. */ +}; +typedef struct wolfIP_esp_sa wolfIP_esp_sa; + +int wolfIP_esp_init(void); +void wolfIP_esp_sa_del(void); +int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len); +int wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len, + uint8_t * auth_key, uint8_t auth_key_len, + uint8_t icv_len); +#endif /* !WOLFESP_H */ diff --git a/wolfip.h b/wolfip.h index e12b1f9..57edca4 100644 --- a/wolfip.h +++ b/wolfip.h @@ -191,32 +191,46 @@ struct msghdr { #endif int wolfIP_sock_socket(struct wolfIP *s, int domain, int type, int protocol); -int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen); +int wolfIP_sock_bind(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, + socklen_t addrlen); int wolfIP_sock_listen(struct wolfIP *s, int sockfd, int backlog); -int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, socklen_t *addrlen); -int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, socklen_t addrlen); -int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags, const struct wolfIP_sockaddr *dest_addr, socklen_t addrlen); -int wolfIP_sock_send(struct wolfIP *s, int sockfd, const void *buf, size_t len, int flags); +int wolfIP_sock_accept(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, + socklen_t *addrlen); +int wolfIP_sock_connect(struct wolfIP *s, int sockfd, const struct wolfIP_sockaddr *addr, + socklen_t addrlen); +int wolfIP_sock_sendto(struct wolfIP *s, int sockfd, const void *buf, size_t len, + int flags, const struct wolfIP_sockaddr *dest_addr, + socklen_t addrlen); +int wolfIP_sock_send(struct wolfIP *s, int sockfd, const void *buf, size_t len, + int flags); int wolfIP_sock_write(struct wolfIP *s, int sockfd, const void *buf, size_t len); -int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, int flags, struct wolfIP_sockaddr *src_addr, socklen_t *addrlen); +int wolfIP_sock_recvfrom(struct wolfIP *s, int sockfd, void *buf, size_t len, + int flags, struct wolfIP_sockaddr *src_addr, socklen_t *addrlen); int wolfIP_sock_recv(struct wolfIP *s, int sockfd, void *buf, size_t len, int flags); -int wolfIP_sock_sendmsg(struct wolfIP *s, int sockfd, const struct msghdr *msg, int flags); -int wolfIP_sock_recvmsg(struct wolfIP *s, int sockfd, struct msghdr *msg, int flags); -int wolfIP_dns_ptr_lookup(struct wolfIP *s, uint32_t ip, uint16_t *id, void (*lookup_cb)(const char *name)); +int wolfIP_sock_sendmsg(struct wolfIP *s, int sockfd, const struct msghdr *msg, + int flags); +int wolfIP_sock_recvmsg(struct wolfIP *s, int sockfd, struct msghdr *msg, + int flags); +int wolfIP_dns_ptr_lookup(struct wolfIP *s, uint32_t ip, uint16_t *id, + void (*lookup_cb)(const char *name)); int wolfIP_sock_get_recv_ttl(struct wolfIP *s, int sockfd, int *ttl); -int wolfIP_sock_setsockopt(struct wolfIP *s, int sockfd, int level, int optname, const void *optval, socklen_t optlen); -int wolfIP_sock_getsockopt(struct wolfIP *s, int sockfd, int level, int optname, void *optval, socklen_t *optlen); +int wolfIP_sock_setsockopt(struct wolfIP *s, int sockfd, int level, int optname, + const void *optval, socklen_t optlen); +int wolfIP_sock_getsockopt(struct wolfIP *s, int sockfd, int level, int optname, + void *optval, socklen_t *optlen); int wolfIP_sock_read(struct wolfIP *s, int sockfd, void *buf, size_t len); int wolfIP_sock_close(struct wolfIP *s, int sockfd); -int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen); -int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, const socklen_t *addrlen); - +int wolfIP_sock_getpeername(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, + const socklen_t *addrlen); +int wolfIP_sock_getsockname(struct wolfIP *s, int sockfd, struct wolfIP_sockaddr *addr, + const socklen_t *addrlen); int dhcp_client_init(struct wolfIP *s); int dhcp_bound(struct wolfIP *s); /* DNS client */ -int nslookup(struct wolfIP *s, const char *name, uint16_t *id, void (*lookup_cb)(uint32_t ip)); +int nslookup(struct wolfIP *s, const char *name, uint16_t *id, + void (*lookup_cb)(uint32_t ip)); #if CONFIG_IPFILTER #include "wolfip-filter.h" @@ -242,7 +256,9 @@ void wolfIP_ipconfig_get_ex(struct wolfIP *s, unsigned int if_idx, ip4 *ip, ip4 #define CB_EVENT_TIMEOUT 0x02 /* Timeout */ #define CB_EVENT_WRITABLE 0x04 /* Connected or space available to send */ #define CB_EVENT_CLOSED 0x10 /* Connection closed by peer */ -void wolfIP_register_callback(struct wolfIP *s, int sock_fd, void (*cb)(int sock_fd, uint16_t events, void *arg), void *arg); +typedef void (*tsocket_cb)(int sock_fd, uint16_t events, void *arg); +void wolfIP_register_callback(struct wolfIP *s, int sock_fd, tsocket_cb cb, + void *arg); /* External requirements */ uint32_t wolfIP_getrandom(void); @@ -287,15 +303,21 @@ static inline void iptoa(ip4 ip, char *buf) } #ifdef WOLFSSL_WOLFIP -#ifdef WOLFSSL_USER_SETTINGS -#include "user_settings.h" -#else -#include -#endif -#include -#include -int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd); -int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); -#endif - -#endif + #ifdef WOLFSSL_USER_SETTINGS + #include "user_settings.h" + #else + #include + #endif /* WOLFSSL_USER_SETTINGS */ + #include + #include + int wolfSSL_SetIO_wolfIP(WOLFSSL* ssl, int fd); + int wolfSSL_SetIO_wolfIP_CTX(WOLFSSL_CTX *ctx, struct wolfIP *s); + + #ifdef WOLFIP_ESP + #include + #include + #include + #endif /* WOLFIP_ESP */ +#endif /* WOLFSSL_WOLFIP */ + +#endif /* !WOLFIP_H */ From c2c3854566595a293d05692dd61a395c691949c0 Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 9 Feb 2026 16:45:23 -0600 Subject: [PATCH 02/10] esp: esp echo server test. --- Makefile | 12 ++- src/test/esp_server.c | 229 ++++++++++++++++++++++++++++++++++++++++++ src/test/test_esp.c | 4 + src/wolfip.c | 25 +++++ tools/ip-xfrm/rfc4106 | 4 + 5 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 src/test/esp_server.c diff --git a/Makefile b/Makefile index 753aab0..73b4a88 100644 --- a/Makefile +++ b/Makefile @@ -145,7 +145,7 @@ endif EXE=build/tcpecho build/tcp_netcat_poll build/tcp_netcat_select \ build/test-evloop build/test-dns build/test-wolfssl-forwarding \ build/test-ttl-expired build/test-wolfssl build/test-httpd \ - build/ipfilter-logger build/test-esp + build/ipfilter-logger build/test-esp build/esp-server LIB=libwolfip.so PREFIX=/usr/local @@ -181,7 +181,7 @@ asan:LDFLAGS+=-static-libasan ESP_CFLAGS = \ -DWOLFIP_ESP \ -DWOLFSSL_WOLFIP \ - -DDEBUG_IP \ + -DDEBUG_IP -DDEBUG_UDP \ -DWOLFIP_DEBUG_ESP # Test @@ -252,6 +252,14 @@ build/test-esp: $(ESP_OBJ) build/test/test_esp.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(ESP_CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) +build/test/esp_server.o: src/test/esp_server.c + @echo "[CC] $@" + @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ + +build/esp-server: $(ESP_OBJ) build/port/posix/bsd_socket.o build/test/esp_server.o + @echo "[LD] $@" + @$(CC) $(CFLAGS) $(ESP_CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) + build/test-wolfssl-forwarding: build/test/test_wolfssl_forwarding.o build/test/wolfip_forwarding.o $(TAP_OBJ) build/port/wolfssl_io.o build/certs/server_key.o build/certs/ca_cert.o build/certs/server_cert.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) diff --git a/src/test/esp_server.c b/src/test/esp_server.c new file mode 100644 index 0000000..4b5372a --- /dev/null +++ b/src/test/esp_server.c @@ -0,0 +1,229 @@ +/* tcp_echo.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include +#include +#include +#include +#include +/* wolfip includes */ +#include "config.h" +#include "wolfip.h" +#include "wolfesp.h" + +#define PORT 8 +#define BUFFER_SIZE 1024 + +static void __attribute__((noreturn)) print_usage_and_die(void); + +static int disable_ipsec = 0; +static int esp_mode = 0; +static int use_udp = 0; + +/* esp security association info */ +static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; +static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; +static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; +static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +/* 32 byte key + 4 byte nonce*/ +static uint8_t in_enc_key[36] = + {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t out_enc_key[36] = + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t in_auth_key[16] = + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; +static uint8_t out_auth_key[16] = + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; + + +int main(int argc, char * argv[]) +{ + int server_fd, client_fd; + struct sockaddr_in address; + int addrlen = sizeof(address); + char buffer[BUFFER_SIZE]; + int opt = 0; + int type = SOCK_STREAM; + int err = 0; + + while ((opt = getopt(argc, argv, "pm:u?")) != -1) { + switch (opt) { + case 'p': + disable_ipsec = 1; + break; + case 'm': + esp_mode = atoi(optarg); + break; + case 'u': + use_udp = 1; + type = SOCK_DGRAM; + break; + case '?': + print_usage_and_die(); + break; + default: + break; + } + } + + if (!disable_ipsec) { + err = wolfIP_esp_init(); + if (err) { + perror("esp_init"); + return 2; + } + + switch (esp_mode) { + case 0: + err = wolfIP_esp_sa_new_aead(1, in_sa_gcm, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key)); + if (err) { return err; } + + err = wolfIP_esp_sa_new_aead(0, out_sa_gcm, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key)); + if (err) { return err; } + break; + + case 1: + err = wolfIP_esp_sa_new_cbc_sha256(1, in_sa_cbc, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key) - 4, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + + err = wolfIP_esp_sa_new_cbc_sha256(0, out_sa_cbc, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key) - 4, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + break; + + default: + break; + } + } + + // Create a socket + if ((server_fd = socket(AF_INET, type, 0)) == 0) { + perror("Socket failed"); + exit(EXIT_FAILURE); + } + printf("Socket created: %d\n", server_fd); + + // Bind to the specified port + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons(PORT); + + if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { + perror("Bind failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + printf("Bind successful\n"); + + if (!use_udp) { + // Start listening for incoming connections + if (listen(server_fd, 3) < 0) { + perror("Listen failed"); + close(server_fd); + exit(EXIT_FAILURE); + } + + printf("Echo tcp server listening on port %d\n", PORT); + + while (1) { + ssize_t bytes_read; + // Accept a client connection + if ((client_fd = accept(server_fd, (struct sockaddr *)&address, + (socklen_t *)&addrlen)) < 0) { + perror("Accept failed"); + continue; + } + + printf("Client connected, fd: %d\n", client_fd); + + while ((bytes_read = read(client_fd, buffer, BUFFER_SIZE)) > 0) { + write(client_fd, buffer, bytes_read); // Echo data back to the client + } + + printf("Client disconnected\n"); + close(client_fd); + } + } + else { + printf("Echo udp server listening on port %d\n", PORT); + + for (;;) { + ssize_t bytes_read = 0; + ssize_t bytes_sent = 0; + struct sockaddr_in cliaddr; + socklen_t cliaddr_len = sizeof(cliaddr); + bytes_read = recvfrom(server_fd, buffer, BUFFER_SIZE, 0, + (struct sockaddr *)&cliaddr, &cliaddr_len); + + if (bytes_read <= 0) { + printf("info: recvfrom: %ld\n", bytes_read); + break; + } + + printf("info: recv from %s: %5d, %ld bytes\n", inet_ntoa(cliaddr.sin_addr), + ntohs(cliaddr.sin_port), bytes_read); + + bytes_sent = sendto(server_fd, buffer, bytes_read, 0, + (struct sockaddr *)&cliaddr, cliaddr_len); + if (bytes_sent <= 0) { + printf("info: sendto: %ld\n", bytes_sent); + break; + } + } + } + + close(server_fd); + return 0; +} + +static void +print_usage_and_die(void) +{ + printf("./test-esp [-m ] [-p]\n"); + printf("\n"); + printf("options:\n"); + printf(" -p force plaintext (disable ipsec)\n"); + printf(" -m 0 aead (default), 1 cbc auth\n"); + printf(" -u use udp (default tcp)\n"); + exit(1); +} diff --git a/src/test/test_esp.c b/src/test/test_esp.c index eee27a0..79a395d 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -580,10 +580,12 @@ int main(int argc, char **argv) err = wolfIP_esp_sa_new_aead(1, in_sa_gcm, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), in_enc_key, sizeof(in_enc_key)); + if (err) { return err; } err = wolfIP_esp_sa_new_aead(0, out_sa_gcm, atoip4(WOLFIP_IP), atoip4(HOST_STACK_IP), out_enc_key, sizeof(out_enc_key)); + if (err) { return err; } break; case 1: @@ -592,12 +594,14 @@ int main(int argc, char **argv) in_enc_key, sizeof(in_enc_key) - 4, in_auth_key, sizeof(in_auth_key), ESP_ICVLEN_HMAC_128); + if (err) { return err; } err = wolfIP_esp_sa_new_cbc_sha256(0, out_sa_cbc, atoip4(WOLFIP_IP), atoip4(HOST_STACK_IP), out_enc_key, sizeof(out_enc_key) - 4, out_auth_key, sizeof(out_auth_key), ESP_ICVLEN_HMAC_128); + if (err) { return err; } break; default: diff --git a/src/wolfip.c b/src/wolfip.c index feecdff..1b1bcd6 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3752,6 +3752,28 @@ static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) } #endif /* DEBUG_IP*/ +#ifdef DEBUG_UDP +static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) +{ + char payload_str[32]; + uint16_t len = ee16(udp->len); + uint16_t max_len = 16; + printf("udp hdr:\n"); + printf("+-------------------+\n"); + printf("| %5d | %5d | (src_port, dst_port)\n", + ee16(udp->src_port), ee16(udp->dst_port)); + printf("+-------------------+\n"); + printf("| %5u | 0x%04x | (len, chksum)\n", + len, ee16(udp->csum)); + printf("+-------------------+\n"); + memset(payload_str, '\0', sizeof(payload_str)); + memcpy(payload_str, udp->data, len < max_len ? len : max_len); + printf("| %17s | (payload first 16 bytes)\n", payload_str); + printf("+-------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_UDP */ + static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) { @@ -3836,6 +3858,9 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, } else if (ip->ver_ihl == 0x45 && ip->proto == 0x11) { struct wolfIP_udp_datagram *udp = (struct wolfIP_udp_datagram *)ip; + #ifdef DEBUG_UDP + wolfIP_print_udp(udp); + #endif /* DEBUG_UDP */ udp_try_recv(s, if_idx, udp, len); } else if (ip->ver_ihl == 0x45 && ip->proto == 0x01) { diff --git a/tools/ip-xfrm/rfc4106 b/tools/ip-xfrm/rfc4106 index 29e02e4..f84675b 100755 --- a/tools/ip-xfrm/rfc4106 +++ b/tools/ip-xfrm/rfc4106 @@ -31,6 +31,10 @@ if [ $# -eq 1 ]; then len=$1 fi +if [ $# -eq 2 ]; then + ip_proto=$2 +fi + # State # ipv4 sudo ip xfrm state add \ From ca25dc727531e164c0af46d9ff400b5edfed2a0d Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 9 Feb 2026 23:04:57 -0600 Subject: [PATCH 03/10] cleanup. --- src/test/esp_server.c | 2 +- src/wolfesp.c | 2 +- src/wolfip.c | 15 ++++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/test/esp_server.c b/src/test/esp_server.c index 4b5372a..b46b45d 100644 --- a/src/test/esp_server.c +++ b/src/test/esp_server.c @@ -1,4 +1,4 @@ -/* tcp_echo.c +/* esp_server.c * * Copyright (C) 2024 wolfSSL Inc. * diff --git a/src/wolfesp.c b/src/wolfesp.c index 1326bef..111d491 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -786,7 +786,7 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) bitn = 1U << (replay->hi_seq - seq); if ((replay->bitmap & bitn) != 0U) { - printf("error: seq replayed: %d, %d\n", bitn, seq); + printf("error: seq replayed: %u, %d\n", bitn, seq); return -1; } else { diff --git a/src/wolfip.c b/src/wolfip.c index 1b1bcd6..bc15bf4 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3755,9 +3755,8 @@ static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) #ifdef DEBUG_UDP static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) { - char payload_str[32]; uint16_t len = ee16(udp->len); - uint16_t max_len = 16; + char payload_str[32]; printf("udp hdr:\n"); printf("+-------------------+\n"); printf("| %5d | %5d | (src_port, dst_port)\n", @@ -3767,7 +3766,17 @@ static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) len, ee16(udp->csum)); printf("+-------------------+\n"); memset(payload_str, '\0', sizeof(payload_str)); - memcpy(payload_str, udp->data, len < max_len ? len : max_len); + { + /* show first 16 printable chars of payload */ + uint16_t max_len = 16; + size_t print_len = (len - 8) < max_len ? (len - 8): max_len; + size_t i = 0; + memset(payload_str, '\0', sizeof(payload_str)); + memcpy(payload_str, udp->data, print_len); + for (i = 0; i < print_len; i++) { + if (!isprint(payload_str[i])) { payload_str[i] = '.'; } + } + } printf("| %17s | (payload first 16 bytes)\n", payload_str); printf("+-------------------+\n"); printf("\n"); From 5f53eb94b2322f012b880bed8eecf9dca3bc3edb Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 10 Feb 2026 13:16:11 -0600 Subject: [PATCH 04/10] esp: des3 support. --- src/test/esp_server.c | 41 ++++-- src/test/test_esp.c | 43 ++++-- src/wolfesp.c | 303 +++++++++++++++++++++++++++++++++------- tools/ip-xfrm/README.md | 2 +- tools/ip-xfrm/des3_auth | 69 +++++++++ wolfesp.h | 26 +++- 6 files changed, 400 insertions(+), 84 deletions(-) create mode 100755 tools/ip-xfrm/des3_auth diff --git a/src/test/esp_server.c b/src/test/esp_server.c index b46b45d..23009a8 100644 --- a/src/test/esp_server.c +++ b/src/test/esp_server.c @@ -44,6 +44,8 @@ static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; +static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; /* 32 byte key + 4 byte nonce*/ static uint8_t in_enc_key[36] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, @@ -64,7 +66,6 @@ static uint8_t out_auth_key[16] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; - int main(int argc, char * argv[]) { int server_fd, client_fd; @@ -116,18 +117,36 @@ int main(int argc, char * argv[]) break; case 1: - err = wolfIP_esp_sa_new_cbc_sha256(1, in_sa_cbc, atoip4(HOST_STACK_IP), - atoip4(WOLFIP_IP), - in_enc_key, sizeof(in_enc_key) - 4, - in_auth_key, sizeof(in_auth_key), - ESP_ICVLEN_HMAC_128); + err = wolfIP_esp_sa_new_cbc_hmac(1, in_sa_cbc, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key) - 4, + ESP_AUTH_SHA256_RFC4868, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + + err = wolfIP_esp_sa_new_cbc_hmac(0, out_sa_cbc, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key) - 4, + ESP_AUTH_SHA256_RFC4868, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + break; + + case 2: + err = wolfIP_esp_sa_new_des3_hmac(1, in_sa_des3, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, ESP_AUTH_SHA256_RFC4868, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); if (err) { return err; } - err = wolfIP_esp_sa_new_cbc_sha256(0, out_sa_cbc, atoip4(WOLFIP_IP), - atoip4(HOST_STACK_IP), - out_enc_key, sizeof(out_enc_key) - 4, - out_auth_key, sizeof(out_auth_key), - ESP_ICVLEN_HMAC_128); + err = wolfIP_esp_sa_new_des3_hmac(0, out_sa_des3, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, ESP_AUTH_SHA256_RFC4868, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); if (err) { return err; } break; diff --git a/src/test/test_esp.c b/src/test/test_esp.c index 79a395d..f92fc4b 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -60,6 +60,8 @@ static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; +static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; /* 32 byte key + 4 byte nonce*/ static uint8_t in_enc_key[36] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, @@ -80,7 +82,6 @@ static uint8_t out_auth_key[16] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; - /* wolfIP: server side callback. */ static void server_cb(int fd, uint16_t event, void *arg) { @@ -589,18 +590,36 @@ int main(int argc, char **argv) break; case 1: - err = wolfIP_esp_sa_new_cbc_sha256(1, in_sa_cbc, atoip4(HOST_STACK_IP), - atoip4(WOLFIP_IP), - in_enc_key, sizeof(in_enc_key) - 4, - in_auth_key, sizeof(in_auth_key), - ESP_ICVLEN_HMAC_128); + err = wolfIP_esp_sa_new_cbc_hmac(1, in_sa_cbc, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, sizeof(in_enc_key) - 4, + ESP_AUTH_SHA256_RFC4868, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + + err = wolfIP_esp_sa_new_cbc_hmac(0, out_sa_cbc, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, sizeof(out_enc_key) - 4, + ESP_AUTH_SHA256_RFC4868, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); + if (err) { return err; } + break; + + case 2: + err = wolfIP_esp_sa_new_des3_hmac(1, in_sa_des3, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), + in_enc_key, ESP_AUTH_SHA256_RFC4868, + in_auth_key, sizeof(in_auth_key), + ESP_ICVLEN_HMAC_128); if (err) { return err; } - err = wolfIP_esp_sa_new_cbc_sha256(0, out_sa_cbc, atoip4(WOLFIP_IP), - atoip4(HOST_STACK_IP), - out_enc_key, sizeof(out_enc_key) - 4, - out_auth_key, sizeof(out_auth_key), - ESP_ICVLEN_HMAC_128); + err = wolfIP_esp_sa_new_des3_hmac(0, out_sa_des3, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), + out_enc_key, ESP_AUTH_SHA256_RFC4868, + out_auth_key, sizeof(out_auth_key), + ESP_ICVLEN_HMAC_128); if (err) { return err; } break; @@ -628,6 +647,6 @@ print_usage_and_die(void) printf("\n"); printf("options:\n"); printf(" -p force plaintext (disable ipsec)\n"); - printf(" -m 0 aead (default), 1 cbc auth\n"); + printf(" -m 0 aead (default), 1 cbc hmac, 2 des3 hmac\n"); exit(1); } diff --git a/src/wolfesp.c b/src/wolfesp.c index 111d491..41cbde0 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -30,24 +30,25 @@ int wolfIP_esp_init(void) return err; } -void wolfIP_esp_sa_del(void) +void wolfIP_esp_sa_del_all(void) { memset(in_sa_list, 0, sizeof(in_sa_list)); memset(out_sa_list, 0, sizeof(out_sa_list)); return ; } -int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len) +static inline wolfIP_esp_sa * +esp_sa_get(int in, const uint8_t * spi) { - wolfIP_esp_sa * new_sa = NULL; + uint8_t empty_sa[4] = {0x00, 0x00, 0x00, 0x00}; wolfIP_esp_sa * list = NULL; size_t i = 0; - uint8_t empty_sa[4] = {0x00, 0x00, 0x00, 0x00}; - int err = 0; - in = (in == 0 ? 0 : 1); + if (spi == NULL) { + spi = empty_sa; + } + in = (in == 0 ? 0 : 1); if (in == 1) { list = in_sa_list; } @@ -56,23 +57,47 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, } for (i = 0; i < WOLFIP_ESP_NUM_SA; ++i) { - if (memcmp(list[i].spi, empty_sa, ESP_SPI_LEN) == 0) { - new_sa = &list[i]; - break; + if (memcmp(list[i].spi, spi, ESP_SPI_LEN) == 0) { + return &list[i]; } } + return NULL; +} + +void wolfIP_esp_sa_del_spi(int in, uint8_t * spi) +{ + wolfIP_esp_sa * sa = NULL; + + sa = esp_sa_get(in, spi); + if (sa != NULL) { + memset(sa, 0, sizeof(*sa)); + } + + return ; +} + +#if defined(WOLFSSL_AESGCM_STREAM) +int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len) +{ + wolfIP_esp_sa * new_sa = NULL; + int err = 0; + + new_sa = esp_sa_get(in, NULL); + if (new_sa == NULL) { printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); return -1; } + memset(new_sa, 0, sizeof(*new_sa)); + esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); + memcpy(new_sa->enc_key, enc_key, enc_key_len); new_sa->src = src; new_sa->dst = dst; - esp_replay_init(new_sa->replay); new_sa->enc = ESP_ENC_GCM_RFC4106; - memcpy(new_sa->enc_key, enc_key, enc_key_len); new_sa->enc_key_len = enc_key_len; new_sa->auth = ESP_AUTH_GCM_RFC4106; new_sa->icv_len = ESP_GCM_RFC4106_ICV_LEN; @@ -90,63 +115,80 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, } #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_sa_new_aead: %s, %zu\n", in == 1 ? "in" : "out", - i); + printf("info: esp_sa_new_aead: %s\n", in == 1 ? "in" : "out"); #endif /* WOLFIP_DEBUG_ESP */ return err; } +#endif /*WOLFSSL_AESGCM_STREAM */ -int wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len, - uint8_t * auth_key, uint8_t auth_key_len, - uint8_t icv_len) +int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len, + esp_auth_t auth, uint8_t * auth_key, + uint8_t auth_key_len, uint8_t icv_len) { wolfIP_esp_sa * new_sa = NULL; - wolfIP_esp_sa * list = NULL; - size_t i = 0; - uint8_t empty_sa[4] = {0x00, 0x00, 0x00, 0x00}; - int err = 0; - in = (in == 0 ? 0 : 1); - - if (in == 1) { - list = in_sa_list; - } - else { - list = out_sa_list; - } - - for (i = 0; i < WOLFIP_ESP_NUM_SA; ++i) { - if (memcmp(list[i].spi, empty_sa, ESP_SPI_LEN) == 0) { - new_sa = &list[i]; - break; - } - } + new_sa = esp_sa_get(in, NULL); if (new_sa == NULL) { printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); return -1; } + memset(new_sa, 0, sizeof(*new_sa)); + esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); + memcpy(new_sa->enc_key, enc_key, enc_key_len); + memcpy(new_sa->auth_key, auth_key, auth_key_len); new_sa->src = src; new_sa->dst = dst; - esp_replay_init(new_sa->replay); new_sa->enc = ESP_ENC_CBC_AES; - memcpy(new_sa->enc_key, enc_key, enc_key_len); new_sa->enc_key_len = enc_key_len; - new_sa->auth = ESP_AUTH_SHA256_RFC4868; - memcpy(new_sa->auth_key, auth_key, auth_key_len); + new_sa->auth = auth; new_sa->auth_key_len = auth_key_len; new_sa->icv_len = icv_len; #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_sa_new_cbc_sha256: %s, %zu\n", in == 1 ? "in" : "out", - i); + printf("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); #endif /* WOLFIP_DEBUG_ESP */ - return err; + return 0; +} + +int +wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, esp_auth_t auth, + uint8_t * auth_key, uint8_t auth_key_len, + uint8_t icv_len) +{ + wolfIP_esp_sa * new_sa = NULL; + + new_sa = esp_sa_get(in, NULL); + + if (new_sa == NULL) { + printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + return -1; + } + + memset(new_sa, 0, sizeof(*new_sa)); + esp_replay_init(new_sa->replay); + memcpy(new_sa->spi, spi, ESP_SPI_LEN); + memcpy(new_sa->enc_key, enc_key, ESP_DES3_KEY_LEN); + memcpy(new_sa->auth_key, auth_key, auth_key_len); + new_sa->src = src; + new_sa->dst = dst; + new_sa->enc = ESP_ENC_CBC_DES3; + new_sa->enc_key_len = ESP_DES3_KEY_LEN; + new_sa->auth = auth; + new_sa->auth_key_len = auth_key_len; + new_sa->icv_len = icv_len; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); + #endif /* WOLFIP_DEBUG_ESP */ + + return 0; } static uint8_t @@ -155,19 +197,17 @@ esp_block_len_from_enc(esp_enc_t enc) uint8_t block_len = 0; switch (enc) { - case ESP_ENC_NONE: - block_len = 0; - break; - case ESP_ENC_CBC_AES: - block_len = AES_BLOCK_SIZE; - break; #ifndef NO_DES3 case ESP_ENC_CBC_DES3: block_len = DES_BLOCK_SIZE; break; #endif /* !NO_DES3 */ + case ESP_ENC_CBC_AES: + block_len = AES_BLOCK_SIZE; + break; case ESP_ENC_GCM_RFC4106: case ESP_ENC_GCM_RFC4543: + case ESP_ENC_NONE: default: block_len = 0; break; @@ -182,15 +222,18 @@ esp_iv_len_from_enc(esp_enc_t enc) uint8_t iv_len = 0; switch (enc) { + #ifndef NO_DES3 + case ESP_ENC_CBC_DES3: + iv_len = ESP_DES3_IV_LEN; + break; + #endif /* !NO_DES3 */ case ESP_ENC_CBC_AES: iv_len = ESP_CBC_RFC3602_IV_LEN; break; - case ESP_ENC_GCM_RFC4106: case ESP_ENC_GCM_RFC4543: iv_len = ESP_GCM_RFC4106_IV_LEN; break; - case ESP_ENC_NONE: default: iv_len = 0; @@ -533,6 +576,127 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, return ret; } +#ifndef NO_DES3 +static int +esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Des3 des3_dec; + int ret = -1; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_DES3_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: des3 dec: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { + printf("error: des3_rfc2451_dec: key len = %d, expected %d\n", + esp_sa->enc_key_len, ESP_DES3_KEY_LEN); + goto des3_dec_out; + } + + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + + ret = wc_Des3Init(&des3_dec, NULL, INVALID_DEVID); + + if (ret != 0) { + printf("error: wc_Des3Init returned: %d\n", ret); + goto des3_dec_out; + } + + inited = 1; + ret = wc_Des3_SetKey(&des3_dec, esp_sa->enc_key, iv, DES_DECRYPTION); + + if (ret != 0) { + printf("error: wc_Des3_SetKey returned: %d\n", ret); + goto des3_dec_out; + } + + /* decrypt in place. */ + ret = wc_Des3_CbcDecrypt(&des3_dec, enc_payload, enc_payload, enc_len); + + if (ret != 0) { + printf("error: wc_Des3_CbcDecrypt returned: %d\n", ret); + goto des3_dec_out; + } + +des3_dec_out: + if (inited) { + wc_Des3Free(&des3_dec); + inited = 0; + } + + return ret; +} + +static int +esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Des3 des3_enc; + int ret = -1; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_DES3_IV_LEN; + uint8_t * enc_payload = NULL; + uint8_t * iv = NULL; + uint16_t enc_len = 0; + uint8_t inited = 0; + + #ifdef WOLFIP_DEBUG_ESP + printf("info: des3 enc: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + + if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { + printf("error: des3_rfc2451_enc: key len = %d, expected %d\n", + esp_sa->enc_key_len, ESP_DES3_KEY_LEN); + goto des3_enc_out; + } + + enc_len = esp_enc_len(esp_len, iv_len, icv_len); + enc_payload = esp_enc_payload(esp_data, iv_len); + iv = esp_enc_iv(esp_data, iv_len); + + ret = wc_Des3Init(&des3_enc, NULL, INVALID_DEVID); + + if (ret != 0) { + printf("error: wc_Des3Init returned: %d\n", ret); + goto des3_enc_out; + } + + inited = 1; + ret = wc_Des3_SetKey(&des3_enc, esp_sa->enc_key, iv, DES_ENCRYPTION); + + if (ret != 0) { + printf("error: wc_Des3_SetKey returned: %d\n", ret); + goto des3_enc_out; + } + + /* encrypt in place. */ + ret = wc_Des3_CbcEncrypt(&des3_enc, enc_payload, enc_payload, enc_len); + + if (ret != 0) { + printf("error: wc_Des3_CbcEncrypt returned: %d\n", ret); + goto des3_enc_out; + } + +des3_enc_out: + if (inited) { + wc_Des3Free(&des3_enc); + inited = 0; + } + + return ret; +} +#endif /* !NO_DES3 */ + +#if defined(WOLFSSL_AESGCM_STREAM) /** * AES-GCM-ESP * The KEYMAT requested for each AES-GCM key is N + 4 octets. The first @@ -717,6 +881,7 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, return err; } +#endif /*WOLFSSL_AESGCM_STREAM */ /** * esp_data covers from start of ESP header to end of ESP trailer, but does not @@ -951,17 +1116,32 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, if (iv_len != 0) { /* Decrypt the payload in place. */ switch(esp_sa->enc) { + #ifndef NO_DES3 + case ESP_ENC_CBC_DES3: + err = esp_des3_rfc2451_dec(esp_sa, ip->data, esp_len); + break; + #endif /* !NO_DES3 */ + case ESP_ENC_CBC_AES: err = esp_aes_rfc3602_dec(esp_sa, ip->data, esp_len); break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_ENC_GCM_RFC4106: err = esp_aes_rfc4106_dec(esp_sa, ip->data, esp_len); break; + #endif /*WOLFSSL_AESGCM_STREAM */ + + #if 0 + /* not implemented yet */ + case ESP_ENC_GCM_RFC4543: + err = esp_aes_rfc4543_dec(esp_sa, ip->data, esp_len); + break; + #endif case ESP_ENC_NONE: default: - printf("error: decrypt: invalid enc: %d\n", esp_sa->enc); + printf("error: decrypt unsupported: %d\n", esp_sa->enc); err = -1; break; } @@ -1150,17 +1330,32 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) int err = -1; switch(esp_sa->enc) { + #ifndef NO_DES3 + case ESP_ENC_CBC_DES3: + err = esp_des3_rfc2451_enc(esp_sa, ip->data, payload_len); + break; + #endif /* !NO_DES3 */ + case ESP_ENC_CBC_AES: err = esp_aes_rfc3602_enc(esp_sa, ip->data, payload_len); break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_ENC_GCM_RFC4106: err = esp_aes_rfc4106_enc(esp_sa, ip->data, payload_len); break; + #endif /*WOLFSSL_AESGCM_STREAM */ + + #if 0 + /* not implemented yet */ + case ESP_ENC_GCM_RFC4543: + err = esp_aes_rfc4543_enc(esp_sa, ip->data, payload_len); + break; + #endif case ESP_ENC_NONE: default: - printf("error: encrypt: invalid enc: %d\n", esp_sa->enc); + printf("error: encrypt unsupported: %d\n", esp_sa->enc); err = -1; break; } diff --git a/tools/ip-xfrm/README.md b/tools/ip-xfrm/README.md index 611e5ea..b1a5421 100644 --- a/tools/ip-xfrm/README.md +++ b/tools/ip-xfrm/README.md @@ -20,7 +20,7 @@ wireshark test.pcap Build wolfssl with: ```sh -./configure --enable-aesgcm-stream +./configure --enable-des3 --enable-aesgcm-stream make sudo make install ``` diff --git a/tools/ip-xfrm/des3_auth b/tools/ip-xfrm/des3_auth new file mode 100755 index 0000000..04bad7d --- /dev/null +++ b/tools/ip-xfrm/des3_auth @@ -0,0 +1,69 @@ +#!/bin/bash +# +# des3-cbc (rfc2451) + hmac-[md5,sha1,sha256]-96,128 example. +# + +print_usage_and_die() { + echo "usage:" + echo " des3_auth [auth]" + echo "" + echo " auth = md5, sha1, sha256" + echo "" + echo "examples:" + echo " ./tools/ip-xfrm/des3_auth sha256 128" + echo " ./tools/ip-xfrm/des3_auth sha256 96" + echo " ./tools/ip-xfrm/des3_auth sha1" + echo " ./tools/ip-xfrm/des3_auth md5" + exit 1 +} + +alg=sha1 +ip_proto=tcp +len=96 + +if [ $# -eq 0 ]; then + print_usage_and_die +fi + +if [ $# -eq 1 ]; then + alg=$1 +fi + +if [ $# -eq 2 ]; then + alg=$1 + len=$2 +fi + +if [ $# -eq 3 ]; then + alg=$1 + len=$2 + ip_proto=$3 +fi + +# State +# ipv4 +sudo ip xfrm state add \ + src 10.10.10.1 dst 10.10.10.2 \ + proto esp \ + spi 0x05050505 \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x01010101010101010101010101010101 $len \ + enc des3_ede 0x030303030303030303030303030303030303030303030303 \ + sel src 10.10.10.1 dst 10.10.10.2 + +sudo ip xfrm state add \ + src 10.10.10.2 dst 10.10.10.1 \ + proto esp \ + spi 0x06060606 \ + mode transport \ + replay-window 64 \ + auth-trunc $alg 0x02020202020202020202020202020202 $len \ + enc des3_ede 0x040404040404040404040404040404040404040404040404 \ + sel src 10.10.10.2 dst 10.10.10.1 + +# Policies +# ipv4 +sudo ip xfrm policy add \ + dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x05050505 mode transport + diff --git a/wolfesp.h b/wolfesp.h index 324b89d..e77bc9f 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -12,8 +12,13 @@ /* hmac-[sha256, sha1, md5]-96*/ #define ESP_ICVLEN_HMAC_96 12 #define ESP_ICVLEN_HMAC_128 16 +/* des3-cbc */ +#ifndef NO_DES3 +#define ESP_DES3_KEY_LEN 24 +#define ESP_DES3_IV_LEN 8 +#endif /* !NO_DES3 */ /* max key size */ -#define ESP_MAX_KEY_LEN (AES_MAX_KEY_SIZE / 8) +#define ESP_MAX_KEY_LEN 32 /* aes-cbc */ #define ESP_CBC_RFC3602_IV_LEN 16 /* aes-gcm */ @@ -26,7 +31,9 @@ typedef enum { ESP_ENC_NONE = 0, ESP_ENC_CBC_AES, + #ifndef NO_DES3 ESP_ENC_CBC_DES3, + #endif /* !NO_DES3 */ ESP_ENC_GCM_RFC4106, ESP_ENC_GCM_RFC4543, /* placeholder to indicate gmac auth. */ } esp_enc_t; @@ -75,11 +82,18 @@ struct wolfIP_esp_sa { typedef struct wolfIP_esp_sa wolfIP_esp_sa; int wolfIP_esp_init(void); -void wolfIP_esp_sa_del(void); +void wolfIP_esp_sa_del(int in, uint8_t * spi); +void wolfIP_esp_sa_del_all(void); +#if defined(WOLFSSL_AESGCM_STREAM) int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, uint8_t enc_key_len); -int wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len, - uint8_t * auth_key, uint8_t auth_key_len, - uint8_t icv_len); +#endif /*WOLFSSL_AESGCM_STREAM */ +int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, uint8_t enc_key_len, + esp_auth_t auth, uint8_t * auth_key, + uint8_t auth_key_len, uint8_t icv_len); +int wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, + uint8_t * enc_key, esp_auth_t auth, + uint8_t * auth_key, uint8_t auth_key_len, + uint8_t icv_len); #endif /* !WOLFESP_H */ From 93a506ed90d11599157c40f8af5a60c75b264249 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 10 Feb 2026 17:13:28 -0600 Subject: [PATCH 05/10] esp udp support, refactor debug functions. --- Makefile | 4 +- src/test/esp/esp_common.c | 46 +++++++++++ src/test/{ => esp}/esp_server.c | 26 +----- src/test/{ => esp}/test_esp.c | 27 +------ src/wolfesp.c | 135 ++++++++++++-------------------- src/wolfip.c | 101 +++++------------------- src/wolfip_debug.c | 100 +++++++++++++++++++++++ tools/ip-xfrm/esp_sa.txt | 4 +- 8 files changed, 222 insertions(+), 221 deletions(-) create mode 100644 src/test/esp/esp_common.c rename src/test/{ => esp}/esp_server.c (85%) rename src/test/{ => esp}/test_esp.c (94%) create mode 100644 src/wolfip_debug.c diff --git a/Makefile b/Makefile index 73b4a88..f8c886e 100644 --- a/Makefile +++ b/Makefile @@ -244,7 +244,7 @@ build/esp/wolfip.o: src/wolfip.c @echo "[CC] $< (esp)" @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ -build/test/test_esp.o: src/test/test_esp.c +build/test/test_esp.o: src/test/esp/test_esp.c @echo "[CC] $@" @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ @@ -252,7 +252,7 @@ build/test-esp: $(ESP_OBJ) build/test/test_esp.o @echo "[LD] $@" @$(CC) $(CFLAGS) $(ESP_CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) -lwolfssl $(END_GROUP) -build/test/esp_server.o: src/test/esp_server.c +build/test/esp_server.o: src/test/esp/esp_server.c @echo "[CC] $@" @$(CC) $(CFLAGS) $(ESP_CFLAGS) -c $< -o $@ diff --git a/src/test/esp/esp_common.c b/src/test/esp/esp_common.c new file mode 100644 index 0000000..dd2f8dd --- /dev/null +++ b/src/test/esp/esp_common.c @@ -0,0 +1,46 @@ +/* esp_common.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; +static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; +static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; +static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; +static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; +/* 32 byte key + 4 byte nonce*/ +static uint8_t in_enc_key[36] = + {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t out_enc_key[36] = + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x0a, 0x0b, 0x0c, 0x0d}; +static uint8_t in_auth_key[16] = + {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; +static uint8_t out_auth_key[16] = + {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; diff --git a/src/test/esp_server.c b/src/test/esp/esp_server.c similarity index 85% rename from src/test/esp_server.c rename to src/test/esp/esp_server.c index 23009a8..bfddb57 100644 --- a/src/test/esp_server.c +++ b/src/test/esp/esp_server.c @@ -40,31 +40,7 @@ static int esp_mode = 0; static int use_udp = 0; /* esp security association info */ -static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; -static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; -static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; -static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; -static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; -static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; -/* 32 byte key + 4 byte nonce*/ -static uint8_t in_enc_key[36] = - {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0a, 0x0b, 0x0c, 0x0d}; -static uint8_t out_enc_key[36] = - {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x0a, 0x0b, 0x0c, 0x0d}; -static uint8_t in_auth_key[16] = - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; -static uint8_t out_auth_key[16] = - {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; +#include "esp_common.c" int main(int argc, char * argv[]) { diff --git a/src/test/test_esp.c b/src/test/esp/test_esp.c similarity index 94% rename from src/test/test_esp.c rename to src/test/esp/test_esp.c index f92fc4b..32b6afa 100644 --- a/src/test/test_esp.c +++ b/src/test/esp/test_esp.c @@ -56,31 +56,8 @@ static int client_connected = 0; static const uint8_t test_pattern[16] = {0x54, 0x65, 0x73, 0x74, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x2d, 0x20, 0x2d}; -static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; -static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; -static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; -static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; -static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; -static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; -/* 32 byte key + 4 byte nonce*/ -static uint8_t in_enc_key[36] = - {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, - 0x0a, 0x0b, 0x0c, 0x0d}; -static uint8_t out_enc_key[36] = - {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, - 0x0a, 0x0b, 0x0c, 0x0d}; -static uint8_t in_auth_key[16] = - {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}; -static uint8_t out_auth_key[16] = - {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, - 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}; +/* esp security association info */ +#include "esp_common.c" /* wolfIP: server side callback. */ static void server_cb(int fd, uint16_t event, void *arg) diff --git a/src/wolfesp.c b/src/wolfesp.c index 41cbde0..66b53a1 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -9,6 +9,14 @@ static wolfIP_esp_sa out_sa_list[WOLFIP_ESP_NUM_SA]; static uint16_t in_sa_num = WOLFIP_ESP_NUM_SA; static uint16_t out_sa_num = WOLFIP_ESP_NUM_SA; +#ifdef WOLFIP_DEBUG_ESP + #define ESP_DEBUG(fmt, ...) \ + printf(fmt, ##__VA_ARGS__) +#else + #define ESP_DEBUG(fmt, ...) \ + do { } while (0) +#endif + int wolfIP_esp_init(void) { int err = 0; @@ -95,12 +103,12 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); memcpy(new_sa->enc_key, enc_key, enc_key_len); - new_sa->src = src; - new_sa->dst = dst; - new_sa->enc = ESP_ENC_GCM_RFC4106; + new_sa->src = src; + new_sa->dst = dst; + new_sa->enc = ESP_ENC_GCM_RFC4106; new_sa->enc_key_len = enc_key_len; - new_sa->auth = ESP_AUTH_GCM_RFC4106; - new_sa->icv_len = ESP_GCM_RFC4106_ICV_LEN; + new_sa->auth = ESP_AUTH_GCM_RFC4106; + new_sa->icv_len = ESP_GCM_RFC4106_ICV_LEN; /* Generate pre-iv for gcm. */ err = wc_RNG_GenerateBlock(&wc_rng, new_sa->pre_iv, @@ -114,10 +122,7 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, err = -1; } - #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_sa_new_aead: %s\n", in == 1 ? "in" : "out"); - #endif /* WOLFIP_DEBUG_ESP */ - + ESP_DEBUG("info: esp_sa_new_aead: %s\n", in == 1 ? "in" : "out"); return err; } #endif /*WOLFSSL_AESGCM_STREAM */ @@ -141,18 +146,15 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, memcpy(new_sa->spi, spi, ESP_SPI_LEN); memcpy(new_sa->enc_key, enc_key, enc_key_len); memcpy(new_sa->auth_key, auth_key, auth_key_len); - new_sa->src = src; - new_sa->dst = dst; - new_sa->enc = ESP_ENC_CBC_AES; - new_sa->enc_key_len = enc_key_len; - new_sa->auth = auth; + new_sa->src = src; + new_sa->dst = dst; + new_sa->enc = ESP_ENC_CBC_AES; + new_sa->enc_key_len = enc_key_len; + new_sa->auth = auth; new_sa->auth_key_len = auth_key_len; - new_sa->icv_len = icv_len; - - #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); - #endif /* WOLFIP_DEBUG_ESP */ + new_sa->icv_len = icv_len; + ESP_DEBUG("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); return 0; } @@ -184,10 +186,7 @@ wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, new_sa->auth_key_len = auth_key_len; new_sa->icv_len = icv_len; - #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); - #endif /* WOLFIP_DEBUG_ESP */ - + ESP_DEBUG("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); return 0; } @@ -474,9 +473,7 @@ esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint16_t enc_len = 0; uint8_t inited = 0; - #ifdef WOLFIP_DEBUG_ESP - printf("info: aes cbc dec: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: aes cbc dec: %d\n", esp_len); enc_len = esp_enc_len(esp_len, iv_len, icv_len); enc_payload = esp_enc_payload(esp_data, iv_len); @@ -528,9 +525,7 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint16_t enc_len = 0; uint8_t inited = 0; - #ifdef WOLFIP_DEBUG_ESP - printf("info: aes cbc enc: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: aes cbc enc: %d\n", esp_len); enc_len = esp_enc_len(esp_len, iv_len, icv_len); enc_payload = esp_enc_payload(esp_data, iv_len); @@ -590,9 +585,7 @@ esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint16_t enc_len = 0; uint8_t inited = 0; - #ifdef WOLFIP_DEBUG_ESP - printf("info: des3 dec: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: des3 dec: %d\n", esp_len); if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { printf("error: des3_rfc2451_dec: key len = %d, expected %d\n", @@ -649,9 +642,7 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint16_t enc_len = 0; uint8_t inited = 0; - #ifdef WOLFIP_DEBUG_ESP - printf("info: des3 enc: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: des3 enc: %d\n", esp_len); if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { printf("error: des3_rfc2451_enc: key len = %d, expected %d\n", @@ -726,9 +717,7 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ - #ifdef WOLFIP_DEBUG_ESP - printf("info: aes gcm dec: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: aes gcm dec: %d\n", esp_len); /* get enc payload, iv, and icv pointers. */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); @@ -803,9 +792,7 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ - #ifdef WOLFIP_DEBUG_ESP - printf("info: aes gcm enc: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: aes gcm enc: %d\n", esp_len); /* get enc payload, iv, and icv pointers. */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); @@ -929,16 +916,12 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) uint32_t bitn = 0; uint32_t seq_low = replay->hi_seq - ESP_REPLAY_WIN; - #if WOLFIP_DEBUG_ESP - printf("info: seq: %u\n", seq); - #endif - if (seq == 0) { return -1; } if (seq < seq_low) { - printf("error: seq (%d) below window (%d)\n", seq, seq_low); + ESP_DEBUG("error: seq (%d) below window (%d)\n", seq, seq_low); return -1; } @@ -951,21 +934,17 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) bitn = 1U << (replay->hi_seq - seq); if ((replay->bitmap & bitn) != 0U) { - printf("error: seq replayed: %u, %d\n", bitn, seq); + ESP_DEBUG("error: seq replayed: %u, %d\n", bitn, seq); return -1; } else { - #if WOLFIP_DEBUG_ESP - printf("info: new seq : %d\n", seq); - #endif + ESP_DEBUG("info: new seq : %d\n", seq); replay->bitmap |= bitn; } } else { /* seq number above window. */ - #if WOLFIP_DEBUG_ESP - printf("info: new hi_seq : %d, %d\n", replay->hi_seq, seq); - #endif + ESP_DEBUG("info: new hi_seq : %d, %d\n", replay->hi_seq, seq); diff = seq - replay->hi_seq; if (diff < ESP_REPLAY_WIN) { /* within a window width, slide up. */ @@ -1009,8 +988,7 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) * Returns -1 on error. * */ static int -esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, - uint32_t * frame_len) +esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) { uint8_t spi[ESP_SPI_LEN]; uint32_t seq = 0; @@ -1024,9 +1002,7 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, memset(spi, 0, sizeof(spi)); if (*frame_len <= (ETH_HEADER_LEN + IP_HEADER_LEN)) { - #ifdef WOLFIP_DEBUG_ESP - printf("error: esp: malformed frame: %d\n", *frame_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("error: esp: malformed frame: %d\n", *frame_len); return -1; } @@ -1034,9 +1010,7 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, /* If not at least SPI and sequence, something wrong. */ if (esp_len < (ESP_SPI_LEN + ESP_SEQ_LEN)) { - #ifdef WOLFIP_DEBUG_ESP - printf("error: esp: malformed packet: %d\n", esp_len); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("error: esp: malformed packet: %d\n", esp_len); return -1; } @@ -1048,10 +1022,8 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, for (size_t i = 0; i < in_sa_num; ++i) { if (memcmp(spi, in_sa_list[i].spi, sizeof(spi)) == 0) { - #ifdef WOLFIP_DEBUG_ESP - printf("info: found sa: 0x%02x%02x%02x%02x\n", - spi[0], spi[1], spi[2], spi[3]); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: found sa: 0x%02x%02x%02x%02x\n", + spi[0], spi[1], spi[2], spi[3]); esp_sa = &in_sa_list[i]; break; } @@ -1073,7 +1045,6 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, } iv_len = esp_iv_len_from_enc(esp_sa->enc); - { /* calculate min expected length based on the security association. */ uint32_t min_len = 0; @@ -1182,8 +1153,6 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, ip->proto = nxt_hdr; ip->csum = 0; iphdr_set_checksum(ip); - - (void)s; return 0; } @@ -1206,8 +1175,8 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, * |<--- integrity checked ---->| * * Returns 0 on success. - * Returns -1 on error. * Returns 1 if no ipsec policy found (send plaintext) + * Returns -1 on error. * */ static int esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) @@ -1228,11 +1197,9 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) for (size_t i = 0; i < out_sa_num; ++i) { if (ip->dst == ee32(out_sa_list[i].dst)) { esp_sa = &out_sa_list[i]; - #ifdef WOLFIP_DEBUG_ESP - printf("info: found out sa: 0x%02x%02x%02x%02x\n", - esp_sa->spi[0], esp_sa->spi[1], esp_sa->spi[2], - esp_sa->spi[3]); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: found out sa: 0x%02x%02x%02x%02x\n", + esp_sa->spi[0], esp_sa->spi[1], esp_sa->spi[2], + esp_sa->spi[3]); break; } } @@ -1409,13 +1376,16 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) * Copy frame to new packet so we can expand and wrap in place * without stepping on the fifo tcp circular buffer. * - * A more intelligent way to do this would be to save extra scratch space - * in the fifo circular buffer for each tcp packet, so we can expand in place. + * A better way to do this would be to save extra scratch space in the fifo + * circular buffer for each tcp packet, so we can expand in place. + * + * Returns 0 on success. + * Returns 1 if no ipsec policy found (send plaintext) + * Returns -1 on error. * */ static int -esp_tcp_output(struct wolfIP_ll_dev * ll_dev, - const struct wolfIP_ip_packet *ip, - uint16_t len) +esp_send(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, + uint16_t len) { /** * 60 is reasonable max ESP overhead (for now), rounded up to 4 bytes. @@ -1437,9 +1407,7 @@ esp_tcp_output(struct wolfIP_ll_dev * ll_dev, esp_rc = esp_transport_wrap(esp, &ip_final_len); if (esp_rc) { - #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_wrap returned: %d\n", esp_rc); - #endif /* WOLFIP_DEBUG_ESP */ + ESP_DEBUG("info: esp_wrap: %d\n", esp_rc); return esp_rc; } @@ -1448,9 +1416,8 @@ esp_tcp_output(struct wolfIP_ll_dev * ll_dev, esp->proto = 0x32; esp->csum = 0; iphdr_set_checksum(esp); - + /* send it */ ll_dev->send(ll_dev, esp, ip_final_len + ETH_HEADER_LEN); - return 0; } #endif /* WOLFIP_ESP && !WOLFESP_SRC */ diff --git a/src/wolfip.c b/src/wolfip.c index bc15bf4..8ff0e52 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3723,65 +3723,9 @@ size_t wolfIP_instance_size(void) return sizeof(struct wolfIP); } -#ifdef DEBUG_IP -static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) -{ - char src[32]; - char dst[32]; - memset(src, 0, sizeof(src)); - memset(dst, 0, sizeof(dst)); - iptoa(ee32(ip->src), src); - iptoa(ee32(ip->dst), dst); - - printf("ip hdr:\n"); - printf("+-----------------------------+\n"); - printf("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", - 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); - printf("+-----------------------------+\n"); - printf("| 0x%04x | 0x%04x | (id, flags_fo)\n", - ee16(ip->id), ee16(ip->flags_fo)); - printf("+-----------------------------+\n"); - printf("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", - ip->ttl, ip->proto, ee16(ip->csum)); - printf("+-----------------------------+\n"); - printf("| %15s | (src)\n", src); - printf("+-----------------------------+\n"); - printf("| %15s | (dst)\n", dst); - printf("+-----------------------------+\n"); - printf("\n"); -} -#endif /* DEBUG_IP*/ - -#ifdef DEBUG_UDP -static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) -{ - uint16_t len = ee16(udp->len); - char payload_str[32]; - printf("udp hdr:\n"); - printf("+-------------------+\n"); - printf("| %5d | %5d | (src_port, dst_port)\n", - ee16(udp->src_port), ee16(udp->dst_port)); - printf("+-------------------+\n"); - printf("| %5u | 0x%04x | (len, chksum)\n", - len, ee16(udp->csum)); - printf("+-------------------+\n"); - memset(payload_str, '\0', sizeof(payload_str)); - { - /* show first 16 printable chars of payload */ - uint16_t max_len = 16; - size_t print_len = (len - 8) < max_len ? (len - 8): max_len; - size_t i = 0; - memset(payload_str, '\0', sizeof(payload_str)); - memcpy(payload_str, udp->data, print_len); - for (i = 0; i < print_len; i++) { - if (!isprint(payload_str[i])) { payload_str[i] = '.'; } - } - } - printf("| %17s | (payload first 16 bytes)\n", payload_str); - printf("+-------------------+\n"); - printf("\n"); -} -#endif /* DEBUG_UDP */ +#if defined(DEBUG_ETH) || defined(DEBUG_IP) || defined(DEBUG_UDP) +#include "src/wolfip_debug.c" +#endif /* DEBUG_ETH || DEBUG_IP || DEBUG_UDP */ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) @@ -3843,7 +3787,6 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, } } #endif /* WOLFIP_ENABLE_FORWARDING */ - #ifdef DEBUG_IP wolfIP_print_ip(ip); #endif /* DEBUG_IP*/ @@ -3853,7 +3796,7 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, * ip forwarding would require esp tunnel mode. */ if (ip->proto == 0x32) { /* proto is ESP 0x32 (50), try to unwrap. */ - int err = esp_transport_unwrap(s, ip, &len); + int err = esp_transport_unwrap(ip, &len); if (err) { printf("info: failed to unwrap esp packet, dropping.\n"); return; @@ -3882,26 +3825,6 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, #endif } -#ifdef DEBUG_ETH -static void wolfIP_print_eth(struct wolfIP_eth_frame * eth, uint32_t len) -{ - uint8_t * dst = eth->dst; - uint8_t * src = eth->src; - uint8_t * type = (uint8_t *) ð->type; - printf("eth hdr:\n"); - printf("+---------------------------------------+\n"); - printf("| %02x:%02x:%02x:%02x:%02x:%02x " - "| %02x:%02x:%02x:%02x:%02x:%02x | (src, dst) \n", - src[0], src[1], src[2], src[3], src[4], src[5], - dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]); - printf("+---------------------------------------+\n"); - printf("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", - type[0], type[1], (unsigned long)len); - printf("+---------------------------------------+\n"); - printf("\n"); -} -#endif /* DEBUG_ETH */ - static void wolfIP_recv_on(struct wolfIP *s, unsigned int if_idx, void *buf, uint32_t len) { #ifdef ETHERNET @@ -4389,7 +4312,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); if (ll && ll->send) { #ifdef WOLFIP_ESP - int esp_err = esp_tcp_output(ll, (struct wolfIP_ip_packet *)tcp, size); + int esp_err = esp_send(ll, (struct wolfIP_ip_packet *)tcp, size); if (esp_err == 1) { /* ipsec not configured on this interface. * send plaintext. */ @@ -4463,8 +4386,20 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) #endif { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); - if (ll && ll->send) + if (ll && ll->send) { + #ifdef DEBUG_UDP + wolfIP_print_udp(udp); + #endif /* DEBUG_UDP */ + #ifdef WOLFIP_ESP + if (esp_send(ll, (struct wolfIP_ip_packet *)udp, len) == 1) { + /* ipsec not configured on this interface. + * send plaintext. */ + ll->send(ll, udp, desc->len); + } + #else ll->send(ll, udp, desc->len); + #endif /* WOLFIP_ESP */ + } } fifo_pop(&t->sock.udp.txbuf); desc = fifo_peek(&t->sock.udp.txbuf); diff --git a/src/wolfip_debug.c b/src/wolfip_debug.c new file mode 100644 index 0000000..572797e --- /dev/null +++ b/src/wolfip_debug.c @@ -0,0 +1,100 @@ +/* wolfip_debug.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#if defined(ETHERNET) && defined(DEBUG_ETH) +static void wolfIP_print_eth(struct wolfIP_eth_frame * eth, uint32_t len) +{ + uint8_t * dst = eth->dst; + uint8_t * src = eth->src; + uint8_t * type = (uint8_t *) ð->type; + printf("eth hdr:\n"); + printf("+---------------------------------------+\n"); + printf("| %02x:%02x:%02x:%02x:%02x:%02x " + "| %02x:%02x:%02x:%02x:%02x:%02x | (dst, src) \n", + dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], + src[0], src[1], src[2], src[3], src[4], src[5]); + printf("+---------------------------------------+\n"); + printf("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", + type[0], type[1], (unsigned long)len); + printf("+---------------------------------------+\n"); + printf("\n"); +} +#endif /* ETHERNET && DEBUG_ETH */ + +#ifdef DEBUG_IP +static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) +{ + char src[32]; + char dst[32]; + memset(src, 0, sizeof(src)); + memset(dst, 0, sizeof(dst)); + iptoa(ee32(ip->src), src); + iptoa(ee32(ip->dst), dst); + + printf("ip hdr:\n"); + printf("+-----------------------------+\n"); + printf("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", + 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); + printf("+-----------------------------+\n"); + printf("| 0x%04x | 0x%04x | (id, flags_fo)\n", + ee16(ip->id), ee16(ip->flags_fo)); + printf("+-----------------------------+\n"); + printf("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", + ip->ttl, ip->proto, ee16(ip->csum)); + printf("+-----------------------------+\n"); + printf("| %15s | (src)\n", src); + printf("+-----------------------------+\n"); + printf("| %15s | (dst)\n", dst); + printf("+-----------------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_IP*/ + +#ifdef DEBUG_UDP +static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) +{ + uint16_t len = ee16(udp->len); + char payload_str[32]; + printf("udp hdr:\n"); + printf("+-------------------+\n"); + printf("| %5d | %5d | (src_port, dst_port)\n", + ee16(udp->src_port), ee16(udp->dst_port)); + printf("+-------------------+\n"); + printf("| %5u | 0x%04x | (len, chksum)\n", + len, ee16(udp->csum)); + printf("+-------------------+\n"); + memset(payload_str, '\0', sizeof(payload_str)); + { + /* show first 16 printable chars of payload */ + uint16_t max_len = 16; + size_t print_len = (len - 8) < max_len ? (len - 8): max_len; + size_t i = 0; + memset(payload_str, '\0', sizeof(payload_str)); + memcpy(payload_str, udp->data, print_len); + for (i = 0; i < print_len; i++) { + if (!isprint(payload_str[i])) { payload_str[i] = '.'; } + } + } + printf("| %17s | (payload first 16 bytes)\n", payload_str); + printf("+-------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_UDP */ diff --git a/tools/ip-xfrm/esp_sa.txt b/tools/ip-xfrm/esp_sa.txt index 846c233..5e269a6 100644 --- a/tools/ip-xfrm/esp_sa.txt +++ b/tools/ip-xfrm/esp_sa.txt @@ -2,9 +2,9 @@ # You can add (but not modify or delete) records with the command line option: # -o 'uat:esp_sa:"protocol","srcIP","dstIP","spi","encryption_algo","encryption_key_string","authentication_algo","authentication_key_string","sn_length","sn_upper"' #"Protocol","Src IP","Dest IP","SPI","Encryption","Encryption Key","Authentication","Authentication Key","SN","ESN High Bits" -"IPv4","10.10.10.1","10.10.10.2","0x05050505","NULL","","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" -"IPv4","10.10.10.2","10.10.10.1","0x06060606","NULL","","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" "IPv4","10.10.10.1","10.10.10.2","0x03030303","AES-CBC [RFC3602]","0x0303030303030303030303030303030303030303030303030303030303030303","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" "IPv4","10.10.10.2","10.10.10.1","0x04040404","AES-CBC [RFC3602]","0x0404040404040404040404040404040404040404040404040404040404040404","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" "IPv4","10.10.10.1","10.10.10.2","0x01010101","AES-GCM with 16 octet ICV [RFC4106]","0x03030303030303030303030303030303030303030303030303030303030303030a0b0c0d","NULL","","32-bit","0" "IPv4","10.10.10.2","10.10.10.1","0x02020202","AES-GCM with 16 octet ICV [RFC4106]","0x04040404040404040404040404040404040404040404040404040404040404040a0b0c0d","NULL","","32-bit","0" +"IPv4","10.10.10.1","10.10.10.2","0x05050505","TripleDES-CBC [RFC2451]","0x030303030303030303030303030303030303030303030303","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" +"IPv4","10.10.10.2","10.10.10.1","0x06060606","TripleDES-CBC [RFC2451]","0x040404040404040404040404040404040404040404040404","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" From 55ce272314492a27d6f5bd987b73a5e50e64b0c2 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 11 Feb 2026 00:32:30 -0600 Subject: [PATCH 06/10] esp: support rfc4543 gmac. --- src/test/esp/esp_common.c | 2 + src/test/esp/esp_server.c | 26 +++-- src/test/esp/test_esp.c | 26 +++-- src/wolfesp.c | 203 ++++++++++++++++++++++++++++++-------- tools/ip-xfrm/rfc4543 | 62 ++++++++++++ wolfesp.h | 14 ++- 6 files changed, 273 insertions(+), 60 deletions(-) create mode 100755 tools/ip-xfrm/rfc4543 diff --git a/src/test/esp/esp_common.c b/src/test/esp/esp_common.c index dd2f8dd..1b7aa91 100644 --- a/src/test/esp/esp_common.c +++ b/src/test/esp/esp_common.c @@ -25,6 +25,8 @@ static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; +static uint8_t in_sa_gmac[ESP_SPI_LEN] = {0x07, 0x07, 0x07, 0x07}; +static uint8_t out_sa_gmac[ESP_SPI_LEN] = {0x08, 0x08, 0x08, 0x08}; /* 32 byte key + 4 byte nonce*/ static uint8_t in_enc_key[36] = {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, diff --git a/src/test/esp/esp_server.c b/src/test/esp/esp_server.c index bfddb57..9b1cacc 100644 --- a/src/test/esp/esp_server.c +++ b/src/test/esp/esp_server.c @@ -81,14 +81,14 @@ int main(int argc, char * argv[]) switch (esp_mode) { case 0: - err = wolfIP_esp_sa_new_aead(1, in_sa_gcm, atoip4(HOST_STACK_IP), - atoip4(WOLFIP_IP), - in_enc_key, sizeof(in_enc_key)); + err = wolfIP_esp_sa_new_gcm(1, in_sa_gcm, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4106, + in_enc_key, sizeof(in_enc_key)); if (err) { return err; } - err = wolfIP_esp_sa_new_aead(0, out_sa_gcm, atoip4(WOLFIP_IP), - atoip4(HOST_STACK_IP), - out_enc_key, sizeof(out_enc_key)); + err = wolfIP_esp_sa_new_gcm(0, out_sa_gcm, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), ESP_ENC_GCM_RFC4106, + out_enc_key, sizeof(out_enc_key)); if (err) { return err; } break; @@ -126,6 +126,18 @@ int main(int argc, char * argv[]) if (err) { return err; } break; + case 3: + err = wolfIP_esp_sa_new_gcm(1, in_sa_gmac, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4543, + in_enc_key, sizeof(in_enc_key)); + if (err) { return err; } + + err = wolfIP_esp_sa_new_gcm(0, out_sa_gmac, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), ESP_ENC_GCM_RFC4543, + out_enc_key, sizeof(out_enc_key)); + if (err) { return err; } + break; + default: break; } @@ -218,7 +230,7 @@ print_usage_and_die(void) printf("\n"); printf("options:\n"); printf(" -p force plaintext (disable ipsec)\n"); - printf(" -m 0 aead (default), 1 cbc auth\n"); + printf(" -m 0 gcm (default), 1 cbc auth, 2 des3 hmac, 3 gmac\n"); printf(" -u use udp (default tcp)\n"); exit(1); } diff --git a/src/test/esp/test_esp.c b/src/test/esp/test_esp.c index 32b6afa..90569a9 100644 --- a/src/test/esp/test_esp.c +++ b/src/test/esp/test_esp.c @@ -555,14 +555,14 @@ int main(int argc, char **argv) if (!disable_ipsec) { switch (mode) { case 0: - err = wolfIP_esp_sa_new_aead(1, in_sa_gcm, atoip4(HOST_STACK_IP), - atoip4(WOLFIP_IP), - in_enc_key, sizeof(in_enc_key)); + err = wolfIP_esp_sa_new_gcm(1, in_sa_gcm, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4106, + in_enc_key, sizeof(in_enc_key)); if (err) { return err; } - err = wolfIP_esp_sa_new_aead(0, out_sa_gcm, atoip4(WOLFIP_IP), - atoip4(HOST_STACK_IP), - out_enc_key, sizeof(out_enc_key)); + err = wolfIP_esp_sa_new_gcm(0, out_sa_gcm, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), ESP_ENC_GCM_RFC4106, + out_enc_key, sizeof(out_enc_key)); if (err) { return err; } break; @@ -600,6 +600,18 @@ int main(int argc, char **argv) if (err) { return err; } break; + case 3: + err = wolfIP_esp_sa_new_gcm(1, in_sa_gmac, atoip4(HOST_STACK_IP), + atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4543, + in_enc_key, sizeof(in_enc_key)); + if (err) { return err; } + + err = wolfIP_esp_sa_new_gcm(0, out_sa_gmac, atoip4(WOLFIP_IP), + atoip4(HOST_STACK_IP), ESP_ENC_GCM_RFC4543, + out_enc_key, sizeof(out_enc_key)); + if (err) { return err; } + break; + default: break; } @@ -624,6 +636,6 @@ print_usage_and_die(void) printf("\n"); printf("options:\n"); printf(" -p force plaintext (disable ipsec)\n"); - printf(" -m 0 aead (default), 1 cbc hmac, 2 des3 hmac\n"); + printf(" -m 0 gcm (default), 1 cbc hmac, 2 des3 hmac, 3 gmac\n"); exit(1); } diff --git a/src/wolfesp.c b/src/wolfesp.c index 66b53a1..f1d0392 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -85,12 +85,16 @@ void wolfIP_esp_sa_del_spi(int in, uint8_t * spi) return ; } -#if defined(WOLFSSL_AESGCM_STREAM) -int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len) +/* Configure a new Security Association based on either + * enc = ESP_ENC_GCM_RFC4106 (gcm), or enc = ESP_AUTH_GCM_RFC4543 (gmac). + * */ +int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, + esp_enc_t enc, uint8_t * enc_key, + uint8_t enc_key_len) { wolfIP_esp_sa * new_sa = NULL; int err = 0; + esp_auth_t auth = 0; new_sa = esp_sa_get(in, NULL); @@ -99,15 +103,30 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, return -1; } + switch (enc) { + #if defined(WOLFSSL_AESGCM_STREAM) + case ESP_ENC_GCM_RFC4106: + auth = ESP_AUTH_GCM_RFC4106; + break; + #endif /* WOLFSSL_AESGCM_STREAM */ + case ESP_ENC_GCM_RFC4543: + auth = ESP_AUTH_GCM_RFC4543; + break; + default: + printf("error: unsupported enc: %d\n", enc); + return -1; + } + memset(new_sa, 0, sizeof(*new_sa)); esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); memcpy(new_sa->enc_key, enc_key, enc_key_len); new_sa->src = src; new_sa->dst = dst; - new_sa->enc = ESP_ENC_GCM_RFC4106; + new_sa->enc = enc; new_sa->enc_key_len = enc_key_len; - new_sa->auth = ESP_AUTH_GCM_RFC4106; + new_sa->auth = auth; + /* rfc4106 and rfc4543 follow the same IV and ICV standards. */ new_sa->icv_len = ESP_GCM_RFC4106_ICV_LEN; /* Generate pre-iv for gcm. */ @@ -125,8 +144,9 @@ int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, ESP_DEBUG("info: esp_sa_new_aead: %s\n", in == 1 ? "in" : "out"); return err; } -#endif /*WOLFSSL_AESGCM_STREAM */ +/* Configure a new Security Association based on aes-cbc with hmac. + * */ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, uint8_t enc_key_len, esp_auth_t auth, uint8_t * auth_key, @@ -158,6 +178,8 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, return 0; } +/* Configure a new Security Association based on des3 with hmac. + * */ int wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, esp_auth_t auth, @@ -480,16 +502,14 @@ esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, iv = esp_enc_iv(esp_data, iv_len); ret = wc_AesInit(&cbc_dec, NULL, INVALID_DEVID); - if (ret != 0) { printf("error: wc_AesInit returned: %d\n", ret); goto aes_dec_out; } - inited = 1; + ret = wc_AesSetKey(&cbc_dec, esp_sa->enc_key, esp_sa->enc_key_len, iv, AES_DECRYPTION); - if (ret != 0) { printf("error: wc_AesSetKey returned: %d\n", ret); goto aes_dec_out; @@ -497,7 +517,6 @@ esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* decrypt in place. */ ret = wc_AesCbcDecrypt(&cbc_dec, enc_payload, enc_payload, enc_len); - if (ret != 0) { printf("error: wc_AesCbcDecrypt returned: %d\n", ret); goto aes_dec_out; @@ -533,14 +552,12 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* Generate random iv block for cbc method. */ ret = wc_RNG_GenerateBlock(&wc_rng, iv, iv_len); - if (ret) { printf("error: wc_RNG_GenerateBlock returned: %d\n", ret); goto aes_enc_out; } ret = wc_AesInit(&cbc_enc, NULL, INVALID_DEVID); - if (ret != 0) { printf("error: wc_AesInit returned: %d\n", ret); goto aes_enc_out; @@ -549,14 +566,12 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, inited = 1; ret = wc_AesSetKey(&cbc_enc, esp_sa->enc_key, esp_sa->enc_key_len, iv, AES_ENCRYPTION); - if (ret != 0) { printf("error: wc_AesSetKey returned: %d\n", ret); goto aes_enc_out; } ret = wc_AesCbcEncrypt(&cbc_enc, enc_payload, enc_payload, enc_len); - if (ret != 0) { printf("error: wc_AesCbcEncrypt returned: %d\n", ret); goto aes_enc_out; @@ -598,15 +613,13 @@ esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, iv = esp_enc_iv(esp_data, iv_len); ret = wc_Des3Init(&des3_dec, NULL, INVALID_DEVID); - if (ret != 0) { printf("error: wc_Des3Init returned: %d\n", ret); goto des3_dec_out; } - inited = 1; - ret = wc_Des3_SetKey(&des3_dec, esp_sa->enc_key, iv, DES_DECRYPTION); + ret = wc_Des3_SetKey(&des3_dec, esp_sa->enc_key, iv, DES_DECRYPTION); if (ret != 0) { printf("error: wc_Des3_SetKey returned: %d\n", ret); goto des3_dec_out; @@ -614,7 +627,6 @@ esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* decrypt in place. */ ret = wc_Des3_CbcDecrypt(&des3_dec, enc_payload, enc_payload, enc_len); - if (ret != 0) { printf("error: wc_Des3_CbcDecrypt returned: %d\n", ret); goto des3_dec_out; @@ -660,10 +672,9 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, printf("error: wc_Des3Init returned: %d\n", ret); goto des3_enc_out; } - inited = 1; - ret = wc_Des3_SetKey(&des3_enc, esp_sa->enc_key, iv, DES_ENCRYPTION); + ret = wc_Des3_SetKey(&des3_enc, esp_sa->enc_key, iv, DES_ENCRYPTION); if (ret != 0) { printf("error: wc_Des3_SetKey returned: %d\n", ret); goto des3_enc_out; @@ -671,7 +682,6 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* encrypt in place. */ ret = wc_Des3_CbcEncrypt(&des3_enc, enc_payload, enc_payload, enc_len); - if (ret != 0) { printf("error: wc_Des3_CbcEncrypt returned: %d\n", ret); goto des3_enc_out; @@ -687,7 +697,6 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } #endif /* !NO_DES3 */ -#if defined(WOLFSSL_AESGCM_STREAM) /** * AES-GCM-ESP * The KEYMAT requested for each AES-GCM key is N + 4 octets. The first @@ -698,6 +707,7 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + (esp_sa)->enc_key_len \ - ESP_GCM_RFC4106_SALT_LEN +#if defined(WOLFSSL_AESGCM_STREAM) static int esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint32_t esp_len) @@ -732,25 +742,21 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, memcpy(nonce + salt_len, iv, iv_len); err = wc_AesInit(&gcm_dec, NULL, INVALID_DEVID); - if (err != 0) { printf("error: wc_AesInit: %d\n", err); goto rfc4106_dec_out; } - inited = 1; /* subtract 4 byte salt from enc_key_len */ err = wc_AesGcmInit(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4, nonce, sizeof(nonce)); - if (err != 0) { printf("error: wc_AesGcmInit: %d\n", err); goto rfc4106_dec_out; } err = wc_AesGcmSetKey(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4); - if (err != 0) { printf("error: wc_AesGcmSetKey: %d\n", err); goto rfc4106_dec_out; @@ -758,7 +764,6 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesGcmDecrypt(&gcm_dec, enc_payload, enc_payload, enc_len, nonce, sizeof(nonce), icv, icv_len, aad, aad_len); - if (err != 0) { printf("error: wc_AesGcmDecrypt: %d\n", err); goto rfc4106_dec_out; @@ -828,25 +833,21 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, memcpy(nonce + salt_len, iv, iv_len); err = wc_AesInit(&gcm_enc, NULL, INVALID_DEVID); - if (err != 0) { printf("error: wc_AesInit: %d\n", err); goto rfc4106_enc_out; } - inited = 1; /* subtract 4 byte salt from enc_key_len */ err = wc_AesGcmInit(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4, nonce, sizeof(nonce)); - if (err != 0) { printf("error: wc_AesGcmInit: %d\n", err); goto rfc4106_enc_out; } err = wc_AesGcmSetKey(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4); - if (err != 0) { printf("error: wc_AesGcmSetKey: %d\n", err); goto rfc4106_enc_out; @@ -854,7 +855,6 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesGcmEncrypt(&gcm_enc, enc_payload, enc_payload, enc_len, nonce, sizeof(nonce), icv, icv_len, aad, aad_len); - if (err != 0) { printf("error: wc_AesGcmDecrypt: %d\n", err); goto rfc4106_enc_out; @@ -870,6 +870,133 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } #endif /*WOLFSSL_AESGCM_STREAM */ +/** + * In rfc4543(gcm(aes)) the AAD consists ofthe SPI, Sequence Number, + * and ESP Payload, and the AES-GCM plaintext is zero-length, while in + * rfc4106(gcm(aes)) the AAD consists only of the SPI and Sequence Number, + * and the AES-GCM plaintext consists of the ESP Payload. + * _____________ _______________________________________________________ + * |aad (N bytes)| = |SPI (4 bytes) + Sequence Number (4 bytes) + ESP Payload| + * ------------- ------------------------------------------------------- + * */ +static int +esp_aes_rfc4543_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + int err = -1; + uint8_t * icv = NULL; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_GCM_RFC4106_IV_LEN; + uint8_t * iv = NULL; + uint8_t * aad = esp_data; + uint16_t aad_len = esp_len - icv_len; + const uint8_t * salt = NULL; + uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; + uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ + + ESP_DEBUG("info: aes gcm rfc4543 dec: %d\n", esp_len); + + /* get enc payload, iv, and icv pointers. */ + iv = esp_enc_iv(esp_data, iv_len); + icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); + + /* Get the salt, and construct nonce. */ + salt = esp_rfc4106_salt(esp_sa); + memcpy(nonce, salt, salt_len); + memcpy(nonce + salt_len, iv, iv_len); + + err = wc_GmacVerify(esp_sa->enc_key, esp_sa->enc_key_len - 4, + nonce, sizeof(nonce), aad, aad_len, + icv, icv_len); + + if (err != 0) { + printf("error: wc_GmacVerify: %d\n", err); + goto rfc4543_dec_out; + } + +rfc4543_dec_out: + return err; +} + +static int +esp_aes_rfc4543_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + uint32_t esp_len) +{ + Gmac gmac_enc; + int err = -1; + uint8_t * icv = NULL; + uint8_t icv_len = esp_sa->icv_len; + uint8_t iv_len = ESP_GCM_RFC4106_IV_LEN; + uint8_t * iv = NULL; + uint8_t inited = 0; + uint8_t * aad = esp_data; + uint16_t aad_len = esp_len - icv_len; + const uint8_t * salt = NULL; + uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; + uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ + + ESP_DEBUG("info: aes gcm enc: %d\n", esp_len); + + /* get enc payload, iv, and icv pointers. */ + iv = esp_enc_iv(esp_data, iv_len); + icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); + + /* Get the salt. */ + salt = esp_rfc4106_salt(esp_sa); + + { + /* Deterministic iv construction using pre-iv salt and sequence number. + * NIST SP 800-38D, section 8.2.1 Deterministic Construction, using + * an integer counter. The sequence number is used as a counter, and + * xor'ed with pre-iv salt. Based on linux kernel crypto/seqiv.c. + * */ + uint32_t seq_num = 0; + uint8_t * seq_num_u8 = (uint8_t *) &seq_num; + + seq_num = ee32(esp_sa->replay.oseq); + + /* copy in the pre_iv. */ + memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); + + /* xor pre-iv salt with current sequence number. */ + for (size_t i = 0; i < sizeof(uint32_t); ++i) { + iv[i + sizeof(uint32_t)] ^= seq_num_u8[i]; + } + } + + memcpy(nonce, salt, salt_len); + memcpy(nonce + salt_len, iv, iv_len); + + err = wc_AesInit(&gmac_enc.aes, NULL, INVALID_DEVID); + if (err != 0) { + printf("error: wc_AesInit: %d\n", err); + goto rfc4543_enc_out; + } + inited = 1; + + /* subtract 4 byte salt from enc_key_len */ + err = wc_GmacSetKey(&gmac_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4); + if (err != 0) { + printf("error: wc_AesGcmSetKey: %d\n", err); + goto rfc4543_enc_out; + } + + err = wc_GmacUpdate(&gmac_enc, nonce, sizeof(nonce), aad, aad_len, + icv, icv_len); + if (err != 0) { + printf("error: wc_AesGmacUpdate: %d\n", err); + goto rfc4543_enc_out; + } + +rfc4543_enc_out: + if (inited) { + wc_AesFree(&gmac_enc.aes); + inited = 0; + } + + return err; +} + /** * esp_data covers from start of ESP header to end of ESP trailer, but does not * include the ESP ICV after trailer. @@ -1103,12 +1230,9 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) break; #endif /*WOLFSSL_AESGCM_STREAM */ - #if 0 - /* not implemented yet */ case ESP_ENC_GCM_RFC4543: err = esp_aes_rfc4543_dec(esp_sa, ip->data, esp_len); break; - #endif case ESP_ENC_NONE: default: @@ -1192,7 +1316,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) wolfIP_esp_sa * esp_sa = NULL; uint8_t iv_len = 0; - /* TODO: priority, tcp/udp port-filtering? currently this grabs + /* todo: priority, proto / port filtering. currently this grabs * the first dst match. */ for (size_t i = 0; i < out_sa_num; ++i) { if (ip->dst == ee32(out_sa_list[i].dst)) { @@ -1313,12 +1437,9 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) break; #endif /*WOLFSSL_AESGCM_STREAM */ - #if 0 - /* not implemented yet */ case ESP_ENC_GCM_RFC4543: err = esp_aes_rfc4543_enc(esp_sa, ip->data, payload_len); break; - #endif case ESP_ENC_NONE: default: @@ -1374,10 +1495,10 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) /** * Copy frame to new packet so we can expand and wrap in place - * without stepping on the fifo tcp circular buffer. + * without stepping on the fifo circular buffer. * * A better way to do this would be to save extra scratch space in the fifo - * circular buffer for each tcp packet, so we can expand in place. + * circular buffer for each packet, so we can expand in place. * * Returns 0 on success. * Returns 1 if no ipsec policy found (send plaintext) diff --git a/tools/ip-xfrm/rfc4543 b/tools/ip-xfrm/rfc4543 new file mode 100755 index 0000000..1cfef70 --- /dev/null +++ b/tools/ip-xfrm/rfc4543 @@ -0,0 +1,62 @@ +#!/bin/bash +# +# rfc4543(gcm(aes)) example: aes-gcm encryption + auth. +# +# The 4 byte nonce is placed at end of key, forming 20 bytes +# of key material. +# + +print_usage_and_die() { + echo "usage:" + echo " rfc4543 [icv_len]" + echo "" + echo " icv_len = 128" + echo "" + echo "examples:" + echo " ./tools/ip-xfrm/rfc4543 128" + echo " ./tools/ip-xfrm/rfc4543" + exit 1 +} + +alg="rfc4543(gcm(aes))" +nonce=0a0b0c0d +ip_proto=tcp +len=128 + +if [ $# -eq 0 ]; then + print_usage_and_die +fi + +if [ $# -eq 1 ]; then + len=$1 +fi + +if [ $# -eq 2 ]; then + ip_proto=$2 +fi + +# State +# ipv4 +sudo ip xfrm state add \ + src 10.10.10.1 dst 10.10.10.2 \ + proto esp \ + spi 0x07070707 \ + mode transport \ + replay-window 64 \ + aead $alg 0x0303030303030303030303030303030303030303030303030303030303030303$nonce $len \ + sel src 10.10.10.1 dst 10.10.10.2 + +sudo ip xfrm state add \ + src 10.10.10.2 dst 10.10.10.1 \ + proto esp \ + spi 0x08080808 \ + mode transport \ + replay-window 64 \ + aead $alg 0x0404040404040404040404040404040404040404040404040404040404040404$nonce $len \ + sel src 10.10.10.2 dst 10.10.10.1 + +# Policies +# ipv4 +sudo ip xfrm policy add \ + dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x07070707 mode transport + diff --git a/wolfesp.h b/wolfesp.h index e77bc9f..1634f54 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -34,7 +34,9 @@ typedef enum { #ifndef NO_DES3 ESP_ENC_CBC_DES3, #endif /* !NO_DES3 */ + #if defined(WOLFSSL_AESGCM_STREAM) ESP_ENC_GCM_RFC4106, + #endif /* WOLFSSL_AESGCM_STREAM */ ESP_ENC_GCM_RFC4543, /* placeholder to indicate gmac auth. */ } esp_enc_t; @@ -43,7 +45,9 @@ typedef enum { ESP_AUTH_MD5_RFC2403, /* hmac(md5)-96 */ ESP_AUTH_SHA1_RFC2404, /* hmac(sha1)-96 */ ESP_AUTH_SHA256_RFC4868, /* hmac(sha256)-N, N=96,128 */ + #if defined(WOLFSSL_AESGCM_STREAM) ESP_AUTH_GCM_RFC4106, /* placeholder to indicate gcm auth. */ + #endif /* WOLFSSL_AESGCM_STREAM */ ESP_AUTH_GCM_RFC4543 /* rfc4543 gmac */ } esp_auth_t; @@ -63,7 +67,8 @@ typedef struct replay_t replay_t; (r).bitmap = 0U; (r).hi_seq = ESP_REPLAY_WIN; (r).oseq = 1U; \ /* Minimal ESP Security Association structure. - * Supports only transport mode. */ + * Supports only transport mode. + * todo: support port/proto filtering, and priority sorting. */ struct wolfIP_esp_sa { uint8_t spi[ESP_SPI_LEN]; /* security parameter index */ ip4 src; /* ip src and dst in network byte order */ @@ -84,10 +89,9 @@ typedef struct wolfIP_esp_sa wolfIP_esp_sa; int wolfIP_esp_init(void); void wolfIP_esp_sa_del(int in, uint8_t * spi); void wolfIP_esp_sa_del_all(void); -#if defined(WOLFSSL_AESGCM_STREAM) -int wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len); -#endif /*WOLFSSL_AESGCM_STREAM */ +int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, + esp_enc_t enc, uint8_t * enc_key, + uint8_t enc_key_len); int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, uint8_t enc_key_len, esp_auth_t auth, uint8_t * auth_key, From 065633fbf5ee0aafaa5841febcdf6980bdcf9a9f Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 11 Feb 2026 15:57:25 -0600 Subject: [PATCH 07/10] refactor debug to use LOG, ESP README, and general cleanup. --- Makefile | 30 ++-- src/port/posix/tap_linux.c | 6 +- src/test/esp/esp_common.c | 5 +- src/test/esp/esp_server.c | 2 +- src/test/esp/test_esp.c | 2 +- src/wolfesp.c | 274 +++++++++++++++++++------------------ src/wolfip.c | 8 +- src/wolfip_debug.c | 78 +++++------ tools/ip-xfrm/README.md | 47 ++++++- tools/ip-xfrm/hmac_auth | 66 --------- tools/ip-xfrm/rfc4106 | 1 + tools/ip-xfrm/rfc4543 | 1 + tools/ip-xfrm/watch_stat | 2 - wolfesp.h | 40 +++--- 14 files changed, 263 insertions(+), 299 deletions(-) delete mode 100755 tools/ip-xfrm/hmac_auth delete mode 100755 tools/ip-xfrm/watch_stat diff --git a/Makefile b/Makefile index f8c886e..9565098 100644 --- a/Makefile +++ b/Makefile @@ -2,24 +2,12 @@ CC?=gcc CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE CFLAGS+=-g -ggdb -Wdeclaration-after-statement LDFLAGS+=-pthread - -# -# Debug flags: -# tap debug: -# CFLAGS+=-DDEBUG_TAP -# -# print ethernet headers: -# CFLAGS+=-DDEBUG_ETH -# -# print ip headers: -# CFLAGS+=-DDEBUG_IP -# -# print tcp headers: -# CFLAGS+=-DDEBUG_TCP -# -# print esp header data: -# CFLAGS+=-DWOLFIP_DEBUG_ESP -# +# additional debug flags: +# CFLAGS+=-DDEBUG_TAP +# CFLAGS+=-DDEBUG_ETH +# CFLAGS+=-DDEBUG_IP +# CFLAGS+=-DDEBUG_UDP +# CFLAGS+=-DDEBUG_ESP UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) @@ -179,10 +167,8 @@ asan:CFLAGS+=-fsanitize=address asan:LDFLAGS+=-static-libasan ESP_CFLAGS = \ - -DWOLFIP_ESP \ - -DWOLFSSL_WOLFIP \ - -DDEBUG_IP -DDEBUG_UDP \ - -DWOLFIP_DEBUG_ESP + -DWOLFIP_ESP -DWOLFSSL_WOLFIP \ + -DDEBUG_IP -DDEBUG_UDP -DDEBUG_ESP # Test diff --git a/src/port/posix/tap_linux.c b/src/port/posix/tap_linux.c index cb8b5db..745da04 100644 --- a/src/port/posix/tap_linux.c +++ b/src/port/posix/tap_linux.c @@ -37,6 +37,7 @@ static int tap_fd; +#if defined(DEBUG_TAP) void print_buffer(uint8_t *buf, int len) { int i; @@ -47,6 +48,7 @@ void print_buffer(uint8_t *buf, int len) } printf("\n"); } +#endif /* DEBUG_TAP */ static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { @@ -69,7 +71,9 @@ static int tap_poll(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) static int tap_send(struct wolfIP_ll_dev *ll, void *buf, uint32_t len) { (void)ll; - //print_buffer(buf, len); + #if defined(DEBUG_TAP) + print_buffer(buf, len); + #endif /* DEBUG_TAP */ return write(tap_fd, buf, len); } diff --git a/src/test/esp/esp_common.c b/src/test/esp/esp_common.c index 1b7aa91..ae84da1 100644 --- a/src/test/esp/esp_common.c +++ b/src/test/esp/esp_common.c @@ -1,6 +1,6 @@ /* esp_common.c * - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfIP TCP/IP stack. * @@ -19,6 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +/* ipsec esp security association info shared by esp tests. + * These match the scripts and esp_sa.txt config file found + * in tools/ip-xfrm/ */ static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; diff --git a/src/test/esp/esp_server.c b/src/test/esp/esp_server.c index 9b1cacc..95cffd2 100644 --- a/src/test/esp/esp_server.c +++ b/src/test/esp/esp_server.c @@ -1,6 +1,6 @@ /* esp_server.c * - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfIP TCP/IP stack. * diff --git a/src/test/esp/test_esp.c b/src/test/esp/test_esp.c index 90569a9..43f5541 100644 --- a/src/test/esp/test_esp.c +++ b/src/test/esp/test_esp.c @@ -1,6 +1,6 @@ /* test_esp.c * - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfIP TCP/IP stack. * diff --git a/src/wolfesp.c b/src/wolfesp.c index f1d0392..fd9776d 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -1,3 +1,24 @@ +/* wolfesp.c + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + #if defined(WOLFIP_ESP) && !defined(WOLFESP_SRC) #define WOLFESP_SRC #include "wolfesp.h" @@ -9,26 +30,28 @@ static wolfIP_esp_sa out_sa_list[WOLFIP_ESP_NUM_SA]; static uint16_t in_sa_num = WOLFIP_ESP_NUM_SA; static uint16_t out_sa_num = WOLFIP_ESP_NUM_SA; -#ifdef WOLFIP_DEBUG_ESP +/* for err and important messages */ +#define ESP_LOG(fmt, ...) LOG(fmt, ##__VA_ARGS__) + +/* for verbose debug */ +#ifdef DEBUG_ESP #define ESP_DEBUG(fmt, ...) \ - printf(fmt, ##__VA_ARGS__) + LOG(fmt, ##__VA_ARGS__) #else #define ESP_DEBUG(fmt, ...) \ do { } while (0) -#endif +#endif /* DEBUG_ESP */ int wolfIP_esp_init(void) { int err = 0; - memset(in_sa_list, 0, sizeof(in_sa_list)); - memset(out_sa_list, 0, sizeof(out_sa_list)); + wolfIP_esp_sa_del_all(); if (rng_inited == 0) { err = wc_InitRng_ex(&wc_rng, NULL, INVALID_DEVID); - if (err) { - printf("error: wc_InitRng_ex: %d\n", err); + ESP_LOG("error: wc_InitRng_ex: %d\n", err); } else { rng_inited = 1; @@ -42,7 +65,7 @@ void wolfIP_esp_sa_del_all(void) { memset(in_sa_list, 0, sizeof(in_sa_list)); memset(out_sa_list, 0, sizeof(out_sa_list)); - return ; + return; } static inline wolfIP_esp_sa * @@ -76,13 +99,11 @@ esp_sa_get(int in, const uint8_t * spi) void wolfIP_esp_sa_del_spi(int in, uint8_t * spi) { wolfIP_esp_sa * sa = NULL; - sa = esp_sa_get(in, spi); if (sa != NULL) { memset(sa, 0, sizeof(*sa)); } - - return ; + return; } /* Configure a new Security Association based on either @@ -97,9 +118,8 @@ int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, esp_auth_t auth = 0; new_sa = esp_sa_get(in, NULL); - if (new_sa == NULL) { - printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + ESP_LOG("error: sa %s pool is full\n", in == 1 ? "in" : "out"); return -1; } @@ -113,7 +133,7 @@ int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, auth = ESP_AUTH_GCM_RFC4543; break; default: - printf("error: unsupported enc: %d\n", enc); + ESP_LOG("error: unsupported enc: %d\n", enc); return -1; } @@ -133,15 +153,12 @@ int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, err = wc_RNG_GenerateBlock(&wc_rng, new_sa->pre_iv, ESP_GCM_RFC4106_IV_LEN); if (err) { - printf("error: wc_RNG_GenerateBlock: %d\n", err); - } - - if (err) { + ESP_LOG("error: wc_RNG_GenerateBlock: %d\n", err); memset(new_sa, 0, sizeof(*new_sa)); err = -1; } - ESP_DEBUG("info: esp_sa_new_aead: %s\n", in == 1 ? "in" : "out"); + ESP_DEBUG("info: esp_sa_new_gcm: %s\n", in == 1 ? "in" : "out"); return err; } @@ -155,9 +172,8 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, wolfIP_esp_sa * new_sa = NULL; new_sa = esp_sa_get(in, NULL); - if (new_sa == NULL) { - printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + ESP_LOG("error: sa %s pool is full\n", in == 1 ? "in" : "out"); return -1; } @@ -174,7 +190,7 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, new_sa->auth_key_len = auth_key_len; new_sa->icv_len = icv_len; - ESP_DEBUG("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); + ESP_DEBUG("info: esp_sa_new_cbc_hmac: %s\n", in == 1 ? "in" : "out"); return 0; } @@ -189,9 +205,8 @@ wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, wolfIP_esp_sa * new_sa = NULL; new_sa = esp_sa_get(in, NULL); - if (new_sa == NULL) { - printf("error: sa %s pool is full\n", in == 1 ? "in" : "out"); + ESP_LOG("error: sa %s pool is full\n", in == 1 ? "in" : "out"); return -1; } @@ -208,7 +223,7 @@ wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, new_sa->auth_key_len = auth_key_len; new_sa->icv_len = icv_len; - ESP_DEBUG("info: esp_sa_new_cbc_sha256: %s\n", in == 1 ? "in" : "out"); + ESP_DEBUG("info: esp_sa_new_des3_hmac: %s\n", in == 1 ? "in" : "out"); return 0; } @@ -264,9 +279,9 @@ esp_iv_len_from_enc(esp_enc_t enc) return iv_len; } -#ifdef WOLFIP_DEBUG_ESP +#ifdef DEBUG_ESP #define esp_print_sep \ - printf("+------------------+\n") + LOG("+------------------+\n") #define esp_str_4hex \ "| %02x %02x %02x %02x |" #define esp_str_skip \ @@ -279,17 +294,17 @@ esp_print_field(const char * fld, const uint8_t * val, uint32_t val_len) { esp_print_sep; - printf(esp_str_4hex " (%s, %d bytes)\n", - val[0], val[1], val[2], val[3], fld, val_len); + LOG(esp_str_4hex " (%s, %d bytes)\n", + val[0], val[1], val[2], val[3], fld, val_len); if (val_len > 4) { for (size_t i = 4; i < val_len; i += 4) { if (i > 16 || (i + 4) > val_len) { - printf(esp_str_skip "\n"); + LOG(esp_str_skip "\n"); break; } - printf(esp_str_4hex"\n", - val[0 + i], val[1 + i], val[2 + i], val[3 + i]); + LOG(esp_str_4hex"\n", + val[0 + i], val[1 + i], val[2 + i], val[3 + i]); } } return; @@ -334,7 +349,7 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, /* last 2 bytes of padding */ padding = esp_data + esp_len - esp_sa->icv_len - 4; - printf("esp packet: (%d bytes)\n", esp_len); + LOG("esp packet: (%d bytes)\n", esp_len); /** ESP header * ______________ @@ -359,8 +374,8 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, * | (variable length) | Length | Header | * ------------------------------------- */ esp_print_sep; - printf(esp_pad_fld " (padding last 2 bytes, pad len, nxt hdr)\n", - padding[0], padding[1], pad_len, nxt_hdr); + LOG(esp_pad_fld " (padding last 2 bytes, pad len, nxt hdr)\n", + padding[0], padding[1], pad_len, nxt_hdr); if (icv) { esp_print_field("icv", icv, esp_sa->icv_len); @@ -370,7 +385,7 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, return; } -#endif /* WOLFIP_DEBUG_ESP */ +#endif /* DEBUG_ESP */ /* * esp_data covers from start of ESP header to end of ESP trailer, but does not @@ -401,8 +416,7 @@ esp_calc_icv_hmac(uint8_t * hash, const wolfIP_esp_sa * esp_sa, break; case ESP_AUTH_NONE: default: - printf("error: esp_calc_icv_hmac: invalid auth: %d\n", - esp_sa->auth); + ESP_LOG("error: esp_calc_icv_hmac: invalid auth: %d\n", esp_sa->auth); return -1; } @@ -410,16 +424,14 @@ esp_calc_icv_hmac(uint8_t * hash, const wolfIP_esp_sa * esp_sa, auth_len = esp_len - esp_sa->icv_len; err = wc_HmacInit(&hmac, NULL, INVALID_DEVID); - if (err) { - printf("error: wc_HmacSetKey: %d\n", err); + ESP_LOG("error: wc_HmacSetKey: %d\n", err); goto calc_icv_hmac_end; } - err = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, - esp_sa->auth_key_len); + err = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, esp_sa->auth_key_len); if (err) { - printf("error: wc_HmacSetKey: %d\n", err); + ESP_LOG("error: wc_HmacSetKey: %d\n", err); goto calc_icv_hmac_end; } @@ -427,13 +439,13 @@ esp_calc_icv_hmac(uint8_t * hash, const wolfIP_esp_sa * esp_sa, * inclusive. */ err = wc_HmacUpdate(&hmac, (const byte *)esp_data, auth_len); if (err) { - printf("error: wc_HmacUpdate: %d\n", err); + ESP_LOG("error: wc_HmacUpdate: %d\n", err); goto calc_icv_hmac_end; } err = wc_HmacFinal(&hmac, hash); if (err) { - printf("error: wc_HmacFinal: %d\n", err); + ESP_LOG("error: wc_HmacFinal: %d\n", err); goto calc_icv_hmac_end; } @@ -503,7 +515,7 @@ esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ret = wc_AesInit(&cbc_dec, NULL, INVALID_DEVID); if (ret != 0) { - printf("error: wc_AesInit returned: %d\n", ret); + ESP_LOG("error: wc_AesInit: %d\n", ret); goto aes_dec_out; } inited = 1; @@ -511,14 +523,14 @@ esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ret = wc_AesSetKey(&cbc_dec, esp_sa->enc_key, esp_sa->enc_key_len, iv, AES_DECRYPTION); if (ret != 0) { - printf("error: wc_AesSetKey returned: %d\n", ret); + ESP_LOG("error: wc_AesSetKey: %d\n", ret); goto aes_dec_out; } /* decrypt in place. */ ret = wc_AesCbcDecrypt(&cbc_dec, enc_payload, enc_payload, enc_len); if (ret != 0) { - printf("error: wc_AesCbcDecrypt returned: %d\n", ret); + ESP_LOG("error: wc_AesCbcDecrypt: %d\n", ret); goto aes_dec_out; } @@ -553,13 +565,13 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* Generate random iv block for cbc method. */ ret = wc_RNG_GenerateBlock(&wc_rng, iv, iv_len); if (ret) { - printf("error: wc_RNG_GenerateBlock returned: %d\n", ret); + ESP_LOG("error: wc_RNG_GenerateBlock: %d\n", ret); goto aes_enc_out; } ret = wc_AesInit(&cbc_enc, NULL, INVALID_DEVID); if (ret != 0) { - printf("error: wc_AesInit returned: %d\n", ret); + ESP_LOG("error: wc_AesInit: %d\n", ret); goto aes_enc_out; } @@ -567,13 +579,13 @@ esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ret = wc_AesSetKey(&cbc_enc, esp_sa->enc_key, esp_sa->enc_key_len, iv, AES_ENCRYPTION); if (ret != 0) { - printf("error: wc_AesSetKey returned: %d\n", ret); + ESP_LOG("error: wc_AesSetKey: %d\n", ret); goto aes_enc_out; } ret = wc_AesCbcEncrypt(&cbc_enc, enc_payload, enc_payload, enc_len); if (ret != 0) { - printf("error: wc_AesCbcEncrypt returned: %d\n", ret); + ESP_LOG("error: wc_AesCbcEncrypt: %d\n", ret); goto aes_enc_out; } @@ -603,7 +615,7 @@ esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ESP_DEBUG("info: des3 dec: %d\n", esp_len); if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { - printf("error: des3_rfc2451_dec: key len = %d, expected %d\n", + ESP_LOG("error: des3_rfc2451_dec: key len = %d, expected %d\n", esp_sa->enc_key_len, ESP_DES3_KEY_LEN); goto des3_dec_out; } @@ -614,21 +626,21 @@ esp_des3_rfc2451_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ret = wc_Des3Init(&des3_dec, NULL, INVALID_DEVID); if (ret != 0) { - printf("error: wc_Des3Init returned: %d\n", ret); + ESP_LOG("error: wc_Des3Init: %d\n", ret); goto des3_dec_out; } inited = 1; ret = wc_Des3_SetKey(&des3_dec, esp_sa->enc_key, iv, DES_DECRYPTION); if (ret != 0) { - printf("error: wc_Des3_SetKey returned: %d\n", ret); + ESP_LOG("error: wc_Des3_SetKey: %d\n", ret); goto des3_dec_out; } /* decrypt in place. */ ret = wc_Des3_CbcDecrypt(&des3_dec, enc_payload, enc_payload, enc_len); if (ret != 0) { - printf("error: wc_Des3_CbcDecrypt returned: %d\n", ret); + ESP_LOG("error: wc_Des3_CbcDecrypt: %d\n", ret); goto des3_dec_out; } @@ -657,7 +669,7 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ESP_DEBUG("info: des3 enc: %d\n", esp_len); if (esp_sa->enc_key_len != ESP_DES3_KEY_LEN) { - printf("error: des3_rfc2451_enc: key len = %d, expected %d\n", + ESP_LOG("error: des3_rfc2451_enc: key len = %d, expected %d\n", esp_sa->enc_key_len, ESP_DES3_KEY_LEN); goto des3_enc_out; } @@ -669,21 +681,21 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, ret = wc_Des3Init(&des3_enc, NULL, INVALID_DEVID); if (ret != 0) { - printf("error: wc_Des3Init returned: %d\n", ret); + ESP_LOG("error: wc_Des3Init: %d\n", ret); goto des3_enc_out; } inited = 1; ret = wc_Des3_SetKey(&des3_enc, esp_sa->enc_key, iv, DES_ENCRYPTION); if (ret != 0) { - printf("error: wc_Des3_SetKey returned: %d\n", ret); + ESP_LOG("error: wc_Des3_SetKey: %d\n", ret); goto des3_enc_out; } /* encrypt in place. */ ret = wc_Des3_CbcEncrypt(&des3_enc, enc_payload, enc_payload, enc_len); if (ret != 0) { - printf("error: wc_Des3_CbcEncrypt returned: %d\n", ret); + ESP_LOG("error: wc_Des3_CbcEncrypt: %d\n", ret); goto des3_enc_out; } @@ -721,8 +733,8 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t * iv = NULL; uint16_t enc_len = 0; uint8_t inited = 0; - uint8_t aad[ESP_SPI_LEN + ESP_SEQ_LEN]; - uint16_t aad_len = sizeof(aad); + uint8_t * aad = NULL; + uint16_t aad_len = ESP_SPI_LEN + ESP_SEQ_LEN; const uint8_t * salt = NULL; uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ @@ -732,18 +744,18 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* get enc payload, iv, and icv pointers. */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); enc_payload = esp_enc_payload(esp_data, iv_len); + aad = esp_data; iv = esp_enc_iv(esp_data, iv_len); icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); - /* Get the salt, aad, and construct nonce. */ + /* Get the salt, and construct nonce. */ salt = esp_rfc4106_salt(esp_sa); - memcpy(aad, esp_data, sizeof(aad)); memcpy(nonce, salt, salt_len); memcpy(nonce + salt_len, iv, iv_len); err = wc_AesInit(&gcm_dec, NULL, INVALID_DEVID); if (err != 0) { - printf("error: wc_AesInit: %d\n", err); + ESP_LOG("error: wc_AesInit: %d\n", err); goto rfc4106_dec_out; } inited = 1; @@ -752,20 +764,20 @@ esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesGcmInit(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4, nonce, sizeof(nonce)); if (err != 0) { - printf("error: wc_AesGcmInit: %d\n", err); + ESP_LOG("error: wc_AesGcmInit: %d\n", err); goto rfc4106_dec_out; } err = wc_AesGcmSetKey(&gcm_dec, esp_sa->enc_key, esp_sa->enc_key_len - 4); if (err != 0) { - printf("error: wc_AesGcmSetKey: %d\n", err); + ESP_LOG("error: wc_AesGcmSetKey: %d\n", err); goto rfc4106_dec_out; } err = wc_AesGcmDecrypt(&gcm_dec, enc_payload, enc_payload, enc_len, nonce, sizeof(nonce), icv, icv_len, aad, aad_len); if (err != 0) { - printf("error: wc_AesGcmDecrypt: %d\n", err); + ESP_LOG("error: wc_AesGcmDecrypt: %d\n", err); goto rfc4106_dec_out; } @@ -791,8 +803,8 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t * iv = NULL; uint16_t enc_len = 0; uint8_t inited = 0; - uint8_t aad[ESP_SPI_LEN + ESP_SEQ_LEN]; - uint16_t aad_len = sizeof(aad); + uint8_t * aad = NULL; + uint16_t aad_len = ESP_SPI_LEN + ESP_SEQ_LEN; const uint8_t * salt = NULL; uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ @@ -802,12 +814,12 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* get enc payload, iv, and icv pointers. */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); enc_payload = esp_enc_payload(esp_data, iv_len); + aad = esp_data; iv = esp_enc_iv(esp_data, iv_len); icv = esp_enc_icv(esp_data, esp_len, esp_sa->icv_len); - /* Get the salt, aad. */ + /* Get the salt, and construct nonce. */ salt = esp_rfc4106_salt(esp_sa); - memcpy(aad, esp_data, sizeof(aad)); { /* Deterministic iv construction using pre-iv salt and sequence number. @@ -834,7 +846,7 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesInit(&gcm_enc, NULL, INVALID_DEVID); if (err != 0) { - printf("error: wc_AesInit: %d\n", err); + ESP_LOG("error: wc_AesInit: %d\n", err); goto rfc4106_enc_out; } inited = 1; @@ -843,20 +855,20 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesGcmInit(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4, nonce, sizeof(nonce)); if (err != 0) { - printf("error: wc_AesGcmInit: %d\n", err); + ESP_LOG("error: wc_AesGcmInit: %d\n", err); goto rfc4106_enc_out; } err = wc_AesGcmSetKey(&gcm_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4); if (err != 0) { - printf("error: wc_AesGcmSetKey: %d\n", err); + ESP_LOG("error: wc_AesGcmSetKey: %d\n", err); goto rfc4106_enc_out; } err = wc_AesGcmEncrypt(&gcm_enc, enc_payload, enc_payload, enc_len, nonce, sizeof(nonce), icv, icv_len, aad, aad_len); if (err != 0) { - printf("error: wc_AesGcmDecrypt: %d\n", err); + ESP_LOG("error: wc_AesGcmDecrypt: %d\n", err); goto rfc4106_enc_out; } @@ -908,9 +920,8 @@ esp_aes_rfc4543_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_GmacVerify(esp_sa->enc_key, esp_sa->enc_key_len - 4, nonce, sizeof(nonce), aad, aad_len, icv, icv_len); - if (err != 0) { - printf("error: wc_GmacVerify: %d\n", err); + ESP_LOG("error: wc_GmacVerify: %d\n", err); goto rfc4543_dec_out; } @@ -969,7 +980,7 @@ esp_aes_rfc4543_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, err = wc_AesInit(&gmac_enc.aes, NULL, INVALID_DEVID); if (err != 0) { - printf("error: wc_AesInit: %d\n", err); + ESP_LOG("error: wc_AesInit: %d\n", err); goto rfc4543_enc_out; } inited = 1; @@ -977,14 +988,14 @@ esp_aes_rfc4543_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* subtract 4 byte salt from enc_key_len */ err = wc_GmacSetKey(&gmac_enc, esp_sa->enc_key, esp_sa->enc_key_len - 4); if (err != 0) { - printf("error: wc_AesGcmSetKey: %d\n", err); + ESP_LOG("error: wc_AesGcmSetKey: %d\n", err); goto rfc4543_enc_out; } err = wc_GmacUpdate(&gmac_enc, nonce, sizeof(nonce), aad, aad_len, icv, icv_len); if (err != 0) { - printf("error: wc_AesGmacUpdate: %d\n", err); + ESP_LOG("error: wc_AesGmacUpdate: %d\n", err); goto rfc4543_enc_out; } @@ -1048,20 +1059,20 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) } if (seq < seq_low) { - ESP_DEBUG("error: seq (%d) below window (%d)\n", seq, seq_low); + ESP_LOG("error: seq (%d) below window (%d)\n", seq, seq_low); return -1; } /* Simple 32 bit replay window: * seq_low - - - - - - - seq - - - - - - hi_seq - * <------------ ESP_REPLAY_WIN --------------> + * |<----------- ESP_REPLAY_WIN --------------| * */ if (seq < replay->hi_seq) { /* seq number within window. */ bitn = 1U << (replay->hi_seq - seq); if ((replay->bitmap & bitn) != 0U) { - ESP_DEBUG("error: seq replayed: %u, %d\n", bitn, seq); + ESP_LOG("error: seq replayed: %u, %d\n", bitn, seq); return -1; } else { @@ -1129,7 +1140,7 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) memset(spi, 0, sizeof(spi)); if (*frame_len <= (ETH_HEADER_LEN + IP_HEADER_LEN)) { - ESP_DEBUG("error: esp: malformed frame: %d\n", *frame_len); + ESP_LOG("error: esp: malformed frame: %d\n", *frame_len); return -1; } @@ -1137,7 +1148,7 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) /* If not at least SPI and sequence, something wrong. */ if (esp_len < (ESP_SPI_LEN + ESP_SEQ_LEN)) { - ESP_DEBUG("error: esp: malformed packet: %d\n", esp_len); + ESP_LOG("error: esp: malformed packet: %d\n", esp_len); return -1; } @@ -1161,7 +1172,7 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) * If no valid Security Association exists for this packet, the * receiver MUST discard the packet; this is an auditable event. * */ - printf("error: unknown spi: 0x%02x%02x%02x%02x\n", + ESP_LOG("error: unknown spi: 0x%02x%02x%02x%02x\n", spi[0], spi[1], spi[2], spi[3]); return -1; } @@ -1180,7 +1191,7 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) ESP_PADDING_LEN + ESP_NEXT_HEADER_LEN + esp_sa->icv_len); if (esp_len < min_len) { - printf("error: esp: got %d, expected >= %d frame len", esp_len, + ESP_LOG("error: esp: got %d, expected >= %d frame len", esp_len, min_len); return -1; } @@ -1188,24 +1199,24 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) if (esp_sa->icv_len) { switch (esp_sa->auth) { - case ESP_AUTH_MD5_RFC2403: - case ESP_AUTH_SHA1_RFC2404: - case ESP_AUTH_SHA256_RFC4868: - err = esp_check_icv_hmac(esp_sa, ip->data, esp_len); - break; - case ESP_AUTH_GCM_RFC4106: - case ESP_AUTH_GCM_RFC4543: - /* icv calculated during decrypt */ - err = 0; - break; - case ESP_AUTH_NONE: - default: - err = -1; - break; + case ESP_AUTH_MD5_RFC2403: + case ESP_AUTH_SHA1_RFC2404: + case ESP_AUTH_SHA256_RFC4868: + err = esp_check_icv_hmac(esp_sa, ip->data, esp_len); + break; + case ESP_AUTH_GCM_RFC4106: + case ESP_AUTH_GCM_RFC4543: + /* icv calculated during decrypt */ + err = 0; + break; + case ESP_AUTH_NONE: + default: + err = -1; + break; } if (err) { - printf("error: icv check failed\n"); + ESP_LOG("error: icv check failed\n"); return -1; } } @@ -1236,13 +1247,13 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) case ESP_ENC_NONE: default: - printf("error: decrypt unsupported: %d\n", esp_sa->enc); + ESP_LOG("error: decrypt unsupported: %d\n", esp_sa->enc); err = -1; break; } if (err) { - printf("error: esp_decrypt(%02x) returned: %d\n", esp_sa->enc, + ESP_LOG("error: esp_decrypt(%02x): %d\n", esp_sa->enc, err); return -1; } @@ -1254,9 +1265,9 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) - ESP_PADDING_LEN); nxt_hdr = *(ip->data + esp_len - esp_sa->icv_len - ESP_NEXT_HEADER_LEN); - #ifdef WOLFIP_DEBUG_ESP + #ifdef DEBUG_ESP wolfIP_print_esp(esp_sa, ip->data, esp_len, pad_len, nxt_hdr); - #endif /* WOLFIP_DEBUG_ESP */ + #endif /* DEBUG_ESP */ /* move ip payload forward to hide ESP header (SPI, SEQ, IV). */ memmove(ip->data, ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + iv_len, @@ -1329,13 +1340,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) } if (esp_sa == NULL) { - /* nothing to do */ - #ifdef WOLFIP_DEBUG_ESP - char ip_str[32]; - memset(ip_str, '\0', sizeof(ip_str)); - iptoa(ip->dst, ip_str); - printf("info: ip dst not found: %s\n", ip_str); - #endif /* WOLFIP_DEBUG_ESP */ + /* no ipsec match found */ return 1; } @@ -1443,14 +1448,13 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) case ESP_ENC_NONE: default: - printf("error: encrypt unsupported: %d\n", esp_sa->enc); + ESP_LOG("error: encrypt unsupported: %d\n", esp_sa->enc); err = -1; break; } if (err) { - printf("error: esp_encrypt(%02x) returned: %d\n", esp_sa->enc, - err); + ESP_LOG("error: esp_encrypt(%02x): %d\n", esp_sa->enc, err); return -1; } /* Payload is now encrypted. Now calculate ICV. */ @@ -1461,34 +1465,34 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) int err = 0; switch (esp_sa->auth) { - case ESP_AUTH_MD5_RFC2403: - case ESP_AUTH_SHA1_RFC2404: - case ESP_AUTH_SHA256_RFC4868: - icv = ip->data + icv_offset; - err = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); - break; - case ESP_AUTH_GCM_RFC4106: - case ESP_AUTH_GCM_RFC4543: - /* icv already calculated during encrypt */ - err = 0; - break; - case ESP_AUTH_NONE: - default: - err = -1; - break; + case ESP_AUTH_MD5_RFC2403: + case ESP_AUTH_SHA1_RFC2404: + case ESP_AUTH_SHA256_RFC4868: + icv = ip->data + icv_offset; + err = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); + break; + case ESP_AUTH_GCM_RFC4106: + case ESP_AUTH_GCM_RFC4543: + /* icv already calculated during encrypt */ + err = 0; + break; + case ESP_AUTH_NONE: + default: + err = -1; + break; } if (err) { - printf("error: icv check failed\n"); + ESP_LOG("error: icv check: %d\n", err); return -1; } } *ip_len = payload_len + IP_HEADER_LEN; - #ifdef WOLFIP_DEBUG_ESP + #ifdef DEBUG_ESP wolfIP_print_esp(esp_sa, ip->data, payload_len, pad_len, ip->proto); - #endif /* WOLFIP_DEBUG_ESP */ + #endif /* DEBUG_ESP */ return 0; } diff --git a/src/wolfip.c b/src/wolfip.c index 8ff0e52..dd08f60 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3723,9 +3723,9 @@ size_t wolfIP_instance_size(void) return sizeof(struct wolfIP); } -#if defined(DEBUG_ETH) || defined(DEBUG_IP) || defined(DEBUG_UDP) +#if defined(DEBUG) #include "src/wolfip_debug.c" -#endif /* DEBUG_ETH || DEBUG_IP || DEBUG_UDP */ +#endif /* DEBUG */ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, uint32_t len) @@ -3798,7 +3798,7 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, /* proto is ESP 0x32 (50), try to unwrap. */ int err = esp_transport_unwrap(ip, &len); if (err) { - printf("info: failed to unwrap esp packet, dropping.\n"); + LOG("info: failed to unwrap esp packet, dropping.\n"); return; } } @@ -3820,7 +3820,7 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, } #ifdef DEBUG_IP else { - printf("info: dropping ip packet: 0x%02x\n", ip->proto); + LOG("info: dropping ip packet: 0x%02x\n", ip->proto); } #endif } diff --git a/src/wolfip_debug.c b/src/wolfip_debug.c index 572797e..e04af6f 100644 --- a/src/wolfip_debug.c +++ b/src/wolfip_debug.c @@ -1,6 +1,6 @@ /* wolfip_debug.c * - * Copyright (C) 2024 wolfSSL Inc. + * Copyright (C) 2026 wolfSSL Inc. * * This file is part of wolfIP TCP/IP stack. * @@ -25,17 +25,17 @@ static void wolfIP_print_eth(struct wolfIP_eth_frame * eth, uint32_t len) uint8_t * dst = eth->dst; uint8_t * src = eth->src; uint8_t * type = (uint8_t *) ð->type; - printf("eth hdr:\n"); - printf("+---------------------------------------+\n"); - printf("| %02x:%02x:%02x:%02x:%02x:%02x " - "| %02x:%02x:%02x:%02x:%02x:%02x | (dst, src) \n", - dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], - src[0], src[1], src[2], src[3], src[4], src[5]); - printf("+---------------------------------------+\n"); - printf("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", - type[0], type[1], (unsigned long)len); - printf("+---------------------------------------+\n"); - printf("\n"); + LOG("eth hdr:\n"); + LOG("+---------------------------------------+\n"); + LOG("| %02x:%02x:%02x:%02x:%02x:%02x " + "| %02x:%02x:%02x:%02x:%02x:%02x | (dst, src) \n", + dst[0], dst[1], dst[2], dst[3], dst[4], dst[5], + src[0], src[1], src[2], src[3], src[4], src[5]); + LOG("+---------------------------------------+\n"); + LOG("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", + type[0], type[1], (unsigned long)len); + LOG("+---------------------------------------+\n"); + LOG("\n"); } #endif /* ETHERNET && DEBUG_ETH */ @@ -49,22 +49,22 @@ static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) iptoa(ee32(ip->src), src); iptoa(ee32(ip->dst), dst); - printf("ip hdr:\n"); - printf("+-----------------------------+\n"); - printf("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", - 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); - printf("+-----------------------------+\n"); - printf("| 0x%04x | 0x%04x | (id, flags_fo)\n", - ee16(ip->id), ee16(ip->flags_fo)); - printf("+-----------------------------+\n"); - printf("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", - ip->ttl, ip->proto, ee16(ip->csum)); - printf("+-----------------------------+\n"); - printf("| %15s | (src)\n", src); - printf("+-----------------------------+\n"); - printf("| %15s | (dst)\n", dst); - printf("+-----------------------------+\n"); - printf("\n"); + LOG("ip hdr:\n"); + LOG("+-----------------------------+\n"); + LOG("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", + 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); + LOG("+-----------------------------+\n"); + LOG("| 0x%04x | 0x%04x | (id, flags_fo)\n", + ee16(ip->id), ee16(ip->flags_fo)); + LOG("+-----------------------------+\n"); + LOG("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", + ip->ttl, ip->proto, ee16(ip->csum)); + LOG("+-----------------------------+\n"); + LOG("| %15s | (src)\n", src); + LOG("+-----------------------------+\n"); + LOG("| %15s | (dst)\n", dst); + LOG("+-----------------------------+\n"); + LOG("\n"); } #endif /* DEBUG_IP*/ @@ -73,14 +73,14 @@ static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) { uint16_t len = ee16(udp->len); char payload_str[32]; - printf("udp hdr:\n"); - printf("+-------------------+\n"); - printf("| %5d | %5d | (src_port, dst_port)\n", - ee16(udp->src_port), ee16(udp->dst_port)); - printf("+-------------------+\n"); - printf("| %5u | 0x%04x | (len, chksum)\n", - len, ee16(udp->csum)); - printf("+-------------------+\n"); + LOG("udp hdr:\n"); + LOG("+-------------------+\n"); + LOG("| %5d | %5d | (src_port, dst_port)\n", + ee16(udp->src_port), ee16(udp->dst_port)); + LOG("+-------------------+\n"); + LOG("| %5u | 0x%04x | (len, chksum)\n", + len, ee16(udp->csum)); + LOG("+-------------------+\n"); memset(payload_str, '\0', sizeof(payload_str)); { /* show first 16 printable chars of payload */ @@ -93,8 +93,8 @@ static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) if (!isprint(payload_str[i])) { payload_str[i] = '.'; } } } - printf("| %17s | (payload first 16 bytes)\n", payload_str); - printf("+-------------------+\n"); - printf("\n"); + LOG("| %17s | (payload first 16 bytes)\n", payload_str); + LOG("+-------------------+\n"); + LOG("\n"); } #endif /* DEBUG_UDP */ diff --git a/tools/ip-xfrm/README.md b/tools/ip-xfrm/README.md index b1a5421..2205e0c 100644 --- a/tools/ip-xfrm/README.md +++ b/tools/ip-xfrm/README.md @@ -1,12 +1,16 @@ -# IPsec ESP and ip xfrm support +# IPsec ESP support and testing -Convenience scripts for testing IPsec with wolfIP: +This contains `ip xfrm` convenience scripts for wolfIP IPsec testing, +as well as sample wireshark ESP SA config for decoding ESP packets: -- `rfc4106` sets up rfc4106 aes-gcm xp frm state and policies. -- `delete_all` (deletes all ip xfrm state and policies) -- `hmac_auth` (set auth only state and policies) -- `show` (show ip xfrm state and policies) -- `esp_sa.txt` (ESP SA config to use in Wireshark) +- `cbc_auth`: sets up aes-cbc (rfc3602) + hmac auth (rfcs 2403, 2404, 4868) + on linux host. +- `des3_auth`: same with des3 (rfc2451) + hmac auth (rfcs 2403, 2404, 4868). +- `rfc4106`: same with aes-gcm (rfc4106). +- `rfc4543`: same with aes-gmac (rfc4543). +- `show`: show all ip xfrm state and policies on linux host. +- `delete_all`: deletes all ip xfrm state and policies on linux host. +- `esp_sa.txt`: wireshark `esp_sa` config file. Copy `esp_sa.txt` to you wireshark config, and you can decrypt and inspect ESP payloads, verify ESP ICV and TCP/IP checksums, etc: @@ -30,6 +34,13 @@ Build wolfIP like normal: make ``` +This will result in two ESP tests: +- `./build/test-esp`: self-contained ESP event loop test (client and + server spawned within test). +- `./build/esp-server`: ESP echo server, supporting TCP and UDP. + +### ESP event-loop test with rfc4106 + Test rfc4106 gcm with wolfIP: ``` ./tools/ip-xfrm/rfc4106 128 @@ -38,3 +49,25 @@ sudo LD_LIBRARY_PATH=/usr/local/lib ./build/test-esp cp tools/ip-xfrm/esp_sa.txt ~/.config/wireshark/esp_sa wireshark test.pcap ``` + +### ESP echo-server with UDP and des3-hmac + +In first terminal: +``` +./tools/ip-xfrm/delete_all +./tools/ip-xfrm/des3_auth sha256 128 udp +``` + +In second terminal: +``` +sudo LD_LIBRARY_PATH=/usr/local/lib ./build/esp-server -m 2 -u +``` + +In first terminal again: +``` +nc 10.10.10.2 8 -p 12345 -u +``` + +Type messages in first terminal, and you should see them arrive +as ESP packets in second terminal, be decrypted, then echoed +back again as ESP packets. diff --git a/tools/ip-xfrm/hmac_auth b/tools/ip-xfrm/hmac_auth deleted file mode 100755 index 2cdf6c2..0000000 --- a/tools/ip-xfrm/hmac_auth +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash -# -# hmac-[md5,sha1,sha256]-96,128 example. -# - -print_usage_and_die() { - echo "usage:" - echo " hmac_auth [auth]" - echo "" - echo " auth = md5, sha1, sha256" - echo "" - echo "examples:" - echo " ./tools/ip-xfrm/hmac_auth sha256 128" - echo " ./tools/ip-xfrm/hmac_auth sha256 96" - echo " ./tools/ip-xfrm/hmac_auth sha1" - echo " ./tools/ip-xfrm/hmac_auth md5" - exit 1 -} - -alg=sha1 -ip_proto=tcp -len=96 - -if [ $# -eq 0 ]; then - print_usage_and_die -fi - -if [ $# -eq 1 ]; then - alg=$1 -fi - -if [ $# -eq 2 ]; then - alg=$1 - len=$2 -fi - -# State -# ipv4 -sudo ip xfrm state add \ - src 10.10.10.1 dst 10.10.10.2 \ - proto esp \ - spi 0x2fa9d8c8 \ - mode transport \ - replay-window 64 \ - auth-trunc $alg 0x01010101010101010101010101010101 $len \ - enc cipher_null "" \ - sel src 10.10.10.1 dst 10.10.10.2 - -sudo ip xfrm state add \ - src 10.10.10.2 dst 10.10.10.1 \ - proto esp \ - spi 0xf6e9b80d \ - mode transport \ - replay-window 64 \ - auth-trunc $alg 0x02020202020202020202020202020202 $len \ - enc cipher_null "" \ - sel src 10.10.10.2 dst 10.10.10.1 - -# Policies -# ipv4 -sudo ip xfrm policy add \ - dst 10.10.10.2 proto $ip_proto dir out tmpl proto esp spi 0x2fa9d8c8 mode transport - -#sudo ip xfrm policy add \ -# dst 10.10.10.1 proto $ip_proto dir out tmpl proto esp spi 0xf6e9b80d mode transport - diff --git a/tools/ip-xfrm/rfc4106 b/tools/ip-xfrm/rfc4106 index f84675b..e4afc6b 100755 --- a/tools/ip-xfrm/rfc4106 +++ b/tools/ip-xfrm/rfc4106 @@ -32,6 +32,7 @@ if [ $# -eq 1 ]; then fi if [ $# -eq 2 ]; then + len=$1 ip_proto=$2 fi diff --git a/tools/ip-xfrm/rfc4543 b/tools/ip-xfrm/rfc4543 index 1cfef70..0806757 100755 --- a/tools/ip-xfrm/rfc4543 +++ b/tools/ip-xfrm/rfc4543 @@ -32,6 +32,7 @@ if [ $# -eq 1 ]; then fi if [ $# -eq 2 ]; then + len=$1 ip_proto=$2 fi diff --git a/tools/ip-xfrm/watch_stat b/tools/ip-xfrm/watch_stat deleted file mode 100755 index dd03e0c..0000000 --- a/tools/ip-xfrm/watch_stat +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -watch cat /proc/net/xfrm_stat diff --git a/wolfesp.h b/wolfesp.h index 1634f54..d36ae19 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -29,26 +29,26 @@ + ESP_GCM_RFC4106_IV_LEN) typedef enum { - ESP_ENC_NONE = 0, - ESP_ENC_CBC_AES, - #ifndef NO_DES3 - ESP_ENC_CBC_DES3, - #endif /* !NO_DES3 */ - #if defined(WOLFSSL_AESGCM_STREAM) - ESP_ENC_GCM_RFC4106, - #endif /* WOLFSSL_AESGCM_STREAM */ - ESP_ENC_GCM_RFC4543, /* placeholder to indicate gmac auth. */ + ESP_ENC_NONE = 0, + ESP_ENC_CBC_AES, + #ifndef NO_DES3 + ESP_ENC_CBC_DES3, + #endif /* !NO_DES3 */ + #if defined(WOLFSSL_AESGCM_STREAM) + ESP_ENC_GCM_RFC4106, + #endif /* WOLFSSL_AESGCM_STREAM */ + ESP_ENC_GCM_RFC4543, /* placeholder to indicate gmac auth. */ } esp_enc_t; typedef enum { - ESP_AUTH_NONE = 0, - ESP_AUTH_MD5_RFC2403, /* hmac(md5)-96 */ - ESP_AUTH_SHA1_RFC2404, /* hmac(sha1)-96 */ - ESP_AUTH_SHA256_RFC4868, /* hmac(sha256)-N, N=96,128 */ - #if defined(WOLFSSL_AESGCM_STREAM) - ESP_AUTH_GCM_RFC4106, /* placeholder to indicate gcm auth. */ - #endif /* WOLFSSL_AESGCM_STREAM */ - ESP_AUTH_GCM_RFC4543 /* rfc4543 gmac */ + ESP_AUTH_NONE = 0, + ESP_AUTH_MD5_RFC2403, /* hmac(md5)-96 */ + ESP_AUTH_SHA1_RFC2404, /* hmac(sha1)-96 */ + ESP_AUTH_SHA256_RFC4868, /* hmac(sha256)-N, N=96,128 */ + #if defined(WOLFSSL_AESGCM_STREAM) + ESP_AUTH_GCM_RFC4106, /* placeholder to indicate gcm auth. */ + #endif /* WOLFSSL_AESGCM_STREAM */ + ESP_AUTH_GCM_RFC4543 /* rfc4543 gmac */ } esp_auth_t; /* simple static 32 bit replay window */ @@ -56,9 +56,9 @@ typedef enum { #define ESP_REPLAY_WIN 32U struct replay_t { - uint32_t bitmap; /* inbound sequence bitmap */ - uint32_t hi_seq; /* inbound high sequence number */ - uint32_t oseq; /* outbound sequence number */ + uint32_t bitmap; /* inbound sequence bitmap */ + uint32_t hi_seq; /* inbound high sequence number */ + uint32_t oseq; /* outbound sequence number */ }; typedef struct replay_t replay_t; From dda5e3b7e682107360b4155db04fb062d2242f8b Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 12 Feb 2026 00:45:42 -0600 Subject: [PATCH 08/10] esp: add key length checks. --- src/wolfesp.c | 32 +++++++++++++++++++++++++++----- tools/ip-xfrm/cbc_auth | 6 ++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index fd9776d..69a82e6 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -35,11 +35,9 @@ static uint16_t out_sa_num = WOLFIP_ESP_NUM_SA; /* for verbose debug */ #ifdef DEBUG_ESP - #define ESP_DEBUG(fmt, ...) \ - LOG(fmt, ##__VA_ARGS__) + #define ESP_DEBUG(fmt, ...) LOG(fmt, ##__VA_ARGS__) #else - #define ESP_DEBUG(fmt, ...) \ - do { } while (0) + #define ESP_DEBUG(fmt, ...) do { } while (0) #endif /* DEBUG_ESP */ int wolfIP_esp_init(void) @@ -123,6 +121,13 @@ int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, return -1; } + if (enc_key_len != (AES_128_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN) && + enc_key_len != (AES_192_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN) && + enc_key_len != (AES_256_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN)) { + ESP_LOG("error: bad key len: %d\n", enc_key_len); + return -1; + } + switch (enc) { #if defined(WOLFSSL_AESGCM_STREAM) case ESP_ENC_GCM_RFC4106: @@ -177,6 +182,18 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, return -1; } + if (enc_key_len != (AES_128_KEY_SIZE) && + enc_key_len != (AES_192_KEY_SIZE) && + enc_key_len != (AES_256_KEY_SIZE)) { + ESP_LOG("error: bad key len: %d\n", enc_key_len); + return -1; + } + + if (auth_key_len > ESP_MAX_KEY_LEN) { + ESP_LOG("error: bad auth key len: %d\n", auth_key_len); + return -1; + } + memset(new_sa, 0, sizeof(*new_sa)); esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); @@ -210,6 +227,11 @@ wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, return -1; } + if (auth_key_len > ESP_MAX_KEY_LEN) { + ESP_LOG("error: bad auth key len: %d\n", auth_key_len); + return -1; + } + memset(new_sa, 0, sizeof(*new_sa)); esp_replay_init(new_sa->replay); memcpy(new_sa->spi, spi, ESP_SPI_LEN); @@ -332,7 +354,7 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, const uint8_t * padding = NULL; uint32_t payload_len = esp_len - ESP_SPI_LEN - ESP_SEQ_LEN - pad_len - ESP_PADDING_LEN - - ESP_NEXT_HEADER_LEN ; + - ESP_NEXT_HEADER_LEN - esp_sa->icv_len; iv_len = esp_iv_len_from_enc(esp_sa->enc); diff --git a/tools/ip-xfrm/cbc_auth b/tools/ip-xfrm/cbc_auth index 3684019..8cb63b1 100755 --- a/tools/ip-xfrm/cbc_auth +++ b/tools/ip-xfrm/cbc_auth @@ -34,6 +34,12 @@ if [ $# -eq 2 ]; then len=$2 fi +if [ $# -eq 3 ]; then + alg=$1 + len=$2 + ip_proto=$3 +fi + # State # ipv4 sudo ip xfrm state add \ From e3097069f3984398ca20c63ecf8ea684a5a0fbe3 Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 12 Feb 2026 15:51:38 -0600 Subject: [PATCH 09/10] esp: address copilot feedback part 1. --- src/test/esp/esp_common.c | 4 ++++ src/test/esp/esp_server.c | 7 ++++--- src/test/esp/test_esp.c | 7 ++++--- src/wolfesp.c | 14 ++++++++++++-- src/wolfip_debug.c | 6 +++++- wolfesp.h | 2 ++ wolfip.h | 1 + 7 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/test/esp/esp_common.c b/src/test/esp/esp_common.c index ae84da1..a1a139a 100644 --- a/src/test/esp/esp_common.c +++ b/src/test/esp/esp_common.c @@ -22,12 +22,16 @@ /* ipsec esp security association info shared by esp tests. * These match the scripts and esp_sa.txt config file found * in tools/ip-xfrm/ */ +#if defined(WOLFSSL_AESGCM_STREAM) static uint8_t in_sa_gcm[ESP_SPI_LEN] = {0x01, 0x01, 0x01, 0x01}; static uint8_t out_sa_gcm[ESP_SPI_LEN] = {0x02, 0x02, 0x02, 0x02}; +#endif /* WOLFSSL_AESGCM_STREAM */ static uint8_t in_sa_cbc[ESP_SPI_LEN] = {0x03, 0x03, 0x03, 0x03}; static uint8_t out_sa_cbc[ESP_SPI_LEN] = {0x04, 0x04, 0x04, 0x04}; +#ifndef NO_DES3 static uint8_t in_sa_des3[ESP_SPI_LEN] = {0x05, 0x05, 0x05, 0x05}; static uint8_t out_sa_des3[ESP_SPI_LEN] = {0x06, 0x06, 0x06, 0x06}; +#endif /* !NO_DES3 */ static uint8_t in_sa_gmac[ESP_SPI_LEN] = {0x07, 0x07, 0x07, 0x07}; static uint8_t out_sa_gmac[ESP_SPI_LEN] = {0x08, 0x08, 0x08, 0x08}; /* 32 byte key + 4 byte nonce*/ diff --git a/src/test/esp/esp_server.c b/src/test/esp/esp_server.c index 95cffd2..59e99f3 100644 --- a/src/test/esp/esp_server.c +++ b/src/test/esp/esp_server.c @@ -80,6 +80,7 @@ int main(int argc, char * argv[]) } switch (esp_mode) { + #if defined(WOLFSSL_AESGCM_STREAM) case 0: err = wolfIP_esp_sa_new_gcm(1, in_sa_gcm, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4106, @@ -91,7 +92,7 @@ int main(int argc, char * argv[]) out_enc_key, sizeof(out_enc_key)); if (err) { return err; } break; - + #endif /* WOLFSSL_AESGCM_STREAM */ case 1: err = wolfIP_esp_sa_new_cbc_hmac(1, in_sa_cbc, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), @@ -109,7 +110,7 @@ int main(int argc, char * argv[]) ESP_ICVLEN_HMAC_128); if (err) { return err; } break; - + #ifndef NO_DES3 case 2: err = wolfIP_esp_sa_new_des3_hmac(1, in_sa_des3, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), @@ -125,7 +126,7 @@ int main(int argc, char * argv[]) ESP_ICVLEN_HMAC_128); if (err) { return err; } break; - + #endif /* !NO_DES3 */ case 3: err = wolfIP_esp_sa_new_gcm(1, in_sa_gmac, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4543, diff --git a/src/test/esp/test_esp.c b/src/test/esp/test_esp.c index 43f5541..f72e8cd 100644 --- a/src/test/esp/test_esp.c +++ b/src/test/esp/test_esp.c @@ -554,6 +554,7 @@ int main(int argc, char **argv) if (!disable_ipsec) { switch (mode) { + #if defined(WOLFSSL_AESGCM_STREAM) case 0: err = wolfIP_esp_sa_new_gcm(1, in_sa_gcm, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4106, @@ -565,7 +566,7 @@ int main(int argc, char **argv) out_enc_key, sizeof(out_enc_key)); if (err) { return err; } break; - + #endif /* WOLFSSL_AESGCM_STREAM */ case 1: err = wolfIP_esp_sa_new_cbc_hmac(1, in_sa_cbc, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), @@ -583,7 +584,7 @@ int main(int argc, char **argv) ESP_ICVLEN_HMAC_128); if (err) { return err; } break; - + #ifndef NO_DES3 case 2: err = wolfIP_esp_sa_new_des3_hmac(1, in_sa_des3, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), @@ -599,7 +600,7 @@ int main(int argc, char **argv) ESP_ICVLEN_HMAC_128); if (err) { return err; } break; - + #endif /* !NO_DES3 */ case 3: err = wolfIP_esp_sa_new_gcm(1, in_sa_gmac, atoip4(HOST_STACK_IP), atoip4(WOLFIP_IP), ESP_ENC_GCM_RFC4543, diff --git a/src/wolfesp.c b/src/wolfesp.c index 69a82e6..413cd8f 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -124,7 +124,7 @@ int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, if (enc_key_len != (AES_128_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN) && enc_key_len != (AES_192_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN) && enc_key_len != (AES_256_KEY_SIZE + ESP_GCM_RFC4106_SALT_LEN)) { - ESP_LOG("error: bad key len: %d\n", enc_key_len); + ESP_LOG("error: bad gcm key len: %d\n", enc_key_len); return -1; } @@ -185,7 +185,7 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, if (enc_key_len != (AES_128_KEY_SIZE) && enc_key_len != (AES_192_KEY_SIZE) && enc_key_len != (AES_256_KEY_SIZE)) { - ESP_LOG("error: bad key len: %d\n", enc_key_len); + ESP_LOG("error: bad aes key len: %d\n", enc_key_len); return -1; } @@ -211,6 +211,7 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, return 0; } +#ifndef NO_DES3 /* Configure a new Security Association based on des3 with hmac. * */ int @@ -248,6 +249,7 @@ wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, ESP_DEBUG("info: esp_sa_new_des3_hmac: %s\n", in == 1 ? "in" : "out"); return 0; } +#endif /* !NO_DES3 */ static uint8_t esp_block_len_from_enc(esp_enc_t enc) @@ -263,7 +265,9 @@ esp_block_len_from_enc(esp_enc_t enc) case ESP_ENC_CBC_AES: block_len = AES_BLOCK_SIZE; break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_ENC_GCM_RFC4106: + #endif /* WOLFSSL_AESGCM_STREAM */ case ESP_ENC_GCM_RFC4543: case ESP_ENC_NONE: default: @@ -288,7 +292,9 @@ esp_iv_len_from_enc(esp_enc_t enc) case ESP_ENC_CBC_AES: iv_len = ESP_CBC_RFC3602_IV_LEN; break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_ENC_GCM_RFC4106: + #endif /* WOLFSSL_AESGCM_STREAM */ case ESP_ENC_GCM_RFC4543: iv_len = ESP_GCM_RFC4106_IV_LEN; break; @@ -1226,7 +1232,9 @@ esp_transport_unwrap(struct wolfIP_ip_packet *ip, uint32_t * frame_len) case ESP_AUTH_SHA256_RFC4868: err = esp_check_icv_hmac(esp_sa, ip->data, esp_len); break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_AUTH_GCM_RFC4106: + #endif /* WOLFSSL_AESGCM_STREAM */ case ESP_AUTH_GCM_RFC4543: /* icv calculated during decrypt */ err = 0; @@ -1493,7 +1501,9 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) icv = ip->data + icv_offset; err = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); break; + #if defined(WOLFSSL_AESGCM_STREAM) case ESP_AUTH_GCM_RFC4106: + #endif /* WOLFSSL_AESGCM_STREAM */ case ESP_AUTH_GCM_RFC4543: /* icv already calculated during encrypt */ err = 0; diff --git a/src/wolfip_debug.c b/src/wolfip_debug.c index e04af6f..7217ff1 100644 --- a/src/wolfip_debug.c +++ b/src/wolfip_debug.c @@ -69,6 +69,10 @@ static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) #endif /* DEBUG_IP*/ #ifdef DEBUG_UDP +static inline int wolfip_isprint(int c) +{ + return (c >= ' ' && c <= '~'); +} static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) { uint16_t len = ee16(udp->len); @@ -90,7 +94,7 @@ static void wolfIP_print_udp(struct wolfIP_udp_datagram * udp) memset(payload_str, '\0', sizeof(payload_str)); memcpy(payload_str, udp->data, print_len); for (i = 0; i < print_len; i++) { - if (!isprint(payload_str[i])) { payload_str[i] = '.'; } + if (!wolfip_isprint(payload_str[i])) { payload_str[i] = '.'; } } } LOG("| %17s | (payload first 16 bytes)\n", payload_str); diff --git a/wolfesp.h b/wolfesp.h index d36ae19..8854963 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -96,8 +96,10 @@ int wolfIP_esp_sa_new_cbc_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, uint8_t enc_key_len, esp_auth_t auth, uint8_t * auth_key, uint8_t auth_key_len, uint8_t icv_len); +#ifndef NO_DES3 int wolfIP_esp_sa_new_des3_hmac(int in, uint8_t * spi, ip4 src, ip4 dst, uint8_t * enc_key, esp_auth_t auth, uint8_t * auth_key, uint8_t auth_key_len, uint8_t icv_len); +#endif /* !NO_DES3 */ #endif /* !WOLFESP_H */ diff --git a/wolfip.h b/wolfip.h index 57edca4..daf638d 100644 --- a/wolfip.h +++ b/wolfip.h @@ -317,6 +317,7 @@ static inline void iptoa(ip4 ip, char *buf) #include #include #include + #include #endif /* WOLFIP_ESP */ #endif /* WOLFSSL_WOLFIP */ From 3b62f950265b2e4464a3724e64d11d319eae72b5 Mon Sep 17 00:00:00 2001 From: jordan Date: Fri, 13 Feb 2026 01:44:45 -0600 Subject: [PATCH 10/10] esp: address copilot feedback part 2, and refactor gen_iv. --- src/wolfesp.c | 72 +++++++++++++++-------------------------- src/wolfip.c | 4 +-- tools/ip-xfrm/cbc_auth | 1 + tools/ip-xfrm/des3_auth | 1 + tools/ip-xfrm/rfc4106 | 3 +- tools/ip-xfrm/rfc4543 | 3 +- wolfesp.h | 10 ++++-- 7 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index 413cd8f..ec63fe5 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -94,7 +94,7 @@ esp_sa_get(int in, const uint8_t * spi) return NULL; } -void wolfIP_esp_sa_del_spi(int in, uint8_t * spi) +void wolfIP_esp_sa_del(int in, uint8_t * spi) { wolfIP_esp_sa * sa = NULL; sa = esp_sa_get(in, spi); @@ -376,7 +376,6 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, /* last 2 bytes of padding */ padding = esp_data + esp_len - esp_sa->icv_len - 4; - LOG("esp packet: (%d bytes)\n", esp_len); /** ESP header @@ -393,7 +392,6 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, if (iv) { esp_print_field("iv", iv, iv_len); } - esp_print_field("payload", payload, payload_len); /** ESP trailer @@ -707,7 +705,6 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, iv = esp_enc_iv(esp_data, iv_len); ret = wc_Des3Init(&des3_enc, NULL, INVALID_DEVID); - if (ret != 0) { ESP_LOG("error: wc_Des3Init: %d\n", ret); goto des3_enc_out; @@ -747,6 +744,27 @@ esp_des3_rfc2451_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, + (esp_sa)->enc_key_len \ - ESP_GCM_RFC4106_SALT_LEN +/* Deterministic iv construction using pre-iv salt and sequence number. + * NIST SP 800-38D, section 8.2.1 Deterministic Construction, using + * an integer counter. The sequence number is used as a counter, and + * xor'ed with pre-iv salt. Based on linux kernel crypto/seqiv.c. + * */ +static inline void +esp_rfc4106_gen_iv(uint8_t * iv, const wolfIP_esp_sa * esp_sa) +{ + uint32_t seq_num = 0; + uint8_t * seq_num_u8 = (uint8_t *) &seq_num; + + seq_num = ee32(esp_sa->replay.oseq); + /* copy in the pre_iv. */ + memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); + /* xor pre-iv salt with current sequence number. */ + for (size_t i = 0; i < sizeof(uint32_t); ++i) { + iv[i + sizeof(uint32_t)] ^= seq_num_u8[i]; + } + return; +} + #if defined(WOLFSSL_AESGCM_STREAM) static int esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, @@ -848,26 +866,7 @@ esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* Get the salt, and construct nonce. */ salt = esp_rfc4106_salt(esp_sa); - - { - /* Deterministic iv construction using pre-iv salt and sequence number. - * NIST SP 800-38D, section 8.2.1 Deterministic Construction, using - * an integer counter. The sequence number is used as a counter, and - * xor'ed with pre-iv salt. Based on linux kernel crypto/seqiv.c. - * */ - uint32_t seq_num = 0; - uint8_t * seq_num_u8 = (uint8_t *) &seq_num; - - seq_num = ee32(esp_sa->replay.oseq); - - /* copy in the pre_iv. */ - memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); - - /* xor pre-iv salt with current sequence number. */ - for (size_t i = 0; i < sizeof(uint32_t); ++i) { - iv[i + sizeof(uint32_t)] ^= seq_num_u8[i]; - } - } + esp_rfc4106_gen_iv(iv, esp_sa); memcpy(nonce, salt, salt_len); memcpy(nonce + salt_len, iv, iv_len); @@ -982,26 +981,7 @@ esp_aes_rfc4543_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* Get the salt. */ salt = esp_rfc4106_salt(esp_sa); - - { - /* Deterministic iv construction using pre-iv salt and sequence number. - * NIST SP 800-38D, section 8.2.1 Deterministic Construction, using - * an integer counter. The sequence number is used as a counter, and - * xor'ed with pre-iv salt. Based on linux kernel crypto/seqiv.c. - * */ - uint32_t seq_num = 0; - uint8_t * seq_num_u8 = (uint8_t *) &seq_num; - - seq_num = ee32(esp_sa->replay.oseq); - - /* copy in the pre_iv. */ - memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); - - /* xor pre-iv salt with current sequence number. */ - for (size_t i = 0; i < sizeof(uint32_t); ++i) { - iv[i + sizeof(uint32_t)] ^= seq_num_u8[i]; - } - } + esp_rfc4106_gen_iv(iv, esp_sa); memcpy(nonce, salt, salt_len); memcpy(nonce + salt_len, iv, iv_len); @@ -1080,7 +1060,7 @@ esp_check_replay(struct replay_t * replay, uint32_t seq) #else uint32_t diff = 0; uint32_t bitn = 0; - uint32_t seq_low = replay->hi_seq - ESP_REPLAY_WIN; + uint32_t seq_low = replay->hi_seq - (ESP_REPLAY_WIN - 1); if (seq == 0) { return -1; @@ -1559,7 +1539,7 @@ esp_send(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, int esp_rc = 0; esp = (struct wolfIP_ip_packet *) frame; - memcpy(esp, ip, sizeof(struct wolfIP_ip_packet) + len); + memcpy(esp, ip, ETH_HEADER_LEN + len); esp_rc = esp_transport_wrap(esp, &ip_final_len); diff --git a/src/wolfip.c b/src/wolfip.c index dd08f60..bb25ef3 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3197,8 +3197,8 @@ static void dhcp_cancel_timer(struct wolfIP *s) } #define DHCP_OPT_data_to_u32(opt) \ - (opt)->data[0] | ((opt)->data[1] << 8) | \ - ((opt)->data[2] << 16) | ((opt)->data[3] << 24); + ((opt)->data[0] | ((opt)->data[1] << 8) | \ + ((opt)->data[2] << 16) | ((opt)->data[3] << 24)) #define DHCP_OPT_u32_to_data(opt, v) \ do { \ diff --git a/tools/ip-xfrm/cbc_auth b/tools/ip-xfrm/cbc_auth index 8cb63b1..7f8ce7d 100755 --- a/tools/ip-xfrm/cbc_auth +++ b/tools/ip-xfrm/cbc_auth @@ -10,6 +10,7 @@ print_usage_and_die() { echo " auth = md5, sha1, sha256" echo "" echo "examples:" + echo " ./tools/ip-xfrm/cbc_auth sha256 128 udp" echo " ./tools/ip-xfrm/cbc_auth sha256 128" echo " ./tools/ip-xfrm/cbc_auth sha256 96" echo " ./tools/ip-xfrm/cbc_auth sha1" diff --git a/tools/ip-xfrm/des3_auth b/tools/ip-xfrm/des3_auth index 04bad7d..9c3524b 100755 --- a/tools/ip-xfrm/des3_auth +++ b/tools/ip-xfrm/des3_auth @@ -10,6 +10,7 @@ print_usage_and_die() { echo " auth = md5, sha1, sha256" echo "" echo "examples:" + echo " ./tools/ip-xfrm/des3_auth sha256 128 udp" echo " ./tools/ip-xfrm/des3_auth sha256 128" echo " ./tools/ip-xfrm/des3_auth sha256 96" echo " ./tools/ip-xfrm/des3_auth sha1" diff --git a/tools/ip-xfrm/rfc4106 b/tools/ip-xfrm/rfc4106 index e4afc6b..699d7f3 100755 --- a/tools/ip-xfrm/rfc4106 +++ b/tools/ip-xfrm/rfc4106 @@ -14,7 +14,8 @@ print_usage_and_die() { echo "" echo "examples:" echo " ./tools/ip-xfrm/rfc4106 128" - echo " ./tools/ip-xfrm/rfc4106" + echo " ./tools/ip-xfrm/rfc4106 128 udp" + echo " ./tools/ip-xfrm/rfc4106 128 tcp" exit 1 } diff --git a/tools/ip-xfrm/rfc4543 b/tools/ip-xfrm/rfc4543 index 0806757..02d8641 100755 --- a/tools/ip-xfrm/rfc4543 +++ b/tools/ip-xfrm/rfc4543 @@ -14,7 +14,8 @@ print_usage_and_die() { echo "" echo "examples:" echo " ./tools/ip-xfrm/rfc4543 128" - echo " ./tools/ip-xfrm/rfc4543" + echo " ./tools/ip-xfrm/rfc4543 128 udp" + echo " ./tools/ip-xfrm/rfc4543 128 tcp" exit 1 } diff --git a/wolfesp.h b/wolfesp.h index 8854963..fbb4b07 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -63,8 +63,12 @@ struct replay_t { typedef struct replay_t replay_t; -#define esp_replay_init(r) \ - (r).bitmap = 0U; (r).hi_seq = ESP_REPLAY_WIN; (r).oseq = 1U; \ +#define esp_replay_init(r) \ + do { \ + (r).bitmap = 0U; \ + (r).hi_seq = ESP_REPLAY_WIN; \ + (r).oseq = 1U; \ + } while (0) /* Minimal ESP Security Association structure. * Supports only transport mode. @@ -87,8 +91,8 @@ struct wolfIP_esp_sa { typedef struct wolfIP_esp_sa wolfIP_esp_sa; int wolfIP_esp_init(void); -void wolfIP_esp_sa_del(int in, uint8_t * spi); void wolfIP_esp_sa_del_all(void); +void wolfIP_esp_sa_del(int in, uint8_t * spi); int wolfIP_esp_sa_new_gcm(int in, uint8_t * spi, ip4 src, ip4 dst, esp_enc_t enc, uint8_t * enc_key, uint8_t enc_key_len);