Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,191 @@ WOLFGUARD_SRC := src/wolfguard/wolfguard.c \
src/wolfguard/wg_timers.c
WOLFGUARD_OBJ := $(patsubst src/%.c,build/wolfguard/%.o,$(WOLFGUARD_SRC))

# wolfSupplicant - per-feature build flags. Core (PSK + 4-way + EAP
# framing) is always built; the per-method modules below are gated.
#
# WOLFIP_ENABLE_EAP_TLS=1 WPA2-Enterprise EAP-TLS (default on)
# WOLFIP_ENABLE_PEAP_MSCHAPV2=1 WPA2-Enterprise PEAPv0/MSCHAPv2
# (default off - pulls in deprecated
# MD4 + DES; needs wolfSSL built with
# --enable-md4 --enable-des3)
# WOLFIP_ENABLE_SAE=1 WPA3-Personal SAE dragonfly
# (default on - needs WOLFSSL_PUBLIC_MP
# in the linked wolfSSL build for the
# mp_* / sp_* math ABI)
# WOLFIP_ENABLE_SAE_H2E=1 WPA3-SAE Hash-to-Element PWE
# (default on; requires WOLFIP_ENABLE_SAE.
# Off = legacy hunt-and-peck only.)
#
# WOLFSSL_PREFIX is optional. When set, the build links against that
# wolfSSL tree (-I, -L, -Wl,-rpath) instead of the system one.
WOLFIP_ENABLE_EAP_TLS ?= 1
WOLFIP_ENABLE_PEAP_MSCHAPV2 ?= 0
WOLFIP_ENABLE_SAE ?= 1
WOLFIP_ENABLE_SAE_H2E ?= 1

ifneq ($(WOLFSSL_PREFIX),)
WOLFSSL_CFLAGS := -I$(WOLFSSL_PREFIX)/include
WOLFSSL_LIBS := -L$(WOLFSSL_PREFIX)/lib -lwolfssl \
-Wl,-rpath,$(WOLFSSL_PREFIX)/lib
endif

# Core (always present). eap_tls.c is just EAP-TLS framing (L/M/S flag
# handling + reassembly buffers) - no wolfSSL TLS engine, so it stays
# in core for use by unit tests even when EAP-TLS is disabled.
SUPPLICANT_SRC := src/supplicant/wpa_crypto.c \
src/supplicant/eapol.c \
src/supplicant/rsn_ie.c \
src/supplicant/eap.c \
src/supplicant/eap_tls.c \
src/supplicant/supplicant.c

ifeq ($(WOLFIP_ENABLE_EAP_TLS),1)
SUPPLICANT_SRC += src/supplicant/eap_tls_engine.c
CFLAGS += -DWOLFIP_ENABLE_EAP_TLS=1
endif

ifeq ($(WOLFIP_ENABLE_PEAP_MSCHAPV2),1)
SUPPLICANT_SRC += src/supplicant/mschapv2.c \
src/supplicant/eap_peap.c
CFLAGS += -DWOLFIP_ENABLE_PEAP_MSCHAPV2=1
# PEAP/MSCHAPv2 transitively requires EAP-TLS for the outer TLS engine.
ifneq ($(WOLFIP_ENABLE_EAP_TLS),1)
$(error WOLFIP_ENABLE_PEAP_MSCHAPV2=1 requires WOLFIP_ENABLE_EAP_TLS=1)
endif
endif

ifeq ($(WOLFIP_ENABLE_SAE),1)
SUPPLICANT_SRC += src/supplicant/sae_crypto.c
CFLAGS += -DWOLFIP_ENABLE_SAE=1
ifeq ($(WOLFIP_ENABLE_SAE_H2E),1)
CFLAGS += -DWOLFIP_ENABLE_SAE_H2E=1
endif
else
ifeq ($(WOLFIP_ENABLE_SAE_H2E),1)
$(error WOLFIP_ENABLE_SAE_H2E=1 requires WOLFIP_ENABLE_SAE=1)
endif
endif

SUPPLICANT_OBJ := $(patsubst src/%.c,build/%.o,$(SUPPLICANT_SRC))

build/supplicant/%.o: src/supplicant/%.c
@mkdir -p `dirname $@` || true
@echo "[CC] $<"
@$(CC) $(CFLAGS) $(WOLFSSL_CFLAGS) $(NL80211_CFLAGS) -Isrc/supplicant -c $< -o $@

# WOLFSSL_LIBS / WOLFSSL_CFLAGS may already be set above when
# WOLFSSL_PREFIX is provided. Otherwise default to pkg-config detection
# and a plain -lwolfssl fallback.
ifeq ($(WOLFSSL_LIBS),)
WOLFSSL_LIBS:=$(shell pkg-config --libs wolfssl 2>/dev/null)
endif
ifeq ($(WOLFSSL_LIBS),)
WOLFSSL_LIBS:=-lwolfssl
endif
ifeq ($(WOLFSSL_CFLAGS),)
WOLFSSL_CFLAGS:=$(shell pkg-config --cflags wolfssl 2>/dev/null)
endif

build/test-wpa-crypto: $(SUPPLICANT_OBJ) build/supplicant/test_wpa_crypto.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

build/test-supplicant-4way: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_4way.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

build/test-eap-framing: $(SUPPLICANT_OBJ) build/supplicant/test_eap_framing.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

ifeq ($(WOLFIP_ENABLE_EAP_TLS),1)
build/test-eap-tls-engine: $(SUPPLICANT_OBJ) build/supplicant/test_eap_tls_engine.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)
endif

ifeq ($(WOLFIP_ENABLE_EAP_TLS),1)
build/test-supplicant-eap-tls: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_eap_tls.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

build/test-supplicant-hostapd: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_hostapd.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)
endif

build/test-supplicant-hostapd-psk: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_hostapd_psk.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

ifeq ($(WOLFIP_ENABLE_SAE),1)
build/test-sae-crypto: $(SUPPLICANT_OBJ) build/supplicant/test_sae_crypto.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

build/test-supplicant-sae: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_sae.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

# WPA3-SAE hostapd interop via mac80211_hwsim + nl80211 external auth.
build/test-supplicant-hostapd-sae: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_hostapd_sae.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(NL80211_LIBS) $(END_GROUP)

supplicant-hwsim-sae-test: build/test-supplicant-hostapd-sae
@sudo ./tools/hostapd/run_hwsim_sae_test.sh
endif

# MSCHAPv2 crypto-only test + full hostapd-PEAP interop. Only built
# when PEAP/MSCHAPv2 is enabled.
ifeq ($(WOLFIP_ENABLE_PEAP_MSCHAPV2),1)
build/test-mschapv2: build/supplicant/mschapv2.o build/supplicant/test_mschapv2.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

build/test-supplicant-hostapd-peap: $(SUPPLICANT_OBJ) build/supplicant/test_supplicant_hostapd_peap.o
@echo "[LD] $@"
@$(CC) $(CFLAGS) -o $@ $(BEGIN_GROUP) $(^) $(LDFLAGS) $(WOLFSSL_LIBS) $(END_GROUP)

supplicant-hostapd-peap-test: build/test-supplicant-hostapd-peap build/test-eap-tls-engine
@sudo MODE=peap ./tools/hostapd/run_hostapd_test.sh
endif

SUPPLICANT_TEST_BINS := build/test-wpa-crypto build/test-supplicant-4way \
build/test-eap-framing
ifeq ($(WOLFIP_ENABLE_EAP_TLS),1)
SUPPLICANT_TEST_BINS += build/test-eap-tls-engine build/test-supplicant-eap-tls
endif
ifeq ($(WOLFIP_ENABLE_SAE),1)
SUPPLICANT_TEST_BINS += build/test-sae-crypto build/test-supplicant-sae
endif

supplicant-tests: $(SUPPLICANT_TEST_BINS)
@for t in $(SUPPLICANT_TEST_BINS); do echo "==> $$t"; $$t || exit 1; done

# Real-authenticator interop tests. Both require hostapd installed and
# root (veth pair + AF_PACKET raw socket). Not part of supplicant-tests
# because of those constraints.
supplicant-hostapd-test: build/test-supplicant-hostapd build/test-eap-tls-engine
@sudo ./tools/hostapd/run_hostapd_test.sh

supplicant-hostapd-psk-test: build/test-supplicant-hostapd-psk
@sudo MODE=psk ./tools/hostapd/run_hostapd_test.sh

# nl80211 helper used by the hwsim path - small libnl-genl-3 client that
# drives the STA's open auth + WPA2 association so hostapd will start
# the real 4-way handshake. EAPOL itself flows via AF_PACKET as usual.
NL80211_CFLAGS:=$(shell pkg-config --cflags libnl-genl-3.0 libnl-3.0 2>/dev/null)
NL80211_LIBS:=$(shell pkg-config --libs libnl-genl-3.0 libnl-3.0 2>/dev/null)

build/nl80211_connect: tools/hostapd/nl80211_connect.c
@echo "[LD] $@"
@$(CC) $(CFLAGS) $(NL80211_CFLAGS) -o $@ $< $(NL80211_LIBS)

supplicant-hwsim-psk-test: build/test-supplicant-hostapd-psk build/nl80211_connect
@sudo ./tools/hostapd/run_hwsim_psk_test.sh

# Test

ifeq ($(CHECK_PKG_LIBS),)
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ configured to forward traffic between multiple network interfaces.
- Optional IPv4-forwarding
- Optional IPv4 UDP multicast with IGMPv3 ASM membership reports
- Reusable allocation-free TFTP module under `src/tftp/`
- Optional in-tree Wi-Fi supplicant (`src/supplicant/`) with WPA2-Personal (PSK 4-way), WPA2-Enterprise (EAP-TLS, optional PEAP/MSCHAPv2), and WPA3-Personal (SAE dragonfly with hunt-and-peck and RFC 9380 Hash-to-Element PWE, groups 19/20/21). See `tools/hostapd/README.md` for the build matrix and interop test harness.

## Supported socket types

Expand Down
109 changes: 109 additions & 0 deletions src/supplicant/eap.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/* eap.c
*
* Copyright (C) 2006-2025 wolfSSL Inc.
*
* This file is part of wolfIP.
*
* 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 2 of the License, or
* (at your option) any later version.
*/

#include "eap.h"
#include "eapol.h"

#include <string.h>

int eap_parse(const uint8_t *body, size_t body_len, struct eap_view *out)
{
uint16_t total;

if (body == NULL || out == NULL) {
return -1;
}
if (body_len < EAP_HEADER_LEN) {
return -1;
}
out->code = body[0];
out->id = body[1];
total = (uint16_t)(((uint16_t)body[2] << 8) | body[3]);
if (total < EAP_HEADER_LEN || (size_t)total > body_len) {
return -1;
}
out->length = total;

if (out->code == EAP_CODE_REQUEST || out->code == EAP_CODE_RESPONSE) {
if (total < EAP_HEADER_LEN + 1U) {
return -1;
}
out->type = body[4];
out->type_data = (total > EAP_HEADER_LEN + 1U) ? &body[5] : NULL;
out->type_data_len = (uint16_t)(total - (EAP_HEADER_LEN + 1U));
}
else {
/* Success / Failure / unknown carry no type. */
out->type = 0U;
out->type_data = NULL;
out->type_data_len = 0U;
}
return 0;
}

int eapol_eap_build(uint8_t *out, size_t out_cap,
uint8_t eapol_type,
const uint8_t *payload, size_t payload_len,
size_t *out_total_len)
{
size_t total;

if (out == NULL || out_total_len == NULL) {
return -1;
}
if (payload == NULL && payload_len != 0U) {
return -1;
}
total = EAPOL_HEADER_LEN + payload_len;
if (total > out_cap) {
return -1;
}
/* 802.1X header. */
out[0] = EAPOL_PROTO_VER;
out[1] = eapol_type;
out[2] = (uint8_t)((payload_len >> 8) & 0xFFU);
out[3] = (uint8_t)(payload_len & 0xFFU);
if (payload_len > 0U) {
memcpy(out + EAPOL_HEADER_LEN, payload, payload_len);
}
*out_total_len = total;
return 0;
}

int eap_build_identity_response(uint8_t *out, size_t out_cap,
uint8_t id,
const uint8_t *identity, size_t identity_len,
size_t *out_total_len)
{
size_t total;

if (out == NULL || out_total_len == NULL) {
return -1;
}
if (identity == NULL && identity_len != 0U) {
return -1;
}
total = EAP_HEADER_LEN + 1U + identity_len;
if (total > out_cap || total > 0xFFFFU) {
return -1;
}
out[0] = EAP_CODE_RESPONSE;
out[1] = id;
out[2] = (uint8_t)((total >> 8) & 0xFFU);
out[3] = (uint8_t)(total & 0xFFU);
out[4] = EAP_TYPE_IDENTITY;
if (identity_len > 0U) {
memcpy(&out[5], identity, identity_len);
}
*out_total_len = total;
return 0;
}
Loading
Loading