diff options
author | Stefan Lippers-Hollmann <s.l-h@gmx.de> | 2014-10-14 12:39:25 +0000 |
---|---|---|
committer | Andrew Shadura <andrewsh@debian.org> | 2016-07-20 23:23:37 +0200 |
commit | 6e1f9c092d6958a8a1c01629f43941647dc7fc20 (patch) | |
tree | cf3c0e907680dcc04786ee490c8b6227abfc5c02 /src | |
parent | 7ea3403faef12dfe4f6ee746c3e21306b4dc4460 (diff) |
Imported Upstream version 2.3
Diffstat (limited to 'src')
150 files changed, 2943 insertions, 1198 deletions
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 7535b1b..d7d5c3b 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -379,7 +379,7 @@ void hostapd_config_free_eap_user(struct hostapd_eap_user *user) { hostapd_config_free_radius_attr(user->accept_attr); os_free(user->identity); - os_free(user->password); + bin_clear_free(user->password, user->password_len); os_free(user); } @@ -388,7 +388,7 @@ static void hostapd_config_free_wep(struct hostapd_wep_keys *keys) { int i; for (i = 0; i < NUM_WEP_KEYS; i++) { - os_free(keys->key[i]); + bin_clear_free(keys->key[i], keys->len[i]); keys->key[i] = NULL; } } @@ -406,10 +406,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf) while (psk) { prev = psk; psk = psk->next; - os_free(prev); + bin_clear_free(prev, sizeof(*prev)); } - os_free(conf->ssid.wpa_passphrase); + str_clear_free(conf->ssid.wpa_passphrase); os_free(conf->ssid.wpa_psk_file); hostapd_config_free_wep(&conf->ssid.wep); #ifdef CONFIG_FULL_DYNAMIC_VLAN @@ -759,7 +759,7 @@ static int hostapd_config_check_bss(struct hostapd_bss_config *bss, conf->hw_mode == HOSTAPD_MODE_IEEE80211B) { bss->disable_11n = 1; wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not " - "allowed, disabling HT capabilites"); + "allowed, disabling HT capabilities"); } if (full_config && conf->ieee80211n && diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 2a4acf2..4cae0d9 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -113,6 +113,10 @@ static u8 * hostapd_eid_pwr_constraint(struct hostapd_data *hapd, u8 *eid) hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) return eid; + /* Let host drivers add this IE if DFS support is offloaded */ + if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) + return eid; + /* * There is no DFS support and power constraint was not directly * requested by config option. @@ -220,7 +224,7 @@ static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid, continue; /* can use same entry */ } - if (start) { + if (start && prev) { pos = hostapd_eid_country_add(pos, end, chan_spacing, start, prev); start = NULL; @@ -265,18 +269,18 @@ static u8 * hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid) { u8 chan; - if (!hapd->iface->cs_freq_params.freq) + if (!hapd->cs_freq_params.freq) return eid; - if (ieee80211_freq_to_chan(hapd->iface->cs_freq_params.freq, &chan) == + if (ieee80211_freq_to_chan(hapd->cs_freq_params.freq, &chan) == NUM_HOSTAPD_MODES) return eid; *eid++ = WLAN_EID_CHANNEL_SWITCH; *eid++ = 3; - *eid++ = hapd->iface->cs_block_tx; + *eid++ = hapd->cs_block_tx; *eid++ = chan; - *eid++ = hapd->iface->cs_count; + *eid++ = hapd->cs_count; return eid; } @@ -286,12 +290,12 @@ static u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid) { u8 sec_ch; - if (!hapd->iface->cs_freq_params.sec_channel_offset) + if (!hapd->cs_freq_params.sec_channel_offset) return eid; - if (hapd->iface->cs_freq_params.sec_channel_offset == -1) + if (hapd->cs_freq_params.sec_channel_offset == -1) sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW; - else if (hapd->iface->cs_freq_params.sec_channel_offset == 1) + else if (hapd->cs_freq_params.sec_channel_offset == 1) sec_ch = HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE; else return eid; @@ -409,7 +413,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_eid_roaming_consortium(hapd, pos); pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp, - &hapd->iface->cs_c_off_proberesp); + &hapd->cs_c_off_proberesp); #ifdef CONFIG_IEEE80211AC pos = hostapd_eid_vht_capabilities(hapd, pos); pos = hostapd_eid_vht_operation(hapd, pos); @@ -824,7 +828,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd, tailpos = hostapd_eid_adv_proto(hapd, tailpos); tailpos = hostapd_eid_roaming_consortium(hapd, tailpos); tailpos = hostapd_add_csa_elems(hapd, tailpos, tail, - &hapd->iface->cs_c_off_beacon); + &hapd->cs_c_off_beacon); #ifdef CONFIG_IEEE80211AC tailpos = hostapd_eid_vht_capabilities(hapd, tailpos); tailpos = hostapd_eid_vht_operation(hapd, tailpos); @@ -957,7 +961,7 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd) struct wpabuf *beacon, *proberesp, *assocresp; int res, ret = -1; - if (hapd->iface->csa_in_progress) { + if (hapd->csa_in_progress) { wpa_printf(MSG_ERROR, "Cannot set beacons during CSA period"); return -1; } diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index ccbbab5..39edbd7 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -230,11 +230,12 @@ static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype, if (mgmt == NULL) return -1; + mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR - " with minor reason code %u (stype=%u)", - MAC2STR(addr), minor_reason_code, stype); + " with minor reason code %u (stype=%u (%s))", + MAC2STR(addr), minor_reason_code, stype, + fc2str(mgmt->frame_control)); - mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype); os_memcpy(mgmt->da, addr, ETH_ALEN); os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN); os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN); diff --git a/src/ap/dfs.c b/src/ap/dfs.c index c30f6d6..a6ec20b 100644 --- a/src/ap/dfs.c +++ b/src/ap/dfs.c @@ -18,10 +18,12 @@ #include "dfs.h" -static int dfs_get_used_n_chans(struct hostapd_iface *iface) +static int dfs_get_used_n_chans(struct hostapd_iface *iface, int *seg1) { int n_chans = 1; + *seg1 = 0; + if (iface->conf->ieee80211n && iface->conf->secondary_channel) n_chans = 2; @@ -35,6 +37,10 @@ static int dfs_get_used_n_chans(struct hostapd_iface *iface) case VHT_CHANWIDTH_160MHZ: n_chans = 8; break; + case VHT_CHANWIDTH_80P80MHZ: + n_chans = 4; + *seg1 = 4; + break; default: break; } @@ -170,10 +176,10 @@ static int dfs_find_channel(struct hostapd_iface *iface, { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan; - int i, channel_idx = 0, n_chans; + int i, channel_idx = 0, n_chans, n_chans1; mode = iface->current_mode; - n_chans = dfs_get_used_n_chans(iface); + n_chans = dfs_get_used_n_chans(iface, &n_chans1); wpa_printf(MSG_DEBUG, "DFS new chan checking %d channels", n_chans); for (i = 0; i < mode->num_channels; i++) { @@ -246,12 +252,15 @@ static void dfs_adjust_vht_center_freq(struct hostapd_iface *iface, /* Return start channel idx we will use for mode->channels[idx] */ -static int dfs_get_start_chan_idx(struct hostapd_iface *iface) +static int dfs_get_start_chan_idx(struct hostapd_iface *iface, int *seg1_start) { struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan; int channel_no = iface->conf->channel; int res = -1, i; + int chan_seg1 = -1; + + *seg1_start = -1; /* HT40- */ if (iface->conf->ieee80211n && iface->conf->secondary_channel == -1) @@ -270,9 +279,15 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface) channel_no = iface->conf->vht_oper_centr_freq_seg0_idx - 14; break; + case VHT_CHANWIDTH_80P80MHZ: + channel_no = + iface->conf->vht_oper_centr_freq_seg0_idx - 6; + chan_seg1 = + iface->conf->vht_oper_centr_freq_seg1_idx - 6; + break; default: wpa_printf(MSG_INFO, - "DFS only VHT20/40/80/160 is supported now"); + "DFS only VHT20/40/80/160/80+80 is supported now"); channel_no = -1; break; } @@ -288,6 +303,23 @@ static int dfs_get_start_chan_idx(struct hostapd_iface *iface) } } + if (res != -1 && chan_seg1 > -1) { + int found = 0; + + /* Get idx for seg1 */ + mode = iface->current_mode; + for (i = 0; i < mode->num_channels; i++) { + chan = &mode->channels[i]; + if (chan->chan == chan_seg1) { + *seg1_start = i; + found = 1; + break; + } + } + if (!found) + res = -1; + } + if (res == -1) { wpa_printf(MSG_DEBUG, "DFS chan_idx seems wrong; num-ch: %d ch-no: %d conf-ch-no: %d 11n: %d sec-ch: %d vht-oper-width: %d", @@ -511,17 +543,17 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled, static int dfs_are_channels_overlapped(struct hostapd_iface *iface, int freq, int chan_width, int cf1, int cf2) { - int start_chan_idx; + int start_chan_idx, start_chan_idx1; struct hostapd_hw_modes *mode; struct hostapd_channel_data *chan; - int n_chans, i, j, frequency = freq, radar_n_chans = 1; + int n_chans, n_chans1, i, j, frequency = freq, radar_n_chans = 1; u8 radar_chan; int res = 0; /* Our configuration */ mode = iface->current_mode; - start_chan_idx = dfs_get_start_chan_idx(iface); - n_chans = dfs_get_used_n_chans(iface); + start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); + n_chans = dfs_get_used_n_chans(iface, &n_chans1); /* Check we are on DFS channel(s) */ if (!dfs_check_chans_radar(iface, start_chan_idx, n_chans)) @@ -604,19 +636,20 @@ static unsigned int dfs_get_cac_time(struct hostapd_iface *iface, int hostapd_handle_dfs(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; - int res, n_chans, start_chan_idx; + int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1; int skip_radar = 0; iface->cac_started = 0; do { /* Get start (first) channel for current configuration */ - start_chan_idx = dfs_get_start_chan_idx(iface); + start_chan_idx = dfs_get_start_chan_idx(iface, + &start_chan_idx1); if (start_chan_idx == -1) return -1; /* Get number of used channels, depend on width */ - n_chans = dfs_get_used_n_chans(iface); + n_chans = dfs_get_used_n_chans(iface, &n_chans1); /* Setup CAC time */ iface->dfs_cac_ms = dfs_get_cac_time(iface, start_chan_idx, @@ -756,6 +789,16 @@ static int hostapd_dfs_start_channel_switch_cac(struct hostapd_iface *iface) } +static int hostapd_csa_in_progress(struct hostapd_iface *iface) +{ + unsigned int i; + for (i = 0; i < iface->num_bss; i++) + if (iface->bss[i]->csa_in_progress) + return 1; + return 0; +} + + static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) { struct hostapd_channel_data *channel; @@ -764,15 +807,15 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) u8 vht_oper_centr_freq_seg1_idx; int skip_radar = 1; struct csa_settings csa_settings; - struct hostapd_data *hapd = iface->bss[0]; + unsigned int i; int err = 1; wpa_printf(MSG_DEBUG, "%s called (CAC active: %s, CSA active: %s)", __func__, iface->cac_started ? "yes" : "no", - iface->csa_in_progress ? "yes" : "no"); + hostapd_csa_in_progress(iface) ? "yes" : "no"); /* Check if CSA in progress */ - if (iface->csa_in_progress) + if (hostapd_csa_in_progress(iface)) return 0; /* Check if active CAC */ @@ -843,7 +886,12 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface) return err; } - err = hostapd_switch_channel(hapd, &csa_settings); + for (i = 0; i < iface->num_bss; i++) { + err = hostapd_switch_channel(iface->bss[i], &csa_settings); + if (err) + break; + } + if (err) { wpa_printf(MSG_WARNING, "DFS failed to schedule CSA (%d) - trying fallback", err); @@ -882,9 +930,8 @@ int hostapd_dfs_radar_detected(struct hostapd_iface *iface, int freq, freq, ht_enabled, chan_offset, chan_width, cf1, cf2); /* mark radar frequency as invalid */ - res = set_dfs_state(iface, freq, ht_enabled, chan_offset, - chan_width, cf1, cf2, - HOSTAPD_CHAN_DFS_UNAVAILABLE); + set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width, + cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE); /* Skip if reported radar event not overlapped our channels */ res = dfs_are_channels_overlapped(iface, freq, chan_width, cf1, cf2); @@ -914,20 +961,25 @@ int hostapd_dfs_nop_finished(struct hostapd_iface *iface, int freq, int hostapd_is_dfs_required(struct hostapd_iface *iface) { - int n_chans, start_chan_idx; + int n_chans, n_chans1, start_chan_idx, start_chan_idx1, res; if (!iface->conf->ieee80211h || !iface->current_mode || iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A) return 0; /* Get start (first) channel for current configuration */ - start_chan_idx = dfs_get_start_chan_idx(iface); + start_chan_idx = dfs_get_start_chan_idx(iface, &start_chan_idx1); if (start_chan_idx == -1) return -1; /* Get number of used channels, depend on width */ - n_chans = dfs_get_used_n_chans(iface); + n_chans = dfs_get_used_n_chans(iface, &n_chans1); /* Check if any of configured channels require DFS */ - return dfs_check_chans_radar(iface, start_chan_idx, n_chans); + res = dfs_check_chans_radar(iface, start_chan_idx, n_chans); + if (res) + return res; + if (start_chan_idx1 >= 0 && n_chans1 > 0) + res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1); + return res; } diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c index fb095ef..3bde720 100644 --- a/src/ap/drv_callbacks.c +++ b/src/ap/drv_callbacks.c @@ -340,6 +340,9 @@ skip_wpa_check: sta->auth_alg, req_ies, req_ies_len); hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf); + + if (sta->auth_alg == WLAN_AUTH_FT) + ap_sta_set_authorized(hapd, sta, 1); #else /* CONFIG_IEEE80211R */ /* Keep compiler silent about unused variables */ if (status) { @@ -350,6 +353,8 @@ skip_wpa_check: sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->flags &= ~WLAN_STA_WNM_SLEEP_MODE; + hostapd_set_sta_flags(hapd, sta); + if (reassoc && (sta->auth_alg == WLAN_AUTH_FT)) wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT); else @@ -489,9 +494,10 @@ void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht, hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx; hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx; - if (hapd->iface->csa_in_progress && - freq == hapd->iface->cs_freq_params.freq) { + if (hapd->csa_in_progress && + freq == hapd->cs_freq_params.freq) { hostapd_cleanup_cs_params(hapd); + ieee802_11_set_beacon(hapd); wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d", freq); @@ -884,6 +890,20 @@ static void hostapd_event_get_survey(struct hostapd_data *hapd, #ifdef NEED_AP_MLME +static void hostapd_event_iface_unavailable(struct hostapd_data *hapd) +{ + wpa_printf(MSG_DEBUG, "Interface %s is unavailable -- stopped", + hapd->conf->iface); + + if (hapd->csa_in_progress) { + wpa_printf(MSG_INFO, "CSA failed (%s was stopped)", + hapd->conf->iface); + hostapd_switch_channel_fallback(hapd->iface, + &hapd->cs_freq_params); + } +} + + static void hostapd_event_dfs_radar_detected(struct hostapd_data *hapd, struct dfs_event *radar) { @@ -1029,6 +1049,8 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, data->eapol_rx.data_len); break; case EVENT_ASSOC: + if (!data) + return; hostapd_notif_assoc(hapd, data->assoc_info.addr, data->assoc_info.req_ies, data->assoc_info.req_ies_len, @@ -1071,6 +1093,9 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, hostapd_event_get_survey(hapd, &data->survey_results); break; #ifdef NEED_AP_MLME + case EVENT_INTERFACE_UNAVAILABLE: + hostapd_event_iface_unavailable(hapd); + break; case EVENT_DFS_RADAR_DETECTED: if (!data) break; diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c index 371a73f..559d77f 100644 --- a/src/ap/eap_user_db.c +++ b/src/ap/eap_user_db.c @@ -83,7 +83,7 @@ static int get_user_cb(void *ctx, int argc, char *argv[], char *col[]) for (i = 0; i < argc; i++) { if (os_strcmp(col[i], "password") == 0 && argv[i]) { - os_free(user->password); + bin_clear_free(user->password, user->password_len); user->password_len = os_strlen(argv[i]); user->password = (u8 *) os_strdup(argv[i]); user->next = (void *) 1; @@ -118,7 +118,7 @@ static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[]) if (len <= user->identity_len && os_memcmp(argv[id], user->identity, len) == 0 && (user->password == NULL || len > user->password_len)) { - os_free(user->password); + bin_clear_free(user->password, user->password_len); user->password_len = os_strlen(argv[id]); user->password = (u8 *) os_strdup(argv[id]); user->next = (void *) 1; @@ -158,8 +158,10 @@ eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity, return NULL; } - os_free(hapd->tmp_eap_user.identity); - os_free(hapd->tmp_eap_user.password); + bin_clear_free(hapd->tmp_eap_user.identity, + hapd->tmp_eap_user.identity_len); + bin_clear_free(hapd->tmp_eap_user.password, + hapd->tmp_eap_user.password_len); os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user)); hapd->tmp_eap_user.phase2 = phase2; hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1); diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index b406880..ad07107 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -414,7 +414,7 @@ static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf, gas_anqp_set_element_len(buf, realm_data_len); } gas_anqp_set_element_len(buf, len); - } else if (nai_home_realm && hapd->conf->nai_realm_data) { + } else if (nai_home_realm && hapd->conf->nai_realm_data && home_realm) { hs20_add_nai_home_realm_matches(hapd, buf, home_realm, home_realm_len); } @@ -686,7 +686,6 @@ static void anqp_add_icon_binary_file(struct hostapd_data *hapd, static struct wpabuf * gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, unsigned int request, - struct gas_dialog_info *di, const u8 *home_realm, size_t home_realm_len, const u8 *icon_name, size_t icon_name_len) { @@ -962,7 +961,7 @@ static void gas_serv_req_local_processing(struct hostapd_data *hapd, { struct wpabuf *buf, *tx_buf; - buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL, + buf = gas_serv_build_gas_resp_payload(hapd, qi->request, qi->home_realm_query, qi->home_realm_query_len, qi->icon_name, qi->icon_name_len); @@ -1214,13 +1213,11 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, { struct hostapd_data *hapd = ctx; const struct ieee80211_mgmt *mgmt; - size_t hdr_len; const u8 *sa, *data; int prot; mgmt = (const struct ieee80211_mgmt *) buf; - hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf; - if (hdr_len > len) + if (len < IEEE80211_HDRLEN + 2) return; if (mgmt->u.action.category != WLAN_ACTION_PUBLIC && mgmt->u.action.category != WLAN_ACTION_PROTECTED_DUAL) @@ -1232,8 +1229,8 @@ static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len, */ prot = mgmt->u.action.category == WLAN_ACTION_PROTECTED_DUAL; sa = mgmt->sa; - len -= hdr_len; - data = &mgmt->u.action.u.public_action.action; + len -= IEEE80211_HDRLEN + 1; + data = buf + IEEE80211_HDRLEN + 1; switch (data[0]) { case WLAN_PA_GAS_INITIAL_REQ: gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1, prot); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index ed73301..3142391 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -311,8 +311,10 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd) #endif /* CONFIG_INTERWORKING */ #ifdef CONFIG_SQLITE - os_free(hapd->tmp_eap_user.identity); - os_free(hapd->tmp_eap_user.password); + bin_clear_free(hapd->tmp_eap_user.identity, + hapd->tmp_eap_user.identity_len); + bin_clear_free(hapd->tmp_eap_user.password, + hapd->tmp_eap_user.password_len); #endif /* CONFIG_SQLITE */ } @@ -691,10 +693,10 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) u8 if_addr[ETH_ALEN]; wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)", - __func__, hapd, hapd->conf->iface, first); + __func__, hapd, conf->iface, first); #ifdef EAP_SERVER_TNC - if (hapd->conf->tnc && tncs_global_init() < 0) { + if (conf->tnc && tncs_global_init() < 0) { wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); return -1; } @@ -702,37 +704,37 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) if (hapd->started) { wpa_printf(MSG_ERROR, "%s: Interface %s was already started", - __func__, hapd->conf->iface); + __func__, conf->iface); return -1; } hapd->started = 1; if (!first || first == -1) { - if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) { + if (hostapd_mac_comp_empty(conf->bssid) == 0) { /* Allocate the next available BSSID. */ do { inc_byte_array(hapd->own_addr, ETH_ALEN); } while (mac_in_conf(hapd->iconf, hapd->own_addr)); } else { /* Allocate the configured BSSID. */ - os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN); + os_memcpy(hapd->own_addr, conf->bssid, ETH_ALEN); if (hostapd_mac_comp(hapd->own_addr, hapd->iface->bss[0]->own_addr) == 0) { wpa_printf(MSG_ERROR, "BSS '%s' may not have " "BSSID set to the MAC address of " - "the radio", hapd->conf->iface); + "the radio", conf->iface); return -1; } } hapd->interface_added = 1; if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS, - hapd->conf->iface, hapd->own_addr, hapd, + conf->iface, hapd->own_addr, hapd, &hapd->drv_priv, force_ifname, if_addr, - hapd->conf->bridge[0] ? hapd->conf->bridge : - NULL, first == -1)) { + conf->bridge[0] ? conf->bridge : NULL, + first == -1)) { wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID=" MACSTR ")", MAC2STR(hapd->own_addr)); hapd->interface_added = 0; @@ -747,7 +749,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) hostapd_set_privacy(hapd, 0); hostapd_broadcast_wep_clear(hapd); - if (hostapd_setup_encryption(hapd->conf->iface, hapd)) + if (hostapd_setup_encryption(conf->iface, hapd)) return -1; /* @@ -781,9 +783,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) if (!hostapd_drv_none(hapd)) { wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR " and ssid \"%s\"", - hapd->conf->iface, MAC2STR(hapd->own_addr), - wpa_ssid_txt(hapd->conf->ssid.ssid, - hapd->conf->ssid.ssid_len)); + conf->iface, MAC2STR(hapd->own_addr), + wpa_ssid_txt(conf->ssid.ssid, conf->ssid.ssid_len)); } if (hostapd_setup_wpa_psk(conf)) { @@ -808,17 +809,17 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (hapd->conf->radius_das_port) { + if (conf->radius_das_port) { struct radius_das_conf das_conf; os_memset(&das_conf, 0, sizeof(das_conf)); - das_conf.port = hapd->conf->radius_das_port; - das_conf.shared_secret = hapd->conf->radius_das_shared_secret; + das_conf.port = conf->radius_das_port; + das_conf.shared_secret = conf->radius_das_shared_secret; das_conf.shared_secret_len = - hapd->conf->radius_das_shared_secret_len; - das_conf.client_addr = &hapd->conf->radius_das_client_addr; - das_conf.time_window = hapd->conf->radius_das_time_window; + conf->radius_das_shared_secret_len; + das_conf.client_addr = &conf->radius_das_client_addr; + das_conf.time_window = conf->radius_das_time_window; das_conf.require_event_timestamp = - hapd->conf->radius_das_require_event_timestamp; + conf->radius_das_require_event_timestamp; das_conf.ctx = hapd; das_conf.disconnect = hostapd_das_disconnect; hapd->radius_das = radius_das_init(&das_conf); @@ -845,7 +846,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if ((hapd->conf->wpa || hapd->conf->osen) && hostapd_setup_wpa(hapd)) + if ((conf->wpa || conf->osen) && hostapd_setup_wpa(hapd)) return -1; if (accounting_init(hapd)) { @@ -853,8 +854,8 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (hapd->conf->ieee802_11f && - (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) { + if (conf->ieee802_11f && + (hapd->iapp = iapp_init(hapd, conf->iapp_iface)) == NULL) { wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization " "failed."); return -1; @@ -879,7 +880,7 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first) return -1; } - if (!hapd->conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) + if (!conf->start_disabled && ieee802_11_set_beacon(hapd) < 0) return -1; if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0) @@ -946,35 +947,24 @@ static void hostapd_set_acl(struct hostapd_data *hapd) if (hapd->iface->drv_max_acl_mac_addrs == 0) return; - if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac)) - return; if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) { - if (conf->bss[0]->num_accept_mac) { - accept_acl = 1; - err = hostapd_set_acl_list(hapd, - conf->bss[0]->accept_mac, - conf->bss[0]->num_accept_mac, - accept_acl); - if (err) { - wpa_printf(MSG_DEBUG, "Failed to set accept acl"); - return; - } - } else { - wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); + accept_acl = 1; + err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac, + conf->bss[0]->num_accept_mac, + accept_acl); + if (err) { + wpa_printf(MSG_DEBUG, "Failed to set accept acl"); + return; } } else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) { - if (conf->bss[0]->num_deny_mac) { - accept_acl = 0; - err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac, - conf->bss[0]->num_deny_mac, - accept_acl); - if (err) { - wpa_printf(MSG_DEBUG, "Failed to set deny acl"); - return; - } - } else { - wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file"); + accept_acl = 0; + err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac, + conf->bss[0]->num_deny_mac, + accept_acl); + if (err) { + wpa_printf(MSG_DEBUG, "Failed to set deny acl"); + return; } } } @@ -1191,12 +1181,15 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) iface->conf->channel, iface->freq); #ifdef NEED_AP_MLME - /* Check DFS */ - res = hostapd_handle_dfs(iface); - if (res <= 0) { - if (res < 0) - goto fail; - return res; + /* Handle DFS only if it is not offloaded to the driver */ + if (!(iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)) { + /* Check DFS */ + res = hostapd_handle_dfs(iface); + if (res <= 0) { + if (res < 0) + goto fail; + return res; + } } #endif /* NEED_AP_MLME */ @@ -2186,13 +2179,12 @@ static void free_beacon_data(struct beacon_data *beacon) } -static int hostapd_build_beacon_data(struct hostapd_iface *iface, +static int hostapd_build_beacon_data(struct hostapd_data *hapd, struct beacon_data *beacon) { struct wpabuf *beacon_extra, *proberesp_extra, *assocresp_extra; struct wpa_driver_ap_params params; int ret; - struct hostapd_data *hapd = iface->bss[0]; os_memset(beacon, 0, sizeof(*beacon)); ret = ieee802_11_build_ap_params(hapd, ¶ms); @@ -2292,13 +2284,13 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, if (!params->channel) { /* check if the new channel is supported by hw */ - channel = hostapd_hw_get_channel(hapd, params->freq); - if (!channel) - return -1; - } else { - channel = params->channel; + params->channel = hostapd_hw_get_channel(hapd, params->freq); } + channel = params->channel; + if (!channel) + return -1; + /* if a pointer to old_params is provided we save previous state */ if (old_params) { old_params->channel = conf->channel; @@ -2316,14 +2308,15 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd, } -static int hostapd_fill_csa_settings(struct hostapd_iface *iface, +static int hostapd_fill_csa_settings(struct hostapd_data *hapd, struct csa_settings *settings) { + struct hostapd_iface *iface = hapd->iface; struct hostapd_freq_params old_freq; int ret; os_memset(&old_freq, 0, sizeof(old_freq)); - if (!iface || !iface->freq || iface->csa_in_progress) + if (!iface || !iface->freq || hapd->csa_in_progress) return -1; ret = hostapd_change_config_freq(iface->bss[0], iface->conf, @@ -2332,7 +2325,7 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, if (ret) return ret; - ret = hostapd_build_beacon_data(iface, &settings->beacon_after); + ret = hostapd_build_beacon_data(hapd, &settings->beacon_after); /* change back the configuration */ hostapd_change_config_freq(iface->bss[0], iface->conf, @@ -2342,18 +2335,18 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, return ret; /* set channel switch parameters for csa ie */ - iface->cs_freq_params = settings->freq_params; - iface->cs_count = settings->cs_count; - iface->cs_block_tx = settings->block_tx; + hapd->cs_freq_params = settings->freq_params; + hapd->cs_count = settings->cs_count; + hapd->cs_block_tx = settings->block_tx; - ret = hostapd_build_beacon_data(iface, &settings->beacon_csa); + ret = hostapd_build_beacon_data(hapd, &settings->beacon_csa); if (ret) { free_beacon_data(&settings->beacon_after); return ret; } - settings->counter_offset_beacon = iface->cs_c_off_beacon; - settings->counter_offset_presp = iface->cs_c_off_proberesp; + settings->counter_offset_beacon = hapd->cs_c_off_beacon; + settings->counter_offset_presp = hapd->cs_c_off_proberesp; return 0; } @@ -2361,13 +2354,12 @@ static int hostapd_fill_csa_settings(struct hostapd_iface *iface, void hostapd_cleanup_cs_params(struct hostapd_data *hapd) { - os_memset(&hapd->iface->cs_freq_params, 0, - sizeof(hapd->iface->cs_freq_params)); - hapd->iface->cs_count = 0; - hapd->iface->cs_block_tx = 0; - hapd->iface->cs_c_off_beacon = 0; - hapd->iface->cs_c_off_proberesp = 0; - hapd->iface->csa_in_progress = 0; + os_memset(&hapd->cs_freq_params, 0, sizeof(hapd->cs_freq_params)); + hapd->cs_count = 0; + hapd->cs_block_tx = 0; + hapd->cs_c_off_beacon = 0; + hapd->cs_c_off_proberesp = 0; + hapd->csa_in_progress = 0; } @@ -2375,7 +2367,7 @@ int hostapd_switch_channel(struct hostapd_data *hapd, struct csa_settings *settings) { int ret; - ret = hostapd_fill_csa_settings(hapd->iface, settings); + ret = hostapd_fill_csa_settings(hapd, settings); if (ret) return ret; @@ -2389,8 +2381,64 @@ int hostapd_switch_channel(struct hostapd_data *hapd, return ret; } - hapd->iface->csa_in_progress = 1; + hapd->csa_in_progress = 1; return 0; } + +void +hostapd_switch_channel_fallback(struct hostapd_iface *iface, + const struct hostapd_freq_params *freq_params) +{ + int vht_seg0_idx = 0, vht_seg1_idx = 0, vht_bw = VHT_CHANWIDTH_USE_HT; + unsigned int i; + + wpa_printf(MSG_DEBUG, "Restarting all CSA-related BSSes"); + + if (freq_params->center_freq1) + vht_seg0_idx = 36 + (freq_params->center_freq1 - 5180) / 5; + if (freq_params->center_freq2) + vht_seg1_idx = 36 + (freq_params->center_freq2 - 5180) / 5; + + switch (freq_params->bandwidth) { + case 0: + case 20: + case 40: + vht_bw = VHT_CHANWIDTH_USE_HT; + break; + case 80: + if (freq_params->center_freq2) + vht_bw = VHT_CHANWIDTH_80P80MHZ; + else + vht_bw = VHT_CHANWIDTH_80MHZ; + break; + case 160: + vht_bw = VHT_CHANWIDTH_160MHZ; + break; + default: + wpa_printf(MSG_WARNING, "Unknown CSA bandwidth: %d", + freq_params->bandwidth); + break; + } + + iface->freq = freq_params->freq; + iface->conf->channel = freq_params->channel; + iface->conf->secondary_channel = freq_params->sec_channel_offset; + iface->conf->vht_oper_centr_freq_seg0_idx = vht_seg0_idx; + iface->conf->vht_oper_centr_freq_seg1_idx = vht_seg1_idx; + iface->conf->vht_oper_chwidth = vht_bw; + iface->conf->ieee80211n = freq_params->ht_enabled; + iface->conf->ieee80211ac = freq_params->vht_enabled; + + /* + * cs_params must not be cleared earlier because the freq_params + * argument may actually point to one of these. + */ + for (i = 0; i < iface->num_bss; i++) + hostapd_cleanup_cs_params(iface->bss[i]); + + hostapd_disable_iface(iface); + hostapd_enable_iface(iface); +} + #endif /* NEED_AP_MLME */ diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index bd85c54..3c8727b 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -210,6 +210,14 @@ struct hostapd_data { size_t psk_len); void *new_psk_cb_ctx; + /* channel switch parameters */ + struct hostapd_freq_params cs_freq_params; + u8 cs_count; + int cs_block_tx; + unsigned int cs_c_off_beacon; + unsigned int cs_c_off_proberesp; + int csa_in_progress; + #ifdef CONFIG_P2P struct p2p_data *p2p; struct p2p_group *p2p_group; @@ -343,14 +351,6 @@ struct hostapd_iface { /* lowest observed noise floor in dBm */ s8 lowest_nf; - /* channel switch parameters */ - struct hostapd_freq_params cs_freq_params; - u8 cs_count; - int cs_block_tx; - unsigned int cs_c_off_beacon; - unsigned int cs_c_off_proberesp; - int csa_in_progress; - unsigned int dfs_cac_ms; struct os_reltime dfs_cac_start; @@ -397,6 +397,9 @@ void hostapd_set_state(struct hostapd_iface *iface, enum hostapd_iface_state s); const char * hostapd_state_text(enum hostapd_iface_state s); int hostapd_switch_channel(struct hostapd_data *hapd, struct csa_settings *settings); +void +hostapd_switch_channel_fallback(struct hostapd_iface *iface, + const struct hostapd_freq_params *freq_params); void hostapd_cleanup_cs_params(struct hostapd_data *hapd); /* utils.c */ diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index ca8db8f..de1ee5e 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -236,7 +236,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta, /* Transaction 3 */ if (!iswep || !sta->challenge || !challenge || - os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) { + os_memcmp_const(sta->challenge, challenge, + WLAN_AUTH_CHALLENGE_LEN)) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_INFO, "shared key authentication - invalid " @@ -402,7 +403,7 @@ static int check_sae_token(struct hostapd_data *hapd, const u8 *addr, return -1; if (hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key), addr, ETH_ALEN, mac) < 0 || - os_memcmp(token, mac, SHA256_MAC_LEN) != 0) + os_memcmp_const(token, mac, SHA256_MAC_LEN) != 0) return -1; return 0; diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index c0a7cd4..fe87883 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -211,8 +211,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, struct ieee80211_2040_intol_chan_report *ic_report; int is_ht_allowed = 1; int i; - const u8 *data = (const u8 *) &mgmt->u.action.u.public_action.action; - size_t hdr_len; + const u8 *data = ((const u8 *) mgmt) + 1; hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d", @@ -221,8 +220,7 @@ void hostapd_2040_coex_action(struct hostapd_data *hapd, if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) return; - hdr_len = data - (u8 *) mgmt; - if (hdr_len > len) + if (len < IEEE80211_HDRLEN + 1) return; data++; diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c index 221d9c2..437cf50 100644 --- a/src/ap/ieee802_11_vht.c +++ b/src/ap/ieee802_11_vht.c @@ -112,25 +112,11 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, const u8 *vht_oper_notif) { - u8 channel_width; - if (!vht_oper_notif) { sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; return WLAN_STATUS_SUCCESS; } - channel_width = *vht_oper_notif & VHT_OPMODE_CHANNEL_WIDTH_MASK; - - if (channel_width != VHT_CHANWIDTH_USE_HT && - channel_width != VHT_CHANWIDTH_80MHZ && - channel_width != VHT_CHANWIDTH_160MHZ && - channel_width != VHT_CHANWIDTH_80P80MHZ && - ((*vht_oper_notif & VHT_OPMODE_CHANNEL_RxNSS_MASK) >> - VHT_OPMODE_NOTIF_RX_NSS_SHIFT) > VHT_RX_NSS_MAX_STREAMS - 1) { - sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; - return WLAN_STATUS_UNSPECIFIED_FAILURE; - } - sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED; sta->vht_opmode = *vht_oper_notif; return WLAN_STATUS_SUCCESS; diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 035415f..2d09b67 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -306,6 +306,67 @@ static void ieee802_1x_learn_identity(struct hostapd_data *hapd, } +static int add_common_radius_sta_attr_rsn(struct hostapd_data *hapd, + struct hostapd_radius_attr *req_attr, + struct sta_info *sta, + struct radius_msg *msg) +{ + u32 suite; + int ver, val; + + ver = wpa_auth_sta_wpa_version(sta->wpa_sm); + val = wpa_auth_get_pairwise(sta->wpa_sm); + suite = wpa_cipher_to_suite(ver, val); + if (val != -1 && + !hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_WLAN_PAIRWISE_CIPHER) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, + suite)) { + wpa_printf(MSG_ERROR, "Could not add WLAN-Pairwise-Cipher"); + return -1; + } + + suite = wpa_cipher_to_suite((hapd->conf->wpa & 0x2) ? + WPA_PROTO_RSN : WPA_PROTO_WPA, + hapd->conf->wpa_group); + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_WLAN_GROUP_CIPHER) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_GROUP_CIPHER, + suite)) { + wpa_printf(MSG_ERROR, "Could not add WLAN-Group-Cipher"); + return -1; + } + + val = wpa_auth_sta_key_mgmt(sta->wpa_sm); + suite = wpa_akm_to_suite(val); + if (val != -1 && + !hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_WLAN_AKM_SUITE) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE, + suite)) { + wpa_printf(MSG_ERROR, "Could not add WLAN-AKM-Suite"); + return -1; + } + +#ifdef CONFIG_IEEE80211W + if (hapd->conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) { + suite = wpa_cipher_to_suite(WPA_PROTO_RSN, + hapd->conf->group_mgmt_cipher); + if (!hostapd_config_get_radius_attr( + req_attr, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER) && + !radius_msg_add_attr_int32( + msg, RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, suite)) { + wpa_printf(MSG_ERROR, + "Could not add WLAN-Group-Mgmt-Cipher"); + return -1; + } + } +#endif /* CONFIG_IEEE80211W */ + + return 0; +} + + static int add_common_radius_sta_attr(struct hostapd_data *hapd, struct hostapd_radius_attr *req_attr, struct sta_info *sta, @@ -357,6 +418,25 @@ static int add_common_radius_sta_attr(struct hostapd_data *hapd, } } +#ifdef CONFIG_IEEE80211R + if (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) && + sta->wpa_sm && + (wpa_key_mgmt_ft(wpa_auth_sta_key_mgmt(sta->wpa_sm)) || + sta->auth_alg == WLAN_AUTH_FT) && + !hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_MOBILITY_DOMAIN_ID) && + !radius_msg_add_attr_int32(msg, RADIUS_ATTR_MOBILITY_DOMAIN_ID, + WPA_GET_BE16( + hapd->conf->mobility_domain))) { + wpa_printf(MSG_ERROR, "Could not add Mobility-Domain-Id"); + return -1; + } +#endif /* CONFIG_IEEE80211R */ + + if (hapd->conf->wpa && sta->wpa_sm && + add_common_radius_sta_attr_rsn(hapd, req_attr, sta, msg) < 0) + return -1; + return 0; } @@ -420,6 +500,22 @@ int add_common_radius_attr(struct hostapd_data *hapd, return -1; } +#ifdef CONFIG_INTERWORKING + if (hapd->conf->interworking && + !is_zero_ether_addr(hapd->conf->hessid)) { + os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, + MAC2STR(hapd->conf->hessid)); + buf[sizeof(buf) - 1] = '\0'; + if (!hostapd_config_get_radius_attr(req_attr, + RADIUS_ATTR_WLAN_HESSID) && + !radius_msg_add_attr(msg, RADIUS_ATTR_WLAN_HESSID, + (u8 *) buf, os_strlen(buf))) { + wpa_printf(MSG_ERROR, "Could not add WLAN-HESSID"); + return -1; + } + } +#endif /* CONFIG_INTERWORKING */ + if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0) return -1; @@ -1526,6 +1622,9 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req, if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0) break; + sta->session_timeout_set = !!session_timeout_set; + sta->session_timeout = session_timeout; + /* RFC 3580, Ch. 3.17 */ if (session_timeout_set && termination_action == RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) { @@ -2300,6 +2399,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, size_t len; /* TODO: get PMKLifetime from WPA parameters */ static const int dot11RSNAConfigPMKLifetime = 43200; + unsigned int session_timeout; #ifdef CONFIG_HS20 if (remediation && !sta->remediation) { @@ -2334,9 +2434,13 @@ static void ieee802_1x_finished(struct hostapd_data *hapd, #endif /* CONFIG_HS20 */ key = ieee802_1x_get_key(sta->eapol_sm, &len); + if (sta->session_timeout_set) + session_timeout = sta->session_timeout; + else + session_timeout = dot11RSNAConfigPMKLifetime; if (success && key && len >= PMK_LEN && !sta->remediation && !sta->hs20_deauth_requested && - wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime, + wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout, sta->eapol_sm) == 0) { hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA, HOSTAPD_LEVEL_DEBUG, diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index 4720b59..9de4cff 100644 --- a/src/ap/pmksa_cache_auth.c +++ b/src/ap/pmksa_cache_auth.c @@ -37,14 +37,12 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { - if (entry == NULL) - return; os_free(entry->identity); wpabuf_free(entry->cui); #ifndef CONFIG_NO_RADIUS radius_free_class(&entry->radius_class); #endif /* CONFIG_NO_RADIUS */ - os_free(entry); + bin_clear_free(entry, sizeof(*entry)); } @@ -52,38 +50,42 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry) { struct rsn_pmksa_cache_entry *pos, *prev; + unsigned int hash; pmksa->pmksa_count--; pmksa->free_cb(entry, pmksa->ctx); - pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; + + /* unlink from hash list */ + hash = PMKID_HASH(entry->pmkid); + pos = pmksa->pmkid[hash]; prev = NULL; while (pos) { if (pos == entry) { - if (prev != NULL) { - prev->hnext = pos->hnext; - } else { - pmksa->pmkid[PMKID_HASH(entry->pmkid)] = - pos->hnext; - } + if (prev != NULL) + prev->hnext = entry->hnext; + else + pmksa->pmkid[hash] = entry->hnext; break; } prev = pos; pos = pos->hnext; } + /* unlink from entry list */ pos = pmksa->pmksa; prev = NULL; while (pos) { if (pos == entry) { if (prev != NULL) - prev->next = pos->next; + prev->next = entry->next; else - pmksa->pmksa = pos->next; + pmksa->pmksa = entry->next; break; } prev = pos; pos = pos->next; } + _pmksa_cache_free_entry(entry); } @@ -188,6 +190,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, struct rsn_pmksa_cache_entry *entry) { struct rsn_pmksa_cache_entry *pos, *prev; + int hash; /* Add the new entry; order by expiration time */ pos = pmksa->pmksa; @@ -205,8 +208,10 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa, entry->next = prev->next; prev->next = entry; } - entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)]; - pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry; + + hash = PMKID_HASH(entry->pmkid); + entry->hnext = pmksa->pmkid[hash]; + pmksa->pmkid[hash] = entry; pmksa->pmksa_count++; if (prev == NULL) @@ -342,6 +347,8 @@ void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa) _pmksa_cache_free_entry(prev); } eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL); + pmksa->pmksa_count = 0; + pmksa->pmksa = NULL; for (i = 0; i < PMKID_HASH_SIZE; i++) pmksa->pmkid[i] = NULL; os_free(pmksa); @@ -361,18 +368,22 @@ pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *entry; - if (pmkid) - entry = pmksa->pmkid[PMKID_HASH(pmkid)]; - else - entry = pmksa->pmksa; - while (entry) { - if ((spa == NULL || - os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && - (pmkid == NULL || - os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0)) - return entry; - entry = pmkid ? entry->hnext : entry->next; + if (pmkid) { + for (entry = pmksa->pmkid[PMKID_HASH(pmkid)]; entry; + entry = entry->hnext) { + if ((spa == NULL || + os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && + os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) + return entry; + } + } else { + for (entry = pmksa->pmksa; entry; entry = entry->next) { + if (spa == NULL || + os_memcmp(entry->spa, spa, ETH_ALEN) == 0) + return entry; + } } + return NULL; } @@ -394,15 +405,13 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc( struct rsn_pmksa_cache_entry *entry; u8 new_pmkid[PMKID_LEN]; - entry = pmksa->pmksa; - while (entry) { + for (entry = pmksa->pmksa; entry; entry = entry->next) { if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0) continue; rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid, wpa_key_mgmt_sha256(entry->akmp)); if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0) return entry; - entry = entry->next; } return NULL; } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 60f0768..efd2a72 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -956,12 +956,12 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, dev_addr = addr; } else dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr); -#endif /* CONFIG_P2P */ if (dev_addr) os_snprintf(buf, sizeof(buf), MACSTR " p2p_dev_addr=" MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr)); else +#endif /* CONFIG_P2P */ os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr)); if (authorized) { diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index 03db98f..faf32d8 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -60,6 +60,7 @@ struct sta_info { unsigned int qos_map_enabled:1; unsigned int remediation:1; unsigned int hs20_deauth_requested:1; + unsigned int session_timeout_set:1; u16 auth_alg; @@ -135,6 +136,8 @@ struct sta_info { #ifdef CONFIG_SAE struct sae_data *sae; #endif /* CONFIG_SAE */ + + u32 session_timeout; /* valid only if session_timeout_set == 1 */ }; diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 8e5bdcb..cf25dbb 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -376,10 +376,9 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, if (len < IEEE80211_HDRLEN + 2) return -1; - payload = &mgmt->u.action.category; - payload++; + payload = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 1; action = *payload++; - plen = (((const u8 *) mgmt) + len) - payload; + plen = len - IEEE80211_HDRLEN - 2; switch (action) { case WNM_BSS_TRANS_MGMT_QUERY: diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index a9cd6f6..1a16b5c 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1390,7 +1390,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES || sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { - if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf, + if (aes_wrap(sm->PTK.kek, 16, + (key_data_len - 8) / 8, buf, (u8 *) (key + 1))) { os_free(hdr); os_free(buf); @@ -1490,7 +1491,7 @@ static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len) os_memset(key->key_mic, 0, 16); if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, data_len, key->key_mic) || - os_memcmp(mic, key->key_mic, 16) != 0) + os_memcmp_const(mic, key->key_mic, 16) != 0) ret = -1; os_memcpy(key->key_mic, mic, 16); return ret; @@ -1877,8 +1878,8 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING) * Verify that PMKR1Name from EAPOL-Key message 2/4 matches * with the value we derived. */ - if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name, - WPA_PMK_NAME_LEN) != 0) { + if (os_memcmp_const(sm->sup_pmk_r1_name, sm->pmk_r1_name, + WPA_PMK_NAME_LEN) != 0) { wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, "PMKR1Name mismatch in FT 4-way " "handshake"); diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c index a80bbb7..781f15f 100644 --- a/src/ap/wpa_auth_ft.c +++ b/src/ap/wpa_auth_ft.c @@ -235,8 +235,8 @@ static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth, r0 = cache->pmk_r0; while (r0) { if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 && - os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN) - == 0) { + os_memcmp_const(r0->pmk_r0_name, pmk_r0_name, + WPA_PMK_NAME_LEN) == 0) { os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN); if (pairwise) *pairwise = r0->pairwise; @@ -285,8 +285,8 @@ static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth, r1 = cache->pmk_r1; while (r1) { if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 && - os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN) - == 0) { + os_memcmp_const(r1->pmk_r1_name, pmk_r1_name, + WPA_PMK_NAME_LEN) == 0) { os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN); if (pairwise) *pairwise = r1->pairwise; @@ -310,7 +310,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, r0kh = sm->wpa_auth->conf.r0kh_list; while (r0kh) { if (r0kh->id_len == sm->r0kh_id_len && - os_memcmp(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) == 0) + os_memcmp_const(r0kh->id, sm->r0kh_id, sm->r0kh_id_len) == + 0) break; r0kh = r0kh->next; } @@ -343,7 +344,8 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, os_memcpy(f.s1kh_id, sm->addr, ETH_ALEN); os_memset(f.pad, 0, sizeof(f.pad)); - if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, + if (aes_wrap(r0kh->key, sizeof(r0kh->key), + (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, f.nonce, frame.nonce) < 0) return -1; @@ -458,7 +460,7 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); subelem[4] = gsm->GTK_len; wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5); - if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { + if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) { os_free(subelem); return NULL; } @@ -490,7 +492,7 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos); pos += 6; *pos++ = WPA_IGTK_LEN; - if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8, + if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8, gsm->IGTK[gsm->GN_igtk - 4], pos)) { os_free(subelem); return NULL; @@ -1013,8 +1015,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_INVALID_PMKID; } - if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) - { + if (os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) + != 0) { wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match " "with the PMKR1Name derived from auth request"); return WLAN_STATUS_INVALID_PMKID; @@ -1060,7 +1062,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, } if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { + os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) + { wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " "the current R0KH-ID"); wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", @@ -1075,8 +1078,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return -1; } - if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, - FT_R1KH_ID_LEN) != 0) { + if (os_memcmp_const(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder, + FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " "ReassocReq"); wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE", @@ -1087,7 +1090,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, } if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { + os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) + { wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); return -1; @@ -1113,7 +1117,7 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, return WLAN_STATUS_UNSPECIFIED_FAILURE; } - if (os_memcmp(mic, ftie->mic, 16) != 0) { + if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR, MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr)); @@ -1333,7 +1337,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, frame = (struct ft_r0kh_r1kh_pull_frame *) data; /* aes_unwrap() does not support inplace decryption, so use a temporary * buffer for the data. */ - if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, + if (aes_unwrap(r1kh->key, sizeof(r1kh->key), + (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8, frame->nonce, f.nonce) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " "request from " MACSTR, MAC2STR(src_addr)); @@ -1373,7 +1378,8 @@ static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth, r.pairwise = host_to_le16(pairwise); os_memset(r.pad, 0, sizeof(r.pad)); - if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, + if (aes_wrap(r1kh->key, sizeof(r1kh->key), + (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, r.nonce, resp.nonce) < 0) { os_memset(pmk_r0, 0, PMK_LEN); return -1; @@ -1461,15 +1467,16 @@ static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth, frame = (struct ft_r0kh_r1kh_resp_frame *) data; /* aes_unwrap() does not support inplace decryption, so use a temporary * buffer for the data. */ - if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, + if (aes_unwrap(r0kh->key, sizeof(r0kh->key), + (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8, frame->nonce, f.nonce) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull " "response from " MACSTR, MAC2STR(src_addr)); return -1; } - if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) - != 0) { + if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder, + FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a " "matching R1KH-ID"); return -1; @@ -1527,7 +1534,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, frame = (struct ft_r0kh_r1kh_push_frame *) data; /* aes_unwrap() does not support inplace decryption, so use a temporary * buffer for the data. */ - if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, + if (aes_unwrap(r0kh->key, sizeof(r0kh->key), + (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, frame->timestamp, f.timestamp) < 0) { wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from " MACSTR, MAC2STR(src_addr)); @@ -1544,8 +1552,8 @@ static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth, return -1; } - if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN) - != 0) { + if (os_memcmp_const(f.r1kh_id, wpa_auth->conf.r1_key_holder, + FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching " "R1KH-ID (received " MACSTR " own " MACSTR ")", MAC2STR(f.r1kh_id), @@ -1686,6 +1694,11 @@ int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr, return -1; } + if (end > pos) { + wpa_hexdump(MSG_DEBUG, "FT: Ignore extra data in end", + pos, end - pos); + } + return 0; } @@ -1719,7 +1732,8 @@ static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth, WPA_PUT_LE32(f.timestamp, now.sec); f.pairwise = host_to_le16(pairwise); os_memset(f.pad, 0, sizeof(f.pad)); - if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, + if (aes_wrap(r1kh->key, sizeof(r1kh->key), + (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8, f.timestamp, frame.timestamp) < 0) return; diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index faa6a39..173a400 100644 --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -546,3 +546,60 @@ int supp_rates_11b_only(struct ieee802_11_elems *elems) return num_11b > 0 && num_others == 0; } + + +const char * fc2str(u16 fc) +{ + u16 stype = WLAN_FC_GET_STYPE(fc); +#define C2S(x) case x: return #x; + + switch (WLAN_FC_GET_TYPE(fc)) { + case WLAN_FC_TYPE_MGMT: + switch (stype) { + C2S(WLAN_FC_STYPE_ASSOC_REQ) + C2S(WLAN_FC_STYPE_ASSOC_RESP) + C2S(WLAN_FC_STYPE_REASSOC_REQ) + C2S(WLAN_FC_STYPE_REASSOC_RESP) + C2S(WLAN_FC_STYPE_PROBE_REQ) + C2S(WLAN_FC_STYPE_PROBE_RESP) + C2S(WLAN_FC_STYPE_BEACON) + C2S(WLAN_FC_STYPE_ATIM) + C2S(WLAN_FC_STYPE_DISASSOC) + C2S(WLAN_FC_STYPE_AUTH) + C2S(WLAN_FC_STYPE_DEAUTH) + C2S(WLAN_FC_STYPE_ACTION) + } + break; + case WLAN_FC_TYPE_CTRL: + switch (stype) { + C2S(WLAN_FC_STYPE_PSPOLL) + C2S(WLAN_FC_STYPE_RTS) + C2S(WLAN_FC_STYPE_CTS) + C2S(WLAN_FC_STYPE_ACK) + C2S(WLAN_FC_STYPE_CFEND) + C2S(WLAN_FC_STYPE_CFENDACK) + } + break; + case WLAN_FC_TYPE_DATA: + switch (stype) { + C2S(WLAN_FC_STYPE_DATA) + C2S(WLAN_FC_STYPE_DATA_CFACK) + C2S(WLAN_FC_STYPE_DATA_CFPOLL) + C2S(WLAN_FC_STYPE_DATA_CFACKPOLL) + C2S(WLAN_FC_STYPE_NULLFUNC) + C2S(WLAN_FC_STYPE_CFACK) + C2S(WLAN_FC_STYPE_CFPOLL) + C2S(WLAN_FC_STYPE_CFACKPOLL) + C2S(WLAN_FC_STYPE_QOS_DATA) + C2S(WLAN_FC_STYPE_QOS_DATA_CFACK) + C2S(WLAN_FC_STYPE_QOS_DATA_CFPOLL) + C2S(WLAN_FC_STYPE_QOS_DATA_CFACKPOLL) + C2S(WLAN_FC_STYPE_QOS_NULL) + C2S(WLAN_FC_STYPE_QOS_CFPOLL) + C2S(WLAN_FC_STYPE_QOS_CFACKPOLL) + } + break; + } + return "WLAN_FC_TYPE_UNKNOWN"; +#undef C2S +} diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 9b8bbd1..cf83057 100644 --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -98,4 +98,5 @@ enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel); int supp_rates_11b_only(struct ieee802_11_elems *elems); +const char * fc2str(u16 fc); #endif /* IEEE802_11_COMMON_H */ diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index b8e9254..6de71e9 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -809,6 +809,7 @@ struct ieee80211_vht_operation { #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 +#define WMM_IE_VENDOR_TYPE 0x0050f202 #define WPS_IE_VENDOR_TYPE 0x0050f204 #define OUI_WFA 0x506f9a #define P2P_IE_VENDOR_TYPE 0x506f9a09 diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h index a56b188..ad3bdfd 100644 --- a/src/common/qca-vendor.h +++ b/src/common/qca-vendor.h @@ -32,6 +32,13 @@ enum qca_radiotap_vendor_ids { * * @QCA_NL80211_VENDOR_SUBCMD_TEST: Test command/event * + * @QCA_NL80211_VENDOR_SUBCMD_ROAMING: Set roaming policy for drivers that use + * internal BSS-selection. This command uses + * @QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY to specify the new roaming policy + * for the current connection (i.e., changes policy set by the nl80211 + * Connect command). @QCA_WLAN_VENDOR_ATTR_MAC_ADDR may optionally be + * included to indicate which BSS to use in case roaming is disabled. + * * @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY: Recommendation of frequency * ranges to avoid to reduce issues due to interference or internal * co-existence information in the driver. The event data structure is @@ -47,12 +54,13 @@ enum qca_radiotap_vendor_ids { enum qca_nl80211_vendor_subcmds { QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0, QCA_NL80211_VENDOR_SUBCMD_TEST = 1, - /* subcmds 2..9 not yet allocated */ + /* subcmds 2..8 not yet allocated */ + QCA_NL80211_VENDOR_SUBCMD_ROAMING = 9, QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY = 10, QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY = 11, QCA_NL80211_VENDOR_SUBCMD_NAN = 12, QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13, - /* 14..19 - reserved for QCA */ + /* 14..49 - reserved for QCA */ }; @@ -64,9 +72,21 @@ enum qca_wlan_vendor_attr { QCA_WLAN_VENDOR_ATTR_NAN = 2, /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */ QCA_WLAN_VENDOR_ATTR_STATS_EXT = 3, + /* used by QCA_NL80211_VENDOR_SUBCMD_STATS_EXT */ + QCA_WLAN_VENDOR_ATTR_IFINDEX = 4, + /* used by QCA_NL80211_VENDOR_SUBCMD_ROAMING, u32 with values defined + * by enum qca_roaming_policy. */ + QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5, + QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6, /* keep last */ QCA_WLAN_VENDOR_ATTR_AFTER_LAST, QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1, }; + +enum qca_roaming_policy { + QCA_ROAMING_NOT_ALLOWED, + QCA_ROAMING_ALLOWED_WITHIN_ESS, +}; + #endif /* QCA_VENDOR_H */ diff --git a/src/common/sae.c b/src/common/sae.c index c1b488e..b67623f 100644 --- a/src/common/sae.c +++ b/src/common/sae.c @@ -1051,7 +1051,7 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len) sae->tmp->own_commit_element_ffc, verifier); - if (os_memcmp(verifier, data + 2, SHA256_MAC_LEN) != 0) { + if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) { wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch"); wpa_hexdump(MSG_DEBUG, "SAE: Received confirm", data + 2, SHA256_MAC_LEN); diff --git a/src/common/version.h b/src/common/version.h index 340afc7..726289d 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -5,6 +5,6 @@ #define VERSION_STR_POSTFIX "" #endif /* VERSION_STR_POSTFIX */ -#define VERSION_STR "2.2" VERSION_STR_POSTFIX +#define VERSION_STR "2.3" VERSION_STR_POSTFIX #endif /* VERSION_H */ diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index adb22c7..7aeb706 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -1002,6 +1002,30 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) } +u32 wpa_akm_to_suite(int akm) +{ + if (akm & WPA_KEY_MGMT_FT_IEEE8021X) + return WLAN_AKM_SUITE_FT_8021X; + if (akm & WPA_KEY_MGMT_FT_PSK) + return WLAN_AKM_SUITE_FT_PSK; + if (akm & WPA_KEY_MGMT_IEEE8021X) + return WLAN_AKM_SUITE_8021X; + if (akm & WPA_KEY_MGMT_IEEE8021X_SHA256) + return WLAN_AKM_SUITE_8021X_SHA256; + if (akm & WPA_KEY_MGMT_IEEE8021X) + return WLAN_AKM_SUITE_8021X; + if (akm & WPA_KEY_MGMT_PSK_SHA256) + return WLAN_AKM_SUITE_PSK_SHA256; + if (akm & WPA_KEY_MGMT_PSK) + return WLAN_AKM_SUITE_PSK; + if (akm & WPA_KEY_MGMT_CCKM) + return WLAN_AKM_SUITE_CCKM; + if (akm & WPA_KEY_MGMT_OSEN) + return WLAN_AKM_SUITE_OSEN; + return 0; +} + + int wpa_compare_rsn_ie(int ft_initial_assoc, const u8 *ie1, size_t ie1len, const u8 *ie2, size_t ie2len) diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index c0b2caa..0ef5a9d 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -377,6 +377,7 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa, const char * wpa_cipher_txt(int cipher); const char * wpa_key_mgmt_txt(int key_mgmt, int proto); +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); diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 534bc99..4812f8d 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -239,6 +239,25 @@ extern "C" { #define WPA_BSS_MASK_DELIM BIT(17) +/* VENDOR_ELEM_* frame id values */ +enum wpa_vendor_elem_frame { + VENDOR_ELEM_PROBE_REQ_P2P = 0, + VENDOR_ELEM_PROBE_RESP_P2P = 1, + VENDOR_ELEM_PROBE_RESP_P2P_GO = 2, + VENDOR_ELEM_BEACON_P2P_GO = 3, + VENDOR_ELEM_P2P_PD_REQ = 4, + VENDOR_ELEM_P2P_PD_RESP = 5, + VENDOR_ELEM_P2P_GO_NEG_REQ = 6, + VENDOR_ELEM_P2P_GO_NEG_RESP = 7, + VENDOR_ELEM_P2P_GO_NEG_CONF = 8, + VENDOR_ELEM_P2P_INV_REQ = 9, + VENDOR_ELEM_P2P_INV_RESP = 10, + VENDOR_ELEM_P2P_ASSOC_REQ = 11, + VENDOR_ELEM_P2P_ASSOC_RESP = 12, + NUM_VENDOR_ELEM_FRAMES +}; + + /* wpa_supplicant/hostapd control interface access */ /** @@ -326,9 +345,10 @@ int wpa_ctrl_detach(struct wpa_ctrl *ctrl); * @reply_len: Length of the reply buffer * Returns: 0 on success, -1 on failure * - * This function will receive a pending control interface message. This - * function will block if no messages are available. The received response will - * be written to reply and reply_len is set to the actual length of the reply. + * This function will receive a pending control interface message. The received + * response will be written to reply and reply_len is set to the actual length + * of the reply. + * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach() * must have been used to register the control interface as an event monitor. */ diff --git a/src/crypto/aes-ccm.c b/src/crypto/aes-ccm.c index d14670d..cf22778 100644 --- a/src/crypto/aes-ccm.c +++ b/src/crypto/aes-ccm.c @@ -203,7 +203,7 @@ int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce, aes_encrypt_deinit(aes); - if (os_memcmp(x, t, M) != 0) { + if (os_memcmp_const(x, t, M) != 0) { wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch"); return -1; } diff --git a/src/crypto/aes-gcm.c b/src/crypto/aes-gcm.c index 3d91c71..84294d2 100644 --- a/src/crypto/aes-gcm.c +++ b/src/crypto/aes-gcm.c @@ -310,7 +310,7 @@ int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len, aes_encrypt_deinit(aes); - if (os_memcmp(tag, T, 16) != 0) { + if (os_memcmp_const(tag, T, 16) != 0) { wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch"); return -1; } diff --git a/src/crypto/aes-unwrap.c b/src/crypto/aes-unwrap.c index 9dd5160..ec793d9 100644 --- a/src/crypto/aes-unwrap.c +++ b/src/crypto/aes-unwrap.c @@ -1,5 +1,5 @@ /* - * AES key unwrap (128-bit KEK, RFC3394) + * AES key unwrap (RFC3394) * * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> * @@ -14,26 +14,29 @@ #include "aes_wrap.h" /** - * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (RFC3394) * @kek: Key encryption key (KEK) + * @kek_len: Length of KEK in octets * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 * bytes * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits * @plain: Plaintext key, n * 64 bits * Returns: 0 on success, -1 on failure (e.g., integrity verification failed) */ -int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) +int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher, + u8 *plain) { - u8 a[8], *r, b[16]; + u8 a[8], *r, b[AES_BLOCK_SIZE]; int i, j; void *ctx; + unsigned int t; /* 1) Initialize variables. */ os_memcpy(a, cipher, 8); r = plain; os_memcpy(r, cipher + 8, 8 * n); - ctx = aes_decrypt_init(kek, 16); + ctx = aes_decrypt_init(kek, kek_len); if (ctx == NULL) return -1; @@ -48,7 +51,11 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain) r = plain + (n - 1) * 8; for (i = n; i >= 1; i--) { os_memcpy(b, a, 8); - b[7] ^= n * j + i; + t = n * j + i; + b[7] ^= t; + b[6] ^= t >> 8; + b[5] ^= t >> 16; + b[4] ^= t >> 24; os_memcpy(b + 8, r, 8); aes_decrypt(ctx, b, b); diff --git a/src/crypto/aes-wrap.c b/src/crypto/aes-wrap.c index 89d6f94..7ed34e8 100644 --- a/src/crypto/aes-wrap.c +++ b/src/crypto/aes-wrap.c @@ -1,5 +1,5 @@ /* - * AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * AES Key Wrap Algorithm (RFC3394) * * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> * @@ -14,19 +14,21 @@ #include "aes_wrap.h" /** - * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394) - * @kek: 16-octet Key encryption key (KEK) + * aes_wrap - Wrap keys with AES Key Wrap Algorithm (RFC3394) + * @kek: Key encryption key (KEK) + * @kek_len: Length of KEK in octets * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16 * bytes * @plain: Plaintext key to be wrapped, n * 64 bits * @cipher: Wrapped key, (n + 1) * 64 bits * Returns: 0 on success, -1 on failure */ -int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) +int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher) { - u8 *a, *r, b[16]; + u8 *a, *r, b[AES_BLOCK_SIZE]; int i, j; void *ctx; + unsigned int t; a = cipher; r = cipher + 8; @@ -35,7 +37,7 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) os_memset(a, 0xa6, 8); os_memcpy(r, plain, 8 * n); - ctx = aes_encrypt_init(kek, 16); + ctx = aes_encrypt_init(kek, kek_len); if (ctx == NULL) return -1; @@ -53,7 +55,11 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher) os_memcpy(b + 8, r, 8); aes_encrypt(ctx, b, b); os_memcpy(a, b, 8); - a[7] ^= n * j + i; + t = n * j + i; + a[7] ^= t; + a[6] ^= t >> 8; + a[5] ^= t >> 16; + a[4] ^= t >> 24; os_memcpy(r, b + 8, 8); r += 8; } diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h index 0433c04..6b3727c 100644 --- a/src/crypto/aes_wrap.h +++ b/src/crypto/aes_wrap.h @@ -1,7 +1,7 @@ /* * AES-based functions * - * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394) + * - AES Key Wrap Algorithm (RFC3394) * - One-Key CBC MAC (OMAC1) hash with AES-128 * - AES-128 CTR mode encryption * - AES-128 EAX mode encryption/decryption @@ -18,8 +18,10 @@ #ifndef AES_WRAP_H #define AES_WRAP_H -int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher); -int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain); +int __must_check aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, + u8 *cipher); +int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n, + const u8 *cipher, u8 *plain); int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac); diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c index 817ee2d..b4c59d1 100644 --- a/src/crypto/crypto_openssl.c +++ b/src/crypto/crypto_openssl.c @@ -40,7 +40,7 @@ static BIGNUM * get_group5_prime(void) { -#if OPENSSL_VERSION_NUMBER < 0x00908000 +#if OPENSSL_VERSION_NUMBER < 0x00908000 || defined(OPENSSL_IS_BORINGSSL) static const unsigned char RFC3526_PRIME_1536[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2, 0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1, @@ -130,7 +130,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher) } pkey[i] = next | 1; - DES_set_key(&pkey, &ks); + DES_set_key((DES_cblock *) &pkey, &ks); DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks, DES_ENCRYPT); } @@ -199,8 +199,10 @@ static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen) switch (keylen) { case 16: return EVP_aes_128_ecb(); +#ifndef OPENSSL_IS_BORINGSSL case 24: return EVP_aes_192_ecb(); +#endif /* OPENSSL_IS_BORINGSSL */ case 32: return EVP_aes_256_ecb(); } @@ -340,10 +342,10 @@ int crypto_mod_exp(const u8 *base, size_t base_len, ret = 0; error: - BN_free(bn_base); - BN_free(bn_exp); - BN_free(bn_modulus); - BN_free(bn_result); + BN_clear_free(bn_base); + BN_clear_free(bn_exp); + BN_clear_free(bn_modulus); + BN_clear_free(bn_result); BN_CTX_free(ctx); return ret; } @@ -378,9 +380,11 @@ struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg, case 16: cipher = EVP_aes_128_cbc(); break; +#ifndef OPENSSL_IS_BORINGSSL case 24: cipher = EVP_aes_192_cbc(); break; +#endif /* OPENSSL_IS_BORINGSSL */ case 32: cipher = EVP_aes_256_cbc(); break; @@ -571,12 +575,12 @@ struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public, if (keylen < 0) goto err; wpabuf_put(res, keylen); - BN_free(pub_key); + BN_clear_free(pub_key); return res; err: - BN_free(pub_key); + BN_clear_free(pub_key); wpabuf_free(res); return NULL; } @@ -1066,7 +1070,8 @@ void crypto_ec_deinit(struct crypto_ec *e) { if (e == NULL) return; - BN_free(e->order); + BN_clear_free(e->order); + BN_clear_free(e->prime); EC_GROUP_free(e->group); BN_CTX_free(e->bnctx); os_free(e); @@ -1138,8 +1143,8 @@ int crypto_ec_point_to_bin(struct crypto_ec *e, ret = 0; } - BN_free(x_bn); - BN_free(y_bn); + BN_clear_free(x_bn); + BN_clear_free(y_bn); return ret; } @@ -1155,20 +1160,20 @@ struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e, y = BN_bin2bn(val + len, len, NULL); elem = EC_POINT_new(e->group); if (x == NULL || y == NULL || elem == NULL) { - BN_free(x); - BN_free(y); - EC_POINT_free(elem); + BN_clear_free(x); + BN_clear_free(y); + EC_POINT_clear_free(elem); return NULL; } if (!EC_POINT_set_affine_coordinates_GFp(e->group, elem, x, y, e->bnctx)) { - EC_POINT_free(elem); + EC_POINT_clear_free(elem); elem = NULL; } - BN_free(x); - BN_free(y); + BN_clear_free(x); + BN_clear_free(y); return (struct crypto_ec_point *) elem; } diff --git a/src/crypto/milenage.c b/src/crypto/milenage.c index a7f9c6a..6edea57 100644 --- a/src/crypto/milenage.c +++ b/src/crypto/milenage.c @@ -217,7 +217,7 @@ int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts, for (i = 0; i < 6; i++) sqn[i] = auts[i] ^ ak[i]; if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) || - memcmp(mac_s, auts + 6, 8) != 0) + os_memcmp_const(mac_s, auts + 6, 8) != 0) return -1; return 0; } @@ -312,7 +312,7 @@ int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand, wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8); - if (os_memcmp(mac_a, autn + 8, 8) != 0) { + if (os_memcmp_const(mac_a, autn + 8, 8) != 0) { wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch"); wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A", autn + 8, 8); diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index d2d6600..e153422 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -38,14 +38,26 @@ #define OPENSSL_SUPPORTS_CTX_APP_DATA #endif -#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT -#ifdef SSL_OP_NO_TICKET +#if OPENSSL_VERSION_NUMBER < 0x10000000L +/* ERR_remove_thread_state replaces ERR_remove_state and the latter is + * deprecated. However, OpenSSL 0.9.8 doesn't include + * ERR_remove_thread_state. */ +#define ERR_remove_thread_state(tid) ERR_remove_state(0) +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x10000000L /* * Session ticket override patch was merged into OpenSSL 0.9.9 tree on * 2008-11-15. This version uses a bit different API compared to the old patch. */ #define CONFIG_OPENSSL_TICKET_OVERRIDE #endif + +#if defined(OPENSSL_IS_BORINGSSL) +/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */ +typedef size_t stack_index_t; +#else +typedef int stack_index_t; #endif #ifdef SSL_set_tlsext_status_type @@ -853,7 +865,7 @@ void tls_deinit(void *ssl_ctx) ENGINE_cleanup(); #endif /* OPENSSL_NO_ENGINE */ CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + ERR_remove_thread_state(NULL); ERR_free_strings(); EVP_cleanup(); os_free(tls_global->ocsp_stapling_response); @@ -1102,7 +1114,8 @@ static int tls_match_altsubject_component(X509 *cert, int type, { GENERAL_NAME *gen; void *ext; - int i, found = 0; + int found = 0; + stack_index_t i; ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); @@ -1204,6 +1217,7 @@ static int tls_match_suffix(X509 *cert, const char *match) GENERAL_NAME *gen; void *ext; int i; + stack_index_t j; int dns_name = 0; X509_NAME *name; @@ -1211,8 +1225,8 @@ static int tls_match_suffix(X509 *cert, const char *match) ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { - gen = sk_GENERAL_NAME_value(ext, i); + for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) { + gen = sk_GENERAL_NAME_value(ext, j); if (gen->type != GEN_DNS) continue; dns_name++; @@ -1639,7 +1653,7 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn, if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { BIO *bio = BIO_from_keystore(&ca_cert[11]); STACK_OF(X509_INFO) *stack = NULL; - int i; + stack_index_t i; if (bio) { stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); @@ -3386,9 +3400,15 @@ unsigned int tls_capabilities(void *tls_ctx) * commented out unless explicitly needed for EAP-FAST in order to be able to * build this file with unmodified openssl. */ +#ifdef OPENSSL_IS_BORINGSSL +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + const SSL_CIPHER **cipher, void *arg) +#else /* OPENSSL_IS_BORINGSSL */ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg) +#endif /* OPENSSL_IS_BORINGSSL */ { struct tls_connection *conn = arg; int ret; diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 6e47b86..6af7294 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -351,7 +351,7 @@ struct wpa_driver_scan_params { * Mbps from the support rates element(s) in the Probe Request frames * and not to transmit the frames at any of those rates. */ - u8 p2p_probe; + unsigned int p2p_probe:1; /** * only_new_results - Request driver to report only new results @@ -360,7 +360,15 @@ struct wpa_driver_scan_params { * been detected after this scan request has been started, i.e., to * flush old cached BSS entries. */ - int only_new_results; + unsigned int only_new_results:1; + + /** + * low_priority - Requests driver to use a lower scan priority + * + * This is used to request the driver to use a lower scan priority + * if it supports such a thing. + */ + unsigned int low_priority:1; /* * NOTE: Whenever adding new parameters here, please make sure @@ -403,6 +411,25 @@ enum wps_mode { */ }; +struct hostapd_freq_params { + int mode; + int freq; + int channel; + /* for HT */ + int ht_enabled; + int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, + * secondary channel below primary, 1 = HT40 + * enabled, secondary channel above primary */ + + /* for VHT */ + int vht_enabled; + + /* valid for both HT and VHT, center_freq2 is non-zero + * only for bandwidth 80 and an 80+80 channel */ + int center_freq1, center_freq2; + int bandwidth; +}; + /** * struct wpa_driver_associate_params - Association parameters * Data for struct wpa_driver_ops::associate(). @@ -435,11 +462,9 @@ struct wpa_driver_associate_params { size_t ssid_len; /** - * freq - Frequency of the channel the selected AP is using - * Frequency that the selected AP is using (in MHz as - * reported in the scan results) + * freq - channel parameters */ - int freq; + struct hostapd_freq_params freq; /** * freq_hint - Frequency of the channel the proposed AP is using @@ -1083,25 +1108,6 @@ struct hostapd_sta_add_params { size_t supp_oper_classes_len; }; -struct hostapd_freq_params { - int mode; - int freq; - int channel; - /* for HT */ - int ht_enabled; - int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, - * secondary channel below primary, 1 = HT40 - * enabled, secondary channel above primary */ - - /* for VHT */ - int vht_enabled; - - /* valid for both HT and VHT, center_freq2 is non-zero - * only for bandwidth 80 and an 80+80 channel */ - int center_freq1, center_freq2; - int bandwidth; -}; - struct mac_address { u8 addr[ETH_ALEN]; }; @@ -2495,6 +2501,7 @@ struct wpa_driver_ops { * @dialog_token: Dialog Token to use in the message (if needed) * @status_code: Status Code or Reason Code to use (if needed) * @peer_capab: TDLS peer capability (TDLS_PEER_* bitfield) + * @initiator: Is the current end the TDLS link initiator * @buf: TDLS IEs to add to the message * @len: Length of buf in octets * Returns: 0 on success, negative (<0) on failure @@ -2504,7 +2511,7 @@ struct wpa_driver_ops { */ int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - const u8 *buf, size_t len); + int initiator, const u8 *buf, size_t len); /** * tdls_oper - Ask the driver to perform high-level TDLS operations @@ -2796,6 +2803,30 @@ struct wpa_driver_ops { */ int (*status)(void *priv, char *buf, size_t buflen); + /** + * roaming - Set roaming policy for driver-based BSS selection + * @priv: Private driver interface data + * @allowed: Whether roaming within ESS is allowed + * @bssid: Forced BSSID if roaming is disabled or %NULL if not set + * Returns: Length of written status information or -1 on failure + * + * This optional callback can be used to update roaming policy from the + * associate() command (bssid being set there indicates that the driver + * should not roam before getting this roaming() call to allow roaming. + * If the driver does not indicate WPA_DRIVER_FLAGS_BSS_SELECTION + * capability, roaming policy is handled within wpa_supplicant and there + * is no need to implement or react to this callback. + */ + int (*roaming)(void *priv, int allowed, const u8 *bssid); + + /** + * set_mac_addr - Set MAC address + * @priv: Private driver interface data + * @addr: MAC address to use or %NULL for setting back to permanent + * Returns: 0 on success, -1 on failure + */ + int (*set_mac_addr)(void *priv, const u8 *addr); + #ifdef CONFIG_MACSEC int (*macsec_init)(void *priv, struct macsec_init_params *params); @@ -3308,7 +3339,8 @@ enum wpa_event_type { * the driver does not support radar detection and another virtual * interfaces caused the operating channel to change. Other similar * resource conflicts could also trigger this for station mode - * interfaces. + * interfaces. This event can be propagated when channel switching + * fails. */ EVENT_INTERFACE_UNAVAILABLE, @@ -4163,6 +4195,9 @@ void wpa_scan_results_free(struct wpa_scan_results *res); /* Convert wpa_event_type to a string for logging */ const char * event_to_string(enum wpa_event_type event); +/* Convert chan_width to a string for logging and control interfaces */ +const char * channel_width_to_string(enum chan_width width); + /* NULL terminated array of linked in driver wrappers */ extern struct wpa_driver_ops *wpa_drivers[]; diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c index c146cdc..b569a0a 100644 --- a/src/drivers/driver_atheros.c +++ b/src/drivers/driver_atheros.c @@ -260,6 +260,17 @@ atheros_configure_wpa(struct atheros_driver_data *drv, case WPA_CIPHER_CCMP: v = IEEE80211_CIPHER_AES_CCM; break; +#ifdef ATH_GCM_SUPPORT + case WPA_CIPHER_CCMP_256: + v = IEEE80211_CIPHER_AES_CCM_256; + break; + case WPA_CIPHER_GCMP: + v = IEEE80211_CIPHER_AES_GCM; + break; + case WPA_CIPHER_GCMP_256: + v = IEEE80211_CIPHER_AES_GCM_256; + break; +#endif /* ATH_GCM_SUPPORT */ case WPA_CIPHER_TKIP: v = IEEE80211_CIPHER_TKIP; break; @@ -294,6 +305,14 @@ atheros_configure_wpa(struct atheros_driver_data *drv, v = 0; if (params->wpa_pairwise & WPA_CIPHER_CCMP) v |= 1<<IEEE80211_CIPHER_AES_CCM; +#ifdef ATH_GCM_SUPPORT + if (params->wpa_pairwise & WPA_CIPHER_CCMP_256) + v |= 1<<IEEE80211_CIPHER_AES_CCM_256; + if (params->wpa_pairwise & WPA_CIPHER_GCMP) + v |= 1<<IEEE80211_CIPHER_AES_GCM; + if (params->wpa_pairwise & WPA_CIPHER_GCMP_256) + v |= 1<<IEEE80211_CIPHER_AES_GCM_256; +#endif /* ATH_GCM_SUPPORT */ if (params->wpa_pairwise & WPA_CIPHER_TKIP) v |= 1<<IEEE80211_CIPHER_TKIP; if (params->wpa_pairwise & WPA_CIPHER_NONE) @@ -471,10 +490,32 @@ atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg, case WPA_ALG_CCMP: cipher = IEEE80211_CIPHER_AES_CCM; break; +#ifdef ATH_GCM_SUPPORT + case WPA_ALG_CCMP_256: + cipher = IEEE80211_CIPHER_AES_CCM_256; + break; + case WPA_ALG_GCMP: + cipher = IEEE80211_CIPHER_AES_GCM; + break; + case WPA_ALG_GCMP_256: + cipher = IEEE80211_CIPHER_AES_GCM_256; + break; +#endif /* ATH_GCM_SUPPORT */ #ifdef CONFIG_IEEE80211W case WPA_ALG_IGTK: cipher = IEEE80211_CIPHER_AES_CMAC; break; +#ifdef ATH_GCM_SUPPORT + case WPA_ALG_BIP_CMAC_256: + cipher = IEEE80211_CIPHER_AES_CMAC_256; + break; + case WPA_ALG_BIP_GMAC_128: + cipher = IEEE80211_CIPHER_AES_GMAC; + break; + case WPA_ALG_BIP_GMAC_256: + cipher = IEEE80211_CIPHER_AES_GMAC_256; + break; +#endif /* ATH_GCM_SUPPORT */ #endif /* CONFIG_IEEE80211W */ default: printf("%s: unknown/unsupported algorithm %d\n", diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index 3058cd5..77e6905 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -84,3 +84,24 @@ const char * event_to_string(enum wpa_event_type event) return "UNKNOWN"; #undef E2S } + + +const char * channel_width_to_string(enum chan_width width) +{ + switch (width) { + case CHAN_WIDTH_20_NOHT: + return "20 MHz (no HT)"; + case CHAN_WIDTH_20: + return "20 MHz"; + case CHAN_WIDTH_40: + return "40 MHz"; + case CHAN_WIDTH_80: + return "80 MHz"; + case CHAN_WIDTH_80P80: + return "80+80 MHz"; + case CHAN_WIDTH_160: + return "160 MHz"; + default: + return "unknown"; + } +} diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index 7568653..d030474 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -19,6 +19,9 @@ #include <netlink/genl/genl.h> #include <netlink/genl/family.h> #include <netlink/genl/ctrl.h> +#ifdef CONFIG_LIBNL3_ROUTE +#include <netlink/route/neighbour.h> +#endif /* CONFIG_LIBNL3_ROUTE */ #include <linux/rtnetlink.h> #include <netpacket/packet.h> #include <linux/filter.h> @@ -232,6 +235,7 @@ struct i802_bss { unsigned int in_deinit:1; unsigned int wdev_id_set:1; unsigned int added_if:1; + unsigned int static_ap:1; u8 addr[ETH_ALEN]; @@ -252,6 +256,7 @@ struct wpa_driver_nl80211_data { struct dl_list list; struct dl_list wiphy_list; char phyname[32]; + u8 perm_addr[ETH_ALEN]; void *ctx; int ifindex; int if_removed; @@ -306,7 +311,11 @@ struct wpa_driver_nl80211_data { unsigned int start_iface_up:1; unsigned int test_use_roc_tx:1; unsigned int ignore_deauth_event:1; + unsigned int roaming_vendor_cmd_avail:1; unsigned int dfs_vendor_cmd_avail:1; + unsigned int have_low_prio_scan:1; + unsigned int force_connect_cmd:1; + unsigned int addr_changed:1; u64 remain_on_chan_cookie; u64 send_action_cookie; @@ -322,6 +331,8 @@ struct wpa_driver_nl80211_data { int eapol_sock; /* socket for EAPOL frames */ + struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */ + int default_if_indices[16]; int *if_indices; int num_if_indices; @@ -347,6 +358,9 @@ static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx); static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, enum nl80211_iftype nlmode); +static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss, + struct hostapd_freq_params *freq); + static int wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, const u8 *set_addr, int first); @@ -413,6 +427,7 @@ static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv); static int wpa_driver_nl80211_authenticate_retry( struct wpa_driver_nl80211_data *drv); +static int i802_set_freq(void *priv, struct hostapd_freq_params *freq); static int i802_set_iface_flags(struct i802_bss *bss, int up); @@ -574,6 +589,20 @@ static int is_p2p_net_interface(enum nl80211_iftype nlmode) } +static struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv, + int ifindex) +{ + struct i802_bss *bss; + + for (bss = drv->first_bss; bss; bss = bss->next) { + if (bss->ifindex == ifindex) + return bss; + } + + return NULL; +} + + static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) { if (drv->associated) @@ -1238,8 +1267,9 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, } extra[sizeof(extra) - 1] = '\0'; - wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_flags=0x%x (%s%s%s%s)", - ifi->ifi_index, ifname, extra, ifi->ifi_flags, + wpa_printf(MSG_DEBUG, "RTM_NEWLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)", + ifi->ifi_index, ifname, extra, ifi->ifi_family, + ifi->ifi_flags, (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", @@ -1291,6 +1321,28 @@ static void wpa_driver_nl80211_event_rtm_newlink(void *ctx, "event since interface %s is marked " "removed", drv->first_bss->ifname); } else { + struct i802_bss *bss; + u8 addr[ETH_ALEN]; + + /* Re-read MAC address as it may have changed */ + bss = get_bss_ifindex(drv, ifi->ifi_index); + if (bss && + linux_get_ifhwaddr(drv->global->ioctl_sock, + bss->ifname, addr) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: %s: failed to re-read MAC address", + bss->ifname); + } else if (bss && + os_memcmp(addr, bss->addr, ETH_ALEN) != 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Own MAC address on ifindex %d (%s) changed from " + MACSTR " to " MACSTR, + ifi->ifi_index, bss->ifname, + MAC2STR(bss->addr), + MAC2STR(addr)); + os_memcpy(bss->addr, addr, ETH_ALEN); + } + wpa_printf(MSG_DEBUG, "nl80211: Interface up"); drv->if_disabled = 0; wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, @@ -1335,6 +1387,7 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, struct rtattr *attr; u32 brid = 0; char ifname[IFNAMSIZ + 1]; + char extra[100], *pos, *end; drv = nl80211_find_drv(global, ifi->ifi_index, buf, len); if (!drv) { @@ -1343,6 +1396,9 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, return; } + extra[0] = '\0'; + pos = extra; + end = pos + sizeof(extra); ifname[0] = '\0'; attrlen = len; @@ -1357,12 +1413,30 @@ static void wpa_driver_nl80211_event_rtm_dellink(void *ctx, break; case IFLA_MASTER: brid = nla_get_u32((struct nlattr *) attr); + pos += os_snprintf(pos, end - pos, " master=%u", brid); + break; + case IFLA_OPERSTATE: + pos += os_snprintf(pos, end - pos, " operstate=%u", + nla_get_u32((struct nlattr *) attr)); + break; + case IFLA_LINKMODE: + pos += os_snprintf(pos, end - pos, " linkmode=%u", + nla_get_u32((struct nlattr *) attr)); break; } attr = RTA_NEXT(attr, attrlen); } + extra[sizeof(extra) - 1] = '\0'; - if (ifname[0]) + wpa_printf(MSG_DEBUG, "RTM_DELLINK: ifi_index=%d ifname=%s%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)", + ifi->ifi_index, ifname, extra, ifi->ifi_family, + ifi->ifi_flags, + (ifi->ifi_flags & IFF_UP) ? "[UP]" : "", + (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "", + (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "", + (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : ""); + + if (ifname[0] && (ifi->ifi_family != AF_BRIDGE || !brid)) wpa_driver_nl80211_event_dellink(drv, ifname); if (ifi->ifi_family == AF_BRIDGE && brid) { @@ -1382,6 +1456,17 @@ static void mlme_event_auth(struct wpa_driver_nl80211_data *drv, const struct ieee80211_mgmt *mgmt; union wpa_event_data event; + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && + drv->force_connect_cmd) { + /* + * Avoid reporting two association events that would confuse + * the core code. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore auth event when using driver SME"); + return; + } + wpa_printf(MSG_DEBUG, "nl80211: Authenticate event"); mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.auth)) { @@ -1448,6 +1533,17 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, union wpa_event_data event; u16 status; + if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) && + drv->force_connect_cmd) { + /* + * Avoid reporting two association events that would confuse + * the core code. + */ + wpa_printf(MSG_DEBUG, + "nl80211: Ignore assoc event when using driver SME"); + return; + } + wpa_printf(MSG_DEBUG, "nl80211: Associate event"); mgmt = (const struct ieee80211_mgmt *) frame; if (len < 24 + sizeof(mgmt->u.assoc_resp)) { @@ -1629,10 +1725,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, return; ifidx = nla_get_u32(ifindex); - for (bss = drv->first_bss; bss; bss = bss->next) - if (bss->ifindex == ifidx) - break; - + bss = get_bss_ifindex(drv, ifidx); if (bss == NULL) { wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring", ifidx); @@ -1676,7 +1769,7 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, bss->freq = data.ch_switch.freq; - wpa_supplicant_event(drv->ctx, EVENT_CH_SWITCH, &data); + wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data); } @@ -1735,8 +1828,10 @@ static void mlme_event_mgmt(struct i802_bss *bss, rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq; } wpa_printf(MSG_DEBUG, - "nl80211: RX frame freq=%d ssi_signal=%d stype=%u len=%u", - rx_freq, ssi_signal, stype, (unsigned int) len); + "nl80211: RX frame sa=" MACSTR + " freq=%d ssi_signal=%d stype=%u (%s) len=%u", + MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc), + (unsigned int) len); event.rx_mgmt.frame = frame; event.rx_mgmt.frame_len = len; event.rx_mgmt.ssi_signal = ssi_signal; @@ -3411,6 +3506,7 @@ struct wiphy_info_data { unsigned int p2p_concurrent:1; unsigned int channel_switch_supported:1; unsigned int set_qos_map_supported:1; + unsigned int have_low_prio_scan:1; }; @@ -3689,6 +3785,9 @@ static void wiphy_info_feature_flags(struct wiphy_info_data *info, if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE) capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX; + + if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN) + info->have_low_prio_scan = 1; } @@ -3835,9 +3934,14 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg) continue; } vinfo = nla_data(nl); - if (vinfo->subcmd == - QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY) + switch (vinfo->subcmd) { + case QCA_NL80211_VENDOR_SUBCMD_ROAMING: + drv->roaming_vendor_cmd_avail = 1; + break; + case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY: drv->dfs_vendor_cmd_avail = 1; + break; + } wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u", vinfo->vendor_id, vinfo->subcmd); @@ -3981,6 +4085,7 @@ static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) drv->data_tx_status = info.data_tx_status; if (info.set_qos_map_supported) drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING; + drv->have_low_prio_scan = info.have_low_prio_scan; /* * If poll command and tx status are supported, mac80211 is new enough @@ -4384,8 +4489,8 @@ static int nl80211_register_frame(struct i802_bss *bss, buf[0] = '\0'; wpa_snprintf_hex(buf, sizeof(buf), match, match_len); - wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p match=%s", - type, nl_handle, buf); + wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s", + type, fc2str(type), nl_handle, buf); nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION); @@ -4538,7 +4643,7 @@ static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss) #ifdef CONFIG_HS20 /* WNM-Notification */ if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x1a", 2) < 0) - return -1; + ret = -1; #endif /* CONFIG_HS20 */ nl80211_mgmt_handle_register_eloop(bss); @@ -4752,6 +4857,9 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, bss->if_dynamic = bss->if_dynamic || drv->global->if_add_wdevid_set; drv->global->if_add_wdevid_set = 0; + if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP) + bss->static_ap = 1; + if (wpa_driver_nl80211_capa(drv)) return -1; @@ -4767,7 +4875,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, if (first && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP) drv->start_mode_ap = 1; - if (drv->hostapd) + if (drv->hostapd || bss->static_ap) nlmode = NL80211_IFTYPE_AP; else if (bss->if_dynamic) nlmode = nl80211_get_ifmode(bss); @@ -4807,6 +4915,7 @@ wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv, if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, bss->addr)) return -1; + os_memcpy(drv->perm_addr, bss->addr, ETH_ALEN); if (send_rfkill_event) { eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill, @@ -4862,6 +4971,8 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) wpa_printf(MSG_INFO, "nl80211: Failed to remove " "interface %s from bridge %s: %s", bss->ifname, bss->brname, strerror(errno)); + if (drv->rtnl_sk) + nl80211_handle_destroy(drv->rtnl_sk); } if (bss->added_bridge) { if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0) @@ -4895,6 +5006,16 @@ static void wpa_driver_nl80211_deinit(struct i802_bss *bss) if (!drv->start_iface_up) (void) i802_set_iface_flags(bss, 0); + + if (drv->addr_changed) { + linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0); + if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, + drv->perm_addr) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Could not restore permanent MAC address"); + } + } + if (drv->nlmode != NL80211_IFTYPE_P2P_DEVICE) { if (!drv->hostapd || !drv->start_mode_ap) wpa_driver_nl80211_set_mode(bss, @@ -4949,6 +5070,7 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd, { struct nl_msg *msg; size_t i; + u32 scan_flags = 0; msg = nlmsg_alloc(); if (!msg) @@ -5007,10 +5129,18 @@ nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd, if (params->only_new_results) { wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH"); - NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, - NL80211_SCAN_FLAG_FLUSH); + scan_flags |= NL80211_SCAN_FLAG_FLUSH; } + if (params->low_priority && drv->have_low_prio_scan) { + wpa_printf(MSG_DEBUG, + "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY"); + scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY; + } + + if (scan_flags) + NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags); + return msg; fail: @@ -7070,8 +7200,10 @@ static int wpa_driver_nl80211_send_mlme(struct i802_bss *bss, const u8 *data, mgmt = (struct ieee80211_mgmt *) data; fc = le_to_host16(mgmt->frame_control); - wpa_printf(MSG_DEBUG, "nl80211: send_mlme - noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x nlmode=%d", - noack, freq, no_cck, offchanok, wait_time, fc, drv->nlmode); + wpa_printf(MSG_DEBUG, "nl80211: send_mlme - da= " MACSTR + " noack=%d freq=%u no_cck=%d offchanok=%d wait_time=%u fc=0x%x (%s) nlmode=%d", + MAC2STR(mgmt->da), noack, freq, no_cck, offchanok, wait_time, + fc, fc2str(fc), drv->nlmode); if ((is_sta_interface(drv->nlmode) || drv->nlmode == NL80211_IFTYPE_P2P_DEVICE) && @@ -7660,6 +7792,43 @@ static int wpa_driver_nl80211_sta_add(void *priv, } +static void rtnl_neigh_delete_fdb_entry(struct i802_bss *bss, const u8 *addr) +{ +#ifdef CONFIG_LIBNL3_ROUTE + struct wpa_driver_nl80211_data *drv = bss->drv; + struct rtnl_neigh *rn; + struct nl_addr *nl_addr; + int err; + + rn = rtnl_neigh_alloc(); + if (!rn) + return; + + rtnl_neigh_set_family(rn, AF_BRIDGE); + rtnl_neigh_set_ifindex(rn, bss->ifindex); + nl_addr = nl_addr_build(AF_BRIDGE, (void *) addr, ETH_ALEN); + if (!nl_addr) { + rtnl_neigh_put(rn); + return; + } + rtnl_neigh_set_lladdr(rn, nl_addr); + + err = rtnl_neigh_delete(drv->rtnl_sk, rn, 0); + if (err < 0) { + wpa_printf(MSG_DEBUG, "nl80211: bridge FDB entry delete for " + MACSTR " ifindex=%d failed: %s", MAC2STR(addr), + bss->ifindex, nl_geterror(err)); + } else { + wpa_printf(MSG_DEBUG, "nl80211: deleted bridge FDB entry for " + MACSTR, MAC2STR(addr)); + } + + nl_addr_put(nl_addr); + rtnl_neigh_put(rn); +#endif /* CONFIG_LIBNL3_ROUTE */ +} + + static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr) { struct wpa_driver_nl80211_data *drv = bss->drv; @@ -7680,6 +7849,10 @@ static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr) wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR " --> %d (%s)", bss->ifname, MAC2STR(addr), ret, strerror(-ret)); + + if (drv->rtnl_sk) + rtnl_neigh_delete_fdb_entry(bss, addr); + if (ret == -ENOENT) return 0; return ret; @@ -8454,6 +8627,11 @@ static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr, struct nlattr *flags; struct nl80211_sta_flag_update upd; + wpa_printf(MSG_DEBUG, "nl80211: Set STA flags - ifname=%s addr=" MACSTR + " total_flags=0x%x flags_or=0x%x flags_and=0x%x authorized=%d", + bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and, + !!(total_flags & WPA_STA_AUTHORIZED)); + msg = nlmsg_alloc(); if (!msg) return -ENOMEM; @@ -8504,9 +8682,6 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, struct wpa_driver_associate_params *params) { enum nl80211_iftype nlmode, old_mode; - struct hostapd_freq_params freq = { - .freq = params->freq, - }; if (params->p2p) { wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P " @@ -8521,7 +8696,7 @@ static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv, return -1; } - if (nl80211_set_channel(drv->first_bss, &freq, 0)) { + if (nl80211_set_channel(drv->first_bss, ¶ms->freq, 0)) { if (old_mode != nlmode) wpa_driver_nl80211_set_mode(drv->first_bss, old_mode); nl80211_remove_monitor_interface(drv); @@ -8575,8 +8750,7 @@ static int wpa_driver_nl80211_ibss(struct wpa_driver_nl80211_data *drv, wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex); - if (wpa_driver_nl80211_set_mode(drv->first_bss, - NL80211_IFTYPE_ADHOC)) { + if (wpa_driver_nl80211_set_mode_ibss(drv->first_bss, ¶ms->freq)) { wpa_printf(MSG_INFO, "nl80211: Failed to set interface into " "IBSS mode"); return -1; @@ -8600,8 +8774,16 @@ retry: os_memcpy(drv->ssid, params->ssid, params->ssid_len); drv->ssid_len = params->ssid_len; - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq); + wpa_printf(MSG_DEBUG, " * ht_enabled=%d", params->freq.ht_enabled); + wpa_printf(MSG_DEBUG, " * sec_channel_offset=%d", + params->freq.sec_channel_offset); + wpa_printf(MSG_DEBUG, " * vht_enabled=%d", params->freq.vht_enabled); + wpa_printf(MSG_DEBUG, " * center_freq1=%d", params->freq.center_freq1); + wpa_printf(MSG_DEBUG, " * center_freq2=%d", params->freq.center_freq2); + wpa_printf(MSG_DEBUG, " * bandwidth=%d", params->freq.bandwidth); + if (nl80211_put_freq_params(msg, ¶ms->freq) < 0) + goto nla_put_failure; if (params->beacon_int > 0) { wpa_printf(MSG_DEBUG, " * beacon_int=%d", params->beacon_int); @@ -8679,10 +8861,10 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, params->bssid_hint); } - if (params->freq) { - wpa_printf(MSG_DEBUG, " * freq=%d", params->freq); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq); - drv->assoc_freq = params->freq; + if (params->freq.freq) { + wpa_printf(MSG_DEBUG, " * freq=%d", params->freq.freq); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq); + drv->assoc_freq = params->freq.freq; } else drv->assoc_freq = 0; @@ -9016,26 +9198,29 @@ nla_put_failure: } -static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, - enum nl80211_iftype nlmode) +static int wpa_driver_nl80211_set_mode_impl( + struct i802_bss *bss, + enum nl80211_iftype nlmode, + struct hostapd_freq_params *desired_freq_params) { struct wpa_driver_nl80211_data *drv = bss->drv; int ret = -1; int i; int was_ap = is_ap_interface(drv->nlmode); int res; + int mode_switch_res; - res = nl80211_set_mode(drv, drv->ifindex, nlmode); - if (res && nlmode == nl80211_get_ifmode(bss)) - res = 0; + mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode); + if (mode_switch_res && nlmode == nl80211_get_ifmode(bss)) + mode_switch_res = 0; - if (res == 0) { + if (mode_switch_res == 0) { drv->nlmode = nlmode; ret = 0; goto done; } - if (res == -ENODEV) + if (mode_switch_res == -ENODEV) return -1; if (nlmode == drv->nlmode) { @@ -9055,21 +9240,35 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, res = i802_set_iface_flags(bss, 0); if (res == -EACCES || res == -ENODEV) break; - if (res == 0) { - /* Try to set the mode again while the interface is - * down */ - ret = nl80211_set_mode(drv, drv->ifindex, nlmode); - if (ret == -EACCES) - break; - res = i802_set_iface_flags(bss, 1); - if (res && !ret) - ret = -1; - else if (ret != -EBUSY) - break; - } else + if (res != 0) { wpa_printf(MSG_DEBUG, "nl80211: Failed to set " "interface down"); - os_sleep(0, 100000); + os_sleep(0, 100000); + continue; + } + + /* + * Setting the mode will fail for some drivers if the phy is + * on a frequency that the mode is disallowed in. + */ + if (desired_freq_params) { + res = i802_set_freq(bss, desired_freq_params); + if (res) { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to set frequency on interface"); + } + } + + /* Try to set the mode again while the interface is down */ + mode_switch_res = nl80211_set_mode(drv, drv->ifindex, nlmode); + if (mode_switch_res == -EBUSY) { + wpa_printf(MSG_DEBUG, + "nl80211: Delaying mode set while interface going down"); + os_sleep(0, 100000); + continue; + } + ret = mode_switch_res; + break; } if (!ret) { @@ -9079,6 +9278,14 @@ static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, drv->ignore_if_down_event = 1; } + /* Bring the interface back up */ + res = linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1); + if (res != 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Failed to set interface up after switching mode"); + ret = -1; + } + done: if (ret) { wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d " @@ -9141,6 +9348,21 @@ static int dfs_info_handler(struct nl_msg *msg, void *arg) } +static int wpa_driver_nl80211_set_mode(struct i802_bss *bss, + enum nl80211_iftype nlmode) +{ + return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL); +} + + +static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss, + struct hostapd_freq_params *freq) +{ + return wpa_driver_nl80211_set_mode_impl(bss, NL80211_IFTYPE_ADHOC, + freq); +} + + static int wpa_driver_nl80211_get_capa(void *priv, struct wpa_driver_capa *capa) { @@ -9917,6 +10139,22 @@ static void *i802_init(struct hostapd_data *hapd, i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0) goto failed; +#ifdef CONFIG_LIBNL3_ROUTE + if (bss->added_if_into_bridge) { + drv->rtnl_sk = nl_socket_alloc(); + if (drv->rtnl_sk == NULL) { + wpa_printf(MSG_ERROR, "nl80211: Failed to allocate nl_sock"); + goto failed; + } + + if (nl_connect(drv->rtnl_sk, NETLINK_ROUTE)) { + wpa_printf(MSG_ERROR, "nl80211: Failed to connect nl_sock to NETLINK_ROUTE: %s", + strerror(errno)); + goto failed; + } + } +#endif /* CONFIG_LIBNL3_ROUTE */ + drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE)); if (drv->eapol_sock < 0) { wpa_printf(MSG_ERROR, "nl80211: socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE) failed: %s", @@ -9933,6 +10171,7 @@ static void *i802_init(struct hostapd_data *hapd, if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname, params->own_addr)) goto failed; + os_memcpy(drv->perm_addr, params->own_addr, ETH_ALEN); memcpy(bss->addr, params->own_addr, ETH_ALEN); @@ -10177,7 +10416,15 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type, if (drv->global) drv->global->if_add_ifindex = ifidx; - if (ifidx > 0) + /* + * Some virtual interfaces need to process EAPOL packets and events on + * the parent interface. This is used mainly with hostapd. + */ + if (ifidx > 0 && + (drv->hostapd || + nlmode == NL80211_IFTYPE_AP_VLAN || + nlmode == NL80211_IFTYPE_WDS || + nlmode == NL80211_IFTYPE_MONITOR)) add_ifidx(drv, ifidx); return 0; @@ -10495,7 +10742,8 @@ static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss, int report) if (!report) { if (bss->nl_preq && drv->device_ap_sme && - is_ap_interface(drv->nlmode)) { + is_ap_interface(drv->nlmode) && !bss->in_deinit && + !bss->static_ap) { /* * Do not disable Probe Request reporting that was * enabled in nl80211_setup_ap(). @@ -10883,6 +11131,7 @@ static int nl80211_set_param(void *priv, const char *param) struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; drv->capa.flags &= ~WPA_DRIVER_FLAGS_SME; + drv->force_connect_cmd = 1; } if (os_strstr(param, "no_offchannel_tx=1")) { @@ -11374,60 +11623,18 @@ static int nl80211_start_radar_detection(void *priv, nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT); NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq); - if (freq->vht_enabled) { - switch (freq->bandwidth) { - case 20: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_20); - break; - case 40: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_40); - break; - case 80: - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80P80); - else - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_80); - break; - case 160: - NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH, - NL80211_CHAN_WIDTH_160); - break; - default: - return -1; - } - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1); - if (freq->center_freq2) - NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2, - freq->center_freq2); - } else if (freq->ht_enabled) { - switch (freq->sec_channel_offset) { - case -1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40MINUS); - break; - case 1: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT40PLUS); - break; - default: - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - NL80211_CHAN_HT20); - break; - } - } + if (nl80211_put_freq_params(msg, freq) < 0) + goto nla_put_failure; ret = send_and_recv_msgs(drv, msg, NULL, NULL); + msg = NULL; if (ret == 0) return 0; wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: " "%d (%s)", ret, strerror(-ret)); nla_put_failure: + nlmsg_free(msg); return -1; } @@ -11435,7 +11642,8 @@ nla_put_failure: static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, - u32 peer_capab, const u8 *buf, size_t len) + u32 peer_capab, int initiator, const u8 *buf, + size_t len) { struct i802_bss *bss = priv; struct wpa_driver_nl80211_data *drv = bss->drv; @@ -11466,6 +11674,8 @@ static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code, */ NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab); } + if (initiator) + NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_INITIATOR); NLA_PUT(msg, NL80211_ATTR_IE, len, buf); return send_and_recv_msgs(drv, msg, NULL, NULL); @@ -11878,6 +12088,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) res = os_snprintf(pos, end - pos, "phyname=%s\n" + "perm_addr=" MACSTR "\n" "drv_ifindex=%d\n" "operstate=%d\n" "scan_state=%s\n" @@ -11894,6 +12105,7 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) "eapol_tx_sock=%d\n" "%s%s%s%s%s%s%s%s%s%s%s%s%s%s", drv->phyname, + MAC2STR(drv->perm_addr), drv->ifindex, drv->operstate, scan_state_str(drv->scan_state), @@ -12047,7 +12259,7 @@ static int nl80211_switch_channel(void *priv, struct csa_settings *settings) return -ENOMEM; nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH); - NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex); NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count); ret = nl80211_put_freq_params(msg, &settings->freq_params); if (ret) @@ -12276,6 +12488,90 @@ nla_put_failure: } +static int nl80211_roaming(void *priv, int allowed, const u8 *bssid) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + struct nl_msg *msg; + struct nlattr *params; + + wpa_printf(MSG_DEBUG, "nl80211: Roaming policy: allowed=%d", allowed); + + if (!drv->roaming_vendor_cmd_avail) { + wpa_printf(MSG_DEBUG, + "nl80211: Ignore roaming policy change since driver does not provide command for setting it"); + return -1; + } + + msg = nlmsg_alloc(); + if (!msg) + return -ENOMEM; + + nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR); + + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA); + NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, + QCA_NL80211_VENDOR_SUBCMD_ROAMING); + + params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA); + if (!params) + goto nla_put_failure; + NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY, + allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS : + QCA_ROAMING_NOT_ALLOWED); + if (bssid) + NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid); + nla_nest_end(msg, params); + + return send_and_recv_msgs(drv, msg, NULL, NULL); + + nla_put_failure: + nlmsg_free(msg); + return -1; +} + + +static int nl80211_set_mac_addr(void *priv, const u8 *addr) +{ + struct i802_bss *bss = priv; + struct wpa_driver_nl80211_data *drv = bss->drv; + int new_addr = addr != NULL; + + if (!addr) + addr = drv->perm_addr; + + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0) < 0) + return -1; + + if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname, addr) < 0) + { + wpa_printf(MSG_DEBUG, + "nl80211: failed to set_mac_addr for %s to " MACSTR, + bss->ifname, MAC2STR(addr)); + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, + 1) < 0) { + wpa_printf(MSG_DEBUG, + "nl80211: Could not restore interface UP after failed set_mac_addr"); + } + return -1; + } + + wpa_printf(MSG_DEBUG, "nl80211: set_mac_addr for %s to " MACSTR, + bss->ifname, MAC2STR(addr)); + drv->addr_changed = new_addr; + os_memcpy(bss->addr, addr, ETH_ALEN); + + if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1) < 0) + { + wpa_printf(MSG_DEBUG, + "nl80211: Could not restore interface UP after set_mac_addr"); + } + + return 0; +} + + const struct wpa_driver_ops wpa_driver_nl80211_ops = { .name = "nl80211", .desc = "Linux nl80211/cfg80211", @@ -12367,4 +12663,6 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = { .vendor_cmd = nl80211_vendor_cmd, .set_qos_map = nl80211_set_qos_map, .set_wowlan = nl80211_set_wowlan, + .roaming = nl80211_roaming, + .set_mac_addr = nl80211_set_mac_addr, }; diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c index 3608b52..66edfa7 100644 --- a/src/drivers/driver_test.c +++ b/src/drivers/driver_test.c @@ -1478,7 +1478,7 @@ static int wpa_driver_test_associate( struct wpa_driver_test_data *drv = dbss->drv; wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d " "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d", - __func__, priv, params->freq, params->pairwise_suite, + __func__, priv, params->freq.freq, params->pairwise_suite, params->group_suite, params->key_mgmt_suite, params->auth_alg, params->mode); wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP); diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c index e5734bd..1b3a757 100644 --- a/src/drivers/driver_wext.c +++ b/src/drivers/driver_wext.c @@ -2027,7 +2027,11 @@ int wpa_driver_wext_associate(void *priv, * Stop cfg80211 from trying to associate before we are done * with all parameters. */ - wpa_driver_wext_set_ssid(drv, (u8 *) "", 0); + if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) { + wpa_printf(MSG_DEBUG, + "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)"); + /* continue anyway */ + } } if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted) @@ -2115,7 +2119,8 @@ int wpa_driver_wext_associate(void *priv, if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0) ret = -1; #endif /* CONFIG_IEEE80211W */ - if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0) + if (params->freq.freq && + wpa_driver_wext_set_freq(drv, params->freq.freq) < 0) ret = -1; if (!drv->cfg80211 && wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0) @@ -2316,6 +2321,37 @@ static const char * wext_get_radio_name(void *priv) } +static int wpa_driver_wext_signal_poll(void *priv, struct wpa_signal_info *si) +{ + struct wpa_driver_wext_data *drv = priv; + struct iw_statistics stats; + struct iwreq iwr; + + os_memset(si, 0, sizeof(*si)); + si->current_signal = -9999; + si->current_noise = 9999; + si->chanwidth = CHAN_WIDTH_UNKNOWN; + + os_memset(&iwr, 0, sizeof(iwr)); + os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ); + iwr.u.data.pointer = (caddr_t) &stats; + iwr.u.data.length = sizeof(stats); + iwr.u.data.flags = 1; + + if (ioctl(drv->ioctl_sock, SIOCGIWSTATS, &iwr) < 0) { + wpa_printf(MSG_ERROR, "WEXT: SIOCGIWSTATS: %s", + strerror(errno)); + return -1; + } + + si->current_signal = stats.qual.level - + ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); + si->current_noise = stats.qual.noise - + ((stats.qual.updated & IW_QUAL_DBM) ? 0x100 : 0); + return 0; +} + + const struct wpa_driver_ops wpa_driver_wext_ops = { .name = "wext", .desc = "Linux wireless extensions (generic)", @@ -2335,4 +2371,5 @@ const struct wpa_driver_ops wpa_driver_wext_ops = { .get_capa = wpa_driver_wext_get_capa, .set_operstate = wpa_driver_wext_set_operstate, .get_radio_name = wext_get_radio_name, + .signal_poll = wpa_driver_wext_signal_poll, }; diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak index 7e175f4..cdb913e 100644 --- a/src/drivers/drivers.mak +++ b/src/drivers/drivers.mak @@ -36,6 +36,10 @@ ifdef CONFIG_LIBNL32 DRV_LIBS += -lnl-3 DRV_LIBS += -lnl-genl-3 DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +ifdef CONFIG_LIBNL3_ROUTE + DRV_LIBS += -lnl-route-3 + DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE +endif else ifdef CONFIG_LIBNL_TINY DRV_LIBS += -lnl-tiny @@ -105,6 +109,9 @@ DRV_AP_OBJS += ../src/drivers/driver_atheros.o CONFIG_L2_PACKET=linux NEED_NETLINK=y NEED_LINUX_IOCTL=y +ifdef ATH_GCM_SUPPORT +CFLAGS += -DATH_GCM_SUPPORT +endif endif ##### PURE CLIENT DRIVERS diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk index db8561a..9fa70d9 100644 --- a/src/drivers/drivers.mk +++ b/src/drivers/drivers.mk @@ -31,6 +31,10 @@ ifdef CONFIG_LIBNL32 DRV_LIBS += -lnl-3 DRV_LIBS += -lnl-genl-3 DRV_CFLAGS += -DCONFIG_LIBNL20 -I/usr/include/libnl3 +ifdef CONFIG_LIBNL3_ROUTE + DRV_LIBS += -lnl-route-3 + DRV_CFLAGS += -DCONFIG_LIBNL3_ROUTE +endif else ifdef CONFIG_LIBNL_TINY DRV_LIBS += -lnl-tiny diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h index 406010d..4b28dc0 100644 --- a/src/drivers/nl80211_copy.h +++ b/src/drivers/nl80211_copy.h @@ -503,6 +503,9 @@ * TX status event pertaining to the TX request. * %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the * management frames at CCK rate or not in 2GHz band. + * %NL80211_ATTR_CSA_C_OFFSETS_TX is an array of offsets to CSA + * counters which will be updated to the current value. This attribute + * is used during CSA period. * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this * command may be used with the corresponding cookie to cancel the wait * time if it is known that it is no longer necessary. @@ -719,6 +722,22 @@ * QoS mapping is relevant for IP packets, it is only valid during an * association. This is cleared on disassociation and AP restart. * + * @NL80211_CMD_ADD_TX_TS: Ask the kernel to add a traffic stream for the given + * %NL80211_ATTR_TSID and %NL80211_ATTR_MAC with %NL80211_ATTR_USER_PRIO + * and %NL80211_ATTR_ADMITTED_TIME parameters. + * Note that the action frame handshake with the AP shall be handled by + * userspace via the normal management RX/TX framework, this only sets + * up the TX TS in the driver/device. + * If the admitted time attribute is not added then the request just checks + * if a subsequent setup could be successful, the intent is to use this to + * avoid setting up a session with the AP when local restrictions would + * make that impossible. However, the subsequent "real" setup may still + * fail even if the check was successful. + * @NL80211_CMD_DEL_TX_TS: Remove an existing TS with the %NL80211_ATTR_TSID + * and %NL80211_ATTR_MAC parameters. It isn't necessary to call this + * before removing a station entry entirely, or before disassociating + * or similar, cleanup will happen in the driver/device in this case. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -890,6 +909,9 @@ enum nl80211_commands { NL80211_CMD_SET_QOS_MAP, + NL80211_CMD_ADD_TX_TS, + NL80211_CMD_DEL_TX_TS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1525,10 +1547,10 @@ enum nl80211_commands { * operation). * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information * for the time while performing a channel switch. - * @NL80211_ATTR_CSA_C_OFF_BEACON: Offset of the channel switch counter - * field in the beacons tail (%NL80211_ATTR_BEACON_TAIL). - * @NL80211_ATTR_CSA_C_OFF_PRESP: Offset of the channel switch counter - * field in the probe response (%NL80211_ATTR_PROBE_RESP). + * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel + * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL). + * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel + * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP). * * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. * As specified in the &enum nl80211_rxmgmt_flags. @@ -1576,6 +1598,11 @@ enum nl80211_commands { * advertise values that cannot always be met. In such cases, an attempt * to add a new station entry with @NL80211_CMD_NEW_STATION may fail. * + * @NL80211_ATTR_CSA_C_OFFSETS_TX: An array of csa counter offsets (u16) which + * should be updated when the frame is transmitted. + * @NL80211_ATTR_MAX_CSA_COUNTERS: U8 attribute used to advertise the maximum + * supported number of csa counters. + * * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32. * As specified in the &enum nl80211_tdls_peer_capability. * @@ -1583,6 +1610,34 @@ enum nl80211_commands { * creation then the new interface will be owned by the netlink socket * that created it and will be destroyed when the socket is closed * + * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is + * the TDLS link initiator. + * + * @NL80211_ATTR_USE_RRM: flag for indicating whether the current connection + * shall support Radio Resource Measurements (11k). This attribute can be + * used with %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests. + * User space applications are expected to use this flag only if the + * underlying device supports these minimal RRM features: + * %NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES, + * %NL80211_FEATURE_QUIET, + * If this flag is used, driver must add the Power Capabilities IE to the + * association request. In addition, it must also set the RRM capability + * flag in the association request's Capability Info field. + * + * @NL80211_ATTR_WIPHY_DYN_ACK: flag attribute used to enable ACK timeout + * estimation algorithm (dynack). In order to activate dynack + * %NL80211_FEATURE_ACKTO_ESTIMATION feature flag must be set by lower + * drivers to indicate dynack capability. Dynack is automatically disabled + * setting valid value for coverage class. + * + * @NL80211_ATTR_TSID: a TSID value (u8 attribute) + * @NL80211_ATTR_USER_PRIO: user priority value (u8 attribute) + * @NL80211_ATTR_ADMITTED_TIME: admitted time in units of 32 microseconds + * (per second) (u16 attribute) + * + * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see + * &enum nl80211_smps_mode. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1920,6 +1975,21 @@ enum nl80211_attrs { NL80211_ATTR_IFACE_SOCKET_OWNER, + NL80211_ATTR_CSA_C_OFFSETS_TX, + NL80211_ATTR_MAX_CSA_COUNTERS, + + NL80211_ATTR_TDLS_INITIATOR, + + NL80211_ATTR_USE_RRM, + + NL80211_ATTR_WIPHY_DYN_ACK, + + NL80211_ATTR_TSID, + NL80211_ATTR_USER_PRIO, + NL80211_ATTR_ADMITTED_TIME, + + NL80211_ATTR_SMPS_MODE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2188,6 +2258,8 @@ enum nl80211_sta_bss_param { * Contains a nested array of signal strength attributes (u8, dBm) * @NL80211_STA_INFO_CHAIN_SIGNAL_AVG: per-chain signal strength average * Same format as NL80211_STA_INFO_CHAIN_SIGNAL. + * @NL80211_STA_EXPECTED_THROUGHPUT: expected throughput considering also the + * 802.11 header (u32, kbps) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -2219,6 +2291,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_TX_BYTES64, NL80211_STA_INFO_CHAIN_SIGNAL, NL80211_STA_INFO_CHAIN_SIGNAL_AVG, + NL80211_STA_INFO_EXPECTED_THROUGHPUT, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -3036,14 +3109,20 @@ enum nl80211_bss_scan_width { * @NL80211_BSS_BSSID: BSSID of the BSS (6 octets) * @NL80211_BSS_FREQUENCY: frequency in MHz (u32) * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64) + * (if @NL80211_BSS_PRESP_DATA is present then this is known to be + * from a probe response, otherwise it may be from the same beacon + * that the NL80211_BSS_BEACON_TSF will be from) * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16) * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16) * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the * raw information elements from the probe response/beacon (bin); - * if the %NL80211_BSS_BEACON_IES attribute is present, the IEs here are - * from a Probe Response frame; otherwise they are from a Beacon frame. + * if the %NL80211_BSS_BEACON_IES attribute is present and the data is + * different then the IEs here are from a Probe Response frame; otherwise + * they are from a Beacon frame. * However, if the driver does not indicate the source of the IEs, these * IEs may be from either frame subtype. + * If present, the @NL80211_BSS_PRESP_DATA attribute indicates that the + * data here is known to be from a probe response, without any heuristics. * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon * in mBm (100 * dBm) (s32) * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon @@ -3055,6 +3134,10 @@ enum nl80211_bss_scan_width { * yet been received * @NL80211_BSS_CHAN_WIDTH: channel width of the control channel * (u32, enum nl80211_bss_scan_width) + * @NL80211_BSS_BEACON_TSF: TSF of the last received beacon (u64) + * (not present if no beacon frame has been received yet) + * @NL80211_BSS_PRESP_DATA: the data in @NL80211_BSS_INFORMATION_ELEMENTS and + * @NL80211_BSS_TSF is known to be from a probe response (flag attribute) * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -3072,6 +3155,8 @@ enum nl80211_bss { NL80211_BSS_SEEN_MS_AGO, NL80211_BSS_BEACON_IES, NL80211_BSS_CHAN_WIDTH, + NL80211_BSS_BEACON_TSF, + NL80211_BSS_PRESP_DATA, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -3688,6 +3773,8 @@ enum nl80211_iface_limit_attrs { * different channels may be used within this group. * @NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS: u32 attribute containing the bitmap * of supported channel widths for radar detection. + * @NL80211_IFACE_COMB_RADAR_DETECT_REGIONS: u32 attribute containing the bitmap + * of supported regulatory regions for radar detection. * @NUM_NL80211_IFACE_COMB: number of attributes * @MAX_NL80211_IFACE_COMB: highest attribute number * @@ -3721,6 +3808,7 @@ enum nl80211_if_combination_attrs { NL80211_IFACE_COMB_STA_AP_BI_MATCH, NL80211_IFACE_COMB_NUM_CHANNELS, NL80211_IFACE_COMB_RADAR_DETECT_WIDTHS, + NL80211_IFACE_COMB_RADAR_DETECT_REGIONS, /* keep last */ NUM_NL80211_IFACE_COMB, @@ -3894,6 +3982,8 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested * to work properly to suppport receiving regulatory hints from * cellular base stations. + * @NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL: (no longer available, only + * here to reserve the value for API/ABI compatibility) * @NL80211_FEATURE_SAE: This driver supports simultaneous authentication of * equals (SAE) with user space SME (NL80211_CMD_AUTHENTICATE) in station * mode @@ -3932,13 +4022,33 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE: This driver supports dynamic * channel bandwidth change (e.g., HT 20 <-> 40 MHz channel) during the * lifetime of a BSS. + * @NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES: This device adds a DS Parameter + * Set IE to probe requests. + * @NL80211_FEATURE_WFA_TPC_IE_IN_PROBES: This device adds a WFA TPC Report IE + * to probe requests. + * @NL80211_FEATURE_QUIET: This device, in client mode, supports Quiet Period + * requests sent to it by an AP. + * @NL80211_FEATURE_TX_POWER_INSERTION: This device is capable of inserting the + * current tx power value into the TPC Report IE in the spectrum + * management TPC Report action frame, and in the Radio Measurement Link + * Measurement Report action frame. + * @NL80211_FEATURE_ACKTO_ESTIMATION: This driver supports dynamic ACK timeout + * estimation (dynack). %NL80211_ATTR_WIPHY_DYN_ACK flag attribute is used + * to enable dynack. + * @NL80211_FEATURE_STATIC_SMPS: Device supports static spatial + * multiplexing powersave, ie. can turn off all but one chain + * even on HT connections that should be using more chains. + * @NL80211_FEATURE_DYNAMIC_SMPS: Device supports dynamic spatial + * multiplexing powersave, ie. can turn off all but one chain + * and then wake the rest up as required after, for example, + * rts/cts handshake. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, - /* bit 4 is reserved - don't use */ + NL80211_FEATURE_P2P_DEVICE_NEEDS_CHANNEL = 1 << 4, NL80211_FEATURE_SAE = 1 << 5, NL80211_FEATURE_LOW_PRIORITY_SCAN = 1 << 6, NL80211_FEATURE_SCAN_FLUSH = 1 << 7, @@ -3953,6 +4063,13 @@ enum nl80211_feature_flags { NL80211_FEATURE_USERSPACE_MPM = 1 << 16, NL80211_FEATURE_ACTIVE_MONITOR = 1 << 17, NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE = 1 << 18, + NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES = 1 << 19, + NL80211_FEATURE_WFA_TPC_IE_IN_PROBES = 1 << 20, + NL80211_FEATURE_QUIET = 1 << 21, + NL80211_FEATURE_TX_POWER_INSERTION = 1 << 22, + NL80211_FEATURE_ACKTO_ESTIMATION = 1 << 23, + NL80211_FEATURE_STATIC_SMPS = 1 << 24, + NL80211_FEATURE_DYNAMIC_SMPS = 1 << 25, }; /** @@ -4027,6 +4144,25 @@ enum nl80211_acl_policy { }; /** + * enum nl80211_smps_mode - SMPS mode + * + * Requested SMPS mode (for AP mode) + * + * @NL80211_SMPS_OFF: SMPS off (use all antennas). + * @NL80211_SMPS_STATIC: static SMPS (use a single antenna) + * @NL80211_SMPS_DYNAMIC: dynamic smps (start with a single antenna and + * turn on other antennas after CTS/RTS). + */ +enum nl80211_smps_mode { + NL80211_SMPS_OFF, + NL80211_SMPS_STATIC, + NL80211_SMPS_DYNAMIC, + + __NL80211_SMPS_AFTER_LAST, + NL80211_SMPS_MAX = __NL80211_SMPS_AFTER_LAST - 1 +}; + +/** * enum nl80211_radar_event - type of radar event for DFS operation * * Type of event to be used with NL80211_ATTR_RADAR_EVENT to inform userspace diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c index a62ac8e..4dfdb3f 100644 --- a/src/eap_common/eap_eke_common.c +++ b/src/eap_common/eap_eke_common.c @@ -692,7 +692,7 @@ int eap_eke_decrypt_prot(struct eap_eke_session *sess, if (eap_eke_mac(sess->mac, sess->ki, prot + block_size, prot_len - block_size - icv_len, icv) < 0) return -1; - if (os_memcmp(icv, prot + prot_len - icv_len, icv_len) != 0) { + if (os_memcmp_const(icv, prot + prot_len - icv_len, icv_len) != 0) { wpa_printf(MSG_INFO, "EAP-EKE: ICV mismatch in Prot() data"); return -1; } diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c index 04b987d..fceb1b0 100644 --- a/src/eap_common/eap_fast_common.c +++ b/src/eap_common/eap_fast_common.c @@ -174,7 +174,7 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk) int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, int len) + int tlv_type, u8 *pos, size_t len) { switch (tlv_type) { case EAP_TLV_EAP_PAYLOAD_TLV: diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h index 8955617..d59a845 100644 --- a/src/eap_common/eap_fast_common.h +++ b/src/eap_common/eap_fast_common.h @@ -102,6 +102,6 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, int len); + int tlv_type, u8 *pos, size_t len); #endif /* EAP_FAST_H */ diff --git a/src/eap_common/eap_gpsk_common.c b/src/eap_common/eap_gpsk_common.c index 7a33215..8c7ae27 100644 --- a/src/eap_common/eap_gpsk_common.c +++ b/src/eap_common/eap_gpsk_common.c @@ -284,7 +284,6 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, u8 *pk, size_t *pk_len) { u8 *seed, *pos; - size_t seed_len; int ret; wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)", @@ -296,8 +295,7 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len); /* Seed = RAND_Peer || ID_Peer || RAND_Server || ID_Server */ - seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; - seed = os_malloc(seed_len); + seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len); if (seed == NULL) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " "for key derivation"); @@ -313,17 +311,18 @@ int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, pos += EAP_GPSK_RAND_LEN; os_memcpy(pos, id_server, id_server_len); pos += id_server_len; - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); + wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed); switch (specifier) { case EAP_GPSK_CIPHER_AES: - ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len, + ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, pos - seed, msk, emsk, sk, sk_len, pk, pk_len); break; #ifdef EAP_GPSK_SHA256 case EAP_GPSK_CIPHER_SHA256: - ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len, + ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, + pos - seed, msk, emsk, sk, sk_len); break; #endif /* EAP_GPSK_SHA256 */ @@ -423,7 +422,6 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, { u8 *seed, *pos; u8 kdf_out[16]; - size_t seed_len; int ret; wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving Session ID(%d:%d)", @@ -441,8 +439,7 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, * Method-ID = GKDF-16 (zero, "Method ID" || EAP_Method_Type || * CSuite_Sel || inputString) */ - seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len; - seed = os_malloc(seed_len); + seed = os_malloc(2 * EAP_GPSK_RAND_LEN + id_server_len + id_peer_len); if (seed == NULL) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory " "for Session-Id derivation"); @@ -458,11 +455,11 @@ int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, pos += EAP_GPSK_RAND_LEN; os_memcpy(pos, id_server, id_server_len); pos += id_server_len; - wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len); + wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, pos - seed); ret = eap_gpsk_derive_mid_helper(specifier, kdf_out, sizeof(kdf_out), - psk, seed, seed_len, + psk, seed, pos - seed, method_type); sid[0] = method_type; diff --git a/src/eap_common/eap_ikev2_common.c b/src/eap_common/eap_ikev2_common.c index 6095fd8..585c79c 100644 --- a/src/eap_common/eap_ikev2_common.c +++ b/src/eap_common/eap_ikev2_common.c @@ -52,22 +52,12 @@ struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code) { struct wpabuf *msg; -#ifdef CCNS_PL - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 1, code, id); - if (msg == NULL) { - wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " - "for fragment ack"); - return NULL; - } - wpabuf_put_u8(msg, 0); /* Flags */ -#else /* CCNS_PL */ msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IKEV2, 0, code, id); if (msg == NULL) { wpa_printf(MSG_ERROR, "EAP-IKEV2: Failed to allocate memory " "for fragment ack"); return NULL; } -#endif /* CCNS_PL */ wpa_printf(MSG_DEBUG, "EAP-IKEV2: Send fragment ack"); @@ -110,7 +100,7 @@ int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, return -1; } - if (os_memcmp(icv, end - icv_len, icv_len) != 0) { + if (os_memcmp_const(icv, end - icv_len, icv_len) != 0) { wpa_printf(MSG_INFO, "EAP-IKEV2: Invalid ICV"); wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Calculated ICV", icv, icv_len); diff --git a/src/eap_common/eap_ikev2_common.h b/src/eap_common/eap_ikev2_common.h index 329ccc4..e7502d7 100644 --- a/src/eap_common/eap_ikev2_common.h +++ b/src/eap_common/eap_ikev2_common.h @@ -9,16 +9,9 @@ #ifndef EAP_IKEV2_COMMON_H #define EAP_IKEV2_COMMON_H -#ifdef CCNS_PL -/* incorrect bit order */ -#define IKEV2_FLAGS_LENGTH_INCLUDED 0x01 -#define IKEV2_FLAGS_MORE_FRAGMENTS 0x02 -#define IKEV2_FLAGS_ICV_INCLUDED 0x04 -#else /* CCNS_PL */ #define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 #define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 #define IKEV2_FLAGS_ICV_INCLUDED 0x20 -#endif /* CCNS_PL */ #define IKEV2_FRAGMENT_SIZE 1400 diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c index 96c9efd..631c363 100644 --- a/src/eap_common/eap_pwd_common.c +++ b/src/eap_common/eap_pwd_common.c @@ -106,9 +106,11 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, case 21: nid = NID_secp521r1; break; +#ifndef OPENSSL_IS_BORINGSSL case 25: nid = NID_X9_62_prime192v1; break; +#endif /* OPENSSL_IS_BORINGSSL */ case 26: nid = NID_secp224r1; break; @@ -263,18 +265,18 @@ int compute_password_element(EAP_PWD_group *grp, u16 num, fail: EC_GROUP_free(grp->group); grp->group = NULL; - EC_POINT_free(grp->pwe); + EC_POINT_clear_free(grp->pwe); grp->pwe = NULL; - BN_free(grp->order); + BN_clear_free(grp->order); grp->order = NULL; - BN_free(grp->prime); + BN_clear_free(grp->prime); grp->prime = NULL; ret = 1; } /* cleanliness and order.... */ - BN_free(cofactor); - BN_free(x_candidate); - BN_free(rnd); + BN_clear_free(cofactor); + BN_clear_free(x_candidate); + BN_clear_free(rnd); os_free(prfbuf); return ret; diff --git a/src/eap_common/eap_sim_common.c b/src/eap_common/eap_sim_common.c index e1773bf..2adc3b3 100644 --- a/src/eap_common/eap_sim_common.c +++ b/src/eap_common/eap_sim_common.c @@ -198,7 +198,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, hmac, EAP_SIM_MAC_LEN); os_free(tmp); - return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; + return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; } @@ -393,7 +393,7 @@ int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, hmac, EAP_SIM_MAC_LEN); os_free(tmp); - return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; + return (os_memcmp_const(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1; } @@ -893,7 +893,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end, if (attr->kdf_count == EAP_AKA_PRIME_KDF_MAX) { wpa_printf(MSG_DEBUG, "EAP-AKA': Too many " "AT_KDF attributes - ignore this"); - continue; + break; } attr->kdf[attr->kdf_count] = WPA_GET_BE16(apos); attr->kdf_count++; @@ -972,7 +972,6 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, struct eap_sim_msg { struct wpabuf *buf; size_t mac, iv, encr; /* index from buf */ - int type; }; @@ -986,7 +985,6 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype) if (msg == NULL) return NULL; - msg->type = type; msg->buf = wpabuf_alloc(EAP_SIM_INIT_LEN); if (msg->buf == NULL) { os_free(msg); @@ -1006,7 +1004,8 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype) } -struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, +struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type, + const u8 *k_aut, const u8 *extra, size_t extra_len) { struct eap_hdr *eap; @@ -1019,7 +1018,7 @@ struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, eap->length = host_to_be16(wpabuf_len(msg->buf)); #if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) - if (k_aut && msg->mac && msg->type == EAP_TYPE_AKA_PRIME) { + if (k_aut && msg->mac && type == EAP_TYPE_AKA_PRIME) { eap_sim_add_mac_sha256(k_aut, (u8 *) wpabuf_head(msg->buf), wpabuf_len(msg->buf), (u8 *) wpabuf_mhead(msg->buf) + diff --git a/src/eap_common/eap_sim_common.h b/src/eap_common/eap_sim_common.h index 6021bd2..daeb0e2 100644 --- a/src/eap_common/eap_sim_common.h +++ b/src/eap_common/eap_sim_common.h @@ -211,7 +211,8 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, struct eap_sim_msg; struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); -struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, +struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type, + const u8 *k_aut, const u8 *extra, size_t extra_len); void eap_sim_msg_free(struct eap_sim_msg *msg); u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c index f061866..3d4fb6f 100644 --- a/src/eap_common/ikev2_common.c +++ b/src/eap_common/ikev2_common.c @@ -173,46 +173,12 @@ const struct ikev2_encr_alg * ikev2_get_encr(int id) } -#ifdef CCNS_PL -/* from des.c */ -struct des3_key_s { - u32 ek[3][32]; - u32 dk[3][32]; -}; - -void des3_key_setup(const u8 *key, struct des3_key_s *dkey); -void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt); -void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain); -#endif /* CCNS_PL */ - - int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, const u8 *plain, u8 *crypt, size_t len) { struct crypto_cipher *cipher; int encr_alg; -#ifdef CCNS_PL - if (alg == ENCR_3DES) { - struct des3_key_s des3key; - size_t i, blocks; - u8 *pos; - - /* ECB mode is used incorrectly for 3DES!? */ - if (key_len != 24) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); - return -1; - } - des3_key_setup(key, &des3key); - - blocks = len / 8; - pos = crypt; - for (i = 0; i < blocks; i++) { - des3_encrypt(pos, &des3key, pos); - pos += 8; - } - } else { -#endif /* CCNS_PL */ switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; @@ -237,9 +203,6 @@ int ikev2_encr_encrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, return -1; } crypto_cipher_deinit(cipher); -#ifdef CCNS_PL - } -#endif /* CCNS_PL */ return 0; } @@ -251,31 +214,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, struct crypto_cipher *cipher; int encr_alg; -#ifdef CCNS_PL - if (alg == ENCR_3DES) { - struct des3_key_s des3key; - size_t i, blocks; - - /* ECB mode is used incorrectly for 3DES!? */ - if (key_len != 24) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encr key length"); - return -1; - } - des3_key_setup(key, &des3key); - - if (len % 8) { - wpa_printf(MSG_INFO, "IKEV2: Invalid encrypted " - "length"); - return -1; - } - blocks = len / 8; - for (i = 0; i < blocks; i++) { - des3_decrypt(crypt, &des3key, plain); - plain += 8; - crypt += 8; - } - } else { -#endif /* CCNS_PL */ switch (alg) { case ENCR_3DES: encr_alg = CRYPTO_CIPHER_ALG_3DES; @@ -300,9 +238,6 @@ int ikev2_encr_decrypt(int alg, const u8 *key, size_t key_len, const u8 *iv, return -1; } crypto_cipher_deinit(cipher); -#ifdef CCNS_PL - } -#endif /* CCNS_PL */ return 0; } @@ -542,7 +477,7 @@ u8 * ikev2_decrypt_payload(int encr_id, int integ_id, "hash"); return NULL; } - if (os_memcmp(integ, hash, integ_alg->hash_len) != 0) { + if (os_memcmp_const(integ, hash, integ_alg->hash_len) != 0) { wpa_printf(MSG_INFO, "IKEV2: Incorrect Integrity Checksum " "Data"); return NULL; @@ -706,10 +641,6 @@ int ikev2_derive_sk_keys(const struct ikev2_prf_alg *prf, keys->SK_integ_len = integ->key_len; keys->SK_encr_len = encr->key_len; keys->SK_prf_len = prf->key_len; -#ifdef CCNS_PL - /* Uses encryption key length for SK_d; should be PRF length */ - keys->SK_d_len = keys->SK_encr_len; -#endif /* CCNS_PL */ keybuf_len = keys->SK_d_len + 2 * keys->SK_integ_len + 2 * keys->SK_encr_len + 2 * keys->SK_prf_len; diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h index 45c970b..8a7982a 100644 --- a/src/eap_common/ikev2_common.h +++ b/src/eap_common/ikev2_common.h @@ -70,11 +70,7 @@ struct ikev2_transform { /* Current IKEv2 version from RFC 4306 */ #define IKEV2_MjVer 2 #define IKEV2_MnVer 0 -#ifdef CCNS_PL -#define IKEV2_VERSION ((IKEV2_MjVer) | ((IKEV2_MnVer) << 4)) -#else /* CCNS_PL */ #define IKEV2_VERSION (((IKEV2_MjVer) << 4) | (IKEV2_MnVer)) -#endif /* CCNS_PL */ /* IKEv2 Exchange Types */ enum { diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c index 47cbbee..9880d3b 100644 --- a/src/eap_peer/eap.c +++ b/src/eap_peer/eap.c @@ -92,6 +92,15 @@ static void eap_notify_status(struct eap_sm *sm, const char *status, } +static void eap_sm_free_key(struct eap_sm *sm) +{ + if (sm->eapKeyData) { + bin_clear_free(sm->eapKeyData, sm->eapKeyDataLen); + sm->eapKeyData = NULL; + } +} + + static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt) { ext_password_free(sm->ext_pw_buf); @@ -144,11 +153,13 @@ SM_STATE(EAP, INITIALIZE) SM_ENTRY(EAP, INITIALIZE); if (sm->fast_reauth && sm->m && sm->m->has_reauth_data && sm->m->has_reauth_data(sm, sm->eap_method_priv) && - !sm->prev_failure) { + !sm->prev_failure && + sm->last_config == eap_get_config(sm)) { wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for " "fast reauthentication"); sm->m->deinit_for_reauth(sm, sm->eap_method_priv); } else { + sm->last_config = eap_get_config(sm); eap_deinit_prev_method(sm, "INITIALIZE"); } sm->selectedMethod = EAP_TYPE_NONE; @@ -159,8 +170,7 @@ SM_STATE(EAP, INITIALIZE) eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout); eapol_set_bool(sm, EAPOL_eapSuccess, FALSE); eapol_set_bool(sm, EAPOL_eapFail, FALSE); - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; + eap_sm_free_key(sm); os_free(sm->eapSessionId); sm->eapSessionId = NULL; sm->eapKeyAvailable = FALSE; @@ -404,7 +414,7 @@ SM_STATE(EAP, METHOD) if (sm->m->isKeyAvailable && sm->m->getKey && sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { - os_free(sm->eapKeyData); + eap_sm_free_key(sm); sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, &sm->eapKeyDataLen); os_free(sm->eapSessionId); @@ -1488,8 +1498,7 @@ void eap_sm_abort(struct eap_sm *sm) sm->lastRespData = NULL; wpabuf_free(sm->eapRespData); sm->eapRespData = NULL; - os_free(sm->eapKeyData); - sm->eapKeyData = NULL; + eap_sm_free_key(sm); os_free(sm->eapSessionId); sm->eapSessionId = NULL; diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c index fee1b7b..0662ae7 100644 --- a/src/eap_peer/eap_aka.c +++ b/src/eap_peer/eap_aka.c @@ -42,7 +42,7 @@ struct eap_aka_data { u8 *last_eap_identity; size_t last_eap_identity_len; enum { - CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE + CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE } state; struct wpabuf *id_msgs; @@ -64,8 +64,6 @@ static const char * eap_aka_state_txt(int state) return "CONTINUE"; case RESULT_SUCCESS: return "RESULT_SUCCESS"; - case RESULT_FAILURE: - return "RESULT_FAILURE"; case SUCCESS: return "SUCCESS"; case FAILURE: @@ -128,6 +126,21 @@ static void * eap_aka_prime_init(struct eap_sm *sm) #endif /* EAP_AKA_PRIME */ +static void eap_aka_clear_keys(struct eap_aka_data *data, int reauth) +{ + if (!reauth) { + os_memset(data->mk, 0, EAP_SIM_MK_LEN); + os_memset(data->k_aut, 0, EAP_AKA_PRIME_K_AUT_LEN); + os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN); + os_memset(data->k_re, 0, EAP_AKA_PRIME_K_RE_LEN); + } + os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); + os_memset(data->autn, 0, EAP_AKA_AUTN_LEN); + os_memset(data->auts, 0, EAP_AKA_AUTS_LEN); +} + + static void eap_aka_deinit(struct eap_sm *sm, void *priv) { struct eap_aka_data *data = priv; @@ -137,6 +150,7 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv) os_free(data->last_eap_identity); wpabuf_free(data->id_msgs); os_free(data->network_name); + eap_aka_clear_keys(data, 0); os_free(data); } } @@ -153,7 +167,7 @@ static int eap_aka_ext_sim_req(struct eap_sm *sm, struct eap_aka_data *data) pos += os_snprintf(pos, end - pos, ":"); pos += wpa_snprintf_hex(pos, end - pos, data->rand, EAP_AKA_RAND_LEN); pos += os_snprintf(pos, end - pos, ":"); - pos += wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN); + wpa_snprintf_hex(pos, end - pos, data->autn, EAP_AKA_AUTN_LEN); eap_sm_request_sim(sm, req); return 1; @@ -296,7 +310,7 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data) { u8 autn[EAP_AKA_AUTN_LEN]; os_memset(autn, '1', EAP_AKA_AUTN_LEN); - if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) { + if (os_memcmp_const(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match " "with expected value"); return -1; @@ -511,7 +525,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data, #endif /* EAP_AKA_PRIME */ sha1_vector(1, &addr, &len, hash); - if (os_memcmp(hash, checkcode, hash_len) != 0) { + if (os_memcmp_const(hash, checkcode, hash_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); return -1; } @@ -534,7 +548,7 @@ static struct wpabuf * eap_aka_client_error(struct eap_aka_data *data, u8 id, msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, EAP_AKA_SUBTYPE_CLIENT_ERROR); eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -551,7 +565,7 @@ static struct wpabuf * eap_aka_authentication_reject(struct eap_aka_data *data, "(id=%d)", id); msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, data->eap_method, EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -570,7 +584,7 @@ static struct wpabuf * eap_aka_synchronization_failure( wpa_printf(MSG_DEBUG, " AT_AUTS"); eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, EAP_AKA_AUTS_LEN); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -614,7 +628,7 @@ static struct wpabuf * eap_aka_response_identity(struct eap_sm *sm, identity, identity_len); } - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -636,7 +650,8 @@ static struct wpabuf * eap_aka_response_challenge(struct eap_aka_data *data, } wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, (u8 *) "", 0); + return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, (u8 *) "", + 0); } @@ -678,7 +693,7 @@ static struct wpabuf * eap_aka_response_reauth(struct eap_aka_data *data, } wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, nonce_s, + return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, nonce_s, EAP_SIM_NONCE_S_LEN); } @@ -712,7 +727,7 @@ static struct wpabuf * eap_aka_response_notification(struct eap_aka_data *data, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); } - return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); + return eap_sim_msg_finish(msg, data->eap_method, k_aut, (u8 *) "", 0); } @@ -792,7 +807,7 @@ static struct wpabuf * eap_aka_prime_kdf_select(struct eap_aka_data *data, EAP_AKA_SUBTYPE_CHALLENGE); wpa_printf(MSG_DEBUG, " AT_KDF"); eap_sim_msg_add(msg, EAP_SIM_AT_KDF, kdf, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); } @@ -1025,7 +1040,7 @@ static struct wpabuf * eap_aka_process_challenge(struct eap_sm *sm, if (data->result_ind && attr->result_ind) data->use_result_ind = 1; - if (data->state != FAILURE && data->state != RESULT_FAILURE) { + if (data->state != FAILURE) { eap_aka_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } @@ -1241,7 +1256,7 @@ static struct wpabuf * eap_aka_process_reauthentication( if (data->result_ind && attr->result_ind) data->use_result_ind = 1; - if (data->state != FAILURE && data->state != RESULT_FAILURE) { + if (data->state != FAILURE) { eap_aka_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } @@ -1347,9 +1362,7 @@ done: */ ret->methodState = data->use_result_ind ? METHOD_DONE : METHOD_MAY_CONT; - } else if (data->state == RESULT_FAILURE) - ret->methodState = METHOD_CONT; - else if (data->state == RESULT_SUCCESS) + } else if (data->state == RESULT_SUCCESS) ret->methodState = METHOD_CONT; if (ret->methodState == METHOD_DONE) { @@ -1376,6 +1389,7 @@ static void eap_aka_deinit_for_reauth(struct eap_sm *sm, void *priv) data->id_msgs = NULL; data->use_result_ind = 0; data->kdf_negotiation = 0; + eap_aka_clear_keys(data, 1); } diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h index daa1d32..2591e11 100644 --- a/src/eap_peer/eap_config.h +++ b/src/eap_peer/eap_config.h @@ -157,7 +157,7 @@ struct eap_peer_config { * * If left out, this will be asked through control interface. */ - u8 *private_key_passwd; + char *private_key_passwd; /** * dh_file - File path to DH/DSA parameters file (in PEM format) @@ -289,7 +289,7 @@ struct eap_peer_config { * This field is like private_key_passwd, but used for phase 2 (inside * EAP-TTLS/PEAP/FAST tunnel) authentication. */ - u8 *private_key2_passwd; + char *private_key2_passwd; /** * dh_file2 - File path to DH/DSA parameters file (in PEM format) diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c index 864ea1d..9fec66c 100644 --- a/src/eap_peer/eap_eke.c +++ b/src/eap_peer/eap_eke.c @@ -138,7 +138,7 @@ static void eap_eke_deinit(struct eap_sm *sm, void *priv) os_free(data->serverid); os_free(data->peerid); wpabuf_free(data->msgs); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -451,7 +451,7 @@ static struct wpabuf * eap_eke_process_commit(struct eap_sm *sm, /* DHComponent_P = Encr(key, y_p) */ rpos = wpabuf_put(resp, data->sess.dhcomp_len); if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S"); + wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P"); os_memset(key, 0, sizeof(key)); return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); @@ -523,7 +523,7 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, end = payload + payload_len; if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) { - wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit"); + wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm"); return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_PROTO_ERROR); } @@ -543,7 +543,7 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S", nonces, 2 * data->sess.nonce_len); if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) { - wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P"); + wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P"); return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_AUTHENTICATION_FAIL); } @@ -566,8 +566,8 @@ static struct wpabuf * eap_eke_process_confirm(struct eap_eke_data *data, EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR); } wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_S", auth_s, data->sess.prf_len); - if (os_memcmp(auth_s, pos + data->sess.pnonce_ps_len, - data->sess.prf_len) != 0) { + if (os_memcmp_const(auth_s, pos + data->sess.pnonce_ps_len, + data->sess.prf_len) != 0) { wpa_printf(MSG_INFO, "EAP-EKE: Auth_S does not match"); return eap_eke_build_fail(data, ret, reqData, EAP_EKE_FAIL_AUTHENTICATION_FAIL); diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c index cc1f264..0739187 100644 --- a/src/eap_peer/eap_fast.c +++ b/src/eap_peer/eap_fast.c @@ -250,6 +250,8 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv) pac = pac->next; eap_fast_free_pac(prev); } + os_memset(data->key_data, 0, EAP_FAST_KEY_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -767,7 +769,7 @@ static struct wpabuf * eap_fast_process_crypto_binding( "MAC calculation", (u8 *) _bind, bind_len); hmac_sha1(cmk, EAP_FAST_CMK_LEN, (u8 *) _bind, bind_len, _bind->compound_mac); - res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac)); + res = os_memcmp_const(cmac, _bind->compound_mac, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC", cmac, sizeof(cmac)); wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", @@ -1080,7 +1082,8 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted, struct eap_fast_tlv_parse *tlv, struct wpabuf **resp) { - int mandatory, tlv_type, len, res; + int mandatory, tlv_type, res; + size_t len; u8 *pos, *end; os_memset(tlv, 0, sizeof(*tlv)); @@ -1094,13 +1097,14 @@ static int eap_fast_parse_decrypted(struct wpabuf *decrypted, pos += 2; len = WPA_GET_BE16(pos); pos += 2; - if (pos + len > end) { + if (len > (size_t) (end - pos)) { wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); return -1; } wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " - "TLV type %d length %d%s", - tlv_type, len, mandatory ? " (mandatory)" : ""); + "TLV type %d length %u%s", + tlv_type, (unsigned int) len, + mandatory ? " (mandatory)" : ""); res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); if (res == -2) @@ -1634,6 +1638,8 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv) os_free(data); return NULL; } + os_memset(data->key_data, 0, EAP_FAST_KEY_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); os_free(data->session_id); data->session_id = NULL; if (data->phase2_priv && data->phase2_method && diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c index 5b023c7..c54bf11 100644 --- a/src/eap_peer/eap_gpsk.c +++ b/src/eap_peer/eap_gpsk.c @@ -134,8 +134,11 @@ static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) struct eap_gpsk_data *data = priv; os_free(data->id_server); os_free(data->id_peer); - os_free(data->psk); - os_free(data); + if (data->psk) { + os_memset(data->psk, 0, data->psk_len); + os_free(data->psk); + } + bin_clear_free(data, sizeof(*data)); } @@ -236,6 +239,8 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, size_t *list_len, const u8 *pos, const u8 *end) { + size_t len; + if (pos == NULL) return NULL; @@ -243,23 +248,25 @@ static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); return NULL; } - *list_len = WPA_GET_BE16(pos); + len = WPA_GET_BE16(pos); pos += 2; - if (end - pos < (int) *list_len) { + if (len > (size_t) (end - pos)) { wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); return NULL; } - if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) { + if (len == 0 || (len % sizeof(struct eap_gpsk_csuite))) { wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu", - (unsigned long) *list_len); + (unsigned long) len); return NULL; } - *list = pos; - pos += *list_len; - if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0) + if (eap_gpsk_select_csuite(sm, data, pos, len) < 0) return NULL; + *list = pos; + *list_len = len; + pos += len; + return pos; } @@ -561,7 +568,7 @@ static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data, wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); return NULL; } - if (os_memcmp(mic, pos, miclen) != 0) { + if (os_memcmp_const(mic, pos, miclen) != 0) { wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h index 8288ba5..fde809c 100644 --- a/src/eap_peer/eap_i.h +++ b/src/eap_peer/eap_i.h @@ -345,6 +345,7 @@ struct eap_sm { struct wps_context *wps; int prev_failure; + struct eap_peer_config *last_config; struct ext_password_data *ext_pw; struct wpabuf *ext_pw_buf; diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c index 45945fe..c12b519 100644 --- a/src/eap_peer/eap_ikev2.c +++ b/src/eap_peer/eap_ikev2.c @@ -113,7 +113,7 @@ static void eap_ikev2_deinit(struct eap_sm *sm, void *priv) wpabuf_free(data->in_buf); wpabuf_free(data->out_buf); ikev2_responder_deinit(&data->ikev2); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -154,12 +154,6 @@ static struct wpabuf * eap_ikev2_build_msg(struct eap_ikev2_data *data, send_len -= 4; } } -#ifdef CCNS_PL - /* Some issues figuring out the length of the message if Message Length - * field not included?! */ - if (!(flags & IKEV2_FLAGS_LENGTH_INCLUDED)) - flags |= IKEV2_FLAGS_LENGTH_INCLUDED; -#endif /* CCNS_PL */ plen = 1 + send_len; if (flags & IKEV2_FLAGS_LENGTH_INCLUDED) @@ -381,12 +375,7 @@ static struct wpabuf * eap_ikev2_process(struct eap_sm *sm, void *priv, "Message Length %u", flags, message_length); if (data->state == WAIT_FRAG_ACK) { -#ifdef CCNS_PL - if (len > 1) /* Empty Flags field included in ACK */ -#else /* CCNS_PL */ - if (len != 0) -#endif /* CCNS_PL */ - { + if (len != 0) { wpa_printf(MSG_DEBUG, "EAP-IKEV2: Unexpected payload " "in WAIT_FRAG_ACK state"); ret->ignore = TRUE; diff --git a/src/eap_peer/eap_leap.c b/src/eap_peer/eap_leap.c index df34013..e0f8bcf 100644 --- a/src/eap_peer/eap_leap.c +++ b/src/eap_peer/eap_leap.c @@ -244,7 +244,7 @@ static struct wpabuf * eap_leap_process_response(struct eap_sm *sm, void *priv, ret->methodState = METHOD_DONE; ret->allowNotifications = FALSE; - if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) { + if (os_memcmp_const(pos, expected, LEAP_RESPONSE_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid " "response - authentication failed"); wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP", @@ -383,6 +383,9 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len) wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN); *len = LEAP_KEY_LEN; + os_memset(pw_hash, 0, sizeof(pw_hash)); + os_memset(pw_hash_hash, 0, sizeof(pw_hash_hash)); + return key; } diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c index f9aa742..430c501 100644 --- a/src/eap_peer/eap_mschapv2.c +++ b/src/eap_peer/eap_mschapv2.c @@ -140,7 +140,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv) os_free(data->peer_challenge); os_free(data->auth_challenge); wpabuf_free(data->prev_challenge); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -303,18 +303,23 @@ static void eap_mschapv2_password_changed(struct eap_sm *sm, WPA_EVENT_PASSWORD_CHANGED "EAP-MSCHAPV2: Password changed successfully"); data->prev_error = 0; - os_free(config->password); + bin_clear_free(config->password, config->password_len); if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { /* TODO: update external storage */ } else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) { config->password = os_malloc(16); config->password_len = 16; - if (config->password) { - nt_password_hash(config->new_password, - config->new_password_len, - config->password); + if (config->password && + nt_password_hash(config->new_password, + config->new_password_len, + config->password)) { + bin_clear_free(config->password, + config->password_len); + config->password = NULL; + config->password_len = 0; } - os_free(config->new_password); + bin_clear_free(config->new_password, + config->new_password_len); } else { config->password = config->new_password; config->password_len = config->new_password_len; @@ -549,15 +554,17 @@ static struct wpabuf * eap_mschapv2_change_password( /* Encrypted-Hash */ if (pwhash) { u8 new_password_hash[16]; - nt_password_hash(new_password, new_password_len, - new_password_hash); + if (nt_password_hash(new_password, new_password_len, + new_password_hash)) + goto fail; nt_password_hash_encrypted_with_block(password, new_password_hash, cp->encr_hash); } else { - old_nt_password_hash_encrypted_with_new_nt_password_hash( - new_password, new_password_len, - password, password_len, cp->encr_hash); + if (old_nt_password_hash_encrypted_with_new_nt_password_hash( + new_password, new_password_len, + password, password_len, cp->encr_hash)) + goto fail; } /* Peer-Challenge */ @@ -594,9 +601,13 @@ static struct wpabuf * eap_mschapv2_change_password( /* Likewise, generate master_key here since we have the needed data * available. */ - nt_password_hash(new_password, new_password_len, password_hash); - hash_nt_password_hash(password_hash, password_hash_hash); - get_master_key(password_hash_hash, cp->nt_response, data->master_key); + if (nt_password_hash(new_password, new_password_len, password_hash) || + hash_nt_password_hash(password_hash, password_hash_hash) || + get_master_key(password_hash_hash, cp->nt_response, + data->master_key)) { + data->auth_response_valid = 0; + goto fail; + } data->master_key_valid = 1; /* Flags */ diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c index 7f87052..1c111c2 100644 --- a/src/eap_peer/eap_pax.c +++ b/src/eap_peer/eap_pax.c @@ -86,7 +86,7 @@ static void eap_pax_deinit(struct eap_sm *sm, void *priv) { struct eap_pax_data *data = priv; os_free(data->cid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -278,7 +278,7 @@ static struct wpabuf * eap_pax_process_std_3(struct eap_pax_data *data, eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN, data->rand.r.y, EAP_PAX_RAND_LEN, (u8 *) data->cid, data->cid_len, NULL, 0, mac); - if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) { + if (os_memcmp_const(pos, mac, EAP_PAX_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) " "received"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)", @@ -415,7 +415,7 @@ static struct wpabuf * eap_pax_process(struct eap_sm *sm, void *priv, wpabuf_head(reqData), mlen, NULL, 0, NULL, 0, icvbuf); } - if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) { + if (os_memcmp_const(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the " "message"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV", diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c index 8634f75..472e861 100644 --- a/src/eap_peer/eap_peap.c +++ b/src/eap_peer/eap_peap.c @@ -170,6 +170,15 @@ static void * eap_peap_init(struct eap_sm *sm) } +static void eap_peap_free_key(struct eap_peap_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN); + data->key_data = NULL; + } +} + + static void eap_peap_deinit(struct eap_sm *sm, void *priv) { struct eap_peap_data *data = priv; @@ -179,7 +188,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv) data->phase2_method->deinit(sm, data->phase2_priv); os_free(data->phase2_types); eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_peap_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -423,7 +432,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, buf, sizeof(buf)); hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); - if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { + if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " "cryptobinding TLV"); wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", @@ -1005,7 +1014,7 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, char *label; wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS done, proceed to Phase 2"); - os_free(data->key_data); + eap_peap_free_key(data); /* draft-josefsson-ppext-eap-tls-eap-05.txt * specifies that PEAPv1 would use "client PEAP * encryption" as the label. However, most existing @@ -1115,8 +1124,7 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_peap_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_peap_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { diff --git a/src/eap_peer/eap_psk.c b/src/eap_peer/eap_psk.c index cd0e3f9..f012663 100644 --- a/src/eap_peer/eap_psk.c +++ b/src/eap_peer/eap_psk.c @@ -76,7 +76,7 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv) struct eap_psk_data *data = priv; os_free(data->id_s); os_free(data->id_p); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -237,7 +237,7 @@ static struct wpabuf * eap_psk_process_3(struct eap_psk_data *data, return NULL; } os_free(buf); - if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { + if (os_memcmp_const(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) { wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third " "message"); ret->methodState = METHOD_DONE; diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c index 2aa7ba5..1c915ed 100644 --- a/src/eap_peer/eap_pwd.c +++ b/src/eap_peer/eap_pwd.c @@ -123,7 +123,7 @@ static void * eap_pwd_init(struct eap_sm *sm) if ((data->password = os_malloc(password_len)) == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: memory allocation psk fail"); BN_CTX_free(data->bnctx); - os_free(data->id_peer); + bin_clear_free(data->id_peer, data->id_peer_len); os_free(data); return NULL; } @@ -148,26 +148,26 @@ static void eap_pwd_deinit(struct eap_sm *sm, void *priv) { struct eap_pwd_data *data = priv; - BN_free(data->private_value); - BN_free(data->server_scalar); - BN_free(data->my_scalar); - BN_free(data->k); + BN_clear_free(data->private_value); + BN_clear_free(data->server_scalar); + BN_clear_free(data->my_scalar); + BN_clear_free(data->k); BN_CTX_free(data->bnctx); - EC_POINT_free(data->my_element); - EC_POINT_free(data->server_element); - os_free(data->id_peer); - os_free(data->id_server); - os_free(data->password); + EC_POINT_clear_free(data->my_element); + EC_POINT_clear_free(data->server_element); + bin_clear_free(data->id_peer, data->id_peer_len); + bin_clear_free(data->id_server, data->id_server_len); + bin_clear_free(data->password, data->password_len); if (data->grp) { EC_GROUP_free(data->grp->group); - EC_POINT_free(data->grp->pwe); - BN_free(data->grp->order); - BN_free(data->grp->prime); + EC_POINT_clear_free(data->grp->pwe); + BN_clear_free(data->grp->order); + BN_clear_free(data->grp->prime); os_free(data->grp); } wpabuf_free(data->inbuf); wpabuf_free(data->outbuf); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -317,11 +317,15 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, goto fin; } - BN_rand_range(data->private_value, data->grp->order); - BN_rand_range(mask, data->grp->order); - BN_add(data->my_scalar, data->private_value, mask); - BN_mod(data->my_scalar, data->my_scalar, data->grp->order, - data->bnctx); + if (BN_rand_range(data->private_value, data->grp->order) != 1 || + BN_rand_range(mask, data->grp->order) != 1 || + BN_add(data->my_scalar, data->private_value, mask) != 1 || + BN_mod(data->my_scalar, data->my_scalar, data->grp->order, + data->bnctx) != 1) { + wpa_printf(MSG_INFO, + "EAP-pwd (peer): unable to get randomness"); + goto fin; + } if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, data->grp->pwe, mask, data->bnctx)) { @@ -336,7 +340,7 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, wpa_printf(MSG_INFO, "EAP-PWD (peer): element inversion fail"); goto fin; } - BN_free(mask); + BN_clear_free(mask); if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { @@ -471,11 +475,11 @@ eap_pwd_perform_commit_exchange(struct eap_sm *sm, struct eap_pwd_data *data, fin: os_free(scalar); os_free(element); - BN_free(x); - BN_free(y); - BN_free(cofactor); - EC_POINT_free(K); - EC_POINT_free(point); + BN_clear_free(x); + BN_clear_free(y); + BN_clear_free(cofactor); + EC_POINT_clear_free(K); + EC_POINT_clear_free(point); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); else @@ -589,7 +593,7 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_final(hash, conf); ptr = (u8 *) payload; - if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) { + if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { wpa_printf(MSG_INFO, "EAP-PWD (peer): confirm did not verify"); goto fin; } @@ -680,9 +684,9 @@ eap_pwd_perform_confirm_exchange(struct eap_sm *sm, struct eap_pwd_data *data, wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); fin: - os_free(cruft); - BN_free(x); - BN_free(y); + bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); + BN_clear_free(x); + BN_clear_free(y); if (data->outbuf == NULL) { ret->methodState = METHOD_DONE; ret->decision = DECISION_FAIL; @@ -782,6 +786,8 @@ eap_pwd_process(struct eap_sm *sm, void *priv, struct eap_method_ret *ret, tot_len = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments whose " "total length = %d", tot_len); + if (tot_len > 15000) + return NULL; data->inbuf = wpabuf_alloc(tot_len); if (data->inbuf == NULL) { wpa_printf(MSG_INFO, "Out of memory to buffer " diff --git a/src/eap_peer/eap_sake.c b/src/eap_peer/eap_sake.c index 431519c..7d14907 100644 --- a/src/eap_peer/eap_sake.c +++ b/src/eap_peer/eap_sake.c @@ -108,7 +108,7 @@ static void eap_sake_deinit(struct eap_sm *sm, void *priv) struct eap_sake_data *data = priv; os_free(data->serverid); os_free(data->peerid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -315,7 +315,7 @@ static struct wpabuf * eap_sake_process_confirm(struct eap_sm *sm, data->peerid, data->peerid_len, 0, wpabuf_head(reqData), wpabuf_len(reqData), attr.mic_s, mic_s); - if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { + if (os_memcmp_const(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S"); eap_sake_state(data, FAILURE); ret->methodState = METHOD_DONE; diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c index fc9df96..bd06df7 100644 --- a/src/eap_peer/eap_sim.c +++ b/src/eap_peer/eap_sim.c @@ -43,7 +43,7 @@ struct eap_sim_data { u8 *last_eap_identity; size_t last_eap_identity_len; enum { - CONTINUE, RESULT_SUCCESS, RESULT_FAILURE, SUCCESS, FAILURE + CONTINUE, RESULT_SUCCESS, SUCCESS, FAILURE } state; int result_ind, use_result_ind; }; @@ -57,8 +57,6 @@ static const char * eap_sim_state_txt(int state) return "CONTINUE"; case RESULT_SUCCESS: return "RESULT_SUCCESS"; - case RESULT_FAILURE: - return "RESULT_FAILURE"; case SUCCESS: return "SUCCESS"; case FAILURE: @@ -132,6 +130,20 @@ static void * eap_sim_init(struct eap_sm *sm) } +static void eap_sim_clear_keys(struct eap_sim_data *data, int reauth) +{ + if (!reauth) { + os_memset(data->mk, 0, EAP_SIM_MK_LEN); + os_memset(data->k_aut, 0, EAP_SIM_K_AUT_LEN); + os_memset(data->k_encr, 0, EAP_SIM_K_ENCR_LEN); + } + os_memset(data->kc, 0, 3 * EAP_SIM_KC_LEN); + os_memset(data->sres, 0, 3 * EAP_SIM_SRES_LEN); + os_memset(data->msk, 0, EAP_SIM_KEYING_DATA_LEN); + os_memset(data->emsk, 0, EAP_EMSK_LEN); +} + + static void eap_sim_deinit(struct eap_sm *sm, void *priv) { struct eap_sim_data *data = priv; @@ -140,6 +152,7 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv) os_free(data->pseudonym); os_free(data->reauth_id); os_free(data->last_eap_identity); + eap_sim_clear_keys(data, 0); os_free(data); } } @@ -451,7 +464,7 @@ static struct wpabuf * eap_sim_client_error(struct eap_sim_data *data, u8 id, msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id, EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CLIENT_ERROR); eap_sim_msg_add(msg, EAP_SIM_AT_CLIENT_ERROR_CODE, err, NULL, 0); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0); } @@ -504,7 +517,7 @@ static struct wpabuf * eap_sim_response_start(struct eap_sm *sm, identity, identity_len); } - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0); } @@ -522,7 +535,8 @@ static struct wpabuf * eap_sim_response_challenge(struct eap_sim_data *data, } wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, (u8 *) data->sres, + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, + (u8 *) data->sres, data->num_chal * EAP_SIM_SRES_LEN); } @@ -564,7 +578,7 @@ static struct wpabuf * eap_sim_response_reauth(struct eap_sim_data *data, } wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, nonce_s, + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, nonce_s, EAP_SIM_NONCE_S_LEN); } @@ -598,7 +612,7 @@ static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); } - return eap_sim_msg_finish(msg, k_aut, (u8 *) "", 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, k_aut, (u8 *) "", 0); } @@ -788,7 +802,7 @@ static struct wpabuf * eap_sim_process_challenge(struct eap_sm *sm, if (data->result_ind && attr->result_ind) data->use_result_ind = 1; - if (data->state != FAILURE && data->state != RESULT_FAILURE) { + if (data->state != FAILURE) { eap_sim_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } @@ -989,7 +1003,7 @@ static struct wpabuf * eap_sim_process_reauthentication( if (data->result_ind && attr->result_ind) data->use_result_ind = 1; - if (data->state != FAILURE && data->state != RESULT_FAILURE) { + if (data->state != FAILURE) { eap_sim_state(data, data->use_result_ind ? RESULT_SUCCESS : SUCCESS); } @@ -1088,9 +1102,7 @@ done: DECISION_UNCOND_SUCC : DECISION_COND_SUCC; ret->methodState = data->use_result_ind ? METHOD_DONE : METHOD_MAY_CONT; - } else if (data->state == RESULT_FAILURE) - ret->methodState = METHOD_CONT; - else if (data->state == RESULT_SUCCESS) + } else if (data->state == RESULT_SUCCESS) ret->methodState = METHOD_CONT; if (ret->methodState == METHOD_DONE) { @@ -1113,6 +1125,7 @@ static void eap_sim_deinit_for_reauth(struct eap_sm *sm, void *priv) struct eap_sim_data *data = priv; eap_sim_clear_identities(sm, data, CLEAR_EAP_ID); data->use_result_ind = 0; + eap_sim_clear_keys(data, 1); } diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c index bb9f3f2..5aa3fd5 100644 --- a/src/eap_peer/eap_tls.c +++ b/src/eap_peer/eap_tls.c @@ -125,13 +125,22 @@ static void * eap_wfa_unauth_tls_init(struct eap_sm *sm) #endif /* CONFIG_HS20 */ +static void eap_tls_free_key(struct eap_tls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); + data->key_data = NULL; + } +} + + static void eap_tls_deinit(struct eap_sm *sm, void *priv) { struct eap_tls_data *data = priv; if (data == NULL) return; eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_tls_free_key(data); os_free(data->session_id); os_free(data); } @@ -181,7 +190,7 @@ static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data, ret->methodState = METHOD_DONE; ret->decision = DECISION_UNCOND_SUCC; - os_free(data->key_data); + eap_tls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "client EAP encryption", EAP_TLS_KEY_LEN + @@ -267,8 +276,7 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_tls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_tls_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c index bc13647..25b9f12 100644 --- a/src/eap_peer/eap_tnc.c +++ b/src/eap_peer/eap_tnc.c @@ -243,7 +243,8 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv, message_length = WPA_GET_BE32(pos); pos += 4; - if (message_length < (u32) (end - pos)) { + if (message_length < (u32) (end - pos) || + message_length > 75000) { wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c index 5091bf0..771da58 100644 --- a/src/eap_peer/eap_ttls.c +++ b/src/eap_peer/eap_ttls.c @@ -133,6 +133,15 @@ static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm, } +static void eap_ttls_free_key(struct eap_ttls_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN); + data->key_data = NULL; + } +} + + static void eap_ttls_deinit(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; @@ -141,7 +150,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv) eap_ttls_phase2_eap_deinit(sm, data); os_free(data->phase2_eap_types); eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); + eap_ttls_free_key(data); os_free(data->session_id); wpabuf_free(data->pending_phase2_req); os_free(data); @@ -213,7 +222,7 @@ static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code, static int eap_ttls_v0_derive_key(struct eap_sm *sm, struct eap_ttls_data *data) { - os_free(data->key_data); + eap_ttls_free_key(data); data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, "ttls keying material", EAP_TLS_KEY_LEN); @@ -492,16 +501,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, wpabuf_put(msg, pos - buf); *resp = msg; - if (sm->workaround) { - /* At least FreeRADIUS seems to be terminating - * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success - * packet. */ - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " - "allow success without tunneled response"); - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - } - return 0; #else /* EAP_MSCHAPv2 */ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); @@ -1540,8 +1539,7 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) { struct eap_ttls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; + eap_ttls_free_key(data); os_free(data->session_id); data->session_id = NULL; if (eap_peer_tls_reauth_init(sm, &data->ssl)) { diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c index 1ccc352..8186afb 100644 --- a/src/eap_peer/ikev2.c +++ b/src/eap_peer/ikev2.c @@ -72,27 +72,10 @@ static int ikev2_derive_keys(struct ikev2_responder_data *data) os_memcpy(pos, data->i_spi, IKEV2_SPI_LEN); pos += IKEV2_SPI_LEN; os_memcpy(pos, data->r_spi, IKEV2_SPI_LEN); -#ifdef CCNS_PL -#if __BYTE_ORDER == __LITTLE_ENDIAN - { - int i; - u8 *tmp = pos - IKEV2_SPI_LEN; - /* Incorrect byte re-ordering on little endian hosts.. */ - for (i = 0; i < IKEV2_SPI_LEN; i++) - *tmp++ = data->i_spi[IKEV2_SPI_LEN - 1 - i]; - for (i = 0; i < IKEV2_SPI_LEN; i++) - *tmp++ = data->r_spi[IKEV2_SPI_LEN - 1 - i]; - } -#endif -#endif /* CCNS_PL */ /* SKEYSEED = prf(Ni | Nr, g^ir) */ /* Use zero-padding per RFC 4306, Sect. 2.14 */ pad_len = data->dh->prime_len - wpabuf_len(shared); -#ifdef CCNS_PL - /* Shared secret is not zero-padded correctly */ - pad_len = 0; -#endif /* CCNS_PL */ pad = os_zalloc(pad_len ? pad_len : 1); if (pad == NULL) { wpabuf_free(shared); @@ -179,21 +162,12 @@ static int ikev2_parse_transform(struct ikev2_proposal_data *prop, "Transform Attr for AES"); break; } -#ifdef CCNS_PL - if (WPA_GET_BE16(pos) != 0x001d /* ?? */) { - wpa_printf(MSG_DEBUG, "IKEV2: Not a " - "Key Size attribute for " - "AES"); - break; - } -#else /* CCNS_PL */ if (WPA_GET_BE16(pos) != 0x800e) { wpa_printf(MSG_DEBUG, "IKEV2: Not a " "Key Size attribute for " "AES"); break; } -#endif /* CCNS_PL */ if (WPA_GET_BE16(pos + 2) != 128) { wpa_printf(MSG_DEBUG, "IKEV2: " "Unsupported AES key size " @@ -456,14 +430,6 @@ static int ikev2_process_ni(struct ikev2_responder_data *data, return -1; } -#ifdef CCNS_PL - /* Zeros are removed incorrectly from the beginning of the nonces */ - while (ni_len > 1 && *ni == 0) { - ni_len--; - ni++; - } -#endif /* CCNS_PL */ - data->i_nonce_len = ni_len; os_memcpy(data->i_nonce, ni, ni_len); wpa_hexdump(MSG_MSGDUMP, "IKEV2: Ni", @@ -599,7 +565,7 @@ static int ikev2_process_auth_secret(struct ikev2_responder_data *data, return -1; if (auth_len != prf->hash_len || - os_memcmp(auth, auth_data, auth_len) != 0) { + os_memcmp_const(auth, auth_data, auth_len) != 0) { wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", auth, auth_len); @@ -887,16 +853,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data, phdr->flags = 0; p = wpabuf_put(msg, sizeof(*p)); -#ifdef CCNS_PL - /* Seems to require that the Proposal # is 1 even though RFC 4306 - * Sect 3.3.1 has following requirement "When a proposal is accepted, - * all of the proposal numbers in the SA payload MUST be the same and - * MUST match the number on the proposal sent that was accepted.". - */ - p->proposal_num = 1; -#else /* CCNS_PL */ p->proposal_num = data->proposal.proposal_num; -#endif /* CCNS_PL */ p->protocol_id = IKEV2_PROTOCOL_IKE; p->num_transforms = 4; @@ -906,11 +863,7 @@ static int ikev2_build_sar1(struct ikev2_responder_data *data, WPA_PUT_BE16(t->transform_id, data->proposal.encr); if (data->proposal.encr == ENCR_AES_CBC) { /* Transform Attribute: Key Len = 128 bits */ -#ifdef CCNS_PL - wpabuf_put_be16(msg, 0x001d); /* ?? */ -#else /* CCNS_PL */ wpabuf_put_be16(msg, 0x800e); /* AF=1, AttrType=14 */ -#endif /* CCNS_PL */ wpabuf_put_be16(msg, 128); /* 128-bit key */ } plen = (u8 *) wpabuf_put(msg, 0) - (u8 *) t; @@ -1082,11 +1035,7 @@ static int ikev2_build_notification(struct ikev2_responder_data *data, phdr = wpabuf_put(msg, sizeof(*phdr)); phdr->next_payload = next_payload; phdr->flags = 0; -#ifdef CCNS_PL - wpabuf_put_u8(msg, 1); /* Protocol ID: IKE_SA notification */ -#else /* CCNS_PL */ wpabuf_put_u8(msg, 0); /* Protocol ID: no existing SA */ -#endif /* CCNS_PL */ wpabuf_put_u8(msg, 0); /* SPI Size */ wpabuf_put_be16(msg, data->error_type); @@ -1130,13 +1079,6 @@ static struct wpabuf * ikev2_build_sa_init(struct ikev2_responder_data *data) data->r_nonce_len = IKEV2_NONCE_MIN_LEN; if (random_get_bytes(data->r_nonce, data->r_nonce_len)) return NULL; -#ifdef CCNS_PL - /* Zeros are removed incorrectly from the beginning of the nonces in - * key derivation; as a workaround, make sure Nr does not start with - * zero.. */ - if (data->r_nonce[0] == 0) - data->r_nonce[0] = 1; -#endif /* CCNS_PL */ wpa_hexdump(MSG_DEBUG, "IKEV2: Nr", data->r_nonce, data->r_nonce_len); msg = wpabuf_alloc(sizeof(struct ikev2_hdr) + data->IDr_len + 1500); diff --git a/src/eap_peer/mschapv2.c b/src/eap_peer/mschapv2.c index 37e6735..9bc7370 100644 --- a/src/eap_peer/mschapv2.c +++ b/src/eap_peer/mschapv2.c @@ -117,8 +117,8 @@ int mschapv2_verify_auth_response(const u8 *auth_response, buf[0] != 'S' || buf[1] != '=' || hexstr2bin((char *) (buf + 2), recv_response, MSCHAPV2_AUTH_RESPONSE_LEN) || - os_memcmp(auth_response, recv_response, - MSCHAPV2_AUTH_RESPONSE_LEN) != 0) + os_memcmp_const(auth_response, recv_response, + MSCHAPV2_AUTH_RESPONSE_LEN) != 0) return -1; return 0; } diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c index 5b1a2d4..7ca956e 100644 --- a/src/eap_peer/tncc.c +++ b/src/eap_peer/tncc.c @@ -1092,8 +1092,10 @@ static int tncc_read_config(struct tncc_data *tncc) int error = 0; imc = tncc_parse_imc(pos + 4, line_end, &error); - if (error) + if (error) { + os_free(config); return -1; + } if (imc) { if (last == NULL) tncc->imc = imc; diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c index 65d00dd..c1bb6b8 100644 --- a/src/eap_server/eap_server.c +++ b/src/eap_server/eap_server.c @@ -168,7 +168,7 @@ SM_STATE(EAP, INITIALIZE) sm->eap_if.eapSuccess = FALSE; sm->eap_if.eapFail = FALSE; sm->eap_if.eapTimeout = FALSE; - os_free(sm->eap_if.eapKeyData); + bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; sm->eap_if.eapKeyAvailable = FALSE; @@ -346,7 +346,7 @@ SM_STATE(EAP, METHOD_RESPONSE) sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); if (sm->m->isDone(sm, sm->eap_method_priv)) { eap_sm_Policy_update(sm, NULL, 0); - os_free(sm->eap_if.eapKeyData); + bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); if (sm->m->getKey) { sm->eap_if.eapKeyData = sm->m->getKey( sm, sm->eap_method_priv, @@ -632,7 +632,7 @@ SM_STATE(EAP, SUCCESS2) if (sm->eap_if.aaaEapKeyAvailable) { EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); } else { - os_free(sm->eap_if.eapKeyData); + bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); sm->eap_if.eapKeyData = NULL; sm->eap_if.eapKeyDataLen = 0; } @@ -1260,7 +1260,7 @@ static void eap_user_free(struct eap_user *user) { if (user == NULL) return; - os_free(user->password); + bin_clear_free(user->password, user->password_len); user->password = NULL; os_free(user); } @@ -1352,7 +1352,7 @@ void eap_server_sm_deinit(struct eap_sm *sm) if (sm->m && sm->eap_method_priv) sm->m->reset(sm, sm->eap_method_priv); wpabuf_free(sm->eap_if.eapReqData); - os_free(sm->eap_if.eapKeyData); + bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen); wpabuf_free(sm->lastReqData); wpabuf_free(sm->eap_if.eapRespData); os_free(sm->identity); @@ -1361,7 +1361,7 @@ void eap_server_sm_deinit(struct eap_sm *sm) os_free(sm->eap_fast_a_id_info); wpabuf_free(sm->eap_if.aaaEapReqData); wpabuf_free(sm->eap_if.aaaEapRespData); - os_free(sm->eap_if.aaaEapKeyData); + bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen); eap_user_free(sm->user); wpabuf_free(sm->assoc_wps_ie); wpabuf_free(sm->assoc_p2p_ie); diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c index 46fc458..09b976e 100644 --- a/src/eap_server/eap_server_aka.c +++ b/src/eap_server/eap_server_aka.c @@ -241,7 +241,7 @@ static void eap_aka_reset(struct eap_sm *sm, void *priv) os_free(data->next_reauth_id); wpabuf_free(data->id_msgs); os_free(data->network_name); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -336,7 +336,7 @@ static int eap_aka_verify_checkcode(struct eap_aka_data *data, else sha1_vector(1, &addr, &len, hash); - if (os_memcmp(hash, checkcode, hash_len) != 0) { + if (os_memcmp_const(hash, checkcode, hash_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-AKA: Mismatch in AT_CHECKCODE"); return -1; } @@ -377,7 +377,7 @@ static struct wpabuf * eap_aka_build_identity(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ"); eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0); } - buf = eap_sim_msg_finish(msg, NULL, NULL, 0); + buf = eap_sim_msg_finish(msg, data->eap_method, NULL, NULL, 0); if (eap_aka_add_id_msg(data, buf) < 0) { wpabuf_free(buf); return NULL; @@ -534,7 +534,7 @@ static struct wpabuf * eap_aka_build_challenge(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0); } @@ -581,7 +581,7 @@ static struct wpabuf * eap_aka_build_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0); } @@ -620,7 +620,7 @@ static struct wpabuf * eap_aka_build_notification(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); } - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); + return eap_sim_msg_finish(msg, data->eap_method, data->k_aut, NULL, 0); } @@ -963,7 +963,7 @@ static void eap_aka_process_challenge(struct eap_sm *sm, */ if (attr->res == NULL || attr->res_len < data->res_len || attr->res_len_bits != data->res_len * 8 || - os_memcmp(attr->res, data->res, data->res_len) != 0) { + os_memcmp_const(attr->res, data->res, data->res_len) != 0) { wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not " "include valid AT_RES (attr len=%lu, res len=%lu " "bits, expected %lu bits)", diff --git a/src/eap_server/eap_server_eke.c b/src/eap_server/eap_server_eke.c index b19a321..966f511 100644 --- a/src/eap_server/eap_server_eke.c +++ b/src/eap_server/eap_server_eke.c @@ -104,7 +104,7 @@ static void eap_eke_reset(struct eap_sm *sm, void *priv) eap_eke_session_clean(&data->sess); os_free(data->peerid); wpabuf_free(data->msgs); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -635,8 +635,8 @@ static void eap_eke_process_confirm(struct eap_sm *sm, return; } wpa_hexdump(MSG_DEBUG, "EAP-EKE: Auth_P", auth_p, data->sess.prf_len); - if (os_memcmp(auth_p, payload + data->sess.pnonce_len, - data->sess.prf_len) != 0) { + if (os_memcmp_const(auth_p, payload + data->sess.pnonce_len, + data->sess.prf_len) != 0) { wpa_printf(MSG_INFO, "EAP-EKE: Auth_P does not match"); eap_eke_fail(data, EAP_EKE_FAIL_AUTHENTICATION_FAIL); return; diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c index fcb80dc..2692bce 100644 --- a/src/eap_server/eap_server_fast.c +++ b/src/eap_server/eap_server_fast.c @@ -161,8 +161,8 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, return 0; } - if (aes_unwrap(data->pac_opaque_encr, (pac_opaque_len - 8) / 8, - pac_opaque, buf) < 0) { + if (aes_unwrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), + (pac_opaque_len - 8) / 8, pac_opaque, buf) < 0) { wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to decrypt " "PAC-Opaque"); os_free(buf); @@ -187,7 +187,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, switch (*pos) { case PAC_OPAQUE_TYPE_PAD: pos = end; - break; + goto done; case PAC_OPAQUE_TYPE_KEY: if (pos[1] != EAP_FAST_PAC_KEY_LEN) { wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid " @@ -218,6 +218,7 @@ static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len, pos += 2 + pos[1]; } +done: if (pac_key == NULL) { wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key included in " @@ -511,7 +512,7 @@ static void eap_fast_reset(struct eap_sm *sm, void *priv) os_free(data->key_block_p); wpabuf_free(data->pending_phase2_resp); os_free(data->identity); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -730,8 +731,8 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm, os_free(pac_buf); return NULL; } - if (aes_wrap(data->pac_opaque_encr, pac_len / 8, pac_buf, - pac_opaque) < 0) { + if (aes_wrap(data->pac_opaque_encr, sizeof(data->pac_opaque_encr), + pac_len / 8, pac_buf, pac_opaque) < 0) { os_free(pac_buf); os_free(pac_opaque); return NULL; @@ -1123,7 +1124,8 @@ static void eap_fast_process_phase2_eap(struct eap_sm *sm, static int eap_fast_parse_tlvs(struct wpabuf *data, struct eap_fast_tlv_parse *tlv) { - int mandatory, tlv_type, len, res; + int mandatory, tlv_type, res; + size_t len; u8 *pos, *end; os_memset(tlv, 0, sizeof(*tlv)); @@ -1136,13 +1138,14 @@ static int eap_fast_parse_tlvs(struct wpabuf *data, pos += 2; len = WPA_GET_BE16(pos); pos += 2; - if (pos + len > end) { + if (len > (size_t) (end - pos)) { wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow"); return -1; } wpa_printf(MSG_DEBUG, "EAP-FAST: Received Phase 2: " - "TLV type %d length %d%s", - tlv_type, len, mandatory ? " (mandatory)" : ""); + "TLV type %d length %u%s", + tlv_type, (unsigned int) len, + mandatory ? " (mandatory)" : ""); res = eap_fast_parse_tlv(tlv, tlv_type, pos, len); if (res == -2) @@ -1196,7 +1199,7 @@ static int eap_fast_validate_crypto_binding( return -1; } - if (os_memcmp(data->crypto_binding_nonce, b->nonce, 31) != 0 || + if (os_memcmp_const(data->crypto_binding_nonce, b->nonce, 31) != 0 || (data->crypto_binding_nonce[31] | 1) != b->nonce[31]) { wpa_printf(MSG_DEBUG, "EAP-FAST: Invalid nonce in " "Crypto-Binding"); @@ -1210,7 +1213,7 @@ static int eap_fast_validate_crypto_binding( (u8 *) b, bind_len); hmac_sha1(data->cmk, EAP_FAST_CMK_LEN, (u8 *) b, bind_len, b->compound_mac); - if (os_memcmp(cmac, b->compound_mac, sizeof(cmac)) != 0) { + if (os_memcmp_const(cmac, b->compound_mac, sizeof(cmac)) != 0) { wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC", b->compound_mac, sizeof(cmac)); diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c index 66f4271..cb369e4 100644 --- a/src/eap_server/eap_server_gpsk.c +++ b/src/eap_server/eap_server_gpsk.c @@ -95,7 +95,7 @@ static void eap_gpsk_reset(struct eap_sm *sm, void *priv) { struct eap_gpsk_data *data = priv; os_free(data->id_peer); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -433,7 +433,7 @@ static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, eap_gpsk_state(data, FAILURE); return; } - if (os_memcmp(mic, pos, miclen) != 0) { + if (os_memcmp_const(mic, pos, miclen) != 0) { wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); @@ -502,7 +502,7 @@ static void eap_gpsk_process_gpsk_4(struct eap_sm *sm, eap_gpsk_state(data, FAILURE); return; } - if (os_memcmp(mic, pos, miclen) != 0) { + if (os_memcmp_const(mic, pos, miclen) != 0) { wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); diff --git a/src/eap_server/eap_server_gtc.c b/src/eap_server/eap_server_gtc.c index f423106..98ac3c6 100644 --- a/src/eap_server/eap_server_gtc.c +++ b/src/eap_server/eap_server_gtc.c @@ -175,7 +175,7 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv, } if (rlen != sm->user->password_len || - os_memcmp(pos, sm->user->password, rlen) != 0) { + os_memcmp_const(pos, sm->user->password, rlen) != 0) { wpa_printf(MSG_DEBUG, "EAP-GTC: Done - Failure"); data->state = FAILURE; } else { diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c index 3e32cc9..65b2ef6 100644 --- a/src/eap_server/eap_server_ikev2.c +++ b/src/eap_server/eap_server_ikev2.c @@ -127,7 +127,7 @@ static void eap_ikev2_reset(struct eap_sm *sm, void *priv) wpabuf_free(data->in_buf); wpabuf_free(data->out_buf); ikev2_initiator_deinit(&data->ikev2); - os_free(data); + bin_clear_free(data, sizeof(*data)); } diff --git a/src/eap_server/eap_server_md5.c b/src/eap_server/eap_server_md5.c index 5a5e290..71e8d59 100644 --- a/src/eap_server/eap_server_md5.c +++ b/src/eap_server/eap_server_md5.c @@ -126,7 +126,7 @@ static void eap_md5_process(struct eap_sm *sm, void *priv, return; } - if (os_memcmp(hash, pos, CHAP_MD5_LEN) == 0) { + if (os_memcmp_const(hash, pos, CHAP_MD5_LEN) == 0) { wpa_printf(MSG_DEBUG, "EAP-MD5: Done - Success"); data->state = SUCCESS; } else { diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c index 0eb7908..f7a753d 100644 --- a/src/eap_server/eap_server_mschapv2.c +++ b/src/eap_server/eap_server_mschapv2.c @@ -91,7 +91,7 @@ static void eap_mschapv2_reset(struct eap_sm *sm, void *priv) return; os_free(data->peer_challenge); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -393,7 +393,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm, return; } - if (os_memcmp(nt_response, expected, 24) == 0) { + if (os_memcmp_const(nt_response, expected, 24) == 0) { const u8 *pw_hash; u8 pw_hash_buf[16], pw_hash_hash[16]; diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c index 35a42ad..d9d4375 100644 --- a/src/eap_server/eap_server_pax.c +++ b/src/eap_server/eap_server_pax.c @@ -64,7 +64,7 @@ static void eap_pax_reset(struct eap_sm *sm, void *priv) { struct eap_pax_data *data = priv; os_free(data->cid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -268,7 +268,7 @@ static Boolean eap_pax_check(struct eap_sm *sm, void *priv, wpabuf_mhead(respData), wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); - if (os_memcmp(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { + if (os_memcmp_const(icvbuf, icv, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); @@ -287,7 +287,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm, struct eap_pax_hdr *resp; u8 mac[EAP_PAX_MAC_LEN], icvbuf[EAP_PAX_ICV_LEN]; const u8 *pos; - size_t len, left; + size_t len, left, cid_len; int i; if (data->state != PAX_STD_1) @@ -320,7 +320,12 @@ static void eap_pax_process_std_2(struct eap_sm *sm, wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)"); return; } - data->cid_len = WPA_GET_BE16(pos); + cid_len = WPA_GET_BE16(pos); + if (cid_len > 1500) { + wpa_printf(MSG_INFO, "EAP-PAX: Too long CID"); + return; + } + data->cid_len = cid_len; os_free(data->cid); data->cid = os_malloc(data->cid_len); if (data->cid == NULL) { @@ -395,7 +400,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm, data->rand.r.x, EAP_PAX_RAND_LEN, data->rand.r.y, EAP_PAX_RAND_LEN, (u8 *) data->cid, data->cid_len, mac); - if (os_memcmp(mac, pos, EAP_PAX_MAC_LEN) != 0) { + if (os_memcmp_const(mac, pos, EAP_PAX_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(A, B, CID) in " "PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected MAC_CK(A, B, CID)", @@ -417,7 +422,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm, wpabuf_head(respData), wpabuf_len(respData) - EAP_PAX_ICV_LEN, NULL, 0, NULL, 0, icvbuf); - if (os_memcmp(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { + if (os_memcmp_const(icvbuf, pos, EAP_PAX_ICV_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PAX: Invalid ICV in PAX_STD-2"); wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Expected ICV", icvbuf, EAP_PAX_ICV_LEN); diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c index defcb3c..594e02d 100644 --- a/src/eap_server/eap_server_peap.c +++ b/src/eap_server/eap_server_peap.c @@ -172,7 +172,7 @@ static void eap_peap_reset(struct eap_sm *sm, void *priv) wpabuf_free(data->pending_phase2_resp); os_free(data->phase2_key); wpabuf_free(data->soh_response); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -593,7 +593,7 @@ static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, buf[60] = EAP_TYPE_PEAP; hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); - if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { + if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " "cryptobinding TLV"); wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20); diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c index 46bedd9..db394e9 100644 --- a/src/eap_server/eap_server_psk.c +++ b/src/eap_server/eap_server_psk.c @@ -47,7 +47,7 @@ static void eap_psk_reset(struct eap_sm *sm, void *priv) { struct eap_psk_data *data = priv; os_free(data->id_p); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -314,7 +314,7 @@ static void eap_psk_process_2(struct eap_sm *sm, } os_free(buf); wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", resp->mac_p, EAP_PSK_MAC_LEN); - if (os_memcmp(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) { + if (os_memcmp_const(mac, resp->mac_p, EAP_PSK_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-PSK: Invalid MAC_P"); wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: Expected MAC_P", mac, EAP_PSK_MAC_LEN); diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c index ec53481..7e1278d 100644 --- a/src/eap_server/eap_server_pwd.c +++ b/src/eap_server/eap_server_pwd.c @@ -106,7 +106,7 @@ static void * eap_pwd_init(struct eap_sm *sm) if (data->password == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: Memory allocation password " "fail"); - os_free(data->id_server); + bin_clear_free(data->id_server, data->id_server_len); os_free(data); return NULL; } @@ -116,8 +116,8 @@ static void * eap_pwd_init(struct eap_sm *sm) data->bnctx = BN_CTX_new(); if (data->bnctx == NULL) { wpa_printf(MSG_INFO, "EAP-PWD: bn context allocation fail"); - os_free(data->password); - os_free(data->id_server); + bin_clear_free(data->password, data->password_len); + bin_clear_free(data->id_server, data->id_server_len); os_free(data); return NULL; } @@ -135,26 +135,26 @@ static void eap_pwd_reset(struct eap_sm *sm, void *priv) { struct eap_pwd_data *data = priv; - BN_free(data->private_value); - BN_free(data->peer_scalar); - BN_free(data->my_scalar); - BN_free(data->k); + BN_clear_free(data->private_value); + BN_clear_free(data->peer_scalar); + BN_clear_free(data->my_scalar); + BN_clear_free(data->k); BN_CTX_free(data->bnctx); - EC_POINT_free(data->my_element); - EC_POINT_free(data->peer_element); - os_free(data->id_peer); - os_free(data->id_server); - os_free(data->password); + EC_POINT_clear_free(data->my_element); + EC_POINT_clear_free(data->peer_element); + bin_clear_free(data->id_peer, data->id_peer_len); + bin_clear_free(data->id_server, data->id_server_len); + bin_clear_free(data->password, data->password_len); if (data->grp) { EC_GROUP_free(data->grp->group); - EC_POINT_free(data->grp->pwe); - BN_free(data->grp->order); - BN_free(data->grp->prime); + EC_POINT_clear_free(data->grp->pwe); + BN_clear_free(data->grp->order); + BN_clear_free(data->grp->prime); os_free(data->grp); } wpabuf_free(data->inbuf); wpabuf_free(data->outbuf); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -210,11 +210,15 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm, goto fin; } - BN_rand_range(data->private_value, data->grp->order); - BN_rand_range(mask, data->grp->order); - BN_add(data->my_scalar, data->private_value, mask); - BN_mod(data->my_scalar, data->my_scalar, data->grp->order, - data->bnctx); + if (BN_rand_range(data->private_value, data->grp->order) != 1 || + BN_rand_range(mask, data->grp->order) != 1 || + BN_add(data->my_scalar, data->private_value, mask) != 1 || + BN_mod(data->my_scalar, data->my_scalar, data->grp->order, + data->bnctx) != 1) { + wpa_printf(MSG_INFO, + "EAP-pwd (server): unable to get randomness"); + goto fin; + } if (!EC_POINT_mul(data->grp->group, data->my_element, NULL, data->grp->pwe, mask, data->bnctx)) { @@ -230,7 +234,7 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm, "fail"); goto fin; } - BN_free(mask); + BN_clear_free(mask); if (((x = BN_new()) == NULL) || ((y = BN_new()) == NULL)) { @@ -282,8 +286,8 @@ static void eap_pwd_build_commit_req(struct eap_sm *sm, fin: os_free(scalar); os_free(element); - BN_free(x); - BN_free(y); + BN_clear_free(x); + BN_clear_free(y); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); } @@ -406,9 +410,9 @@ static void eap_pwd_build_confirm_req(struct eap_sm *sm, wpabuf_put_data(data->outbuf, conf, SHA256_MAC_LEN); fin: - os_free(cruft); - BN_free(x); - BN_free(y); + bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); + BN_clear_free(x); + BN_clear_free(y); if (data->outbuf == NULL) eap_pwd_state(data, FAILURE); } @@ -724,11 +728,11 @@ eap_pwd_process_commit_resp(struct eap_sm *sm, struct eap_pwd_data *data, res = 1; fin: - EC_POINT_free(K); - EC_POINT_free(point); - BN_free(cofactor); - BN_free(x); - BN_free(y); + EC_POINT_clear_free(K); + EC_POINT_clear_free(point); + BN_clear_free(cofactor); + BN_clear_free(x); + BN_clear_free(y); if (res) eap_pwd_state(data, PWD_Confirm_Req); @@ -835,7 +839,7 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_h_final(hash, conf); ptr = (u8 *) payload; - if (os_memcmp(conf, ptr, SHA256_MAC_LEN)) { + if (os_memcmp_const(conf, ptr, SHA256_MAC_LEN)) { wpa_printf(MSG_INFO, "EAP-PWD (server): confirm did not " "verify"); goto fin; @@ -851,9 +855,9 @@ eap_pwd_process_confirm_resp(struct eap_sm *sm, struct eap_pwd_data *data, eap_pwd_state(data, SUCCESS); fin: - os_free(cruft); - BN_free(x); - BN_free(y); + bin_clear_free(cruft, BN_num_bytes(data->grp->prime)); + BN_clear_free(x); + BN_clear_free(y); } @@ -900,6 +904,8 @@ static void eap_pwd_process(struct eap_sm *sm, void *priv, tot_len = WPA_GET_BE16(pos); wpa_printf(MSG_DEBUG, "EAP-pwd: Incoming fragments, total " "length = %d", tot_len); + if (tot_len > 15000) + return; data->inbuf = wpabuf_alloc(tot_len); if (data->inbuf == NULL) { wpa_printf(MSG_INFO, "EAP-pwd: Out of memory to " diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c index 68dd76b..1937621 100644 --- a/src/eap_server/eap_server_sake.c +++ b/src/eap_server/eap_server_sake.c @@ -83,7 +83,7 @@ static void eap_sake_reset(struct eap_sm *sm, void *priv) { struct eap_sake_data *data = priv; os_free(data->peerid); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -351,7 +351,7 @@ static void eap_sake_process_challenge(struct eap_sm *sm, data->peerid, data->peerid_len, 1, wpabuf_head(respData), wpabuf_len(respData), attr.mic_p, mic_p); - if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { + if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); eap_sake_state(data, FAILURE); return; @@ -388,7 +388,7 @@ static void eap_sake_process_confirm(struct eap_sm *sm, data->peerid, data->peerid_len, 1, wpabuf_head(respData), wpabuf_len(respData), attr.mic_p, mic_p); - if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { + if (os_memcmp_const(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) { wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P"); eap_sake_state(data, FAILURE); } else diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c index b531241..23ee2b6 100644 --- a/src/eap_server/eap_server_sim.c +++ b/src/eap_server/eap_server_sim.c @@ -94,7 +94,7 @@ static void eap_sim_reset(struct eap_sm *sm, void *priv) struct eap_sim_data *data = priv; os_free(data->next_pseudonym); os_free(data->next_reauth_id); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -140,7 +140,7 @@ static struct wpabuf * eap_sim_build_start(struct eap_sm *sm, ver[1] = EAP_SIM_VERSION; eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver), ver, sizeof(ver)); - return eap_sim_msg_finish(msg, NULL, NULL, 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, NULL, NULL, 0); } @@ -240,8 +240,8 @@ static struct wpabuf * eap_sim_build_challenge(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, data->nonce_mt, - EAP_SIM_NONCE_MT_LEN); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, + data->nonce_mt, EAP_SIM_NONCE_MT_LEN); } @@ -278,7 +278,7 @@ static struct wpabuf * eap_sim_build_reauth(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0); } @@ -317,7 +317,7 @@ static struct wpabuf * eap_sim_build_notification(struct eap_sm *sm, wpa_printf(MSG_DEBUG, " AT_MAC"); eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC); } - return eap_sim_msg_finish(msg, data->k_aut, NULL, 0); + return eap_sim_msg_finish(msg, EAP_TYPE_SIM, data->k_aut, NULL, 0); } diff --git a/src/eap_server/eap_server_tnc.c b/src/eap_server/eap_server_tnc.c index 67a3dfa..21bd26f 100644 --- a/src/eap_server/eap_server_tnc.c +++ b/src/eap_server/eap_server_tnc.c @@ -480,7 +480,8 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv, message_length = WPA_GET_BE32(pos); pos += 4; - if (message_length < (u32) (end - pos)) { + if (message_length < (u32) (end - pos) || + message_length > 75000) { wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message " "Length (%d; %ld remaining in this msg)", message_length, (long) (end - pos)); diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c index d09a769..31e3871 100644 --- a/src/eap_server/eap_server_ttls.c +++ b/src/eap_server/eap_server_ttls.c @@ -336,7 +336,7 @@ static void eap_ttls_reset(struct eap_sm *sm, void *priv) data->phase2_method->reset(sm, data->phase2_priv); eap_server_tls_ssl_deinit(sm, &data->ssl); wpabuf_free(data->pending_phase2_eap_resp); - os_free(data); + bin_clear_free(data, sizeof(*data)); } @@ -509,8 +509,8 @@ static void eap_ttls_process_phase2_pap(struct eap_sm *sm, } if (sm->user->password_len != user_password_len || - os_memcmp(sm->user->password, user_password, user_password_len) != - 0) { + os_memcmp_const(sm->user->password, user_password, + user_password_len) != 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Invalid user password"); eap_ttls_state(data, FAILURE); return; @@ -558,7 +558,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm, return; } - if (os_memcmp(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) != 0 || + if (os_memcmp_const(challenge, chal, EAP_TTLS_CHAP_CHALLENGE_LEN) + != 0 || password[0] != chal[EAP_TTLS_CHAP_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Challenge mismatch"); os_free(chal); @@ -571,7 +572,8 @@ static void eap_ttls_process_phase2_chap(struct eap_sm *sm, chap_md5(password[0], sm->user->password, sm->user->password_len, challenge, challenge_len, hash); - if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) { + if (os_memcmp_const(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == + 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password"); eap_ttls_state(data, SUCCESS); } else { @@ -616,7 +618,8 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, return; } - if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) != 0 || + if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAP_CHALLENGE_LEN) + != 0 || response[0] != chal[EAP_TTLS_MSCHAP_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Challenge mismatch"); os_free(chal); @@ -631,7 +634,7 @@ static void eap_ttls_process_phase2_mschap(struct eap_sm *sm, nt_challenge_response(challenge, sm->user->password, sm->user->password_len, nt_response); - if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) { + if (os_memcmp_const(nt_response, response + 2 + 24, 24) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response"); eap_ttls_state(data, SUCCESS); } else { @@ -703,7 +706,8 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, return; } - if (os_memcmp(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) != 0 || + if (os_memcmp_const(challenge, chal, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) + != 0 || response[0] != chal[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN]) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Challenge mismatch"); os_free(chal); @@ -736,7 +740,7 @@ static void eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, } rx_resp = response + 2 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 8; - if (os_memcmp(nt_response, rx_resp, 24) == 0) { + if (os_memcmp_const(nt_response, rx_resp, 24) == 0) { wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct " "NT-Response"); data->mschapv2_resp_ok = 1; diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c index 512ba30..632598f 100644 --- a/src/eap_server/ikev2.c +++ b/src/eap_server/ikev2.c @@ -633,7 +633,7 @@ static int ikev2_process_auth_secret(struct ikev2_initiator_data *data, return -1; if (auth_len != prf->hash_len || - os_memcmp(auth, auth_data, auth_len) != 0) { + os_memcmp_const(auth, auth_data, auth_len) != 0) { wpa_printf(MSG_INFO, "IKEV2: Invalid Authentication Data"); wpa_hexdump(MSG_DEBUG, "IKEV2: Received Authentication Data", auth, auth_len); diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c index 1004b1a..70258be 100644 --- a/src/eapol_supp/eapol_supp_sm.c +++ b/src/eapol_supp/eapol_supp_sm.c @@ -255,12 +255,14 @@ SM_STATE(SUPP_PAE, CONNECTING) * delay authentication. Use a short timeout to send the first * EAPOL-Start if Authenticator does not start authentication. */ -#ifdef CONFIG_WPS - /* Reduce latency on starting WPS negotiation. */ - sm->startWhen = 1; -#else /* CONFIG_WPS */ - sm->startWhen = 3; -#endif /* CONFIG_WPS */ + if (sm->conf.wps) { + /* Reduce latency on starting WPS negotiation. */ + wpa_printf(MSG_DEBUG, + "EAPOL: Using shorter startWhen for WPS"); + sm->startWhen = 1; + } else { + sm->startWhen = 2; + } } eapol_enable_timer_tick(sm); sm->eapolEap = FALSE; @@ -719,8 +721,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm) hmac_md5(keydata.sign_key, sign_key_len, sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), key->key_signature); - if (os_memcmp(orig_key_sign, key->key_signature, - IEEE8021X_KEY_SIGN_LEN) != 0) { + if (os_memcmp_const(orig_key_sign, key->key_signature, + IEEE8021X_KEY_SIGN_LEN) != 0) { wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " "EAPOL-Key packet"); os_memcpy(key->key_signature, orig_key_sign, @@ -1242,7 +1244,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, return 0; } #ifdef CONFIG_WPS - if (sm->conf.workaround && + if (sm->conf.wps && sm->conf.workaround && plen < len - sizeof(*hdr) && hdr->type == IEEE802_1X_TYPE_EAP_PACKET && len - sizeof(*hdr) > sizeof(struct eap_hdr)) { @@ -1491,6 +1493,7 @@ void eapol_sm_notify_config(struct eapol_sm *sm, sm->conf.required_keys = conf->required_keys; sm->conf.fast_reauth = conf->fast_reauth; sm->conf.workaround = conf->workaround; + sm->conf.wps = conf->wps; #ifdef CONFIG_EAP_PROXY if (sm->use_eap_proxy) { /* Using EAP Proxy, so skip EAP state machine update */ @@ -1523,7 +1526,7 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) size_t eap_len; #ifdef CONFIG_EAP_PROXY - if (sm->use_eap_proxy) { + if (sm && sm->use_eap_proxy) { /* Get key from EAP proxy */ if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) { wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h index d76c8c2..5b37314 100644 --- a/src/eapol_supp/eapol_supp_sm.h +++ b/src/eapol_supp/eapol_supp_sm.h @@ -58,6 +58,11 @@ struct eapol_config { * external_sim - Use external processing for SIM/USIM operations */ int external_sim; + + /** + * wps - Whether this connection is used for WPS + */ + int wps; }; struct eapol_sm; diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c index 1875ca4..9985e4f 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -12,6 +12,7 @@ #include "eloop.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "wps/wps_i.h" #include "p2p_i.h" #include "p2p.h" @@ -183,6 +184,14 @@ void p2p_set_state(struct p2p_data *p2p, int new_state) p2p_dbg(p2p, "State %s -> %s", p2p_state_txt(p2p->state), p2p_state_txt(new_state)); p2p->state = new_state; + + if (new_state == P2P_IDLE && p2p->pending_channel) { + p2p_dbg(p2p, "Apply change in listen channel"); + p2p->cfg->reg_class = p2p->pending_reg_class; + p2p->cfg->channel = p2p->pending_channel; + p2p->pending_reg_class = 0; + p2p->pending_channel = 0; + } } @@ -250,7 +259,8 @@ static void p2p_listen_in_find(struct p2p_data *p2p, int dev_disc) return; } - os_get_random((u8 *) &r, sizeof(r)); + if (os_get_random((u8 *) &r, sizeof(r)) < 0) + r = 0; tu = (r % ((p2p->max_disc_int - p2p->min_disc_int) + 1) + p2p->min_disc_int) * 100; if (p2p->max_disc_tu >= 0 && tu > (unsigned int) p2p->max_disc_tu) @@ -600,6 +610,46 @@ static void p2p_copy_wps_info(struct p2p_data *p2p, struct p2p_device *dev, } +static void p2p_update_peer_vendor_elems(struct p2p_device *dev, const u8 *ies, + size_t ies_len) +{ + const u8 *pos, *end; + u8 id, len; + + wpabuf_free(dev->info.vendor_elems); + dev->info.vendor_elems = NULL; + + end = ies + ies_len; + + for (pos = ies; pos + 1 < end; pos += len) { + id = *pos++; + len = *pos++; + + if (pos + len > end) + break; + + if (id != WLAN_EID_VENDOR_SPECIFIC || len < 3) + continue; + + if (len >= 4) { + u32 type = WPA_GET_BE32(pos); + + if (type == WPA_IE_VENDOR_TYPE || + type == WMM_IE_VENDOR_TYPE || + type == WPS_IE_VENDOR_TYPE || + type == P2P_IE_VENDOR_TYPE || + type == WFD_IE_VENDOR_TYPE) + continue; + } + + /* Unknown vendor element - make raw IE data available */ + if (wpabuf_resize(&dev->info.vendor_elems, 2 + len) < 0) + break; + wpabuf_put_data(dev->info.vendor_elems, pos - 2, 2 + len); + } +} + + /** * p2p_add_device - Add peer entries based on scan results or P2P frames * @p2p: P2P module context from p2p_init() @@ -748,6 +798,8 @@ int p2p_add_device(struct p2p_data *p2p, const u8 *addr, int freq, p2p_parse_free(&msg); + p2p_update_peer_vendor_elems(dev, ies, ies_len); + if (dev->flags & P2P_DEV_REPORTED) return 0; @@ -817,6 +869,7 @@ static void p2p_device_free(struct p2p_data *p2p, struct p2p_device *dev) } wpabuf_free(dev->info.wfd_subelems); + wpabuf_free(dev->info.vendor_elems); wpabuf_free(dev->go_neg_conf); os_free(dev); @@ -1234,8 +1287,8 @@ static void p2p_prepare_channel_best(struct p2p_data *p2p) } else if (p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class, &p2p->op_channel) == 0) { - p2p_dbg(p2p, "Select random available social channel %d from 2.4 GHz band as operating channel preference", - p2p->op_channel); + p2p_dbg(p2p, "Select random available social channel (op_class %u channel %u) as operating channel preference", + p2p->op_reg_class, p2p->op_channel); } else { /* Select any random available channel from the first available * operating class */ @@ -1553,7 +1606,7 @@ void p2p_build_ssid(struct p2p_data *p2p, u8 *ssid, size_t *ssid_len) int p2p_go_params(struct p2p_data *p2p, struct p2p_go_neg_results *params) { p2p_build_ssid(p2p, params->ssid, ¶ms->ssid_len); - p2p_random(params->passphrase, 8); + p2p_random(params->passphrase, p2p->cfg->passphrase_len); return 0; } @@ -1587,7 +1640,7 @@ void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer) p2p->op_channel); os_memcpy(res.ssid, p2p->ssid, p2p->ssid_len); res.ssid_len = p2p->ssid_len; - p2p_random(res.passphrase, 8); + p2p_random(res.passphrase, p2p->cfg->passphrase_len); } else { res.freq = peer->oper_freq; if (p2p->ssid_len) { @@ -1772,8 +1825,17 @@ static void p2p_go_neg_start(void *eloop_ctx, void *timeout_ctx) struct p2p_data *p2p = eloop_ctx; if (p2p->go_neg_peer == NULL) return; + if (p2p->pending_listen_freq) { + p2p_dbg(p2p, "Clear pending_listen_freq for p2p_go_neg_start"); + p2p->pending_listen_freq = 0; + } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); p2p->go_neg_peer->status = P2P_SC_SUCCESS; + /* + * Set new timeout to make sure a previously set one does not expire + * too quickly while waiting for the GO Negotiation to complete. + */ + p2p_set_timeout(p2p, 0, 500000); p2p_connect_send(p2p, p2p->go_neg_peer); } @@ -1783,6 +1845,10 @@ static void p2p_invite_start(void *eloop_ctx, void *timeout_ctx) struct p2p_data *p2p = eloop_ctx; if (p2p->invite_peer == NULL) return; + if (p2p->pending_listen_freq) { + p2p_dbg(p2p, "Clear pending_listen_freq for p2p_invite_start"); + p2p->pending_listen_freq = 0; + } p2p->cfg->stop_listen(p2p->cfg->cb_ctx); p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr, p2p->invite_dev_pw_id); @@ -1949,6 +2015,9 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) extra = wpabuf_len(p2p->wfd_ie_probe_resp); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -1969,6 +2038,10 @@ struct wpabuf * p2p_build_probe_resp_ies(struct p2p_data *p2p) wpabuf_put_buf(buf, p2p->wfd_ie_probe_resp); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]) + wpabuf_put_buf(buf, + p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P]); + /* P2P IE */ len = p2p_buf_add_ie_hdr(buf); p2p_buf_add_capability(buf, p2p->dev_capab & @@ -2244,6 +2317,9 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, extra = wpabuf_len(p2p->wfd_ie_assoc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]); + /* * (Re)Association Request - P2P IE * P2P Capability attribute (shall be present) @@ -2259,6 +2335,10 @@ int p2p_assoc_req_ie(struct p2p_data *p2p, const u8 *bssid, u8 *buf, wpabuf_put_buf(tmp, p2p->wfd_ie_assoc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]) + wpabuf_put_buf(tmp, + p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_REQ]); + peer = bssid ? p2p_get_device(p2p, bssid) : NULL; lpos = p2p_buf_add_ie_hdr(tmp); @@ -2380,7 +2460,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) { struct p2p_data *p2p; - if (cfg->max_peers < 1) + if (cfg->max_peers < 1 || + cfg->passphrase_len < 8 || cfg->passphrase_len > 63) return NULL; p2p = os_zalloc(sizeof(*p2p) + sizeof(*cfg)); @@ -2413,7 +2494,8 @@ struct p2p_data * p2p_init(const struct p2p_config *cfg) p2p->max_disc_int = 3; p2p->max_disc_tu = -1; - os_get_random(&p2p->next_tie_breaker, 1); + if (os_get_random(&p2p->next_tie_breaker, 1) < 0) + p2p->next_tie_breaker = 0; p2p->next_tie_breaker &= 0x01; if (cfg->sd_request) p2p->dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY; @@ -2706,6 +2788,19 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success) return; } + if (p2p->sd_query->for_all_peers) { + /* Update the pending broadcast SD query count for this device + */ + p2p->sd_peer->sd_pending_bcast_queries--; + + /* + * If there are no pending broadcast queries for this device, + * mark it as done (-1). + */ + if (p2p->sd_peer->sd_pending_bcast_queries == 0) + p2p->sd_peer->sd_pending_bcast_queries = -1; + } + /* Wait for response from the peer */ p2p_set_state(p2p, P2P_SD_DURING_FIND); p2p_set_timeout(p2p, 0, 200000); @@ -2845,6 +2940,10 @@ void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id) wpabuf_put_buf(ies, p2p->wfd_ie_probe_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]) + wpabuf_put_buf(ies, + p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]); + len = p2p_buf_add_ie_hdr(ies); p2p_buf_add_capability(ies, p2p->dev_capab & ~P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY, 0); @@ -2871,6 +2970,10 @@ size_t p2p_scan_ie_buf_len(struct p2p_data *p2p) len += wpabuf_len(p2p->wfd_ie_probe_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p && p2p->vendor_elem && + p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]) + len += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_PROBE_REQ_P2P]); + return len; } @@ -2928,7 +3031,8 @@ static void p2p_go_neg_req_cb(struct p2p_data *p2p, int success) * make it less likely to hit cases where we could end up in * sync with peer not listening. */ - os_get_random((u8 *) &r, sizeof(r)); + if (os_get_random((u8 *) &r, sizeof(r)) < 0) + r = 0; timeout += r % 100000; } p2p_set_timeout(p2p, 0, timeout); @@ -3991,20 +4095,50 @@ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled) } -int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel) +int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class, + u8 *op_channel) +{ + return p2p_channel_random_social(&p2p->channels, op_class, op_channel); +} + + +int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel, + u8 forced) { if (p2p_channel_to_freq(reg_class, channel) < 0) return -1; p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u", reg_class, channel); - p2p->cfg->reg_class = reg_class; - p2p->cfg->channel = channel; + + /* + * Listen channel was set in configuration or set by control interface; + * cannot override it. + */ + if (p2p->cfg->channel_forced && forced == 0) + return -1; + + if (p2p->state == P2P_IDLE) { + p2p->cfg->reg_class = reg_class; + p2p->cfg->channel = channel; + p2p->cfg->channel_forced = forced; + } else { + p2p_dbg(p2p, "Defer setting listen channel"); + p2p->pending_reg_class = reg_class; + p2p->pending_channel = channel; + p2p->pending_channel_forced = forced; + } return 0; } +u8 p2p_get_listen_channel(struct p2p_data *p2p) +{ + return p2p->cfg->channel; +} + + int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len) { p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len)); @@ -4462,6 +4596,19 @@ void p2p_err(struct p2p_data *p2p, const char *fmt, ...) } +void p2p_loop_on_known_peers(struct p2p_data *p2p, + void (*peer_callback)(struct p2p_peer_info *peer, + void *user_data), + void *user_data) +{ + struct p2p_device *dev, *n; + + dl_list_for_each_safe(dev, n, &p2p->devices, struct p2p_device, list) { + peer_callback(&dev->info, user_data); + } +} + + #ifdef CONFIG_WPS_NFC static struct wpabuf * p2p_build_nfc_handover(struct p2p_data *p2p, @@ -4688,3 +4835,18 @@ void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id, } #endif /* CONFIG_WPS_NFC */ + + +int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len) +{ + if (len < 8 || len > 63) + return -1; + p2p->cfg->passphrase_len = len; + return 0; +} + + +void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem) +{ + p2p->vendor_elem = vendor_elem; +} diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h index fa8031d..076a2ac 100644 --- a/src/p2p/p2p.h +++ b/src/p2p/p2p.h @@ -230,6 +230,14 @@ struct p2p_peer_info { * wfd_subelems - Wi-Fi Display subelements from WFD IE(s) */ struct wpabuf *wfd_subelems; + + /** + * vendor_elems - Unrecognized vendor elements + * + * This buffer includes any other vendor element than P2P, WPS, and WFD + * IE(s) from the frame that was used to discover the peer. + */ + struct wpabuf *vendor_elems; }; enum p2p_prov_disc_status { @@ -267,6 +275,12 @@ struct p2p_config { u8 channel; /** + * channel_forced - the listen channel was forced by configuration + * or by control interface and cannot be overridden + */ + u8 channel_forced; + + /** * Regulatory class for own operational channel */ u8 op_reg_class; @@ -389,6 +403,14 @@ struct p2p_config { unsigned int max_listen; /** + * passphrase_len - Passphrase length (8..63) + * + * This parameter controls the length of the random passphrase that is + * generated at the GO. + */ + unsigned int passphrase_len; + + /** * cb_ctx - Context to use with callback functions */ void *cb_ctx; @@ -1669,7 +1691,24 @@ void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled); */ void p2p_set_managed_oper(struct p2p_data *p2p, int enabled); -int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel); +/** + * p2p_config_get_random_social - Return a random social channel + * @p2p: P2P config + * @op_class: Selected operating class + * @op_channel: Selected social channel + * Returns: 0 on success, -1 on failure + * + * This function is used before p2p_init is called. A random social channel + * from supports bands 2.4 GHz (channels 1,6,11) and 60 GHz (channel 2) is + * returned on success. + */ +int p2p_config_get_random_social(struct p2p_config *p2p, u8 *op_class, + u8 *op_channel); + +int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel, + u8 forced); + +u8 p2p_get_listen_channel(struct p2p_data *p2p); int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len); @@ -1771,7 +1810,7 @@ unsigned int p2p_get_group_num_members(struct p2p_group *group); * @group: P2P group context from p2p_group_init() * @next: iteration pointer, must be a pointer to a void * that is set to %NULL * on the first call and not modified later - * Returns: A P2P Interface Address for each call and %NULL for no more members + * Returns: A P2P Device Address for each call and %NULL for no more members */ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next); @@ -1793,6 +1832,26 @@ const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr); int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr); /** + * p2p_group_get_config - Get the group configuration + * @group: P2P group context from p2p_group_init() + * Returns: The group configuration pointer + */ +const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group); + +/** + * p2p_loop_on_all_groups - Run the given callback on all groups + * @p2p: P2P module context from p2p_init() + * @group_callback: The callback function pointer + * @user_data: Some user data pointer which can be %NULL + * + * The group_callback function can stop the iteration by returning 0. + */ +void p2p_loop_on_all_groups(struct p2p_data *p2p, + int (*group_callback)(struct p2p_group *group, + void *user_data), + void *user_data); + +/** * p2p_get_peer_found - Get P2P peer info structure of a found peer * @p2p: P2P module context from p2p_init() * @addr: P2P Device Address of the peer or %NULL to indicate the first peer @@ -1951,4 +2010,13 @@ void p2p_set_authorized_oob_dev_pw_id(struct p2p_data *p2p, u16 dev_pw_id, int go_intent, const u8 *own_interface_addr); +int p2p_set_passphrase_len(struct p2p_data *p2p, unsigned int len); + +void p2p_loop_on_known_peers(struct p2p_data *p2p, + void (*peer_callback)(struct p2p_peer_info *peer, + void *user_data), + void *user_data); + +void p2p_set_vendor_elems(struct p2p_data *p2p, struct wpabuf **vendor_elem); + #endif /* P2P_H */ diff --git a/src/p2p/p2p_dev_disc.c b/src/p2p/p2p_dev_disc.c index 76d01cf..86bae1a 100644 --- a/src/p2p/p2p_dev_disc.c +++ b/src/p2p/p2p_dev_disc.c @@ -68,6 +68,7 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev) { struct p2p_device *go; struct wpabuf *req; + unsigned int wait_time; go = p2p_get_device(p2p, dev->member_in_go_dev); if (go == NULL || dev->oper_freq <= 0) { @@ -88,9 +89,12 @@ int p2p_send_dev_disc_req(struct p2p_data *p2p, struct p2p_device *dev) os_memcpy(p2p->pending_client_disc_addr, dev->info.p2p_device_addr, ETH_ALEN); p2p->pending_action_state = P2P_PENDING_DEV_DISC_REQUEST; + wait_time = 1000; + if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen) + wait_time = p2p->cfg->max_listen; if (p2p_send_action(p2p, dev->oper_freq, go->info.p2p_device_addr, p2p->cfg->dev_addr, go->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 1000) < 0) { + wpabuf_head(req), wpabuf_len(req), wait_time) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); wpabuf_free(req); /* TODO: how to recover from failure? */ diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index f24fe23..21fae3f 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" @@ -142,6 +143,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -191,6 +195,9 @@ static struct wpabuf * p2p_build_go_neg_req(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_REQ]); + return buf; } @@ -268,6 +275,9 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -336,6 +346,8 @@ static struct wpabuf * p2p_build_go_neg_resp(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_RESP]); return buf; } @@ -844,6 +856,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -888,6 +903,9 @@ static struct wpabuf * p2p_build_go_neg_conf(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_go_neg); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_GO_NEG_CONF]); + return buf; } @@ -940,7 +958,10 @@ void p2p_process_go_neg_resp(struct p2p_data *p2p, const u8 *sa, p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation"); dev->flags |= P2P_DEV_NOT_YET_READY; os_get_reltime(&dev->go_neg_wait_started); - p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); + if (p2p->state == P2P_CONNECT_LISTEN) + p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT); + else + p2p_set_state(p2p, P2P_WAIT_PEER_IDLE); p2p_set_timeout(p2p, 0, 0); } else { p2p_dbg(p2p, "Stop GO Negotiation attempt"); diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c index 395ca08..da8588a 100644 --- a/src/p2p/p2p_group.c +++ b/src/p2p/p2p_group.c @@ -11,6 +11,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" #include "common/ieee802_11_common.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "wps/wps_i.h" #include "p2p_i.h" @@ -214,6 +215,10 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) extra = wpabuf_len(group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + ie = wpabuf_alloc(257 + extra); if (ie == NULL) return NULL; @@ -223,6 +228,11 @@ static struct wpabuf * p2p_group_build_beacon_ie(struct p2p_group *group) wpabuf_put_buf(ie, group->p2p->wfd_ie_beacon); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]) + wpabuf_put_buf(ie, + group->p2p->vendor_elem[VENDOR_ELEM_BEACON_P2P_GO]); + len = p2p_buf_add_ie_hdr(ie); p2p_group_add_common_ies(group, ie); p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr); @@ -448,6 +458,13 @@ static struct wpabuf * p2p_group_build_probe_resp_ie(struct p2p_group *group) ie = p2p_group_encaps_probe_resp(p2p_subelems); wpabuf_free(p2p_subelems); + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]) { + struct wpabuf *extra; + extra = wpabuf_dup(group->p2p->vendor_elem[VENDOR_ELEM_PROBE_RESP_P2P_GO]); + ie = wpabuf_concat(extra, ie); + } + #ifdef CONFIG_WIFI_DISPLAY if (group->wfd_ie) { struct wpabuf *wfd = wpabuf_dup(group->wfd_ie); @@ -634,6 +651,10 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) extra = wpabuf_len(group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + extra += wpabuf_len(group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); + /* * (Re)Association Response - P2P IE * Status attribute (shall be present when association request is @@ -649,6 +670,11 @@ struct wpabuf * p2p_group_assoc_resp_ie(struct p2p_group *group, u8 status) wpabuf_put_buf(resp, group->wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (group->p2p->vendor_elem && + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]) + wpabuf_put_buf(resp, + group->p2p->vendor_elem[VENDOR_ELEM_P2P_ASSOC_RESP]); + rlen = p2p_buf_add_ie_hdr(resp); if (status != P2P_SC_SUCCESS) p2p_buf_add_status(resp, status); @@ -973,7 +999,7 @@ const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next) if (!iter) return NULL; - return iter->addr; + return iter->dev_addr; } @@ -1013,3 +1039,23 @@ int p2p_group_get_freq(struct p2p_group *group) { return group->cfg->freq; } + + +const struct p2p_group_config * p2p_group_get_config(struct p2p_group *group) +{ + return group->cfg; +} + + +void p2p_loop_on_all_groups(struct p2p_data *p2p, + int (*group_callback)(struct p2p_group *group, + void *user_data), + void *user_data) +{ + unsigned int i; + + for (i = 0; i < p2p->num_groups; i++) { + if (!group_callback(p2p->groups[i], user_data)) + break; + } +} diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h index 65ff9ef..3b60582 100644 --- a/src/p2p/p2p_i.h +++ b/src/p2p/p2p_i.h @@ -480,6 +480,10 @@ struct p2p_data { unsigned int search_delay; int in_search_delay; + u8 pending_reg_class; + u8 pending_channel; + u8 pending_channel_forced; + #ifdef CONFIG_WIFI_DISPLAY struct wpabuf *wfd_ie_beacon; struct wpabuf *wfd_ie_probe_req; @@ -495,6 +499,8 @@ struct p2p_data { #endif /* CONFIG_WIFI_DISPLAY */ u16 authorized_oob_dev_pw_id; + + struct wpabuf **vendor_elem; }; /** diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c index a36898e..ef01a66 100644 --- a/src/p2p/p2p_invitation.c +++ b/src/p2p/p2p_invitation.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "p2p_i.h" #include "p2p.h" @@ -45,6 +46,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, extra = wpabuf_len(wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -86,6 +90,9 @@ static struct wpabuf * p2p_build_invitation_req(struct p2p_data *p2p, wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_INV_REQ]); + if (dev_pw_id >= 0) { /* WSC IE in Invitation Request for NFC static handover */ p2p_build_wps_ie(p2p, buf, dev_pw_id, 0); diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c index 68d79d2..e101367 100644 --- a/src/p2p/p2p_pd.c +++ b/src/p2p/p2p_pd.c @@ -10,6 +10,7 @@ #include "common.h" #include "common/ieee802_11_defs.h" +#include "common/wpa_ctrl.h" #include "wps/wps_defs.h" #include "p2p_i.h" #include "p2p.h" @@ -53,6 +54,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, extra = wpabuf_len(p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); + buf = wpabuf_alloc(1000 + extra); if (buf == NULL) return NULL; @@ -77,6 +81,9 @@ static struct wpabuf * p2p_build_prov_disc_req(struct p2p_data *p2p, wpabuf_put_buf(buf, p2p->wfd_ie_prov_disc_req); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_REQ]); + return buf; } @@ -111,6 +118,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, extra = wpabuf_len(wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) + extra += wpabuf_len(p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); + buf = wpabuf_alloc(100 + extra); if (buf == NULL) return NULL; @@ -125,6 +135,9 @@ static struct wpabuf * p2p_build_prov_disc_resp(struct p2p_data *p2p, wpabuf_put_buf(buf, wfd_ie); #endif /* CONFIG_WIFI_DISPLAY */ + if (p2p->vendor_elem && p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]) + wpabuf_put_buf(buf, p2p->vendor_elem[VENDOR_ELEM_P2P_PD_RESP]); + return buf; } diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c index 9df834c..13119c2 100644 --- a/src/p2p/p2p_sd.c +++ b/src/p2p/p2p_sd.c @@ -266,6 +266,7 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) int ret = 0; struct p2p_sd_query *query; int freq; + unsigned int wait_time; freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq; if (freq <= 0) { @@ -290,23 +291,16 @@ int p2p_start_sd(struct p2p_data *p2p, struct p2p_device *dev) p2p->sd_query = query; p2p->pending_action_state = P2P_PENDING_SD; + wait_time = 5000; + if (p2p->cfg->max_listen && wait_time > p2p->cfg->max_listen) + wait_time = p2p->cfg->max_listen; if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr, p2p->cfg->dev_addr, dev->info.p2p_device_addr, - wpabuf_head(req), wpabuf_len(req), 5000) < 0) { + wpabuf_head(req), wpabuf_len(req), wait_time) < 0) { p2p_dbg(p2p, "Failed to send Action frame"); ret = -1; } - /* Update the pending broadcast SD query count for this device */ - dev->sd_pending_bcast_queries--; - - /* - * If there are no pending broadcast queries for this device, mark it as - * done (-1). - */ - if (dev->sd_pending_bcast_queries == 0) - dev->sd_pending_bcast_queries = -1; - wpabuf_free(req); return ret; diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c index ac19064..23acce7 100644 --- a/src/p2p/p2p_utils.c +++ b/src/p2p/p2p_utils.c @@ -149,6 +149,15 @@ int p2p_freq_to_channel(unsigned int freq, u8 *op_class, u8 *channel) return 0; } + if (freq >= 58320 && freq <= 64800) { + if ((freq - 58320) % 2160) + return -1; + + *op_class = 180; /* 60 GHz, channels 1..4 */ + *channel = (freq - 56160) / 2160; + return 0; + } + return -1; } @@ -388,17 +397,19 @@ unsigned int p2p_get_pref_freq(struct p2p_data *p2p, const struct p2p_channels *channels) { unsigned int i; - int freq; + int freq = 0; + const struct p2p_channels *tmpc = channels ? + channels : &p2p->cfg->channels; + + if (tmpc == NULL) + return 0; for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) { freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class, p2p->cfg->pref_chan[i].chan); - if (freq <= 0) - continue; - if (!channels || p2p_channels_includes_freq(channels, freq)) + if (p2p_channels_includes_freq(tmpc, freq)) return freq; } - return 0; } @@ -439,7 +450,8 @@ void p2p_channels_dump(struct p2p_data *p2p, const char *title, static u8 p2p_channel_pick_random(const u8 *channels, unsigned int num_channels) { unsigned int r; - os_get_random((u8 *) &r, sizeof(r)); + if (os_get_random((u8 *) &r, sizeof(r)) < 0) + r = 0; r %= num_channels; return channels[r]; } @@ -479,7 +491,7 @@ int p2p_channel_select(struct p2p_channels *chans, const int *classes, int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class, u8 *op_channel) { - u8 chan[3]; + u8 chan[4]; unsigned int num_channels = 0; /* Try to find available social channels from 2.4 GHz */ @@ -490,11 +502,18 @@ int p2p_channel_random_social(struct p2p_channels *chans, u8 *op_class, if (p2p_channels_includes(chans, 81, 11)) chan[num_channels++] = 11; + /* Try to find available social channels from 60 GHz */ + if (p2p_channels_includes(chans, 180, 2)) + chan[num_channels++] = 2; + if (num_channels == 0) return -1; - *op_class = 81; *op_channel = p2p_channel_pick_random(chan, num_channels); + if (*op_channel == 2) + *op_class = 180; + else + *op_class = 81; return 0; } diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c index fb8a8ca..b1cf32d 100644 --- a/src/pae/ieee802_1x_kay.c +++ b/src/pae/ieee802_1x_kay.c @@ -1451,7 +1451,7 @@ ieee802_1x_mka_encode_dist_sak_body( os_memcpy(body->sak, cipher_suite_tbl[cs_index].id, CS_ID_LEN); sak_pos = CS_ID_LEN; } - if (aes_wrap(participant->kek.key, + if (aes_wrap(participant->kek.key, 16, cipher_suite_tbl[cs_index].sak_len / 8, sak->key, body->sak + sak_pos)) { wpa_printf(MSG_ERROR, "KaY: AES wrap failed"); @@ -1611,7 +1611,7 @@ ieee802_1x_mka_decode_dist_sak_body( wpa_printf(MSG_ERROR, "KaY-%s: Out of memory", __func__); return -1; } - if (aes_unwrap(participant->kek.key, sak_len >> 3, wrap_sak, + if (aes_unwrap(participant->kek.key, 16, sak_len >> 3, wrap_sak, unwrap_sak)) { wpa_printf(MSG_ERROR, "KaY: AES unwrap failed"); os_free(unwrap_sak); @@ -2942,8 +2942,9 @@ static int ieee802_1x_kay_mkpdu_sanity_check(struct ieee802_1x_kay *kay, mka_msg_len); if (msg_icv) { - if (os_memcmp(msg_icv, icv, - mka_alg_tbl[kay->mka_algindex].icv_len) != 0) { + if (os_memcmp_const(msg_icv, icv, + mka_alg_tbl[kay->mka_algindex].icv_len) != + 0) { wpa_printf(MSG_ERROR, "KaY: Computed ICV is not equal to Received ICV"); return -1; diff --git a/src/radius/radius.c b/src/radius/radius.c index e34d08b..f3b645d 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -233,6 +233,17 @@ static struct radius_attr_type radius_attrs[] = { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 }, { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }, { RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id", + RADIUS_ATTR_INT32 }, + { RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT }, + { RADIUS_ATTR_WLAN_PAIRWISE_CIPHER, "WLAN-Pairwise-Cipher", + RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_WLAN_GROUP_CIPHER, "WLAN-Group-Cipher", + RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_WLAN_AKM_SUITE, "WLAN-AKM-Suite", + RADIUS_ATTR_HEXDUMP }, + { RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER, "WLAN-Group-Mgmt-Pairwise-Cipher", + RADIUS_ATTR_HEXDUMP }, }; #define RADIUS_ATTRS ARRAY_SIZE(radius_attrs) @@ -508,7 +519,7 @@ int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret, addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); - return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; + return os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0; } @@ -535,7 +546,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); - if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) + if (os_memcmp_const(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0) return 1; for (i = 0; i < msg->attr_used; i++) { @@ -568,7 +579,7 @@ int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret, os_memcpy(msg->hdr->authenticator, orig_authenticator, sizeof(orig_authenticator)); - return os_memcmp(orig, auth, MD5_MAC_LEN) != 0; + return os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0; } @@ -801,7 +812,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret, sizeof(orig_authenticator)); } - if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) { + if (os_memcmp_const(orig, auth, MD5_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "Invalid Message-Authenticator!"); return 1; } @@ -838,7 +849,7 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret, addr[3] = secret; len[3] = secret_len; md5_vector(4, addr, len, hash); - if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { + if (os_memcmp_const(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) { wpa_printf(MSG_INFO, "Response Authenticator invalid!"); return 1; } diff --git a/src/radius/radius.h b/src/radius/radius.h index 34307f2..62faae1 100644 --- a/src/radius/radius.h +++ b/src/radius/radius.h @@ -92,6 +92,12 @@ enum { RADIUS_ATTR_USER_NAME = 1, RADIUS_ATTR_NAS_IPV6_ADDRESS = 95, RADIUS_ATTR_ERROR_CAUSE = 101, RADIUS_ATTR_EAP_KEY_NAME = 102, + RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177, + RADIUS_ATTR_WLAN_HESSID = 181, + RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186, + RADIUS_ATTR_WLAN_GROUP_CIPHER = 187, + RADIUS_ATTR_WLAN_AKM_SUITE = 188, + RADIUS_ATTR_WLAN_GROUP_MGMT_CIPHER = 189, }; diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 10056a6..e2766e2 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -1080,19 +1080,23 @@ radius_change_server(struct radius_client_data *radius, switch (nserv->addr.af) { case AF_INET: claddrlen = sizeof(claddr); - getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); - wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", - inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); + if (getsockname(sel_sock, (struct sockaddr *) &claddr, + &claddrlen) == 0) { + wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", + inet_ntoa(claddr.sin_addr), + ntohs(claddr.sin_port)); + } break; #ifdef CONFIG_IPV6 case AF_INET6: { claddrlen = sizeof(claddr6); - getsockname(sel_sock, (struct sockaddr *) &claddr6, - &claddrlen); - wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", - inet_ntop(AF_INET6, &claddr6.sin6_addr, - abuf, sizeof(abuf)), - ntohs(claddr6.sin6_port)); + if (getsockname(sel_sock, (struct sockaddr *) &claddr6, + &claddrlen) == 0) { + wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", + inet_ntop(AF_INET6, &claddr6.sin6_addr, + abuf, sizeof(abuf)), + ntohs(claddr6.sin6_port)); + } break; } #endif /* CONFIG_IPV6 */ diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index c35ba55..00394b4 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -623,7 +623,7 @@ radius_server_get_new_session(struct radius_server_data *data, os_memset(&tmp, 0, sizeof(tmp)); res = data->get_eap_user(data->conf_ctx, user, user_len, 0, &tmp); - os_free(tmp.password); + bin_clear_free(tmp.password, tmp.password_len); if (res != 0) { RADIUS_DEBUG("User-Name not found from user database"); @@ -852,7 +852,7 @@ radius_server_macacl(struct radius_server_data *data, os_strlen(sess->username), 0, &tmp); if (res || !tmp.macacl || tmp.password == NULL) { RADIUS_DEBUG("No MAC ACL user entry"); - os_free(tmp.password); + bin_clear_free(tmp.password, tmp.password_len); code = RADIUS_CODE_ACCESS_REJECT; } else { u8 buf[128]; @@ -861,10 +861,10 @@ radius_server_macacl(struct radius_server_data *data, (u8 *) client->shared_secret, client->shared_secret_len, buf, sizeof(buf)); - os_free(tmp.password); + bin_clear_free(tmp.password, tmp.password_len); if (res < 0 || pw_len != (size_t) res || - os_memcmp(pw, buf, res) != 0) { + os_memcmp_const(pw, buf, res) != 0) { RADIUS_DEBUG("Incorrect User-Password"); code = RADIUS_CODE_ACCESS_REJECT; } @@ -1926,7 +1926,7 @@ int radius_server_get_mib(struct radius_server_data *data, char *buf, if (inet_ntop(AF_INET6, &cli->addr6, abuf, sizeof(abuf)) == NULL) abuf[0] = '\0'; - if (inet_ntop(AF_INET6, &cli->mask6, abuf, + if (inet_ntop(AF_INET6, &cli->mask6, mbuf, sizeof(mbuf)) == NULL) mbuf[0] = '\0'; } @@ -2048,8 +2048,6 @@ void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx) sess = s; break; } - if (sess) - break; } if (sess) break; diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c index 88550e4..aab8b7e 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -653,11 +653,11 @@ static int wpa_supplicant_process_smk_error( static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, struct wpa_peerkey *peerkey, const struct wpa_eapol_key *key, - u16 ver) + u16 ver, const u8 *key_data, + size_t key_data_len) { struct wpa_eapol_ie_parse ie; - const u8 *kde; - size_t len, kde_buf_len; + size_t kde_buf_len; struct wpa_ptk *stk; u8 buf[8], *kde_buf, *pos; be32 lifetime; @@ -668,14 +668,13 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, os_memset(&ie, 0, sizeof(ie)); /* RSN: msg 1/4 should contain SMKID for the selected SMK */ - kde = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len); - if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) { + wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0 || + ie.pmkid == NULL) { wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4"); return; } - if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) { + if (os_memcmp_const(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) { wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4", ie.pmkid, PMKID_LEN); return; @@ -760,11 +759,10 @@ static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, struct wpa_peerkey *peerkey, const struct wpa_eapol_key *key, - u16 ver) + u16 ver, const u8 *key_data, + size_t key_data_len) { struct wpa_eapol_ie_parse kde; - const u8 *keydata; - size_t len; wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from " MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); @@ -773,16 +771,14 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE * from the peer. It may also include Lifetime KDE. */ - keydata = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len); - if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 || + wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0 || kde.pmkid == NULL || kde.rsn_ie == NULL) { wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4"); return; } - if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) { + if (os_memcmp_const(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) { wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4", kde.pmkid, PMKID_LEN); return; @@ -809,11 +805,11 @@ static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, struct wpa_peerkey *peerkey, const struct wpa_eapol_key *key, - u16 ver) + u16 ver, const u8 *key_data, + size_t key_data_len) { struct wpa_eapol_ie_parse kde; - const u8 *keydata; - size_t len, key_len; + size_t key_len; const u8 *_key; u8 key_buf[32], rsc[6]; @@ -824,10 +820,8 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include * Lifetime KDE. */ - keydata = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len); - if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) { + wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &kde) < 0) { wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in " "STK 3/4"); return; @@ -935,7 +929,7 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, os_memset(key->key_mic, 0, 16); wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len, key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { + if (os_memcmp_const(mic, key->key_mic, 16) != 0) { wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " "when using TSTK - ignoring TSTK"); } else { @@ -951,7 +945,7 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, os_memset(key->key_mic, 0, 16); wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len, key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { + if (os_memcmp_const(mic, key->key_mic, 16) != 0) { wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " "- dropping packet"); return -1; @@ -1117,21 +1111,25 @@ void peerkey_deinit(struct wpa_sm *sm) void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver) + struct wpa_eapol_key *key, u16 key_info, u16 ver, + const u8 *key_data, size_t key_data_len) { if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) == (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) { /* 3/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver); + wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver, + key_data, key_data_len); } else if (key_info & WPA_KEY_INFO_ACK) { /* 1/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver); + wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver, + key_data, key_data_len); } else if (key_info & WPA_KEY_INFO_SECURE) { /* 4/4 STK 4-Way Handshake */ wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver); } else { /* 2/4 STK 4-Way Handshake */ - wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver); + wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver, + key_data, key_data_len); } } diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h index f420691..4c17eae 100644 --- a/src/rsn_supp/peerkey.h +++ b/src/rsn_supp/peerkey.h @@ -41,7 +41,8 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, struct wpa_eapol_key *key, u16 ver, const u8 *buf, size_t len); void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver); + struct wpa_eapol_key *key, u16 key_info, u16 ver, + const u8 *key_data, size_t key_data_len); void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, struct wpa_eapol_key *key, size_t extra_len, u16 key_info, u16 ver); @@ -60,7 +61,8 @@ peerkey_verify_eapol_key_mic(struct wpa_sm *sm, static inline void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, - struct wpa_eapol_key *key, u16 key_info, u16 ver) + struct wpa_eapol_key *key, u16 key_info, u16 ver, + const u8 *key_data, size_t key_data_len) { } diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c index 0960815..885291a 100644 --- a/src/rsn_supp/pmksa_cache.c +++ b/src/rsn_supp/pmksa_cache.c @@ -35,7 +35,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa); static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry) { - os_free(entry); + bin_clear_free(entry, sizeof(*entry)); } @@ -152,9 +152,9 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, while (pos) { if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) { if (pos->pmk_len == pmk_len && - os_memcmp(pos->pmk, pmk, pmk_len) == 0 && - os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == - 0) { + os_memcmp_const(pos->pmk, pmk, pmk_len) == 0 && + os_memcmp_const(pos->pmkid, entry->pmkid, + PMKID_LEN) == 0) { wpa_printf(MSG_DEBUG, "WPA: reusing previous " "PMKSA entry"); os_free(entry); diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 3b14656..8cb19a2 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -218,26 +218,29 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer) static int wpa_tdls_send_tpk_msg(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - const u8 *buf, size_t len) + int initiator, const u8 *buf, size_t len) { return wpa_sm_send_tdls_mgmt(sm, dst, action_code, dialog_token, - status_code, peer_capab, buf, len); + status_code, peer_capab, initiator, buf, + len); } static int wpa_tdls_tpk_send(struct wpa_sm *sm, const u8 *dest, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - const u8 *msg, size_t msg_len) + int initiator, const u8 *msg, size_t msg_len) { struct wpa_tdls_peer *peer; wpa_printf(MSG_DEBUG, "TDLS: TPK send dest=" MACSTR " action_code=%u " - "dialog_token=%u status_code=%u peer_capab=%u msg_len=%u", + "dialog_token=%u status_code=%u peer_capab=%u initiator=%d " + "msg_len=%u", MAC2STR(dest), action_code, dialog_token, status_code, - peer_capab, (unsigned int) msg_len); + peer_capab, initiator, (unsigned int) msg_len); if (wpa_tdls_send_tpk_msg(sm, dest, action_code, dialog_token, - status_code, peer_capab, msg, msg_len)) { + status_code, peer_capab, initiator, msg, + msg_len)) { wpa_printf(MSG_INFO, "TDLS: Failed to send message " "(action_code=%u)", action_code); return -1; @@ -333,6 +336,7 @@ static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx) peer->sm_tmr.dialog_token, peer->sm_tmr.status_code, peer->sm_tmr.peer_capab, + peer->initiator, peer->sm_tmr.buf, peer->sm_tmr.buf_len)) { wpa_printf(MSG_INFO, "TDLS: Failed to retry " @@ -564,7 +568,7 @@ static int wpa_supplicant_verify_tdls_mic(u8 trans_seq, wpa_tdls_ftie_mic(peer->tpk.kck, trans_seq, lnkid, peer->rsnie_p, timeoutie, (u8 *) ftie, mic); - if (os_memcmp(mic, ftie->mic, 16) != 0) { + if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_INFO, "TDLS: Invalid MIC in FTIE - " "dropping packet"); wpa_hexdump(MSG_DEBUG, "TDLS: Received MIC", @@ -591,7 +595,7 @@ static int wpa_supplicant_verify_tdls_mic_teardown( if (peer->tpk_set) { wpa_tdls_key_mic_teardown(peer->tpk.kck, trans_seq, rcode, dtoken, lnkid, (u8 *) ftie, mic); - if (os_memcmp(mic, ftie->mic, 16) != 0) { + if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_INFO, "TDLS: Invalid MIC in Teardown - " "dropping packet"); return -1; @@ -631,7 +635,33 @@ static void wpa_tdls_tpk_timeout(void *eloop_ctx, void *timeout_ctx) } -static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) +static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm, + struct wpa_tdls_peer *peer) +{ + struct wpa_tdls_peer *cur, *prev; + + cur = sm->tdls; + prev = NULL; + while (cur && cur != peer) { + prev = cur; + cur = cur->next; + } + + if (cur != peer) { + wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR + " to remove it from the list", + MAC2STR(peer->addr)); + return; + } + + if (prev) + prev->next = peer->next; + else + sm->tdls = peer->next; +} + + +static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer) { wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR, MAC2STR(peer->addr)); @@ -663,6 +693,14 @@ static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) } +static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer) +{ + wpa_tdls_peer_clear(sm, peer); + wpa_tdls_peer_remove_from_list(sm, peer); + os_free(peer); +} + + static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer, struct wpa_tdls_lnkid *lnkid) { @@ -759,7 +797,7 @@ skip_ies: /* request driver to send Teardown using this FTIE */ wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_TEARDOWN, 0, - reason_code, 0, rbuf, pos - rbuf); + reason_code, 0, peer->initiator, rbuf, pos - rbuf); os_free(rbuf); return 0; @@ -802,7 +840,7 @@ static void wpa_tdls_disable_peer_link(struct wpa_sm *sm, } -void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr) +void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr) { struct wpa_tdls_peer *peer; @@ -811,8 +849,25 @@ void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr) break; } - if (peer) + if (!peer || !peer->tpk_success) { + wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR + " not connected - cannot teardown unreachable link", + MAC2STR(addr)); + return; + } + + if (wpa_tdls_is_external_setup(sm)) { + /* + * Disable the link, send a teardown packet through the + * AP, and then reset link data. + */ + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr); + wpa_tdls_send_teardown(sm, addr, + WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE); + wpa_tdls_peer_free(sm, peer); + } else { wpa_tdls_disable_peer_link(sm, peer); + } } @@ -917,17 +972,19 @@ skip_ftie: * appropriate status code mentioning reason for error/failure. * @dst - MAC addr of Peer station * @tdls_action - TDLS frame type for which error code is sent + * @initiator - was this end the initiator of the connection * @status - status code mentioning reason */ static int wpa_tdls_send_error(struct wpa_sm *sm, const u8 *dst, - u8 tdls_action, u8 dialog_token, u16 status) + u8 tdls_action, u8 dialog_token, int initiator, + u16 status) { wpa_printf(MSG_DEBUG, "TDLS: Sending error to " MACSTR " (action=%u status=%u)", MAC2STR(dst), tdls_action, status); return wpa_tdls_tpk_send(sm, dst, tdls_action, dialog_token, status, - 0, NULL, 0); + 0, initiator, NULL, 0); } @@ -1133,7 +1190,7 @@ skip_ies: MAC2STR(peer->addr)); status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, - 1, 0, 0, rbuf, pos - rbuf); + 1, 0, 0, peer->initiator, rbuf, pos - rbuf); os_free(rbuf); return status; @@ -1223,7 +1280,8 @@ static int wpa_tdls_send_tpk_m2(struct wpa_sm *sm, skip_ies: status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, - dtoken, 0, 0, rbuf, pos - rbuf); + dtoken, 0, 0, peer->initiator, rbuf, + pos - rbuf); os_free(rbuf); return status; @@ -1320,7 +1378,8 @@ skip_ies: peer_capab |= TDLS_PEER_WMM; status = wpa_tdls_tpk_send(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, - dtoken, 0, peer_capab, rbuf, pos - rbuf); + dtoken, 0, peer_capab, peer->initiator, + rbuf, pos - rbuf); os_free(rbuf); return status; @@ -1331,11 +1390,85 @@ static int wpa_tdls_send_discovery_response(struct wpa_sm *sm, struct wpa_tdls_peer *peer, u8 dialog_token) { + size_t buf_len = 0; + struct wpa_tdls_timeoutie timeoutie; + u16 rsn_capab; + u8 *rbuf, *pos, *count_pos; + u16 count; + struct rsn_ie_hdr *hdr; + int status; + wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response " "(peer " MACSTR ")", MAC2STR(peer->addr)); + if (!wpa_tdls_get_privacy(sm)) + goto skip_rsn_ies; + + /* Filling RSN IE */ + hdr = (struct rsn_ie_hdr *) peer->rsnie_i; + hdr->elem_id = WLAN_EID_RSN; + WPA_PUT_LE16(hdr->version, RSN_VERSION); + pos = (u8 *) (hdr + 1); + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED); + pos += RSN_SELECTOR_LEN; + count_pos = pos; + pos += 2; + count = 0; + + /* + * AES-CCMP is the default encryption preferred for TDLS, so + * RSN IE is filled only with CCMP cipher suite. + * Note: TKIP is not used to encrypt TDLS link. + * + * Regardless of the cipher used on the AP connection, select CCMP + * here. + */ + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); + pos += RSN_SELECTOR_LEN; + count++; + WPA_PUT_LE16(count_pos, count); + WPA_PUT_LE16(pos, 1); + pos += 2; + RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE); + pos += RSN_SELECTOR_LEN; + + rsn_capab = WPA_CAPABILITY_PEERKEY_ENABLED; + rsn_capab |= RSN_NUM_REPLAY_COUNTERS_16 << 2; + WPA_PUT_LE16(pos, rsn_capab); + pos += 2; + hdr->len = (pos - (u8 *) hdr) - 2; + peer->rsnie_i_len = pos - peer->rsnie_i; + + wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE for Discovery Response", + (u8 *) hdr, hdr->len + 2); +skip_rsn_ies: + buf_len = 0; + if (wpa_tdls_get_privacy(sm)) { + /* Peer RSN IE, Lifetime */ + buf_len += peer->rsnie_i_len + + sizeof(struct wpa_tdls_timeoutie); + } + rbuf = os_zalloc(buf_len + 1); + if (rbuf == NULL) { + wpa_tdls_peer_free(sm, peer); + return -1; + } + pos = rbuf; + + if (!wpa_tdls_get_privacy(sm)) + goto skip_ies; + /* Initiator RSN IE */ + pos = wpa_add_ie(pos, peer->rsnie_i, peer->rsnie_i_len); + /* Lifetime */ + peer->lifetime = TPK_LIFETIME; + pos = wpa_add_tdls_timeoutie(pos, (u8 *) &timeoutie, + sizeof(timeoutie), peer->lifetime); + wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime %u seconds", peer->lifetime); +skip_ies: + status = wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, + dialog_token, 0, 0, 0, rbuf, pos - rbuf); + os_free(rbuf); - return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE, - dialog_token, 0, 0, NULL, 0); + return status; } @@ -1361,10 +1494,17 @@ wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr, dialog_token = buf[sizeof(struct wpa_tdls_frame)]; + /* + * Some APs will tack on a weird IE to the end of a TDLS + * discovery request packet. This needn't fail the response, + * since the required IE are verified separately. + */ if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1, len - (sizeof(struct wpa_tdls_frame) + 1), - &kde) < 0) - return -1; + &kde) < 0) { + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse IEs in Discovery Request - ignore as an interop workaround"); + } if (!kde.lnkid) { wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery " @@ -1396,7 +1536,7 @@ int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr) wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer " MACSTR, MAC2STR(addr)); return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST, - 1, 0, 0, NULL, 0); + 1, 0, 0, 1, NULL, 0); } @@ -1573,6 +1713,23 @@ static int copy_peer_supp_oper_classes(const struct wpa_eapol_ie_parse *kde, } +static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer, + int add) +{ + return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid, + peer->capability, + peer->supp_rates, peer->supp_rates_len, + peer->ht_capabilities, + peer->vht_capabilities, + peer->qos_info, peer->wmm_capable, + peer->ext_capab, peer->ext_capab_len, + peer->supp_channels, + peer->supp_channels_len, + peer->supp_oper_classes, + peer->supp_oper_classes_len); +} + + static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { @@ -1620,16 +1777,16 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while " "direct link is enabled - tear down the " "old link first"); - wpa_tdls_disable_peer_link(sm, peer); - } - - /* - * An entry is already present, so check if we already sent a - * TDLS Setup Request. If so, compare MAC addresses and let the - * STA with the lower MAC address continue as the initiator. - * The other negotiation is terminated. - */ - if (peer->initiator) { + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); + wpa_tdls_peer_clear(sm, peer); + } else if (peer->initiator) { + /* + * An entry is already present, so check if we already + * sent a TDLS Setup Request. If so, compare MAC + * addresses and let the STA with the lower MAC address + * continue as the initiator. The other negotiation is + * terminated. + */ if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) { wpa_printf(MSG_DEBUG, "TDLS: Discard request " "from peer with higher address " @@ -1641,7 +1798,9 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, MACSTR " (terminate previously " "initiated negotiation", MAC2STR(src_addr)); - wpa_tdls_disable_peer_link(sm, peer); + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, + peer->addr); + wpa_tdls_peer_clear(sm, peer); } } } @@ -1666,7 +1825,7 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, lnkid = (struct wpa_tdls_lnkid *) kde.lnkid; if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) { wpa_printf(MSG_INFO, "TDLS: TPK M1 from diff BSS"); - status = WLAN_STATUS_NOT_IN_SAME_BSS; + status = WLAN_STATUS_REQUEST_DECLINED; goto error; } @@ -1707,6 +1866,8 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of " "TDLS setup - send own request"); peer->initiator = 1; + wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, + NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0); wpa_tdls_send_tpk_m1(sm, peer); } @@ -1831,7 +1992,6 @@ skip_rsn: if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) { wpa_msg(sm->ctx->ctx, MSG_WARNING, "TDLS: Failed to get random data for responder nonce"); - wpa_tdls_peer_free(sm, peer); goto error; } } @@ -1886,22 +2046,33 @@ skip_rsn: wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid); skip_rsn_check: - /* add the peer to the driver as a "setup in progress" peer */ - wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0, NULL, 0, NULL, 0); +#ifdef CONFIG_TDLS_TESTING + if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) + goto skip_add_peer; +#endif /* CONFIG_TDLS_TESTING */ + + /* add supported rates, capabilities, and qos_info to the TDLS peer */ + if (wpa_tdls_addset_peer(sm, peer, 1) < 0) + goto error; + +#ifdef CONFIG_TDLS_TESTING +skip_add_peer: +#endif /* CONFIG_TDLS_TESTING */ peer->tpk_in_progress = 1; wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2"); if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) { - wpa_tdls_disable_peer_link(sm, peer); + wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr); goto error; } return 0; error: - wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, + wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken, 0, status); + if (peer) + wpa_tdls_peer_free(sm, peer); return -1; } @@ -1930,20 +2101,6 @@ static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer) #endif /* CONFIG_TDLS_TESTING */ } - /* add supported rates, capabilities, and qos_info to the TDLS peer */ - if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid, - peer->capability, - peer->supp_rates, peer->supp_rates_len, - peer->ht_capabilities, - peer->vht_capabilities, - peer->qos_info, peer->ext_capab, - peer->ext_capab_len, - peer->supp_channels, - peer->supp_channels_len, - peer->supp_oper_classes, - peer->supp_oper_classes_len) < 0) - return -1; - if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) { wpa_printf(MSG_INFO, "TDLS: Could not configure key to the " "driver"); @@ -2098,6 +2255,13 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M2", kde.rsn_ie, kde.rsn_ie_len); + if (kde.rsn_ie_len > TDLS_MAX_IE_LEN) { + wpa_printf(MSG_INFO, + "TDLS: Too long Responder RSN IE in TPK M2"); + status = WLAN_STATUS_INVALID_RSNIE; + goto error; + } + /* * FIX: bitwise comparison of RSN IE is not the correct way of * validation this. It can be different, but certain fields must @@ -2190,12 +2354,14 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, skip_rsn: peer->dtoken = dtoken; + /* add supported rates, capabilities, and qos_info to the TDLS peer */ + if (wpa_tdls_addset_peer(sm, peer, 0) < 0) + goto error; + wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / " "TPK Handshake Message 3"); - if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) { - wpa_tdls_disable_peer_link(sm, peer); - return -1; - } + if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) + goto error; if (!peer->tpk_success) { /* @@ -2214,7 +2380,7 @@ skip_rsn: return ret; error: - wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, + wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken, 1, status); wpa_tdls_disable_peer_link(sm, peer); return -1; @@ -2263,9 +2429,16 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, pos += 2 /* status code */ + 1 /* dialog token */; ielen = len - (pos - buf); /* start of IE in buf */ + + /* + * Don't reject the message if failing to parse IEs. The IEs we need are + * explicitly checked below. Some APs piggy-back broken IEs to the end + * of a TDLS Confirm packet, which will fail the link if we don't ignore + * this error. + */ if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) { - wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3"); - goto error; + wpa_printf(MSG_DEBUG, + "TDLS: Failed to parse KDEs in TPK M3 - ignore as an interop workaround"); } if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) { @@ -2350,6 +2523,10 @@ static int wpa_tdls_process_tpk_m3(struct wpa_sm *sm, const u8 *src_addr, } skip_rsn: + /* add supported rates, capabilities, and qos_info to the TDLS peer */ + if (wpa_tdls_addset_peer(sm, peer, 0) < 0) + goto error; + if (!peer->tpk_success) { /* * Enable Link only when tpk_success is 0, signifying that this @@ -2359,14 +2536,12 @@ skip_rsn: ret = wpa_tdls_enable_link(sm, peer); if (ret < 0) { wpa_printf(MSG_DEBUG, "TDLS: Could not enable link"); - wpa_tdls_do_teardown( - sm, peer, - WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); + goto error; } } return ret; error: - wpa_tdls_disable_peer_link(sm, peer); + wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED); return -1; } @@ -2429,8 +2604,11 @@ int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr) peer->initiator = 1; /* add the peer to the driver as a "setup in progress" peer */ - wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0, - NULL, 0, NULL, 0, NULL, 0); + if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, + NULL, 0, 0, NULL, 0, NULL, 0, NULL, 0)) { + wpa_tdls_disable_peer_link(sm, peer); + return -1; + } peer->tpk_in_progress = 1; @@ -2580,13 +2758,14 @@ int wpa_tdls_init(struct wpa_sm *sm) void wpa_tdls_teardown_peers(struct wpa_sm *sm) { - struct wpa_tdls_peer *peer; + struct wpa_tdls_peer *peer, *tmp; peer = sm->tdls; wpa_printf(MSG_DEBUG, "TDLS: Tear down peers"); while (peer) { + tmp = peer->next; wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR, MAC2STR(peer->addr)); if (sm->tdls_external_setup) @@ -2595,7 +2774,7 @@ void wpa_tdls_teardown_peers(struct wpa_sm *sm) else wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr); - peer = peer->next; + peer = tmp; } } @@ -2605,7 +2784,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm) struct wpa_tdls_peer *peer, *tmp; peer = sm->tdls; - sm->tdls = NULL; while (peer) { int res; @@ -2614,7 +2792,6 @@ static void wpa_tdls_remove_peers(struct wpa_sm *sm) wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)", MAC2STR(peer->addr), res); wpa_tdls_peer_free(sm, peer); - os_free(peer); peer = tmp; } } diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index ba2a8c8..b17fc88 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -162,7 +162,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, } if (pmkid && sm->cur_pmksa && - os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { + os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) { wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN); wpa_sm_set_pmk_from_pmksa(sm); wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache", @@ -379,7 +379,8 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, - u16 ver) + u16 ver, const u8 *key_data, + size_t key_data_len) { struct wpa_eapol_ie_parse ie; struct wpa_ptk *ptk; @@ -401,10 +402,9 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { /* RSN: msg 1/4 should contain PMKID for the selected PMK */ - const u8 *_buf = (const u8 *) (key + 1); - size_t len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len); - if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0) + wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", + key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) goto failed; if (ie.pmkid) { wpa_hexdump(MSG_DEBUG, "RSN: PMKID from " @@ -906,7 +906,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm, return -1; } - if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) { + if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) + { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: PMKR1Name mismatch in " "FT 4-way handshake message 3/4"); @@ -1068,10 +1069,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, const struct wpa_eapol_key *key, - u16 ver) + u16 ver, const u8 *key_data, + size_t key_data_len) { - u16 key_info, keylen, len; - const u8 *pos; + u16 key_info, keylen; struct wpa_eapol_ie_parse ie; wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE); @@ -1080,10 +1081,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, key_info = WPA_GET_BE16(key->key_info); - pos = (const u8 *) (key + 1); - len = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len); - if (wpa_supplicant_parse_ies(pos, len, &ie) < 0) + wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len); + if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0) goto failed; if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, @@ -1238,21 +1237,14 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm, static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, const struct wpa_eapol_key *key, - size_t keydatalen, int key_info, - size_t extra_len, u16 ver, - struct wpa_gtk_data *gd) + const u8 *key_data, + size_t key_data_len, u16 key_info, + u16 ver, struct wpa_gtk_data *gd) { size_t maxkeylen; gd->gtk_len = WPA_GET_BE16(key->key_length); - maxkeylen = keydatalen; - if (keydatalen > extra_len) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, - "WPA: Truncated EAPOL-Key packet: " - "key_data_length=%lu > extra_len=%lu", - (unsigned long) keydatalen, (unsigned long) extra_len); - return -1; - } + maxkeylen = key_data_len; if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { if (maxkeylen < 8) { wpa_msg(sm->ctx->msg_ctx, MSG_INFO, @@ -1272,16 +1264,16 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, WPA_KEY_INFO_KEY_INDEX_SHIFT; if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { u8 ek[32]; - if (keydatalen > sizeof(gd->gtk)) { + if (key_data_len > sizeof(gd->gtk)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: RC4 key data too long (%lu)", - (unsigned long) keydatalen); + (unsigned long) key_data_len); return -1; } os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); - os_memcpy(gd->gtk, key + 1, keydatalen); - if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) { + os_memcpy(gd->gtk, key_data, key_data_len); + if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) { os_memset(ek, 0, sizeof(ek)); wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, "WPA: RC4 failed"); @@ -1289,22 +1281,22 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, } os_memset(ek, 0, sizeof(ek)); } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) { - if (keydatalen % 8) { + if (maxkeylen % 8) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Unsupported AES-WRAP len %lu", - (unsigned long) keydatalen); + (unsigned long) maxkeylen); return -1; } if (maxkeylen > sizeof(gd->gtk)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: AES-WRAP key data " "too long (keydatalen=%lu maxkeylen=%lu)", - (unsigned long) keydatalen, + (unsigned long) key_data_len, (unsigned long) maxkeylen); return -1; } - if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, - (const u8 *) (key + 1), gd->gtk)) { + if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data, + gd->gtk)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: AES unwrap failed - could not decrypt " "GTK"); @@ -1360,9 +1352,10 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, const unsigned char *src_addr, const struct wpa_eapol_key *key, - int extra_len, u16 ver) + const u8 *key_data, + size_t key_data_len, u16 ver) { - u16 key_info, keydatalen; + u16 key_info; int rekey, ret; struct wpa_gtk_data gd; @@ -1373,17 +1366,15 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm, "Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver); key_info = WPA_GET_BE16(key->key_info); - keydatalen = WPA_GET_BE16(key->key_data_length); if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) { - ret = wpa_supplicant_process_1_of_2_rsn(sm, - (const u8 *) (key + 1), - keydatalen, key_info, + ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data, + key_data_len, key_info, &gd); } else { - ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen, - key_info, extra_len, - ver, &gd); + ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data, + key_data_len, + key_info, ver, &gd); } wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE); @@ -1429,7 +1420,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, os_memset(key->key_mic, 0, 16); wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len, key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { + if (os_memcmp_const(mic, key->key_mic, 16) != 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Invalid EAPOL-Key MIC " "when using TPTK - ignoring TPTK"); @@ -1446,7 +1437,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, os_memset(key->key_mic, 0, 16); wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len, key->key_mic); - if (os_memcmp(mic, key->key_mic, 16) != 0) { + if (os_memcmp_const(mic, key->key_mic, 16) != 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Invalid EAPOL-Key MIC - " "dropping packet"); @@ -1471,12 +1462,11 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, /* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, - struct wpa_eapol_key *key, u16 ver) + struct wpa_eapol_key *key, u16 ver, + u8 *key_data, size_t *key_data_len) { - u16 keydatalen = WPA_GET_BE16(key->key_data_length); - wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data", - (u8 *) (key + 1), keydatalen); + key_data, *key_data_len); if (!sm->ptk_set) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: PTK not available, cannot decrypt EAPOL-Key Key " @@ -1490,7 +1480,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, u8 ek[32]; os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->ptk.kek, 16); - if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) { + if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) { os_memset(ek, 0, sizeof(ek)); wpa_msg(sm->ctx->msg_ctx, MSG_ERROR, "WPA: RC4 failed"); @@ -1501,37 +1491,37 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, ver == WPA_KEY_INFO_TYPE_AES_128_CMAC || sm->key_mgmt == WPA_KEY_MGMT_OSEN) { u8 *buf; - if (keydatalen % 8) { + if (*key_data_len < 8 || *key_data_len % 8) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, - "WPA: Unsupported AES-WRAP len %d", - keydatalen); + "WPA: Unsupported AES-WRAP len %u", + (unsigned int) *key_data_len); return -1; } - keydatalen -= 8; /* AES-WRAP adds 8 bytes */ - buf = os_malloc(keydatalen); + *key_data_len -= 8; /* AES-WRAP adds 8 bytes */ + buf = os_malloc(*key_data_len); if (buf == NULL) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No memory for AES-UNWRAP buffer"); return -1; } - if (aes_unwrap(sm->ptk.kek, keydatalen / 8, - (u8 *) (key + 1), buf)) { + if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8, + key_data, buf)) { os_free(buf); wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: AES unwrap failed - " "could not decrypt EAPOL-Key key data"); return -1; } - os_memcpy(key + 1, buf, keydatalen); + os_memcpy(key_data, buf, *key_data_len); os_free(buf); - WPA_PUT_BE16(key->key_data_length, keydatalen); + WPA_PUT_BE16(key->key_data_length, *key_data_len); } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Unsupported key_info type %d", ver); return -1; } wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data", - (u8 *) (key + 1), keydatalen); + key_data, *key_data_len); return 0; } @@ -1605,13 +1595,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm, int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, const u8 *buf, size_t len) { - size_t plen, data_len, extra_len; - struct ieee802_1x_hdr *hdr; + size_t plen, data_len, key_data_len; + const struct ieee802_1x_hdr *hdr; struct wpa_eapol_key *key; u16 key_info, ver; - u8 *tmp; + u8 *tmp = NULL; int ret = -1; struct wpa_peerkey *peerkey = NULL; + u8 *key_data; #ifdef CONFIG_IEEE80211R sm->ft_completed = 0; @@ -1626,13 +1617,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, return 0; } - tmp = os_malloc(len); - if (tmp == NULL) - return -1; - os_memcpy(tmp, buf, len); - - hdr = (struct ieee802_1x_hdr *) tmp; - key = (struct wpa_eapol_key *) (hdr + 1); + hdr = (const struct ieee802_1x_hdr *) buf; plen = be_to_host16(hdr->length); data_len = plen + sizeof(*hdr); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, @@ -1649,6 +1634,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, ret = 0; goto out; } + wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len); if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) { wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: EAPOL frame payload size %lu " @@ -1657,6 +1643,22 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, ret = 0; goto out; } + if (data_len < len) { + wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, + "WPA: ignoring %lu bytes after the IEEE 802.1X data", + (unsigned long) len - data_len); + } + + /* + * Make a copy of the frame since we need to modify the buffer during + * MAC validation and Key Data decryption. + */ + tmp = os_malloc(data_len); + if (tmp == NULL) + goto out; + os_memcpy(tmp, buf, data_len); + key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr)); + key_data = (u8 *) (key + 1); if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN) { @@ -1668,13 +1670,16 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, } wpa_eapol_key_dump(sm, key); - eapol_sm_notify_lower_layer_success(sm->eapol, 0); - wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len); - if (data_len < len) { - wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, - "WPA: ignoring %lu bytes after the IEEE 802.1X data", - (unsigned long) len - data_len); + key_data_len = WPA_GET_BE16(key->key_data_length); + if (key_data_len > plen - sizeof(struct wpa_eapol_key)) { + wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " + "frame - key_data overflow (%u > %u)", + (unsigned int) key_data_len, + (unsigned int) (plen - sizeof(struct wpa_eapol_key))); + goto out; } + + eapol_sm_notify_lower_layer_success(sm->eapol, 0); key_info = WPA_GET_BE16(key->key_info); ver = key_info & WPA_KEY_INFO_TYPE_MASK; if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && @@ -1814,22 +1819,11 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, goto out; #endif /* CONFIG_PEERKEY */ - extra_len = data_len - sizeof(*hdr) - sizeof(*key); - - if (WPA_GET_BE16(key->key_data_length) > extra_len) { - wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key " - "frame - key_data overflow (%d > %lu)", - WPA_GET_BE16(key->key_data_length), - (unsigned long) extra_len); - goto out; - } - extra_len = WPA_GET_BE16(key->key_data_length); - if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) && (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) { - if (wpa_supplicant_decrypt_key_data(sm, key, ver)) + if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data, + &key_data_len)) goto out; - extra_len = WPA_GET_BE16(key->key_data_length); } if (key_info & WPA_KEY_INFO_KEY_TYPE) { @@ -1841,24 +1835,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, } if (peerkey) { /* PeerKey 4-Way Handshake */ - peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver); + peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver, + key_data, key_data_len); } else if (key_info & WPA_KEY_INFO_MIC) { /* 3/4 4-Way Handshake */ - wpa_supplicant_process_3_of_4(sm, key, ver); + wpa_supplicant_process_3_of_4(sm, key, ver, key_data, + key_data_len); } else { /* 1/4 4-Way Handshake */ wpa_supplicant_process_1_of_4(sm, src_addr, key, - ver); + ver, key_data, + key_data_len); } } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) { /* PeerKey SMK Handshake */ - peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info, + peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info, ver); } else { if (key_info & WPA_KEY_INFO_MIC) { /* 1/2 Group Key Handshake */ wpa_supplicant_process_1_of_2(sm, src_addr, key, - extra_len, ver); + key_data, key_data_len, + ver); } else { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: EAPOL-Key (Group) without Mic bit - " diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h index e98967c..63032b0 100644 --- a/src/rsn_supp/wpa.h +++ b/src/rsn_supp/wpa.h @@ -55,14 +55,14 @@ struct wpa_sm_ctx { int (*send_tdls_mgmt)(void *ctx, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - const u8 *buf, size_t len); + int initiator, const u8 *buf, size_t len); int (*tdls_oper)(void *ctx, int oper, const u8 *peer); int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add, u16 aid, u16 capability, const u8 *supp_rates, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, + u8 qosinfo, int wmm, const u8 *ext_capab, size_t ext_capab_len, const u8 *supp_channels, size_t supp_channels_len, const u8 *supp_oper_classes, @@ -385,7 +385,7 @@ int wpa_tdls_init(struct wpa_sm *sm); void wpa_tdls_teardown_peers(struct wpa_sm *sm); void wpa_tdls_deinit(struct wpa_sm *sm); void wpa_tdls_enable(struct wpa_sm *sm, int enabled); -void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr); +void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr); const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr); int wpa_tdls_is_external_setup(struct wpa_sm *sm); diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c index c8d8cfc..3b3c9d0 100644 --- a/src/rsn_supp/wpa_ft.c +++ b/src/rsn_supp/wpa_ft.c @@ -442,7 +442,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, } if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { + os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) + { wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " "the current R0KH-ID"); wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", @@ -458,7 +459,8 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, } if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) { + os_memcmp_const(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) + { wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in " "RSNIE"); return -1; @@ -564,7 +566,7 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, return -1; } gtk_len = gtk_elem_len - 19; - if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) { + if (aes_unwrap(sm->ptk.kek, 16, gtk_len / 8, gtk_elem + 11, gtk)) { wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " "decrypt GTK"); return -1; @@ -643,7 +645,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, return -1; } - if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { + if (aes_unwrap(sm->ptk.kek, 16, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) + { wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " "decrypt IGTK"); return -1; @@ -727,7 +730,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, } if (parse.r0kh_id_len != sm->r0kh_id_len || - os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) { + os_memcmp_const(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) + { wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with " "the current R0KH-ID"); wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE", @@ -742,14 +746,15 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; } - if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { + if (os_memcmp_const(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in " "ReassocResp"); return -1; } if (parse.rsn_pmkid == NULL || - os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) { + os_memcmp_const(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) + { wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in " "RSNIE (pmkid=%d)", !!parse.rsn_pmkid); return -1; @@ -775,7 +780,7 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, return -1; } - if (os_memcmp(mic, ftie->mic, 16) != 0) { + if (os_memcmp_const(mic, ftie->mic, 16) != 0) { wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE"); wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16); wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16); diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h index e20e9da..839b545 100644 --- a/src/rsn_supp/wpa_i.h +++ b/src/rsn_supp/wpa_i.h @@ -268,12 +268,14 @@ static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm, static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst, u8 action_code, u8 dialog_token, u16 status_code, u32 peer_capab, - const u8 *buf, size_t len) + int initiator, const u8 *buf, + size_t len) { if (sm->ctx->send_tdls_mgmt) return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code, dialog_token, status_code, - peer_capab, buf, len); + peer_capab, initiator, buf, + len); return -1; } @@ -291,16 +293,16 @@ wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add, size_t supp_rates_len, const struct ieee80211_ht_capabilities *ht_capab, const struct ieee80211_vht_capabilities *vht_capab, - u8 qosinfo, const u8 *ext_capab, size_t ext_capab_len, - const u8 *supp_channels, size_t supp_channels_len, - const u8 *supp_oper_classes, + u8 qosinfo, int wmm, const u8 *ext_capab, + size_t ext_capab_len, const u8 *supp_channels, + size_t supp_channels_len, const u8 *supp_oper_classes, size_t supp_oper_classes_len) { if (sm->ctx->tdls_peer_addset) return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add, aid, capability, supp_rates, supp_rates_len, ht_capab, - vht_capab, qosinfo, + vht_capab, qosinfo, wmm, ext_capab, ext_capab_len, supp_channels, supp_channels_len, diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 2329033..93e8cf6 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -549,7 +549,7 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ie->ht_capabilities_len = pos[1]; } else if (*pos == WLAN_EID_VHT_AID) { if (pos[1] >= 2) - ie->aid = WPA_GET_LE16(pos + 2); + ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff; } else if (*pos == WLAN_EID_VHT_CAP) { ie->vht_capabilities = pos + 2; ie->vht_capabilities_len = pos[1]; diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c index 381b7a0..141ac50 100644 --- a/src/tls/pkcs1.c +++ b/src/tls/pkcs1.c @@ -298,7 +298,7 @@ int pkcs1_v15_sig_ver(struct crypto_public_key *pk, hdr.payload, hdr.length); if (hdr.length != hash_len || - os_memcmp(hdr.payload, hash, hdr.length) != 0) { + os_memcmp_const(hdr.payload, hash, hdr.length) != 0) { wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash"); os_free(decrypted); return -1; diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index f78921d..4f08e0f 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -962,7 +962,7 @@ static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct, wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)", verify_data, TLS_VERIFY_DATA_LEN); - if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { + if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data"); tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECRYPT_ERROR); diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c index 8a4645b..ced28cf 100644 --- a/src/tls/tlsv1_common.c +++ b/src/tls/tlsv1_common.c @@ -481,7 +481,8 @@ int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk, } #endif /* CONFIG_TLSV12 */ - if (buflen != data_len || os_memcmp(decrypted, data, data_len) != 0) { + if (buflen != data_len || + os_memcmp_const(decrypted, data, data_len) != 0) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash"); os_free(buf); *alert = TLS_ALERT_DECRYPT_ERROR; diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c index 3bec3be..0c6897a 100644 --- a/src/tls/tlsv1_record.c +++ b/src/tls/tlsv1_record.c @@ -456,7 +456,7 @@ int tlsv1_record_receive(struct tlsv1_record_layer *rl, return -1; } if (hlen != rl->hash_size || - os_memcmp(hash, out_data + plen, hlen) != 0 || + os_memcmp_const(hash, out_data + plen, hlen) != 0 || force_mac_error) { wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in " "received message (force_mac_error=%d)", diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index c34545e..728e137 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -1135,7 +1135,7 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)", verify_data, TLS_VERIFY_DATA_LEN); - if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { + if (os_memcmp_const(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) { tlsv1_server_log(conn, "Mismatch in verify_data"); return -1; } diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 751a268..e1e4df8 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -1776,7 +1776,7 @@ skip_digest_oid: } if (hdr.length != hash_len || - os_memcmp(hdr.payload, hash, hdr.length) != 0) { + os_memcmp_const(hdr.payload, hash, hdr.length) != 0) { wpa_printf(MSG_INFO, "X509: Certificate Digest does not match " "with calculated tbsCertificate hash"); os_free(data); diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c index a066392..d5ff5b5 100644 --- a/src/utils/browser-android.c +++ b/src/utils/browser-android.c @@ -75,7 +75,7 @@ int hs20_web_browser(const char *url) os_memset(&data, 0, sizeof(data)); ret = os_snprintf(cmd, sizeof(cmd), - "am start -a android.intent.action.VIEW -d '%s' " + "start -a android.intent.action.VIEW -d %s " "-n com.android.browser/.BrowserActivity", url); if (ret < 0 || (size_t) ret >= sizeof(cmd)) { wpa_printf(MSG_ERROR, "Too long URL"); @@ -94,7 +94,7 @@ int hs20_web_browser(const char *url) return -1; } - if (system(cmd) != 0) { + if (os_exec("/system/bin/am", cmd, 1) != 0) { wpa_printf(MSG_INFO, "Failed to launch Android browser"); eloop_cancel_timeout(browser_timeout, NULL, NULL); http_server_deinit(http); @@ -109,7 +109,7 @@ int hs20_web_browser(const char *url) eloop_destroy(); wpa_printf(MSG_INFO, "Closing Android browser"); - if (system("input keyevent 3") != 0) { + if (os_exec("/system/bin/input", "keyevent 3", 1) != 0) { wpa_printf(MSG_INFO, "Failed to inject keyevent"); } diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c index 2884d34..a080e2c 100644 --- a/src/utils/browser-system.c +++ b/src/utils/browser-system.c @@ -92,7 +92,7 @@ int hs20_web_browser(const char *url) return -1; } - if (system(cmd) != 0) { + if (os_exec("/usr/bin/x-www-browser", url, 0) != 0) { wpa_printf(MSG_INFO, "Failed to launch browser"); eloop_cancel_timeout(browser_timeout, NULL, NULL); http_server_deinit(http); diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c index eeb8f65..ce3054b 100644 --- a/src/utils/browser-wpadebug.c +++ b/src/utils/browser-wpadebug.c @@ -76,7 +76,7 @@ int hs20_web_browser(const char *url) os_memset(&data, 0, sizeof(data)); ret = os_snprintf(cmd, sizeof(cmd), - "am start -a android.action.MAIN " + "start -a android.action.MAIN " "-c android.intent.category.LAUNCHER " "-n w1.fi.wpadebug/.WpaWebViewActivity " "-e w1.fi.wpadebug.URL '%s'", url); @@ -97,7 +97,7 @@ int hs20_web_browser(const char *url) return -1; } - if (system(cmd) != 0) { + if (os_exec("/system/bin/am", cmd, 1) != 0) { wpa_printf(MSG_INFO, "Failed to launch wpadebug browser"); eloop_cancel_timeout(browser_timeout, NULL, NULL); http_server_deinit(http); @@ -112,10 +112,11 @@ int hs20_web_browser(const char *url) eloop_destroy(); wpa_printf(MSG_INFO, "Closing Android browser"); - if (system("am start -a android.action.MAIN " - "-c android.intent.category.LAUNCHER " - "-n w1.fi.wpadebug/.WpaWebViewActivity " - "-e w1.fi.wpadebug.URL FINISH") != 0) { + if (os_exec("/system/bin/am", + "start -a android.action.MAIN " + "-c android.intent.category.LAUNCHER " + "-n w1.fi.wpadebug/.WpaWebViewActivity " + "-e w1.fi.wpadebug.URL FINISH", 1) != 0) { wpa_printf(MSG_INFO, "Failed to close wpadebug browser"); } diff --git a/src/utils/common.c b/src/utils/common.c index 7dc4797..9902004 100644 --- a/src/utils/common.c +++ b/src/utils/common.c @@ -362,7 +362,7 @@ void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len) *txt++ = '\\'; *txt++ = '\\'; break; - case '\e': + case '\033': *txt++ = '\\'; *txt++ = 'e'; break; @@ -427,7 +427,7 @@ size_t printf_decode(u8 *buf, size_t maxlen, const char *str) pos++; break; case 'e': - buf[len++] = '\e'; + buf[len++] = '\033'; pos++; break; case 'x': @@ -827,3 +827,42 @@ void int_array_add_unique(int **res, int a) *res = n; } + + +void str_clear_free(char *str) +{ + if (str) { + size_t len = os_strlen(str); + os_memset(str, 0, len); + os_free(str); + } +} + + +void bin_clear_free(void *bin, size_t len) +{ + if (bin) { + os_memset(bin, 0, len); + os_free(bin); + } +} + + +int random_mac_addr(u8 *addr) +{ + if (os_get_random(addr, ETH_ALEN) < 0) + return -1; + addr[0] &= 0xfe; /* unicast */ + addr[0] |= 0x02; /* locally administered */ + return 0; +} + + +int random_mac_addr_keep_oui(u8 *addr) +{ + if (os_get_random(addr + 3, 3) < 0) + return -1; + addr[0] &= 0xfe; /* unicast */ + addr[0] |= 0x02; /* locally administered */ + return 0; +} diff --git a/src/utils/common.h b/src/utils/common.h index a85cc15..14d9ad1 100644 --- a/src/utils/common.h +++ b/src/utils/common.h @@ -535,6 +535,13 @@ void int_array_add_unique(int **res, int a); #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) +void str_clear_free(char *str); +void bin_clear_free(void *bin, size_t len); + +int random_mac_addr(u8 *addr); +int random_mac_addr_keep_oui(u8 *addr); + + /* * gcc 4.4 ends up generating strict-aliasing warnings about some very common * networking socket uses that do not really result in a real problem and diff --git a/src/utils/ext_password_test.c b/src/utils/ext_password_test.c index 3801bb8..b3a4552 100644 --- a/src/utils/ext_password_test.c +++ b/src/utils/ext_password_test.c @@ -36,7 +36,7 @@ static void ext_password_test_deinit(void *ctx) { struct ext_password_test_data *data = ctx; - os_free(data->params); + str_clear_free(data->params); os_free(data); } diff --git a/src/utils/http_curl.c b/src/utils/http_curl.c index 07d9af0..0c18269 100644 --- a/src/utils/http_curl.c +++ b/src/utils/http_curl.c @@ -1099,7 +1099,6 @@ static int ocsp_resp_cb(SSL *s, void *arg) certs = NULL; } if (ctx->peer_issuer_issuer) { - X509 *cert; cert = X509_dup(ctx->peer_issuer_issuer); if (cert && !sk_X509_push(certs, cert)) { tls_show_errors( @@ -1178,9 +1177,10 @@ static int ocsp_resp_cb(SSL *s, void *arg) if (status == V_OCSP_CERTSTATUS_GOOD) return 1; - if (status == V_OCSP_CERTSTATUS_REVOKED) + if (status == V_OCSP_CERTSTATUS_REVOKED) { ctx->last_err = "Server certificate has been revoked"; return 0; + } if (ctx->ocsp == MANDATORY_OCSP) { wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); ctx->last_err = "OCSP status unknown"; @@ -1368,8 +1368,8 @@ int soap_reinit_client(struct http_ctx *ctx) client_cert, client_key); os_free(address); os_free(ca_fname); - os_free(username); - os_free(password); + str_clear_free(username); + str_clear_free(password); os_free(client_cert); os_free(client_key); return ret; @@ -1487,8 +1487,8 @@ void http_deinit_ctx(struct http_ctx *ctx) os_free(ctx->svc_address); os_free(ctx->svc_ca_fname); - os_free(ctx->svc_username); - os_free(ctx->svc_password); + str_clear_free(ctx->svc_username); + str_clear_free(ctx->svc_password); os_free(ctx->svc_client_cert); os_free(ctx->svc_client_key); diff --git a/src/utils/os.h b/src/utils/os.h index f019e26..b9247d8 100644 --- a/src/utils/os.h +++ b/src/utils/os.h @@ -584,6 +584,32 @@ static inline void os_remove_in_array(void *ptr, size_t nmemb, size_t size, */ size_t os_strlcpy(char *dest, const char *src, size_t siz); +/** + * os_memcmp_const - Constant time memory comparison + * @a: First buffer to compare + * @b: Second buffer to compare + * @len: Number of octets to compare + * Returns: 0 if buffers are equal, non-zero if not + * + * This function is meant for comparing passwords or hash values where + * difference in execution time could provide external observer information + * about the location of the difference in the memory buffers. The return value + * does not behave like os_memcmp(), i.e., os_memcmp_const() cannot be used to + * sort items into a defined order. Unlike os_memcmp(), execution time of + * os_memcmp_const() does not depend on the contents of the compared memory + * buffers, but only on the total compared length. + */ +int os_memcmp_const(const void *a, const void *b, size_t len); + +/** + * os_exec - Execute an external program + * @program: Path to the program + * @arg: Command line argument string + * @wait_completion: Whether to wait until the program execution completes + * Returns: 0 on success, -1 on error + */ +int os_exec(const char *program, const char *arg, int wait_completion); + #ifdef OS_REJECT_C_LIB_FUNCTIONS #define malloc OS_DO_NOT_USE_malloc diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c index 2cb0d12..90b6688 100644 --- a/src/utils/os_internal.c +++ b/src/utils/os_internal.c @@ -463,6 +463,20 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz) } +int os_memcmp_const(const void *a, const void *b, size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + size_t i; + u8 res; + + for (res = 0, i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return res; +} + + char * os_strstr(const char *haystack, const char *needle) { size_t len = os_strlen(needle); diff --git a/src/utils/os_none.c b/src/utils/os_none.c index 228c472..2649111 100644 --- a/src/utils/os_none.c +++ b/src/utils/os_none.c @@ -218,6 +218,11 @@ size_t os_strlcpy(char *dest, const char *src, size_t size) } +int os_memcmp_const(const void *a, const void *b, size_t len) +{ + return 0; +} + char * os_strstr(const char *haystack, const char *needle) { return NULL; diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c index 008ec6b..523a4d0 100644 --- a/src/utils/os_unix.c +++ b/src/utils/os_unix.c @@ -9,10 +9,11 @@ #include "includes.h" #include <time.h> +#include <sys/wait.h> #ifdef ANDROID #include <sys/capability.h> -#include <linux/prctl.h> +#include <sys/prctl.h> #include <private/android_filesystem_config.h> #endif /* ANDROID */ @@ -450,6 +451,20 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz) } +int os_memcmp_const(const void *a, const void *b, size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + size_t i; + u8 res; + + for (res = 0, i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return res; +} + + #ifdef WPA_TRACE void * os_malloc(size_t size) @@ -540,3 +555,57 @@ char * os_strdup(const char *s) } #endif /* WPA_TRACE */ + + +int os_exec(const char *program, const char *arg, int wait_completion) +{ + pid_t pid; + int pid_status; + + pid = fork(); + if (pid < 0) { + perror("fork"); + return -1; + } + + if (pid == 0) { + /* run the external command in the child process */ + const int MAX_ARG = 30; + char *_program, *_arg, *pos; + char *argv[MAX_ARG + 1]; + int i; + + _program = os_strdup(program); + _arg = os_strdup(arg); + + argv[0] = _program; + + i = 1; + pos = _arg; + while (i < MAX_ARG && pos && *pos) { + while (*pos == ' ') + pos++; + if (*pos == '\0') + break; + argv[i++] = pos; + pos = os_strchr(pos, ' '); + if (pos) + *pos++ = '\0'; + } + argv[i] = NULL; + + execv(program, argv); + perror("execv"); + os_free(_program); + os_free(_arg); + exit(0); + return -1; + } + + if (wait_completion) { + /* wait for the child process to complete in the parent */ + waitpid(pid, &pid_status, 0); + } + + return 0; +} diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c index 1cfa7a5..57ee132 100644 --- a/src/utils/os_win32.c +++ b/src/utils/os_win32.c @@ -244,3 +244,23 @@ size_t os_strlcpy(char *dest, const char *src, size_t siz) return s - src - 1; } + + +int os_memcmp_const(const void *a, const void *b, size_t len) +{ + const u8 *aa = a; + const u8 *bb = b; + size_t i; + u8 res; + + for (res = 0, i = 0; i < len; i++) + res |= aa[i] ^ bb[i]; + + return res; +} + + +int os_exec(const char *program, const char *arg, int wait_completion) +{ + return -1; +} diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c index ec06556..d955dc4 100644 --- a/src/utils/pcsc_funcs.c +++ b/src/utils/pcsc_funcs.c @@ -1406,6 +1406,12 @@ int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand, pos += IK_LEN; wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN); + if (end > pos) { + wpa_hexdump(MSG_DEBUG, + "SCARD: Ignore extra data in end", + pos, end - pos); + } + return 0; } diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c index 647f6b4..68cbace 100644 --- a/src/utils/wpa_debug.c +++ b/src/utils/wpa_debug.c @@ -685,6 +685,34 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...) } +void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) +{ + va_list ap; + char *buf; + int buflen; + int len; + + if (!wpa_msg_cb) + return; + + va_start(ap, fmt); + buflen = vsnprintf(NULL, 0, fmt, ap) + 1; + va_end(ap); + + buf = os_malloc(buflen); + if (buf == NULL) { + wpa_printf(MSG_ERROR, + "wpa_msg_global_ctrl: Failed to allocate message buffer"); + return; + } + va_start(ap, fmt); + len = vsnprintf(buf, buflen, fmt, ap); + va_end(ap); + wpa_msg_cb(ctx, level, 1, buf, len); + os_free(buf); +} + + void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) { va_list ap; diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h index 50e8ae9..391f197 100644 --- a/src/utils/wpa_debug.h +++ b/src/utils/wpa_debug.h @@ -160,6 +160,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, #define wpa_msg(args...) do { } while (0) #define wpa_msg_ctrl(args...) do { } while (0) #define wpa_msg_global(args...) do { } while (0) +#define wpa_msg_global_ctrl(args...) do { } while (0) #define wpa_msg_no_global(args...) do { } while (0) #define wpa_msg_register_cb(f) do { } while (0) #define wpa_msg_register_ifname_cb(f) do { } while (0) @@ -212,6 +213,21 @@ void wpa_msg_global(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); /** + * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg_global(), but it sends the output only to the + * attached global ctrl_iface monitors. In other words, it can be used for + * frequent events that do not need to be sent to syslog. + */ +void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + +/** * wpa_msg_no_global - Conditional printf for ctrl_iface monitors * @ctx: Pointer to context data; this is the ctx variable registered * with struct wpa_driver_ops::init() diff --git a/src/wps/httpread.c b/src/wps/httpread.c index 6d2d11c..2f08f37 100644 --- a/src/wps/httpread.c +++ b/src/wps/httpread.c @@ -413,8 +413,8 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx) */ if (httpread_debug >= 10) wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h); - h->got_body = 1; - goto got_file; + h->got_body = 1; + goto got_file; } rbp = readbuf; diff --git a/src/wps/wps.c b/src/wps/wps.c index 648cfd1..b0f6887 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -89,7 +89,7 @@ struct wps_data * wps_init(const struct wps_config *cfg) if (cfg->pbc) { /* Use special PIN '00000000' for PBC */ data->dev_pw_id = DEV_PW_PUSHBUTTON; - os_free(data->dev_password); + bin_clear_free(data->dev_password, data->dev_password_len); data->dev_password = (u8 *) os_strdup("00000000"); if (data->dev_password == NULL) { os_free(data); @@ -122,7 +122,8 @@ struct wps_data * wps_init(const struct wps_config *cfg) data->new_ap_settings = os_malloc(sizeof(*data->new_ap_settings)); if (data->new_ap_settings == NULL) { - os_free(data->dev_password); + bin_clear_free(data->dev_password, + data->dev_password_len); os_free(data); return NULL; } @@ -173,11 +174,11 @@ void wps_deinit(struct wps_data *data) wpabuf_free(data->dh_pubkey_e); wpabuf_free(data->dh_pubkey_r); wpabuf_free(data->last_msg); - os_free(data->dev_password); - os_free(data->alt_dev_password); - os_free(data->new_psk); + bin_clear_free(data->dev_password, data->dev_password_len); + bin_clear_free(data->alt_dev_password, data->alt_dev_password_len); + bin_clear_free(data->new_psk, data->new_psk_len); wps_device_data_free(&data->peer_dev); - os_free(data->new_ap_settings); + bin_clear_free(data->new_ap_settings, sizeof(*data->new_ap_settings)); dh5_free(data->dh_ctx); os_free(data); } diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c index 5266620..eadb22f 100644 --- a/src/wps/wps_attr_process.c +++ b/src/wps/wps_attr_process.c @@ -41,7 +41,7 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator, len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN; hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash); - if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { + if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator"); return -1; } @@ -71,7 +71,7 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg, } hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash); - if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { + if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: Invalid KWA"); return -1; } diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index d072582..9f5a90c 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -175,6 +175,12 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps) } wps_derive_psk(wps, wps->dev_password, wps->dev_password_len); + if (wps->wps->ap && random_pool_ready() != 1) { + wpa_printf(MSG_INFO, + "WPS: Not enough entropy in random pool to proceed - do not allow AP PIN to be used"); + return NULL; + } + msg = wpabuf_alloc(1000); if (msg == NULL) return NULL; @@ -268,8 +274,12 @@ static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg) char hex[65]; u8 psk[32]; /* Generate a random per-device PSK */ - if (random_get_bytes(psk, sizeof(psk)) < 0) + if (random_pool_ready() != 1 || + random_get_bytes(psk, sizeof(psk)) < 0) { + wpa_printf(MSG_INFO, + "WPS: Could not generate random PSK"); return -1; + } wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", psk, sizeof(psk)); wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", @@ -525,8 +535,8 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk, if (wps->peer_pubkey_hash_set) { u8 hash[WPS_HASH_LEN]; sha256_vector(1, &pk, &pk_len, hash); - if (os_memcmp(hash, wps->peer_pubkey_hash, - WPS_OOB_PUBKEY_HASH_LEN) != 0) { + if (os_memcmp_const(hash, wps->peer_pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN) != 0) { wpa_printf(MSG_ERROR, "WPS: Public Key hash mismatch"); wpa_hexdump(MSG_DEBUG, "WPS: Received public key", pk, pk_len); @@ -605,7 +615,7 @@ static int wps_process_r_snonce1(struct wps_data *wps, const u8 *r_snonce1) len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); - if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { + if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does " "not match with the pre-committed value"); wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; @@ -645,7 +655,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2) len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); - if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { + if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does " "not match with the pre-committed value"); wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; @@ -892,7 +902,7 @@ static int wps_process_dev_pw_id(struct wps_data *wps, const u8 *dev_pw_id) if (wps->alt_dev_password && wps->alt_dev_pw_id == id) { wpa_printf(MSG_DEBUG, "WPS: Found a matching Device Password"); - os_free(wps->dev_password); + bin_clear_free(wps->dev_password, wps->dev_password_len); wps->dev_pw_id = wps->alt_dev_pw_id; wps->dev_password = wps->alt_dev_password; wps->dev_password_len = wps->alt_dev_password_len; diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 8b2675e..078ff72 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -579,12 +579,15 @@ static void wps_er_parse_device_description(struct wps_er_ap *ap, wpa_printf(MSG_DEBUG, "WPS ER: serialNumber='%s'", ap->serial_number); ap->udn = xml_get_first_item(data, "UDN"); - wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn); - pos = os_strstr(ap->udn, "uuid:"); - if (pos) { - pos += 5; - if (uuid_str2bin(pos, ap->uuid) < 0) - wpa_printf(MSG_DEBUG, "WPS ER: Invalid UUID in UDN"); + if (ap->udn) { + wpa_printf(MSG_DEBUG, "WPS ER: UDN='%s'", ap->udn); + pos = os_strstr(ap->udn, "uuid:"); + if (pos) { + pos += 5; + if (uuid_str2bin(pos, ap->uuid) < 0) + wpa_printf(MSG_DEBUG, + "WPS ER: Invalid UUID in UDN"); + } } ap->upc = xml_get_first_item(data, "UPC"); diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index b917e6b..b90cc25 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -42,7 +42,7 @@ struct wps_nfc_pw_token { static void wps_remove_nfc_pw_token(struct wps_nfc_pw_token *token) { dl_list_del(&token->list); - os_free(token); + bin_clear_free(token, sizeof(*token)); } @@ -91,7 +91,7 @@ struct wps_uuid_pin { static void wps_free_pin(struct wps_uuid_pin *pin) { - os_free(pin->pin); + bin_clear_free(pin->pin, pin->pin_len); os_free(pin); } @@ -826,7 +826,7 @@ static int wps_registrar_invalidate_wildcard_pin(struct wps_registrar *reg, { if (dev_pw && pin->pin && (dev_pw_len != pin->pin_len || - os_memcmp(dev_pw, pin->pin, dev_pw_len) != 0)) + os_memcmp_const(dev_pw, pin->pin, dev_pw_len) != 0)) continue; /* different PIN */ if (pin->wildcard_uuid) { wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID", @@ -1343,7 +1343,7 @@ static int wps_get_dev_password(struct wps_data *wps) const u8 *pin; size_t pin_len = 0; - os_free(wps->dev_password); + bin_clear_free(wps->dev_password, wps->dev_password_len); wps->dev_password = NULL; if (wps->pbc) { @@ -1640,8 +1640,12 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) !wps->wps->registrar->disable_auto_conf) { u8 r[16]; /* Generate a random passphrase */ - if (random_get_bytes(r, sizeof(r)) < 0) + if (random_pool_ready() != 1 || + random_get_bytes(r, sizeof(r)) < 0) { + wpa_printf(MSG_INFO, + "WPS: Could not generate random PSK"); return -1; + } os_free(wps->new_psk); wps->new_psk = base64_encode(r, sizeof(r), &wps->new_psk_len); if (wps->new_psk == NULL) @@ -1674,7 +1678,10 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wps->new_psk = os_malloc(wps->new_psk_len); if (wps->new_psk == NULL) return -1; - if (random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) { + if (random_pool_ready() != 1 || + random_get_bytes(wps->new_psk, wps->new_psk_len) < 0) { + wpa_printf(MSG_INFO, + "WPS: Could not generate random PSK"); os_free(wps->new_psk); wps->new_psk = NULL; return -1; @@ -2211,7 +2218,7 @@ static int wps_process_e_snonce1(struct wps_data *wps, const u8 *e_snonce1) len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); - if (os_memcmp(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { + if (os_memcmp_const(wps->peer_hash1, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash1 derived from E-S1 does " "not match with the pre-committed value"); wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE; @@ -2251,7 +2258,7 @@ static int wps_process_e_snonce2(struct wps_data *wps, const u8 *e_snonce2) len[3] = wpabuf_len(wps->dh_pubkey_r); hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 4, addr, len, hash); - if (os_memcmp(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { + if (os_memcmp_const(wps->peer_hash2, hash, WPS_HASH_LEN) != 0) { wpa_printf(MSG_DEBUG, "WPS: E-Hash2 derived from E-S2 does " "not match with the pre-committed value"); wps_registrar_invalidate_pin(wps->wps->registrar, wps->uuid_e); @@ -2591,8 +2598,9 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps, addr[0] = attr->public_key; sha256_vector(1, addr, &attr->public_key_len, hash); - if (os_memcmp(hash, wps->nfc_pw_token->pubkey_hash, - WPS_OOB_PUBKEY_HASH_LEN) != 0) { + if (os_memcmp_const(hash, + wps->nfc_pw_token->pubkey_hash, + WPS_OOB_PUBKEY_HASH_LEN) != 0) { wpa_printf(MSG_ERROR, "WPS: Public Key hash " "mismatch"); wps->state = SEND_M2D; diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index 6fb3d4c..ae94a9f 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -227,6 +227,8 @@ void format_date(struct wpabuf *buf) t = time(NULL); date = gmtime(&t); + if (date == NULL) + return; wpabuf_printf(buf, "%s, %02d %s %d %02d:%02d:%02d GMT", &weekday_str[date->tm_wday * 4], date->tm_mday, &month_str[date->tm_mon * 4], date->tm_year + 1900, @@ -594,7 +596,10 @@ static struct wpabuf * build_fake_wsc_ack(void) wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); - wps_build_wfa_ext(msg, 0, NULL, 0); + if (wps_build_wfa_ext(msg, 0, NULL, 0)) { + wpabuf_free(msg); + return NULL; + } return msg; } |