]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Process OWE IE and update DH IE to the driver if needed
authorLiangwei Dong <liangwei@codeaurora.org>
Wed, 29 May 2019 09:11:48 +0000 (05:11 -0400)
committerJouni Malinen <jouni@codeaurora.org>
Fri, 14 Jun 2019 20:10:51 +0000 (23:10 +0300)
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>
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/drv_callbacks.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/sta_info.h

index dced3371d84ea7ceea9ab05158d323ab9d416386..7c9dcf9b9a0bb06ac76d41bccbd8af54670123dd 100644 (file)
@@ -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);
+}
index 2a914dc65c9e103c1745f71bf4f8783d74a38df8..ca7f7abe01fd8c83922b0ce29aba0fc47c876a18 100644 (file)
@@ -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"
index 104dc1cd7c0c99d1275e6d367b9199d648e6c7ad..31587685fe3b8dfaf21340e38f92b13b4450cc88 100644 (file)
@@ -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);
index 02f56701ee7e51e401d8dd0a88e7d28226c40b68..4aef59e88bc2187036a4f894ebc6835f58071348 100644 (file)
@@ -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;
index 914cd1f19e98349637d4107e6f761e56fc506677..8822a1785c775be8a49fb95357b1895c3a2eddf1 100644 (file)
@@ -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,
index 9a081cb2352af9bf31d8ecabf2c6d1ab334a45c1..5456a63a7c263afa8c4f06fa54b36cff4f551c26 100644 (file)
@@ -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;