Cumulative patch from commit 7efc7f66b1d63b3bbb99d9176f6f68c4d1fc6327
7efc7f6 TDLS: Fix TPK M1 error case (CID 68214)
d1bb7ae nl80211: Fix non-hostapd interface addition to not call add_ifidx()
38ddcca TDLS: Add ctrl_iface option for flushing all TDLS peers
342bce6 TDLS: Bail on STA add failure in tpk_m1 processing
947f900 TDLS: Handle unreachable link teardown for external setup
cf1600a hostapd: Configure driver ACL even if MAC address list is empty
fa21e6c Fix CONFIG_MODULE_TESTS=y build without CONFIG_P2P=y
bd10d93 P2P: Clean up by moving ifdef CONFIG_P2P to p2p_suppplicant.h
e3bd6e9 P2P: Use another interface operating channel as listen channel
28812a8 P2P: Try using one of the social channels for GO
751b00b P2P: Modify p2p_get_pref_freq
0a816e8 P2P: Remove duplicated code from get_shared_radio_freqs_data()
504df28 Remove unused dump_freq_array()
a0c90bb P2P: Collect and use extended data on used frequencies
b278f32 P2P: Remove unused code from get_shared_radio_freqs_data()
e627012 Clean up EAPOL-Key Key Data processing
d56d7e5 Clean up EAPOL-Key processing
8605eab EAP-EKE: Fix typos in debug message
25be28a dbus: Check return value more consistently (CID 62841)
ac79fcf wext: Verify set_ssid results consistently (CID 62842)
f62415d Note chmod() failure in debug log even in ignore case (CID 62843)
305000e WPS: Check wps_build_wfa_ext() return value consistently (CID 68104)
2485835 EAP-MSCHAPv2: Check hash function results more consistently (CID 68105)
b7c61c9 Fix validation of EAPOL-Key length with AES key wrap (CID 62859)
Change-Id: I4da11c59a54467301c38c3bec52629b9db19647d
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index ed73301..4e09fa3 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -946,35 +946,24 @@
if (hapd->iface->drv_max_acl_mac_addrs == 0)
return;
- if (!(conf->bss[0]->num_accept_mac || conf->bss[0]->num_deny_mac))
- return;
if (conf->bss[0]->macaddr_acl == DENY_UNLESS_ACCEPTED) {
- if (conf->bss[0]->num_accept_mac) {
- accept_acl = 1;
- err = hostapd_set_acl_list(hapd,
- conf->bss[0]->accept_mac,
- conf->bss[0]->num_accept_mac,
- accept_acl);
- if (err) {
- wpa_printf(MSG_DEBUG, "Failed to set accept acl");
- return;
- }
- } else {
- wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ accept_acl = 1;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->accept_mac,
+ conf->bss[0]->num_accept_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set accept acl");
+ return;
}
} else if (conf->bss[0]->macaddr_acl == ACCEPT_UNLESS_DENIED) {
- if (conf->bss[0]->num_deny_mac) {
- accept_acl = 0;
- err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
- conf->bss[0]->num_deny_mac,
- accept_acl);
- if (err) {
- wpa_printf(MSG_DEBUG, "Failed to set deny acl");
- return;
- }
- } else {
- wpa_printf(MSG_DEBUG, "Mismatch between ACL Policy & Accept/deny lists file");
+ accept_acl = 0;
+ err = hostapd_set_acl_list(hapd, conf->bss[0]->deny_mac,
+ conf->bss[0]->num_deny_mac,
+ accept_acl);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "Failed to set deny acl");
+ return;
}
}
}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 7568653..aa2cd04 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -10177,7 +10177,15 @@
if (drv->global)
drv->global->if_add_ifindex = ifidx;
- if (ifidx > 0)
+ /*
+ * Some virtual interfaces need to process EAPOL packets and events on
+ * the parent interface. This is used mainly with hostapd.
+ */
+ if (ifidx > 0 &&
+ (drv->hostapd ||
+ nlmode == NL80211_IFTYPE_AP_VLAN ||
+ nlmode == NL80211_IFTYPE_WDS ||
+ nlmode == NL80211_IFTYPE_MONITOR))
add_ifidx(drv, ifidx);
return 0;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index e5734bd..a4f9cec 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -2027,7 +2027,11 @@
* Stop cfg80211 from trying to associate before we are done
* with all parameters.
*/
- wpa_driver_wext_set_ssid(drv, (u8 *) "", 0);
+ if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "WEXT: Failed to clear SSID to stop pending cfg80211 association attempts (if any)");
+ /* continue anyway */
+ }
}
if (wpa_driver_wext_set_drop_unencrypted(drv, params->drop_unencrypted)
diff --git a/src/eap_peer/eap_eke.c b/src/eap_peer/eap_eke.c
index 864ea1d..6818b08 100644
--- a/src/eap_peer/eap_eke.c
+++ b/src/eap_peer/eap_eke.c
@@ -451,7 +451,7 @@
/* DHComponent_P = Encr(key, y_p) */
rpos = wpabuf_put(resp, data->sess.dhcomp_len);
if (eap_eke_dhcomp(&data->sess, key, pub, rpos) < 0) {
- wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_S");
+ wpa_printf(MSG_INFO, "EAP-EKE: Failed to build DHComponent_P");
os_memset(key, 0, sizeof(key));
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_PRIVATE_INTERNAL_ERROR);
@@ -523,7 +523,7 @@
end = payload + payload_len;
if (pos + data->sess.pnonce_ps_len + data->sess.prf_len > end) {
- wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Commit");
+ wpa_printf(MSG_DEBUG, "EAP-EKE: Too short EAP-EKE-Confirm");
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_PROTO_ERROR);
}
@@ -543,7 +543,7 @@
wpa_hexdump_key(MSG_DEBUG, "EAP-EKE: Received Nonce_P | Nonce_S",
nonces, 2 * data->sess.nonce_len);
if (os_memcmp(data->nonce_p, nonces, data->sess.nonce_len) != 0) {
- wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match trnsmitted Nonce_P");
+ wpa_printf(MSG_INFO, "EAP-EKE: Received Nonce_P does not match transmitted Nonce_P");
return eap_eke_build_fail(data, ret, reqData,
EAP_EKE_FAIL_AUTHENTICATION_FAIL);
}
diff --git a/src/eap_peer/eap_mschapv2.c b/src/eap_peer/eap_mschapv2.c
index f9aa742..f2fcc37 100644
--- a/src/eap_peer/eap_mschapv2.c
+++ b/src/eap_peer/eap_mschapv2.c
@@ -309,10 +309,13 @@
} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
config->password = os_malloc(16);
config->password_len = 16;
- if (config->password) {
- nt_password_hash(config->new_password,
- config->new_password_len,
- config->password);
+ if (config->password &&
+ nt_password_hash(config->new_password,
+ config->new_password_len,
+ config->password)) {
+ os_free(config->password);
+ config->password = NULL;
+ config->password_len = 0;
}
os_free(config->new_password);
} else {
@@ -549,15 +552,17 @@
/* Encrypted-Hash */
if (pwhash) {
u8 new_password_hash[16];
- nt_password_hash(new_password, new_password_len,
- new_password_hash);
+ if (nt_password_hash(new_password, new_password_len,
+ new_password_hash))
+ goto fail;
nt_password_hash_encrypted_with_block(password,
new_password_hash,
cp->encr_hash);
} else {
- old_nt_password_hash_encrypted_with_new_nt_password_hash(
- new_password, new_password_len,
- password, password_len, cp->encr_hash);
+ if (old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ new_password, new_password_len,
+ password, password_len, cp->encr_hash))
+ goto fail;
}
/* Peer-Challenge */
@@ -594,9 +599,13 @@
/* Likewise, generate master_key here since we have the needed data
* available. */
- nt_password_hash(new_password, new_password_len, password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
- get_master_key(password_hash_hash, cp->nt_response, data->master_key);
+ if (nt_password_hash(new_password, new_password_len, password_hash) ||
+ hash_nt_password_hash(password_hash, password_hash_hash) ||
+ get_master_key(password_hash_hash, cp->nt_response,
+ data->master_key)) {
+ data->auth_response_valid = 0;
+ goto fail;
+ }
data->master_key_valid = 1;
/* Flags */
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 1875ca4..104f77b 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -183,6 +183,14 @@
p2p_dbg(p2p, "State %s -> %s",
p2p_state_txt(p2p->state), p2p_state_txt(new_state));
p2p->state = new_state;
+
+ if (new_state == P2P_IDLE && p2p->pending_channel) {
+ p2p_dbg(p2p, "Apply change in listen channel");
+ p2p->cfg->reg_class = p2p->pending_reg_class;
+ p2p->cfg->channel = p2p->pending_channel;
+ p2p->pending_reg_class = 0;
+ p2p->pending_channel = 0;
+ }
}
@@ -3991,20 +3999,43 @@
}
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel)
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced)
{
if (p2p_channel_to_freq(reg_class, channel) < 0)
return -1;
p2p_dbg(p2p, "Set Listen channel: reg_class %u channel %u",
reg_class, channel);
- p2p->cfg->reg_class = reg_class;
- p2p->cfg->channel = channel;
+
+ /*
+ * Listen channel was set in configuration or set by control interface;
+ * cannot override it.
+ */
+ if (p2p->cfg->channel_forced && forced == 0)
+ return -1;
+
+ if (p2p->state == P2P_IDLE) {
+ p2p->cfg->reg_class = reg_class;
+ p2p->cfg->channel = channel;
+ p2p->cfg->channel_forced = forced;
+ } else {
+ p2p_dbg(p2p, "Defer setting listen channel");
+ p2p->pending_reg_class = reg_class;
+ p2p->pending_channel = channel;
+ p2p->pending_channel_forced = forced;
+ }
return 0;
}
+u8 p2p_get_listen_channel(struct p2p_data *p2p)
+{
+ return p2p->cfg->channel;
+}
+
+
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len)
{
p2p_dbg(p2p, "New SSID postfix: %s", wpa_ssid_txt(postfix, len));
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index fa8031d..9cf100f 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -267,6 +267,12 @@
u8 channel;
/**
+ * channel_forced - the listen channel was forced by configuration
+ * or by control interface and cannot be overridden
+ */
+ u8 channel_forced;
+
+ /**
* Regulatory class for own operational channel
*/
u8 op_reg_class;
@@ -1669,7 +1675,10 @@
*/
void p2p_set_managed_oper(struct p2p_data *p2p, int enabled);
-int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel);
+int p2p_set_listen_channel(struct p2p_data *p2p, u8 reg_class, u8 channel,
+ u8 forced);
+
+u8 p2p_get_listen_channel(struct p2p_data *p2p);
int p2p_set_ssid_postfix(struct p2p_data *p2p, const u8 *postfix, size_t len);
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 65ff9ef..39a927a 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -480,6 +480,10 @@
unsigned int search_delay;
int in_search_delay;
+ u8 pending_reg_class;
+ u8 pending_channel;
+ u8 pending_channel_forced;
+
#ifdef CONFIG_WIFI_DISPLAY
struct wpabuf *wfd_ie_beacon;
struct wpabuf *wfd_ie_probe_req;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index ac19064..189300a 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -388,17 +388,19 @@
const struct p2p_channels *channels)
{
unsigned int i;
- int freq;
+ int freq = 0;
+ const struct p2p_channels *tmpc = channels ?
+ channels : &p2p->cfg->channels;
+
+ if (tmpc == NULL)
+ return 0;
for (i = 0; p2p->cfg->pref_chan && i < p2p->cfg->num_pref_chan; i++) {
freq = p2p_channel_to_freq(p2p->cfg->pref_chan[i].op_class,
p2p->cfg->pref_chan[i].chan);
- if (freq <= 0)
- continue;
- if (!channels || p2p_channels_includes_freq(channels, freq))
+ if (p2p_channels_includes_freq(tmpc, freq))
return freq;
}
-
return 0;
}
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 84b7c1b..59ed2c9 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -802,7 +802,7 @@
}
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr)
{
struct wpa_tdls_peer *peer;
@@ -811,8 +811,25 @@
break;
}
- if (peer)
+ if (!peer || !peer->tpk_success) {
+ wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+ " not connected - cannot teardown unreachable link",
+ MAC2STR(addr));
+ return;
+ }
+
+ if (wpa_tdls_is_external_setup(sm)) {
+ /*
+ * Disable the link, send a teardown packet through the
+ * AP, and then reset link data.
+ */
+ wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+ wpa_tdls_send_teardown(sm, addr,
+ WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
+ wpa_tdls_peer_free(sm, peer);
+ } else {
wpa_tdls_disable_peer_link(sm, peer);
+ }
}
@@ -1831,7 +1848,6 @@
if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->ctx, MSG_WARNING,
"TDLS: Failed to get random data for responder nonce");
- wpa_tdls_peer_free(sm, peer);
goto error;
}
}
@@ -1887,8 +1903,10 @@
skip_rsn_check:
/* add the peer to the driver as a "setup in progress" peer */
- wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
- NULL, 0, NULL, 0, NULL, 0);
+ if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+ NULL, 0, NULL, 0, NULL, 0, NULL, 0))
+ goto error;
+
peer->tpk_in_progress = 1;
wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
@@ -1902,6 +1920,8 @@
error:
wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_RESPONSE, dtoken,
status);
+ if (peer)
+ wpa_tdls_peer_free(sm, peer);
return -1;
}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index ba2a8c8..40fb92a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -379,7 +379,8 @@
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
struct wpa_eapol_ie_parse ie;
struct wpa_ptk *ptk;
@@ -401,10 +402,9 @@
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
- const u8 *_buf = (const u8 *) (key + 1);
- size_t len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
- if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
+ key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
@@ -1068,10 +1068,10 @@
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
- u16 key_info, keylen, len;
- const u8 *pos;
+ u16 key_info, keylen;
struct wpa_eapol_ie_parse ie;
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
@@ -1080,10 +1080,8 @@
key_info = WPA_GET_BE16(key->key_info);
- pos = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1238,21 +1236,14 @@
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- size_t keydatalen, int key_info,
- size_t extra_len, u16 ver,
- struct wpa_gtk_data *gd)
+ const u8 *key_data,
+ size_t key_data_len, u16 key_info,
+ u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
gd->gtk_len = WPA_GET_BE16(key->key_length);
- maxkeylen = keydatalen;
- if (keydatalen > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
- "WPA: Truncated EAPOL-Key packet: "
- "key_data_length=%lu > extra_len=%lu",
- (unsigned long) keydatalen, (unsigned long) extra_len);
- return -1;
- }
+ maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1272,16 +1263,16 @@
WPA_KEY_INFO_KEY_INDEX_SHIFT;
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
u8 ek[32];
- if (keydatalen > sizeof(gd->gtk)) {
+ if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: RC4 key data too long (%lu)",
- (unsigned long) keydatalen);
+ (unsigned long) key_data_len);
return -1;
}
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, 16);
- os_memcpy(gd->gtk, key + 1, keydatalen);
- if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+ os_memcpy(gd->gtk, key_data, key_data_len);
+ if (rc4_skip(ek, 32, 256, gd->gtk, key_data_len)) {
os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
@@ -1289,22 +1280,21 @@
}
os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- if (keydatalen % 8) {
+ if (maxkeylen % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported AES-WRAP len %lu",
- (unsigned long) keydatalen);
+ (unsigned long) maxkeylen);
return -1;
}
if (maxkeylen > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES-WRAP key data "
"too long (keydatalen=%lu maxkeylen=%lu)",
- (unsigned long) keydatalen,
+ (unsigned long) key_data_len,
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
- (const u8 *) (key + 1), gd->gtk)) {
+ if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, key_data, gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1360,9 +1350,10 @@
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ const u8 *key_data,
+ size_t key_data_len, u16 ver)
{
- u16 key_info, keydatalen;
+ u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
@@ -1373,17 +1364,15 @@
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
key_info = WPA_GET_BE16(key->key_info);
- keydatalen = WPA_GET_BE16(key->key_data_length);
if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
- ret = wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
+ ret = wpa_supplicant_process_1_of_2_rsn(sm, key_data,
+ key_data_len, key_info,
&gd);
} else {
- ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
- key_info, extra_len,
- ver, &gd);
+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, key_data,
+ key_data_len,
+ key_info, ver, &gd);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
@@ -1471,12 +1460,11 @@
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver)
+ struct wpa_eapol_key *key, u16 ver,
+ u8 *key_data, size_t *key_data_len)
{
- u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
if (!sm->ptk_set) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
@@ -1490,7 +1478,7 @@
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+ if (rc4_skip(ek, 32, 256, key_data, *key_data_len)) {
os_memset(ek, 0, sizeof(ek));
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
"WPA: RC4 failed");
@@ -1501,37 +1489,37 @@
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
sm->key_mgmt == WPA_KEY_MGMT_OSEN) {
u8 *buf;
- if (keydatalen % 8) {
+ if (*key_data_len < 8 || *key_data_len % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
- "WPA: Unsupported AES-WRAP len %d",
- keydatalen);
+ "WPA: Unsupported AES-WRAP len %u",
+ (unsigned int) *key_data_len);
return -1;
}
- keydatalen -= 8; /* AES-WRAP adds 8 bytes */
- buf = os_malloc(keydatalen);
+ *key_data_len -= 8; /* AES-WRAP adds 8 bytes */
+ buf = os_malloc(*key_data_len);
if (buf == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
- (u8 *) (key + 1), buf)) {
+ if (aes_unwrap(sm->ptk.kek, *key_data_len / 8,
+ key_data, buf)) {
os_free(buf);
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
- os_memcpy(key + 1, buf, keydatalen);
+ os_memcpy(key_data, buf, *key_data_len);
os_free(buf);
- WPA_PUT_BE16(key->key_data_length, keydatalen);
+ WPA_PUT_BE16(key->key_data_length, *key_data_len);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Unsupported key_info type %d", ver);
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
return 0;
}
@@ -1605,13 +1593,14 @@
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
- size_t plen, data_len, extra_len;
- struct ieee802_1x_hdr *hdr;
+ size_t plen, data_len, key_data_len;
+ const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
u16 key_info, ver;
- u8 *tmp;
+ u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
+ u8 *key_data;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
@@ -1626,13 +1615,7 @@
return 0;
}
- tmp = os_malloc(len);
- if (tmp == NULL)
- return -1;
- os_memcpy(tmp, buf, len);
-
- hdr = (struct ieee802_1x_hdr *) tmp;
- key = (struct wpa_eapol_key *) (hdr + 1);
+ hdr = (const struct ieee802_1x_hdr *) buf;
plen = be_to_host16(hdr->length);
data_len = plen + sizeof(*hdr);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
@@ -1649,6 +1632,7 @@
ret = 0;
goto out;
}
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
@@ -1657,6 +1641,22 @@
ret = 0;
goto out;
}
+ if (data_len < len) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+ (unsigned long) len - data_len);
+ }
+
+ /*
+ * Make a copy of the frame since we need to modify the buffer during
+ * MAC validation and Key Data decryption.
+ */
+ tmp = os_malloc(data_len);
+ if (tmp == NULL)
+ goto out;
+ os_memcpy(tmp, buf, data_len);
+ key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
+ key_data = (u8 *) (key + 1);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1668,13 +1668,16 @@
}
wpa_eapol_key_dump(sm, key);
- eapol_sm_notify_lower_layer_success(sm->eapol, 0);
- wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
- if (data_len < len) {
- wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
- "WPA: ignoring %lu bytes after the IEEE 802.1X data",
- (unsigned long) len - data_len);
+ key_data_len = WPA_GET_BE16(key->key_data_length);
+ if (key_data_len > plen - sizeof(struct wpa_eapol_key)) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+ "frame - key_data overflow (%u > %u)",
+ (unsigned int) key_data_len,
+ (unsigned int) (plen - sizeof(struct wpa_eapol_key)));
+ goto out;
}
+
+ eapol_sm_notify_lower_layer_success(sm->eapol, 0);
key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
@@ -1814,22 +1817,11 @@
goto out;
#endif /* CONFIG_PEERKEY */
- extra_len = data_len - sizeof(*hdr) - sizeof(*key);
-
- if (WPA_GET_BE16(key->key_data_length) > extra_len) {
- wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
- "frame - key_data overflow (%d > %lu)",
- WPA_GET_BE16(key->key_data_length),
- (unsigned long) extra_len);
- goto out;
- }
- extra_len = WPA_GET_BE16(key->key_data_length);
-
if ((sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+ if (wpa_supplicant_decrypt_key_data(sm, key, ver, key_data,
+ &key_data_len))
goto out;
- extra_len = WPA_GET_BE16(key->key_data_length);
}
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
@@ -1844,21 +1836,24 @@
peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
} else if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, key, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+ key_data_len);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
- ver);
+ ver, key_data,
+ key_data_len);
}
} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
/* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
ver);
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
- extra_len, ver);
+ key_data, key_data_len,
+ ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic bit - "
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index e98967c..07a7bf9 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -385,7 +385,7 @@
void wpa_tdls_teardown_peers(struct wpa_sm *sm);
void wpa_tdls_deinit(struct wpa_sm *sm);
void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
-void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
int wpa_tdls_is_external_setup(struct wpa_sm *sm);
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index f62b49e..ae94a9f 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -596,7 +596,10 @@
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
wpabuf_put_be16(msg, WPS_NONCE_LEN);
wpabuf_put(msg, WPS_NONCE_LEN);
- wps_build_wfa_ext(msg, 0, NULL, 0);
+ if (wps_build_wfa_ext(msg, 0, NULL, 0)) {
+ wpabuf_free(msg);
+ return NULL;
+ }
return msg;
}