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>
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 3e0155c..2491b78 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -639,23 +639,26 @@
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 3ca85a0..14d9ae9 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -73,6 +73,7 @@
#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 @@
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 aa3a51a..25eb490 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -254,6 +254,7 @@
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 5ba48c9..83cfd0f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -503,7 +503,8 @@
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 a7129f1..13604ed 100644
--- a/src/ap/ap_mlme.c
+++ b/src/ap/ap_mlme.c
@@ -120,8 +120,6 @@
* 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 c27cf3b..11351c4 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -281,6 +281,10 @@
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 @@
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 @@
}
#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 @@
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 @@
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 @@
}
#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 fd1041e..49f6e87 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -71,7 +71,6 @@
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 @@
}
-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 @@
{
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 @@
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 @@
}
-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 @@
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 @@
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 @@
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 7e392b3..4ec3201 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 bc5bb6c..4ed718c 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1093,7 +1093,7 @@
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 @@
}
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 @@
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 @@
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 @@
#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 @@
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 @@
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"Failed to prepare rates table.");
- return -1;
+ goto fail;
}
}
@@ -1185,14 +1190,14 @@
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 @@
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 @@
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 @@
*/
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 @@
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 @@
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 28e92fd..d319ce0 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -327,7 +327,7 @@
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 @@
"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 bad080f..9b2900f 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -242,29 +242,22 @@
*/
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 c97cef1..14fb567 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1445,17 +1445,6 @@
}
#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 @@
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 @@
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 @@
* 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 @@
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 a166178..138d049 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -54,7 +54,20 @@
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 b78fd01..12403f9 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -170,6 +170,8 @@
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 @@
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 c7d051b..f5417de 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -239,7 +239,6 @@
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 c0bab6f..2dbdeb1 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -61,7 +61,6 @@
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 @@
/* 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 7d89edf..4d19bb0 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1918,7 +1918,9 @@
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 @@
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 @@
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 @@
#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 @@
{
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 @@
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 d99db69..3ab3e3d 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -142,6 +142,7 @@
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 da5fea7..6ee9a4f 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -49,6 +49,7 @@
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 fcd5878..2e1bdcf 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -154,7 +154,7 @@
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 7a49751..e957c6e 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -261,7 +261,25 @@
}
/* 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 @@
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 27f58aa..adb22c7 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -368,6 +368,8 @@
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 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 @@
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 @@
#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 @@
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 @@
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 @@
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 5684ef3..c0b2caa 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -77,9 +77,7 @@
#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 @@
#ifdef CONFIG_IEEE80211W
#define WPA_IGTK_LEN 16
+#define WPA_IGTK_MAX_LEN 32
#endif /* CONFIG_IEEE80211W */
@@ -285,10 +284,11 @@
} 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_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 81e588f..65e0f79 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -544,6 +544,11 @@
#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 2e40db1..a32cfac 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -618,7 +618,8 @@
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 c929fe1..f2ea393 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -554,6 +554,26 @@
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 8a978f7..9b8ca6b 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -1466,6 +1466,29 @@
}
+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 @@
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 @@
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 de86cdf..77d7991 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -742,13 +742,15 @@
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 @@
"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 @@
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 @@
}
#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 610b65a..2329033 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -201,7 +201,7 @@
}
#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 @@
}
/* 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 @@
/**
+ * 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 @@
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 82b6fa3..0fc42cc 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -59,6 +59,8 @@
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 8367e36..f78921d 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -409,12 +409,37 @@
}
+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 @@
(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 4aeccf6..23d0b81 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -316,7 +316,7 @@
}
#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 @@
{
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 9a36d8f..96d79b3 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -78,5 +78,7 @@
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 04622b5..c34545e 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -31,7 +31,9 @@
{
#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 @@
u8 *shared;
size_t shared_len;
int res;
+ const u8 *dh_p;
+ size_t dh_p_len;
/*
* struct {
@@ -641,7 +645,9 @@
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 @@
/* 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 @@
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 619b9ab..15e6692 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -248,6 +248,8 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
/* 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 @@
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 70d6a17..89f1366 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -265,6 +265,29 @@
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 22070db..f7154f8 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -212,5 +212,7 @@
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 6d879be..900dd5a 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -1170,8 +1170,8 @@
}
-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;