[14/25] OCV: Include and verify OCI in the FT handshake

Message ID 20180806194643.1328-15-Mathy.Vanhoef@cs.kuleuven.be
State Accepted
Headers show
Series
  • Add support for Operating Channel Validation (OCV)
Related show

Commit Message

Mathy Vanhoef Aug. 6, 2018, 7:46 p.m.
Include and verify the the OCI element in (Re)Association Request and
Responses of the FT hanshake. In case verification fails, the handshake
message is silently ignored.

Signed-off-by: Mathy Vanhoef <Mathy.Vanhoef@cs.kuleuven.be>
---
 src/ap/wpa_auth_ft.c  | 64 +++++++++++++++++++++++++++++++++++++++++++
 src/rsn_supp/wpa_ft.c | 41 +++++++++++++++++++++++++++
 2 files changed, 105 insertions(+)

Patch

diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e8d46ab0d..702af98fc 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -13,6 +13,8 @@ 
 #include "utils/list.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
 #include "crypto/aes.h"
 #include "crypto/aes_siv.h"
 #include "crypto/aes_wrap.h"
@@ -727,6 +729,15 @@  static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
 }
 
 
+static int wpa_channel_info(struct wpa_authenticator *wpa_auth,
+			       struct wpa_channel_info *ci)
+{
+	if (wpa_auth->cb->channel_info == NULL)
+		return -1;
+	return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci);
+}
+
+
 int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
 	u8 *pos = buf;
@@ -2430,6 +2441,35 @@  u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 			os_free(igtk);
 		}
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_OCV
+		if (wpa_auth_uses_ocv(sm)) {
+			struct wpa_channel_info ci;
+			u8 *nbuf, *ocipos;
+
+			if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+				wpa_printf(MSG_WARNING, "Failed to get "
+					   "channel info for OCI element");
+				os_free(subelem);
+				return pos;
+			}
+
+			subelem_len += 2 + OCV_OCI_LEN;
+			nbuf = os_realloc(subelem, subelem_len);
+			if (nbuf == NULL) {
+				os_free(subelem);
+				return pos;
+			}
+			subelem = nbuf;
+
+			ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN;
+			*ocipos++ = FTIE_SUBELEM_OCI;
+			*ocipos++ = OCV_OCI_LEN;
+			if (ocv_insert_oci(&ci, &ocipos) < 0) {
+				os_free(subelem);
+				return pos;
+			}
+		}
+#endif /* CONFIG_OCV */
 	} else {
 		r0kh_id = conf->r0_key_holder;
 		r0kh_id_len = conf->r0_key_holder_len;
@@ -3178,6 +3218,30 @@  u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
 		return WLAN_STATUS_INVALID_FTIE;
 	}
 
+#ifdef CONFIG_OCV
+	if (wpa_auth_uses_ocv(sm)) {
+		struct wpa_channel_info ci;
+		int tx_chanwidth;
+		int tx_seg1_idx;
+
+		if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
+			wpa_printf(MSG_WARNING, "Failed to get channel info to"
+				   "validate received OCI in (Re)Assoc Request");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		} else if (get_sta_tx_parameters(sm, channel_width_to_int(ci.chanwidth),
+						 ci.seg1_idx, &tx_chanwidth,
+						 &tx_seg1_idx) < 0) {
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+					 tx_chanwidth, tx_seg1_idx) != 0) {
+			wpa_printf(MSG_WARNING, ocv_errorstr);
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+	}
+#endif /* CONFIG_OCV */
+
 	return WLAN_STATUS_SUCCESS;
 }
 
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 9caff859d..bff5b283f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -14,6 +14,8 @@ 
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
+#include "common/ocv.h"
+#include "drivers/driver.h"
 #include "wpa.h"
 #include "wpa_i.h"
 
@@ -325,6 +327,26 @@  static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
 	*pos++ = sm->r0kh_id_len;
 	os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
 	pos += sm->r0kh_id_len;
+#ifdef CONFIG_OCV
+	if (kck && wpa_sm_ocv_enabled(sm)) {
+		/* OCI sub-element in third FT message */
+		struct wpa_channel_info ci;
+
+		if (wpa_sm_channel_info(sm, &ci) != 0) {
+			wpa_printf(MSG_WARNING, "Failed to get channel "
+				   "info for OCI element in FTE");
+			os_free(buf);
+			return NULL;
+		}
+
+		*pos++ = FTIE_SUBELEM_OCI;
+		*pos++ = OCV_OCI_LEN;
+		if (ocv_insert_oci(&ci, &pos) < 0) {
+			os_free(buf);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_OCV */
 	*ftie_len = pos - ftie_len - 1;
 
 	if (ric_ies) {
@@ -963,6 +985,25 @@  int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
 		return -1;
 	}
 
+#ifdef CONFIG_OCV
+	if (wpa_sm_ocv_enabled(sm)) {
+		struct wpa_channel_info ci;
+
+		if (wpa_sm_channel_info(sm, &ci) != 0) {
+			wpa_printf(MSG_WARNING, "Failed to get channel info to "
+				   "validate received OCI in (Re)Assoc Response");
+			return -1;
+		}
+
+		if (ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+					 channel_width_to_int(ci.chanwidth),
+					 ci.seg1_idx) != 0) {
+			wpa_printf(MSG_WARNING, ocv_errorstr);
+			return -1;
+		}
+	}
+#endif /* CONFIG_OCV */
+
 	sm->ft_reassoc_completed = 1;
 
 	if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)