/*
* 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.
* 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)
* @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
}
}
if (key_mic &&
- wpa_eapol_key_mic(kck, sm->key_mgmt, 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 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);
*/
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 (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->key_mgmt))
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 ||
sm->proto == WPA_PROTO_OSEN) ?
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);
}
"RSN: the new PMK matches with the "
"PMKID");
abort_cached = 0;
+ } else if (sa && !sm->cur_pmksa && pmkid) {
+ /*
+ * It looks like the authentication server
+ * derived mismatching MSK. This should not
+ * really happen, but bugs happen.. There is not
+ * much we can do here without knowing what
+ * exactly caused the server to misbehave.
+ */
+ wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+ "RSN: PMKID mismatch - authentication server may have derived different MSK?!");
+ return -1;
}
if (!sm->cur_pmksa)
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) {
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 ||
sm->proto == WPA_PROTO_OSEN) ?
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 = wpa_cipher_key_len(sm->pairwise_cipher) + 32;
#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);
}
if (sm->pairwise_cipher == WPA_CIPHER_TKIP) {
u8 buf[8];
/* 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);
+ 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;
}
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 ")",
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,
u16 ver, u16 key_info,
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;
+ 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 ||
sm->proto == WPA_PROTO_OSEN) ?
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 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;
}
struct rsn_pmksa_cache_entry *sa;
sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
- sm->ptk.kck, sizeof(sm->ptk.kck),
+ 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:
&gd->key_rsc_len, &gd->alg))
return -1;
- wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
- ie.gtk, ie.gtk_len);
+ wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in group key handshake",
+ ie.gtk, ie.gtk_len);
gd->keyidx = ie.gtk[0] & 0x3;
gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
!!(ie.gtk[0] & BIT(2)));
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) {
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) {
+#ifdef CONFIG_NO_RC4
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: RC4 not supported in the build");
+ return -1;
+#else /* CONFIG_NO_RC4 */
u8 ek[32];
if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
return -1;
}
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 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));
return -1;
}
os_memset(ek, 0, sizeof(ek));
+#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (maxkeylen % 8) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
(unsigned long) maxkeylen);
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data,
- 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");
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 ||
sm->proto == WPA_PROTO_OSEN) ?
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;
}
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;
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 "
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, sm->key_mgmt, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(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");
}
if (!ok && sm->ptk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(sm->ptk.kck, sm->key_mgmt, ver, buf, len,
- key->key_mic);
- if (os_memcmp_const(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");
/* 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) {
+#ifdef CONFIG_NO_RC4
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: RC4 not supported in the build");
+ return -1;
+#else /* CONFIG_NO_RC4 */
u8 ek[32];
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->ptk.kek, 16);
+ 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,
return -1;
}
os_memset(ek, 0, sizeof(ek));
+#endif /* CONFIG_NO_RC4 */
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
"WPA: No memory for AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8,
+ 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,
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);
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 */
}
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 = 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;
}
goto out;
}
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
- if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+ 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)",
goto out;
os_memcpy(tmp, buf, data_len);
key = (struct wpa_eapol_key *) (tmp + sizeof(struct ieee802_1x_hdr));
- key_data = (u8 *) (key + 1);
+ 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)
{
ret = 0;
goto out;
}
- wpa_eapol_key_dump(sm, key);
- key_data_len = WPA_GET_BE16(key->key_data_length);
- if (key_data_len > plen - sizeof(struct wpa_eapol_key)) {
+ 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 - sizeof(struct wpa_eapol_key)));
+ (unsigned int) (plen - keyhdrlen));
goto out;
}
}
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 */
ret = 1;
out:
- os_free(tmp);
+ bin_clear_free(tmp, data_len);
return ret;
}
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;
}
sm->dot11RSNAConfigPMKLifetime,
sm->dot11RSNAConfigPMKReauthThreshold,
sm->dot11RSNAConfigSATimeout);
- if (ret < 0 || (size_t) ret >= buflen)
+ if (os_snprintf_error(buflen, ret))
return 0;
len = ret;
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;
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
*/
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);
#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;
}
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;
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;
}
}
-#ifdef CONFIG_TESTING_OPTIONS
void wpa_sm_drop_sa(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
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 */
}
-#endif /* CONFIG_TESTING_OPTIONS */
int wpa_sm_has_ptk(struct wpa_sm *sm)
}
-void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
- const u8 *ptk_kek)
+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) {
- os_memcpy(sm->ptk.kck, ptk_kck, 16);
+ 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) {
- os_memcpy(sm->ptk.kek, ptk_kek, 16);
+ 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;