diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index c2c5693c5..f70816598 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -2298,14 +2298,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING) pos += wpa_ie_len; #ifdef CONFIG_IEEE80211R if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) { - int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name); + 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; } - pos += res; + pos -= wpa_ie_len; + pos += elen; } #endif /* CONFIG_IEEE80211R */ if (gtk) { diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index f3ea28161..b5f57b3ec 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1280,13 +1280,13 @@ int wpa_compare_rsn_ie(int ft_initial_assoc, #ifdef CONFIG_IEEE80211R -int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid) { u8 *start, *end, *rpos, *rend; int added = 0; start = ies; - end = ies + ies_len; + end = ies + *ies_len; while (start < end) { if (*start == WLAN_EID_RSN) @@ -1339,11 +1339,29 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) added += 2 + PMKID_LEN; start[1] += 2 + PMKID_LEN; } else { - /* PMKID-Count was included; use it */ - if (WPA_GET_LE16(rpos) != 0) { - wpa_printf(MSG_ERROR, "FT: Unexpected PMKID " - "in RSN IE in EAPOL-Key data"); + u16 num_pmkid; + + if (rend - rpos < 2) return -1; + num_pmkid = WPA_GET_LE16(rpos); + /* PMKID-Count was included; use it */ + if (num_pmkid != 0) { + u8 *after; + + if (num_pmkid * PMKID_LEN > rend - rpos - 2) + return -1; + /* + * PMKID may have been included in RSN IE in + * (Re)Association Request frame, so remove the old + * PMKID(s) first before adding the new one. + */ + wpa_printf(MSG_DEBUG, + "FT: Remove %u old PMKID(s) from RSN IE", + num_pmkid); + after = rpos + 2 + num_pmkid * PMKID_LEN; + os_memmove(rpos + 2, after, rend - after); + start[1] -= num_pmkid * PMKID_LEN; + added -= num_pmkid * PMKID_LEN; } WPA_PUT_LE16(rpos, 1); rpos += 2; @@ -1356,7 +1374,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid) wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification " "(PMKID inserted)", start, 2 + start[1]); - return added; + *ies_len += added; + + return 0; } #endif /* CONFIG_IEEE80211R */ diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index ee71bfc09..af1d0f0c6 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -409,7 +409,7 @@ u32 wpa_akm_to_suite(int akm); int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len); -int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid); +int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid); struct wpa_ft_ies { const u8 *mdie; diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 7a708234b..9bde3c816 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -364,13 +364,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, if (rsn_ie_buf == NULL) return -1; os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len); - res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len, + res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len, sm->pmk_r1_name); if (res < 0) { os_free(rsn_ie_buf); return -1; } - wpa_ie_len += res; if (sm->assoc_resp_ies) { os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,