Cumulative patch from commit 3f56a2b7460a57a2b68b48b936be134bf04aa36d (DO NOT MERGE)
3f56a2b Ignore pmf=1 default if driver does not support PMF
fa38860 nl80211: Fix build with libnl 1.1
937403b Update copyright notices for the new year 2015
399e613 Add Suite B AKMs to key_mgmt capability list
5e3b519 Add Suite B 192-bit AKM
97ae35a Add HMAC-SHA384
98cd3d1 Preparations for variable length KCK and KEK
30bff1d Extend AES-CMAC routines to support 256-bit keys
86f9b1c nl80211: Fix default group key management index configuration
b5f045d Show supported group_mgmt capabilities
893e152 Interworking: More debug messages
f45bae5 Interworking: Add logging to track nai_realm_find_eap failures
5a5aab7 Interworking: Remove unnecessary NULL check
400de9b hostapd: Debug messages for dodgy RADIUS servers
ad905e4 wpa_gui: Sort frequency and signal numerically in the scan results dialog
c35e35e Add passive_scan configuration parameter
bff162a P2P: Fix NULL pointer dereference with SD query cancellation
630b323 nl80211: Increase netlink receive buffer size
Change-Id: I32d4bd934ad76e24c646e9925bb839b1ba2a148e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 9d257cc..79dc0f9 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1271,6 +1271,11 @@
sm->eap_if->aaaEapKeyDataLen = len;
sm->eap_if->aaaEapKeyAvailable = TRUE;
}
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p",
+ keys, keys ? keys->send : NULL,
+ keys ? keys->recv : NULL);
}
if (keys) {
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 650e9a8..877affe 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -269,7 +269,9 @@
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (wpa_key_mgmt_suite_b(akmp))
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+ else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index f71b028..1905dc9 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -849,34 +849,45 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info, key_data_length;
enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
SMK_M1, SMK_M3, SMK_ERROR } msg;
char *msgtxt;
struct wpa_eapol_ie_parse kde;
int ft;
- const u8 *eapol_key_ie;
- size_t eapol_key_ie_len;
+ const u8 *eapol_key_ie, *key_data;
+ size_t eapol_key_ie_len, keyhdrlen, mic_len;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
- if (data_len < sizeof(*hdr) + sizeof(*key))
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (data_len < sizeof(*hdr) + keyhdrlen)
return;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- key_data_length = WPA_GET_BE16(key->key_data_length);
+ if (mic_len == 24) {
+ key_data = (const u8 *) (key192 + 1);
+ key_data_length = WPA_GET_BE16(key192->key_data_length);
+ } else {
+ key_data = (const u8 *) (key + 1);
+ key_data_length = WPA_GET_BE16(key->key_data_length);
+ }
wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
" key_info=0x%x type=%u key_data_length=%u",
MAC2STR(sm->addr), key_info, key->type, key_data_length);
- if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+ if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
"key_data overflow (%d > %lu)",
key_data_length,
(unsigned long) (data_len - sizeof(*hdr) -
- sizeof(*key)));
+ keyhdrlen));
return;
}
@@ -1083,8 +1094,7 @@
wpa_sta_disconnect(wpa_auth, sm->addr);
return;
}
- if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
- &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, key_data_length, &kde) < 0) {
wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
"received EAPOL-Key msg 2/4 with "
"invalid Key Data contents");
@@ -1241,8 +1251,7 @@
*/
if (msg == SMK_ERROR) {
#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, (const u8 *) (key + 1),
- key_data_length);
+ wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1257,12 +1266,12 @@
wpa_request_new_ptk(sm);
#ifdef CONFIG_PEERKEY
} else if (msg == SMK_M1) {
- wpa_smk_m1(wpa_auth, sm, key, (const u8 *) (key + 1),
+ wpa_smk_m1(wpa_auth, sm, key, key_data,
key_data_length);
#endif /* CONFIG_PEERKEY */
} else if (key_data_length > 0 &&
- wpa_parse_kde_ies((const u8 *) (key + 1),
- key_data_length, &kde) == 0 &&
+ wpa_parse_kde_ies(key_data, key_data_length,
+ &kde) == 0 &&
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1300,8 +1309,7 @@
#ifdef CONFIG_PEERKEY
if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key, (const u8 *) (key + 1),
- key_data_length);
+ wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
return;
}
#endif /* CONFIG_PEERKEY */
@@ -1376,14 +1384,19 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- size_t len;
+ struct wpa_eapol_key_192 *key192;
+ size_t len, mic_len, keyhdrlen;
int alg;
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
int i;
+ u8 *key_data;
- len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
if (force_version)
version = force_version;
@@ -1430,6 +1443,8 @@
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1466,8 +1481,11 @@
os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
if (kde && !encr) {
- os_memcpy(key + 1, kde, kde_len);
- WPA_PUT_BE16(key->key_data_length, kde_len);
+ os_memcpy(key_data, kde, kde_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length, kde_len);
+ else
+ WPA_PUT_BE16(key->key_data_length, kde_len);
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1487,29 +1505,44 @@
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- if (aes_wrap(sm->PTK.kek, 16,
- (key_data_len - 8) / 8, buf,
- (u8 *) (key + 1))) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
+ (key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
os_free(buf);
return;
}
- WPA_PUT_BE16(key->key_data_length, key_data_len);
- } else {
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else if (sm->PTK.kek_len == 16) {
u8 ek[32];
os_memcpy(key->key_iv,
sm->group->Counter + WPA_NONCE_LEN - 16, 16);
inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
os_memcpy(ek, key->key_iv, 16);
- os_memcpy(ek + 16, sm->PTK.kek, 16);
- os_memcpy(key + 1, buf, key_data_len);
- rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
- WPA_PUT_BE16(key->key_data_length, key_data_len);
+ os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
+ os_memcpy(key_data, buf, key_data_len);
+ rc4_skip(ek, 32, 256, key_data, key_data_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else {
+ os_free(hdr);
+ os_free(buf);
+ return;
}
os_free(buf);
}
if (key_info & WPA_KEY_INFO_MIC) {
+ u8 *key_mic;
+
if (!sm->PTK_valid) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
@@ -1517,8 +1550,11 @@
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
- (u8 *) hdr, len, key->key_mic);
+
+ key_mic = key192->key_mic; /* same offset for key and key192 */
+ wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+ sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1526,7 +1562,7 @@
wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
- key->key_mic[0]++;
+ key_mic[0]++;
}
#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1575,23 +1611,27 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info;
int ret = 0;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = wpa_mic_len(akmp);
if (data_len < sizeof(*hdr) + sizeof(*key))
return -1;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- os_memcpy(mic, key->key_mic, 16);
- os_memset(key->key_mic, 0, 16);
- if (wpa_eapol_key_mic(PTK->kck, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key->key_mic) ||
- os_memcmp_const(mic, key->key_mic, 16) != 0)
+ os_memcpy(mic, key192->key_mic, mic_len);
+ os_memset(key192->key_mic, 0, mic_len);
+ if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
+ key_info & WPA_KEY_INFO_TYPE_MASK,
+ data, data_len, key192->key_mic) ||
+ os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
ret = -1;
- os_memcpy(key->key_mic, mic, 16);
+ os_memcpy(key192->key_mic, mic, mic_len);
return ret;
}
@@ -1839,7 +1879,8 @@
}
#endif /* CONFIG_IEEE80211R */
} else {
- wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+ sm->wpa_auth->cb.get_msk);
}
sm->req_replay_counter_used = 0;
@@ -1927,18 +1968,14 @@
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, struct wpa_ptk *ptk)
{
- size_t ptk_len = wpa_cipher_key_len(sm->pairwise) + 32;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
- return 0;
+ return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+ sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
+ ptk, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -2270,7 +2307,7 @@
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)) {
+ sm->PTK.tk, klen)) {
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
return;
}
@@ -3170,7 +3207,7 @@
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
- sm->PTK.kck, sizeof(sm->PTK.kck),
+ sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e061b5e..ef3249a 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -362,7 +362,7 @@
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len)
+ struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
@@ -374,7 +374,6 @@
const u8 *ssid = sm->wpa_auth->conf.ssid;
size_t ssid_len = sm->wpa_auth->conf.ssid_len;
-
if (sm->xxkey_len == 0) {
wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
"derivation");
@@ -396,13 +395,9 @@
wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
sm->pairwise);
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, sm->pmk_r1_name,
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -461,7 +456,8 @@
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
subelem[4] = gsm->GTK_len;
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
- if (aes_wrap(sm->PTK.kek, 16, key_len / 8, key, subelem + 13)) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
+ subelem + 13)) {
os_free(subelem);
return NULL;
}
@@ -493,7 +489,7 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
os_free(subelem);
return NULL;
@@ -745,7 +741,8 @@
ric_start = NULL;
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+ wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+ sm->wpa_auth->addr, 6,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
@@ -789,7 +786,7 @@
* optimized by adding the STA entry earlier.
*/
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen))
+ sm->PTK.tk, klen))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -807,7 +804,7 @@
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
- size_t buflen, ptk_len;
+ size_t buflen;
int ret;
u8 *pos, *end;
int pairwise;
@@ -892,13 +889,11 @@
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
- ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
- wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
- sm->wpa_auth->addr, pmk_r1_name,
- (u8 *) &sm->PTK, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->PTK, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, pmk_r1_name,
+ &sm->PTK, ptk_name, sm->wpa_key_mgmt,
+ pairwise) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
sm->PTK_valid = TRUE;
@@ -993,7 +988,8 @@
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
unsigned int count;
if (sm == NULL)
@@ -1108,7 +1104,8 @@
return -1;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+ if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+ sm->wpa_auth->addr, 5,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -1118,12 +1115,13 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, mic_len) != 0) {
wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
- wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
- wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC",
+ ftie->mic, mic_len);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 8592b90..7f83207 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -249,12 +249,17 @@
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA");
return -1;
+ }
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
- if (key == NULL)
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p",
+ sta->eapol_sm);
return -1;
+ }
if (keylen > *len)
keylen = *len;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 478bc95..7b2cd3e 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -248,7 +248,7 @@
u8 *buf, size_t len, const u8 *subelem,
size_t subelem_len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len);
+ struct wpa_ptk *ptk);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
void wpa_ft_install_ptk(struct wpa_state_machine *sm);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index c926765..f287297 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -205,6 +205,11 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -482,6 +487,8 @@
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
#ifdef CONFIG_IEEE80211R
@@ -562,6 +569,8 @@
}
if (0) {
}
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
#ifdef CONFIG_IEEE80211R
diff --git a/src/common/defs.h b/src/common/defs.h
index 2efb985..b5f4f80 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -50,6 +50,7 @@
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
@@ -58,7 +59,8 @@
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -91,9 +93,15 @@
WPA_KEY_MGMT_IEEE8021X_SUITE_B));
}
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
static inline int wpa_key_mgmt_suite_b(int akm)
{
- return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B);
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa(int akm)
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 803b8cc..97a4537 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -1192,6 +1192,7 @@
#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC11
+#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC12
#define WLAN_AKM_SUITE_CCKM 0x00409600
#define WLAN_AKM_SUITE_OSEN 0x506f9a01
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a573e11..de81d53 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
@@ -19,9 +20,34 @@
#include "wpa_common.h"
+static unsigned int wpa_kck_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
+static unsigned int wpa_kek_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 32;
+ return 16;
+}
+
+
+unsigned int wpa_mic_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @key_len: KCK length in octets
* @akmp: WPA_KEY_MGMT_* used in key derivation
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
@@ -38,18 +64,18 @@
* happened during final editing of the standard and the correct behavior is
* defined in the last draft (IEEE 802.11i/D10).
*/
-int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
- size_t len, u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic)
{
- u8 hash[SHA256_MAC_LEN];
+ u8 hash[SHA384_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
- return hmac_md5(key, 16, buf, len, mic);
+ return hmac_md5(key, key_len, buf, len, mic);
#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
- if (hmac_sha1(key, 16, buf, len, hash))
+ if (hmac_sha1(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
@@ -65,11 +91,18 @@
#endif /* CONFIG_HS20 */
#ifdef CONFIG_SUITEB
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- if (hmac_sha256(key, 16, buf, len, hash))
+ if (hmac_sha256(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_SUITEB192 */
default:
return -1;
}
@@ -92,8 +125,9 @@
* @nonce1: ANonce or SNonce
* @nonce2: SNonce or ANonce
* @ptk: Buffer for pairwise transient key
- * @ptk_len: Length of PTK
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -104,12 +138,14 @@
* Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
* Min(INonce, PNonce) || Max(INonce, PNonce))
*/
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256)
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *nonce1, const u8 *nonce2,
+ struct wpa_ptk *ptk, int akmp, int cipher)
{
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
@@ -129,27 +165,44 @@
WPA_NONCE_LEN);
}
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
- ptk, ptk_len);
+ tmp, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
- sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
- ptk_len);
+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, ptk_len);
wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
MAC2STR(addr1), MAC2STR(addr2));
wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
- wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+
+ os_memset(tmp, 0, sizeof(tmp));
+ return 0;
}
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic)
@@ -157,6 +210,12 @@
u8 *buf, *pos;
size_t buf_len;
+ if (kck_len != 16) {
+ wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+ (unsigned int) kck_len);
+ return -1;
+ }
+
buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
buf = os_malloc(buf_len);
if (buf == NULL)
@@ -413,6 +472,8 @@
#endif /* CONFIG_SAE */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
+ return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
return 0;
}
@@ -858,15 +919,17 @@
*
* IEEE Std 802.11r-2008 - 8.5.1.5.5
*/
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name)
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
@@ -882,7 +945,12 @@
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
+ sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -903,6 +971,19 @@
sha256_vector(6, addr, len, hash);
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+ os_memset(tmp, 0, sizeof(tmp));
+
+ return 0;
}
#endif /* CONFIG_IEEE80211R */
@@ -975,6 +1056,39 @@
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+/**
+ * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA384_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB192 */
+
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -1054,6 +1168,8 @@
return "OSEN";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
return "WPA2-EAP-SUITE-B";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return "WPA2-EAP-SUITE-B-192";
default:
return "UNKNOWN";
}
@@ -1082,6 +1198,8 @@
return WLAN_AKM_SUITE_OSEN;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
return WLAN_AKM_SUITE_8021X_SUITE_B;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return WLAN_AKM_SUITE_8021X_SUITE_B_192;
return 0;
}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 17bed34..091e317 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -63,8 +63,8 @@
#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
-#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
@@ -191,22 +191,38 @@
/* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
+struct wpa_eapol_key_192 {
+ u8 type;
+ /* Note: key_info, key_length, and key_data_length are unaligned */
+ u8 key_info[2]; /* big endian */
+ u8 key_length[2]; /* big endian */
+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+ u8 key_nonce[WPA_NONCE_LEN];
+ u8 key_iv[16];
+ u8 key_rsc[WPA_KEY_RSC_LEN];
+ u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+ u8 key_mic[24];
+ u8 key_data_length[2]; /* big endian */
+ /* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
+#define WPA_KCK_MAX_LEN 24
+#define WPA_KEK_MAX_LEN 32
+#define WPA_TK_MAX_LEN 32
+
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
*/
struct wpa_ptk {
- u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
- u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
- u8 tk1[16]; /* Temporal Key 1 (TK1) */
- union {
- u8 tk2[16]; /* Temporal Key 2 (TK2) */
- struct {
- u8 tx_mic_key[8];
- u8 rx_mic_key[8];
- } auth;
- } u;
-} STRUCT_PACKED;
+ u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+ size_t kck_len;
+ size_t kek_len;
+ size_t tk_len;
+};
/* WPA IE version 1
@@ -327,16 +343,17 @@
#endif /* _MSC_VER */
-int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
- size_t len, u8 *mic);
-void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
- const u8 *addr1, const u8 *addr2,
- const u8 *nonce1, const u8 *nonce2,
- u8 *ptk, size_t ptk_len, int use_sha256);
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic);
+int wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+ const u8 *addr1, const u8 *addr2,
+ const u8 *nonce1, const u8 *nonce2,
+ struct wpa_ptk *ptk, int akmp, int cipher);
#ifdef CONFIG_IEEE80211R
-int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
- u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
+ const u8 *ap_addr, u8 transaction_seqnum,
+ const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
const u8 *ric, size_t ric_len, u8 *mic);
@@ -349,10 +366,10 @@
void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
const u8 *r1kh_id, const u8 *s1kh_id,
u8 *pmk_r1, u8 *pmk_r1_name);
-void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
- const u8 *sta_addr, const u8 *bssid,
- const u8 *pmk_r1_name,
- u8 *ptk, size_t ptk_len, u8 *ptk_name);
+int wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+ const u8 *sta_addr, const u8 *bssid,
+ const u8 *pmk_r1_name,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -384,6 +401,16 @@
return -1;
}
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB192 */
+static inline int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB192 */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
@@ -429,5 +456,6 @@
int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+unsigned int wpa_mic_len(int akmp);
#endif /* WPA_COMMON_H */
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index c2b0686..375db57 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -1,5 +1,5 @@
/*
- * One-key CBC MAC (OMAC1) hash with AES-128
+ * One-key CBC MAC (OMAC1) hash with AES
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -27,8 +27,9 @@
/**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
@@ -39,15 +40,15 @@
* OMAC1 was standardized with the name CMAC by NIST in a Special Publication
* (SP) 800-38B.
*/
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
void *ctx;
u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
const u8 *pos, *end;
size_t i, e, left, total_len;
- ctx = aes_encrypt_init(key, 16);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
@@ -114,6 +115,26 @@
/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
* omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
* @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
@@ -129,3 +150,21 @@
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-bit key for the hash operation
+ * @data: Data buffer for which a MAC is determined
+ * @data_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 6b3727c..4a14209 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -2,7 +2,7 @@
* AES-based functions
*
* - AES Key Wrap Algorithm (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
@@ -22,11 +22,16 @@
u8 *cipher);
int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_vector(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac);
int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
const u8 *addr[], const size_t *len,
u8 *mac);
int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
u8 *mac);
+int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
+ u8 *mac);
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len);
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index adb42a4..f79055c 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,6 +28,7 @@
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
+#include "sha384.h"
#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
@@ -786,6 +787,40 @@
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HMAC_CTX ctx;
+ size_t i;
+ unsigned int mdlen;
+ int res;
+
+ HMAC_CTX_init(&ctx);
+ if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha384(), NULL) != 1)
+ return -1;
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(&ctx, addr[i], len[i]);
+
+ mdlen = 32;
+ res = HMAC_Final(&ctx, mac, &mdlen);
+ HMAC_CTX_cleanup(&ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
int crypto_get_random(void *buf, size_t len)
{
if (RAND_bytes(buf, len) != 1)
@@ -795,8 +830,8 @@
#ifdef CONFIG_OPENSSL_CMAC
-int omac1_aes_128_vector(const u8 *key, size_t num_elem,
- const u8 *addr[], const size_t *len, u8 *mac)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
CMAC_CTX *ctx;
int ret = -1;
@@ -806,8 +841,15 @@
if (ctx == NULL)
return -1;
- if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ if (key_len == 32) {
+ if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
+ goto fail;
+ } else if (key_len == 16) {
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ } else {
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (!CMAC_Update(ctx, addr[i], len[i]))
goto fail;
@@ -822,10 +864,23 @@
}
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/src/crypto/sha384.h b/src/crypto/sha384.h
new file mode 100644
index 0000000..e6a1fe4
--- /dev/null
+++ b/src/crypto/sha384.h
@@ -0,0 +1,19 @@
+/*
+ * SHA384 hash implementation and interface functions
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA384_H
+#define SHA384_H
+
+#define SHA384_MAC_LEN 48
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
+
+#endif /* SHA384_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index b8a7c51..c9e860f 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -1,6 +1,6 @@
/*
* Driver interface definition
- * Copyright (c) 2003-2014, 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.
@@ -1072,6 +1072,8 @@
#define WPA_DRIVER_CAPA_KEY_MGMT_FT 0x00000020
#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK 0x00000040
#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK 0x00000080
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B 0x00000100
+#define WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 0x00000200
/** Bitfield of supported key management suites */
unsigned int key_mgmt;
@@ -2859,14 +2861,17 @@
* set_rekey_info - Set rekey information
* @priv: Private driver interface data
* @kek: Current KEK
+ * @kek_len: KEK length in octets
* @kck: Current KCK
+ * @kck_len: KCK length in octets
* @replay_ctr: Current EAPOL-Key Replay Counter
*
* This optional function can be used to provide information for the
* driver/firmware to process EAPOL-Key frames in Group Key Handshake
* while the host (including wpa_supplicant) is sleeping.
*/
- void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+ void (*set_rekey_info)(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3ed9851..d681ea6 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2003-2004, Instant802 Networks, Inc.
* Copyright (c) 2005-2006, Devicescape Software, Inc.
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
@@ -132,6 +132,22 @@
eloop_sock_handler handler,
void *eloop_data)
{
+#ifdef CONFIG_LIBNL20
+ /*
+ * libnl uses a pretty small buffer (32 kB that gets converted to 64 kB)
+ * by default. It is possible to hit that limit in some cases where
+ * operations are blocked, e.g., with a burst of Deauthentication frames
+ * to hostapd and STA entry deletion. Try to increase the buffer to make
+ * this less likely to occur.
+ */
+ if (nl_socket_set_buffer_size(*handle, 262144, 0) < 0) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Could not set nl_socket RX buffer size: %s",
+ strerror(errno));
+ /* continue anyway with the default (smaller) buffer */
+ }
+#endif /* CONFIG_LIBNL20 */
+
nl_socket_set_nonblocking(*handle);
eloop_register_read_sock(nl_socket_get_fd(*handle), handler,
eloop_data, *handle);
@@ -2479,7 +2495,10 @@
msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
if (!msg ||
nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
- nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+ nla_put_flag(msg, (alg == WPA_ALG_IGTK ||
+ alg == WPA_ALG_BIP_GMAC_128 ||
+ alg == WPA_ALG_BIP_GMAC_256 ||
+ alg == WPA_ALG_BIP_CMAC_256) ?
NL80211_ATTR_KEY_DEFAULT_MGMT :
NL80211_ATTR_KEY_DEFAULT))
goto fail;
@@ -4446,7 +4465,8 @@
params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
- params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
int mgmt = WLAN_AKM_SUITE_PSK;
switch (params->key_mgmt_suite) {
@@ -4474,6 +4494,9 @@
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
break;
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ mgmt = WLAN_AKM_SUITE_8021X_SUITE_B_192;
+ break;
case WPA_KEY_MGMT_PSK:
default:
mgmt = WLAN_AKM_SUITE_PSK;
@@ -6764,7 +6787,8 @@
}
-static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr)
{
struct i802_bss *bss = priv;
@@ -6779,8 +6803,8 @@
wpa_printf(MSG_DEBUG, "nl80211: Set rekey offload");
if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
!(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
- nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
- nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+ nla_put(msg, NL80211_REKEY_DATA_KEK, kek_len, kek) ||
+ nla_put(msg, NL80211_REKEY_DATA_KCK, kck_len, kck) ||
nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
replay_ctr)) {
nl80211_nlmsg_clear(msg);
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 6e52bde..36c8ce2 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -1,6 +1,6 @@
/*
* Driver interaction with Linux nl80211/cfg80211 - Capabilities
- * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
* Copyright (c) 2009-2010, Atheros Communications
*
@@ -791,7 +791,9 @@
drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
+ WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
WPA_DRIVER_AUTH_SHARED |
WPA_DRIVER_AUTH_LEAP;
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index fc61081..f3e31a8 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -2847,7 +2847,7 @@
return;
}
- if (p2p->sd_query->for_all_peers) {
+ if (p2p->sd_query && p2p->sd_query->for_all_peers) {
/* Update the pending broadcast SD query count for this device
*/
p2p->sd_peer->sd_pending_bcast_queries--;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 6eba2eb..8d878a4 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -993,13 +993,16 @@
/* key: 16-bit salt followed by encrypted key info */
- if (len < 2 + 16)
+ if (len < 2 + 16) {
+ wpa_printf(MSG_DEBUG, "RADIUS: %s: Len is too small: %d",
+ __func__, (int) len);
return NULL;
+ }
pos = key + 2;
left = len - 2;
if (left % 16) {
- wpa_printf(MSG_INFO, "Invalid ms key len %lu",
+ wpa_printf(MSG_INFO, "RADIUS: Invalid ms key len %lu",
(unsigned long) left);
return NULL;
}
@@ -1034,7 +1037,7 @@
}
if (plain[0] == 0 || plain[0] > plen - 1) {
- wpa_printf(MSG_INFO, "Failed to decrypt MPPE key");
+ wpa_printf(MSG_INFO, "RADIUS: Failed to decrypt MPPE key");
os_free(plain);
return NULL;
}
@@ -1123,6 +1126,10 @@
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->send_len);
+ if (!keys->send) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt send key");
+ }
os_free(key);
}
@@ -1134,6 +1141,10 @@
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->recv_len);
+ if (!keys->recv) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS: Failed to decrypt recv key");
+ }
os_free(key);
}
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index aca8f54..79764d9 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -65,6 +65,7 @@
{
size_t rlen;
struct wpa_eapol_key *err;
+ struct wpa_eapol_key_192 *err192;
struct rsn_error_kde error;
u8 *rbuf, *pos;
size_t kde_len;
@@ -79,6 +80,7 @@
(void *) &err);
if (rbuf == NULL)
return -1;
+ err192 = (struct wpa_eapol_key_192 *) err;
err->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -112,8 +114,8 @@
"(mui %d error_type %d)", mui, error_type);
}
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
- rbuf, rlen, err->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst,
+ ETH_P_EAPOL, rbuf, rlen, err192->key_mic);
return 0;
}
@@ -126,6 +128,7 @@
{
size_t rlen;
struct wpa_eapol_key *reply;
+ struct wpa_eapol_key_192 *reply192;
u8 *rbuf, *pos;
size_t kde_len;
u16 key_info;
@@ -140,6 +143,7 @@
(void *) &reply);
if (rbuf == NULL)
return -1;
+ reply192 = (struct wpa_eapol_key_192 *) reply;
reply->type = EAPOL_KEY_TYPE_RSN;
key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
@@ -164,8 +168,8 @@
wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
- rbuf, rlen, reply->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr,
+ ETH_P_EAPOL, rbuf, rlen, reply192->key_mic);
return 0;
}
@@ -240,12 +244,7 @@
os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
peerkey->rsnie_i_len = kde.rsn_ie_len;
peerkey->cipher = cipher;
-#ifdef CONFIG_IEEE80211W
- if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_PSK_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = ie.key_mgmt;
if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -289,14 +288,14 @@
* @mac_p: Peer MAC address
* @inonce: Initiator Nonce
* @mac_i: Initiator MAC address
- * @use_sha256: Whether to use SHA256-based KDF
+ * @akmp: Negotiated AKM
*
* 8.5.1.4 Station to station (STK) key hierarchy
* SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
*/
static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
const u8 *inonce, const u8 *mac_i, u8 *smkid,
- int use_sha256)
+ int akmp)
{
char *title = "SMK Name";
const u8 *addr[5];
@@ -311,7 +310,7 @@
addr[4] = mac_i;
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
else
#endif /* CONFIG_IEEE80211W */
@@ -372,7 +371,7 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, NULL, 0, ver, peerkey->addr, ETH_P_EAPOL,
mbuf, mlen, NULL);
}
@@ -427,8 +426,9 @@
wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
MAC2STR(peerkey->addr));
- wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
- ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+ wpa_eapol_key_send(sm, peerkey->stk.kck, peerkey->stk.kck_len, ver,
+ peerkey->addr, ETH_P_EAPOL, mbuf, mlen,
+ msg->key_mic);
}
@@ -576,12 +576,12 @@
if (peerkey->initiator) {
rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
peerkey->inonce, sm->own_addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
wpa_supplicant_send_stk_1_of_4(sm, peerkey);
} else {
rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
peerkey->inonce, peerkey->addr, peerkey->smkid,
- peerkey->use_sha256);
+ peerkey->akmp);
}
wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
@@ -695,12 +695,11 @@
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->pnonce, key->key_nonce,
- (u8 *) stk, sizeof(*stk),
- peerkey->use_sha256);
+ stk, peerkey->akmp, peerkey->cipher);
/* Supplicant: swap tx/rx Mic keys */
- os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
- os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
- os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+ os_memcpy(buf, &stk->tk[16], 8);
+ os_memcpy(&stk->tk[16], &stk->tk[24], 8);
+ os_memcpy(&stk->tk[24], buf, 8);
peerkey->tstk_set = 1;
kde_buf_len = peerkey->rsnie_p_len +
@@ -856,12 +855,12 @@
&peerkey->stk))
return;
- _key = (u8 *) peerkey->stk.tk1;
+ _key = peerkey->stk.tk;
if (peerkey->cipher == WPA_CIPHER_TKIP) {
/* Swap Tx/Rx keys for Michael MIC */
os_memcpy(key_buf, _key, 16);
- os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
- os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+ os_memcpy(key_buf + 16, _key + 24, 8);
+ os_memcpy(key_buf + 24, _key + 16, 8);
_key = key_buf;
key_len = 32;
} else
@@ -870,10 +869,12 @@
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
rsc, sizeof(rsc), _key, key_len) < 0) {
+ os_memset(key_buf, 0, sizeof(key_buf));
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
return;
}
+ os_memset(key_buf, 0, sizeof(key_buf));
}
@@ -889,7 +890,7 @@
os_memset(rsc, 0, 6);
if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
- rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+ rsc, sizeof(rsc), peerkey->stk.tk,
peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
"driver.");
@@ -910,27 +911,27 @@
*/
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ 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];
+ size_t mic_len = 16;
int ok = 0;
if (peerkey->initiator && !peerkey->stk_set) {
wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
sm->own_addr, peerkey->addr,
peerkey->inonce, key->key_nonce,
- (u8 *) &peerkey->stk, sizeof(peerkey->stk),
- peerkey->use_sha256);
+ &peerkey->stk, peerkey->akmp, peerkey->cipher);
peerkey->stk_set = 1;
}
- os_memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, mic_len);
if (peerkey->tstk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->tstk.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(peerkey->tstk.kck, peerkey->tstk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"when using TSTK - ignoring TSTK");
} else {
@@ -939,14 +940,15 @@
peerkey->stk_set = 1;
os_memcpy(&peerkey->stk, &peerkey->tstk,
sizeof(peerkey->stk));
+ os_memset(&peerkey->tstk, 0, sizeof(peerkey->tstk));
}
}
if (!ok && peerkey->stk_set) {
- os_memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(peerkey->stk.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(peerkey->stk.kck, peerkey->stk.kck_len,
+ sm->key_mgmt, ver, buf, len, key->key_mic);
+ if (os_memcmp_const(mic, key->key_mic, mic_len) != 0) {
wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -1015,10 +1017,7 @@
return -1;
peerkey->initiator = 1;
os_memcpy(peerkey->addr, peer, ETH_ALEN);
-#ifdef CONFIG_IEEE80211W
- if (wpa_key_mgmt_sha256(sm->key_mgmt))
- peerkey->use_sha256 = 1;
-#endif /* CONFIG_IEEE80211W */
+ peerkey->akmp = sm->key_mgmt;
/* SMK M1:
* EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
@@ -1085,8 +1084,8 @@
wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
MACSTR ")", MAC2STR(peer));
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
- rbuf, rlen, req->key_mic);
+ wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid,
+ ETH_P_EAPOL, rbuf, rlen, req->key_mic);
peerkey->next = sm->peerkey;
sm->peerkey = peerkey;
diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h
index 4c17eae..6ccd948 100644
--- a/src/rsn_supp/peerkey.h
+++ b/src/rsn_supp/peerkey.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -27,7 +27,7 @@
int cipher; /* Selected cipher (WPA_CIPHER_*) */
u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
int replay_counter_set;
- int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+ int akmp;
struct wpa_ptk stk, tstk;
int stk_set, tstk_set;
@@ -38,7 +38,7 @@
int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_peerkey *peerkey,
- struct wpa_eapol_key *key, u16 ver,
+ struct wpa_eapol_key_192 *key, u16 ver,
const u8 *buf, size_t len);
void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
struct wpa_eapol_key *key, u16 key_info, u16 ver,
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 8af04d0..ef7b683 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -141,7 +141,9 @@
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (wpa_key_mgmt_suite_b(akmp))
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+ else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index af0e108..6356912 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -1,6 +1,6 @@
/*
* RSN pre-authentication (supplicant)
- * 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.
@@ -300,7 +300,8 @@
wpa_sm_get_state(sm) != WPA_COMPLETED ||
(sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
- sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B)) {
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B &&
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)) {
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
"state for new pre-authentication");
return; /* invalid state for new pre-auth */
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 8ea54bb..b892a66 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 @@
}
}
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);
@@ -84,10 +88,11 @@
*/
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))
@@ -106,10 +111,13 @@
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) ?
@@ -127,15 +135,21 @@
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);
}
@@ -301,9 +315,10 @@
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) {
@@ -345,13 +360,16 @@
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) ?
@@ -367,35 +385,38 @@
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);
}
@@ -462,9 +483,9 @@
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;
@@ -601,7 +622,7 @@
}
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 ")",
@@ -610,8 +631,7 @@
}
/* TK is not needed anymore in supplicant */
- os_memset(sm->ptk.tk1, 0, sizeof(sm->ptk.tk1));
- os_memset(sm->ptk.u.tk2, 0, sizeof(sm->ptk.u.tk2));
+ os_memset(sm->ptk.tk, 0, WPA_TK_MAX_LEN);
if (sm->wpa_ptk_rekey) {
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
@@ -1062,14 +1082,18 @@
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) ?
@@ -1084,11 +1108,15 @@
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;
}
@@ -1209,7 +1237,7 @@
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)
@@ -1303,7 +1331,7 @@
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) {
u8 ek[32];
if (key_data_len > sizeof(gd->gtk)) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1312,7 +1340,7 @@
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));
@@ -1336,8 +1364,8 @@
(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");
@@ -1358,14 +1386,18 @@
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) ?
@@ -1380,11 +1412,15 @@
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;
}
@@ -1451,19 +1487,20 @@
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");
@@ -1477,10 +1514,10 @@
}
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");
@@ -1519,10 +1556,10 @@
/* 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);
+ 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,
@@ -1548,7 +1585,7 @@
"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,
@@ -1585,7 +1622,9 @@
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);
@@ -1607,15 +1646,14 @@
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 */
}
@@ -1642,22 +1680,27 @@
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;
}
@@ -1679,7 +1722,7 @@
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)",
@@ -1702,7 +1745,12 @@
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)
{
@@ -1712,14 +1760,18 @@
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;
}
@@ -1869,12 +1921,13 @@
}
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 */
@@ -1964,6 +2017,8 @@
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;
}
@@ -2870,15 +2925,18 @@
}
-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;
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index cc12893..e163b70 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2007, 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.
@@ -73,7 +73,8 @@
const struct hostapd_freq_params *params);
int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
#endif /* CONFIG_TDLS */
- void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+ void (*set_rekey_offload)(void *ctx, const u8 *kek, size_t kek_len,
+ const u8 *kck, size_t kck_len,
const u8 *replay_ctr);
int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
};
@@ -155,8 +156,9 @@
int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
-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);
#else /* CONFIG_NO_WPA */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 3b3c9d0..06dea05 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -19,8 +19,7 @@
#ifdef CONFIG_IEEE80211R
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len)
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk)
{
u8 ptk_name[WPA_PMK_NAME_LEN];
const u8 *anonce = key->key_nonce;
@@ -43,13 +42,9 @@
wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
WPA_PMK_NAME_LEN);
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
- sm->bssid, sm->pmk_r1_name,
- (u8 *) ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
-
- return 0;
+ return wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
+ sm->bssid, sm->pmk_r1_name, ptk, ptk_name,
+ sm->key_mgmt, sm->pairwise_cipher);
}
@@ -134,6 +129,7 @@
* @anonce: ANonce or %NULL if not yet available
* @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
* @kck: 128-bit KCK for MIC or %NULL if no MIC is used
+ * @kck_len: KCK length in octets
* @target_ap: Target AP address
* @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
* @ric_ies_len: Length of ric_ies buffer in octets
@@ -144,7 +140,8 @@
*/
static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
const u8 *anonce, const u8 *pmk_name,
- const u8 *kck, const u8 *target_ap,
+ const u8 *kck, size_t kck_len,
+ const u8 *target_ap,
const u8 *ric_ies, size_t ric_ies_len,
const u8 *ap_mdie)
{
@@ -298,7 +295,7 @@
/* Information element count */
ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
ric_ies_len);
- if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
+ if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
@@ -333,7 +330,7 @@
keylen = wpa_cipher_key_len(sm->pairwise_cipher);
if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
- sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
+ sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
return -1;
}
@@ -360,7 +357,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, sm->bssid, NULL, 0, mdie);
+ NULL, 0, sm->bssid, NULL, 0, mdie);
if (ft_ies) {
wpa_sm_update_ft_ies(sm, sm->mobility_domain,
ft_ies, ft_ies_len);
@@ -376,7 +373,7 @@
const u8 *ric_ies, size_t ric_ies_len)
{
u8 *ft_ies;
- size_t ft_ies_len, ptk_len;
+ size_t ft_ies_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
@@ -478,16 +475,14 @@
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
- ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
- wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
- bssid, sm->pmk_r1_name,
- (u8 *) &sm->ptk, ptk_len, ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->ptk, ptk_len);
- wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+ if (wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce,
+ sm->own_addr, bssid, sm->pmk_r1_name, &sm->ptk,
+ ptk_name, sm->key_mgmt, sm->pairwise_cipher) < 0)
+ return -1;
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
- sm->pmk_r1_name, sm->ptk.kck, bssid,
+ sm->pmk_r1_name,
+ sm->ptk.kck, sm->ptk.kck_len, bssid,
ric_ies, ric_ies_len,
parse.mdie ? parse.mdie - 2 : NULL);
if (ft_ies) {
@@ -566,7 +561,8 @@
return -1;
}
gtk_len = gtk_elem_len - 19;
- if (aes_unwrap(sm->ptk.kek, 16, gtk_len / 8, gtk_elem + 11, gtk)) {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11,
+ gtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt GTK");
return -1;
@@ -645,8 +641,8 @@
return -1;
}
- if (aes_unwrap(sm->ptk.kek, 16, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk))
- {
+ if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8,
+ igtk_elem + 9, igtk)) {
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
"decrypt IGTK");
return -1;
@@ -677,7 +673,7 @@
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
unsigned int count;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
@@ -770,7 +766,7 @@
return -1;
}
- if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
+ if (wpa_ft_mic(sm->ptk.kck, sm->ptk.kck_len, sm->own_addr, src_addr, 6,
parse.mdie - 2, parse.mdie_len + 2,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
@@ -839,7 +835,7 @@
}
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
- NULL, target_ap, NULL, 0, mdie);
+ NULL, 0, target_ap, NULL, 0, mdie);
if (ft_ies) {
sm->over_the_ds_in_progress = 1;
os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 07f3692..431bb20 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -1,6 +1,6 @@
/*
* Internal WPA/RSN supplicant state machine definitions
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -254,8 +254,9 @@
{
if (!sm->ctx->set_rekey_offload)
return;
- sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
- sm->ptk.kck, sm->rx_replay_counter);
+ sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek, sm->ptk.kek_len,
+ sm->ptk.kck, sm->ptk.kck_len,
+ sm->rx_replay_counter);
}
#ifdef CONFIG_TDLS
@@ -347,7 +348,7 @@
return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
}
-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);
int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
@@ -361,8 +362,7 @@
struct wpa_ptk *ptk);
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
- const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk, size_t ptk_len);
+ const struct wpa_eapol_key *key, struct wpa_ptk *ptk);
void wpa_tdls_assoc(struct wpa_sm *sm);
void wpa_tdls_disassoc(struct wpa_sm *sm);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 51876ed..cb334df 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2008, 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.
@@ -173,6 +173,8 @@
} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
#endif /* CONFIG_SAE */
+ } else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
} else {