diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2014-03-17 10:57:26 -0700 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2014-03-17 10:59:23 -0700 |
| commit | b36ed7cd946148d829f311de8fe53ea3ffaaffe3 (patch) | |
| tree | 86c726cbf3ef9770d402395e6630dcb227009304 /src | |
| parent | d5dc24eb5fbf0e0feff214c0260cae845721d5fe (diff) | |
| download | android_external_wpa_supplicant_8-b36ed7cd946148d829f311de8fe53ea3ffaaffe3.tar.gz android_external_wpa_supplicant_8-b36ed7cd946148d829f311de8fe53ea3ffaaffe3.tar.bz2 android_external_wpa_supplicant_8-b36ed7cd946148d829f311de8fe53ea3ffaaffe3.zip | |
Cumulative patch from commit f4e3860f8a770a0db3816196c77baf894c7ccc1e
f4e3860 Fix AP mode default TXOP Limit values for AC_VI and AC_VO
47bd94a TLS testing: Add new test cases for RSA-DHE primes
f5bbb2f TLS client: Reject RSA-DHE prime if it shorter than 768 bits
817742f TLS testing: Fix test_flags check for ApplData report
1120e45 Allow config blobs to be set through ctrl_iface
c3722e1 ACS: Fix VHT20
49b7443 Fix HT40 co-ex scan for some pri/sec channel switches
5bdac4a Remove unused STA entry information
c9d9ee9 Fix hostapd_add_iface error path to deinit partially initialized BSS
6829da3 Fix external radio_work deinit path
8dd9f9c Allow management group cipher to be configured
67d39cf P2P: Do not create another group interface on NFC Token enable
6aa1cd4 wpa_supplicant: Apply VHT_OVERRIDES to wpas_start_assoc_cb()
db63757 hostapd: Supply default parameters for OBSS scan
6e9375e TDLS: Add get_capability tdls command
67e1a40 hostapd: For VHT 20/40, allow center segment 0 to be zero
d0bf06f GAS server: Remove incomplete remote ANQP processing
fdb4535 WPS: Extend per-station PSK to support ER case as well
9a1a538 wpa_supplicant AP: Allow PMF to be enabled with ieee80211w
ce6b9cd Allow reason code to be specified for DEAUTH/DISASSOC test frame
dda8be7 TDLS: Use QoS info from WMM IE obtained in TDLS frames
daa70bd Fix CONFIG_NO_SCAN_PROCESSING=y build
3a8ec73 P2P: Report dev_found event (if not yet done) from GO Neg Req RX
0f23a5e Mark AP disabled if initialization steps fail
Change-Id: I7e499241552147c734fec9b77351b47ffd6e3a7c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src')
38 files changed, 555 insertions, 320 deletions
diff --git a/src/ap/acs.c b/src/ap/acs.c index 3e0155c7..2491b78f 100644 --- a/src/ap/acs.c +++ b/src/ap/acs.c @@ -639,23 +639,26 @@ acs_find_ideal_chan(struct hostapd_iface *iface) static void acs_adjust_vht_center_freq(struct hostapd_iface *iface) { + int offset; + wpa_printf(MSG_DEBUG, "ACS: Adjusting VHT center frequency"); switch (iface->conf->vht_oper_chwidth) { case VHT_CHANWIDTH_USE_HT: - iface->conf->vht_oper_centr_freq_seg0_idx = - iface->conf->channel + 2; + offset = 2 * iface->conf->secondary_channel; break; case VHT_CHANWIDTH_80MHZ: - iface->conf->vht_oper_centr_freq_seg0_idx = - iface->conf->channel + 6; + offset = 6; break; default: /* TODO: How can this be calculated? Adjust * acs_find_ideal_chan() */ wpa_printf(MSG_INFO, "ACS: Only VHT20/40/80 is supported now"); - break; + return; } + + iface->conf->vht_oper_centr_freq_seg0_idx = + iface->conf->channel + offset; } diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 3ca85a0f..14d9ae9d 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -73,6 +73,7 @@ void hostapd_config_defaults_bss(struct hostapd_bss_config *bss) #ifdef CONFIG_IEEE80211W bss->assoc_sa_query_max_timeout = 1000; bss->assoc_sa_query_retry_timeout = 201; + bss->group_mgmt_cipher = WPA_CIPHER_AES_128_CMAC; #endif /* CONFIG_IEEE80211W */ #ifdef EAP_SERVER_FAST /* both anonymous and authenticated provisioning */ @@ -106,9 +107,9 @@ struct hostapd_config * hostapd_config_defaults(void) const struct hostapd_wmm_ac_params ac_be = { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ - { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; + { aCWmin - 1, aCWmin, 2, 3008 / 32, 0 }; const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ - { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; + { aCWmin - 2, aCWmin - 1, 2, 1504 / 32, 0 }; const struct hostapd_tx_queue_params txq_bk = { 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 }; const struct hostapd_tx_queue_params txq_be = diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index aa3a51ae..25eb4903 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -254,6 +254,7 @@ struct hostapd_bss_config { int wpa_key_mgmt; #ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; + int group_mgmt_cipher; /* dot11AssociationSAQueryMaximumTimeout (in TUs) */ unsigned int assoc_sa_query_max_timeout; /* dot11AssociationSAQueryRetryTimeout (in TUs) */ diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 5ba48c9d..83cfd0f4 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -503,7 +503,8 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode, case VHT_CHANWIDTH_USE_HT: if (center_segment1) return -1; - if (5000 + center_segment0 * 5 != data->center_freq1 && + if (center_segment0 != 0 && + 5000 + center_segment0 * 5 != data->center_freq1 && 2407 + center_segment0 * 5 != data->center_freq1) return -1; break; diff --git a/src/ap/ap_mlme.c b/src/ap/ap_mlme.c index a7129f14..13604edc 100644 --- a/src/ap/ap_mlme.c +++ b/src/ap/ap_mlme.c @@ -120,8 +120,6 @@ void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta) * reassociation procedure that was initiated by that specific peer MAC entity. * * PeerSTAAddress = sta->addr - * - * sta->previous_ap contains the "Current AP" information from ReassocReq. */ void mlme_reassociate_indication(struct hostapd_data *hapd, struct sta_info *sta) diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index c27cf3b9..11351c4b 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -281,6 +281,10 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, if (hwaddr_aton(txtaddr, addr)) return -1; + pos = os_strstr(txtaddr, " reason="); + if (pos) + reason = atoi(pos + 8); + pos = os_strstr(txtaddr, " test="); if (pos) { struct ieee80211_mgmt mgmt; @@ -295,8 +299,7 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, 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); - mgmt.u.deauth.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); + mgmt.u.deauth.reason_code = host_to_le16(reason); if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth), @@ -313,10 +316,6 @@ int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd, } #endif /* CONFIG_P2P_MANAGER */ - pos = os_strstr(txtaddr, " reason="); - if (pos) - reason = atoi(pos + 8); - hostapd_drv_sta_deauth(hapd, addr, reason); sta = ap_get_sta(hapd, addr); if (sta) @@ -342,6 +341,10 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, if (hwaddr_aton(txtaddr, addr)) return -1; + pos = os_strstr(txtaddr, " reason="); + if (pos) + reason = atoi(pos + 8); + pos = os_strstr(txtaddr, " test="); if (pos) { struct ieee80211_mgmt mgmt; @@ -356,8 +359,7 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, 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); - mgmt.u.disassoc.reason_code = - host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID); + mgmt.u.disassoc.reason_code = host_to_le16(reason); if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt, IEEE80211_HDRLEN + sizeof(mgmt.u.deauth), @@ -374,10 +376,6 @@ int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd, } #endif /* CONFIG_P2P_MANAGER */ - pos = os_strstr(txtaddr, " reason="); - if (pos) - reason = atoi(pos + 8); - hostapd_drv_sta_disassoc(hapd, addr, reason); sta = ap_get_sta(hapd, addr); if (sta) diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c index fd1041ea..49f6e87b 100644 --- a/src/ap/gas_serv.c +++ b/src/ap/gas_serv.c @@ -71,7 +71,6 @@ gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token) continue; dia = &sta->gas_dialog[i]; dia->valid = 1; - dia->index = i; dia->dialog_token = dialog_token; sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i; return dia; @@ -744,40 +743,21 @@ gas_serv_build_gas_resp_payload(struct hostapd_data *hapd, } -static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx) -{ - struct gas_dialog_info *dia = eloop_data; - - wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for " - "dialog token %d", dia->dialog_token); - - gas_serv_dialog_clear(dia); -} - - struct anqp_query_info { unsigned int request; - unsigned int remote_request; const u8 *home_realm_query; size_t home_realm_query_len; const u8 *icon_name; size_t icon_name_len; - u16 remote_delay; }; static void set_anqp_req(unsigned int bit, const char *name, int local, - unsigned int remote, u16 remote_delay, struct anqp_query_info *qi) { qi->request |= bit; if (local) { wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name); - } else if (bit & remote) { - wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name); - qi->remote_request |= bit; - if (remote_delay > qi->remote_delay) - qi->remote_delay = remote_delay; } else { wpa_printf(MSG_DEBUG, "ANQP: %s not available", name); } @@ -789,43 +769,38 @@ static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id, { switch (info_id) { case ANQP_CAPABILITY_LIST: - set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0, - 0, qi); + set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, + qi); break; case ANQP_VENUE_NAME: set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name", - hapd->conf->venue_name != NULL, 0, 0, qi); + hapd->conf->venue_name != NULL, qi); break; case ANQP_NETWORK_AUTH_TYPE: set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type", - hapd->conf->network_auth_type != NULL, - 0, 0, qi); + hapd->conf->network_auth_type != NULL, qi); break; case ANQP_ROAMING_CONSORTIUM: set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium", - hapd->conf->roaming_consortium != NULL, 0, 0, qi); + hapd->conf->roaming_consortium != NULL, qi); break; case ANQP_IP_ADDR_TYPE_AVAILABILITY: set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY, "IP Addr Type Availability", - hapd->conf->ipaddr_type_configured, - 0, 0, qi); + hapd->conf->ipaddr_type_configured, qi); break; case ANQP_NAI_REALM: set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm", - hapd->conf->nai_realm_data != NULL, - 0, 0, qi); + hapd->conf->nai_realm_data != NULL, qi); break; case ANQP_3GPP_CELLULAR_NETWORK: set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK, "3GPP Cellular Network", - hapd->conf->anqp_3gpp_cell_net != NULL, - 0, 0, qi); + hapd->conf->anqp_3gpp_cell_net != NULL, qi); break; case ANQP_DOMAIN_NAME: set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name", - hapd->conf->domain_name != NULL, - 0, 0, qi); + hapd->conf->domain_name != NULL, qi); break; default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u", @@ -857,33 +832,30 @@ static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype, switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List", - 1, 0, 0, qi); + 1, qi); break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME, "Operator Friendly Name", - hapd->conf->hs20_oper_friendly_name != NULL, - 0, 0, qi); + hapd->conf->hs20_oper_friendly_name != NULL, qi); break; case HS20_STYPE_WAN_METRICS: set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics", - hapd->conf->hs20_wan_metrics != NULL, - 0, 0, qi); + hapd->conf->hs20_wan_metrics != NULL, qi); break; case HS20_STYPE_CONNECTION_CAPABILITY: set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY, "Connection Capability", hapd->conf->hs20_connection_capability != NULL, - 0, 0, qi); + qi); break; case HS20_STYPE_OPERATING_CLASS: set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class", - hapd->conf->hs20_operating_class != NULL, - 0, 0, qi); + hapd->conf->hs20_operating_class != NULL, qi); break; case HS20_STYPE_OSU_PROVIDERS_LIST: set_anqp_req(ANQP_REQ_OSU_PROVIDERS_LIST, "OSU Providers list", - hapd->conf->hs20_osu_providers_count, 0, 0, qi); + hapd->conf->hs20_osu_providers_count, qi); break; default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u", @@ -1150,97 +1122,6 @@ static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, } -void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, - struct gas_dialog_info *dialog) -{ - struct wpabuf *buf, *tx_buf; - u8 dialog_token = dialog->dialog_token; - size_t frag_len; - - if (dialog->sd_resp == NULL) { - buf = gas_serv_build_gas_resp_payload(hapd, - dialog->all_requested, - dialog, NULL, 0, NULL, 0); - wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", - buf); - if (!buf) - goto tx_gas_response_done; - dialog->sd_resp = buf; - dialog->sd_resp_pos = 0; - } - frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; - if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay || - hapd->conf->gas_comeback_delay) { - u16 comeback_delay_tus = dialog->comeback_delay + - GAS_SERV_COMEBACK_DELAY_FUDGE; - u32 comeback_delay_secs, comeback_delay_usecs; - - if (hapd->conf->gas_comeback_delay) { - /* Testing - allow overriding of the delay value */ - comeback_delay_tus = hapd->conf->gas_comeback_delay; - } - - wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit " - "%u) and comeback delay %u, " - "requesting comebacks", (unsigned int) frag_len, - (unsigned int) hapd->gas_frag_limit, - dialog->comeback_delay); - tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, - WLAN_STATUS_SUCCESS, - comeback_delay_tus, - NULL); - if (tx_buf) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, - "GAS: Tx GAS Initial Resp (comeback = 10TU)"); - if (dialog->prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, - dst, - wpabuf_head(tx_buf), - wpabuf_len(tx_buf)); - } - wpabuf_free(tx_buf); - - /* start a timer of 1.5 * comeback-delay */ - comeback_delay_tus = comeback_delay_tus + - (comeback_delay_tus / 2); - comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000; - comeback_delay_usecs = (comeback_delay_tus * 1024) - - (comeback_delay_secs * 1000000); - eloop_register_timeout(comeback_delay_secs, - comeback_delay_usecs, - gas_serv_clear_cached_ies, dialog, - NULL); - goto tx_gas_response_done; - } - - buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) + - dialog->sd_resp_pos, frag_len); - if (buf == NULL) { - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation " - "failed"); - goto tx_gas_response_done; - } - tx_buf = gas_anqp_build_initial_resp_buf(dialog_token, - WLAN_STATUS_SUCCESS, 0, buf); - wpabuf_free(buf); - if (tx_buf == NULL) - goto tx_gas_response_done; - wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial " - "Response (frag_id %d frag_len %d)", - dialog->sd_frag_id, (int) frag_len); - dialog->sd_frag_id++; - - if (dialog->prot) - convert_to_protected_dual(tx_buf); - hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst, - wpabuf_head(tx_buf), wpabuf_len(tx_buf)); - wpabuf_free(tx_buf); -tx_gas_response_done: - gas_serv_clear_cached_ies(dialog, NULL); -} - - static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, const u8 *sa, const u8 *data, size_t len, int prot) @@ -1274,33 +1155,6 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, goto send_resp; } - if (dialog->sd_resp == NULL) { - wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x", - dialog->requested, dialog->received); - if ((dialog->requested & dialog->received) != - dialog->requested) { - wpa_printf(MSG_DEBUG, "GAS: Did not receive response " - "from remote processing"); - gas_serv_dialog_clear(dialog); - tx_buf = gas_anqp_build_comeback_resp_buf( - dialog_token, - WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0, - NULL); - if (tx_buf == NULL) - return; - goto send_resp; - } - - buf = gas_serv_build_gas_resp_payload(hapd, - dialog->all_requested, - dialog, NULL, 0, NULL, 0); - wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses", - buf); - if (!buf) - goto rx_gas_comeback_req_done; - dialog->sd_resp = buf; - dialog->sd_resp_pos = 0; - } frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos; if (frag_len > hapd->gas_frag_limit) { frag_len = hapd->gas_frag_limit; @@ -1313,15 +1167,18 @@ static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd, if (buf == NULL) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate " "buffer"); - goto rx_gas_comeback_req_done; + gas_serv_dialog_clear(dialog); + return; } tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token, WLAN_STATUS_SUCCESS, dialog->sd_frag_id, more, 0, buf); wpabuf_free(buf); - if (tx_buf == NULL) - goto rx_gas_comeback_req_done; + if (tx_buf == NULL) { + gas_serv_dialog_clear(dialog); + return; + } wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response " "(frag_id %d more=%d frag_len=%d)", dialog->sd_frag_id, more, (int) frag_len); @@ -1346,10 +1203,6 @@ send_resp: hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, wpabuf_head(tx_buf), wpabuf_len(tx_buf)); wpabuf_free(tx_buf); - return; - -rx_gas_comeback_req_done: - gas_serv_clear_cached_ies(dialog, NULL); } diff --git a/src/ap/gas_serv.h b/src/ap/gas_serv.h index 7e392b36..4ec32019 100644 --- a/src/ap/gas_serv.h +++ b/src/ap/gas_serv.h @@ -42,29 +42,17 @@ #define ANQP_REQ_ICON_REQUEST \ (0x10000 << HS20_STYPE_ICON_REQUEST) -/* To account for latencies between hostapd and external ANQP processor */ -#define GAS_SERV_COMEBACK_DELAY_FUDGE 10 -#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */ - struct gas_dialog_info { u8 valid; - u8 index; struct wpabuf *sd_resp; /* Fragmented response */ u8 dialog_token; size_t sd_resp_pos; /* Offset in sd_resp */ u8 sd_frag_id; - u16 comeback_delay; int prot; /* whether Protected Dual of Public Action frame is used */ - - unsigned int requested; - unsigned int received; - unsigned int all_requested; }; struct hostapd_data; -void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst, - struct gas_dialog_info *dialog); struct gas_dialog_info * gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token); diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index bc5bb6cf..4ed718cf 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1093,7 +1093,7 @@ static int setup_interface2(struct hostapd_iface *iface) if (ret < 0) { wpa_printf(MSG_ERROR, "Could not select hw_mode and " "channel. (%d)", ret); - return -1; + goto fail; } if (ret == 1) { wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)"); @@ -1101,7 +1101,7 @@ static int setup_interface2(struct hostapd_iface *iface) } ret = hostapd_check_ht_capab(iface); if (ret < 0) - return -1; + goto fail; if (ret == 1) { wpa_printf(MSG_DEBUG, "Interface initialization will " "be completed in a callback"); @@ -1112,6 +1112,13 @@ static int setup_interface2(struct hostapd_iface *iface) wpa_printf(MSG_DEBUG, "DFS support is enabled"); } return hostapd_setup_interface_complete(iface, 0); + +fail: + hostapd_set_state(iface, HAPD_IFACE_DISABLED); + wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); + if (iface->interfaces && iface->interfaces->terminate_on_error) + eloop_terminate(); + return -1; } @@ -1129,13 +1136,8 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) size_t j; u8 *prev_addr; - if (err) { - wpa_printf(MSG_ERROR, "Interface initialization failed"); - hostapd_set_state(iface, HAPD_IFACE_DISABLED); - if (iface->interfaces && iface->interfaces->terminate_on_error) - eloop_terminate(); - return -1; - } + if (err) + goto fail; wpa_printf(MSG_DEBUG, "Completing interface initialization"); if (iface->conf->channel) { @@ -1152,8 +1154,11 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) #ifdef NEED_AP_MLME /* Check DFS */ res = hostapd_handle_dfs(iface); - if (res <= 0) + if (res <= 0) { + if (res < 0) + goto fail; return res; + } #endif /* NEED_AP_MLME */ if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, @@ -1166,7 +1171,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) hapd->iconf->vht_oper_centr_freq_seg1_idx)) { wpa_printf(MSG_ERROR, "Could not set channel for " "kernel driver"); - return -1; + goto fail; } } @@ -1177,7 +1182,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, HOSTAPD_LEVEL_WARNING, "Failed to prepare rates table."); - return -1; + goto fail; } } @@ -1185,14 +1190,14 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) { wpa_printf(MSG_ERROR, "Could not set RTS threshold for " "kernel driver"); - return -1; + goto fail; } if (hapd->iconf->fragm_threshold > -1 && hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) { wpa_printf(MSG_ERROR, "Could not set fragmentation threshold " "for kernel driver"); - return -1; + goto fail; } prev_addr = hapd->own_addr; @@ -1202,7 +1207,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) if (j) os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN); if (hostapd_setup_bss(hapd, j == 0)) - return -1; + goto fail; if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) prev_addr = hapd->own_addr; } @@ -1217,7 +1222,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) if (hostapd_driver_commit(hapd) < 0) { wpa_printf(MSG_ERROR, "%s: Failed to commit driver " "configuration", __func__); - return -1; + goto fail; } /* @@ -1228,7 +1233,7 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) */ for (j = 0; j < iface->num_bss; j++) { if (hostapd_init_wps_complete(iface->bss[j])) - return -1; + goto fail; } hostapd_set_state(iface, HAPD_IFACE_ENABLED); @@ -1242,6 +1247,14 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) iface->interfaces->terminate_on_error--; return 0; + +fail: + wpa_printf(MSG_ERROR, "Interface initialization failed"); + hostapd_set_state(iface, HAPD_IFACE_DISABLED); + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED); + if (iface->interfaces && iface->interfaces->terminate_on_error) + eloop_terminate(); + return -1; } @@ -1824,6 +1837,7 @@ int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf) if (start_ctrl_iface_bss(hapd) < 0 || (hapd_iface->state == HAPD_IFACE_ENABLED && hostapd_setup_bss(hapd, -1))) { + hostapd_cleanup(hapd); hapd_iface->bss[hapd_iface->num_bss - 1] = NULL; hapd_iface->conf->num_bss--; hapd_iface->num_bss--; diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c index 28e92fd8..d319ce00 100644 --- a/src/ap/hw_features.c +++ b/src/ap/hw_features.c @@ -327,7 +327,7 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, int match; pri_chan = iface->conf->channel; - sec_chan = iface->conf->secondary_channel * 4; + sec_chan = pri_chan + iface->conf->secondary_channel * 4; pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan); if (iface->conf->secondary_channel > 0) sec_freq = pri_freq + 20; @@ -351,6 +351,7 @@ static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface, "channel to get secondary channel with no Beacons " "from other BSSes"); ieee80211n_switch_pri_sec(iface); + return 1; } /* diff --git a/src/ap/iapp.c b/src/ap/iapp.c index bad080f0..9b2900f2 100644 --- a/src/ap/iapp.c +++ b/src/ap/iapp.c @@ -242,29 +242,22 @@ static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr) */ void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta) { - struct ieee80211_mgmt *assoc; - u16 seq; + u16 seq = 0; /* TODO */ if (iapp == NULL) return; - assoc = sta->last_assoc_req; - seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0; - /* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */ hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP, HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq); iapp_send_layer2_update(iapp, sta->addr); iapp_send_add(iapp, sta->addr, seq); - if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) == - WLAN_FC_STYPE_REASSOC_REQ) { - /* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP, - * Context Block, Timeout) - */ - /* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to - * IP address */ - } + /* TODO: If this was reassociation: + * IAPP-MOVE.request(MAC Address, Sequence Number, Old AP, + * Context Block, Timeout) + * TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to + * IP address */ } diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index c97cef13..14fb5675 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -1445,17 +1445,6 @@ static void handle_assoc(struct hostapd_data *hapd, } #endif /* CONFIG_IEEE80211W */ - if (reassoc) { - os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap, - ETH_ALEN); - } - - if (sta->last_assoc_req) - os_free(sta->last_assoc_req); - sta->last_assoc_req = os_malloc(len); - if (sta->last_assoc_req) - os_memcpy(sta->last_assoc_req, mgmt, len); - /* Make sure that the previously registered inactivity timer will not * remove the STA immediately. */ sta->timeout_next = STA_NULLFUNC; @@ -1924,7 +1913,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, status = le_to_host16(mgmt->u.assoc_resp.status_code); if (status != WLAN_STATUS_SUCCESS) - goto fail; + return; /* Stop previous accounting session, if one is started, and allocate * new session id for the new session. */ @@ -1986,7 +1975,7 @@ static void handle_assoc_cb(struct hostapd_data *hapd, ap_sta_disconnect(hapd, sta, sta->addr, WLAN_REASON_DISASSOC_AP_BUSY); - goto fail; + return; } if (sta->flags & WLAN_STA_WDS) { @@ -2006,11 +1995,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd, * interface selection is not going to change anymore. */ if (ap_sta_bind_vlan(hapd, sta, 0) < 0) - goto fail; + return; } else if (sta->vlan_id) { /* VLAN ID already set (e.g., by PMKSA caching), so bind STA */ if (ap_sta_bind_vlan(hapd, sta, 0) < 0) - goto fail; + return; } hostapd_set_sta_flags(hapd, sta); @@ -2022,13 +2011,6 @@ static void handle_assoc_cb(struct hostapd_data *hapd, hapd->new_assoc_sta_cb(hapd, sta, !new_assoc); ieee802_1x_notify_port_enabled(sta->eapol_sm, 1); - - fail: - /* Copy of the association request is not needed anymore */ - if (sta->last_assoc_req) { - os_free(sta->last_assoc_req); - sta->last_assoc_req = NULL; - } } diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c index a1661783..138d0497 100644 --- a/src/ap/ieee802_11_ht.c +++ b/src/ap/ieee802_11_ht.c @@ -54,7 +54,20 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid) scan_params->width_trigger_scan_interval = host_to_le16(hapd->iconf->obss_interval); - /* TODO: Fill in more parameters (supplicant ignores them) */ + /* Fill in default values for remaining parameters + * (IEEE Std 802.11-2012, 8.4.2.61 and MIB defval) */ + scan_params->scan_passive_dwell = + host_to_le16(20); + scan_params->scan_active_dwell = + host_to_le16(10); + scan_params->scan_passive_total_per_channel = + host_to_le16(200); + scan_params->scan_active_total_per_channel = + host_to_le16(20); + scan_params->channel_transition_delay_factor = + host_to_le16(5); + scan_params->scan_activity_threshold = + host_to_le16(25); pos += sizeof(*scan_params); } diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c index b78fd010..12403f99 100644 --- a/src/ap/ieee802_11_shared.c +++ b/src/ap/ieee802_11_shared.c @@ -170,6 +170,8 @@ static void hostapd_ext_capab_byte(struct hostapd_data *hapd, u8 *pos, int idx) switch (idx) { case 0: /* Bits 0-7 */ + if (hapd->iconf->obss_interval) + *pos |= 0x01; /* Bit 0 - Coexistence management */ break; case 1: /* Bits 8-15 */ break; @@ -223,6 +225,8 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid) len = 4; if (len < 3 && hapd->conf->wnm_sleep_mode) len = 3; + if (len < 1 && hapd->iconf->obss_interval) + len = 1; if (len < 7 && hapd->conf->ssid.utf8_ssid) len = 7; #ifdef CONFIG_WNM diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index c7d051be..f5417de0 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -239,7 +239,6 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta) radius_client_flush_auth(hapd->radius, sta->addr); #endif /* CONFIG_NO_RADIUS */ - os_free(sta->last_assoc_req); os_free(sta->challenge); #ifdef CONFIG_IEEE80211W diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index c0bab6f2..2dbdeb18 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -61,7 +61,6 @@ struct sta_info { unsigned int hs20_deauth_requested:1; u16 auth_alg; - u8 previous_ap[6]; enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE, @@ -74,9 +73,6 @@ struct sta_info { /* IEEE 802.1X related data */ struct eapol_state_machine *eapol_sm; - /* IEEE 802.11f (IAPP) related data */ - struct ieee80211_mgmt *last_assoc_req; - u32 acct_session_id_hi; u32 acct_session_id_lo; struct os_reltime acct_session_start; diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c index 7d89edf4..4d19bb03 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -1918,7 +1918,9 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2) static int ieee80211w_kde_len(struct wpa_state_machine *sm) { if (sm->mgmt_frame_prot) { - return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde); + size_t len; + len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); + return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len; } return 0; @@ -1930,6 +1932,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) struct wpa_igtk_kde igtk; struct wpa_group *gsm = sm->group; u8 rsc[WPA_KEY_RSC_LEN]; + size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); if (!sm->mgmt_frame_prot) return pos; @@ -1941,17 +1944,18 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos) os_memset(igtk.pn, 0, sizeof(igtk.pn)); else os_memcpy(igtk.pn, rsc, sizeof(igtk.pn)); - os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], len); if (sm->wpa_auth->conf.disable_gtk) { /* * Provide unique random IGTK to each STA to prevent use of * IGTK in the BSS. */ - if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0) + if (random_get_bytes(igtk.igtk, len) < 0) return pos; } pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK, - (const u8 *) &igtk, sizeof(igtk), NULL, 0); + (const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len, + NULL, 0); return pos; } @@ -2457,15 +2461,16 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth, #ifdef CONFIG_IEEE80211W if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + size_t len; + len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN); inc_byte_array(group->Counter, WPA_NONCE_LEN); if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion", wpa_auth->addr, group->GNonce, - group->IGTK[group->GN_igtk - 4], - WPA_IGTK_LEN) < 0) + group->IGTK[group->GN_igtk - 4], len) < 0) ret = -1; wpa_hexdump_key(MSG_DEBUG, "IGTK", - group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN); + group->IGTK[group->GN_igtk - 4], len); } #endif /* CONFIG_IEEE80211W */ @@ -2582,26 +2587,27 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) { struct wpa_group *gsm = sm->group; u8 *start = pos; + size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher); /* * IGTK subelement: * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16] */ *pos++ = WNM_SLEEP_SUBELEM_IGTK; - *pos++ = 2 + 6 + WPA_IGTK_LEN; + *pos++ = 2 + 6 + len; WPA_PUT_LE16(pos, gsm->GN_igtk); pos += 2; if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0) return 0; pos += 6; - os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); - pos += WPA_IGTK_LEN; + os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], len); + pos += len; wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit", gsm->GN_igtk); wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit", - gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); + gsm->IGTK[gsm->GN_igtk - 4], len); return pos - start; } @@ -2656,12 +2662,19 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth, ret = -1; #ifdef CONFIG_IEEE80211W - if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION && - wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK, - broadcast_ether_addr, group->GN_igtk, - group->IGTK[group->GN_igtk - 4], - WPA_IGTK_LEN) < 0) - ret = -1; + if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) { + enum wpa_alg alg; + size_t len; + + alg = wpa_cipher_to_alg(wpa_auth->conf.group_mgmt_cipher); + len = wpa_cipher_key_len(wpa_auth->conf.group_mgmt_cipher); + + if (ret == 0 && + wpa_auth_set_key(wpa_auth, group->vlan_id, alg, + broadcast_ether_addr, group->GN_igtk, + group->IGTK[group->GN_igtk - 4], len) < 0) + ret = -1; + } #endif /* CONFIG_IEEE80211W */ return ret; diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h index d99db691..3ab3e3d5 100644 --- a/src/ap/wpa_auth.h +++ b/src/ap/wpa_auth.h @@ -142,6 +142,7 @@ struct wpa_auth_config { int tx_status; #ifdef CONFIG_IEEE80211W enum mfp_options ieee80211w; + int group_mgmt_cipher; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R #define SSID_LEN 32 diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c index da5fea7c..6ee9a4f8 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -49,6 +49,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf, wconf->okc = conf->okc; #ifdef CONFIG_IEEE80211W wconf->ieee80211w = conf->ieee80211w; + wconf->group_mgmt_cipher = conf->group_mgmt_cipher; #endif /* CONFIG_IEEE80211W */ #ifdef CONFIG_IEEE80211R wconf->ssid_len = conf->ssid.ssid_len; diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h index fcd5878e..2e1bdcf4 100644 --- a/src/ap/wpa_auth_i.h +++ b/src/ap/wpa_auth_i.h @@ -154,7 +154,7 @@ struct wpa_group { Boolean first_sta_seen; Boolean reject_4way_hs_for_entropy; #ifdef CONFIG_IEEE80211W - u8 IGTK[2][WPA_IGTK_LEN]; + u8 IGTK[2][WPA_IGTK_MAX_LEN]; int GN_igtk, GM_igtk; #endif /* CONFIG_IEEE80211W */ }; diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index 7a497516..e957c6e9 100644 --- a/src/ap/wpa_auth_ie.c +++ b/src/ap/wpa_auth_ie.c @@ -261,7 +261,25 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, } /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + switch (conf->group_mgmt_cipher) { + case WPA_CIPHER_AES_128_CMAC: + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + break; + case WPA_CIPHER_BIP_GMAC_128: + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128); + break; + case WPA_CIPHER_BIP_GMAC_256: + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256); + break; + case WPA_CIPHER_BIP_CMAC_256: + RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256); + break; + default: + wpa_printf(MSG_DEBUG, + "Invalid group management cipher (0x%x)", + conf->group_mgmt_cipher); + return -1; + } pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ @@ -586,7 +604,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, return WPA_MGMT_FRAME_PROTECTION_VIOLATION; } - if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { + if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher) + { wpa_printf(MSG_DEBUG, "Unsupported management group " "cipher %d", data.mgmt_group_cipher); return WPA_INVALID_MGMT_GROUP_CIPHER; diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c index 27f58aa3..adb22c76 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -368,6 +368,8 @@ static int rsn_selector_to_bitfield(const u8 *s) return WPA_CIPHER_BIP_GMAC_256; if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_BIP_CMAC_256) return WPA_CIPHER_BIP_CMAC_256; + if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED) + return WPA_CIPHER_GTK_NOT_USED; return 0; } @@ -400,6 +402,26 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) } +static int wpa_cipher_valid_group(int cipher) +{ + return wpa_cipher_valid_pairwise(cipher) || + cipher == WPA_CIPHER_WEP104 || + cipher == WPA_CIPHER_WEP40 || + cipher == WPA_CIPHER_GTK_NOT_USED; +} + + +#ifdef CONFIG_IEEE80211W +int wpa_cipher_valid_mgmt_group(int cipher) +{ + return cipher == WPA_CIPHER_AES_128_CMAC || + cipher == WPA_CIPHER_BIP_GMAC_128 || + cipher == WPA_CIPHER_BIP_GMAC_256 || + cipher == WPA_CIPHER_BIP_CMAC_256; +} +#endif /* CONFIG_IEEE80211W */ + + /** * wpa_parse_wpa_ie_rsn - Parse RSN IE * @rsn_ie: Buffer containing RSN IE @@ -455,13 +477,11 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, if (left >= RSN_SELECTOR_LEN) { data->group_cipher = rsn_selector_to_bitfield(pos); -#ifdef CONFIG_IEEE80211W - if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) { - wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group " - "cipher", __func__); + if (!wpa_cipher_valid_group(data->group_cipher)) { + wpa_printf(MSG_DEBUG, "%s: invalid group cipher 0x%x", + __func__, data->group_cipher); return -1; } -#endif /* CONFIG_IEEE80211W */ pos += RSN_SELECTOR_LEN; left -= RSN_SELECTOR_LEN; } else if (left > 0) { @@ -546,7 +566,7 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len, #ifdef CONFIG_IEEE80211W if (left >= 4) { data->mgmt_group_cipher = rsn_selector_to_bitfield(pos); - if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) { + if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) { wpa_printf(MSG_DEBUG, "%s: Unsupported management " "group cipher 0x%x", __func__, data->mgmt_group_cipher); @@ -1103,9 +1123,13 @@ int wpa_cipher_key_len(int cipher) switch (cipher) { case WPA_CIPHER_CCMP_256: case WPA_CIPHER_GCMP_256: + case WPA_CIPHER_BIP_GMAC_256: + case WPA_CIPHER_BIP_CMAC_256: return 32; case WPA_CIPHER_CCMP: case WPA_CIPHER_GCMP: + case WPA_CIPHER_AES_128_CMAC: + case WPA_CIPHER_BIP_GMAC_128: return 16; case WPA_CIPHER_TKIP: return 32; @@ -1153,6 +1177,14 @@ int wpa_cipher_to_alg(int cipher) case WPA_CIPHER_WEP104: case WPA_CIPHER_WEP40: return WPA_ALG_WEP; + case WPA_CIPHER_AES_128_CMAC: + return WPA_ALG_IGTK; + case WPA_CIPHER_BIP_GMAC_128: + return WPA_ALG_BIP_GMAC_128; + case WPA_CIPHER_BIP_GMAC_256: + return WPA_ALG_BIP_GMAC_256; + case WPA_CIPHER_BIP_CMAC_256: + return WPA_ALG_BIP_CMAC_256; } return WPA_ALG_NONE; } @@ -1193,6 +1225,14 @@ u32 wpa_cipher_to_suite(int proto, int cipher) RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE); if (cipher & WPA_CIPHER_GTK_NOT_USED) return RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED; + if (cipher & WPA_CIPHER_AES_128_CMAC) + return RSN_CIPHER_SUITE_AES_128_CMAC; + if (cipher & WPA_CIPHER_BIP_GMAC_128) + return RSN_CIPHER_SUITE_BIP_GMAC_128; + if (cipher & WPA_CIPHER_BIP_GMAC_256) + return RSN_CIPHER_SUITE_BIP_GMAC_256; + if (cipher & WPA_CIPHER_BIP_CMAC_256) + return RSN_CIPHER_SUITE_BIP_CMAC_256; return 0; } diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h index 5684ef3f..c0b2caae 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -77,9 +77,7 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #endif #define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4) #define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5) -#ifdef CONFIG_IEEE80211W #define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6) -#endif /* CONFIG_IEEE80211W */ #define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7) #define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8) #define RSN_CIPHER_SUITE_GCMP_256 RSN_SELECTOR(0x00, 0x0f, 0xac, 9) @@ -130,6 +128,7 @@ RSN_SELECTOR(0x00, 0x0f, 0xac, 13) #ifdef CONFIG_IEEE80211W #define WPA_IGTK_LEN 16 +#define WPA_IGTK_MAX_LEN 32 #endif /* CONFIG_IEEE80211W */ @@ -285,10 +284,11 @@ struct rsn_error_kde { } STRUCT_PACKED; #ifdef CONFIG_IEEE80211W +#define WPA_IGTK_KDE_PREFIX_LEN (2 + 6) struct wpa_igtk_kde { u8 keyid[2]; u8 pn[6]; - u8 igtk[WPA_IGTK_LEN]; + u8 igtk[WPA_IGTK_MAX_LEN]; } STRUCT_PACKED; #endif /* CONFIG_IEEE80211W */ @@ -409,6 +409,7 @@ int wpa_cipher_key_len(int cipher); int wpa_cipher_rsc_len(int cipher); int wpa_cipher_to_alg(int cipher); int wpa_cipher_valid_pairwise(int cipher); +int wpa_cipher_valid_mgmt_group(int cipher); u32 wpa_cipher_to_suite(int proto, int cipher); int rsn_cipher_put_suites(u8 *pos, int ciphers); int wpa_cipher_put_suites(u8 *pos, int ciphers); diff --git a/src/crypto/tls.h b/src/crypto/tls.h index 81e588fb..65e0f797 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -544,6 +544,11 @@ void tls_connection_set_log_cb(struct tls_connection *conn, #define TLS_BREAK_VERIFY_DATA BIT(0) #define TLS_BREAK_SRV_KEY_X_HASH BIT(1) #define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2) +#define TLS_DHE_PRIME_511B BIT(3) +#define TLS_DHE_PRIME_767B BIT(4) +#define TLS_DHE_PRIME_15 BIT(5) +#define TLS_DHE_PRIME_58B BIT(6) +#define TLS_DHE_NON_PRIME BIT(7) void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags); diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c index 2e40db10..a32cfac6 100644 --- a/src/p2p/p2p_go_neg.c +++ b/src/p2p/p2p_go_neg.c @@ -618,7 +618,8 @@ void p2p_process_go_neg_req(struct p2p_data *p2p, const u8 *sa, if (dev == NULL) dev = p2p_add_dev_from_go_neg_req(p2p, sa, &msg); - else if (dev->flags & P2P_DEV_PROBE_REQ_ONLY) + else if ((dev->flags & P2P_DEV_PROBE_REQ_ONLY) || + !(dev->flags & P2P_DEV_REPORTED)) p2p_add_dev_info(p2p, sa, dev, &msg); else if (!dev->listen_freq && !dev->oper_freq) { /* diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c index c929fe18..f2ea3932 100644 --- a/src/radius/radius_server.c +++ b/src/radius/radius_server.c @@ -554,6 +554,26 @@ static void radius_server_testing_options_tls(struct radius_session *sess, srv_log(sess, "TLS test - break ServerKeyExchange ServerParams Signature"); eap_conf->tls_test_flags = TLS_BREAK_SRV_KEY_X_SIGNATURE; break; + case 4: + srv_log(sess, "TLS test - RSA-DHE using a short 511-bit prime"); + eap_conf->tls_test_flags = TLS_DHE_PRIME_511B; + break; + case 5: + srv_log(sess, "TLS test - RSA-DHE using a short 767-bit prime"); + eap_conf->tls_test_flags = TLS_DHE_PRIME_767B; + break; + case 6: + srv_log(sess, "TLS test - RSA-DHE using a bogus 15 \"prime\""); + eap_conf->tls_test_flags = TLS_DHE_PRIME_15; + break; + case 7: + srv_log(sess, "TLS test - RSA-DHE using a short 58-bit prime in long container"); + eap_conf->tls_test_flags = TLS_DHE_PRIME_58B; + break; + case 8: + srv_log(sess, "TLS test - RSA-DHE using a non-prime"); + eap_conf->tls_test_flags = TLS_DHE_NON_PRIME; + break; default: srv_log(sess, "Unrecognized TLS test"); break; diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c index 8a978f74..9b8ca6b8 100644 --- a/src/rsn_supp/tdls.c +++ b/src/rsn_supp/tdls.c @@ -1466,6 +1466,29 @@ static int copy_peer_ext_capab(const struct wpa_eapol_ie_parse *kde, } +static int copy_peer_wmm_capab(const struct wpa_eapol_ie_parse *kde, + struct wpa_tdls_peer *peer) +{ + struct wmm_information_element *wmm; + + if (!kde->wmm) { + wpa_printf(MSG_DEBUG, "TDLS: No supported WMM capabilities received"); + return 0; + } + + if (kde->wmm_len < sizeof(struct wmm_information_element)) { + wpa_printf(MSG_DEBUG, "TDLS: Invalid supported WMM capabilities received"); + return -1; + } + + wmm = (struct wmm_information_element *) kde->wmm; + peer->qos_info = wmm->qos_info; + + wpa_printf(MSG_DEBUG, "TDLS: Peer WMM QOS Info 0x%x", peer->qos_info); + return 0; +} + + static int copy_peer_supp_channels(const struct wpa_eapol_ie_parse *kde, struct wpa_tdls_peer *peer) { @@ -1638,6 +1661,10 @@ static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr, peer->qos_info = kde.qosinfo; + /* Overwrite with the qos_info obtained in WMM IE */ + if (copy_peer_wmm_capab(&kde, peer) < 0) + goto error; + peer->aid = kde.aid; #ifdef CONFIG_TDLS_TESTING @@ -2018,6 +2045,10 @@ static int wpa_tdls_process_tpk_m2(struct wpa_sm *sm, const u8 *src_addr, peer->qos_info = kde.qosinfo; + /* Overwrite with the qos_info obtained in WMM IE */ + if (copy_peer_wmm_capab(&kde, peer) < 0) + goto error; + peer->aid = kde.aid; if (!wpa_tdls_get_privacy(sm)) { diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index de86cdf6..77d7991f 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -742,13 +742,15 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { #ifdef CONFIG_IEEE80211W - if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) + if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher)) return 0; if (ie->igtk) { + size_t len; const struct wpa_igtk_kde *igtk; u16 keyidx; - if (ie->igtk_len != sizeof(*igtk)) + len = wpa_cipher_key_len(sm->mgmt_group_cipher); + if (ie->igtk_len != WPA_IGTK_KDE_PREFIX_LEN + len) return -1; igtk = (const struct wpa_igtk_kde *) ie->igtk; keyidx = WPA_GET_LE16(igtk->keyid); @@ -756,15 +758,16 @@ static int ieee80211w_set_keys(struct wpa_sm *sm, "pn %02x%02x%02x%02x%02x%02x", keyidx, MAC2STR(igtk->pn)); wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", - igtk->igtk, WPA_IGTK_LEN); + igtk->igtk, len); if (keyidx > 4095) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Invalid IGTK KeyID %d", keyidx); return -1; } - if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, keyidx, 0, igtk->pn, sizeof(igtk->pn), - igtk->igtk, WPA_IGTK_LEN) < 0) { + igtk->igtk, len) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to configure IGTK to the driver"); return -1; @@ -1097,7 +1100,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, goto failed; } - if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) { + if (ie.igtk && + wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher) && + ie.igtk_len != WPA_IGTK_KDE_PREFIX_LEN + + (unsigned int) wpa_cipher_key_len(sm->mgmt_group_cipher)) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Invalid IGTK KDE length %lu", (unsigned long) ie.igtk_len); @@ -2748,17 +2754,19 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) } #ifdef CONFIG_IEEE80211W } else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) { + keylen = wpa_cipher_key_len(sm->mgmt_group_cipher); os_memcpy(igd.keyid, buf + 2, 2); os_memcpy(igd.pn, buf + 4, 6); keyidx = WPA_GET_LE16(igd.keyid); - os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN); + os_memcpy(igd.igtk, buf + 10, keylen); wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", - igd.igtk, WPA_IGTK_LEN); - if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, + igd.igtk, keylen); + if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher), + broadcast_ether_addr, keyidx, 0, igd.pn, sizeof(igd.pn), - igd.igtk, WPA_IGTK_LEN) < 0) { + igd.igtk, keylen) < 0) { wpa_printf(MSG_DEBUG, "Failed to install the IGTK in " "WNM mode"); return -1; diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 610b65a8..2329033e 100644 --- a/src/rsn_supp/wpa_ie.c +++ b/src/rsn_supp/wpa_ie.c @@ -201,7 +201,7 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } #ifdef CONFIG_IEEE80211W - if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) { + if (wpa_cipher_valid_mgmt_group(mgmt_group_cipher)) { if (!sm->cur_pmksa) { /* PMKID Count */ WPA_PUT_LE16(pos, 0); @@ -209,7 +209,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } /* Management Group Cipher Suite */ - RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC); + RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, + mgmt_group_cipher)); pos += RSN_SELECTOR_LEN; } #endif /* CONFIG_IEEE80211W */ @@ -311,6 +312,42 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len) /** + * wpa_parse_vendor_specific - Parse Vendor Specific IEs + * @pos: Pointer to the IE header + * @end: Pointer to the end of the Key Data buffer + * @ie: Pointer to parsed IE data + * Returns: 0 on success, 1 if end mark is found, -1 on failure + */ +static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end, + struct wpa_eapol_ie_parse *ie) +{ + unsigned int oui; + + if (pos[1] < 4) { + wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)", + pos[1]); + return 1; + } + + oui = WPA_GET_BE24(&pos[2]); + if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) { + if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) { + ie->wmm = &pos[2]; + ie->wmm_len = pos[1]; + wpa_hexdump(MSG_DEBUG, "WPA: WMM IE", + ie->wmm, ie->wmm_len); + } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) { + ie->wmm = &pos[2]; + ie->wmm_len = pos[1]; + wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element", + ie->wmm, ie->wmm_len); + } + } + return 0; +} + + +/** * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs * @pos: Pointer to the IE header * @end: Pointer to the end of the Key Data buffer @@ -540,6 +577,14 @@ int wpa_supplicant_parse_ies(const u8 *buf, size_t len, ret = 0; break; } + + ret = wpa_parse_vendor_specific(pos, end, ie); + if (ret < 0) + break; + if (ret > 0) { + ret = 0; + break; + } } else { wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key " "Key Data IE", pos, 2 + pos[1]); diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h index 82b6fa3f..0fc42cc4 100644 --- a/src/rsn_supp/wpa_ie.h +++ b/src/rsn_supp/wpa_ie.h @@ -59,6 +59,8 @@ struct wpa_eapol_ie_parse { size_t supp_oper_classes_len; u8 qosinfo; u16 aid; + const u8 *wmm; + size_t wmm_len; #ifdef CONFIG_P2P const u8 *ip_addr_req; const u8 *ip_addr_alloc; diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 8367e361..f78921d9 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -409,12 +409,37 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct, } +static unsigned int count_bits(const u8 *val, size_t len) +{ + size_t i; + unsigned int bits; + u8 tmp; + + for (i = 0; i < len; i++) { + if (val[i]) + break; + } + if (i == len) + return 0; + + bits = (len - i - 1) * 8; + tmp = val[i]; + while (tmp) { + bits++; + tmp >>= 1; + } + + return bits; +} + + static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, const u8 *buf, size_t len, tls_key_exchange key_exchange) { const u8 *pos, *end, *server_params, *server_params_end; u8 alert; + unsigned int bits; tlsv1_client_free_dh(conn); @@ -431,6 +456,14 @@ static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn, (unsigned long) conn->dh_p_len); goto fail; } + bits = count_bits(pos, conn->dh_p_len); + if (bits < 768) { + wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)", + bits); + wpa_hexdump(MSG_DEBUG, "TLSv1: Rejected DH prime", + pos, conn->dh_p_len); + goto fail; + } conn->dh_p = os_malloc(conn->dh_p_len); if (conn->dh_p == NULL) goto fail; diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c index 4aeccf6a..23d0b815 100644 --- a/src/tls/tlsv1_server.c +++ b/src/tls/tlsv1_server.c @@ -316,7 +316,7 @@ int tlsv1_server_decrypt(struct tlsv1_server *conn, } #ifdef CONFIG_TESTING_OPTIONS - if ((conn->test_flags && + if ((conn->test_flags & (TLS_BREAK_VERIFY_DATA | TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) && !conn->test_failure_reported) { @@ -673,4 +673,110 @@ void tlsv1_server_set_test_flags(struct tlsv1_server *conn, u32 flags) { conn->test_flags = flags; } + + +static const u8 test_tls_prime15[1] = { + 15 +}; + +static const u8 test_tls_prime511b[64] = { + 0x50, 0xfb, 0xf1, 0xae, 0x01, 0xf1, 0xfe, 0xe6, + 0xe1, 0xae, 0xdc, 0x1e, 0xbe, 0xfb, 0x9e, 0x58, + 0x9a, 0xd7, 0x54, 0x9d, 0x6b, 0xb3, 0x78, 0xe2, + 0x39, 0x7f, 0x30, 0x01, 0x25, 0xa1, 0xf9, 0x7c, + 0x55, 0x0e, 0xa1, 0x15, 0xcc, 0x36, 0x34, 0xbb, + 0x6c, 0x8b, 0x64, 0x45, 0x15, 0x7f, 0xd3, 0xe7, + 0x31, 0xc8, 0x8e, 0x56, 0x8e, 0x95, 0xdc, 0xea, + 0x9e, 0xdf, 0xf7, 0x56, 0xdd, 0xb0, 0x34, 0xdb +}; + +static const u8 test_tls_prime767b[96] = { + 0x4c, 0xdc, 0xb8, 0x21, 0x20, 0x9d, 0xe8, 0xa3, + 0x53, 0xd9, 0x1c, 0x18, 0xc1, 0x3a, 0x58, 0x67, + 0xa7, 0x85, 0xf9, 0x28, 0x9b, 0xce, 0xc0, 0xd1, + 0x05, 0x84, 0x61, 0x97, 0xb2, 0x86, 0x1c, 0xd0, + 0xd1, 0x96, 0x23, 0x29, 0x8c, 0xc5, 0x30, 0x68, + 0x3e, 0xf9, 0x05, 0xba, 0x60, 0xeb, 0xdb, 0xee, + 0x2d, 0xdf, 0x84, 0x65, 0x49, 0x87, 0x90, 0x2a, + 0xc9, 0x8e, 0x34, 0x63, 0x6d, 0x9a, 0x2d, 0x32, + 0x1c, 0x46, 0xd5, 0x4e, 0x20, 0x20, 0x90, 0xac, + 0xd5, 0x48, 0x79, 0x99, 0x0c, 0xe6, 0xed, 0xbf, + 0x79, 0xc2, 0x47, 0x50, 0x95, 0x38, 0x38, 0xbc, + 0xde, 0xb0, 0xd2, 0xe8, 0x97, 0xcb, 0x22, 0xbb +}; + +static const u8 test_tls_prime58[128] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0xc1, 0xba, 0xc8, 0x25, 0xbe, 0x2d, 0xf3 +}; + +static const u8 test_tls_non_prime[] = { + /* + * This is not a prime and the value has the following factors: + * 13736783488716579923 * 16254860191773456563 * 18229434976173670763 * + * 11112313018289079419 * 10260802278580253339 * 12394009491575311499 * + * 12419059668711064739 * 14317973192687985827 * 10498605410533203179 * + * 16338688760390249003 * 11128963991123878883 * 12990532258280301419 * + * 3 + */ + 0x0C, 0x8C, 0x36, 0x9C, 0x6F, 0x71, 0x2E, 0xA7, + 0xAB, 0x32, 0xD3, 0x0F, 0x68, 0x3D, 0xB2, 0x6D, + 0x81, 0xDD, 0xC4, 0x84, 0x0D, 0x9C, 0x6E, 0x36, + 0x29, 0x70, 0xF3, 0x1E, 0x9A, 0x42, 0x0B, 0x67, + 0x82, 0x6B, 0xB1, 0xF2, 0xAF, 0x55, 0x28, 0xE7, + 0xDB, 0x67, 0x6C, 0xF7, 0x6B, 0xAC, 0xAC, 0xE5, + 0xF7, 0x9F, 0xD4, 0x63, 0x55, 0x70, 0x32, 0x7C, + 0x70, 0xFB, 0xAF, 0xB8, 0xEB, 0x37, 0xCF, 0x3F, + 0xFE, 0x94, 0x73, 0xF9, 0x7A, 0xC7, 0x12, 0x2E, + 0x9B, 0xB4, 0x7D, 0x08, 0x60, 0x83, 0x43, 0x52, + 0x83, 0x1E, 0xA5, 0xFC, 0xFA, 0x87, 0x12, 0xF4, + 0x64, 0xE2, 0xCE, 0x71, 0x17, 0x72, 0xB6, 0xAB +}; + #endif /* CONFIG_TESTING_OPTIONS */ + + +void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p, + size_t *dh_p_len) +{ + *dh_p = conn->cred->dh_p; + *dh_p_len = conn->cred->dh_p_len; + +#ifdef CONFIG_TESTING_OPTIONS + if (conn->test_flags & TLS_DHE_PRIME_511B) { + tlsv1_server_log(conn, "TESTING: Use short 511-bit prime with DHE"); + *dh_p = test_tls_prime511b; + *dh_p_len = sizeof(test_tls_prime511b); + } else if (conn->test_flags & TLS_DHE_PRIME_767B) { + tlsv1_server_log(conn, "TESTING: Use short 767-bit prime with DHE"); + *dh_p = test_tls_prime767b; + *dh_p_len = sizeof(test_tls_prime767b); + } else if (conn->test_flags & TLS_DHE_PRIME_15) { + tlsv1_server_log(conn, "TESTING: Use bogus 15 \"prime\" with DHE"); + *dh_p = test_tls_prime15; + *dh_p_len = sizeof(test_tls_prime15); + } else if (conn->test_flags & TLS_DHE_PRIME_58B) { + tlsv1_server_log(conn, "TESTING: Use short 58-bit prime in long container with DHE"); + *dh_p = test_tls_prime58; + *dh_p_len = sizeof(test_tls_prime58); + } else if (conn->test_flags & TLS_DHE_NON_PRIME) { + tlsv1_server_log(conn, "TESTING: Use claim non-prime as the DHE prime"); + *dh_p = test_tls_non_prime; + *dh_p_len = sizeof(test_tls_non_prime); + } +#endif /* CONFIG_TESTING_OPTIONS */ +} diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h index 9a36d8f0..96d79b3a 100644 --- a/src/tls/tlsv1_server_i.h +++ b/src/tls/tlsv1_server_i.h @@ -78,5 +78,7 @@ u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level, u8 description, size_t *out_len); int tlsv1_server_process_handshake(struct tlsv1_server *conn, u8 ct, const u8 *buf, size_t *len); +void tlsv1_server_get_dh_p(struct tlsv1_server *conn, const u8 **dh_p, + size_t *dh_p_len); #endif /* TLSV1_SERVER_I_H */ diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 04622b5e..c34545ed 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -31,7 +31,9 @@ static int testing_cipher_suite_filter(struct tlsv1_server *conn, u16 suite) { #ifdef CONFIG_TESTING_OPTIONS if ((conn->test_flags & - (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE)) && + (TLS_BREAK_SRV_KEY_X_HASH | TLS_BREAK_SRV_KEY_X_SIGNATURE | + TLS_DHE_PRIME_511B | TLS_DHE_PRIME_767B | TLS_DHE_PRIME_15 | + TLS_DHE_PRIME_58B | TLS_DHE_NON_PRIME)) && suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 && suite != TLS_DHE_RSA_WITH_AES_256_CBC_SHA && suite != TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 && @@ -590,6 +592,8 @@ static int tls_process_client_key_exchange_dh( u8 *shared; size_t shared_len; int res; + const u8 *dh_p; + size_t dh_p_len; /* * struct { @@ -641,7 +645,9 @@ static int tls_process_client_key_exchange_dh( return -1; } - shared_len = conn->cred->dh_p_len; + tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len); + + shared_len = dh_p_len; shared = os_malloc(shared_len); if (shared == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for " @@ -653,8 +659,7 @@ static int tls_process_client_key_exchange_dh( /* shared = Yc^secret mod p */ if (crypto_mod_exp(dh_yc, dh_yc_len, conn->dh_secret, - conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, + conn->dh_secret_len, dh_p, dh_p_len, shared, &shared_len)) { os_free(shared); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, @@ -994,6 +999,36 @@ static int tls_process_client_finished(struct tlsv1_server *conn, u8 ct, tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after invalid ServerKeyExchange"); conn->test_failure_reported = 1; } + + if ((conn->test_flags & TLS_DHE_PRIME_15) && + !conn->test_failure_reported) { + tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after bogus DHE \"prime\" 15"); + conn->test_failure_reported = 1; + } + + if ((conn->test_flags & TLS_DHE_PRIME_58B) && + !conn->test_failure_reported) { + tlsv1_server_log(conn, "TEST-FAILURE: Client Finished received after short 58-bit DHE prime in long container"); + conn->test_failure_reported = 1; + } + + if ((conn->test_flags & TLS_DHE_PRIME_511B) && + !conn->test_failure_reported) { + tlsv1_server_log(conn, "TEST-WARNING: Client Finished received after short 511-bit DHE prime (insecure)"); + conn->test_failure_reported = 1; + } + + if ((conn->test_flags & TLS_DHE_PRIME_767B) && + !conn->test_failure_reported) { + tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after 767-bit DHE prime (relatively insecure)"); + conn->test_failure_reported = 1; + } + + if ((conn->test_flags & TLS_DHE_NON_PRIME) && + !conn->test_failure_reported) { + tlsv1_server_log(conn, "TEST-NOTE: Client Finished received after non-prime claimed as DHE prime"); + conn->test_failure_reported = 1; + } #endif /* CONFIG_TESTING_OPTIONS */ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) { diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c index 619b9ab8..15e66921 100644 --- a/src/tls/tlsv1_server_write.c +++ b/src/tls/tlsv1_server_write.c @@ -248,6 +248,8 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, size_t rlen; u8 *dh_ys; size_t dh_ys_len; + const u8 *dh_p; + size_t dh_p_len; suite = tls_get_cipher_suite(conn->rl.cipher_suite); if (suite == NULL) @@ -273,8 +275,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, return -1; } + tlsv1_server_get_dh_p(conn, &dh_p, &dh_p_len); + os_free(conn->dh_secret); - conn->dh_secret_len = conn->cred->dh_p_len; + conn->dh_secret_len = dh_p_len; conn->dh_secret = os_malloc(conn->dh_secret_len); if (conn->dh_secret == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate " @@ -293,8 +297,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, return -1; } - if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) > - 0) + if (os_memcmp(conn->dh_secret, dh_p, conn->dh_secret_len) > 0) conn->dh_secret[0] = 0; /* make sure secret < p */ pos = conn->dh_secret; @@ -309,7 +312,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, conn->dh_secret, conn->dh_secret_len); /* Ys = g^secret mod p */ - dh_ys_len = conn->cred->dh_p_len; + dh_ys_len = dh_p_len; dh_ys = os_malloc(dh_ys_len); if (dh_ys == NULL) { wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for " @@ -320,8 +323,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, } if (crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len, conn->dh_secret, conn->dh_secret_len, - conn->cred->dh_p, conn->cred->dh_p_len, - dh_ys, &dh_ys_len)) { + dh_p, dh_p_len, dh_ys, &dh_ys_len)) { tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR); os_free(dh_ys); @@ -369,7 +371,7 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, /* body - ServerDHParams */ server_params = pos; /* dh_p */ - if (pos + 2 + conn->cred->dh_p_len > end) { + if (pos + 2 + dh_p_len > end) { wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for " "dh_p"); tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, @@ -377,10 +379,10 @@ static int tls_write_server_key_exchange(struct tlsv1_server *conn, os_free(dh_ys); return -1; } - WPA_PUT_BE16(pos, conn->cred->dh_p_len); + WPA_PUT_BE16(pos, dh_p_len); pos += 2; - os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len); - pos += conn->cred->dh_p_len; + os_memcpy(pos, dh_p, dh_p_len); + pos += dh_p_len; /* dh_g */ if (pos + 2 + conn->cred->dh_g_len > end) { diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index 70d6a178..89f13664 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -265,6 +265,29 @@ static int wps_build_cred_encr_type(struct wps_data *wps, struct wpabuf *msg) static int wps_build_cred_network_key(struct wps_data *wps, struct wpabuf *msg) { + if ((wps->wps->ap_auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) && + wps->wps->network_key_len == 0) { + char hex[65]; + u8 psk[32]; + /* Generate a random per-device PSK */ + if (random_get_bytes(psk, sizeof(psk)) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "WPS: Generated per-device PSK", + psk, sizeof(psk)); + wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", + (unsigned int) wps->new_psk_len * 2); + wpa_snprintf_hex(hex, sizeof(hex), psk, sizeof(psk)); + wpabuf_put_be16(msg, ATTR_NETWORK_KEY); + wpabuf_put_be16(msg, sizeof(psk) * 2); + wpabuf_put_data(msg, hex, sizeof(psk) * 2); + if (wps->wps->registrar) { + wps_cb_new_psk(wps->wps->registrar, + wps->peer_dev.mac_addr, + wps->p2p_dev_addr, psk, sizeof(psk)); + } + return 0; + } + wpa_printf(MSG_DEBUG, "WPS: * Network Key (len=%u)", (unsigned int) wps->wps->network_key_len); wpabuf_put_be16(msg, ATTR_NETWORK_KEY); diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 22070db9..f7154f87 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -212,5 +212,7 @@ int wps_registrar_pbc_overlap(struct wps_registrar *reg, const u8 *addr, const u8 *uuid_e); void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg, struct wps_nfc_pw_token *token); +int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr, + const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len); #endif /* WPS_I_H */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 6d879be2..900dd5a1 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -1170,8 +1170,8 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, } -static int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr, - const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) +int wps_cb_new_psk(struct wps_registrar *reg, const u8 *mac_addr, + const u8 *p2p_dev_addr, const u8 *psk, size_t psk_len) { if (reg->new_psk_cb == NULL) return 0; |
