]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Allow EAPOL-Key messages 1/4 and 3/4 to be retransmitted for testing
authorJouni Malinen <j@w1.fi>
Sat, 14 Oct 2017 14:23:59 +0000 (17:23 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 16 Oct 2017 14:47:24 +0000 (17:47 +0300)
The new hostapd control interface commands "RESEND_M1 <addr>" and
"RESEND_M3 <addr>" can be used to request a retransmission of the 4-Way
Handshake messages 1/4 and 3/4 witht he same or modified ANonce (in M1).

This functionality is for testing purposes and included only in builds
with CONFIG_TESTING_OPTIONS=y.

Signed-off-by: Jouni Malinen <j@w1.fi>
hostapd/ctrl_iface.c
src/ap/wpa_auth.c
src/ap/wpa_auth.h

index 247de0a1f2600853ac7fbdc47d29925a1a638124..4f4ed62d72aaf6cdea5673c530001ea3de08a50f 100644 (file)
@@ -2034,6 +2034,41 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 }
 
 
+static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
+{
+       struct sta_info *sta;
+       u8 addr[ETH_ALEN];
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta || !sta->wpa_sm)
+               return -1;
+
+       wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
+       return wpa_auth_resend_m1(sta->wpa_sm,
+                                 os_strstr(cmd, "change-anonce") != NULL);
+}
+
+
+static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
+{
+       struct sta_info *sta;
+       u8 addr[ETH_ALEN];
+
+       if (hwaddr_aton(cmd, addr))
+               return -1;
+
+       sta = ap_get_sta(hapd, addr);
+       if (!sta || !sta->wpa_sm)
+               return -1;
+
+       wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
+       return wpa_auth_resend_m3(sta->wpa_sm);
+}
+
+
 static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
                                        const char *cmd)
 {
@@ -2772,6 +2807,12 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
        } else if (os_strncmp(buf, "RESET_PN ", 9) == 0) {
                if (hostapd_ctrl_reset_pn(hapd, buf + 9) < 0)
                        reply_len = -1;
+       } else if (os_strncmp(buf, "RESEND_M1 ", 10) == 0) {
+               if (hostapd_ctrl_resend_m1(hapd, buf + 10) < 0)
+                       reply_len = -1;
+       } else if (os_strncmp(buf, "RESEND_M3 ", 10) == 0) {
+               if (hostapd_ctrl_resend_m3(hapd, buf + 10) < 0)
+                       reply_len = -1;
        } else if (os_strncmp(buf, "RESEND_GROUP_M1 ", 16) == 0) {
                if (hostapd_ctrl_resend_group_m1(hapd, buf + 16) < 0)
                        reply_len = -1;
index 1632072767bc9c3036a9a99db74f83914feade7d..039c55e733f134a15cae5143d5f6ca0d7f411a32 100644 (file)
@@ -4504,6 +4504,187 @@ void wpa_auth_get_fils_aead_params(struct wpa_state_machine *sm,
 
 
 #if CONFIG_TESTING_OPTIONS
+
+int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce)
+{
+       const u8 *anonce = sm->ANonce;
+       u8 anonce_buf[WPA_NONCE_LEN];
+
+       if (change_anonce) {
+               if (random_get_bytes(anonce_buf, WPA_NONCE_LEN))
+                       return -1;
+               anonce = anonce_buf;
+       }
+
+       wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                       "sending 1/4 msg of 4-Way Handshake (TESTING)");
+       wpa_send_eapol(sm->wpa_auth, sm,
+                      WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+                      anonce, NULL, 0, 0, 0);
+       return 0;
+}
+
+
+int wpa_auth_resend_m3(struct wpa_state_machine *sm)
+{
+       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, *opos;
+       size_t gtk_len, kde_len;
+       struct wpa_group *gsm = sm->group;
+       u8 *wpa_ie;
+       int wpa_ie_len, secure, keyidx, encr = 0;
+
+       /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
+          GTK[GN], IGTK, [FTIE], [TIE * 2])
+        */
+
+       /* Use 0 RSC */
+       os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+       /* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
+       wpa_ie = sm->wpa_auth->wpa_ie;
+       wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+       if (sm->wpa == WPA_VERSION_WPA &&
+           (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+           wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+               /* WPA-only STA, remove RSN IE and possible MDIE */
+               wpa_ie = wpa_ie + wpa_ie[1] + 2;
+               if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
+                       wpa_ie = wpa_ie + wpa_ie[1] + 2;
+               wpa_ie_len = wpa_ie[1] + 2;
+       }
+       wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                       "sending 3/4 msg of 4-Way Handshake (TESTING)");
+       if (sm->wpa == WPA_VERSION_WPA2) {
+               /* WPA2 send GTK in the 4-way handshake */
+               secure = 1;
+               gtk = gsm->GTK[gsm->GN - 1];
+               gtk_len = gsm->GTK_len;
+               keyidx = gsm->GN;
+               _rsc = rsc;
+               encr = 1;
+       } else {
+               /* WPA does not include GTK in msg 3/4 */
+               secure = 0;
+               gtk = NULL;
+               gtk_len = 0;
+               keyidx = 0;
+               _rsc = NULL;
+               if (sm->rx_eapol_key_secure) {
+                       /*
+                        * It looks like Windows 7 supplicant tries to use
+                        * Secure bit in msg 2/4 after having reported Michael
+                        * MIC failure and it then rejects the 4-way handshake
+                        * if msg 3/4 does not set Secure bit. Work around this
+                        * by setting the Secure bit here even in the case of
+                        * WPA if the supplicant used it first.
+                        */
+                       wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                                       "STA used Secure bit in WPA msg 2/4 - "
+                                       "set Secure for 3/4 as workaround");
+                       secure = 1;
+               }
+       }
+
+       kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+       if (gtk)
+               kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+#ifdef CONFIG_IEEE80211R_AP
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+               kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
+               kde_len += 300; /* FTIE + 2 * TIE */
+       }
+#endif /* CONFIG_IEEE80211R_AP */
+       kde = os_malloc(kde_len);
+       if (kde == NULL)
+               return -1;
+
+       pos = kde;
+       os_memcpy(pos, wpa_ie, wpa_ie_len);
+       pos += wpa_ie_len;
+#ifdef CONFIG_IEEE80211R_AP
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+               int res;
+               size_t elen;
+
+               elen = pos - kde;
+               res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
+               if (res < 0) {
+                       wpa_printf(MSG_ERROR, "FT: Failed to insert "
+                                  "PMKR1Name into RSN IE in EAPOL-Key data");
+                       os_free(kde);
+                       return -1;
+               }
+               pos -= wpa_ie_len;
+               pos += elen;
+       }
+#endif /* CONFIG_IEEE80211R_AP */
+       if (gtk) {
+               u8 hdr[2];
+               hdr[0] = keyidx & 0x03;
+               hdr[1] = 0;
+               pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+                                 gtk, gtk_len);
+       }
+       opos = pos;
+       pos = ieee80211w_kde_add(sm, pos);
+       if (pos - opos >= WPA_IGTK_KDE_PREFIX_LEN) {
+               opos += 2; /* skip keyid */
+               os_memset(opos, 0, 6); /* clear PN */
+       }
+
+#ifdef CONFIG_IEEE80211R_AP
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+               int res;
+               struct wpa_auth_config *conf;
+
+               conf = &sm->wpa_auth->conf;
+               if (sm->assoc_resp_ftie &&
+                   kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
+                       os_memcpy(pos, sm->assoc_resp_ftie,
+                                 2 + sm->assoc_resp_ftie[1]);
+                       res = 2 + sm->assoc_resp_ftie[1];
+               } else {
+                       res = wpa_write_ftie(conf, conf->r0_key_holder,
+                                            conf->r0_key_holder_len,
+                                            NULL, NULL, pos,
+                                            kde + kde_len - pos,
+                                            NULL, 0);
+               }
+               if (res < 0) {
+                       wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
+                                  "into EAPOL-Key Key Data");
+                       os_free(kde);
+                       return -1;
+               }
+               pos += res;
+
+               /* TIE[ReassociationDeadline] (TU) */
+               *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+               *pos++ = 5;
+               *pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
+               WPA_PUT_LE32(pos, conf->reassociation_deadline);
+               pos += 4;
+
+               /* TIE[KeyLifetime] (seconds) */
+               *pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+               *pos++ = 5;
+               *pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
+               WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+               pos += 4;
+       }
+#endif /* CONFIG_IEEE80211R_AP */
+
+       wpa_send_eapol(sm->wpa_auth, sm,
+                      (secure ? WPA_KEY_INFO_SECURE : 0) |
+                      (wpa_mic_len(sm->wpa_key_mgmt, sm->pmk_len) ?
+                       WPA_KEY_INFO_MIC : 0) |
+                      WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+                      WPA_KEY_INFO_KEY_TYPE,
+                      _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+       os_free(kde);
+       return 0;
+}
+
+
 int wpa_auth_resend_group_m1(struct wpa_state_machine *sm)
 {
        u8 rsc[WPA_KEY_RSC_LEN];
@@ -4555,4 +4736,5 @@ int wpa_auth_resend_group_m1(struct wpa_state_machine *sm)
        os_free(kde_buf);
        return 0;
 }
+
 #endif /* CONFIG_TESTING_OPTIONS */
index ea91eda5b9ce315ff218149ae8104a30978c8a3e..38d9e7eab255b5483fd997ea2416b380d3f9863f 100644 (file)
@@ -427,6 +427,8 @@ u8 * wpa_auth_write_assoc_resp_owe(struct wpa_state_machine *sm,
                                   u8 *pos, size_t max_len,
                                   const u8 *req_ies, size_t req_ies_len);
 
+int wpa_auth_resend_m1(struct wpa_state_machine *sm, int change_anonce);
+int wpa_auth_resend_m3(struct wpa_state_machine *sm);
 int wpa_auth_resend_group_m1(struct wpa_state_machine *sm);
 
 #endif /* WPA_AUTH_H */