* IEEE 802.11 RSN / WPA Authenticator
* Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
*/
#include "utils/includes.h"
static const int dot11RSNAConfigSATimeout = 60;
-static inline void wpa_auth_mic_failure_report(
+static inline int wpa_auth_mic_failure_report(
struct wpa_authenticator *wpa_auth, const u8 *addr)
{
if (wpa_auth->cb.mic_failure_report)
- wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+ return 0;
}
}
-static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- group->GTK_len = 16;
- break;
- case WPA_CIPHER_TKIP:
- group->GTK_len = 32;
- break;
- case WPA_CIPHER_WEP104:
- group->GTK_len = 13;
- break;
- case WPA_CIPHER_WEP40:
- group->GTK_len = 5;
- break;
- }
-}
-
-
static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
- u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
u8 rkey[32];
+ unsigned long ptr;
if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
return -1;
*/
os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
wpa_get_ntp_timestamp(buf + ETH_ALEN);
- os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+ ptr = (unsigned long) group;
+ os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
if (random_get_bytes(rkey, sizeof(rkey)) < 0)
return -1;
group->GTKAuthenticator = TRUE;
group->vlan_id = vlan_id;
-
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
if (random_pool_ready() != 1) {
wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
* configuration.
*/
group = wpa_auth->group;
- wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
group->GInit = TRUE;
wpa_group_sm_step(wpa_auth, group);
group->GInit = FALSE;
}
-static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
+static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,
const u8 *replay_counter)
{
int i;
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
- if (!sm->key_replay[i].valid)
+ if (!ctr[i].valid)
break;
- if (os_memcmp(replay_counter, sm->key_replay[i].counter,
+ if (os_memcmp(replay_counter, ctr[i].counter,
WPA_REPLAY_COUNTER_LEN) == 0)
return 1;
}
}
+static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
+ const u8 *replay_counter)
+{
+ int i;
+ for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+ if (ctr[i].valid &&
+ (replay_counter == NULL ||
+ os_memcmp(replay_counter, ctr[i].counter,
+ WPA_REPLAY_COUNTER_LEN) == 0))
+ ctr[i].valid = FALSE;
+ }
+}
+
+
#ifdef CONFIG_IEEE80211R
static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm,
#endif /* CONFIG_IEEE80211R */
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
- struct wpa_state_machine *sm, int group)
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+ struct wpa_state_machine *sm, int group)
{
/* Supplicant reported a Michael MIC error */
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"ignore Michael MIC failure report since "
"pairwise cipher is not TKIP");
} else {
- wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+ if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+ return 1; /* STA entry was removed */
sm->dot11RSNAStatsTKIPRemoteMICFailures++;
wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
}
* Authenticator may do it, let's change the keys now anyway.
*/
wpa_request_new_ptk(sm);
+ return 0;
}
}
if (sm->wpa == WPA_VERSION_WPA2) {
- if (key->type != EAPOL_KEY_TYPE_RSN) {
+ if (key->type == EAPOL_KEY_TYPE_WPA) {
+ /*
+ * Some deployed station implementations seem to send
+ * msg 4/4 with incorrect type value in WPA2 mode.
+ */
+ wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
+ "with unexpected WPA type in RSN mode");
+ } else if (key->type != EAPOL_KEY_TYPE_RSN) {
wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
"unexpected type %d in RSN mode",
key->type);
if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
msg == GROUP_2) {
u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
- if (sm->pairwise == WPA_CIPHER_CCMP) {
+ if (sm->pairwise == WPA_CIPHER_CCMP ||
+ sm->pairwise == WPA_CIPHER_GCMP) {
if (wpa_use_aes_cmac(sm) &&
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
wpa_auth_logger(wpa_auth, sm->addr,
wpa_auth_logger(wpa_auth, sm->addr,
LOGGER_WARNING,
"did not use HMAC-SHA1-AES "
- "with CCMP");
+ "with CCMP/GCMP");
return;
}
}
}
if (!(key_info & WPA_KEY_INFO_REQUEST) &&
- !wpa_replay_counter_valid(sm, key->replay_counter)) {
+ !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
int i;
- wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
- "received EAPOL-Key %s with unexpected "
- "replay counter", msgtxt);
+
+ if (msg == PAIRWISE_2 &&
+ wpa_replay_counter_valid(sm->prev_key_replay,
+ key->replay_counter) &&
+ sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+ os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0)
+ {
+ /*
+ * Some supplicant implementations (e.g., Windows XP
+ * WZC) update SNonce for each EAPOL-Key 2/4. This
+ * breaks the workaround on accepting any of the
+ * pending requests, so allow the SNonce to be updated
+ * even if we have already sent out EAPOL-Key 3/4.
+ */
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "Process SNonce update from STA "
+ "based on retransmitted EAPOL-Key "
+ "1/4");
+ sm->update_snonce = 1;
+ wpa_replay_counter_mark_invalid(sm->prev_key_replay,
+ key->replay_counter);
+ goto continue_processing;
+ }
+
+ if (msg == PAIRWISE_2 &&
+ wpa_replay_counter_valid(sm->prev_key_replay,
+ key->replay_counter) &&
+ sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "ignore retransmitted EAPOL-Key %s - "
+ "SNonce did not change", msgtxt);
+ } else {
+ wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+ "received EAPOL-Key %s with "
+ "unexpected replay counter", msgtxt);
+ }
for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
if (!sm->key_replay[i].valid)
break;
return;
}
+continue_processing:
switch (msg) {
case PAIRWISE_2:
if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
- sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING) {
+ sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
+ (!sm->update_snonce ||
+ sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key msg 2/4 in "
"invalid state (%d) - dropped",
wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
"collect more entropy for random number "
"generation");
- sm->group->reject_4way_hs_for_entropy = FALSE;
random_mark_pool_ready();
- sm->group->first_sta_seen = FALSE;
wpa_sta_disconnect(wpa_auth, sm->addr);
return;
}
}
sm->MICVerified = FALSE;
- if (sm->PTK_valid) {
+ if (sm->PTK_valid && !sm->update_snonce) {
if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key with invalid MIC");
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
- wpa_receive_error_report(
- wpa_auth, sm,
- !(key_info & WPA_KEY_INFO_KEY_TYPE));
+ if (wpa_receive_error_report(
+ wpa_auth, sm,
+ !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+ return; /* STA entry was removed */
} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key Request for new "
wpa_rekey_gtk(wpa_auth, NULL);
}
} else {
- /* Do not allow the same key replay counter to be reused. This
- * does also invalidate all other pending replay counters if
- * retransmissions were used, i.e., we will only process one of
- * the pending replies and ignore rest if more than one is
- * received. */
- sm->key_replay[0].valid = FALSE;
+ /* Do not allow the same key replay counter to be reused. */
+ wpa_replay_counter_mark_invalid(sm->key_replay,
+ key->replay_counter);
+
+ if (msg == PAIRWISE_2) {
+ /*
+ * Maintain a copy of the pending EAPOL-Key frames in
+ * case the EAPOL-Key frame was retransmitted. This is
+ * needed to allow EAPOL-Key msg 2/4 reply to another
+ * pending msg 1/4 to update the SNonce to work around
+ * unexpected supplicant behavior.
+ */
+ os_memcpy(sm->prev_key_replay, sm->key_replay,
+ sizeof(sm->key_replay));
+ } else {
+ os_memset(sm->prev_key_replay, 0,
+ sizeof(sm->prev_key_replay));
+ }
+
+ /*
+ * Make sure old valid counters are not accepted anymore and
+ * do not get copied again.
+ */
+ wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
}
#ifdef CONFIG_PEERKEY
version = force_version;
else if (wpa_use_aes_cmac(sm))
version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
- else if (sm->pairwise == WPA_CIPHER_CCMP)
+ else if (sm->pairwise != WPA_CIPHER_TKIP)
version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
else
version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
WPA_PUT_BE16(key->key_info, key_info);
alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
- switch (alg) {
- case WPA_CIPHER_CCMP:
- WPA_PUT_BE16(key->key_length, 16);
- break;
- case WPA_CIPHER_TKIP:
- WPA_PUT_BE16(key->key_length, 32);
- break;
- case WPA_CIPHER_WEP40:
- WPA_PUT_BE16(key->key_length, 5);
- break;
- case WPA_CIPHER_WEP104:
- WPA_PUT_BE16(key->key_length, 13);
- break;
- }
+ WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
WPA_PUT_BE16(key->key_length, 0);
}
-static enum wpa_alg wpa_alg_enum(int alg)
-{
- switch (alg) {
- case WPA_CIPHER_CCMP:
- return WPA_ALG_CCMP;
- case WPA_CIPHER_TKIP:
- return WPA_ALG_TKIP;
- case WPA_CIPHER_WEP104:
- case WPA_CIPHER_WEP40:
- return WPA_ALG_WEP;
- default:
- return WPA_ALG_NONE;
- }
-}
-
-
SM_STATE(WPA_PTK, INITIALIZE)
{
SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
}
-static void wpa_group_first_station(struct wpa_authenticator *wpa_auth,
- struct wpa_group *group)
+static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group)
{
+ if (group->first_sta_seen)
+ return;
/*
* System has run bit further than at the time hostapd was started
* potentially very early during boot up. This provides better chances
wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
"to proceed - reject first 4-way handshake");
group->reject_4way_hs_for_entropy = TRUE;
+ } else {
+ group->first_sta_seen = TRUE;
+ group->reject_4way_hs_for_entropy = FALSE;
}
+
wpa_group_init_gmk_and_counter(wpa_auth, group);
wpa_gtk_update(wpa_auth, group);
wpa_group_config_group_keys(wpa_auth, group);
{
SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
- if (!sm->group->first_sta_seen) {
- wpa_group_first_station(sm->wpa_auth, sm->group);
- sm->group->first_sta_seen = TRUE;
- }
+ wpa_group_ensure_init(sm->wpa_auth, sm->group);
- os_memcpy(sm->ANonce, sm->group->Counter, WPA_NONCE_LEN);
+ /*
+ * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+ * ambiguous. The Authenticator state machine uses a counter that is
+ * incremented by one for each 4-way handshake. However, the security
+ * analysis of 4-way handshake points out that unpredictable nonces
+ * help in preventing precomputation attacks. Instead of the state
+ * machine definition, use an unpredictable nonce value here to provide
+ * stronger protection against potential precomputation attacks.
+ */
+ if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+ wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+ "ANonce.");
+ wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+ return;
+ }
wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
WPA_NONCE_LEN);
- inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
sm->ReAuthenticationRequest = FALSE;
/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
* logical place than INITIALIZE since AUTHENTICATION2 can be
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk)
{
- size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
+ size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
+ sm->update_snonce = FALSE;
/* WPA with IEEE 802.1X: use the derived PMK from EAP
* WPA-PSK: iterate through possible PSKs and select the one matching
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
os_memset(igtk.pn, 0, sizeof(igtk.pn));
os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_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)
+ return pos;
+ }
pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
(const u8 *) &igtk, sizeof(igtk), NULL, 0);
SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
{
- u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+ u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
size_t gtk_len, kde_len;
struct wpa_group *gsm = sm->group;
u8 *wpa_ie;
secure = 1;
gtk = gsm->GTK[gsm->GN - 1];
gtk_len = gsm->GTK_len;
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
keyidx = gsm->GN;
_rsc = rsc;
encr = 1;
SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
sm->EAPOLKeyReceived = FALSE;
if (sm->Pair) {
- enum wpa_alg alg;
- int klen;
- if (sm->pairwise == WPA_CIPHER_TKIP) {
- alg = WPA_ALG_TKIP;
- klen = 32;
- } else {
- alg = WPA_ALG_CCMP;
- klen = 16;
- }
+ enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+ int klen = wpa_cipher_key_len(sm->pairwise);
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
sm->PTK.tk1, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
break;
case WPA_PTK_PTKINITNEGOTIATING:
- if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
- sm->EAPOLKeyPairwise && sm->MICVerified)
+ if (sm->update_snonce)
+ SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+ else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+ sm->EAPOLKeyPairwise && sm->MICVerified)
SM_ENTER(WPA_PTK, PTKINITDONE);
else if (sm->TimeoutCtr >
(int) dot11RSNAConfigPairwiseUpdateCount) {
struct wpa_group *gsm = sm->group;
u8 *kde, *pos, hdr[2];
size_t kde_len;
+ u8 *gtk, dummy_gtk[32];
SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"sending 1/2 msg of Group Key Handshake");
+ gtk = gsm->GTK[gsm->GN - 1];
+ if (sm->wpa_auth->conf.disable_gtk) {
+ /*
+ * Provide unique random GTK to each STA to prevent use
+ * of GTK in the BSS.
+ */
+ if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+ return;
+ gtk = dummy_gtk;
+ }
if (sm->wpa == WPA_VERSION_WPA2) {
kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
ieee80211w_kde_len(sm);
hdr[0] = gsm->GN & 0x03;
hdr[1] = 0;
pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
- gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ gtk, gsm->GTK_len);
pos = ieee80211w_kde_add(sm, pos);
} else {
- kde = gsm->GTK[gsm->GN - 1];
+ kde = gtk;
pos = kde + gsm->GTK_len;
}
static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
{
+ if (ctx != NULL && ctx != sm->group)
+ return 0;
+
if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"Not in PTKINITDONE; skip Group Key update");
"marking station for GTK rekeying");
}
+ /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
+ if (sm->is_wnmsleep)
+ return 0;
+
sm->group->GKeyDoneStations++;
sm->GUpdateStationKeys = TRUE;
}
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+ if (sm->is_wnmsleep)
+ return;
+
+ wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+ sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+
+ /*
+ * GTK subelement:
+ * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+ * Key[5..32]
+ */
+ *pos++ = WNM_SLEEP_SUBELEM_GTK;
+ *pos++ = 11 + gsm->GTK_len;
+ /* Key ID in B0-B1 of Key Info */
+ WPA_PUT_LE16(pos, gsm->GN & 0x03);
+ pos += 2;
+ *pos++ = gsm->GTK_len;
+ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
+ return 0;
+ pos += 8;
+ os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+ pos += gsm->GTK_len;
+
+ wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+ gsm->GN);
+ wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
+ gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+
+ return pos - start;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+ struct wpa_group *gsm = sm->group;
+ u8 *start = pos;
+
+ /*
+ * 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;
+ 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;
+
+ 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);
+
+ return pos - start;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_WNM */
+
+
static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
struct wpa_group *group)
{
group->GKeyDoneStations);
group->GKeyDoneStations = 0;
}
- wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+ wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
group->GKeyDoneStations);
}
int ret = 0;
if (wpa_auth_set_key(wpa_auth, group->vlan_id,
- wpa_alg_enum(wpa_auth->conf.wpa_group),
+ wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
broadcast_ether_addr, group->GN,
group->GTK[group->GN - 1], group->GTK_len) < 0)
ret = -1;
}
-static int wpa_cipher_bits(int cipher)
-{
- switch (cipher) {
- case WPA_CIPHER_CCMP:
- return 128;
- case WPA_CIPHER_TKIP:
- return 256;
- case WPA_CIPHER_WEP104:
- return 104;
- case WPA_CIPHER_WEP40:
- return 40;
- default:
- return 0;
- }
-}
-
-
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) \
((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
!!wpa_auth->conf.wpa_strict_rekey,
dot11RSNAConfigGroupUpdateCount,
dot11RSNAConfigPairwiseUpdateCount,
- wpa_cipher_bits(wpa_auth->conf.wpa_group),
+ wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
dot11RSNAConfigPMKLifetime,
dot11RSNAConfigPMKReauthThreshold,
dot11RSNAConfigSATimeout,
/* dot11RSNAStatsEntry */
- if (sm->wpa == WPA_VERSION_WPA) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = WPA_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = WPA_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = WPA_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = WPA_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = WPA_CIPHER_SUITE_NONE;
- } else if (sm->wpa == WPA_VERSION_WPA2) {
- if (sm->pairwise == WPA_CIPHER_CCMP)
- pairwise = RSN_CIPHER_SUITE_CCMP;
- else if (sm->pairwise == WPA_CIPHER_TKIP)
- pairwise = RSN_CIPHER_SUITE_TKIP;
- else if (sm->pairwise == WPA_CIPHER_WEP104)
- pairwise = RSN_CIPHER_SUITE_WEP104;
- else if (sm->pairwise == WPA_CIPHER_WEP40)
- pairwise = RSN_CIPHER_SUITE_WEP40;
- else if (sm->pairwise == WPA_CIPHER_NONE)
- pairwise = RSN_CIPHER_SUITE_NONE;
- } else
+ pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+ WPA_PROTO_RSN : WPA_PROTO_WPA,
+ sm->pairwise);
+ if (pairwise == 0)
return 0;
ret = os_snprintf(
wpa_send_eapol_timeout, wpa_auth, sm);
}
}
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}