From 3d47370eb811846683f341d33d3bb649f655fb8b Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 28 Jan 2026 16:43:59 -0600 Subject: [PATCH 01/16] IPsec transport support, and misc cleanup. --- .gitignore | 1 + Makefile | 18 + README.md | 6 +- core.md | 79 +- scripts/ip-xfrm/README.md | 62 ++ scripts/ip-xfrm/cbc_auth | 63 ++ scripts/ip-xfrm/delete_all | 3 + scripts/ip-xfrm/esp_sa.txt | 5 + scripts/ip-xfrm/gcm | 48 + scripts/ip-xfrm/hmac_auth | 66 ++ scripts/ip-xfrm/monitor | 2 + scripts/ip-xfrm/show | 7 + scripts/ip-xfrm/watch_stat | 2 + src/port/raspberry-pico-usb-server/README.md | 2 +- src/test/esp_sa_list.c | 70 ++ src/test/tcp_echo.c | 1 - src/test/test_dhcp_dns.c | 6 +- src/test/test_eventloop.c | 17 +- src/test/test_httpd.c | 2 - src/wolfesp.c | 870 +++++++++++++++++++ src/wolfip.c | 90 +- wolfesp.h | 66 ++ wolfip.h | 30 +- 23 files changed, 1449 insertions(+), 67 deletions(-) create mode 100644 scripts/ip-xfrm/README.md create mode 100755 scripts/ip-xfrm/cbc_auth create mode 100755 scripts/ip-xfrm/delete_all create mode 100644 scripts/ip-xfrm/esp_sa.txt create mode 100755 scripts/ip-xfrm/gcm create mode 100755 scripts/ip-xfrm/hmac_auth create mode 100755 scripts/ip-xfrm/monitor create mode 100755 scripts/ip-xfrm/show create mode 100755 scripts/ip-xfrm/watch_stat create mode 100644 src/test/esp_sa_list.c create mode 100644 src/wolfesp.c create mode 100644 wolfesp.h 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 9ba83b1..7bebfa9 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,26 @@ CC?=gcc CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE CFLAGS+=-g -ggdb -Wdeclaration-after-statement +CFLAGS+=-Wno-error=unterminated-string-initialization LDFLAGS+=-pthread +# Debug flags: +# 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 +#FLAGS+=-DWOLFIP_DEBUG_ESP +#CFLAGS+=-DWOLFIP_DEBUG_ESP_VERBOSE + +# ESP support +#CFLAGS+=-DWOLFIP_ESP +#CFLAGS+=-DWOLFSSL_WOLFIP +#LDFLAGS+=-lwolfssl + UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) UNAME_LC:=$(shell echo $(UNAME_S) | tr 'A-Z' 'a-z') diff --git a/README.md b/README.md index 349ecd2..c48f60c 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. @@ -19,7 +19,7 @@ A single network interface can be associated with the device. - DHCP (RFC 2131): client only - DNS (RFC 1035): client only - UDP (RFC 768): unicast only -- TCP (RFC 793) +- TCP (RFC 793) - TCP options supported: Timestamps, Maximum Segment Size - BSD-like, non blocking socket API, with custom callbacks - No dynamic memory allocation 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) | +| +---------------+ | | +| +-----------------------+ +| | +| | +| | +| +-----------------------+ +| +-------------+ | | + 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; + 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 ; + + if (esp_sa->iv_len) { + iv = payload; + payload += esp_sa->iv_len; + payload_len -= esp_sa->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, esp_sa->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 */ + +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 = WC_AES_BLOCK_SIZE; + break; + case ESP_ENC_CBC_DES3: + block_len = DES_BLOCK_SIZE; + break; + case ESP_ENC_GCM_RFC4106: + case ESP_ENC_GCM_RFC4543: + default: + block_len = 0; + break; + } + + return block_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 wolf_ret = 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; + + wolf_ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + + if (wolf_ret) { + printf("error: wc_HmacSetKey returned %d\n", wolf_ret); + goto calc_icv_hmac_end; + } + + wolf_ret = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, + esp_sa->auth_key_len); + if (wolf_ret) { + printf("error: wc_HmacSetKey returned %d\n", wolf_ret); + goto calc_icv_hmac_end; + } + + /* Now calculate the ICV. The ICV covers from SPI to Next Header, + * inclusive. */ + wolf_ret = wc_HmacUpdate(&hmac, (const byte *)esp_data, auth_len); + if (wolf_ret) { + printf("error: wc_HmacUpdate returned %d\n", wolf_ret); + goto calc_icv_hmac_end; + } + + wolf_ret = wc_HmacFinal(&hmac, hash); + if (wolf_ret) { + printf("error: wc_HmacFinal returned %d\n", wolf_ret); + goto calc_icv_hmac_end; + } + +calc_icv_hmac_end: + wc_HmacFree(&hmac); + + return wolf_ret; +} + +static int +esp_const_memcmp(const uint8_t * vec_a, const uint8_t * vec_b, uint32_t len) +{ + uint32_t i; + 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 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_sa->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\n"); + #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_sa->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\n"); + #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; +} + + +/** + * 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; +} + +/** + * Decapsulate an ipv4 ESP packet. 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_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; + int rc = 0; + + memset(spi, 0, sizeof(spi)); + + if (*frame_len <= (ETH_HEADER_LEN + IP_HEADER_LEN)) { + #ifdef WOLFIP_DEBUG_ESP + printf("error: esp: malformed frame: %d\n", *frame_len); + #endif /* WOLFIP_DEBUG_ESP */ + return -1; + } + + esp_len = *frame_len - ETH_HEADER_LEN - IP_HEADER_LEN; + + /* If not at least SPI and sequence, something wrong. */ + if (esp_len < (ESP_SPI_LEN + ESP_SEQ_LEN)) { + #ifdef WOLFIP_DEBUG_ESP + printf("error: esp: malformed packet: %d\n", esp_len); + #endif /* WOLFIP_DEBUG_ESP */ + return -1; + } + + /* First 4 bytes are the spi (Security Parameters Index). */ + memcpy(spi, ip->data, sizeof(spi)); + /* Next 4 bytes are the seq (Sequence Number).*/ + memcpy(&seq, ip->data + ESP_SPI_LEN, sizeof(seq)); + seq = ee32(seq); + + for (size_t i = 0; i < in_sa_num; ++i) { + if (memcmp(spi, in_sa_list[i].spi, sizeof(spi)) == 0) { + #ifdef WOLFIP_DEBUG_ESP + printf("info: found sa: 0x%02x%02x%02x%02x\n", + spi[0], spi[1], spi[2], spi[3]); + #endif /* WOLFIP_DEBUG_ESP */ + esp_sa = &in_sa_list[i]; + break; + } + } + + if (esp_sa == NULL) { + /** + * RFC4303: + * If no valid Security Association exists for this packet, the + * receiver MUST discard the packet; this is an auditable event. + * */ + printf("error: unknown spi: 0x%02x%02x%02x%02x\n", + spi[0], spi[1], spi[2], spi[3]); + return -1; + } + + { + /* calculate min expected length based on the security association. */ + uint32_t min_len = 0; + + min_len = (ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->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) { + rc = esp_check_icv_hmac(esp_sa, ip->data, esp_len); + if (rc) { + printf("error: icv check failed\n"); + return -1; + } + } + + if (esp_sa->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_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 */ + + #ifdef WOLFIP_DEBUG_ESP_VERBOSE + esp_dump_data_verbose("esp_packet before unwrap", ip->data, esp_len); + #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ + + /* move ip payload forward to hide ESP header (SPI, SEQ, IV). */ + memmove(ip->data, ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->iv_len, + esp_len - (ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->iv_len)); + + /* subtract ESP header from frame_len and ip.len. */ + *frame_len = *frame_len - (esp_sa->iv_len + ESP_SPI_LEN + ESP_SEQ_LEN); + ip->len = ee16(ip->len) - (esp_sa->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); + + #ifdef WOLFIP_DEBUG_ESP_VERBOSE + esp_dump_data_verbose("esp_packet after unwrap", ip->data, + *frame_len - ETH_HEADER_LEN - IP_HEADER_LEN); + #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ + + (void)s; + return 0; +} + +/** + * Encapsulate an ipv4 packet with ESP. + * + * 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_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; + struct wolfIP_esp_sa * esp_sa = NULL; + + /* TODO: priority, tcp/udp port-filtering? */ + for (size_t i = 0; i < out_sa_num; ++i) { + if (ip->dst == 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; + } + + #ifdef WOLFIP_DEBUG_ESP_VERBOSE + esp_dump_data_verbose("ip packet before wrap", ip->data, orig_payload_len); + #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ + + #if 0 + /* return early, do nothing. */ + return 0; + #endif + + /* move ip payload back to make room for ESP header (SPI, SEQ) + IV. */ + memmove(ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->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; + + esp_sa->oseq++; + seq_n = ee32(esp_sa->oseq); + memcpy(payload, &seq_n, sizeof(seq_n)); + payload += ESP_SEQ_LEN; + + if (esp_sa->iv_len) { + /* skip iv field, will generate later. */ + payload += esp_sa->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 = esp_sa->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 + esp_sa->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 + esp_sa->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 + esp_sa->iv_len + + pad_len + ESP_PADDING_LEN + ESP_NEXT_HEADER_LEN + + esp_sa->icv_len; + + /* encrypt from payload to end of ESP trailer. */ + if (esp_sa->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_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 rc = 0; + + icv = ip->data + icv_offset; + + rc = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); + if (rc) { + 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 */ + + #ifdef WOLFIP_DEBUG_ESP_VERBOSE + esp_dump_data_verbose("ip packet after wrap", ip->data, payload_len); + #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ + + return 0; +} + +/** + * Copy frame to new packet so we can expand and wrap in place + * without stepping on the fifo tcp circular buffer. + * */ +static int esp_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_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 45db54b..a9ccd71 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -1495,6 +1495,10 @@ 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) { @@ -3306,6 +3310,10 @@ void wolfIP_init(struct wolfIP *s) } } #endif + + #ifdef WOLFIP_ESP + esp_init(); + #endif /* WOLFIP_ESP */ } struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s) @@ -3322,6 +3330,10 @@ struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) static struct wolfIP wolfIP_static; void wolfIP_init_static(struct wolfIP **s) { + #ifdef WOLFIP_ESP + esp_init(); + #endif /* WOLFIP_ESP */ + if (!s) return; wolfIP_init(&wolfIP_static); @@ -3339,12 +3351,42 @@ size_t wolfIP_instance_size(void) return sizeof(struct wolfIP); } +#ifdef DEBUG_IP +static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) +{ + char src[32]; + char dst[32]; + memset(src, 0, sizeof(src)); + memset(dst, 0, sizeof(dst)); + iptoa(ee32(ip->src), src); + iptoa(ee32(ip->dst), dst); + + printf("ip hdr:\n"); + printf("+-----------------------------+\n"); + printf("| 0x%02x | 0x%02x | 0x%02x | %4d | (ipv, hdr_len, tos, ip_len)\n", + 0x04, ip->ver_ihl, ip->tos, ee16(ip->len)); + printf("+-----------------------------+\n"); + printf("| 0x%04x | 0x%04x | (id, flags_fo)\n", + ee16(ip->id), ee16(ip->flags_fo)); + printf("+-----------------------------+\n"); + printf("| %3d | 0x%02x | 0x%04x | (ttl, proto, chksum)\n", + ip->ttl, ip->proto, ee16(ip->csum)); + printf("+-----------------------------+\n"); + printf("| %15s | (src)\n", src); + printf("+-----------------------------+\n"); + printf("| %15s | (dst)\n", dst); + printf("+-----------------------------+\n"); + printf("\n"); +} +#endif /* DEBUG_IP*/ + 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 + #if WOLFIP_ENABLE_LOOPBACK if (!wolfIP_is_loopback_if(if_idx)) { ip4 dest = ee32(ip->dst); @@ -3395,6 +3437,22 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ } } #endif + #ifdef DEBUG_IP + wolfIP_print_ip(ip); + #endif /* DEBUG_IP*/ + + #ifdef WOLFIP_ESP + if (ip->proto == 0x32) { + /* proto is ESP 0x32 (50), try to unwrap. */ + int esp_rc = 0; + esp_rc = esp_unwrap(s, ip, &len); + if (esp_rc) { + 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); @@ -3402,10 +3460,36 @@ 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 | %5d bytes data | (eth type, payload) \n", + type[0], type[1], 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) { @@ -3877,7 +3961,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_output(ll, (struct wolfIP_ip_packet *)tcp, size); + #else ll->send(ll, tcp, desc->len); + #endif /* WOLFIP_ESP */ } } desc->flags |= PKT_FLAG_SENT; diff --git a/wolfesp.h b/wolfesp.h new file mode 100644 index 0000000..2944130 --- /dev/null +++ b/wolfesp.h @@ -0,0 +1,66 @@ +#ifndef WOLFESP_H +#define WOLFESP_H + +#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 +#define WOLFIP_ESP_NUM_SA 2 + +/* aes-128 */ +#define ESP_128_KEY_LEN 16 +#define ESP_128_IV_LEN 16 + +/* gcm */ +#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 \ + +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; + +/* 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; + uint32_t oseq; /* outbound sequence number */ + uint32_t seq; /* inbound sequence number */ + uint8_t iv_len; + esp_enc_t enc; + uint8_t enc_key[32]; + uint8_t enc_key_len; + esp_auth_t auth; + uint8_t auth_key[32]; + uint8_t auth_key_len; + uint8_t icv_len; + #if 0 + uint8_t pre_iv[ESP_GCM_RFC4106_IV_LEN]; /* unique salt that is xor'ed with + * oseq to generate the iv. */ + #endif +}; + +int esp_init(void); +void esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, uint16_t in); + +#endif /* !WOLFESP_H */ diff --git a/wolfip.h b/wolfip.h index e12b1f9..407ace5 100644 --- a/wolfip.h +++ b/wolfip.h @@ -287,15 +287,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 c950f7d845204f8d6faee746b09aa005d8a32a50 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 28 Jan 2026 16:50:00 -0600 Subject: [PATCH 02/16] cleanup: fix unterminated string warning. --- Makefile | 1 - src/test/ipfilter_logger.c | 5 ++++- src/test/test_native_wolfssl.c | 5 ++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 7bebfa9..549d293 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ CC?=gcc CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE CFLAGS+=-g -ggdb -Wdeclaration-after-statement -CFLAGS+=-Wno-error=unterminated-string-initialization LDFLAGS+=-pthread # Debug flags: diff --git a/src/test/ipfilter_logger.c b/src/test/ipfilter_logger.c index 1ba5c6e..c9508fd 100644 --- a/src/test/ipfilter_logger.c +++ b/src/test/ipfilter_logger.c @@ -33,7 +33,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/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 */ From d91461947520523432affe57d34d58eb748c2a64 Mon Sep 17 00:00:00 2001 From: jordan Date: Wed, 28 Jan 2026 16:56:46 -0600 Subject: [PATCH 03/16] cleanup: fix cppcheck cast warning. --- src/wolfip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index a9ccd71..a2c37f1 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3484,8 +3484,8 @@ static void wolfIP_print_eth(struct wolfIP_eth_frame * eth, uint32_t len) 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 | %5d bytes data | (eth type, payload) \n", - type[0], type[1], len); + printf("| 0x%02x%02x | %5lu bytes data | (eth type, payload) \n", + type[0], type[1], (unsigned long)len); printf("+---------------------------------------+\n"); printf("\n"); } From 8f3b86b4f42c0db35742803c34dd6d6a712b19f7 Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 13:21:06 -0600 Subject: [PATCH 04/16] esp: rfc4106. --- Makefile | 17 +- scripts/ip-xfrm/esp_sa.txt | 7 +- scripts/ip-xfrm/rfc4106 | 58 ++++ src/test/esp_sa_list.c | 46 ++- src/test/test_esp.c | 572 +++++++++++++++++++++++++++++++++++++ src/wolfesp.c | 251 +++++++++++++++- wolfesp.h | 4 +- 7 files changed, 925 insertions(+), 30 deletions(-) create mode 100755 scripts/ip-xfrm/rfc4106 create mode 100644 src/test/test_esp.c diff --git a/Makefile b/Makefile index 549d293..1b93143 100644 --- a/Makefile +++ b/Makefile @@ -8,17 +8,17 @@ LDFLAGS+=-pthread # print ethernet headers # CFLAGS+=-DDEBUG_ETH # print ip headers -#CFLAGS+=-DDEBUG_IP + CFLAGS+=-DDEBUG_IP # print tcp headers -# CFLAGS+=-DDEBUG_TCP + CFLAGS+=-DDEBUG_TCP # print esp header data -#FLAGS+=-DWOLFIP_DEBUG_ESP + CFLAGS+=-DWOLFIP_DEBUG_ESP #CFLAGS+=-DWOLFIP_DEBUG_ESP_VERBOSE # ESP support -#CFLAGS+=-DWOLFIP_ESP -#CFLAGS+=-DWOLFSSL_WOLFIP -#LDFLAGS+=-lwolfssl +CFLAGS+=-DWOLFIP_ESP +CFLAGS+=-DWOLFSSL_WOLFIP +LDFLAGS+=-lwolfssl UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) @@ -138,7 +138,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 @@ -206,6 +206,9 @@ build/tcp_netcat_select: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_net @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(END_GROUP) +build/test-esp: $(OBJ) build/test/test_esp.o + @echo "[LD] $@" + @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(END_GROUP) build/test-wolfssl:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP build/test-httpd:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -Isrc/http diff --git a/scripts/ip-xfrm/esp_sa.txt b/scripts/ip-xfrm/esp_sa.txt index 2245be9..425cb3f 100644 --- a/scripts/ip-xfrm/esp_sa.txt +++ b/scripts/ip-xfrm/esp_sa.txt @@ -1,5 +1,10 @@ -# This file is automatically generated, DO NOT MODIFY. +# 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.2","10.10.10.1","0xf6e9b80d","NULL","","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" "IPv4","10.10.10.1","10.10.10.2","0x2fa9d8c8","NULL","","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" "IPv4","10.10.10.1","10.10.10.2","0x764f47c9","AES-CBC [RFC3602]","0x03030303030303030303030303030303","HMAC-SHA-256-128 [RFC4868]","0x01010101010101010101010101010101","32-bit","0" "IPv4","10.10.10.2","10.10.10.1","0x49ebfdd4","AES-CBC [RFC3602]","0x04040404040404040404040404040404","HMAC-SHA-256-128 [RFC4868]","0x02020202020202020202020202020202","32-bit","0" +"IPv4","10.10.10.2","10.10.10.1","0x02020202","AES-GCM with 16 octet ICV [RFC4106]","0x040404040404040404040404040404040a0b0c0d","NULL","0x02020202020202020202020202020202","32-bit","0" +"IPv4","10.10.10.1","10.10.10.2","0x01010101","AES-GCM with 16 octet ICV [RFC4106]","0x030303030303030303030303030303030a0b0c0d","NULL","0x02020202020202020202020202020202","32-bit","0" diff --git a/scripts/ip-xfrm/rfc4106 b/scripts/ip-xfrm/rfc4106 new file mode 100755 index 0000000..f6b0176 --- /dev/null +++ b/scripts/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 " ./scripts/ip-xfrm/rfc4106 128" + echo " ./scripts/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 0x03030303030303030303030303030303$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 0x04040404040404040404040404040404$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/src/test/esp_sa_list.c b/src/test/esp_sa_list.c index 0a76350..c17fefa 100644 --- a/src/test/esp_sa_list.c +++ b/src/test/esp_sa_list.c @@ -2,7 +2,7 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = { - { + { /* null hmac 128 */ {0x2f, 0xa9, 0xd8, 0xc8}, /* spi */ 0x010A0A0A, /* src */ 0x020A0A0A, /* dst */ @@ -13,9 +13,9 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 16, - ESP_ICVLEN_HMAC_128 + ESP_ICVLEN_HMAC_128 /* icv len */ }, - { + { /* cbc hmac 128 */ {0x76, 0x4f, 0x47, 0xc9}, /* spi */ 0x010A0A0A, /* src */ 0x020A0A0A, /* dst */ @@ -29,13 +29,28 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 16, - ESP_ICVLEN_HMAC_128 + ESP_ICVLEN_HMAC_128/* icv len */ + }, + { /* gcm4106 */ + {0x01, 0x01, 0x01, 0x01}, /* spi */ + 0x010A0A0A, /* src */ + 0x020A0A0A, /* dst */ + 0,0, /* oseq, seq */ + ESP_GCM_RFC4106_IV_LEN, /* iv len */ + ESP_ENC_GCM_RFC4106, + {0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x0a, 0x0b, 0x0c, 0x0d}, + 16 + 4, /* key + nonce */ + ESP_AUTH_GCM_RFC4106, + {0}, 0, /* null auth key */ + ESP_GCM_RFC4106_ICV_LEN/* icv len */ }, }; static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = { - { + { /* null hmac 128 */ {0xf6, 0xe9, 0xb8, 0x0d}, /* spi */ 0x020A0A0A, /* src */ 0x030A0A0A, /* dst */ @@ -48,11 +63,10 @@ static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = 16, ESP_ICVLEN_HMAC_128 }, - - { + { /* cbc hmac 128 */ {0x49, 0xeb, 0xfd, 0xd4}, /* spi */ 0x020A0A0A, /* src */ - 0x010A0A0A, /* dst */ + 0x030A0A0A, /* dst */ 0,0, /* oseq, seq */ ESP_128_IV_LEN, /* iv len */ ESP_ENC_CBC_AES, @@ -66,5 +80,19 @@ static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = ESP_ICVLEN_HMAC_128 }, + { /* gcm4106 */ + {0x02, 0x02, 0x02, 0x02}, /* spi */ + 0x020A0A0A, /* src */ + 0x010A0A0A, /* dst */ + 0,0, /* oseq, seq */ + ESP_GCM_RFC4106_IV_LEN, /* iv len */ + ESP_ENC_GCM_RFC4106, + {0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x0a, 0x0b, 0x0c, 0x0d}, + 16 + 4, /* key + nonce */ + ESP_AUTH_GCM_RFC4106, + {0}, 0, /* null auth key */ + ESP_GCM_RFC4106_ICV_LEN/* icv len */ + }, }; - diff --git a/src/test/test_esp.c b/src/test/test_esp.c new file mode 100644 index 0000000..ce56dcc --- /dev/null +++ b/src/test/test_esp.c @@ -0,0 +1,572 @@ +/* test_esp.c + * + * Copyright (C) 2024 wolfSSL Inc. + * + * This file is part of wolfIP TCP/IP stack. + * + * wolfIP is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfIP is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "wolfip.h" + +#if defined(WOLFIP_ESP) + #include "wolfesp.h" + #include "esp_sa_list.c" +#endif + +#define TEST_SIZE (4 * 1024) + +#define BUFFER_SIZE TEST_SIZE + +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}; + + +/* 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; + } + + /* Client side test: server is closing the connection */ + /* Excluded for now because binding twice on port 8 is not supported */ +#if 0 + conn_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (conn_fd < 0) { + printf("cannot create socket: %d\n", conn_fd); + } + 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*)0); + printf("Starting test: echo client passive close\n"); + ret = test_loop(s, 0); + printf("Test echo client, server closing: %d\n", ret); + pthread_join(pt, (void **)&test_ret); + printf("Test host server: %d\n", test_ret); +#endif +} + +/* Main test function. */ +int main(int argc, char **argv) +{ + struct wolfIP *s; + struct wolfIP_ll_dev *tapdev; + struct timeval tv = {0, 0}; + struct in_addr host_stack_ip; + uint32_t srv_ip; + ip4 ip = 0, nm = 0, gw = 0; + + (void)argc; + (void)argv; + (void)ip; + (void)nm; + (void)gw; + (void)tv; + wolfIP_init_static(&s); + tapdev = wolfIP_getdev(s); + if (!tapdev) + 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 + } + +#ifdef DHCP + gettimeofday(&tv, NULL); + wolfIP_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000); + dhcp_client_init(s); + do { + gettimeofday(&tv, NULL); + wolfIP_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000); + usleep(1000); + wolfIP_ipconfig_get(s, &ip, &nm, &gw); + } while (!dhcp_bound(s)); + printf("DHCP: obtained IP address.\n"); + wolfIP_ipconfig_get(s, &ip, &nm, &gw); + srv_ip = htonl(ip); +#else + 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); +#endif + +#if defined(WOLFIP_ESP) + esp_load_sa_list(test_in_sa_list, WOLFIP_ESP_NUM_SA, 1); + esp_load_sa_list(test_out_sa_list, WOLFIP_ESP_NUM_SA, 0); +#endif + + /* 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; +} diff --git a/src/wolfesp.c b/src/wolfesp.c index 57764d7..e7c4f69 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -25,7 +25,6 @@ esp_init(void) return ret; } - static struct wolfIP_esp_sa * in_sa_list = NULL; static struct wolfIP_esp_sa * out_sa_list = NULL; static uint16_t in_sa_num = 0; @@ -183,7 +182,7 @@ static void wolfIP_print_esp(const struct wolfIP_esp_sa * esp_sa, } #endif /* WOLFIP_DEBUG_ESP */ -uint8_t +static uint8_t esp_block_len_from_enc(esp_enc_t enc) { uint8_t block_len = 0; @@ -195,9 +194,11 @@ esp_block_len_from_enc(esp_enc_t enc) case ESP_ENC_CBC_AES: block_len = WC_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: @@ -279,10 +280,11 @@ esp_calc_icv_hmac(uint8_t * hash, const struct wolfIP_esp_sa * esp_sa, return wolf_ret; } +/* 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; + uint32_t i = 0; int sum = 0; for (i = 0; i < len; i++) { @@ -305,6 +307,12 @@ esp_const_memcmp(const uint8_t * vec_a, const uint8_t * vec_b, uint32_t len) #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. * */ @@ -426,6 +434,184 @@ esp_aes_rfc3602_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, 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_sa->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\n"); + #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_sa->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 */ + +rfc4106_enc_out: + if (inited) { + wc_AesFree(&gcm_enc); + inited = 0; + } + + /* 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 salt and sequence number. */ + uint32_t seq_num = 0; + uint8_t * seq_num_u8 = (uint8_t *) &seq_num; + + seq_num = ee32(esp_sa->oseq); + + /* copy in the salt. */ + memcpy(iv, salt, ESP_GCM_RFC4106_SALT_LEN); + + /* xor 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; + } + + + return err; +} /** * esp_data covers from start of ESP header to end of ESP trailer, but does not @@ -496,7 +682,6 @@ static int esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t esp_len = 0; uint8_t pad_len = 0; uint8_t nxt_hdr = 0; - int rc = 0; memset(spi, 0, sizeof(spi)); @@ -560,8 +745,25 @@ static int esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, } if (esp_sa->icv_len) { - rc = esp_check_icv_hmac(esp_sa, ip->data, esp_len); - if (rc) { + int err = 0; + 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; } @@ -576,6 +778,10 @@ static int esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, 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); @@ -667,7 +873,8 @@ static int esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) uint16_t icv_offset = 0; struct wolfIP_esp_sa * esp_sa = NULL; - /* TODO: priority, tcp/udp port-filtering? */ + /* 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 == out_sa_list[i].dst) { esp_sa = &out_sa_list[i]; @@ -783,6 +990,10 @@ static int esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) 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); @@ -800,12 +1011,28 @@ static int esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) if (esp_sa->icv_len) { uint8_t * icv = NULL; - int rc = 0; - - icv = ip->data + icv_offset; + 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; + } - rc = esp_calc_icv_hmac(icv, esp_sa, ip->data, payload_len); - if (rc) { + if (err) { + printf("error: icv check failed\n"); return -1; } } diff --git a/wolfesp.h b/wolfesp.h index 2944130..b27fb90 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -9,16 +9,18 @@ /* hmac-[sha256, sha1, md5]-96*/ #define ESP_ICVLEN_HMAC_96 12 #define ESP_ICVLEN_HMAC_128 16 -#define WOLFIP_ESP_NUM_SA 2 +#define WOLFIP_ESP_NUM_SA 3 /* aes-128 */ #define ESP_128_KEY_LEN 16 #define ESP_128_IV_LEN 16 /* 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, From f638c62102b54e99a826d5f4eae80fe0d6b3a1bf Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 13:31:29 -0600 Subject: [PATCH 05/16] cleanup. --- Makefile | 12 ++++++------ src/wolfesp.c | 26 ++++++++++++++++---------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 1b93143..4b88bfb 100644 --- a/Makefile +++ b/Makefile @@ -8,17 +8,17 @@ LDFLAGS+=-pthread # print ethernet headers # CFLAGS+=-DDEBUG_ETH # print ip headers - CFLAGS+=-DDEBUG_IP +# CFLAGS+=-DDEBUG_IP # print tcp headers - CFLAGS+=-DDEBUG_TCP +# CFLAGS+=-DDEBUG_TCP # print esp header data - CFLAGS+=-DWOLFIP_DEBUG_ESP +# CFLAGS+=-DWOLFIP_DEBUG_ESP #CFLAGS+=-DWOLFIP_DEBUG_ESP_VERBOSE # ESP support -CFLAGS+=-DWOLFIP_ESP -CFLAGS+=-DWOLFSSL_WOLFIP -LDFLAGS+=-lwolfssl +# CFLAGS+=-DWOLFIP_ESP +# CFLAGS+=-DWOLFSSL_WOLFIP +# LDFLAGS+=-lwolfssl UNAME_S:=$(shell uname -s) UNAME_M:=$(shell uname -m) diff --git a/src/wolfesp.c b/src/wolfesp.c index e7c4f69..1464a92 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -333,7 +333,7 @@ esp_aes_rfc3602_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t inited = 0; #ifdef WOLFIP_DEBUG_ESP - printf("info: aes cbc dec\n"); + printf("info: aes cbc dec: %d\n", esp_len); #endif /* WOLFIP_DEBUG_ESP */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); @@ -387,7 +387,7 @@ esp_aes_rfc3602_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t inited = 0; #ifdef WOLFIP_DEBUG_ESP - printf("info: aes cbc enc\n"); + printf("info: aes cbc enc: %d\n", esp_len); #endif /* WOLFIP_DEBUG_ESP */ enc_len = esp_enc_len(esp_len, iv_len, icv_len); @@ -464,7 +464,7 @@ esp_aes_rfc4106_dec(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ #ifdef WOLFIP_DEBUG_ESP - printf("info: aes gcm dec\n"); + printf("info: aes gcm dec: %d\n", esp_len); #endif /* WOLFIP_DEBUG_ESP */ /* get enc payload, iv, and icv pointers. */ @@ -540,11 +540,9 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, uint8_t salt_len = ESP_GCM_RFC4106_SALT_LEN; uint8_t nonce[ESP_GCM_RFC4106_NONCE_LEN]; /* 4 salt + 8 iv */ -rfc4106_enc_out: - if (inited) { - wc_AesFree(&gcm_enc); - inited = 0; - } + #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); @@ -557,7 +555,11 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, memcpy(aad, esp_data, sizeof(aad)); { - /* Deterministic iv construction using salt and sequence number. */ + /* Deterministic iv construction using 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 salt. Based on linux kernel crypto/seqiv.c. + * */ uint32_t seq_num = 0; uint8_t * seq_num_u8 = (uint8_t *) &seq_num; @@ -572,7 +574,6 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } } - memcpy(nonce, salt, salt_len); memcpy(nonce + salt_len, iv, iv_len); @@ -609,6 +610,11 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, goto rfc4106_enc_out; } +rfc4106_enc_out: + if (inited) { + wc_AesFree(&gcm_enc); + inited = 0; + } return err; } From 1a753aad06ff6d70f1dad8be515cd1a2e241da29 Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 15:18:12 -0600 Subject: [PATCH 06/16] fix pre_iv handling for rfc4106 salt. --- Makefile | 2 +- src/test/esp_sa_list.c | 18 ++++++++++++------ src/wolfesp.c | 8 ++++---- wolfesp.h | 6 ++---- 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 4b88bfb..34b8b8a 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ LDFLAGS+=-pthread # print tcp headers # CFLAGS+=-DDEBUG_TCP # print esp header data -# CFLAGS+=-DWOLFIP_DEBUG_ESP + CFLAGS+=-DWOLFIP_DEBUG_ESP #CFLAGS+=-DWOLFIP_DEBUG_ESP_VERBOSE # ESP support diff --git a/src/test/esp_sa_list.c b/src/test/esp_sa_list.c index c17fefa..7f511e4 100644 --- a/src/test/esp_sa_list.c +++ b/src/test/esp_sa_list.c @@ -13,7 +13,8 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 16, - ESP_ICVLEN_HMAC_128 /* icv len */ + ESP_ICVLEN_HMAC_128, /* icv len */ + {0} /* pre-iv */ }, { /* cbc hmac 128 */ {0x76, 0x4f, 0x47, 0xc9}, /* spi */ @@ -29,7 +30,8 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, 16, - ESP_ICVLEN_HMAC_128/* icv len */ + ESP_ICVLEN_HMAC_128, /* icv len */ + {0} /* pre-iv */ }, { /* gcm4106 */ {0x01, 0x01, 0x01, 0x01}, /* spi */ @@ -44,7 +46,8 @@ static struct wolfIP_esp_sa test_in_sa_list[WOLFIP_ESP_NUM_SA] = 16 + 4, /* key + nonce */ ESP_AUTH_GCM_RFC4106, {0}, 0, /* null auth key */ - ESP_GCM_RFC4106_ICV_LEN/* icv len */ + ESP_GCM_RFC4106_ICV_LEN, /* icv len */ + {0} /* pre-iv */ }, }; @@ -61,7 +64,8 @@ static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, 16, - ESP_ICVLEN_HMAC_128 + ESP_ICVLEN_HMAC_128, + {0} /* pre-iv */ }, { /* cbc hmac 128 */ {0x49, 0xeb, 0xfd, 0xd4}, /* spi */ @@ -77,7 +81,8 @@ static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = {0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02}, 16, - ESP_ICVLEN_HMAC_128 + ESP_ICVLEN_HMAC_128, + {0} /* pre-iv */ }, { /* gcm4106 */ @@ -93,6 +98,7 @@ static struct wolfIP_esp_sa test_out_sa_list[WOLFIP_ESP_NUM_SA] = 16 + 4, /* key + nonce */ ESP_AUTH_GCM_RFC4106, {0}, 0, /* null auth key */ - ESP_GCM_RFC4106_ICV_LEN/* icv len */ + ESP_GCM_RFC4106_ICV_LEN, /* icv len */ + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08} /* pre-iv */ }, }; diff --git a/src/wolfesp.c b/src/wolfesp.c index 1464a92..c1dcfba 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -555,18 +555,18 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, memcpy(aad, esp_data, sizeof(aad)); { - /* Deterministic iv construction using salt and sequence number. + /* 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 salt. Based on linux kernel crypto/seqiv.c. + * 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->oseq); - /* copy in the salt. */ - memcpy(iv, salt, ESP_GCM_RFC4106_SALT_LEN); + /* copy in the pre_iv. */ + memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); /* xor salt with current sequence number. */ for (size_t i = 0; i < sizeof(uint32_t); ++i) { diff --git a/wolfesp.h b/wolfesp.h index b27fb90..d069c79 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -56,10 +56,8 @@ struct wolfIP_esp_sa { uint8_t auth_key[32]; uint8_t auth_key_len; uint8_t icv_len; - #if 0 - uint8_t pre_iv[ESP_GCM_RFC4106_IV_LEN]; /* unique salt that is xor'ed with - * oseq to generate the iv. */ - #endif + uint8_t pre_iv[ESP_GCM_RFC4106_IV_LEN]; /* unique salt that is xor'ed + * with oseq to generate iv. */ }; int esp_init(void); From 31c2cc581685a2479ccafde445b27287fc158696 Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 17:28:57 -0600 Subject: [PATCH 07/16] separate test esp build. --- Makefile | 56 ++++++++++++++++++++++++++++++++++----------------- src/wolfesp.c | 6 +++++- 2 files changed, 43 insertions(+), 19 deletions(-) diff --git a/Makefile b/Makefile index 34b8b8a..57fcd2a 100644 --- a/Makefile +++ b/Makefile @@ -3,22 +3,23 @@ CFLAGS:=-Wall -Werror -Wextra -I. -D_GNU_SOURCE CFLAGS+=-g -ggdb -Wdeclaration-after-statement LDFLAGS+=-pthread +# # Debug flags: -# 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 -#CFLAGS+=-DWOLFIP_DEBUG_ESP_VERBOSE - -# ESP support -# CFLAGS+=-DWOLFIP_ESP -# CFLAGS+=-DWOLFSSL_WOLFIP -# LDFLAGS+=-lwolfssl +# 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) @@ -119,6 +120,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). @@ -171,6 +175,11 @@ asan: $(EXE) $(LIB) asan:CFLAGS+=-fsanitize=address asan:LDFLAGS+=-static-libasan +ESP_CFLAGS = \ + -DWOLFIP_ESP \ + -DWOLFSSL_WOLFIP \ + -DDEBUG_IP \ + -DWOLFIP_DEBUG_ESP # Test @@ -206,9 +215,6 @@ build/tcp_netcat_select: $(OBJ) build/port/posix/bsd_socket.o build/test/tcp_net @echo "[LD] $@" @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(END_GROUP) -build/test-esp: $(OBJ) build/test/test_esp.o - @echo "[LD] $@" - @$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(END_GROUP) build/test-wolfssl:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP build/test-httpd:CFLAGS+=-Wno-cpp -DWOLFSSL_DEBUG -DWOLFSSL_WOLFIP -Isrc/http @@ -229,6 +235,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/src/wolfesp.c b/src/wolfesp.c index c1dcfba..47068ac 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -33,6 +33,10 @@ static uint16_t out_sa_num = 0; void esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, uint16_t 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; @@ -568,7 +572,7 @@ esp_aes_rfc4106_enc(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, /* copy in the pre_iv. */ memcpy(iv, esp_sa->pre_iv, sizeof(esp_sa->pre_iv)); - /* xor salt with current sequence number. */ + /* 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]; } From 513501d5f0401292e8083be8fb7f96602713a65d Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 18:06:51 -0600 Subject: [PATCH 08/16] use AES_BLOCK_SIZE instead of newer WC_AES_BLOCK_SIZE. --- src/wolfesp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index 47068ac..aead683 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -196,7 +196,7 @@ esp_block_len_from_enc(esp_enc_t enc) block_len = 0; break; case ESP_ENC_CBC_AES: - block_len = WC_AES_BLOCK_SIZE; + block_len = AES_BLOCK_SIZE; break; #ifndef NO_DES3 case ESP_ENC_CBC_DES3: From 85821a271028bf60f8a09dc660360163382e725e Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 18:12:47 -0600 Subject: [PATCH 09/16] remove old ESP stuff from eventloop test. --- src/test/test_eventloop.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/test/test_eventloop.c b/src/test/test_eventloop.c index 87b688b..dde8eb6 100644 --- a/src/test/test_eventloop.c +++ b/src/test/test_eventloop.c @@ -34,11 +34,6 @@ #include "config.h" #include "wolfip.h" -#if defined(WOLFIP_ESP) - #include "wolfesp.h" - #include "esp_sa_list.c" -#endif - #define TEST_SIZE (4 * 1024) #define BUFFER_SIZE TEST_SIZE @@ -547,11 +542,6 @@ int main(int argc, char **argv) inet_pton(AF_INET, WOLFIP_IP, &srv_ip); #endif -#if defined(WOLFIP_ESP) - esp_load_sa_list(test_in_sa_list, 2, 1); - esp_load_sa_list(test_out_sa_list, 2, 0); -#endif - /* Server side test */ test_wolfip_echoserver(s, srv_ip); From 9e1a68fa063ef6b8769649d803a167603dc3ec63 Mon Sep 17 00:00:00 2001 From: jordan Date: Sat, 31 Jan 2026 18:29:19 -0600 Subject: [PATCH 10/16] add esp github workflow. --- .github/workflows/linux.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml index 3530cab..5556dc0 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 ./scripts/ip-xfrm/rfc4106 128 + sudo ./build/test-esp + sudo killall tcpdump || true + sudo ./scripts/ip-xfrm/delete_all + - name: Run standalone wolfssl test run: | sudo ./build/test-wolfssl From b3ea6387eba57e4b007da182ae79d434c0661a19 Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 2 Feb 2026 15:54:38 -0600 Subject: [PATCH 11/16] esp: add wolfIP prefix, line lengths, and cleanup. --- src/test/test_esp.c | 104 +++++++++++++++++--------------------------- src/wolfesp.c | 8 ++-- src/wolfip.c | 8 ---- wolfesp.h | 5 ++- 4 files changed, 47 insertions(+), 78 deletions(-) diff --git a/src/test/test_esp.c b/src/test/test_esp.c index ce56dcc..73b242b 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -33,11 +33,9 @@ #include #include "config.h" #include "wolfip.h" +#include "wolfesp.h" -#if defined(WOLFIP_ESP) - #include "wolfesp.h" - #include "esp_sa_list.c" -#endif +#include "esp_sa_list.c" #define TEST_SIZE (4 * 1024) @@ -63,22 +61,27 @@ 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); + 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); + } + 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) { + } + 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) { + } + else if (ret > 0) { printf("recv: %d, echoing back\n", ret); tot_recv += ret; } @@ -100,7 +103,8 @@ static void server_cb(int fd, uint16_t event, void *arg) if (snd_ret < 0) { printf("Send error: %d\n", snd_ret); wolfIP_sock_close((struct wolfIP *)arg, client_fd); - } else { + } + else { tot_sent += snd_ret; printf("sent %d bytes\n", snd_ret); if (tot_recv == tot_sent) { @@ -142,8 +146,10 @@ static void client_cb(int fd, uint16_t event, void *arg) 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 (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; @@ -290,14 +296,16 @@ static void *pt_echoclient(void *arg) printf("connect still in progress after timeout\n"); continue; } - if (err != EINPROGRESS && err != EALREADY && err != EWOULDBLOCK && err != EAGAIN) { + 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 { + } + else { printf("connect returned immediately\n"); } if (fcntl(fd, F_SETFL, old_flags) < 0) @@ -476,48 +484,33 @@ static void test_wolfip_echoclient(struct wolfIP *s) wolfIP_sock_close(s, conn_fd); conn_fd = -1; } - - /* Client side test: server is closing the connection */ - /* Excluded for now because binding twice on port 8 is not supported */ -#if 0 - conn_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); - if (conn_fd < 0) { - printf("cannot create socket: %d\n", conn_fd); - } - 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*)0); - printf("Starting test: echo client passive close\n"); - ret = test_loop(s, 0); - printf("Test echo client, server closing: %d\n", ret); - pthread_join(pt, (void **)&test_ret); - printf("Test host server: %d\n", test_ret); -#endif } /* Main test function. */ int main(int argc, char **argv) { - struct wolfIP *s; - struct wolfIP_ll_dev *tapdev; - struct timeval tv = {0, 0}; - struct in_addr host_stack_ip; - uint32_t srv_ip; - ip4 ip = 0, nm = 0, gw = 0; + struct wolfIP_ll_dev * tapdev = NULL; + struct wolfIP * s = NULL; + struct in_addr host_stack_ip; + uint32_t srv_ip = 0; + int err = 0; (void)argc; (void)argv; - (void)ip; - (void)nm; - (void)gw; - (void)tv; + + err = wolfIP_esp_init(); + if (err) { + perror("esp_init"); + return 2; + } + wolfIP_init_static(&s); tapdev = wolfIP_getdev(s); - if (!tapdev) + 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"); @@ -534,30 +527,13 @@ int main(int argc, char **argv) #endif } -#ifdef DHCP - gettimeofday(&tv, NULL); - wolfIP_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000); - dhcp_client_init(s); - do { - gettimeofday(&tv, NULL); - wolfIP_poll(s, tv.tv_sec * 1000 + tv.tv_usec / 1000); - usleep(1000); - wolfIP_ipconfig_get(s, &ip, &nm, &gw); - } while (!dhcp_bound(s)); - printf("DHCP: obtained IP address.\n"); - wolfIP_ipconfig_get(s, &ip, &nm, &gw); - srv_ip = htonl(ip); -#else 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); -#endif -#if defined(WOLFIP_ESP) - esp_load_sa_list(test_in_sa_list, WOLFIP_ESP_NUM_SA, 1); - esp_load_sa_list(test_out_sa_list, WOLFIP_ESP_NUM_SA, 0); -#endif + wolfIP_esp_load_sa_list(test_in_sa_list, WOLFIP_ESP_NUM_SA, 1); + wolfIP_esp_load_sa_list(test_out_sa_list, WOLFIP_ESP_NUM_SA, 0); /* Server side test */ test_wolfip_echoserver(s, srv_ip); diff --git a/src/wolfesp.c b/src/wolfesp.c index aead683..cb04d32 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -3,11 +3,11 @@ #include "wolfesp.h" -static WC_RNG wc_rng; -static uint8_t rng_inited = 0; +static WC_RNG wc_rng; +static volatile int rng_inited = 0; int -esp_init(void) +wolfIP_esp_init(void) { int ret = 0; @@ -31,7 +31,7 @@ static uint16_t in_sa_num = 0; static uint16_t out_sa_num = 0; void -esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, uint16_t in) +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); diff --git a/src/wolfip.c b/src/wolfip.c index a2c37f1..74918ee 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -3310,10 +3310,6 @@ void wolfIP_init(struct wolfIP *s) } } #endif - - #ifdef WOLFIP_ESP - esp_init(); - #endif /* WOLFIP_ESP */ } struct wolfIP_ll_dev *wolfIP_getdev(struct wolfIP *s) @@ -3330,10 +3326,6 @@ struct wolfIP_ll_dev *wolfIP_getdev_ex(struct wolfIP *s, unsigned int if_idx) static struct wolfIP wolfIP_static; void wolfIP_init_static(struct wolfIP **s) { - #ifdef WOLFIP_ESP - esp_init(); - #endif /* WOLFIP_ESP */ - if (!s) return; wolfIP_init(&wolfIP_static); diff --git a/wolfesp.h b/wolfesp.h index d069c79..08b7f16 100644 --- a/wolfesp.h +++ b/wolfesp.h @@ -60,7 +60,8 @@ struct wolfIP_esp_sa { * with oseq to generate iv. */ }; -int esp_init(void); -void esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, uint16_t in); +int wolfIP_esp_init(void); +void wolfIP_esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, + int in); #endif /* !WOLFESP_H */ From 5119ed36b05f356ca8f3abbf92e70815d4c538bc Mon Sep 17 00:00:00 2001 From: jordan Date: Mon, 2 Feb 2026 17:38:04 -0600 Subject: [PATCH 12/16] wolfip: cleanup overlong lines. --- src/wolfip.c | 116 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 38 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 74918ee..d995123 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -534,7 +534,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; @@ -569,7 +572,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; @@ -585,7 +590,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; @@ -600,7 +606,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; @@ -614,7 +622,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; @@ -628,7 +638,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; @@ -641,7 +653,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; @@ -799,8 +813,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 @@ -820,8 +835,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; @@ -1055,8 +1070,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); @@ -1064,7 +1080,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}; @@ -1098,7 +1115,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; @@ -1225,7 +1243,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; @@ -1276,7 +1295,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); @@ -1476,7 +1496,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); @@ -1500,7 +1521,8 @@ static int eth_output_add_header(struct wolfIP *S, unsigned int if_idx, const ui #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) @@ -1531,7 +1553,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); @@ -1543,11 +1567,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) @@ -1566,7 +1593,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; @@ -1739,7 +1767,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; if (wolfIP_filter_notify_tcp(WOLFIP_FILT_RECEIVING, S, if_idx, tcp, frame_len) != 0) @@ -2408,7 +2437,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) @@ -2436,7 +2466,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) @@ -2517,7 +2548,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; @@ -2557,7 +2589,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; @@ -2745,7 +2778,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; @@ -2768,7 +2802,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; @@ -3174,7 +3209,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; @@ -3372,8 +3408,8 @@ static void wolfIP_print_ip(struct wolfIP_ip_packet * ip) } #endif /* DEBUG_IP*/ -static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_packet *ip, - uint32_t len) +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; @@ -3638,7 +3674,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; @@ -3751,7 +3788,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; @@ -4078,7 +4116,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) @@ -4088,7 +4127,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) From 47815280adcc72641636060f96ae7c7cbcadd373 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 3 Feb 2026 10:49:22 -0600 Subject: [PATCH 13/16] cleanup, update test. --- src/test/test_esp.c | 2 +- src/wolfesp.c | 51 +++++++++++++++++++++++---------------------- src/wolfip.c | 42 ++++++++++++++++++++++++++----------- wolfip.h | 48 ++++++++++++++++++++++++++++-------------- 4 files changed, 89 insertions(+), 54 deletions(-) diff --git a/src/test/test_esp.c b/src/test/test_esp.c index 73b242b..f9b6034 100644 --- a/src/test/test_esp.c +++ b/src/test/test_esp.c @@ -37,7 +37,7 @@ #include "esp_sa_list.c" -#define TEST_SIZE (4 * 1024) +#define TEST_SIZE (12 * 1024) #define BUFFER_SIZE TEST_SIZE diff --git a/src/wolfesp.c b/src/wolfesp.c index cb04d32..d259a56 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -9,20 +9,20 @@ static volatile int rng_inited = 0; int wolfIP_esp_init(void) { - int ret = 0; + int err = 0; if (rng_inited == 0) { - ret = wc_InitRng_ex(&wc_rng, NULL, INVALID_DEVID); + err = wc_InitRng_ex(&wc_rng, NULL, INVALID_DEVID); - if (ret) { - printf("error: wc_InitRng_ex returned: %d\n", ret); + if (err) { + printf("error: wc_InitRng_ex: %d\n", err); } else { rng_inited = 1; } } - return ret; + return err; } static struct wolfIP_esp_sa * in_sa_list = NULL; @@ -226,7 +226,7 @@ esp_calc_icv_hmac(uint8_t * hash, const struct wolfIP_esp_sa * esp_sa, * - WC_MD5_DIGEST_SIZE 16 bytes * */ Hmac hmac; - int wolf_ret = 0; + int err = 0; int type = 0; uint32_t auth_len = esp_len; @@ -250,38 +250,38 @@ esp_calc_icv_hmac(uint8_t * hash, const struct wolfIP_esp_sa * esp_sa, /* the icv is not included in icv calculation. */ auth_len = esp_len - esp_sa->icv_len; - wolf_ret = wc_HmacInit(&hmac, NULL, INVALID_DEVID); + err = wc_HmacInit(&hmac, NULL, INVALID_DEVID); - if (wolf_ret) { - printf("error: wc_HmacSetKey returned %d\n", wolf_ret); + if (err) { + printf("error: wc_HmacSetKey: %d\n", err); goto calc_icv_hmac_end; } - wolf_ret = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, + err = wc_HmacSetKey(&hmac, type, esp_sa->auth_key, esp_sa->auth_key_len); - if (wolf_ret) { - printf("error: wc_HmacSetKey returned %d\n", wolf_ret); + 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. */ - wolf_ret = wc_HmacUpdate(&hmac, (const byte *)esp_data, auth_len); - if (wolf_ret) { - printf("error: wc_HmacUpdate returned %d\n", wolf_ret); + err = wc_HmacUpdate(&hmac, (const byte *)esp_data, auth_len); + if (err) { + printf("error: wc_HmacUpdate: %d\n", err); goto calc_icv_hmac_end; } - wolf_ret = wc_HmacFinal(&hmac, hash); - if (wolf_ret) { - printf("error: wc_HmacFinal returned %d\n", wolf_ret); + 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 wolf_ret; + return err; } /* From wolfcrypt misc.c */ @@ -683,8 +683,8 @@ esp_check_icv_hmac(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, * Returns 0 on success. * Returns -1 on error. * */ -static int esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, - uint32_t * frame_len) +static int +esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t * frame_len) { uint8_t spi[ESP_SPI_LEN]; uint32_t seq = 0; @@ -871,7 +871,8 @@ static int esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, * Returns 0 on success. * Returns -1 on error. * */ -static int esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) +static int +esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) { uint8_t block_len = 0; uint16_t orig_ip_len = *ip_len; @@ -1064,9 +1065,9 @@ static int esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) * Copy frame to new packet so we can expand and wrap in place * without stepping on the fifo tcp circular buffer. * */ -static int esp_output(struct wolfIP_ll_dev * ll_dev, - const struct wolfIP_ip_packet *ip, - uint16_t len) +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. diff --git a/src/wolfip.c b/src/wolfip.c index d995123..30f7f90 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -778,7 +778,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); @@ -1125,7 +1125,8 @@ static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, #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) @@ -1632,7 +1633,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 @@ -1895,7 +1897,8 @@ static void tcp_input(struct wolfIP *S, unsigned int if_idx, } 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); } @@ -1994,7 +1997,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; @@ -2884,11 +2888,13 @@ 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 = opt->data[0] | (opt->data[1] << 8) | + (opt->data[2] << 16) | (opt->data[3] << 24); 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 = opt->data[0] | (opt->data[1] << 8) | + (opt->data[2] << 16) | (opt->data[3] << 24); } opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); @@ -2923,7 +2929,8 @@ 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 = opt->data[0] | (opt->data[1] << 8) | + (opt->data[2] << 16) | (opt->data[3] << 24); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); @@ -2957,7 +2964,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)) @@ -3129,7 +3137,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; } @@ -3266,7 +3275,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)); } @@ -3935,6 +3945,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 = 0; @@ -3992,7 +4005,7 @@ int wolfIP_poll(struct wolfIP *s, uint64_t now) struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); if (ll && ll->send) { #ifdef WOLFIP_ESP - esp_output(ll, (struct wolfIP_ip_packet *)tcp, size); + esp_tcp_output(ll, (struct wolfIP_ip_packet *)tcp, size); #else ll->send(ll, tcp, desc->len); #endif /* WOLFIP_ESP */ @@ -4021,6 +4034,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); diff --git a/wolfip.h b/wolfip.h index 407ace5..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); From 5beb5bd69c67fe6b133523ac9b75d53b1e346389 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 3 Feb 2026 11:39:56 -0600 Subject: [PATCH 14/16] DHCP_OPT_TO_U32 macro. --- src/wolfip.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/wolfip.c b/src/wolfip.c index 30f7f90..3bc8161 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2876,6 +2876,10 @@ static void dhcp_cancel_timer(struct wolfIP *s) } } +#define DHCP_OPT_TO_U32(opt) \ + (opt)->data[0] | ((opt)->data[1] << 8) | \ + ((opt)->data[2] << 16) | ((opt)->data[3] << 24); + static int dhcp_parse_offer(struct wolfIP *s, struct dhcp_msg *msg) { struct dhcp_option *opt = (struct dhcp_option *)(msg->options); @@ -2888,13 +2892,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_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_TO_U32(opt); } opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); @@ -2929,8 +2931,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_TO_U32(opt); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); From ddbfd06c492a79ab8a4bb5c9705564374dbb6cf7 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 3 Feb 2026 12:40:31 -0600 Subject: [PATCH 15/16] DHCP macro cleanup. --- src/wolfesp.c | 11 ++++++----- src/wolfip.c | 39 ++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index d259a56..411c9f5 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -659,7 +659,7 @@ esp_check_icv_hmac(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, } /** - * Decapsulate an ipv4 ESP packet. The packet is + * 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 @@ -684,7 +684,8 @@ esp_check_icv_hmac(const struct wolfIP_esp_sa * esp_sa, uint8_t * esp_data, * Returns -1 on error. * */ static int -esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t * frame_len) +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; @@ -851,7 +852,7 @@ esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t * frame_len) } /** - * Encapsulate an ipv4 packet with ESP. + * Encapsulate an ipv4 packet with ESP transport mode. * * Transport Mode: * before: @@ -872,7 +873,7 @@ esp_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, uint32_t * frame_len) * Returns -1 on error. * */ static int -esp_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) +esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) { uint8_t block_len = 0; uint16_t orig_ip_len = *ip_len; @@ -1086,7 +1087,7 @@ esp_tcp_output(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, esp = (struct wolfIP_ip_packet *) frame; memcpy(esp, ip, sizeof(struct wolfIP_ip_packet) + len); - esp_rc = esp_wrap(esp, &ip_final_len); + esp_rc = esp_transport_wrap(esp, &ip_final_len); if (esp_rc) { #ifdef WOLFIP_DEBUG_ESP diff --git a/src/wolfip.c b/src/wolfip.c index 3bc8161..9d6200e 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2876,10 +2876,18 @@ static void dhcp_cancel_timer(struct wolfIP *s) } } -#define DHCP_OPT_TO_U32(opt) \ - (opt)->data[0] | ((opt)->data[1] << 8) | \ +#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); @@ -2892,11 +2900,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 = DHCP_OPT_TO_U32(opt); + uint32_t data = DHCP_OPT_data_to_u32(opt); s->dhcp_server_ip = ee32(data); } if (opt->code == DHCP_OPTION_SUBNET_MASK) { - netmask = DHCP_OPT_TO_U32(opt); + netmask = DHCP_OPT_data_to_u32(opt); } opt = (struct dhcp_option *)((uint8_t *)opt + 2 + opt->len); @@ -2931,7 +2939,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 = DHCP_OPT_TO_U32(opt); + data = DHCP_OPT_data_to_u32(opt); while (opt->code != 0xFF) { if (opt->code == DHCP_OPTION_SERVER_ID) s->dhcp_server_ip = ee32(data); @@ -3024,18 +3032,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++; @@ -3475,17 +3477,20 @@ static inline void ip_recv(struct wolfIP *s, unsigned int if_idx, } } } -#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 esp_rc = 0; - esp_rc = esp_unwrap(s, ip, &len); - if (esp_rc) { + int err = 0; + err = esp_transport_unwrap(s, ip, &len); + if (err) { printf("info: failed to unwrap esp packet, dropping.\n"); return; } From af886890bbedd21e1422e7878df808c21e91831a Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 3 Feb 2026 13:58:18 -0600 Subject: [PATCH 16/16] wolfesp: remove dead debug code. --- src/wolfesp.c | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index 411c9f5..400a6ac 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -50,25 +50,6 @@ wolfIP_esp_load_sa_list(struct wolfIP_esp_sa * sa_list, uint16_t num, int in) } #ifdef WOLFIP_DEBUG_ESP - #ifdef WOLFIP_DEBUG_ESP_VERBOSE - static void - esp_dump_data_verbose(const char * what, const uint8_t * data, - size_t data_len) - { - printf("info: %s: \n", what); - - for (size_t i = 0; i < data_len; ++i) { - printf("%02x", data[i]); - if (i && ((i + 1) % 8) == 0) { - printf("\n"); - } - } - - printf("\n"); - return; - } - #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ - static void esp_dump_data(const char * what, const uint8_t * data, size_t data_len) { @@ -818,10 +799,6 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, wolfIP_print_esp(esp_sa, ip->data, esp_len, pad_len, nxt_hdr); #endif /* WOLFIP_DEBUG_ESP */ - #ifdef WOLFIP_DEBUG_ESP_VERBOSE - esp_dump_data_verbose("esp_packet before unwrap", ip->data, esp_len); - #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ - /* move ip payload forward to hide ESP header (SPI, SEQ, IV). */ memmove(ip->data, ip->data + ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->iv_len, esp_len - (ESP_SPI_LEN + ESP_SEQ_LEN + esp_sa->iv_len)); @@ -842,11 +819,6 @@ esp_transport_unwrap(struct wolfIP *s, struct wolfIP_ip_packet *ip, ip->csum = 0; iphdr_set_checksum(ip); - #ifdef WOLFIP_DEBUG_ESP_VERBOSE - esp_dump_data_verbose("esp_packet after unwrap", ip->data, - *frame_len - ETH_HEADER_LEN - IP_HEADER_LEN); - #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ - (void)s; return 0; } @@ -909,10 +881,6 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) return 0; } - #ifdef WOLFIP_DEBUG_ESP_VERBOSE - esp_dump_data_verbose("ip packet before wrap", ip->data, orig_payload_len); - #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ - #if 0 /* return early, do nothing. */ return 0; @@ -1055,10 +1023,6 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) wolfIP_print_esp(esp_sa, ip->data, payload_len, pad_len, ip->proto); #endif /* WOLFIP_DEBUG_ESP */ - #ifdef WOLFIP_DEBUG_ESP_VERBOSE - esp_dump_data_verbose("ip packet after wrap", ip->data, payload_len); - #endif /* WOLFIP_DEBUG_ESP_VERBOSE */ - return 0; }