From 3f15804691a4f8c3c7056994517fdfb3b505f267 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 29 Sep 2026 12:34:09 -0500 Subject: [PATCH 1/4] esp: esp_print_field, fix short fields. --- src/wolfesp.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index bd16ed6b..f49c58a7 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -532,7 +532,7 @@ esp_iv_len_from_enc(esp_enc_t enc) #ifdef DEBUG_ESP #define esp_print_sep \ - LOG("+------------------+\n") + ESP_LOG("+------------------+\n") #define esp_str_4hex \ "| %02x %02x %02x %02x |" #define esp_str_skip \ @@ -540,24 +540,36 @@ esp_iv_len_from_enc(esp_enc_t enc) #define esp_pad_fld \ "| %02x%02x | %02d | 0x%02x |" +/* Prints an esp packet field (spi, seq, iv, payload, etc). + * The majority of these are minimum 4 bytes, or 4 byte multiple. + * */ static inline void esp_print_field(const char * fld, const uint8_t * val, uint32_t val_len) { esp_print_sep; - LOG(esp_str_4hex " (%s, %d bytes)\n", - val[0], val[1], val[2], val[3], fld, val_len); - if (val_len > 4) { - for (size_t i = 4; i < val_len; i += 4) { - if (i > 16 || (i + 4) > val_len) { - LOG(esp_str_skip "\n"); - break; - } + if (val_len < 4) { + /* short field */ + ESP_LOG(esp_str_skip " (%s, %d bytes)\n", fld, val_len); + } + else { + /* print first 4 bytes, and subsequent full multiples of 4. */ + ESP_LOG(esp_str_4hex " (%s, %d bytes)\n", + val[0], val[1], val[2], val[3], fld, val_len); + if (val_len > 4) { + for (size_t i = 4; i < val_len; i += 4) { + if (i > 16 || (i + 4) > val_len) { + /* short remainder */ + ESP_LOG(esp_str_skip "\n"); + break; + } - LOG(esp_str_4hex"\n", - val[0 + i], val[1 + i], val[2 + i], val[3 + i]); + ESP_LOG(esp_str_4hex"\n", + val[0 + i], val[1 + i], val[2 + i], val[3 + i]); + } } } + return; } @@ -599,7 +611,7 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, /* last 2 bytes of padding */ padding = esp_data + esp_len - esp_sa->icv_len - 4; - LOG("esp packet: (%d bytes)\n", esp_len); + ESP_LOG("esp packet: (%d bytes)\n", esp_len); /** ESP header * ______________ @@ -623,8 +635,8 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, * | (variable length) | Length | Header | * ------------------------------------- */ esp_print_sep; - LOG(esp_pad_fld " (padding last 2 bytes, pad len, nxt hdr)\n", - padding[0], padding[1], pad_len, nxt_hdr); + ESP_LOG(esp_pad_fld " (padding last 2 bytes, pad len, nxt hdr)\n", + padding[0], padding[1], pad_len, nxt_hdr); if (icv) { esp_print_field("icv", icv, esp_sa->icv_len); From f39c9adca7e9d6e2fdd059c202b3f71c54f49f10 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 29 Sep 2026 12:56:59 -0500 Subject: [PATCH 2/4] esp: esp_transport_wrap, defer esp_state_save until success. --- src/wolfesp.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index f49c58a7..1c1ff30d 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -1701,6 +1701,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) uint16_t icv_offset = 0; wolfIP_esp_sa * esp_sa = NULL; uint8_t iv_len = 0; + uint32_t oseq = 0; if (ip_hdr_len < IP_HEADER_LEN || orig_ip_len < ip_hdr_len) { ESP_LOG("error: ip_len below header: %u\n", orig_ip_len); @@ -1756,14 +1757,15 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) memcpy(payload, esp_sa->spi, sizeof(esp_sa->spi)); payload += ESP_SPI_LEN; - esp_sa->replay.oseq++; - if (esp_sa->replay.oseq == 0) { - esp_sa->replay.oseq--; + oseq = esp_sa->replay.oseq; + oseq++; + + if (oseq == 0) { ESP_LOG("error: oseq overflow\n"); return -1; } - esp_state_save(esp_sa); - seq_n = ee32(esp_sa->replay.oseq); + + seq_n = ee32(oseq); memcpy(payload, &seq_n, sizeof(seq_n)); payload += ESP_SEQ_LEN; @@ -1912,6 +1914,10 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) wolfIP_print_esp(esp_sa, esp_base, payload_len, pad_len, ip->proto); #endif /* DEBUG_ESP */ + /* finally, commit the esp state */ + esp_sa->replay.oseq = oseq; + esp_state_save(esp_sa); + /* update len, set proto to ESP 0x32 (50), recalculate iphdr checksum. */ ip->len = ee16(*ip_len); ip->proto = 0x32; From 389b5ab86155061d1c6567602a59051b71b468c8 Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 29 Sep 2026 21:48:26 -0500 Subject: [PATCH 3/4] esp: handle esp_send err. --- src/wolfesp.c | 6 +-- src/wolfip.c | 136 ++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 112 insertions(+), 30 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index 1c1ff30d..1cc4fe9b 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -550,11 +550,11 @@ esp_print_field(const char * fld, const uint8_t * val, esp_print_sep; if (val_len < 4) { /* short field */ - ESP_LOG(esp_str_skip " (%s, %d bytes)\n", fld, val_len); + ESP_LOG(esp_str_skip " (%s, %u bytes)\n", fld, val_len); } else { /* print first 4 bytes, and subsequent full multiples of 4. */ - ESP_LOG(esp_str_4hex " (%s, %d bytes)\n", + ESP_LOG(esp_str_4hex " (%s, %u bytes)\n", val[0], val[1], val[2], val[3], fld, val_len); if (val_len > 4) { for (size_t i = 4; i < val_len; i += 4) { @@ -611,7 +611,7 @@ static void wolfIP_print_esp(const wolfIP_esp_sa * esp_sa, /* last 2 bytes of padding */ padding = esp_data + esp_len - esp_sa->icv_len - 4; - ESP_LOG("esp packet: (%d bytes)\n", esp_len); + ESP_LOG("esp packet: (%u bytes)\n", esp_len); /** ESP header * ______________ diff --git a/src/wolfip.c b/src/wolfip.c index d0ebf728..201b0ed5 100644 --- a/src/wolfip.c +++ b/src/wolfip.c @@ -2416,8 +2416,16 @@ static void wolfIP_send_ttl_exceeded(struct wolfIP *s, unsigned int if_idx, } #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(s, if_idx)) { - if (esp_send(ll, &icmp.ip, (uint16_t)(frame_len - ETH_HEADER_LEN)) == 1) { + int esp_err = esp_send(ll, &icmp.ip, + (uint16_t)(frame_len - ETH_HEADER_LEN)); + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); @@ -2530,14 +2538,21 @@ static void wolfIP_send_param_problem(struct wolfIP *s, unsigned int if_idx, #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(s, if_idx)) { struct wolfIP_ll_dev *esp_ll = ll; -#if WOLFIP_VLAN + #if WOLFIP_VLAN /* A VLAN sub-iface has no send function of its own; esp_send needs * the physical device's send path. */ if (ll->vlan_active && ll->vlan_parent) esp_ll = ll->vlan_parent; -#endif - if (esp_send(esp_ll, &icmp.ip, (uint16_t)(frame_len - ETH_HEADER_LEN)) == 1) { + #endif + int esp_err = esp_send(esp_ll, &icmp.ip, + (uint16_t)(frame_len - ETH_HEADER_LEN)); + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); @@ -2659,14 +2674,23 @@ static void wolfIP_send_frag_needed(struct wolfIP *s, unsigned int in_if, #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(s, in_if)) { struct wolfIP_ll_dev *esp_ll = ll; -#if WOLFIP_VLAN + int esp_err = 0; + #if WOLFIP_VLAN /* A VLAN sub-iface has no send function of its own; esp_send needs * the physical device's send path. */ if (ll->vlan_active && ll->vlan_parent) esp_ll = ll->vlan_parent; -#endif - if (esp_send(esp_ll, &icmp.ip, (uint16_t)(frame_len - ETH_HEADER_LEN)) == 1) { + #endif + esp_err = esp_send(esp_ll, &icmp.ip, + (uint16_t)(frame_len - ETH_HEADER_LEN)); + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, in_if, &icmp, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, in_if, &icmp, frame_len); @@ -2763,8 +2787,15 @@ static void wolfIP_send_port_unreachable(struct wolfIP *s, unsigned int if_idx, } #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(s, if_idx)) { - if (esp_send(ll, &icmp.ip, (uint16_t)(frame_len - ETH_HEADER_LEN)) == 1) { + int esp_err = esp_send(ll, &icmp.ip, + (uint16_t)(frame_len - ETH_HEADER_LEN)); + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, if_idx, &icmp, frame_len); @@ -4018,10 +4049,16 @@ static int tcp_send_empty_immediate(struct tsocket *t, struct wolfIP_tcp_seg *tc #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(t->S, tx_if)) { struct wolfIP_ll_dev *ll_esp = wolfIP_ll_at(t->S, tx_if); - int esp_err = esp_send(ll_esp, (struct wolfIP_ip_packet *)tcp, - (uint16_t)(frame_len - ETH_HEADER_LEN)); - if (esp_err == 1) { + send_ret = esp_send(ll_esp, (struct wolfIP_ip_packet *)tcp, + (uint16_t)(frame_len - ETH_HEADER_LEN)); + + switch (send_ret) { + case 1: /* send plaintext */ send_ret = wolfIP_ll_send_frame(t->S, tx_if, tcp, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", send_ret); } } else { send_ret = wolfIP_ll_send_frame(t->S, tx_if, tcp, frame_len); @@ -4227,9 +4264,15 @@ static void tcp_send_reset_reply(struct wolfIP *s, unsigned int if_idx, if (!wolfIP_ll_is_non_ethernet(s, if_idx)) { struct wolfIP_ll_dev *ll_esp = wolfIP_ll_at(s, if_idx); int esp_err = esp_send(ll_esp, &out->ip, - (uint16_t)(out_len - ETH_HEADER_LEN)); - if (esp_err == 1) { + (uint16_t)(out_len - ETH_HEADER_LEN)); + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, if_idx, &out->ip, out_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, if_idx, &out->ip, out_len); @@ -4810,9 +4853,16 @@ static int tcp_send_zero_wnd_probe(struct tsocket *t) if (!wolfIP_ll_is_non_ethernet(t->S, tx_if)) { struct wolfIP_ll_dev *ll_esp = wolfIP_ll_at(t->S, tx_if); int esp_err = esp_send(ll_esp, (struct wolfIP_ip_packet *)probe, - (uint16_t)(frame_len - ETH_HEADER_LEN)); - if (esp_err == 1) { + (uint16_t)(frame_len - ETH_HEADER_LEN)); + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(t->S, tx_if, probe, frame_len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); + return -1; } } else { wolfIP_ll_send_frame(t->S, tx_if, probe, frame_len); @@ -5094,9 +5144,17 @@ static int igmp_send_report(struct wolfIP *s, unsigned int if_idx, ip4 group, * is configured for 224.0.0.22 so the normal path is unchanged. */ if (!wolfIP_ll_is_non_ethernet(s, if_idx)) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); - if (esp_send(ll, ip, ip_len) == 1) + int esp_err = esp_send(ll, ip, ip_len); + + switch (esp_err) { + case 1: /* send plaintext */ return wolfIP_ll_send_frame(s, if_idx, frame, sizeof(frame)); - return 0; + case 0: /* success */ + return 0; + default: /* error */ + LOG("esp_send: %d\n", esp_err); + return -1; + } } #endif return wolfIP_ll_send_frame(s, if_idx, frame, sizeof(frame)); @@ -5356,8 +5414,14 @@ static void wolfIP_forward_packet(struct wolfIP *s, unsigned int out_if, /* Encapsulate the datagram at its declared length; bytes past * the IP total length are L2 padding, not payload. */ int esp_err = esp_send(ll_esp, ip, (uint16_t)ee16(ip->len)); - if (esp_err == 1) { + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, out_if, ip, len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, out_if, ip, len); @@ -9393,10 +9457,15 @@ static void icmp_input(struct wolfIP *s, unsigned int if_idx, struct wolfIP_ip_p struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, if_idx); /* Encapsulate the datagram at its declared length; bytes past * the IP total length are L2 padding, not payload. */ - if (esp_send(ll, ip, (uint16_t)ee16(ip->len)) == 1) { - /* ipsec not configured on this interface. - * send plaintext. */ + int esp_err = esp_send(ll, ip, (uint16_t)ee16(ip->len)); + + switch (esp_err) { + case 1: /* send plaintext */ wolfIP_ll_send_frame(s, if_idx, ip, len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", esp_err); } } else { wolfIP_ll_send_frame(s, if_idx, ip, len); @@ -12775,11 +12844,17 @@ static void flush_tcp_tx(struct wolfIP *s, uint64_t now) #ifdef WOLFIP_ESP if (!wolfIP_ll_is_non_ethernet(s, tx_if)) { struct wolfIP_ll_dev *ll = wolfIP_ll_at(s, tx_if); - int esp_err = esp_send(ll, (struct wolfIP_ip_packet *)tcp, size); - if (esp_err == 1) { - /* ipsec not configured on this interface. - * send plaintext. */ - send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); + send_ret = esp_send(ll, (struct wolfIP_ip_packet *)tcp, + size); + + switch (send_ret) { + case 1: /* send plaintext */ + send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, + desc->len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", send_ret); } } else { send_ret = wolfIP_ll_send_frame(s, tx_if, tcp, desc->len); @@ -12953,8 +13028,15 @@ static void flush_datagram_tx(struct wolfIP *s, struct tsocket *socks, /* IPsec not configured on this interface. * Send plaintext instead. * */ - if (esp_send(ll, ip, (uint16_t)(desc->len - ETH_HEADER_LEN)) == 1) + send_ret = esp_send(ll, ip, (uint16_t)(desc->len - ETH_HEADER_LEN)); + switch (send_ret) { + case 1: /* send plaintext */ send_ret = wolfIP_ll_send_frame(s, tx_if, ip, desc->len); + case 0: /* success */ + break; + default: /* error */ + LOG("esp_send: %d\n", send_ret); + } } else { send_ret = wolfIP_ll_send_frame(s, tx_if, ip, desc->len); } From b2d84cf222cd03ea485a698e939e18c449e0e93d Mon Sep 17 00:00:00 2001 From: jordan Date: Tue, 29 Sep 2026 22:26:12 -0500 Subject: [PATCH 4/4] esp: check len in esp_send. --- src/wolfesp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/wolfesp.c b/src/wolfesp.c index 1cc4fe9b..788c6739 100644 --- a/src/wolfesp.c +++ b/src/wolfesp.c @@ -1938,7 +1938,7 @@ esp_transport_wrap(struct wolfIP_ip_packet *ip, uint16_t * ip_len) * Returns -1 on error. * */ static int -esp_send(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, +esp_send(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet * ip, uint16_t len) { /** @@ -1955,8 +1955,17 @@ esp_send(struct wolfIP_ll_dev * ll_dev, const struct wolfIP_ip_packet *ip, uint16_t ip_final_len = len; int esp_rc = 0; - if (!ll_dev || ll_dev->non_ethernet) + if (!ll_dev || ll_dev->non_ethernet) { + ESP_DEBUG("info: esp_wrap: %s\n", !ll_dev ? + "no ll_dev" : "non-ether"); return 1; + } + + if ((size_t)(ETH_HEADER_LEN + len) > sizeof(frame)) { + ESP_LOG("error: esp_wrap: ip packet too large: %u > %zu\n", + ETH_HEADER_LEN + len, sizeof(frame)); + return -1; + } esp = (struct wolfIP_ip_packet *) frame; memcpy(esp, ip, ETH_HEADER_LEN + len);