diff options
Diffstat (limited to 'freebsd/contrib/wpa/src/ap/wpa_auth_ft.c')
-rw-r--r-- | freebsd/contrib/wpa/src/ap/wpa_auth_ft.c | 188 |
1 files changed, 165 insertions, 23 deletions
diff --git a/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c b/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c index fa1cce94..619f0566 100644 --- a/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c +++ b/freebsd/contrib/wpa/src/ap/wpa_auth_ft.c @@ -15,6 +15,8 @@ #include "utils/list.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/ocv.h" +#include "drivers/driver.h" #include "crypto/aes.h" #include "crypto/aes_siv.h" #include "crypto/aes_wrap.h" @@ -25,6 +27,7 @@ #include "wmm.h" #include "wpa_auth.h" #include "wpa_auth_i.h" +#include "pmksa_cache_auth.h" #ifdef CONFIG_IEEE80211R_AP @@ -66,7 +69,7 @@ struct tlv_list { * Returns: 0 on success, -1 on error */ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len, - const u8 *enc, const size_t enc_len, + const u8 *enc, size_t enc_len, const u8 *auth, const size_t auth_len, const u8 *src_addr, u8 type, u8 **plain, size_t *plain_size) @@ -74,7 +77,11 @@ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len, const u8 *ad[3] = { src_addr, auth, &type }; size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) }; + wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u", + MAC2STR(src_addr), type); wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypt using key", key, key_len); + wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", enc, enc_len); + wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len); if (!key) { /* skip decryption */ *plain = os_memdup(enc, enc_len); @@ -97,8 +104,18 @@ static int wpa_ft_rrb_decrypt(const u8 *key, const size_t key_len, goto err; if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len, - *plain) < 0) - goto err; + *plain) < 0) { + if (enc_len < AES_BLOCK_SIZE + 2) + goto err; + + /* Try to work around Ethernet devices that add extra + * two octet padding even if the frame is longer than + * the minimum Ethernet frame. */ + enc_len -= 2; + if (aes_siv_decrypt(key, key_len, enc, enc_len, 3, ad, ad_len, + *plain) < 0) + goto err; + } *plain_size = enc_len - AES_BLOCK_SIZE; wpa_hexdump_key(MSG_DEBUG, "FT(RRB): decrypted TLVs", @@ -463,9 +480,12 @@ static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len, const u8 *ad[3] = { src_addr, auth, &type }; size_t ad_len[3] = { ETH_ALEN, auth_len, sizeof(type) }; + wpa_printf(MSG_DEBUG, "FT(RRB): src_addr=" MACSTR " type=%u", + MAC2STR(src_addr), type); wpa_hexdump_key(MSG_DEBUG, "FT(RRB): plaintext message", plain, plain_len); wpa_hexdump_key(MSG_DEBUG, "FT(RRB): encrypt using key", key, key_len); + wpa_hexdump(MSG_DEBUG, "FT(RRB): authenticated TLVs", auth, auth_len); if (!key) { /* encryption not needed, return plaintext as packet */ @@ -475,6 +495,8 @@ static int wpa_ft_rrb_encrypt(const u8 *key, const size_t key_len, wpa_printf(MSG_ERROR, "FT: Failed to encrypt RRB-OUI message"); return -1; } + wpa_hexdump(MSG_DEBUG, "FT(RRB): encrypted TLVs", + enc, plain_len + AES_BLOCK_SIZE); return 0; } @@ -503,9 +525,10 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len, const u8 *src_addr, u8 type, u8 **packet, size_t *packet_len) { - u8 *plain = NULL, *auth = NULL, *pos; + u8 *plain = NULL, *auth = NULL, *pos, *tmp; size_t plain_len = 0, auth_len = 0; int ret = -1; + size_t pad_len = 0; *packet = NULL; if (wpa_ft_rrb_lin(tlvs_enc0, tlvs_enc1, vlan, &plain, &plain_len) < 0) @@ -517,6 +540,28 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len, *packet_len = sizeof(u16) + auth_len + plain_len; if (key) *packet_len += AES_BLOCK_SIZE; +#define RRB_MIN_MSG_LEN 64 + if (*packet_len < RRB_MIN_MSG_LEN) { + pad_len = RRB_MIN_MSG_LEN - *packet_len; + if (pad_len < sizeof(struct ft_rrb_tlv)) + pad_len = sizeof(struct ft_rrb_tlv); + wpa_printf(MSG_DEBUG, + "FT: Pad message to minimum Ethernet frame length (%d --> %d)", + (int) *packet_len, (int) (*packet_len + pad_len)); + *packet_len += pad_len; + tmp = os_realloc(auth, auth_len + pad_len); + if (!tmp) + goto out; + auth = tmp; + pos = auth + auth_len; + WPA_PUT_LE16(pos, FT_RRB_LAST_EMPTY); + pos += 2; + WPA_PUT_LE16(pos, pad_len - sizeof(struct ft_rrb_tlv)); + pos += 2; + os_memset(pos, 0, pad_len - sizeof(struct ft_rrb_tlv)); + auth_len += pad_len; + + } *packet = os_zalloc(*packet_len); if (!*packet) goto out; @@ -529,6 +574,7 @@ static int wpa_ft_rrb_build(const u8 *key, const size_t key_len, if (wpa_ft_rrb_encrypt(key, key_len, plain, plain_len, auth, auth_len, src_addr, type, pos) < 0) goto out; + wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", *packet, *packet_len); ret = 0; @@ -596,8 +642,8 @@ static int wpa_ft_rrb_oui_send(struct wpa_authenticator *wpa_auth, { if (!wpa_auth->cb->send_oui) return -1; - wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR, - oui_suffix, MAC2STR(dst)); + wpa_printf(MSG_DEBUG, "FT: RRB-OUI type %u send to " MACSTR " (len=%u)", + oui_suffix, MAC2STR(dst), (unsigned int) data_len); return wpa_auth->cb->send_oui(wpa_auth->cb_ctx, dst, oui_suffix, data, data_len); } @@ -620,7 +666,7 @@ static const u8 * wpa_ft_get_psk(struct wpa_authenticator *wpa_auth, if (wpa_auth->cb->get_psk == NULL) return NULL; return wpa_auth->cb->get_psk(wpa_auth->cb_ctx, addr, p2p_dev_addr, - prev_psk, NULL); + prev_psk, NULL, NULL); } @@ -729,6 +775,17 @@ static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth, } +#ifdef CONFIG_OCV +static int wpa_channel_info(struct wpa_authenticator *wpa_auth, + struct wpa_channel_info *ci) +{ + if (!wpa_auth->cb->channel_info) + return -1; + return wpa_auth->cb->channel_info(wpa_auth->cb_ctx, ci); +} +#endif /* CONFIG_OCV */ + + int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len) { u8 *pos = buf; @@ -896,6 +953,8 @@ wpa_ft_rrb_seq_req(struct wpa_authenticator *wpa_auth, goto err; } + wpa_printf(MSG_DEBUG, "FT: Send out sequence number request to " MACSTR, + MAC2STR(src_addr)); item = os_zalloc(sizeof(*item)); if (!item) goto err; @@ -2018,8 +2077,7 @@ int wpa_ft_store_pmk_fils(struct wpa_state_machine *sm, } -int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, - struct wpa_ptk *ptk) +int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, struct wpa_ptk *ptk) { u8 pmk_r0[PMK_LEN_MAX], pmk_r0_name[WPA_PMK_NAME_LEN]; size_t pmk_r0_len = wpa_key_mgmt_sha384(sm->wpa_key_mgmt) ? @@ -2039,8 +2097,16 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, const u8 *identity, *radius_cui; size_t identity_len, radius_cui_len; int session_timeout; - - if (sm->xxkey_len == 0) { + const u8 *mpmk; + size_t mpmk_len; + + if (sm->xxkey_len > 0) { + mpmk = sm->xxkey; + mpmk_len = sm->xxkey_len; + } else if (sm->pmksa) { + mpmk = sm->pmksa->pmk; + mpmk_len = sm->pmksa->pmk_len; + } else { wpa_printf(MSG_DEBUG, "FT: XXKey not available for key " "derivation"); return -1; @@ -2057,7 +2123,7 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, &radius_cui); session_timeout = wpa_ft_get_session_timeout(sm->wpa_auth, sm->addr); - if (wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid, + if (wpa_derive_pmk_r0(mpmk, mpmk_len, ssid, ssid_len, mdid, r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name, wpa_key_mgmt_sha384(sm->wpa_key_mgmt)) < 0) @@ -2162,6 +2228,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) return NULL; } + forced_memzero(keybuf, sizeof(keybuf)); *len = subelem_len; return subelem; } @@ -2375,10 +2442,24 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, end = pos + max_len; - if (auth_alg == WLAN_AUTH_FT) { + if (auth_alg == WLAN_AUTH_FT || + ((auth_alg == WLAN_AUTH_FILS_SK || + auth_alg == WLAN_AUTH_FILS_SK_PFS || + auth_alg == WLAN_AUTH_FILS_PK) && + (sm->wpa_key_mgmt & (WPA_KEY_MGMT_FT_FILS_SHA256 | + WPA_KEY_MGMT_FT_FILS_SHA384)))) { + if (!sm->pmk_r1_name_valid) { + wpa_printf(MSG_ERROR, + "FT: PMKR1Name is not valid for Assoc Resp RSNE"); + return NULL; + } + wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name for Assoc Resp RSNE", + sm->pmk_r1_name, WPA_PMK_NAME_LEN); /* * RSN (only present if this is a Reassociation Response and - * part of a fast BSS transition) + * part of a fast BSS transition; or if this is a + * (Re)Association Response frame during an FT initial mobility + * domain association using FILS) */ res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name); if (res < 0) @@ -2432,6 +2513,35 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, os_free(igtk); } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_OCV + if (wpa_auth_uses_ocv(sm)) { + struct wpa_channel_info ci; + u8 *nbuf, *ocipos; + + if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info for OCI element"); + os_free(subelem); + return NULL; + } + + subelem_len += 2 + OCV_OCI_LEN; + nbuf = os_realloc(subelem, subelem_len); + if (!nbuf) { + os_free(subelem); + return NULL; + } + subelem = nbuf; + + ocipos = subelem + subelem_len - 2 - OCV_OCI_LEN; + *ocipos++ = FTIE_SUBELEM_OCI; + *ocipos++ = OCV_OCI_LEN; + if (ocv_insert_oci(&ci, &ocipos) < 0) { + os_free(subelem); + return NULL; + } + } +#endif /* CONFIG_OCV */ } else { r0kh_id = conf->r0_key_holder; r0kh_id_len = conf->r0_key_holder_len; @@ -2598,6 +2708,8 @@ static int wpa_ft_psk_pmk_r1(struct wpa_state_machine *sm, os_memcpy(out_pmk_r1, pmk_r1, PMK_LEN); if (out_pairwise) *out_pairwise = pairwise; + os_memcpy(sm->PMK, pmk, PMK_LEN); + sm->pmk_len = PMK_LEN; if (out_vlan && wpa_ft_get_vlan(sm->wpa_auth, sm->addr, out_vlan) < 0) { wpa_printf(MSG_DEBUG, "FT: vlan not available for STA " @@ -2883,6 +2995,8 @@ pmk_r1_derived: wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, pmk_r1_len); sm->pmk_r1_name_valid = 1; os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN); + os_memcpy(sm->pmk_r1, pmk_r1, pmk_r1_len); + sm->pmk_r1_len = pmk_r1_len; if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) { wpa_printf(MSG_DEBUG, "FT: Failed to get random data for " @@ -2988,8 +3102,9 @@ void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid, status = res; wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR - " auth_transaction=%d status=%d", - MAC2STR(sm->addr), auth_transaction + 1, status); + " auth_transaction=%d status=%u (%s)", + MAC2STR(sm->addr), auth_transaction + 1, status, + status2str(status)); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); cb(ctx, sm->addr, bssid, auth_transaction + 1, status, resp_ies, resp_ies_len); @@ -3180,6 +3295,32 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_INVALID_FTIE; } +#ifdef CONFIG_OCV + if (wpa_auth_uses_ocv(sm)) { + struct wpa_channel_info ci; + int tx_chanwidth; + int tx_seg1_idx; + + if (wpa_channel_info(sm->wpa_auth, &ci) != 0) { + wpa_printf(MSG_WARNING, + "Failed to get channel info to validate received OCI in (Re)Assoc Request"); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + + if (get_sta_tx_parameters(sm, + channel_width_to_int(ci.chanwidth), + ci.seg1_idx, &tx_chanwidth, + &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) != 0) { + wpa_printf(MSG_WARNING, "%s", ocv_errorstr); + return WLAN_STATUS_UNSPECIFIED_FAILURE; + } + } +#endif /* CONFIG_OCV */ + return WLAN_STATUS_SUCCESS; } @@ -3321,8 +3462,9 @@ static int wpa_ft_send_rrb_auth_resp(struct wpa_state_machine *sm, u8 *pos; wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR - " CurrentAP=" MACSTR " status=%d", - MAC2STR(sm->addr), MAC2STR(current_ap), status); + " CurrentAP=" MACSTR " status=%u (%s)", + MAC2STR(sm->addr), MAC2STR(current_ap), status, + status2str(status)); wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len); /* RRB - Forward action frame response to the Current AP */ @@ -3428,7 +3570,7 @@ static int wpa_ft_rrb_build_r0(const u8 *key, const size_t key_len, pmk_r0->vlan, src_addr, type, packet, packet_len); - os_memset(pmk_r1, 0, sizeof(pmk_r1)); + forced_memzero(pmk_r1, sizeof(pmk_r1)); return ret; } @@ -3754,10 +3896,7 @@ static int wpa_ft_rrb_rx_r1(struct wpa_authenticator *wpa_auth, ret = 0; out: - if (plain) { - os_memset(plain, 0, plain_len); - os_free(plain); - } + bin_clear_free(plain, plain_len); return ret; @@ -4305,6 +4444,7 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, wpa_printf(MSG_DEBUG, "FT: RRB-OUI received frame from remote AP " MACSTR, MAC2STR(src_addr)); wpa_printf(MSG_DEBUG, "FT: RRB-OUI frame - oui_suffix=%d", oui_suffix); + wpa_hexdump(MSG_MSGDUMP, "FT: RRB frame payload", data, data_len); if (is_multicast_ether_addr(src_addr)) { wpa_printf(MSG_DEBUG, @@ -4333,8 +4473,10 @@ void wpa_ft_rrb_oui_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, } auth = data + sizeof(u16); + wpa_hexdump(MSG_MSGDUMP, "FT: Authenticated payload", auth, alen); enc = data + sizeof(u16) + alen; elen = data_len - sizeof(u16) - alen; + wpa_hexdump(MSG_MSGDUMP, "FT: Encrypted payload", enc, elen); switch (oui_suffix) { case FT_PACKET_R0KH_R1KH_PULL: |