summaryrefslogtreecommitdiff
path: root/src/rsn_supp/wpa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rsn_supp/wpa.c')
-rw-r--r--src/rsn_supp/wpa.c842
1 files changed, 547 insertions, 295 deletions
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e50404ce78a79..8adeef4af1a5c 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,6 +27,7 @@
* wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @kck: Key Confirmation Key (KCK, part of PTK)
+ * @kck_len: KCK length in octets
* @ver: Version field from Key Info
* @dest: Destination address for the frame
* @proto: Ethertype (usually ETH_P_EAPOL)
@@ -34,10 +35,12 @@
* @msg_len: Length of message
* @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
*/
-void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
+
if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
/*
* Association event was not yet received; try to fetch
@@ -56,14 +59,15 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+ wpa_eapol_key_mic(kck, kck_len, sm->key_mgmt, ver, msg, msg_len,
+ key_mic)) {
wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
- "WPA: Failed to generate EAPOL-Key "
- "version %d MIC", ver);
+ "WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+ ver, sm->key_mgmt);
goto out;
}
- wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
- wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, kck_len);
+ wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
@@ -84,12 +88,17 @@ out:
*/
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
int key_info, ver;
- u8 bssid[ETH_ALEN], *rbuf;
+ u8 bssid[ETH_ALEN], *rbuf, *key_mic;
- if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt))
+ ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
+ else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
+ wpa_key_mgmt_sha256(sm->key_mgmt))
ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -102,12 +111,16 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
return;
}
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
if (sm->ptk_set)
@@ -122,15 +135,39 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
+ if (!(key_info & WPA_KEY_INFO_MIC))
+ key_mic = NULL;
+ else
+ key_mic = reply192->key_mic; /* same offset in reply */
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Sending EAPOL-Key Request (error=%d "
"pairwise=%d ptk_set=%d len=%lu)",
error, pairwise, sm->ptk_set, (unsigned long) rlen);
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
- reply->key_mic : NULL);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
+}
+
+
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+ if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set low order 256 bits of MSK for key management offload");
+ } else {
+#endif /* CONFIG_IEEE80211R */
+ if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+ }
+#endif /* CONFIG_IEEE80211R */
}
@@ -158,7 +195,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (pmkid && sm->cur_pmksa &&
- os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -194,10 +231,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
+ wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
sm->pmk, pmk_len,
+ NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
@@ -231,7 +271,9 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
- !wpa_key_mgmt_ft(sm->key_mgmt)) {
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
+ {
/* Send EAPOL-Start to trigger full EAP authentication. */
u8 *buf;
size_t buflen;
@@ -273,9 +315,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
u8 *rsn_ie_buf = NULL;
if (wpa_ie == NULL) {
@@ -317,19 +360,23 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
- NULL, sizeof(*reply) + wpa_ie_len,
+ NULL, hdrlen + wpa_ie_len,
&rlen, (void *) &reply);
if (rbuf == NULL) {
os_free(rsn_ie_buf);
return -1;
}
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
WPA_PUT_BE16(reply->key_info,
ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
@@ -338,47 +385,52 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24) {
+ WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len);
+ os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len);
+ } else {
+ WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+ os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ }
os_free(rsn_ie_buf);
os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
- return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+ return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
- sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->key_mgmt));
- return 0;
+ return wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+ sm->own_addr, sm->bssid, sm->snonce,
+ key->key_nonce, ptk, sm->key_mgmt,
+ sm->pairwise_cipher);
}
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;
- u8 buf[8];
int res;
+ u8 *kde, *kde_buf = NULL;
+ size_t kde_len;
if (wpa_sm_get_network_ctx(sm) == NULL) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
@@ -392,20 +444,17 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
os_memset(&ie, 0, sizeof(ie));
-#ifndef CONFIG_NO_WPA2
- if (sm->proto == WPA_PROTO_RSN) {
+ 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 "
"Authenticator", ie.pmkid, PMKID_LEN);
}
}
-#endif /* CONFIG_NO_WPA2 */
res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
if (res == -2) {
@@ -431,21 +480,49 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
* been verified when processing message 3/4. */
ptk = &sm->tptk;
wpa_derive_ptk(sm, src_addr, key, ptk);
- /* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
- os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
- os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+ if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
+ u8 buf[8];
+ /* Supplicant: swap tx/rx Mic keys */
+ os_memcpy(buf, &ptk->tk[16], 8);
+ os_memcpy(&ptk->tk[16], &ptk->tk[24], 8);
+ os_memcpy(&ptk->tk[24], buf, 8);
+ os_memset(buf, 0, sizeof(buf));
+ }
sm->tptk_set = 1;
+ kde = sm->assoc_wpa_ie;
+ kde_len = sm->assoc_wpa_ie_len;
+
+#ifdef CONFIG_P2P
+ if (sm->p2p) {
+ kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
+ if (kde_buf) {
+ u8 *pos;
+ wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
+ "into EAPOL-Key 2/4");
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
+ }
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
- sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
- ptk))
+ kde, kde_len, ptk))
goto failed;
+ os_free(kde_buf);
os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
return;
failed:
+ os_free(kde_buf);
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -537,7 +614,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
- if (sm->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
@@ -545,7 +622,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
}
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
- (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sm->ptk.tk, keylen) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set PTK to the "
"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -553,6 +630,9 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
return -1;
}
+ /* TK is not needed anymore in supplicant */
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
+
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -625,6 +705,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to set GTK to the driver "
"(Group only)");
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
@@ -634,8 +715,10 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
"WPA: Failed to set GTK to "
"the driver (alg=%d keylen=%d keyidx=%d)",
gd->alg, gd->gtk_len, gd->keyidx);
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return -1;
}
+ os_memset(gtk_buf, 0, sizeof(gtk_buf));
return 0;
}
@@ -664,7 +747,6 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
const u8 *gtk, size_t gtk_len,
int key_info)
{
-#ifndef CONFIG_NO_WPA2
struct wpa_gtk_data gd;
/*
@@ -691,21 +773,21 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gtk_len, gtk_len,
- &gd.key_rsc_len, &gd.alg) ||
- wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
+ if (sm->group_cipher != WPA_CIPHER_GTK_NOT_USED &&
+ (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, gtk_len,
+ &gd.key_rsc_len, &gd.alg) ||
+ wpa_supplicant_install_gtk(sm, &gd, key->key_rsc))) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Failed to install GTK");
+ os_memset(&gd, 0, sizeof(gd));
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info & WPA_KEY_INFO_SECURE);
return 0;
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -713,13 +795,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);
@@ -727,15 +811,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;
@@ -868,7 +953,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
return -1;
}
- if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+ if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+ {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"FT: PMKR1Name mismatch in "
"FT 4-way handshake message 3/4");
@@ -988,49 +1074,49 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
* @key: Pointer to the EAPOL-Key frame header
* @ver: Version bits from EAPOL-Key Key Info
* @key_info: Key Info
- * @kde: KDEs to include the EAPOL-Key frame
- * @kde_len: Length of KDEs
* @ptk: PTK to use for keyed hash and encryption
* Returns: 0 on success, -1 on failure
*/
int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
const struct wpa_eapol_key *key,
u16 ver, u16 key_info,
- const u8 *kde, size_t kde_len,
struct wpa_ptk *ptk)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
-
- if (kde)
- wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply) + kde_len,
- &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_SECURE;
key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, kde_len);
- if (kde)
- os_memcpy(reply + 1, kde, kde_len);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, key_mic);
return 0;
}
@@ -1038,10 +1124,10 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- u16 ver)
+ u16 ver, const u8 *key_data,
+ size_t key_data_len)
{
- u16 key_info, keylen, len;
- const u8 *pos;
+ u16 key_info, keylen;
struct wpa_eapol_ie_parse ie;
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
@@ -1050,10 +1136,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
key_info = WPA_GET_BE16(key->key_info);
- pos = (const u8 *) (key + 1);
- len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", key_data, key_data_len);
+ if (wpa_supplicant_parse_ies(key_data, key_data_len, &ie) < 0)
goto failed;
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1067,7 +1151,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);
@@ -1095,8 +1182,16 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
+#ifdef CONFIG_P2P
+ if (ie.ip_addr_alloc) {
+ os_memcpy(sm->p2p_ip_addr, ie.ip_addr_alloc, 3 * 4);
+ wpa_hexdump(MSG_DEBUG, "P2P: IP address info",
+ sm->p2p_ip_addr, sizeof(sm->p2p_ip_addr));
+ }
+#endif /* CONFIG_P2P */
+
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
- NULL, 0, &sm->ptk)) {
+ &sm->ptk)) {
goto failed;
}
@@ -1118,7 +1213,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
- if (ie.gtk &&
+ if (sm->group_cipher == WPA_CIPHER_GTK_NOT_USED) {
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
+ key_info & WPA_KEY_INFO_SECURE);
+ } else if (ie.gtk &&
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1132,8 +1230,21 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
goto failed;
}
- wpa_sm_set_rekey_offload(sm);
+ if (ie.gtk)
+ wpa_sm_set_rekey_offload(sm);
+
+ if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+ struct rsn_pmksa_cache_entry *sa;
+
+ sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ if (!sm->cur_pmksa)
+ sm->cur_pmksa = sa;
+ }
+ sm->msg_3_of_4_ok = 1;
return;
failed:
@@ -1193,22 +1304,15 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
- size_t keydatalen, int key_info,
- size_t extra_len, u16 ver,
- struct wpa_gtk_data *gd)
+ const u8 *key_data,
+ size_t key_data_len, u16 key_info,
+ u16 ver, struct wpa_gtk_data *gd)
{
size_t maxkeylen;
- u8 ek[32];
+ u16 gtk_len;
- 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;
- }
+ gtk_len = WPA_GET_BE16(key->key_length);
+ maxkeylen = key_data_len;
if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen < 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
@@ -1219,45 +1323,50 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
maxkeylen -= 8;
}
- if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
- gd->gtk_len, maxkeylen,
+ if (gtk_len > maxkeylen ||
+ wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+ gtk_len, maxkeylen,
&gd->key_rsc_len, &gd->alg))
return -1;
+ gd->gtk_len = gtk_len;
gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
WPA_KEY_INFO_KEY_INDEX_SHIFT;
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
- os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
- if (keydatalen > sizeof(gd->gtk)) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
+ u8 ek[32];
+ 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(gd->gtk, key + 1, keydatalen);
- if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ 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");
return -1;
}
+ 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, sm->ptk.kek_len, maxkeylen / 8,
+ key_data, gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: AES unwrap failed - could not decrypt "
"GTK");
@@ -1278,32 +1387,41 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
int ver, u16 key_info)
{
- size_t rlen;
+ size_t mic_len, hdrlen, rlen;
struct wpa_eapol_key *reply;
- u8 *rbuf;
+ struct wpa_eapol_key_192 *reply192;
+ u8 *rbuf, *key_mic;
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ hdrlen, &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
- reply->type = sm->proto == WPA_PROTO_RSN ?
+ reply->type = (sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
WPA_PUT_BE16(reply->key_info, key_info);
- if (sm->proto == WPA_PROTO_RSN)
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN)
WPA_PUT_BE16(reply->key_length, 0);
else
os_memcpy(reply->key_length, key->key_length, 2);
os_memcpy(reply->replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ key_mic = reply192->key_mic; /* same offset for reply and reply192 */
+ if (mic_len == 24)
+ WPA_PUT_BE16(reply192->key_data_length, 0);
+ else
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, sm->bssid,
+ ETH_P_EAPOL, rbuf, rlen, key_mic);
return 0;
}
@@ -1312,12 +1430,19 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ const u8 *key_data,
+ size_t key_data_len, u16 ver)
{
- u16 key_info, keydatalen;
+ u16 key_info;
int rekey, ret;
struct wpa_gtk_data gd;
+ if (!sm->msg_3_of_4_ok) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Group Key Handshake started prior to completion of 4-way handshake");
+ goto failed;
+ }
+
os_memset(&gd, 0, sizeof(gd));
rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
@@ -1325,17 +1450,15 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
key_info = WPA_GET_BE16(key->key_info);
- keydatalen = WPA_GET_BE16(key->key_data_length);
- if (sm->proto == WPA_PROTO_RSN) {
- ret = wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
+ if (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) {
+ 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);
@@ -1346,6 +1469,7 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
goto failed;
+ os_memset(&gd, 0, sizeof(gd));
if (rekey) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
@@ -1353,34 +1477,37 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_cancel_auth_timeout(sm);
wpa_sm_set_state(sm, WPA_COMPLETED);
-
- wpa_sm_set_rekey_offload(sm);
} else {
wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
WPA_KEY_INFO_SECURE);
}
+
+ wpa_sm_set_rekey_offload(sm);
+
return;
failed:
+ os_memset(&gd, 0, sizeof(gd));
wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
- struct wpa_eapol_key *key,
+ struct wpa_eapol_key_192 *key,
u16 ver,
const u8 *buf, size_t len)
{
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
int ok = 0;
+ size_t mic_len = wpa_mic_len(sm->key_mgmt);
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (sm->tptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->tptk.kck, sm->tptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
@@ -1389,14 +1516,15 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
sm->tptk_set = 0;
sm->ptk_set = 1;
os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
}
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
- key->key_mic);
- if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ os_memset(key->key_mic, 0, mic_len);
+ wpa_eapol_key_mic(sm->ptk.kck, sm->ptk.kck_len, sm->key_mgmt,
+ ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Invalid EAPOL-Key MIC - "
"dropping packet");
@@ -1421,12 +1549,11 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
- struct wpa_eapol_key *key, u16 ver)
+ struct wpa_eapol_key *key, u16 ver,
+ u8 *key_data, size_t *key_data_len)
{
- u16 keydatalen = WPA_GET_BE16(key->key_data_length);
-
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
- (u8 *) (key + 1), keydatalen);
+ key_data, *key_data_len);
if (!sm->ptk_set) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
@@ -1436,49 +1563,53 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
/* Decrypt key data here so that this operation does not need
* to be implemented separately for each message type. */
- if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
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)) {
+ os_memcpy(ek + 16, sm->ptk.kek, sm->ptk.kek_len);
+ 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");
return -1;
}
+ os_memset(ek, 0, sizeof(ek));
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
- ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
+ sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+ wpa_key_mgmt_suite_b(sm->key_mgmt)) {
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, sm->ptk.kek_len, *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;
}
@@ -1498,7 +1629,9 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm)
static void wpa_eapol_key_dump(struct wpa_sm *sm,
- const struct wpa_eapol_key *key)
+ const struct wpa_eapol_key *key,
+ unsigned int key_data_len,
+ const u8 *mic, unsigned int mic_len)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
u16 key_info = WPA_GET_BE16(key->key_info);
@@ -1520,15 +1653,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
" key_length=%u key_data_length=%u",
- WPA_GET_BE16(key->key_length),
- WPA_GET_BE16(key->key_data_length));
+ WPA_GET_BE16(key->key_length), key_data_len);
wpa_hexdump(MSG_DEBUG, " replay_counter",
key->replay_counter, WPA_REPLAY_COUNTER_LEN);
wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16);
wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8);
wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8);
- wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);
+ wpa_hexdump(MSG_DEBUG, " key_mic", mic, mic_len);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
@@ -1552,34 +1684,34 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm,
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
- size_t plen, data_len, extra_len;
- struct ieee802_1x_hdr *hdr;
+ size_t plen, data_len, key_data_len;
+ const struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info, ver;
- u8 *tmp;
+ u8 *tmp = NULL;
int ret = -1;
struct wpa_peerkey *peerkey = NULL;
+ u8 *key_data;
+ size_t mic_len, keyhdrlen;
#ifdef CONFIG_IEEE80211R
sm->ft_completed = 0;
#endif /* CONFIG_IEEE80211R */
- if (len < sizeof(*hdr) + sizeof(*key)) {
+ mic_len = wpa_mic_len(sm->key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (len < sizeof(*hdr) + keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame too short to be a WPA "
"EAPOL-Key (len %lu, expecting at least %lu)",
(unsigned long) len,
- (unsigned long) sizeof(*hdr) + sizeof(*key));
+ (unsigned long) sizeof(*hdr) + keyhdrlen);
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,
@@ -1596,7 +1728,8 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
+ if (plen > len - sizeof(*hdr) || plen < keyhdrlen) {
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: EAPOL frame payload size %lu "
"invalid (frame size %lu)",
@@ -1604,6 +1737,27 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ if (data_len < len) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: ignoring %lu bytes after the IEEE 802.1X data",
+ (unsigned long) len - data_len);
+ }
+
+ /*
+ * Make a copy of the frame since we need to modify the buffer during
+ * MAC validation and Key Data decryption.
+ */
+ tmp = os_malloc(data_len);
+ if (tmp == NULL)
+ goto out;
+ os_memcpy(tmp, buf, data_len);
+ key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
+ key192 = (struct wpa_eapol_key_192 *)
+ (tmp + sizeof(struct ieee802_1x_hdr));
+ if (mic_len == 24)
+ key_data = (u8 *) (key192 + 1);
+ else
+ key_data = (u8 *) (key + 1);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
@@ -1613,28 +1767,53 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
- 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);
+ if (mic_len == 24)
+ key_data_len = WPA_GET_BE16(key192->key_data_length);
+ else
+ key_data_len = WPA_GET_BE16(key->key_data_length);
+ wpa_eapol_key_dump(sm, key, key_data_len, key192->key_mic, mic_len);
+
+ if (key_data_len > plen - keyhdrlen) {
+ 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 - keyhdrlen));
+ 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 &&
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Unsupported EAPOL-Key descriptor version %d",
ver);
goto out;
}
+ if (sm->key_mgmt == WPA_KEY_MGMT_OSEN &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "OSEN: Unsupported EAPOL-Key descriptor version %d",
+ ver);
+ goto out;
+ }
+
+ if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
+ ver);
+ goto out;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) {
/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
@@ -1647,7 +1826,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
#endif /* CONFIG_IEEE80211R */
#ifdef CONFIG_IEEE80211W
if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
- if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+ sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: AP did not use the "
"negotiated AES-128-CMAC");
@@ -1656,6 +1837,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} else
#endif /* CONFIG_IEEE80211W */
if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: CCMP is used, but EAPOL-Key "
@@ -1669,11 +1851,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: Backwards compatibility: allow invalid "
"version for non-CCMP group keys");
+ } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
} else
goto out;
- }
- if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
- ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+ !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+ ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: GCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2", ver);
@@ -1743,31 +1928,21 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
- wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+ wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len))
goto out;
#ifdef CONFIG_PEERKEY
if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
- peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+ peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp,
+ data_len))
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 &&
+ 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) {
@@ -1779,24 +1954,28 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
}
if (peerkey) {
/* PeerKey 4-Way Handshake */
- peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+ peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver,
+ key_data, key_data_len);
} else if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, key, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver, key_data,
+ key_data_len);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
- ver);
+ ver, key_data,
+ key_data_len);
}
} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
/* PeerKey SMK Handshake */
- peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+ peerkey_rx_eapol_smk(sm, src_addr, key, key_data_len, key_info,
ver);
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
wpa_supplicant_process_1_of_2(sm, src_addr, key,
- extra_len, ver);
+ key_data, key_data_len,
+ ver);
} else {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: EAPOL-Key (Group) without Mic bit - "
@@ -1807,7 +1986,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
@@ -1817,7 +1996,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
{
switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return (sm->proto == WPA_PROTO_RSN ?
+ return ((sm->proto == WPA_PROTO_RSN ||
+ sm->proto == WPA_PROTO_OSEN) ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK:
@@ -1842,6 +2022,10 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
WPA_AUTH_KEY_MGMT_CCKM);
case WPA_KEY_MGMT_WPA_NONE:
return WPA_AUTH_KEY_MGMT_NONE;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
default:
return 0;
}
@@ -1899,7 +2083,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
@@ -1926,7 +2110,7 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
sm->group_cipher)),
sm->dot11RSNA4WayHandshakeFailures);
- if (ret >= 0 && (size_t) ret < buflen)
+ if (!os_snprintf_error(buflen - len, ret))
len += ret;
return (int) len;
@@ -2024,6 +2208,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
os_free(sm->assoc_wpa_ie);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ wpa_sm_drop_sa(sm);
os_free(sm->ctx);
peerkey_deinit(sm);
#ifdef CONFIG_IEEE80211R
@@ -2080,12 +2265,18 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
sm->ptk_set = 0;
+ os_memset(&sm->ptk, 0, sizeof(sm->ptk));
sm->tptk_set = 0;
+ os_memset(&sm->tptk, 0, sizeof(sm->tptk));
}
#ifdef CONFIG_TDLS
wpa_tdls_assoc(sm);
#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_P2P
+ os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
+#endif /* CONFIG_P2P */
}
@@ -2098,6 +2289,9 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
*/
void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
+ eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+ eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+ peerkey_deinit(sm);
rsn_preauth_deinit(sm);
pmksa_cache_clear_current(sm);
if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
@@ -2105,6 +2299,11 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
#ifdef CONFIG_TDLS
wpa_tdls_disassoc(sm);
#endif /* CONFIG_TDLS */
+
+ /* Keys are not needed in the WPA state machine anymore */
+ wpa_sm_drop_sa(sm);
+
+ sm->msg_3_of_4_ok = 0;
}
@@ -2113,10 +2312,12 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @pmk: The new PMK
* @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
*
* Configure the PMK for WPA state machine.
*/
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+ const u8 *bssid)
{
if (sm == NULL)
return;
@@ -2129,6 +2330,12 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
sm->xxkey_len = pmk_len;
os_memcpy(sm->xxkey, pmk, pmk_len);
#endif /* CONFIG_IEEE80211R */
+
+ if (bssid) {
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+ bssid, sm->own_addr,
+ sm->network_ctx, sm->key_mgmt);
+ }
}
@@ -2208,6 +2415,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
} else
sm->ssid_len = 0;
sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+ sm->p2p = config->p2p;
} else {
sm->network_ctx = NULL;
sm->peerkey_enabled = 0;
@@ -2217,6 +2425,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
sm->eap_conf_ctx = NULL;
sm->ssid_len = 0;
sm->wpa_ptk_rekey = 0;
+ sm->p2p = 0;
}
}
@@ -2327,44 +2536,6 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
/**
- * wpa_sm_get_param - Get WPA state machine parameters
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @param: Parameter field
- * Returns: Parameter value
- */
-unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
-{
- if (sm == NULL)
- return 0;
-
- switch (param) {
- case RSNA_PMK_LIFETIME:
- return sm->dot11RSNAConfigPMKLifetime;
- case RSNA_PMK_REAUTH_THRESHOLD:
- return sm->dot11RSNAConfigPMKReauthThreshold;
- case RSNA_SA_TIMEOUT:
- return sm->dot11RSNAConfigSATimeout;
- case WPA_PARAM_PROTO:
- return sm->proto;
- case WPA_PARAM_PAIRWISE:
- return sm->pairwise_cipher;
- case WPA_PARAM_GROUP:
- return sm->group_cipher;
- case WPA_PARAM_KEY_MGMT:
- return sm->key_mgmt;
-#ifdef CONFIG_IEEE80211W
- case WPA_PARAM_MGMT_GROUP:
- return sm->mgmt_group_cipher;
-#endif /* CONFIG_IEEE80211W */
- case WPA_PARAM_RSN_ENABLED:
- return sm->rsn_enabled;
- default:
- return 0;
- }
-}
-
-
-/**
* wpa_sm_get_status - Get WPA state machine
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @buf: Buffer for status information
@@ -2389,7 +2560,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
wpa_cipher_txt(sm->pairwise_cipher),
wpa_cipher_txt(sm->group_cipher),
wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
@@ -2402,7 +2573,7 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
ret = os_snprintf(pos, end - pos, "pmf=%d\n",
(rsn.capabilities &
WPA_CAPABILITY_MFPR) ? 2 : 1);
- if (ret < 0 || ret >= end - pos)
+ if (os_snprintf_error(end - pos, ret))
return pos - buf;
pos += ret;
}
@@ -2412,6 +2583,21 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
}
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+ struct wpa_ie_data rsn;
+
+ if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+ return 0;
+
+ if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+ rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+ return 1;
+
+ return 0;
+}
+
+
/**
* wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2586,11 +2772,7 @@ int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
{
-#ifndef CONFIG_NO_WPA2
return pmksa_cache_list(sm->pmksa, buf, len);
-#else /* CONFIG_NO_WPA2 */
- return -1;
-#endif /* CONFIG_NO_WPA2 */
}
@@ -2602,6 +2784,11 @@ void wpa_sm_drop_sa(struct wpa_sm *sm)
os_memset(sm->pmk, 0, sizeof(sm->pmk));
os_memset(&sm->ptk, 0, sizeof(sm->ptk));
os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+#ifdef CONFIG_IEEE80211R
+ os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+ os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+ os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+#endif /* CONFIG_IEEE80211R */
}
@@ -2621,38 +2808,29 @@ void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
{
-#ifndef CONFIG_NO_WPA2
- pmksa_cache_flush(sm->pmksa, network_ctx);
-#endif /* CONFIG_NO_WPA2 */
+ pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
}
#ifdef CONFIG_WNM
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
{
- struct wpa_gtk_data gd;
-#ifdef CONFIG_IEEE80211W
- struct wpa_igtk_kde igd;
- u16 keyidx;
-#endif /* CONFIG_IEEE80211W */
u16 keyinfo;
u8 keylen; /* plaintext key len */
u8 *key_rsc;
- os_memset(&gd, 0, sizeof(gd));
-#ifdef CONFIG_IEEE80211W
- os_memset(&igd, 0, sizeof(igd));
-#endif /* CONFIG_IEEE80211W */
-
- keylen = wpa_cipher_key_len(sm->group_cipher);
- gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
- gd.alg = wpa_cipher_to_alg(sm->group_cipher);
- if (gd.alg == WPA_ALG_NONE) {
- wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
- return -1;
- }
-
if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+ struct wpa_gtk_data gd;
+
+ os_memset(&gd, 0, sizeof(gd));
+ keylen = wpa_cipher_key_len(sm->group_cipher);
+ gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+ gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+ if (gd.alg == WPA_ALG_NONE) {
+ wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+ return -1;
+ }
+
key_rsc = buf + 5;
keyinfo = WPA_GET_LE16(buf + 2);
gd.gtk_len = keylen;
@@ -2670,27 +2848,37 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
gd.gtk, gd.gtk_len);
if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+ os_memset(&gd, 0, sizeof(gd));
wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
"WNM mode");
return -1;
}
+ os_memset(&gd, 0, sizeof(gd));
#ifdef CONFIG_IEEE80211W
} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+ struct wpa_igtk_kde igd;
+ u16 keyidx;
+
+ os_memset(&igd, 0, sizeof(igd));
+ 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");
+ os_memset(&igd, 0, sizeof(igd));
return -1;
}
+ os_memset(&igd, 0, sizeof(igd));
#endif /* CONFIG_IEEE80211W */
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
@@ -2700,3 +2888,67 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
return 0;
}
#endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_rx_eapol_peerkey(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_peerkey *peerkey;
+
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!peerkey)
+ return 0;
+
+ wpa_sm_rx_eapol(sm, src_addr, buf, len);
+
+ return 1;
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_P2P
+
+int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
+{
+ if (sm == NULL || WPA_GET_BE32(sm->p2p_ip_addr) == 0)
+ return -1;
+ os_memcpy(buf, sm->p2p_ip_addr, 3 * 4);
+ return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+ if (rx_replay_counter == NULL)
+ return;
+
+ os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ sm->rx_replay_counter_set = 1;
+ wpa_printf(MSG_DEBUG, "Updated key replay counter");
+}
+
+
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
+ const u8 *ptk_kck, size_t ptk_kck_len,
+ const u8 *ptk_kek, size_t ptk_kek_len)
+{
+ if (ptk_kck && ptk_kck_len <= WPA_KCK_MAX_LEN) {
+ os_memcpy(sm->ptk.kck, ptk_kck, ptk_kck_len);
+ sm->ptk.kck_len = ptk_kck_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+ }
+ if (ptk_kek && ptk_kek_len <= WPA_KEK_MAX_LEN) {
+ os_memcpy(sm->ptk.kek, ptk_kek, ptk_kek_len);
+ sm->ptk.kek_len = ptk_kek_len;
+ wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+ }
+ sm->ptk_set = 1;
+}