Skip to content

Commit 07f0d67

Browse files
committed
- support for wolfguard (fips on and off);
- unit-wolfguard and test-wolfguard; - updated documentation; - workflow (non-fips); - minor edits to the esp source and unit tests to be FIPS compliant when running against a wolfssl built in FIPS mode;
1 parent 079235f commit 07f0d67

10 files changed

Lines changed: 2128 additions & 1 deletion

File tree

.github/workflows/wolfguard.yml

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
name: wolfguard tests (non-FIPS)
2+
3+
on:
4+
push:
5+
branches: [ 'master', 'main', 'release/**' ]
6+
pull_request:
7+
branches: [ '*' ]
8+
9+
jobs:
10+
wolfguard:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 30
13+
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Install dependencies
18+
run: |
19+
sudo apt-get update
20+
sudo apt-get install -y \
21+
build-essential autoconf libtool \
22+
linux-headers-$(uname -r) \
23+
iproute2 check \
24+
gawk kmod
25+
26+
- name: Clone wolfSSL and wolfguard sources
27+
run: |
28+
mkdir -p wolf-sources
29+
# nightly-snapshot is the branch required by wolfguard for its latest
30+
# kernel-module API. Pin to a tagged release once wolfguard stabilises.
31+
git clone --depth=1 https://github.com/wolfssl/wolfssl \
32+
--branch nightly-snapshot wolf-sources/wolfssl
33+
git clone --depth=1 https://github.com/wolfssl/wolfguard \
34+
wolf-sources/wolfguard
35+
36+
- name: Build and install wolfssl user library
37+
working-directory: wolf-sources/wolfssl
38+
run: |
39+
./autogen.sh
40+
./configure --quiet --enable-wolfguard --enable-all-asm
41+
make -j$(nproc)
42+
sudo make install
43+
sudo ldconfig
44+
45+
- name: Build and install wg-fips user tool
46+
run: |
47+
make -j$(nproc) -C wolf-sources/wolfguard/user-src
48+
sudo make -C wolf-sources/wolfguard/user-src install
49+
50+
- name: Build and install libwolfssl.ko (non-FIPS)
51+
working-directory: wolf-sources/wolfssl
52+
run: |
53+
make distclean
54+
./configure --quiet --enable-wolfguard --enable-cryptonly \
55+
--enable-intelasm --enable-linuxkm \
56+
--with-linux-source=/lib/modules/$(uname -r)/build \
57+
--prefix=$(pwd)/linuxkm/build
58+
make -j$(nproc) module
59+
sudo make install
60+
61+
- name: Build wolfguard.ko
62+
working-directory: wolf-sources/wolfguard/kernel-src
63+
run: |
64+
make -j$(nproc) \
65+
KERNELDIR=/lib/modules/$(uname -r)/build \
66+
KERNELRELEASE=$(uname -r) \
67+
EXTRA_CFLAGS="-I$(realpath ../../wolfssl)"
68+
69+
- name: Load kernel modules
70+
run: |
71+
sudo insmod /lib/modules/$(uname -r)/wolfssl/libwolfssl.ko
72+
sudo insmod wolf-sources/wolfguard/kernel-src/wolfguard.ko
73+
74+
- name: Build wolfguard unit tests
75+
run: make unit-wolfguard
76+
77+
- name: Run wolfguard unit tests
78+
timeout-minutes: 5
79+
run: |
80+
set -euo pipefail
81+
timeout --preserve-status 5m ./build/test/unit-wolfguard
82+
83+
- name: Build wolfguard functional test
84+
run: make build/test-wolfguard
85+
86+
- name: Run wolfguard functional test
87+
timeout-minutes: 5
88+
run: |
89+
set -euo pipefail
90+
timeout --preserve-status 5m sudo ./build/test-wolfguard
91+
92+
- name: Unload kernel modules
93+
if: always()
94+
run: |
95+
sudo rmmod wolfguard || true
96+
sudo rmmod libwolfssl || true

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ tags
1717
cppcheck_results.xml
1818
src/port/stm32h563/app.elf
1919
src/port/va416xx/app.elf
20+
wolf-sources/

Makefile

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,12 @@ leaksan:LDFLAGS+=-fsanitize=leak
199199
ESP_CFLAGS = \
200200
-DWOLFIP_ESP -DWOLFSSL_WOLFIP
201201

202+
WOLFGUARD_CFLAGS = -DWOLFIP_WOLFGUARD
203+
204+
WG_OBJ = build/wolfguard/wolfip.o \
205+
build/wolfguard/wolfip_wolfguard.o \
206+
$(TAP_OBJ)
207+
202208
# Test
203209

204210
ifeq ($(CHECK_PKG_LIBS),)
@@ -255,6 +261,53 @@ build/ipfilter/wolfip.o: src/wolfip.c
255261

256262
build/test/ipfilter_logger.o: CFLAGS+=-DCONFIG_IPFILTER=1
257263

264+
# wolfguard
265+
build/wolfguard/wolfip.o: src/wolfip.c
266+
@mkdir -p `dirname $@` || true
267+
@echo "[CC] $< (wolfguard)"
268+
@$(CC) $(CFLAGS) $(WOLFGUARD_CFLAGS) -c $< -o $@
269+
270+
build/wolfguard/wolfip_wolfguard.o: src/wolfip_wolfguard.c
271+
@mkdir -p `dirname $@` || true
272+
@echo "[CC] $< (wolfguard)"
273+
@$(CC) $(CFLAGS) $(WOLFGUARD_CFLAGS) -c $< -o $@
274+
275+
build/test/wolfguard/test_wolfguard.o: src/test/wolfguard/test_wolfguard.c
276+
@mkdir -p `dirname $@` || true
277+
@echo "[CC] $@"
278+
@$(CC) $(CFLAGS) $(WOLFGUARD_CFLAGS) -c $< -o $@
279+
280+
build/test-wolfguard: $(WG_OBJ) build/test/wolfguard/test_wolfguard.o
281+
@echo "[LD] $@"
282+
@$(CC) $(CFLAGS) $(WOLFGUARD_CFLAGS) $(LDFLAGS) -o $@ \
283+
$(BEGIN_GROUP) $(^) $(END_GROUP) -lwolfssl
284+
285+
unit-wolfguard: build/test/unit-wolfguard
286+
287+
build/test/unit-wolfguard: src/test/unit/unit_wolfguard.c
288+
@mkdir -p build/test/
289+
@echo "[CC] unit_wolfguard.c"
290+
@$(CC) $(CFLAGS) $(WOLFGUARD_CFLAGS) $(UNIT_CFLAGS) \
291+
-c src/test/unit/unit_wolfguard.c -o build/test/unit_wolfguard.o
292+
@echo "[LD] $@"
293+
@$(CC) build/test/unit_wolfguard.o -o $@ \
294+
$(UNIT_LDFLAGS) $(LDFLAGS) $(UNIT_LIBS)
295+
296+
clean-unit-wolfguard:
297+
@rm -f build/test/unit-wolfguard build/test/unit_wolfguard.o
298+
299+
unit-wolfguard-asan: CFLAGS+=-fsanitize=address
300+
unit-wolfguard-asan: LDFLAGS+=-fsanitize=address $(UNIT_LIBS)
301+
unit-wolfguard-asan: clean-unit-wolfguard build/test/unit-wolfguard
302+
303+
unit-wolfguard-ubsan: CFLAGS+=-fsanitize=undefined -fno-sanitize-recover=all
304+
unit-wolfguard-ubsan: LDFLAGS+=-fsanitize=undefined $(UNIT_LIBS)
305+
unit-wolfguard-ubsan: clean-unit-wolfguard build/test/unit-wolfguard
306+
307+
unit-wolfguard-leaksan: CFLAGS+=-fsanitize=leak
308+
unit-wolfguard-leaksan: LDFLAGS+=-fsanitize=leak $(UNIT_LIBS)
309+
unit-wolfguard-leaksan: clean-unit-wolfguard build/test/unit-wolfguard
310+
258311
# ipsec esp
259312
build/esp/wolfip.o: src/wolfip.c
260313
@mkdir -p `dirname $@` || true
@@ -438,7 +491,8 @@ install:
438491
ldconfig
439492

440493
.PHONY: clean all static cppcheck cov autocov unit-asan unit-ubsan unit-leaksan clean-unit \
441-
unit-esp-asan unit-esp-ubsan unit-esp-leaksan clean-unit-esp
494+
unit-esp-asan unit-esp-ubsan unit-esp-leaksan clean-unit-esp \
495+
unit-wolfguard unit-wolfguard-asan unit-wolfguard-ubsan unit-wolfguard-leaksan clean-unit-wolfguard
442496

443497
cppcheck:
444498
$(CPPCHECK) $(CPPCHECK_FLAGS) src/ 2>cppcheck_results.xml

README.md

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ A single network interface can be associated with the device.
2828
| **Network** | IPv4 Forwarding | Multi-interface routing (optional) | [RFC 1812](https://datatracker.ietf.org/doc/html/rfc1812) |
2929
| **Network** | ICMP | Echo request/reply, TTL exceeded | [RFC 792](https://datatracker.ietf.org/doc/html/rfc792) |
3030
| **Network** | IPsec | ESP Transport mode | [RFC 4303](https://datatracker.ietf.org/doc/html/rfc4303) |
31+
| **Network** | WolfGuard | VPN tunnel via wolfguard kernel module (SECP256R1, AES-256-GCM, SHA-256) | See `wolf-sources/wolfssl/wolfguard/README.md` |
3132
| **Transport** | UDP | Unicast datagrams, checksum | [RFC 768](https://datatracker.ietf.org/doc/html/rfc768) |
3233
| **Transport** | TCP | Connection management, reliable delivery | [RFC 793](https://datatracker.ietf.org/doc/html/rfc793), [RFC 9293](https://datatracker.ietf.org/doc/html/rfc9293) |
3334
| **Transport** | TCP | Maximum Segment Size negotiation | [RFC 793](https://datatracker.ietf.org/doc/html/rfc793) |
@@ -69,6 +70,92 @@ The `-I wtcp0` flag pins the test to the injected interface and `-c5`
6970
generates five echo requests. Successful replies confirm the ICMP
7071
datagram socket support end-to-end through the tap device.
7172

73+
## WolfGuard support
74+
75+
wolfIP can use [WolfGuard](wolf-sources/wolfssl/wolfguard/README.md) as its
76+
link-layer driver, giving every socket opened on the stack transparent
77+
WireGuard-compatible encryption without any changes to application code.
78+
79+
### How it works
80+
81+
WolfGuard is a kernel module (`wolfguard.ko`) that registers a standard Linux
82+
network interface (`ARPHRD_NONE`, identical in structure to the upstream
83+
WireGuard driver) and performs the handshake and encryption inside the kernel
84+
using wolfSSL's FIPS-ready primitives (SECP256R1, AES-256-GCM, SHA-256).
85+
86+
`wolfip_wolfguard.c` is a wolfIP ll_dev driver that bridges the two:
87+
88+
1. Creates the wolfguard interface via Netlink (`RTM_NEWLINK type=wolfguard`).
89+
2. Configures keys and peers via the wolfguard Generic Netlink family
90+
(`WG_CMD_SET_DEVICE`).
91+
3. Connects to the interface with an `AF_PACKET/SOCK_DGRAM` socket, injecting
92+
and receiving raw IP packets that the kernel module encrypts/decrypts
93+
transparently.
94+
4. Provides a synthetic ARP proxy so wolfIP's Ethernet layer can resolve peer
95+
IPs without kernel ARP involvement.
96+
97+
### Prerequisites
98+
99+
Build and load the wolfguard kernel module and its wolfSSL dependency by
100+
following the instructions in
101+
[wolf-sources/wolfssl/wolfguard/README.md](wolf-sources/wolfssl/wolfguard/README.md).
102+
Then load the modules before running any wolfguard-enabled binary:
103+
104+
```sh
105+
insmod /lib/modules/$(uname -r)/wolfssl/libwolfssl.ko
106+
insmod /path/to/wolfguard.ko
107+
modprobe udp_tunnel
108+
modprobe ip6_udp_tunnel
109+
```
110+
111+
### Enabling wolfguard support
112+
113+
Add `-DWOLFIP_WOLFGUARD` to your `CFLAGS` and link `wolfip_wolfguard.c` into
114+
your build. In the wolfIP Makefile the dedicated targets handle this
115+
automatically:
116+
117+
```sh
118+
make unit-wolfguard # driver unit tests (no kernel module required)
119+
make build/test-wolfguard # functional test binary
120+
```
121+
122+
To integrate into your own application, call `wolfIP_wg_init()` in place of
123+
`tap_init()`:
124+
125+
```c
126+
#include "wolfip_wolfguard.h"
127+
128+
struct wolfIP_wg_config cfg = { ... }; /* keys, peers, listen port */
129+
struct wolfIP *stack;
130+
131+
wolfIP_init_static(&stack);
132+
wolfIP_wg_init(&cfg, wolfIP_getdev(stack));
133+
wolfIP_ipconfig_set(stack, atoip4("10.8.0.1"), atoip4("255.255.255.0"),
134+
atoip4("10.8.0.1"));
135+
/* use wolfIP sockets normally — all traffic is encrypted by wolfguard */
136+
```
137+
138+
### Running the tests
139+
140+
**Unit tests** exercise the driver logic (ARP proxy, L2/L3 bridging) entirely
141+
in userspace with a mock pipe — no kernel module required:
142+
143+
```sh
144+
make unit-wolfguard
145+
./build/test/unit-wolfguard
146+
```
147+
148+
**Functional test** performs a full loopback: wolfIP sends a UDP packet,
149+
wolfguard encrypts it, a kernel-side peer decrypts and echoes it back, and
150+
wolfIP verifies the payload. Requires the kernel modules to be loaded,
151+
`wg-fips` in `PATH`, and root (or `NET_ADMIN` capability) to create network
152+
interfaces:
153+
154+
```sh
155+
make build/test-wolfguard
156+
sudo ./build/test-wolfguard
157+
```
158+
72159
## FreeRTOS Port
73160

74161
wolfIP now includes a dedicated FreeRTOS wrapper port at:

src/test/unit/unit_esp.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,7 @@ START_TEST(test_unwrap_pad_too_big)
674674
}
675675
END_TEST
676676

677+
677678
/*
678679
* full enc/dec round-trips
679680
* */
@@ -771,6 +772,7 @@ START_TEST(test_roundtrip_aes128_cbc_sha1)
771772
}
772773
END_TEST
773774

775+
#ifndef HAVE_FIPS
774776
START_TEST(test_roundtrip_aes128_cbc_md5)
775777
{
776778
do_roundtrip_cbc_hmac(k_aes128, sizeof(k_aes128),
@@ -779,6 +781,7 @@ START_TEST(test_roundtrip_aes128_cbc_md5)
779781
ESP_ICVLEN_HMAC_96);
780782
}
781783
END_TEST
784+
#endif
782785

783786
START_TEST(test_roundtrip_aes256_cbc_sha256_128)
784787
{
@@ -1140,7 +1143,10 @@ static Suite *esp_suite(void)
11401143
tcase_add_test(tc, test_roundtrip_aes128_cbc_sha256_128);
11411144
tcase_add_test(tc, test_roundtrip_aes128_cbc_sha256_96);
11421145
tcase_add_test(tc, test_roundtrip_aes128_cbc_sha1);
1146+
/* run this test only if the build is not in FIPS mode, since md5 is not approved. */
1147+
#ifndef HAVE_FIPS
11431148
tcase_add_test(tc, test_roundtrip_aes128_cbc_md5);
1149+
#endif
11441150
tcase_add_test(tc, test_roundtrip_aes256_cbc_sha256_128);
11451151
#ifndef NO_DES3
11461152
tcase_add_test(tc, test_roundtrip_des3_sha256);

0 commit comments

Comments
 (0)