From 9d3f347a2b14652e767d51142600206a32676b62 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 24 Jan 2022 20:57:19 +0200 Subject: [PATCH] DPP3: Add PKEX initiator retries and fallback from v2 to v1 for hostapd This extends hostapd with the design used in wpa_supplicant for PKEX initiator retries and automatic version fallback from v2 to v1 (the latter is enabled only with CONFIG_DPP3=y). Signed-off-by: Jouni Malinen CVE: CVE-2022-37660 Upstream-Status: Backport [https://git.w1.fi/cgit/hostap/commit/?id=9d3f347a2b14652e767d51142600206a32676b62] Signed-off-by: Divya Chellam --- src/ap/dpp_hostapd.c | 188 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 171 insertions(+), 17 deletions(-) diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c index 13e1fc5..6c30ba3 100644 --- a/src/ap/dpp_hostapd.c +++ b/src/ap/dpp_hostapd.c @@ -216,6 +216,163 @@ static void hostapd_dpp_auth_resp_retry(struct hostapd_data *hapd) } +static int hostapd_dpp_allow_ir(struct hostapd_data *hapd, unsigned int freq) +{ + int i, j; + + if (!hapd->iface->hw_features) + return -1; + + for (i = 0; i < hapd->iface->num_hw_features; i++) { + struct hostapd_hw_modes *mode = &hapd->iface->hw_features[i]; + + for (j = 0; j < mode->num_channels; j++) { + struct hostapd_channel_data *chan = &mode->channels[j]; + + if (chan->freq != (int) freq) + continue; + + if (chan->flag & (HOSTAPD_CHAN_DISABLED | + HOSTAPD_CHAN_NO_IR | + HOSTAPD_CHAN_RADAR)) + continue; + + return 1; + } + } + + wpa_printf(MSG_DEBUG, + "DPP: Frequency %u MHz not supported or does not allow PKEX initiation in the current channel list", + freq); + + return 0; +} + + +static int hostapd_dpp_pkex_next_channel(struct hostapd_data *hapd, + struct dpp_pkex *pkex) +{ + if (pkex->freq == 2437) + pkex->freq = 5745; + else if (pkex->freq == 5745) + pkex->freq = 5220; + else if (pkex->freq == 5220) + pkex->freq = 60480; + else + return -1; /* no more channels to try */ + + if (hostapd_dpp_allow_ir(hapd, pkex->freq) == 1) { + wpa_printf(MSG_DEBUG, "DPP: Try to initiate on %u MHz", + pkex->freq); + return 0; + } + + /* Could not use this channel - try the next one */ + return hostapd_dpp_pkex_next_channel(hapd, pkex); +} + + +static int hostapd_dpp_pkex_init(struct hostapd_data *hapd, bool v2) +{ + struct dpp_pkex *pkex; + struct wpabuf *msg; + unsigned int wait_time; + + wpa_printf(MSG_DEBUG, "DPP: Initiating PKEXv%d", v2 ? 2 : 1); + dpp_pkex_free(hapd->dpp_pkex); + hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, hapd->dpp_pkex_bi, + hapd->own_addr, + hapd->dpp_pkex_identifier, + hapd->dpp_pkex_code, v2); + pkex = hapd->dpp_pkex; + if (!pkex) + return -1; + + msg = hapd->dpp_pkex->exchange_req; + wait_time = 2000; /* TODO: hapd->max_remain_on_chan; */ + pkex->freq = 2437; + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", MAC2STR(broadcast), pkex->freq, + v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + hostapd_drv_send_action(hapd, pkex->freq, 0, broadcast, + wpabuf_head(msg), wpabuf_len(msg)); + pkex->exch_req_wait_time = wait_time; + pkex->exch_req_tries = 1; + + return 0; +} + + +static void hostapd_dpp_pkex_retry_timeout(void *eloop_ctx, void *timeout_ctx) +{ + struct hostapd_data *hapd = eloop_ctx; + struct dpp_pkex *pkex = hapd->dpp_pkex; + + if (!pkex || !pkex->exchange_req) + return; + if (pkex->exch_req_tries >= 5) { + if (hostapd_dpp_pkex_next_channel(hapd, pkex) < 0) { +#ifdef CONFIG_DPP3 + if (pkex->v2) { + wpa_printf(MSG_DEBUG, + "DPP: Fall back to PKEXv1"); + hostapd_dpp_pkex_init(hapd, false); + return; + } +#endif /* CONFIG_DPP3 */ + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_FAIL + "No response from PKEX peer"); + dpp_pkex_free(pkex); + hapd->dpp_pkex = NULL; + return; + } + pkex->exch_req_tries = 0; + } + + pkex->exch_req_tries++; + wpa_printf(MSG_DEBUG, "DPP: Retransmit PKEX Exchange Request (try %u)", + pkex->exch_req_tries); + wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR + " freq=%u type=%d", + MAC2STR(broadcast), pkex->freq, + pkex->v2 ? DPP_PA_PKEX_EXCHANGE_REQ : + DPP_PA_PKEX_V1_EXCHANGE_REQ); + hostapd_drv_send_action(hapd, pkex->freq, pkex->exch_req_wait_time, + broadcast, + wpabuf_head(pkex->exchange_req), + wpabuf_len(pkex->exchange_req)); +} + + +static void hostapd_dpp_pkex_tx_status(struct hostapd_data *hapd, const u8 *dst, + const u8 *data, size_t data_len, int ok) +{ + struct dpp_pkex *pkex = hapd->dpp_pkex; + + if (pkex->failed) { + wpa_printf(MSG_DEBUG, + "DPP: Terminate PKEX exchange due to an earlier error"); + if (pkex->t > pkex->own_bi->pkex_t) + pkex->own_bi->pkex_t = pkex->t; + dpp_pkex_free(pkex); + hapd->dpp_pkex = NULL; + return; + } + + if (pkex->exch_req_wait_time && pkex->exchange_req) { + /* Wait for PKEX Exchange Response frame and retry request if + * no response is seen. */ + eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, + NULL); + eloop_register_timeout(pkex->exch_req_wait_time / 1000, + (pkex->exch_req_wait_time % 1000) * 1000, + hostapd_dpp_pkex_retry_timeout, hapd, + NULL); + } +} + + void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, const u8 *data, size_t data_len, int ok) { @@ -227,6 +384,11 @@ void hostapd_dpp_tx_status(struct hostapd_data *hapd, const u8 *dst, " result=%s", MAC2STR(dst), ok ? "SUCCESS" : "FAILED"); if (!hapd->dpp_auth) { + if (hapd->dpp_pkex) { + hostapd_dpp_pkex_tx_status(hapd, dst, data, data_len, + ok); + return; + } wpa_printf(MSG_DEBUG, "DPP: Ignore TX status since there is no ongoing authentication exchange"); return; @@ -1783,6 +1945,9 @@ hostapd_dpp_rx_pkex_exchange_resp(struct hostapd_data *hapd, const u8 *src, return; } + eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL); + hapd->dpp_pkex->exch_req_wait_time = 0; + msg = dpp_pkex_rx_exchange_resp(hapd->dpp_pkex, src, buf, len); if (!msg) { wpa_printf(MSG_DEBUG, "DPP: Failed to process the response"); @@ -2172,26 +2337,14 @@ int hostapd_dpp_pkex_add(struct hostapd_data *hapd, const char *cmd) return -1; if (os_strstr(cmd, " init=1") || os_strstr(cmd, " init=2")) { - struct wpabuf *msg; +#ifdef CONFIG_DPP3 + bool v2 = true; +#else /* CONFIG_DPP3 */ bool v2 = os_strstr(cmd, " init=2") != NULL; +#endif /* CONFIG_DPP3 */ - wpa_printf(MSG_DEBUG, "DPP: Initiating PKEX"); - dpp_pkex_free(hapd->dpp_pkex); - hapd->dpp_pkex = dpp_pkex_init(hapd->msg_ctx, own_bi, - hapd->own_addr, - hapd->dpp_pkex_identifier, - hapd->dpp_pkex_code, v2); - if (!hapd->dpp_pkex) + if (hostapd_dpp_pkex_init(hapd, v2) < 0) return -1; - - msg = hapd->dpp_pkex->exchange_req; - /* TODO: Which channel to use? */ - wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_TX "dst=" MACSTR - " freq=%u type=%d", MAC2STR(broadcast), 2437, - v2 ? DPP_PA_PKEX_EXCHANGE_REQ : - DPP_PA_PKEX_V1_EXCHANGE_REQ); - hostapd_drv_send_action(hapd, 2437, 0, broadcast, - wpabuf_head(msg), wpabuf_len(msg)); } /* TODO: Support multiple PKEX info entries */ @@ -2319,6 +2472,7 @@ void hostapd_dpp_deinit(struct hostapd_data *hapd) #endif /* CONFIG_TESTING_OPTIONS */ if (!hapd->dpp_init_done) return; + eloop_cancel_timeout(hostapd_dpp_pkex_retry_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_reply_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_auth_conf_wait_timeout, hapd, NULL); eloop_cancel_timeout(hostapd_dpp_init_timeout, hapd, NULL); -- 2.40.0