X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=hostapd%2Fwpa_ft.c;h=5a5a443146599ba7500cad1568cfcc7dcbdc4b63;hb=7d737d6bf92b75d8c0a6e52c04115dd8e730c22b;hp=8c36df9b3ab96023987a7c438ec947bb55f690f0;hpb=b27f13ed281b4454236cb85801582c46f95fa349;p=wpasupplicant diff --git a/hostapd/wpa_ft.c b/hostapd/wpa_ft.c index 8c36df9..5a5a443 100644 --- a/hostapd/wpa_ft.c +++ b/hostapd/wpa_ft.c @@ -19,6 +19,7 @@ #include "wpa.h" #include "aes_wrap.h" #include "ieee802_11.h" +#include "wme.h" #include "defs.h" #include "wpa_auth_i.h" #include "wpa_auth_ie.h" @@ -26,6 +27,28 @@ #ifdef CONFIG_IEEE80211R +struct wpa_ft_ies { + const u8 *mdie; + size_t mdie_len; + const u8 *ftie; + size_t ftie_len; + const u8 *r1kh_id; + const u8 *gtk; + size_t gtk_len; + const u8 *r0kh_id; + size_t r0kh_id_len; + const u8 *rsn; + size_t rsn_len; + const u8 *rsn_pmkid; + const u8 *ric; + size_t ric_len; +}; + + +static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, + struct wpa_ft_ies *parse); + + static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst, const u8 *data, size_t data_len) { @@ -444,8 +467,9 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) struct wpa_group *gsm = sm->group; size_t subelem_len; - /* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16+8] */ - subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8; + /* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] | + * Key[16+8] */ + subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8; subelem = os_zalloc(subelem_len); if (subelem == NULL) return NULL; @@ -457,6 +481,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) pos += 2; wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, pos); pos += 6; + *pos++ = WPA_IGTK_LEN; if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, gsm->IGTK[gsm->GN_igtk - 4], pos)) { os_free(subelem); @@ -469,14 +494,122 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) #endif /* CONFIG_IEEE80211W */ +static u8 * wpa_ft_process_rdie(u8 *pos, u8 *end, u8 id, u8 descr_count, + const u8 *ies, size_t ies_len) +{ + struct ieee802_11_elems parse; + struct rsn_rdie *rdie; + + wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d", + id, descr_count); + wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)", + ies, ies_len); + + if (end - pos < (int) sizeof(*rdie)) { + wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE"); + return pos; + } + + *pos++ = WLAN_EID_RIC_DATA; + *pos++ = sizeof(*rdie); + rdie = (struct rsn_rdie *) pos; + rdie->id = id; + rdie->descr_count = 0; + rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS); + pos += sizeof(*rdie); + + if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) == + ParseFailed) { + wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs"); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + + if (parse.wmm_tspec) { + struct wmm_tspec_element *tspec; + int res; + + if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) { + wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE " + "(%d)", (int) parse.wmm_tspec_len); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + if (end - pos < (int) sizeof(*tspec)) { + wpa_printf(MSG_ERROR, "FT: Not enough room for " + "response TSPEC"); + rdie->status_code = + host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; + } + tspec = (struct wmm_tspec_element *) pos; + os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec)); + res = wmm_process_tspec(tspec); + wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res); + if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS) + rdie->status_code = + host_to_le16(WLAN_STATUS_INVALID_PARAMETERS); + else if (res == WMM_ADDTS_STATUS_REFUSED) + rdie->status_code = + host_to_le16(WLAN_STATUS_REQUEST_DECLINED); + else { + /* TSPEC accepted; include updated TSPEC in response */ + rdie->descr_count = 1; + pos += sizeof(*tspec); + } + return pos; + } + + wpa_printf(MSG_DEBUG, "FT: No supported resource requested"); + rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE); + return pos; +} + + +static u8 * wpa_ft_process_ric(u8 *pos, u8 *end, const u8 *ric, size_t ric_len) +{ + const u8 *rpos, *start; + const struct rsn_rdie *rdie; + + wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len); + + rpos = ric; + while (rpos + sizeof(*rdie) < ric + ric_len) { + if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) || + rpos + 2 + rpos[1] > ric + ric_len) + break; + rdie = (const struct rsn_rdie *) (rpos + 2); + rpos += 2 + rpos[1]; + start = rpos; + + while (rpos + 2 <= ric + ric_len && + rpos + 2 + rpos[1] <= ric + ric_len) { + if (rpos[0] == WLAN_EID_RIC_DATA) + break; + rpos += 2 + rpos[1]; + } + pos = wpa_ft_process_rdie(pos, end, rdie->id, + rdie->descr_count, + start, rpos - start); + } + + return pos; +} + + u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, - size_t max_len, int auth_alg) + size_t max_len, int auth_alg, + const u8 *req_ies, size_t req_ies_len) { u8 *end, *mdie, *ftie, *rsnie, *r0kh_id, *subelem = NULL; size_t mdie_len, ftie_len, rsnie_len, r0kh_id_len, subelem_len = 0; int res; struct wpa_auth_config *conf; struct rsn_ftie *_ftie; + struct wpa_ft_ies parse; + u8 *ric_start; if (sm == NULL) return pos; @@ -547,31 +680,27 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, _ftie = (struct rsn_ftie *) (ftie + 2); _ftie->mic_control[1] = 3; /* Information element count */ + + ric_start = pos; + if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) { + pos = wpa_ft_process_ric(pos, end, parse.ric, parse.ric_len); + _ftie->mic_control[1] += ieee802_11_ie_count(ric_start, + pos - ric_start); + } + if (ric_start == pos) + ric_start = NULL; + if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6, mdie, mdie_len, ftie, ftie_len, - rsnie, rsnie_len, NULL, 0, _ftie->mic) < 0) + rsnie, rsnie_len, + ric_start, ric_start ? pos - ric_start : 0, + _ftie->mic) < 0) wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); return pos; } -struct wpa_ft_ies { - const u8 *mdie; - size_t mdie_len; - const u8 *ftie; - size_t ftie_len; - const u8 *r1kh_id; - const u8 *gtk; - size_t gtk_len; - const u8 *r0kh_id; - size_t r0kh_id_len; - const u8 *rsn; - size_t rsn_len; - const u8 *rsn_pmkid; -}; - - static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len, struct wpa_ft_ies *parse) { @@ -621,6 +750,8 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, const u8 *end, *pos; struct wpa_ie_data data; int ret; + const struct rsn_ftie *ftie; + int prot_ie_count = 0; os_memset(parse, 0, sizeof(*parse)); if (ies == NULL) @@ -649,14 +780,60 @@ static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, parse->mdie_len = pos[1]; break; case WLAN_EID_FAST_BSS_TRANSITION: + if (pos[1] < sizeof(*ftie)) + return -1; + ftie = (const struct rsn_ftie *) (pos + 2); + prot_ie_count = ftie->mic_control[1]; if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0) return -1; break; + case WLAN_EID_RIC_DATA: + if (parse->ric == NULL) + parse->ric = pos; } pos += 2 + pos[1]; } + if (prot_ie_count == 0) + return 0; /* no MIC */ + + /* + * Check that the protected IE count matches with IEs included in the + * frame. + */ + if (parse->rsn) + prot_ie_count--; + if (parse->mdie) + prot_ie_count--; + if (parse->ftie) + prot_ie_count--; + if (prot_ie_count < 0) { + wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in " + "the protected IE count"); + return -1; + } + + if (prot_ie_count == 0 && parse->ric) { + wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not " + "included in protected IE count"); + return -1; + } + + /* Determine the end of the RIC IE(s) */ + pos = parse->ric; + while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end && + prot_ie_count) { + prot_ie_count--; + pos += 2 + pos[1]; + } + parse->ric_len = pos - parse->ric; + if (prot_ie_count) { + wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from " + "frame", (int) prot_ie_count); + return -1; + } + return 0; } @@ -935,20 +1112,11 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_INVALID_FTIE; } - /* - * Assume that MDIE, FTIE, and RSN IE are protected and that there is - * no RIC, so total of 3 protected IEs. - */ - if (ftie->mic_control[1] != 3) { - wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in FTIE (%d)", - ftie->mic_control[1]); - return WLAN_STATUS_INVALID_FTIE; - } - if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5, parse.mdie - 2, parse.mdie_len + 2, parse.ftie - 2, parse.ftie_len + 2, - parse.rsn - 2, parse.rsn_len + 2, NULL, 0, + parse.rsn - 2, parse.rsn_len + 2, + parse.ric, parse.ric_len, mic) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC"); return WLAN_STATUS_UNSPECIFIED_FAILURE;