FT: Validate MDIE and FTIE in FT 4-way handshake message 2/4
authorJouni Malinen <j@w1.fi>
Sat, 10 Apr 2010 19:40:35 +0000 (22:40 +0300)
committerJouni Malinen <j@w1.fi>
Sat, 10 Apr 2010 19:40:35 +0000 (22:40 +0300)
src/ap/wpa_auth.c
src/ap/wpa_auth_ft.c
src/ap/wpa_auth_i.h
src/ap/wpa_auth_ie.c
src/ap/wpa_auth_ie.h

index 1f76e96..3784afd 100644 (file)
@@ -539,6 +539,9 @@ void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
 
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
+#ifdef CONFIG_IEEE80211R
+       os_free(sm->assoc_resp_ftie);
+#endif /* CONFIG_IEEE80211R */
        os_free(sm->last_rx_eapol_key);
        os_free(sm->wpa_ie);
        os_free(sm);
@@ -598,6 +601,56 @@ static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
 }
 
 
+#ifdef CONFIG_IEEE80211R
+static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
+                              struct wpa_state_machine *sm,
+                              struct wpa_eapol_ie_parse *kde)
+{
+       struct wpa_ie_data ie;
+       struct rsn_mdie *mdie;
+
+       if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
+           ie.num_pmkid != 1 || ie.pmkid == NULL) {
+               wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
+                          "FT 4-way handshake message 2/4");
+               return -1;
+       }
+
+       os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
+       wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
+                   sm->sup_pmk_r1_name, PMKID_LEN);
+
+       if (!kde->mdie || !kde->ftie) {
+               wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
+                          "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+               return -1;
+       }
+
+       mdie = (struct rsn_mdie *) (kde->mdie + 2);
+       if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
+           os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
+                     MOBILITY_DOMAIN_ID_LEN) != 0) {
+               wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
+               return -1;
+       }
+
+       if (sm->assoc_resp_ftie &&
+           (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
+            os_memcmp(kde->ftie, sm->assoc_resp_ftie,
+                      2 + sm->assoc_resp_ftie[1]) != 0)) {
+               wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
+               wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
+                           kde->ftie, kde->ftie_len);
+               wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
+                           sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
+               return -1;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
                 struct wpa_state_machine *sm,
                 u8 *data, size_t data_len)
@@ -776,19 +829,9 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                        return;
                }
 #ifdef CONFIG_IEEE80211R
-               if (ft) {
-                       struct wpa_ie_data ie;
-                       if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len,
-                                                &ie) < 0 ||
-                           ie.num_pmkid != 1 || ie.pmkid == NULL) {
-                               wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
-                                          "FT 4-way handshake message 2/4");
-                               wpa_sta_disconnect(wpa_auth, sm->addr);
-                               return;
-                       }
-                       os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
-                       wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
-                                   sm->sup_pmk_r1_name, PMKID_LEN);
+               if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
+                       wpa_sta_disconnect(wpa_auth, sm->addr);
+                       return;
                }
 #endif /* CONFIG_IEEE80211R */
                break;
index 2c441eb..0ab3fb4 100644 (file)
@@ -692,6 +692,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
        ftie_len = res;
        pos += res;
 
+       os_free(sm->assoc_resp_ftie);
+       sm->assoc_resp_ftie = os_malloc(ftie_len);
+       if (sm->assoc_resp_ftie)
+               os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+
        _ftie = (struct rsn_ftie *) (ftie + 2);
        if (auth_alg == WLAN_AUTH_FT)
                _ftie->mic_control[1] = 3; /* Information element count */
index a7cbfd0..b69129f 100644 (file)
@@ -118,6 +118,7 @@ struct wpa_state_machine {
        size_t r0kh_id_len;
        u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
                                               * message 2/4 */
+       u8 *assoc_resp_ftie;
 #endif /* CONFIG_IEEE80211R */
 };
 
index f6eb5c4..f8a1804 100644 (file)
@@ -840,6 +840,9 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
                } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
                        ie->mdie = pos;
                        ie->mdie_len = pos[1] + 2;
+               } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+                       ie->ftie = pos;
+                       ie->ftie_len = pos[1] + 2;
 #endif /* CONFIG_IEEE80211R */
                } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
                        ret = wpa_parse_generic(pos, end, ie);
index 9968d2d..61d4cb4 100644 (file)
@@ -42,6 +42,8 @@ struct wpa_eapol_ie_parse {
 #ifdef CONFIG_IEEE80211R
        const u8 *mdie;
        size_t mdie_len;
+       const u8 *ftie;
+       size_t ftie_len;
 #endif /* CONFIG_IEEE80211R */
 };