]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OCV: Work around for misbehaving STAs that indicate OCVC=1 without OCI
authorVeerendranath Jakkam <vjakkam@codeaurora.org>
Wed, 7 Oct 2020 07:21:58 +0000 (12:51 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 8 Oct 2020 15:46:38 +0000 (18:46 +0300)
Some legacy stations copy previously reserved RSN capability bits,
including OCVC, in (Re)Association Request frames from the AP's RSNE but
do not indicate MFP capability and/or do not send OCI in RSN handshakes.
This is causing connection failures with such erroneous STAs.

To improve interoperability with such legacy STAs allow a workaround OCV
mode to be enabled to ignore OCVC=1 from the STA if it does not follow
OCV requirements in the first protected exchange. This covers cases
where a STA claims to have OCV capability, but it does not negotiate use
of management frame protection or does not include OCI in EAPOL Key msg
2/4, FT Reassociation Request frame, or FILS (Re)Association Reqest.

The previous behavior with ocv=1 is maintained, i.e., misbehaving STAs
are not allowed to connect. When the new workaround mode is enabled with
ocv=2, the AP considers STA as OCV capable on below criteria
- STA indicates both OCV and MFP capability
- STA sends OCI during connection attempt in a protected frame

Enabling this workaround mode reduced OCV protection to some extend
since it allows misbehavior to go through. As such, this should be
enabled only if interoperability with misbehaving STAs is needed.

Signed-off-by: Veerendranath Jakkam <vjakkam@codeaurora.org>
hostapd/hostapd.conf
src/ap/ieee802_11.c
src/ap/wpa_auth.c
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_i.h
src/ap/wpa_auth_ie.c

index 25b4e49276c0da7d0223728d29605846539d2663..29717d2c6de759a9d8eadb2370c9b97315b1d285 100644 (file)
@@ -1732,6 +1732,19 @@ own_ip_addr=127.0.0.1
 # Enabling this automatically also enables ieee80211w, if not yet enabled.
 # 0 = disabled (default)
 # 1 = enabled
+# 2 = enabled in workaround mode - Allow STA that claims OCV capability to
+#     connect even if the STA doesn't send OCI or negotiate PMF. This
+#     workaround is to improve interoperability with legacy STAs which are
+#     wrongly copying reserved bits of RSN capabilities from the AP's
+#     RSNE into (Re)Association Request frames. When this configuration is
+#     enabled, the AP considers STA is OCV capable only when the STA indicates
+#     MFP capability in (Re)Association Request frames and sends OCI in
+#     EAPOL-Key msg 2/4/FT Reassociation Request frame/FILS (Re)Association
+#     Request frame; otherwise, the AP disables OCV for the current connection
+#     with the STA. Enabling this workaround mode reduced OCV protection to
+#     some extend since it allows misbehavior to go through. As such, this
+#     should be enabled only if interoperability with misbehaving STAs is
+#     needed.
 #ocv=1
 
 # disable_pmksa_caching: Disable PMKSA caching
index 78c1b8c8cc17b0fcad5eeae4ddebba3c99c3c02f..a1a27f1020a6f7b9e73840b73fa9be854a444c69 100644 (file)
@@ -3561,6 +3561,7 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                struct wpa_channel_info ci;
                int tx_chanwidth;
                int tx_seg1_idx;
+               enum oci_verify_result res;
 
                if (hostapd_drv_channel_info(hapd, &ci) != 0) {
                        wpa_printf(MSG_WARNING,
@@ -3574,9 +3575,15 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                                          &tx_seg1_idx) < 0)
                        return WLAN_STATUS_UNSPECIFIED_FAILURE;
 
-               if (ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
-                                        tx_chanwidth, tx_seg1_idx) !=
-                   OCI_SUCCESS) {
+               res = ocv_verify_tx_params(elems.oci, elems.oci_len, &ci,
+                                          tx_chanwidth, tx_seg1_idx);
+               if (wpa_auth_uses_ocv(sta->wpa_sm) == 2 &&
+                   res == OCI_NOT_FOUND) {
+                       /* Work around misbehaving STAs */
+                       wpa_printf(MSG_INFO,
+                                  "FILS: Disable OCV with a STA that does not send OCI");
+                       wpa_auth_set_ocv(sta->wpa_sm, 0);
+               } else if (res != OCI_SUCCESS) {
                        wpa_printf(MSG_WARNING, "FILS: OCV failed: %s",
                                   ocv_errorstr);
                        wpa_msg(hapd->msg_ctx, MSG_INFO, OCV_FAILURE "addr="
index a5b1953f659ea9a4fc3a6e613868a3b97f81d6b5..9d74bfcd78e24bf1aea2c0f9466763cf808fdbf9 100644 (file)
@@ -3037,6 +3037,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                struct wpa_channel_info ci;
                int tx_chanwidth;
                int tx_seg1_idx;
+               enum oci_verify_result res;
 
                if (wpa_channel_info(wpa_auth, &ci) != 0) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -3050,9 +3051,14 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                                          &tx_seg1_idx) < 0)
                        return;
 
-               if (ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
-                                        tx_chanwidth, tx_seg1_idx) !=
-                   OCI_SUCCESS) {
+               res = ocv_verify_tx_params(kde.oci, kde.oci_len, &ci,
+                                          tx_chanwidth, tx_seg1_idx);
+               if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+                       /* Work around misbehaving STAs */
+                       wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+                                        "Disable OCV with a STA that does not send OCI");
+                       wpa_auth_set_ocv(sm, 0);
+               } else if (res != OCI_SUCCESS) {
                        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
                                         "OCV failed: %s", ocv_errorstr);
                        if (wpa_auth->conf.msg_ctx)
index 94a688ed99c5a77a97b6b2420a28cedc3990526c..5aa363eca94877dc02e0f2f6688204b579604f3f 100644 (file)
@@ -3505,6 +3505,7 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
                struct wpa_channel_info ci;
                int tx_chanwidth;
                int tx_seg1_idx;
+               enum oci_verify_result res;
 
                if (wpa_channel_info(sm->wpa_auth, &ci) != 0) {
                        wpa_printf(MSG_WARNING,
@@ -3518,9 +3519,14 @@ int wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
                                          &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) !=
-                   OCI_SUCCESS) {
+               res = ocv_verify_tx_params(parse.oci, parse.oci_len, &ci,
+                                          tx_chanwidth, tx_seg1_idx);
+               if (wpa_auth_uses_ocv(sm) == 2 && res == OCI_NOT_FOUND) {
+                       /* Work around misbehaving STAs */
+                       wpa_printf(MSG_INFO,
+                                  "Disable OCV with a STA that does not send OCI");
+                       wpa_auth_set_ocv(sm, 0);
+               } else if (res != OCI_SUCCESS) {
                        wpa_printf(MSG_WARNING, "OCV failed: %s", ocv_errorstr);
                        if (sm->wpa_auth->conf.msg_ctx)
                                wpa_msg(sm->wpa_auth->conf.msg_ctx, MSG_INFO,
index ba08ac257067ee34859a4b2ce18301de33164cb8..a6dc1a59185d4756e3600e371eb2ca5f46517940 100644 (file)
@@ -95,8 +95,9 @@ struct wpa_state_machine {
 #endif /* CONFIG_IEEE80211R_AP */
        unsigned int is_wnmsleep:1;
        unsigned int pmkid_set:1;
+
 #ifdef CONFIG_OCV
-       unsigned int ocv_enabled:1;
+       int ocv_enabled;
 #endif /* CONFIG_OCV */
 
        u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
index 3a16997cfec02eb896324534089799390d54ff0a..3704fc05eb72858d12f2b54833f694826fbe8ae2 100644 (file)
@@ -810,12 +810,24 @@ wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 #ifdef CONFIG_OCV
        if (wpa_auth->conf.ocv && (data.capabilities & WPA_CAPABILITY_OCVC) &&
            !(data.capabilities & WPA_CAPABILITY_MFPC)) {
-               wpa_printf(MSG_DEBUG,
-                          "Management frame protection required with OCV, but client did not enable it");
-               return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+               /* Some legacy MFP incapable STAs wrongly copy OCVC bit from
+                * AP RSN capabilities. To improve interoperability with such
+                * legacy STAs allow connection without enabling OCV when the
+                * workaround mode (ocv=2) is enabled.
+                */
+               if (wpa_auth->conf.ocv == 2) {
+                       wpa_printf(MSG_DEBUG,
+                                  "Allow connecting MFP incapable and OCV capable STA without enabling OCV");
+                       wpa_auth_set_ocv(sm, 0);
+               } else {
+                       wpa_printf(MSG_DEBUG,
+                                  "Management frame protection required with OCV, but client did not enable it");
+                       return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+               }
+       } else {
+               wpa_auth_set_ocv(sm, (data.capabilities & WPA_CAPABILITY_OCVC) ?
+                                wpa_auth->conf.ocv : 0);
        }
-       wpa_auth_set_ocv(sm, wpa_auth->conf.ocv &&
-                        (data.capabilities & WPA_CAPABILITY_OCVC));
 #endif /* CONFIG_OCV */
 
        if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||