aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/Android.mk4
-rw-r--r--hostapd/Makefile4
-rw-r--r--hostapd/config_file.c2
-rw-r--r--hostapd/defconfig2
-rw-r--r--hostapd/hostapd.conf5
-rw-r--r--src/ap/ap_config.h1
-rw-r--r--src/ap/ieee802_11.c132
-rw-r--r--src/ap/ieee802_11_shared.c5
-rw-r--r--src/ap/sta_info.c4
-rw-r--r--src/ap/sta_info.h4
10 files changed, 149 insertions, 14 deletions
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 10018bc..b1940f8 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -272,6 +272,10 @@ L_CFLAGS += -DCONFIG_FILS
OBJS += src/ap/fils_hlp.c
NEED_SHA384=y
NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+L_CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
endif
ifdef CONFIG_WNM
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 34a0e68..c443618 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -316,6 +316,10 @@ CFLAGS += -DCONFIG_FILS
OBJS += ../src/ap/fils_hlp.o
NEED_SHA384=y
NEED_AES_SIV=y
+ifdef CONFIG_FILS_SK_PFS
+CFLAGS += -DCONFIG_FILS_SK_PFS
+NEED_ECC=y
+endif
endif
ifdef CONFIG_WNM
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 2e4433d..7b43806 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3658,6 +3658,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
} else if (os_strcmp(buf, "fils_realm") == 0) {
if (parse_fils_realm(bss, pos) < 0)
return 1;
+ } else if (os_strcmp(buf, "fils_dh_group") == 0) {
+ bss->fils_dh_group = atoi(pos);
} else if (os_strcmp(buf, "dhcp_server") == 0) {
if (hostapd_parse_ip_addr(pos, &bss->dhcp_server)) {
wpa_printf(MSG_ERROR,
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 2370fc1..521d877 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -358,6 +358,8 @@ CONFIG_IPV6=y
# Note: This is an experimental and not yet complete implementation. This
# should not be enabled for production use.
#CONFIG_FILS=y
+# FILS shared key authentication with PFS
+#CONFIG_FILS_SK_PFS=y
# Include internal line edit mode in hostapd_cli. This can be used to provide
# limited command line editing and history support.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 19596ce..18c330b 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -1393,6 +1393,11 @@ own_ip_addr=127.0.0.1
#fils_realm=example.com
#fils_realm=example.org
+# FILS DH Group for PFS
+# 0 = PFS disabled with FILS shared key authentication (default)
+# 1-65535 DH Group to use for FILS PFS
+#fils_dh_group=0
+
# DHCP server for FILS HLP
# If configured, hostapd will act as a DHCP relay for all FILS HLP requests
# that include a DHCPDISCOVER message and send them to the specific DHCP
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 5394339..989b071 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -610,6 +610,7 @@ struct hostapd_bss_config {
u8 fils_cache_id[FILS_CACHE_ID_LEN];
int fils_cache_id_set;
struct dl_list fils_realms; /* list of struct fils_realm */
+ int fils_dh_group;
struct hostapd_ip_addr dhcp_server;
int dhcp_rapid_commit_proxy;
unsigned int fils_hlp_wait_time;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 5bbd585..ec73329 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1014,8 +1014,9 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
const u8 *msk, size_t msk_len);
static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
- const struct ieee80211_mgmt *mgmt, size_t len,
- u16 auth_transaction, u16 status_code)
+ const struct ieee80211_mgmt *mgmt, size_t len,
+ u16 auth_alg, u16 auth_transaction,
+ u16 status_code)
{
u16 resp = WLAN_STATUS_SUCCESS;
const u8 *pos, *end;
@@ -1033,8 +1034,76 @@ static void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
wpa_hexdump(MSG_DEBUG, "FILS: Authentication frame fields",
pos, end - pos);
- /* TODO: Finite Cyclic Group when using PK or PFS */
- /* TODO: Element when using PK or PFS */
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (auth_alg == WLAN_AUTH_FILS_SK_PFS) {
+ u16 group;
+ struct wpabuf *pub;
+ size_t elem_len;
+
+ /* Using FILS PFS */
+
+ /* Finite Cyclic Group */
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: No room for Finite Cyclic Group");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ if (group != hapd->conf->fils_dh_group) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Unsupported Finite Cyclic Group: %u (expected %u)",
+ group, hapd->conf->fils_dh_group);
+ resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = crypto_ecdh_init(group);
+ if (!sta->fils_ecdh) {
+ wpa_printf(MSG_INFO,
+ "FILS: Could not initialize ECDH with group %d",
+ group);
+ resp = WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+ goto fail;
+ }
+
+ pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
+ if (!pub) {
+ wpa_printf(MSG_DEBUG,
+ "FILS: Failed to derive ECDH public key");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ elem_len = wpabuf_len(pub);
+ wpabuf_free(pub);
+
+ /* Element */
+ if ((size_t) (end - pos) < elem_len) {
+ wpa_printf(MSG_DEBUG, "FILS: No room for Element");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = crypto_ecdh_set_peerkey(sta->fils_ecdh, 1,
+ pos, elem_len);
+ if (!sta->fils_dh_ss) {
+ wpa_printf(MSG_DEBUG, "FILS: ECDH operation failed");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ wpa_hexdump_buf_key(MSG_DEBUG, "FILS: DH_SS", sta->fils_dh_ss);
+ pos += elem_len;
+ } else {
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = NULL;
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = NULL;
+ }
+#endif /* CONFIG_FILS_SK_PFS */
wpa_hexdump(MSG_DEBUG, "FILS: Remaining IEs", pos, end - pos);
if (ieee802_11_parse_elems(pos, end - pos, &elems, 1) == ParseFailed) {
@@ -1173,6 +1242,8 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
const u8 *pmk = NULL;
size_t pmk_len = 0;
u8 pmk_buf[PMK_LEN_MAX];
+ struct wpabuf *pub = NULL;
+ u16 auth_alg;
if (resp != WLAN_STATUS_SUCCESS)
goto fail;
@@ -1204,14 +1275,32 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
wpa_hexdump(MSG_DEBUG, "RSN: Generated FILS Nonce",
fils_nonce, FILS_NONCE_LEN);
- data = wpabuf_alloc(1000 + ielen);
+#ifdef CONFIG_FILS_SK_PFS
+ if (sta->fils_dh_ss && sta->fils_ecdh) {
+ pub = crypto_ecdh_get_pubkey(sta->fils_ecdh, 1);
+ if (!pub) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ }
+#endif /* CONFIG_FILS_SK_PFS */
+
+ data = wpabuf_alloc(1000 + ielen + (pub ? wpabuf_len(pub) : 0));
if (!data) {
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
goto fail;
}
- /* TODO: Finite Cyclic Group when using PK or PFS */
- /* TODO: Element when using PK or PFS */
+ /* TODO: FILS PK */
+#ifdef CONFIG_FILS_SK_PFS
+ if (pub) {
+ /* Finite Cyclic Group */
+ wpabuf_put_le16(data, hapd->conf->fils_dh_group);
+
+ /* Element */
+ wpabuf_put_buf(data, pub);
+ }
+#endif /* CONFIG_FILS_SK_PFS */
/* RSNE */
wpabuf_put_data(data, ie, ielen);
@@ -1243,7 +1332,11 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
if (fils_rmsk_to_pmk(wpa_auth_sta_key_mgmt(sta->wpa_sm),
msk, msk_len, sta->fils_snonce, fils_nonce,
- NULL, 0, pmk_buf, &pmk_len)) {
+ sta->fils_dh_ss ?
+ wpabuf_head(sta->fils_dh_ss) : NULL,
+ sta->fils_dh_ss ?
+ wpabuf_len(sta->fils_dh_ss) : 0,
+ pmk_buf, &pmk_len)) {
wpa_printf(MSG_DEBUG, "FILS: Failed to derive PMK");
resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
wpabuf_free(data);
@@ -1273,8 +1366,10 @@ static void handle_auth_fils_finish(struct hostapd_data *hapd,
}
fail:
- send_auth_reply(hapd, sta->addr, hapd->own_addr, WLAN_AUTH_FILS_SK, 2,
- resp,
+ auth_alg = (pub ||
+ resp == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED) ?
+ WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
+ send_auth_reply(hapd, sta->addr, hapd->own_addr, auth_alg, 2, resp,
data ? wpabuf_head(data) : (u8 *) "",
data ? wpabuf_len(data) : 0);
wpabuf_free(data);
@@ -1285,11 +1380,18 @@ fail:
"authentication OK (FILS)");
sta->flags |= WLAN_STA_AUTH;
wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->auth_alg = WLAN_AUTH_FILS_SK;
+ sta->auth_alg = pub ? WLAN_AUTH_FILS_SK_PFS : WLAN_AUTH_FILS_SK;
mlme_authenticate_indication(hapd, sta);
}
os_free(ie_buf);
+ wpabuf_free(pub);
+ wpabuf_clear_free(sta->fils_dh_ss);
+ sta->fils_dh_ss = NULL;
+#ifdef CONFIG_FILS_SK_PFS
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ sta->fils_ecdh = NULL;
+#endif /* CONFIG_FILS_SK_PFS */
}
@@ -1472,6 +1574,9 @@ static void handle_auth(struct hostapd_data *hapd,
#ifdef CONFIG_FILS
(hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
auth_alg == WLAN_AUTH_FILS_SK) ||
+ (hapd->conf->wpa && wpa_key_mgmt_fils(hapd->conf->wpa_key_mgmt) &&
+ hapd->conf->fils_dh_group &&
+ auth_alg == WLAN_AUTH_FILS_SK_PFS) ||
#endif /* CONFIG_FILS */
((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
auth_alg == WLAN_AUTH_SHARED_KEY))) {
@@ -1738,8 +1843,9 @@ static void handle_auth(struct hostapd_data *hapd,
#endif /* CONFIG_SAE */
#ifdef CONFIG_FILS
case WLAN_AUTH_FILS_SK:
- handle_auth_fils(hapd, sta, mgmt, len, auth_transaction,
- status_code);
+ case WLAN_AUTH_FILS_SK_PFS:
+ handle_auth_fils(hapd, sta, mgmt, len, auth_alg,
+ auth_transaction, status_code);
return;
#endif /* CONFIG_FILS */
}
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index daacf7e..4d5ec2f 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -630,7 +630,10 @@ u8 * hostapd_eid_fils_indic(struct hostapd_data *hapd, u8 *eid, int hessid)
fils_info |= BIT(8); /* HESSID Included */
/* FILS Shared Key Authentication without PFS Supported */
fils_info |= BIT(9);
- /* TODO: B10: FILS Shared Key Authentication with PFS Supported */
+ if (hapd->conf->fils_dh_group) {
+ /* FILS Shared Key Authentication with PFS Supported */
+ fils_info |= BIT(10);
+ }
/* TODO: B11: FILS Public Key Authentication Supported */
/* B12..B15: Reserved */
WPA_PUT_LE16(pos, fils_info);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index f233d75..ea217f3 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -345,6 +345,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
wpabuf_free(sta->fils_hlp_resp);
wpabuf_free(sta->hlp_dhcp_discover);
eloop_cancel_timeout(fils_hlp_timeout, hapd, sta);
+#ifdef CONFIG_FILS_SK_PFS
+ crypto_ecdh_deinit(sta->fils_ecdh);
+ wpabuf_clear_free(sta->fils_dh_ss);
+#endif /* CONFIG_FILS_SK_PFS */
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index b5d1d33..0295798 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -231,6 +231,10 @@ struct sta_info {
unsigned int fils_dhcp_rapid_commit_proxy:1;
struct wpabuf *fils_hlp_resp;
struct wpabuf *hlp_dhcp_discover;
+#ifdef CONFIG_FILS_SK_PFS
+ struct crypto_ecdh *fils_ecdh;
+#endif /* CONFIG_FILS_SK_PFS */
+ struct wpabuf *fils_dh_ss;
#endif /* CONFIG_FILS */
#ifdef CONFIG_OWE