aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiangwei Dong <liangwei@codeaurora.org>2019-05-29 09:11:48 (GMT)
committerJouni Malinen <jouni@codeaurora.org>2019-06-14 20:10:51 (GMT)
commitef60f0121ffcc1aed6aed3202a180705bb855221 (patch)
tree00ff8c0315b153e98a3e85cdbe892266416c302b
parentd1836e230853e2175256ea7b6e3435160e26d175 (diff)
downloadhostap-ef60f0121ffcc1aed6aed3202a180705bb855221.zip
hostap-ef60f0121ffcc1aed6aed3202a180705bb855221.tar.gz
hostap-ef60f0121ffcc1aed6aed3202a180705bb855221.tar.bz2
hostapd: Process OWE IE and update DH IE to the driver if needed
This implements the required functionality in hostapd to facilitate OWE connection with the AP SME-in-driver cases. Stations can either send DH IE or PMKID (in RSNE) (or both) in Association Request frame during the OWE handshake. The drivers that use this offload mechanism do not interpret this information and instead, pass the same to hostapd for further processing. hostapd will either validate the PMKID obtained from the STA or generate DH IE and further indicate the same to the driver. The driver further sends this information in the Association Response frame. Signed-off-by: Srinivas Dasari <dasaris@codeaurora.org> Signed-off-by: Liangwei Dong <liangwei@codeaurora.org> Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--src/ap/ap_drv_ops.c10
-rw-r--r--src/ap/ap_drv_ops.h2
-rw-r--r--src/ap/drv_callbacks.c76
-rw-r--r--src/ap/ieee802_11.c124
-rw-r--r--src/ap/ieee802_11.h6
-rw-r--r--src/ap/sta_info.h1
6 files changed, 219 insertions, 0 deletions
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index dced337..7c9dcf9 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -956,3 +956,13 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
return ret;
}
+
+
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen)
+{
+ if (!hapd->driver || !hapd->driver->update_dh_ie || !hapd->drv_priv)
+ return 0;
+ return hapd->driver->update_dh_ie(hapd->drv_priv, peer, reason_code,
+ ie, ielen);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 2a914dc..ca7f7ab 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -130,6 +130,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
+int hostapd_drv_update_dh_ie(struct hostapd_data *hapd, const u8 *peer,
+ u16 reason_code, const u8 *ie, size_t ielen);
#include "drivers/driver.h"
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 104dc1c..3158768 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1589,6 +1589,73 @@ static void hostapd_event_wds_sta_interface_status(struct hostapd_data *hapd,
}
+#ifdef CONFIG_OWE
+static int hostapd_notif_update_dh_ie(struct hostapd_data *hapd,
+ const u8 *peer, const u8 *ie,
+ size_t ie_len)
+{
+ u16 status;
+ struct sta_info *sta;
+ struct ieee802_11_elems elems;
+
+ if (!hapd || !hapd->wpa_auth) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid hapd context");
+ return -1;
+ }
+ if (!peer) {
+ wpa_printf(MSG_DEBUG, "OWE: Peer unknown");
+ return -1;
+ }
+ if (!(hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG, "OWE: No OWE AKM configured");
+ status = WLAN_STATUS_AKMP_NOT_VALID;
+ goto err;
+ }
+ if (ieee802_11_parse_elems(ie, ie_len, &elems, 1) == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "OWE: Failed to parse OWE IE for "
+ MACSTR, MAC2STR(peer));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ status = owe_validate_request(hapd, peer, elems.rsn_ie,
+ elems.rsn_ie_len,
+ elems.owe_dh, elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto err;
+
+ sta = ap_get_sta(hapd, peer);
+ if (sta) {
+ ap_sta_no_session_timeout(hapd, sta);
+ accounting_sta_stop(hapd, sta);
+
+ /*
+ * Make sure that the previously registered inactivity timer
+ * will not remove the STA immediately.
+ */
+ sta->timeout_next = STA_NULLFUNC;
+ } else {
+ sta = ap_sta_add(hapd, peer);
+ if (!sta) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto err;
+ }
+ }
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+ status = owe_process_rsn_ie(hapd, sta, elems.rsn_ie,
+ elems.rsn_ie_len, elems.owe_dh,
+ elems.owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ ap_free_sta(hapd, sta);
+
+ return 0;
+err:
+ hostapd_drv_update_dh_ie(hapd, peer, status, NULL, 0);
+ return 0;
+}
+#endif /* CONFIG_OWE */
+
+
void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data)
{
@@ -1694,6 +1761,15 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
data->assoc_info.req_ies_len,
data->assoc_info.reassoc);
break;
+#ifdef CONFIG_OWE
+ case EVENT_UPDATE_DH:
+ if (!data)
+ return;
+ hostapd_notif_update_dh_ie(hapd, data->update_dh.peer,
+ data->update_dh.ie,
+ data->update_dh.ie_len);
+ break;
+#endif /* CONFIG_OWE */
case EVENT_DISASSOC:
if (data)
hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 02f5670..4aef59e 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -23,6 +23,7 @@
#include "common/sae.h"
#include "common/dpp.h"
#include "common/ocv.h"
+#include "common/wpa_common.h"
#include "radius/radius.h"
#include "radius/radius_client.h"
#include "p2p/p2p.h"
@@ -2795,6 +2796,123 @@ static u16 owe_process_assoc_req(struct hostapd_data *hapd,
return WLAN_STATUS_SUCCESS;
}
+
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ struct wpa_ie_data data;
+ int res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: Invalid RSNE from " MACSTR,
+ MAC2STR(peer));
+ return WLAN_STATUS_INVALID_IE;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+
+ res = wpa_parse_wpa_ie_rsn(rsn_ie, rsn_ie_len, &data);
+ if (res) {
+ wpa_printf(MSG_DEBUG, "Failed to parse RSNE from " MACSTR
+ " (res=%d)", MAC2STR(peer), res);
+ wpa_hexdump(MSG_DEBUG, "RSNE", rsn_ie, rsn_ie_len);
+ return wpa_res_to_status_code(res);
+ }
+ if (!(data.key_mgmt & WPA_KEY_MGMT_OWE)) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: Unexpected key mgmt 0x%x from " MACSTR,
+ (unsigned int) data.key_mgmt, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+ if (!owe_dh) {
+ wpa_printf(MSG_DEBUG,
+ "OWE: No Diffie-Hellman Parameter element from "
+ MACSTR, MAC2STR(peer));
+ return WLAN_STATUS_AKMP_NOT_VALID;
+ }
+
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u16 owe_process_rsn_ie(struct hostapd_data *hapd,
+ struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len)
+{
+ u16 status;
+ u8 *owe_buf, ie[256 * 2];
+ size_t ie_len = 0;
+ int res;
+
+ if (!rsn_ie || rsn_ie_len < 2) {
+ wpa_printf(MSG_DEBUG, "OWE: No RSNE in (Re)AssocReq");
+ status = WLAN_STATUS_INVALID_IE;
+ goto end;
+ }
+
+ if (!sta->wpa_sm)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr,
+ NULL);
+ if (!sta->wpa_sm) {
+ wpa_printf(MSG_WARNING,
+ "OWE: Failed to initialize WPA state machine");
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+ rsn_ie -= 2;
+ rsn_ie_len += 2;
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ hapd->iface->freq, rsn_ie, rsn_ie_len,
+ NULL, 0, owe_dh, owe_dh_len);
+ status = wpa_res_to_status_code(res);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ status = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
+ if (status != WLAN_STATUS_SUCCESS)
+ goto end;
+ owe_buf = wpa_auth_write_assoc_resp_owe(sta->wpa_sm, ie, sizeof(ie),
+ NULL, 0);
+ if (!owe_buf) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ if (sta->owe_ecdh) {
+ struct wpabuf *pub;
+
+ pub = crypto_ecdh_get_pubkey(sta->owe_ecdh, 0);
+ if (!pub) {
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto end;
+ }
+
+ /* OWE Diffie-Hellman Parameter element */
+ *owe_buf++ = WLAN_EID_EXTENSION; /* Element ID */
+ *owe_buf++ = 1 + 2 + wpabuf_len(pub); /* Length */
+ *owe_buf++ = WLAN_EID_EXT_OWE_DH_PARAM; /* Element ID Extension
+ */
+ WPA_PUT_LE16(owe_buf, sta->owe_group);
+ owe_buf += 2;
+ os_memcpy(owe_buf, wpabuf_head(pub), wpabuf_len(pub));
+ owe_buf += wpabuf_len(pub);
+ wpabuf_free(pub);
+ sta->external_dh_updated = 1;
+ }
+ ie_len = owe_buf - ie;
+
+end:
+ wpa_printf(MSG_DEBUG, "OWE: Update status %d, ie len %d for peer "
+ MACSTR, status, (unsigned int) ie_len,
+ MAC2STR(sta->addr));
+ hostapd_drv_update_dh_ie(hapd, sta->addr, status,
+ status == WLAN_STATUS_SUCCESS ? ie : NULL,
+ ie_len);
+
+ return status;
+}
+
#endif /* CONFIG_OWE */
@@ -3648,6 +3766,12 @@ u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
return owe_buf;
}
+ if (sta->owe_pmk && sta->external_dh_updated) {
+ wpa_printf(MSG_DEBUG, "OWE: Using previously derived PMK");
+ *reason = WLAN_STATUS_SUCCESS;
+ return owe_buf;
+ }
+
*reason = owe_process_assoc_req(hapd, sta, owe_dh, owe_dh_len);
if (*reason != WLAN_STATUS_SUCCESS)
return NULL;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 914cd1f..8822a17 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -160,6 +160,12 @@ void ieee802_11_finish_fils_auth(struct hostapd_data *hapd,
u8 * owe_assoc_req_process(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *owe_dh, u8 owe_dh_len,
u8 *owe_buf, size_t owe_buf_len, u16 *reason);
+u16 owe_process_rsn_ie(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
+u16 owe_validate_request(struct hostapd_data *hapd, const u8 *peer,
+ const u8 *rsn_ie, size_t rsn_ie_len,
+ const u8 *owe_dh, size_t owe_dh_len);
void fils_hlp_timeout(void *eloop_ctx, void *eloop_data);
void fils_hlp_finish_assoc(struct hostapd_data *hapd, struct sta_info *sta);
void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9a081cb..5456a63 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -120,6 +120,7 @@ struct sta_info {
unsigned int agreed_to_steer:1;
unsigned int hs20_t_c_filtering:1;
unsigned int ft_over_ds:1;
+ unsigned int external_dh_updated:1;
u16 auth_alg;