From 5b92271a80773ca076d051ea2420c0fc03eee6f8 Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 5 Feb 2026 15:26:21 -0600 Subject: [PATCH 1/4] IPsec transport support, and misc cleanup. --- .github/workflows/linux.yml | 7 + .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 | 640 +++++++++ src/test/test_eventloop.c | 7 +- src/test/test_httpd.c | 2 - src/test/test_native_wolfssl.c | 5 +- src/wolfesp.c | 1305 ++++++++++++++++++ src/wolfip.c | 263 +++- 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 | 91 ++ wolfip.h | 78 +- 25 files changed, 2643 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..67e6bd7 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -31,6 +31,13 @@ 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 + - 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); +#if 0 +#include "esp_sa_list.c" +#endif + +#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: /* '?' */ + fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", + argv[0]); + exit(EXIT_FAILURE); + } + } + + (void)argc; + (void)argv; + + 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..2f466eb --- /dev/null +++ b/src/wolfesp.c @@ -0,0 +1,1305 @@ +#if defined(WOLFIP_ESP) && !defined(WOLFESP_SRC) +#define WOLFESP_SRC + +#include "wolfesp.h" +static uint8_t esp_iv_len_from_enc(esp_enc_t enc); + +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; +} + +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; +} + +#if 0 +void +wolfIP_esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, int in) +{ + #ifdef WOLFIP_DEBUG_ESP + printf("info: esp_load_sa_list: %p, %d, %d\n", sa_list, num, in); + #endif /* WOLFIP_DEBUG_ESP */ + + if (in == 1) { + in_sa_list = sa_list; + in_sa_num = num; + } + else { + out_sa_list = sa_list; + out_sa_num = num; + } + + return; +} +#endif + +#ifdef WOLFIP_DEBUG_ESP +static void +esp_dump_data(const char * what, const uint8_t * data, size_t data_len) +{ + printf("info: %s: 0x", what); + + for (size_t i = 0; i < data_len; ++i) { + printf("%02x", data[i]); + } + + printf("\n"); + return; +} + +#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 struct 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 */ + +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; +} + +/* + * 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 struct 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 struct 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 struct 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, AES_BLOCK_SIZE, + 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 struct 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 struct 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 struct 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); + if (rc) { + #ifdef WOLFIP_DEBUG_ESP + esp_dump_data("icv not matched", hash, esp_sa->icv_len); + #endif /* WOLFIP_DEBUG_ESP */ + } + + 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; + struct 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) { + #ifdef WOLFIP_DEBUG_ESP + printf("info: sa: 0x%02x%02x%02x%02x\n", + in_sa_list[i].spi[0], in_sa_list[i].spi[1], + in_sa_list[i].spi[2], in_sa_list[i].spi[3]); + #endif /* WOLFIP_DEBUG_ESP */ + + 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; + } + } + + if (iv_len != 0) { + /* Decrypt the payload in place. */ + int err = -1; + + 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. */ + } + + /* icv check good, now finish unwrapping esp packet. */ + 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. + * */ +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 0; + } + + 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) { + 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("error: 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 721a750..2b89139 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -588,7 +588,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; @@ -623,7 +626,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; @@ -639,7 +644,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; @@ -654,7 +660,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; @@ -668,7 +676,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; @@ -682,7 +692,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; @@ -695,7 +707,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; @@ -821,7 +835,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); @@ -856,8 +870,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 @@ -877,8 +892,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; @@ -1112,8 +1127,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); @@ -1121,7 +1137,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}; @@ -1155,7 +1172,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; @@ -1164,7 +1182,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) @@ -1282,7 +1301,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; @@ -1341,7 +1361,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); @@ -1625,7 +1646,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); @@ -1644,8 +1666,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) @@ -1676,7 +1703,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); @@ -1688,11 +1717,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) @@ -1711,7 +1743,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; @@ -1749,7 +1782,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 @@ -1915,7 +1949,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; @@ -2085,7 +2120,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); } @@ -2188,7 +2224,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; @@ -2649,7 +2686,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) @@ -2677,7 +2715,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) @@ -2758,7 +2797,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; @@ -2798,7 +2838,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; @@ -2986,7 +3027,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; @@ -3009,7 +3051,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; @@ -3084,6 +3127,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); @@ -3096,11 +3151,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); @@ -3135,7 +3190,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); @@ -3169,7 +3224,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)) @@ -3227,18 +3283,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++; @@ -3341,7 +3391,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; } @@ -3421,7 +3472,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; @@ -3480,7 +3532,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)); } @@ -3601,14 +3654,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 @@ -3660,7 +3742,26 @@ 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 = 0; + 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); @@ -3668,11 +3769,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 @@ -3828,7 +3955,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; @@ -3941,7 +4069,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; @@ -4089,6 +4218,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; @@ -4151,7 +4283,11 @@ 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 + esp_tcp_output(ll, (struct wolfIP_ip_packet *)tcp, size); + #else ll->send(ll, tcp, desc->len); + #endif /* WOLFIP_ESP */ } } desc->flags |= PKT_FLAG_SENT; @@ -4179,6 +4315,11 @@ 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); @@ -4274,7 +4415,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) @@ -4284,7 +4426,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..97189a2 --- /dev/null +++ b/wolfesp.h @@ -0,0 +1,91 @@ +#ifndef WOLFESP_H +#define WOLFESP_H + +/* size of static pool */ +#define WOLFIP_ESP_NUM_SA 3 + +#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); +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); +#if 0 +void wolfIP_esp_load_sa_list(wolfIP_esp_sa * sa_list, uint16_t num, + int in); +#endif + +#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 a6cf1f85e91f6849febef0aebccc2072e581d2ee Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 5 Feb 2026 20:25:15 -0600 Subject: [PATCH 2/4] esp: fix silly cbc bug, and add cbc hmac 256 test. --- .github/workflows/linux.yml | 4 ++++ src/test/test_esp.c | 5 +---- src/wolfesp.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 67e6bd7..36ba19c 100644 --- a/.github/workflows/linux.yml +++ b/.github/workflows/linux.yml @@ -37,6 +37,10 @@ jobs: 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: | diff --git a/src/test/test_esp.c b/src/test/test_esp.c index 1b41aee..495ac5a 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -38,9 +38,6 @@ #include "wolfesp.h" static void __attribute__((noreturn)) print_usage_and_die(void); -#if 0 -#include "esp_sa_list.c" -#endif #define TEST_SIZE (12 * 1024) @@ -606,7 +603,7 @@ int main(int argc, char **argv) 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_enc_key, sizeof(out_enc_key) - 4, out_auth_key, sizeof(out_auth_key), ESP_ICVLEN_HMAC_128); break; diff --git a/src/wolfesp.c b/src/wolfesp.c index 2f466eb..da33fb1 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -541,7 +541,7 @@ esp_aes_rfc3602_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } inited = 1; - ret = wc_AesSetKey(&cbc_enc, esp_sa->enc_key, AES_BLOCK_SIZE, + ret = wc_AesSetKey(&cbc_enc, esp_sa->enc_key, esp_sa->enc_key_len, iv, AES_ENCRYPTION); if (ret != 0) { From 6b0a36413805233376a3891d64ff985447dd51d8 Mon Sep 17 00:00:00 2001 From: jordan Date: Thu, 5 Feb 2026 21:39:29 -0600 Subject: [PATCH 3/4] cleanup. --- src/wolfesp.c | 65 +++++++++++++++++++++------------------------------ src/wolfip.c | 10 +++++++- wolfesp.h | 1 + 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index da33fb1..b51a52c 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -12,8 +12,7 @@ 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 wolfIP_esp_init(void) { int err = 0; @@ -34,9 +33,15 @@ wolfIP_esp_init(void) return err; } -int -wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, - uint8_t * enc_key, uint8_t enc_key_len) +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; @@ -76,7 +81,8 @@ wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, 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); + 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); } @@ -94,11 +100,10 @@ wolfIP_esp_sa_new_aead(int in, uint8_t * spi, ip4 src, ip4 dst, 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) +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; @@ -147,27 +152,6 @@ wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, return err; } -#if 0 -void -wolfIP_esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, int in) -{ - #ifdef WOLFIP_DEBUG_ESP - printf("info: esp_load_sa_list: %p, %d, %d\n", sa_list, num, in); - #endif /* WOLFIP_DEBUG_ESP */ - - if (in == 1) { - in_sa_list = sa_list; - in_sa_num = num; - } - else { - out_sa_list = sa_list; - out_sa_num = num; - } - - return; -} -#endif - #ifdef WOLFIP_DEBUG_ESP static void esp_dump_data(const char * what, const uint8_t * data, size_t data_len) @@ -1013,7 +997,8 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, } if (err) { - printf("error: esp_decrypt(%02x) returned: %d\n", esp_sa->enc, err); + printf("error: esp_decrypt(%02x) returned: %d\n", esp_sa->enc, + err); return -1; } @@ -1074,6 +1059,7 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, * * Returns 0 on success. * Returns -1 on error. + * Returns 1 if no ipsec policy not found (send plaintext) * */ static int esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) @@ -1096,7 +1082,8 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) 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]); + esp_sa->spi[0], esp_sa->spi[1], esp_sa->spi[2], + esp_sa->spi[3]); #endif /* WOLFIP_DEBUG_ESP */ break; } @@ -1110,7 +1097,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) iptoa(ip->dst, ip_str); printf("info: ip dst not found: %s\n", ip_str); #endif /* WOLFIP_DEBUG_ESP */ - return 0; + return 1; } iv_len = esp_iv_len_from_enc(esp_sa->enc); @@ -1211,7 +1198,8 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) } if (err) { - printf("error: esp_encrypt(%02x) returned: %d\n", esp_sa->enc, err); + printf("error: esp_encrypt(%02x) returned: %d\n", esp_sa->enc, + err); return -1; } @@ -1263,7 +1251,8 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) * 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, +esp_tcp_output(struct wolfIP_ll_dev * ll_dev, + const struct wolfIP_ip_packet *ip, uint16_t len) { /** @@ -1287,7 +1276,7 @@ esp_tcp_output(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, if (esp_rc) { #ifdef WOLFIP_DEBUG_ESP - printf("error: esp_wrap returned: %d\n", esp_rc); + printf("info: esp_wrap returned: %d\n", esp_rc); #endif /* WOLFIP_DEBUG_ESP */ return esp_rc; } diff --git a/src/wolfip.c b/src/wolfip.c index 2b89139..205ad84 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3816,6 +3816,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)) { @@ -4284,7 +4287,12 @@ 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 - esp_tcp_output(ll, (struct wolfIP_ip_packet *)tcp, size); + 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 */ diff --git a/wolfesp.h b/wolfesp.h index 97189a2..1b96ae3 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -77,6 +77,7 @@ struct wolfIP_esp_sa { 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, From 5eb24a1c8608294612f52bec88d8b86449e73fa9 Mon Sep 17 00:00:00 2001 From: jordan Date: Fri, 6 Feb 2026 02:35:05 -0600 Subject: [PATCH 4/4] cleanup. --- src/test/test_esp.c | 18 ++--- src/wolfesp.c | 167 ++++++++++++++++++-------------------------- src/wolfip.c | 6 +- wolfesp.h | 11 +-- 4 files changed, 76 insertions(+), 126 deletions(-) diff --git a/src/test/test_esp.c b/src/test/test_esp.c index 495ac5a..eee27a0 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -40,7 +40,6 @@ static void __attribute__((noreturn)) print_usage_and_die(void); #define TEST_SIZE (12 * 1024) - #define BUFFER_SIZE TEST_SIZE static int disable_ipsec = 0; @@ -54,10 +53,9 @@ 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 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}; @@ -75,7 +73,6 @@ static uint8_t out_enc_key[36] = 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}; @@ -536,16 +533,11 @@ int main(int argc, char **argv) case '?': print_usage_and_die(); break; - default: /* '?' */ - fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n", - argv[0]); - exit(EXIT_FAILURE); + default: + break; } } - (void)argc; - (void)argv; - if (!disable_ipsec) { err = wolfIP_esp_init(); if (err) { diff --git a/src/wolfesp.c b/src/wolfesp.c index b51a52c..1326bef 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -1,9 +1,6 @@ #if defined(WOLFIP_ESP) && !defined(WOLFESP_SRC) #define WOLFESP_SRC - #include "wolfesp.h" -static uint8_t esp_iv_len_from_enc(esp_enc_t enc); - static WC_RNG wc_rng; static volatile int rng_inited = 0; /* security association static pool*/ @@ -152,20 +149,58 @@ int wolfIP_esp_sa_new_cbc_sha256(int in, uint8_t * spi, ip4 src, ip4 dst, return err; } -#ifdef WOLFIP_DEBUG_ESP -static void -esp_dump_data(const char * what, const uint8_t * data, size_t data_len) +static uint8_t +esp_block_len_from_enc(esp_enc_t enc) { - printf("info: %s: 0x", what); + uint8_t block_len = 0; - for (size_t i = 0; i < data_len; ++i) { - printf("%02x", data[i]); + 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; } - printf("\n"); - return; + 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 \ @@ -205,7 +240,7 @@ esp_print_field(const char * fld, const uint8_t * val, * |<---- encrypted ----->| * |<--- integrity checked ---->| * */ -static void wolfIP_print_esp(const struct wolfIP_esp_sa * esp_sa, +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) { @@ -273,63 +308,12 @@ static void wolfIP_print_esp(const struct wolfIP_esp_sa * esp_sa, } #endif /* WOLFIP_DEBUG_ESP */ -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; -} - /* * 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 struct wolfIP_esp_sa * esp_sa, +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: @@ -435,7 +419,7 @@ esp_const_memcmp(const uint8_t * vec_a, const uint8_t * vec_b, uint32_t len) (data) + ESP_SPI_LEN + ESP_SEQ_LEN + (iv_len) static int -esp_aes_rfc3602_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, +esp_aes_rfc3602_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint32_t esp_len) { Aes cbc_dec; @@ -489,7 +473,7 @@ esp_aes_rfc3602_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } static int -esp_aes_rfc3602_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, +esp_aes_rfc3602_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint32_t esp_len) { Aes cbc_enc; @@ -560,7 +544,7 @@ esp_aes_rfc3602_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, - ESP_GCM_RFC4106_SALT_LEN static int -esp_aes_rfc4106_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, +esp_aes_rfc4106_dec(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint32_t esp_len) { Aes gcm_dec; @@ -637,7 +621,7 @@ esp_aes_rfc4106_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } static int -esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, +esp_aes_rfc4106_enc(const wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint32_t esp_len) { Aes gcm_enc; @@ -739,7 +723,7 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, * include the ESP ICV after trailer. * */ static int -esp_check_icv_hmac(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, +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: @@ -760,12 +744,6 @@ esp_check_icv_hmac(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* compare the first N bits depending on truncation type. */ rc = esp_const_memcmp(icv, hash, esp_sa->icv_len); - if (rc) { - #ifdef WOLFIP_DEBUG_ESP - esp_dump_data("icv not matched", hash, esp_sa->icv_len); - #endif /* WOLFIP_DEBUG_ESP */ - } - return rc; } @@ -869,14 +847,14 @@ 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; - struct 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; + 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)); @@ -904,12 +882,6 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, seq = ee32(seq); for (size_t i = 0; i < in_sa_num; ++i) { - #ifdef WOLFIP_DEBUG_ESP - printf("info: sa: 0x%02x%02x%02x%02x\n", - in_sa_list[i].spi[0], in_sa_list[i].spi[1], - in_sa_list[i].spi[2], in_sa_list[i].spi[3]); - #endif /* WOLFIP_DEBUG_ESP */ - 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", @@ -921,8 +893,7 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, } if (esp_sa == NULL) { - /** - * RFC4303: + /* RFC4303: * If no valid Security Association exists for this packet, the * receiver MUST discard the packet; this is an auditable event. * */ @@ -976,10 +947,9 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, } } + /* icv check good, now finish unwrapping esp packet. */ if (iv_len != 0) { /* Decrypt the payload in place. */ - int err = -1; - switch(esp_sa->enc) { case ESP_ENC_CBC_AES: err = esp_aes_rfc3602_dec(esp_sa, ip->data, esp_len); @@ -1001,12 +971,10 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, err); return -1; } - - /* Payload is now decrypted. We can now parse - * the ESP trailer for next header and padding. */ } - /* icv check good, now finish unwrapping esp packet. */ + /* 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); @@ -1059,7 +1027,7 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, * * Returns 0 on success. * Returns -1 on error. - * Returns 1 if no ipsec policy not found (send plaintext) + * Returns 1 if no ipsec policy found (send plaintext) * */ static int esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) @@ -1101,7 +1069,6 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) } 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); @@ -1156,6 +1123,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) 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); @@ -1202,7 +1170,6 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) err); return -1; } - /* Payload is now encrypted. Now calculate ICV. */ } diff --git a/src/wolfip.c b/src/wolfip.c index 205ad84..ee8dd78 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3753,8 +3753,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 = 0; - err = esp_transport_unwrap(s, ip, &len); + int err = esp_transport_unwrap(s, ip, &len); if (err) { printf("info: failed to unwrap esp packet, dropping.\n"); return; @@ -4324,8 +4323,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) } } - - /** + /* * UDP * */ for (i = 0; i < MAX_UDPSOCKETS; i++) { diff --git a/wolfesp.h b/wolfesp.h index 1b96ae3..324b89d 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -3,7 +3,7 @@ /* 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 @@ -56,8 +56,7 @@ 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. */ struct wolfIP_esp_sa { uint8_t spi[ESP_SPI_LEN]; /* security parameter index */ ip4 src; /* ip src and dst in network byte order */ @@ -73,7 +72,6 @@ struct wolfIP_esp_sa { 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); @@ -84,9 +82,4 @@ 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); -#if 0 -void wolfIP_esp_load_sa_list(wolfIP_esp_sa * sa_list, uint16_t num, - int in); -#endif - #endif /* !WOLFESP_H */