diff options
68 files changed, 1131 insertions, 420 deletions
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS index d20a5566..ca09bae6 100644 --- a/CONTRIBUTIONS +++ b/CONTRIBUTIONS @@ -112,7 +112,7 @@ The license terms used for hostap.git files Modified BSD license (no advertisement clause): -Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. Redistribution and use in source and binary forms, with or without @@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. @@ -1,7 +1,7 @@ wpa_supplicant and hostapd -------------------------- -Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. These programs are licensed under the BSD license (the one with diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 4e6a36ee..c8ef46b9 100644 --- a/hostapd/Android.mk +++ b/hostapd/Android.mk @@ -215,6 +215,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_SUITEB192 +L_CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y @@ -768,6 +773,9 @@ ifdef NEED_TLS_PRF_SHA256 OBJS += src/crypto/sha256-tlsprf.c endif endif +ifdef NEED_SHA384 +L_CFLAGS += -DCONFIG_SHA384 +endif ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c diff --git a/hostapd/Makefile b/hostapd/Makefile index e231e744..894b6527 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -204,6 +204,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_SUITEB192 +CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + ifdef CONFIG_IEEE80211W CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y @@ -764,6 +769,9 @@ ifdef NEED_HMAC_SHA256_KDF OBJS += ../src/crypto/sha256-kdf.o endif endif +ifdef NEED_SHA384 +CFLAGS += -DCONFIG_SHA384 +endif ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o diff --git a/hostapd/README b/hostapd/README index ea016cc5..366b1998 100644 --- a/hostapd/README +++ b/hostapd/README @@ -2,7 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP Authenticator and RADIUS authentication server ================================================================ -Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 99cd0528..7cbb46b4 100644 --- a/hostapd/config_file.c +++ b/hostapd/config_file.c @@ -1,6 +1,6 @@ /* * hostapd / Configuration file parser - * 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. @@ -680,8 +680,14 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value) else if (os_strcmp(start, "FT-SAE") == 0) val |= WPA_KEY_MGMT_FT_SAE; #endif /* CONFIG_SAE */ +#ifdef CONFIG_SUITEB else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; +#endif /* CONFIG_SUITEB192 */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index bef16b15..54b17dc9 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -1,6 +1,6 @@ /* * hostapd / UNIX domain socket -based control interface - * 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. @@ -1171,6 +1171,14 @@ static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd, return pos - buf; pos += ret; } + if (hapd->conf->wpa_key_mgmt & + WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + ret = os_snprintf(pos, end - pos, + "WPA-EAP-SUITE-B-192 "); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } ret = os_snprintf(pos, end - pos, "\n"); if (os_snprintf_error(end - pos, ret)) diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index 70091842..3f00cbbf 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -1,6 +1,6 @@ /* * hostapd - command line interface for hostapd daemon - * 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. @@ -18,7 +18,7 @@ static const char *hostapd_cli_version = "hostapd_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors"; static const char *hostapd_cli_license = diff --git a/hostapd/main.c b/hostapd/main.c index 3ecd009d..dd389a8d 100644 --- a/hostapd/main.c +++ b/hostapd/main.c @@ -1,6 +1,6 @@ /* * hostapd / main() - * Copyright (c) 2002-2011, 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. @@ -424,7 +424,7 @@ static void show_version(void) "hostapd v" VERSION_STR "\n" "User space daemon for IEEE 802.11 AP management,\n" "IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n" - "Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> " + "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> " "and contributors\n"); } diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c index 9d257cc3..79dc0f95 100644 --- a/src/ap/ieee802_1x.c +++ b/src/ap/ieee802_1x.c @@ -1271,6 +1271,11 @@ static void ieee802_1x_get_keys(struct hostapd_data *hapd, 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 650e9a81..877affe4 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 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa, 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 f71b0285..1905dc94 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 @@ void wpa_receive(struct wpa_authenticator *wpa_auth, { 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 @@ continue_processing: 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 @@ continue_processing: */ 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 @@ continue_processing: 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 @@ continue_processing: #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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, { 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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, 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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, 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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, 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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, 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 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, 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 @@ static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data, { 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 @@ SM_STATE(WPA_PTK, INITPMK) } #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 @@ SM_STATE(WPA_PTK, PTKSTART) 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 @@ SM_STATE(WPA_PTK, PTKINITDONE) 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 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk, 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 e061b5e1..ef3249a3 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 @@ static int wpa_ft_pull_pmk_r1(struct wpa_state_machine *sm, 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 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, 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 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, 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 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len) 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 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len) 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 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos, 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 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm) * 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 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, 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 @@ static int wpa_ft_process_auth_req(struct wpa_state_machine *sm, 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 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, 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 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, 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 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies, 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 8592b90b..7f832070 100644 --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -249,12 +249,17 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk, 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 478bc955..7b2cd3ea 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 @@ int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id, 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 c926765d..f2872970 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 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len, 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 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, 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 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth, } 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 2efb9857..b5f4f801 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 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean; #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 @@ static inline int wpa_key_mgmt_wpa_ieee8021x(int akm) 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 @@ static inline int wpa_key_mgmt_sha256(int akm) 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 803b8ccc..97a4537e 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 @@ enum plink_action_field { #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 a573e11e..de81d536 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 @@ int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf, #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 @@ int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf, * @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 @@ int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf, * 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 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label, 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 @@ int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr, 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 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s) #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 @@ void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name, * * 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 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, 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 @@ void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce, 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 @@ int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, #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 @@ const char * wpa_key_mgmt_txt(int key_mgmt, int proto) 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 @@ u32 wpa_akm_to_suite(int akm) 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 17bed34a..091e317f 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 @@ WPA_CIPHER_GTK_NOT_USED) #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 @@ struct wpa_eapol_key { /* 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 @@ struct rsn_rdie { #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_name(const u8 *pmk_r0_name, const u8 *r1kh_id, 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 @@ static inline int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa, 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_pick_group_cipher(int ciphers); 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 c2b06867..375db573 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 @@ static void gf_mulx(u8 *pad) /** - * 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 @@ static void gf_mulx(u8 *pad) * 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 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem, /** + * 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 @@ 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); } + + +/** + * 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 6b3727c7..4a142093 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 @@ int __must_check aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, 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 adb42a45..f79055cf 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 @@ int hmac_sha256(const u8 *key, size_t key_len, const u8 *data, #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 @@ int crypto_get_random(void *buf, size_t len) #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 @@ int omac1_aes_128_vector(const u8 *key, size_t num_elem, 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 @@ fail: } +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 00000000..e6a1fe41 --- /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 b8a7c519..c9e860f8 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 @@ struct wpa_driver_capa { #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 @@ struct wpa_driver_ops { * 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 3ed98511..d681ea63 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 @@ static void nl80211_register_eloop_read(struct nl_handle **handle, 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 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss, 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 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, 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 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv, 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 int wpa_driver_nl80211_get_survey(void *priv, unsigned int freq) } -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 @@ static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck, 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 6e52bdef..36c8ce2b 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 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv) 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 fc610819..f3e31a80 100644 --- a/src/p2p/p2p.c +++ b/src/p2p/p2p.c @@ -2847,7 +2847,7 @@ static void p2p_sd_cb(struct p2p_data *p2p, int success) 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 6eba2eb6..8d878a4b 100644 --- a/src/radius/radius.c +++ b/src/radius/radius.c @@ -993,13 +993,16 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, /* 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 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len, } 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 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 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 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg, 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 aca8f540..79764d94 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 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, { 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 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, (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 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, "(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 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, { 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 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, (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 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_smk_m2( 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 @@ static int wpa_supplicant_process_smk_m2( * @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 @@ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, 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 @@ static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, 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 @@ static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_smk_m45( 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 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, 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 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, &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 @@ static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, 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 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm, 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 @@ static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm, */ 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 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm, 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 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) 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 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) 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 4c17eae0..6ccd948b 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 @@ struct wpa_peerkey { 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 @@ struct wpa_peerkey { 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 8af04d0f..ef7b6838 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 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, 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 af0e1085..63569120 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 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm) 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 8ea54bba..b892a66d 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - WPA state machine and EAPOL-Key processing - * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> + * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -27,6 +27,7 @@ * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message * @sm: Pointer to WPA state machine data from wpa_sm_init() * @kck: Key Confirmation Key (KCK, part of PTK) + * @kck_len: KCK length in octets * @ver: Version field from Key Info * @dest: Destination address for the frame * @proto: Ethertype (usually ETH_P_EAPOL) @@ -34,10 +35,12 @@ * @msg_len: Length of message * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written */ -void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, +void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, size_t kck_len, int ver, const u8 *dest, u16 proto, u8 *msg, size_t msg_len, u8 *key_mic) { + size_t mic_len = wpa_mic_len(sm->key_mgmt); + if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { /* * Association event was not yet received; try to fetch @@ -56,14 +59,15 @@ void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck, } } if (key_mic && - wpa_eapol_key_mic(kck, 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 @@ out: */ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) { - size_t rlen; + size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; + struct wpa_eapol_key_192 *reply192; int key_info, ver; - u8 bssid[ETH_ALEN], *rbuf; + u8 bssid[ETH_ALEN], *rbuf, *key_mic; if (sm->key_mgmt == WPA_KEY_MGMT_OSEN || wpa_key_mgmt_suite_b(sm->key_mgmt)) @@ -106,10 +111,13 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) return; } + mic_len = wpa_mic_len(sm->key_mgmt); + hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply); rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*reply), &rlen, (void *) &reply); + hdrlen, &rlen, (void *) &reply); if (rbuf == NULL) return; + reply192 = (struct wpa_eapol_key_192 *) reply; reply->type = (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) ? @@ -127,15 +135,21 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise) WPA_REPLAY_COUNTER_LEN); inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); - WPA_PUT_BE16(reply->key_data_length, 0); + if (mic_len == 24) + WPA_PUT_BE16(reply192->key_data_length, 0); + else + WPA_PUT_BE16(reply->key_data_length, 0); + if (!(key_info & WPA_KEY_INFO_MIC)) + key_mic = NULL; + else + key_mic = reply192->key_mic; /* same offset in reply */ wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d " "pairwise=%d ptk_set=%d len=%lu)", error, pairwise, sm->ptk_set, (unsigned long) rlen); - wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, - rbuf, rlen, key_info & WPA_KEY_INFO_MIC ? - reply->key_mic : NULL); + wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, bssid, + ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -301,9 +315,10 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ptk *ptk) { - size_t rlen; + size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; - u8 *rbuf; + struct wpa_eapol_key_192 *reply192; + u8 *rbuf, *key_mic; u8 *rsn_ie_buf = NULL; if (wpa_ie == NULL) { @@ -345,13 +360,16 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len); + mic_len = wpa_mic_len(sm->key_mgmt); + hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply); rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, - NULL, sizeof(*reply) + wpa_ie_len, + NULL, hdrlen + wpa_ie_len, &rlen, (void *) &reply); if (rbuf == NULL) { os_free(rsn_ie_buf); return -1; } + reply192 = (struct wpa_eapol_key_192 *) reply; reply->type = (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) ? @@ -367,35 +385,38 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst, wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter, WPA_REPLAY_COUNTER_LEN); - WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); - os_memcpy(reply + 1, wpa_ie, wpa_ie_len); + key_mic = reply192->key_mic; /* same offset for reply and reply192 */ + if (mic_len == 24) { + WPA_PUT_BE16(reply192->key_data_length, wpa_ie_len); + os_memcpy(reply192 + 1, wpa_ie, wpa_ie_len); + } else { + WPA_PUT_BE16(reply->key_data_length, wpa_ie_len); + os_memcpy(reply + 1, wpa_ie, wpa_ie_len); + } os_free(rsn_ie_buf); os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4"); - wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); + wpa_eapol_key_send(sm, ptk->kck, ptk->kck_len, ver, dst, ETH_P_EAPOL, + rbuf, rlen, key_mic); return 0; } static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr, - const struct wpa_eapol_key *key, - struct wpa_ptk *ptk) + const struct wpa_eapol_key *key, struct wpa_ptk *ptk) { - size_t ptk_len = 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 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, } if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen, - (u8 *) sm->ptk.tk1, keylen) < 0) { + sm->ptk.tk, keylen) < 0) { wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: Failed to set PTK to the " "driver (alg=%d keylen=%d bssid=" MACSTR ")", @@ -610,8 +631,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm, } /* 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 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, 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 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, 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 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, 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 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm, (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 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, const struct wpa_eapol_key *key, int ver, u16 key_info) { - size_t rlen; + size_t mic_len, hdrlen, rlen; struct wpa_eapol_key *reply; - u8 *rbuf; + struct wpa_eapol_key_192 *reply192; + u8 *rbuf, *key_mic; + mic_len = wpa_mic_len(sm->key_mgmt); + hdrlen = mic_len == 24 ? sizeof(*reply192) : sizeof(*reply); rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, - sizeof(*reply), &rlen, (void *) &reply); + hdrlen, &rlen, (void *) &reply); if (rbuf == NULL) return -1; + reply192 = (struct wpa_eapol_key_192 *) reply; reply->type = (sm->proto == WPA_PROTO_RSN || sm->proto == WPA_PROTO_OSEN) ? @@ -1380,11 +1412,15 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm, 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 @@ failed: 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 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm, } 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 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, /* Decrypt key data here so that this operation does not need * to be implemented separately for each message type. */ - if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) { + if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 && sm->ptk.kek_len == 16) { u8 ek[32]; os_memcpy(ek, key->key_iv, 16); - os_memcpy(ek + 16, sm->ptk.kek, 16); + 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 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm, "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 @@ void wpa_sm_aborted_cached(struct wpa_sm *sm) static void wpa_eapol_key_dump(struct wpa_sm *sm, - const struct wpa_eapol_key *key) + const struct wpa_eapol_key *key, + unsigned int key_data_len, + const u8 *mic, unsigned int mic_len) { #ifndef CONFIG_NO_STDOUT_DEBUG u16 key_info = WPA_GET_BE16(key->key_info); @@ -1607,15 +1646,14 @@ static void wpa_eapol_key_dump(struct wpa_sm *sm, key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : ""); wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, " key_length=%u key_data_length=%u", - WPA_GET_BE16(key->key_length), - WPA_GET_BE16(key->key_data_length)); + WPA_GET_BE16(key->key_length), key_data_len); wpa_hexdump(MSG_DEBUG, " replay_counter", key->replay_counter, WPA_REPLAY_COUNTER_LEN); wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN); wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16); wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8); wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8); - wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16); + wpa_hexdump(MSG_DEBUG, " key_mic", mic, mic_len); #endif /* CONFIG_NO_STDOUT_DEBUG */ } @@ -1642,22 +1680,27 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, 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 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, 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 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, 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 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, 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 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr, } if ((key_info & WPA_KEY_INFO_MIC) && !peerkey && - wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len)) + wpa_supplicant_verify_eapol_key_mic(sm, key192, ver, tmp, data_len)) goto out; #ifdef CONFIG_PEERKEY if ((key_info & WPA_KEY_INFO_MIC) && peerkey && - peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len)) + peerkey_verify_eapol_key_mic(sm, peerkey, key192, ver, tmp, + data_len)) goto out; #endif /* CONFIG_PEERKEY */ @@ -1964,6 +2017,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm) 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_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) { - 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 cc128935..e163b701 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 @@ struct wpa_sm_ctx { 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 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx); 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 3b3c9d0d..06dea055 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 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, 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 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) * @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 @@ int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len) */ 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 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len, /* 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 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid) 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 @@ int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie) } 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 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, 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 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len, 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 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, 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 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, 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 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, 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 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, 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 @@ int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap, } 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 07f3692c..431bb207 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 @@ static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm) { 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 @@ static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm, 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 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst, 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 51876eda..cb334df6 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 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len, } 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 { diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index 512918ba..96a969e1 100644 --- a/wpa_supplicant/Android.mk +++ b/wpa_supplicant/Android.mk @@ -189,6 +189,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_SUITEB192 +L_CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + ifdef CONFIG_IEEE80211W L_CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y @@ -1237,6 +1242,9 @@ SHA256OBJS += src/crypto/sha256-kdf.c endif OBJS += $(SHA256OBJS) endif +ifdef NEED_SHA384 +L_CFLAGS += -DCONFIG_SHA384 +endif ifdef NEED_DH_GROUPS OBJS += src/crypto/dh_groups.c diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 9e1ffc89..21486c4c 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -192,6 +192,11 @@ NEED_SHA256=y NEED_AES_OMAC1=y endif +ifdef CONFIG_SUITEB192 +CFLAGS += -DCONFIG_SUITEB192 +NEED_SHA384=y +endif + ifdef CONFIG_IEEE80211W CFLAGS += -DCONFIG_IEEE80211W NEED_SHA256=y @@ -1250,6 +1255,9 @@ OBJS += ../src/crypto/sha256-kdf.o endif OBJS += $(SHA256OBJS) endif +ifdef NEED_SHA384 +CFLAGS += -DCONFIG_SHA384 +endif ifdef NEED_DH_GROUPS OBJS += ../src/crypto/dh_groups.o diff --git a/wpa_supplicant/README b/wpa_supplicant/README index 653848e4..f9c65d2e 100644 --- a/wpa_supplicant/README +++ b/wpa_supplicant/README @@ -1,7 +1,7 @@ WPA Supplicant ============== -Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors +Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors All Rights Reserved. This program is licensed under the BSD license (the one with diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 5d7a063c..1ffc2dca 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Configuration parser and common functions - * 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. @@ -678,8 +678,14 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data, else if (os_strcmp(start, "OSEN") == 0) val |= WPA_KEY_MGMT_OSEN; #endif /* CONFIG_HS20 */ +#ifdef CONFIG_SUITEB else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0) val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0) + val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; +#endif /* CONFIG_SUITEB192 */ else { wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'", line, start); @@ -856,6 +862,7 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } #endif /* CONFIG_HS20 */ +#ifdef CONFIG_SUITEB if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B", pos == buf ? "" : " "); @@ -865,6 +872,19 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data, } pos += ret; } +#endif /* CONFIG_SUITEB */ + +#ifdef CONFIG_SUITEB192 + if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B-192", + pos == buf ? "" : " "); + if (os_snprintf_error(end - pos, ret)) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } +#endif /* CONFIG_SUITEB192 */ if (pos == buf) { os_free(buf); @@ -4129,6 +4149,7 @@ static const struct global_parse_data global_fields[] = { { INT(rand_addr_lifetime), 0 }, { INT(preassoc_mac_addr), 0 }, { INT(key_mgmt_offload), 0}, + { INT(passive_scan), 0 }, }; #undef FUNC diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index eeb4ba7f..6adf1eb3 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -1137,6 +1137,18 @@ struct wpa_config { * By default: 300 seconds. */ int mesh_max_inactivity; + + /** + * passive_scan - Whether to force passive scan for network connection + * + * This parameter can be used to force only passive scanning to be used + * for network connection cases. It should be noted that this will slow + * down scan operations and reduce likelihood of finding the AP. In + * addition, some use cases will override this due to functional + * requirements, e.g., for finding an AP that uses hidden SSID + * (scan_ssid=1) or P2P device discovery. + */ + int passive_scan; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index 9c9685a7..33af428d 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -1227,6 +1227,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (config->mesh_max_inactivity != DEFAULT_MESH_MAX_INACTIVITY) fprintf(f, "mesh_max_inactivity=%d\n", config->mesh_max_inactivity); + + if (config->passive_scan) + fprintf(f, "cert_in_cb=%d\n", config->passive_scan); } #endif /* CONFIG_NO_CONFIG_WRITE */ diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 8e71727f..caa480cb 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -1,6 +1,6 @@ /* * WPA Supplicant / Control interface (shared code for all backends) - * 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. @@ -2323,6 +2323,7 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, } #endif /* CONFIG_IEEE80211W */ +#ifdef CONFIG_SUITEB if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B", pos == start ? "" : "+"); @@ -2330,6 +2331,17 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto, return pos; pos += ret; } +#endif /* CONFIG_SUITEB */ + +#ifdef CONFIG_SUITEB192 + if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192", + pos == start ? "" : "+"); + if (os_snprintf_error(end - pos, ret)) + return pos; + pos += ret; + } +#endif /* CONFIG_SUITEB192 */ pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher); @@ -3333,6 +3345,13 @@ static const struct cipher_info ciphers[] = { { WPA_DRIVER_CAPA_ENC_WEP40, "WEP40", 1 } }; +static const struct cipher_info ciphers_group_mgmt[] = { + { WPA_DRIVER_CAPA_ENC_BIP, "AES-128-CMAC", 1 }, + { WPA_DRIVER_CAPA_ENC_BIP_GMAC_128, "BIP-GMAC-128", 1 }, + { WPA_DRIVER_CAPA_ENC_BIP_GMAC_256, "BIP-GMAC-256", 1 }, + { WPA_DRIVER_CAPA_ENC_BIP_CMAC_256, "BIP-CMAC-256", 1 }, +}; + static int ctrl_iface_get_capability_pairwise(int res, char *strict, struct wpa_driver_capa *capa, @@ -3406,6 +3425,35 @@ static int ctrl_iface_get_capability_group(int res, char *strict, } +static int ctrl_iface_get_capability_group_mgmt(int res, char *strict, + struct wpa_driver_capa *capa, + char *buf, size_t buflen) +{ + int ret; + char *pos, *end; + unsigned int i; + + pos = buf; + end = pos + buflen; + + if (res < 0) + return 0; + + for (i = 0; i < ARRAY_SIZE(ciphers_group_mgmt); i++) { + if (capa->enc & ciphers_group_mgmt[i].capa) { + ret = os_snprintf(pos, end - pos, "%s%s", + pos == buf ? "" : " ", + ciphers_group_mgmt[i].name); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } + } + + return pos - buf; +} + + static int ctrl_iface_get_capability_key_mgmt(int res, char *strict, struct wpa_driver_capa *capa, char *buf, size_t buflen) @@ -3455,6 +3503,23 @@ static int ctrl_iface_get_capability_key_mgmt(int res, char *strict, pos += ret; } +#ifdef CONFIG_SUITEB + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B) { + ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192) { + ret = os_snprintf(pos, end - pos, " WPA-EAP-SUITE-B-192"); + if (os_snprintf_error(end - pos, ret)) + return pos - buf; + pos += ret; + } +#endif /* CONFIG_SUITEB192 */ + return pos - buf; } @@ -3755,6 +3820,10 @@ static int wpa_supplicant_ctrl_iface_get_capability( return ctrl_iface_get_capability_group(res, strict, &capa, buf, buflen); + if (os_strcmp(field, "group_mgmt") == 0) + return ctrl_iface_get_capability_group_mgmt(res, strict, &capa, + buf, buflen); + if (os_strcmp(field, "key_mgmt") == 0) return ctrl_iface_get_capability_key_mgmt(res, strict, &capa, buf, buflen); diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 0b029207..e7c2dd88 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -2,7 +2,7 @@ * WPA Supplicant / dbus-based control interface * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com> - * Copyright (c) 2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -3590,7 +3590,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, DBusMessageIter iter_dict, variant_iter; const char *group; const char *pairwise[5]; /* max 5 pairwise ciphers is supported */ - const char *key_mgmt[8]; /* max 8 key managements may be supported */ + const char *key_mgmt[9]; /* max 9 key managements may be supported */ int n; if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, @@ -3614,8 +3614,14 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter, key_mgmt[n++] = "wpa-ft-eap"; if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) key_mgmt[n++] = "wpa-eap-sha256"; +#ifdef CONFIG_SUITEB if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) key_mgmt[n++] = "wpa-eap-suite-b"; +#endif /* CONFIG_SUITEB */ +#ifdef CONFIG_SUITEB192 + if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + key_mgmt[n++] = "wpa-eap-suite-b-192"; +#endif /* CONFIG_SUITEB192 */ if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE) key_mgmt[n++] = "wpa-none"; diff --git a/wpa_supplicant/doc/docbook/eapol_test.sgml b/wpa_supplicant/doc/docbook/eapol_test.sgml index fec174b0..e9af6d96 100644 --- a/wpa_supplicant/doc/docbook/eapol_test.sgml +++ b/wpa_supplicant/doc/docbook/eapol_test.sgml @@ -194,7 +194,7 @@ eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1 </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_background.sgml b/wpa_supplicant/doc/docbook/wpa_background.sgml index 860b5a02..afb8c3b7 100644 --- a/wpa_supplicant/doc/docbook/wpa_background.sgml +++ b/wpa_supplicant/doc/docbook/wpa_background.sgml @@ -90,7 +90,7 @@ <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_cli.sgml b/wpa_supplicant/doc/docbook/wpa_cli.sgml index 142e1ab3..47947c1d 100644 --- a/wpa_supplicant/doc/docbook/wpa_cli.sgml +++ b/wpa_supplicant/doc/docbook/wpa_cli.sgml @@ -345,7 +345,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_gui.sgml b/wpa_supplicant/doc/docbook/wpa_gui.sgml index f6ef8f14..84766db3 100644 --- a/wpa_supplicant/doc/docbook/wpa_gui.sgml +++ b/wpa_supplicant/doc/docbook/wpa_gui.sgml @@ -74,7 +74,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml index 3b4360bc..b381e409 100644 --- a/wpa_supplicant/doc/docbook/wpa_passphrase.sgml +++ b/wpa_supplicant/doc/docbook/wpa_passphrase.sgml @@ -62,7 +62,7 @@ </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_priv.sgml b/wpa_supplicant/doc/docbook/wpa_priv.sgml index 9c114cc3..d13a5dbb 100644 --- a/wpa_supplicant/doc/docbook/wpa_priv.sgml +++ b/wpa_supplicant/doc/docbook/wpa_priv.sgml @@ -137,7 +137,7 @@ wpa_supplicant -i ath0 -c wpa_supplicant.conf </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml index e7bf4e07..46c21b5c 100644 --- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml +++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml @@ -736,7 +736,7 @@ fi </refsect1> <refsect1> <title>Legal</title> - <para>wpa_supplicant is copyright (c) 2003-2014, + <para>wpa_supplicant is copyright (c) 2003-2015, Jouni Malinen <email>j@w1.fi</email> and contributors. All Rights Reserved.</para> diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h index 9debcf84..65b430d4 100644 --- a/wpa_supplicant/driver_i.h +++ b/wpa_supplicant/driver_i.h @@ -1,6 +1,6 @@ /* * wpa_supplicant - Internal driver interface wrappers - * Copyright (c) 2003-2009, 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. @@ -569,12 +569,14 @@ static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s, #endif /* ANDROID */ static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s, - const u8 *kek, const u8 *kck, + const u8 *kek, size_t kek_len, + const u8 *kck, size_t kck_len, const u8 *replay_ctr) { if (!wpa_s->driver->set_rekey_info) return; - wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr); + wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kek_len, + kck, kck_len, replay_ctr); } static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s, diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index a89ab298..f1f8864e 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Driver event processing - * 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. @@ -476,8 +476,7 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211W if (!(ie.capabilities & WPA_CAPABILITY_MFPC) && - (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w) == + wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { wpa_dbg(wpa_s, MSG_DEBUG, " skip RSN IE - no mgmt " "frame protection"); @@ -2996,7 +2995,9 @@ static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s, } wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr); wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck, - data->assoc_info.ptk_kek); + data->assoc_info.ptk_kck_len, + data->assoc_info.ptk_kek, + data->assoc_info.ptk_kek_len); } diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c index 3e919bd2..5ea046fa 100644 --- a/wpa_supplicant/interworking.c +++ b/wpa_supplicant/interworking.c @@ -587,56 +587,91 @@ static int nai_realm_match(struct nai_realm *realm, const char *home_realm) } -static int nai_realm_cred_username(struct nai_realm_eap *eap) +static int nai_realm_cred_username(struct wpa_supplicant *wpa_s, + struct nai_realm_eap *eap) { - if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) + if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: EAP method not supported: %d", + eap->method); return 0; /* method not supported */ + } if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP && eap->method != EAP_TYPE_FAST) { /* Only tunneled methods with username/password supported */ + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: Method: %d is not TTLS, PEAP, or FAST", + eap->method); return 0; } if (eap->method == EAP_TYPE_PEAP || eap->method == EAP_TYPE_FAST) { if (eap->inner_method && - eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) + eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: PEAP/FAST: Inner method not supported: %d", + eap->inner_method); return 0; + } if (!eap->inner_method && - eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) + eap_get_name(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2) == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: MSCHAPv2 not supported"); return 0; + } } if (eap->method == EAP_TYPE_TTLS) { if (eap->inner_method == 0 && eap->inner_non_eap == 0) return 1; /* Assume TTLS/MSCHAPv2 is used */ if (eap->inner_method && - eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) + eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: TTLS, but inner not supported: %d", + eap->inner_method); return 0; + } if (eap->inner_non_eap && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP && eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP && - eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) + eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: TTLS, inner-non-eap not supported: %d", + eap->inner_non_eap); return 0; + } } if (eap->inner_method && eap->inner_method != EAP_TYPE_GTC && - eap->inner_method != EAP_TYPE_MSCHAPV2) + eap->inner_method != EAP_TYPE_MSCHAPV2) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-username: inner-method not GTC or MSCHAPv2: %d", + eap->inner_method); return 0; + } return 1; } -static int nai_realm_cred_cert(struct nai_realm_eap *eap) +static int nai_realm_cred_cert(struct wpa_supplicant *wpa_s, + struct nai_realm_eap *eap) { - if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) + if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-cert: Method not supported: %d", + eap->method); return 0; /* method not supported */ + } if (eap->method != EAP_TYPE_TLS) { /* Only EAP-TLS supported for credential authentication */ + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-cred-cert: Method not TLS: %d", + eap->method); return 0; } @@ -644,27 +679,33 @@ static int nai_realm_cred_cert(struct nai_realm_eap *eap) } -static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred, +static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s, + struct wpa_cred *cred, struct nai_realm *realm) { u8 e; - if (cred == NULL || - cred->username == NULL || + if (cred->username == NULL || cred->username[0] == '\0' || ((cred->password == NULL || cred->password[0] == '\0') && (cred->private_key == NULL || - cred->private_key[0] == '\0'))) + cred->private_key[0] == '\0'))) { + wpa_msg(wpa_s, MSG_DEBUG, + "nai-realm-find-eap: incomplete cred info: username: %s password: %s private_key: %s", + cred->username ? cred->username : "NULL", + cred->password ? cred->password : "NULL", + cred->private_key ? cred->private_key : "NULL"); return NULL; + } for (e = 0; e < realm->eap_count; e++) { struct nai_realm_eap *eap = &realm->eap[e]; if (cred->password && cred->password[0] && - nai_realm_cred_username(eap)) + nai_realm_cred_username(wpa_s, eap)) return eap; if (cred->private_key && cred->private_key[0] && - nai_realm_cred_cert(eap)) + nai_realm_cred_cert(wpa_s, eap)) return eap; } @@ -1644,7 +1685,7 @@ static int interworking_connect_helper(struct wpa_supplicant *wpa_s, for (i = 0; i < count; i++) { if (!nai_realm_match(&realm[i], cred->realm)) continue; - eap = nai_realm_find_eap(cred, &realm[i]); + eap = nai_realm_find_eap(wpa_s, cred, &realm[i]); if (eap) break; } @@ -1813,22 +1854,29 @@ static struct wpa_cred * interworking_credentials_available_3gpp( int ret; int is_excluded = 0; - if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) + if (bss->anqp == NULL || bss->anqp->anqp_3gpp == NULL) { + wpa_msg(wpa_s, MSG_DEBUG, + "interworking-avail-3gpp: not avail, anqp: %p anqp_3gpp: %p", + bss->anqp, bss->anqp ? bss->anqp->anqp_3gpp : NULL); return NULL; + } #ifdef CONFIG_EAP_PROXY if (!wpa_s->imsi[0]) { size_t len; - wpa_printf(MSG_DEBUG, "Interworking: IMSI not available - try to read again through eap_proxy"); + wpa_msg(wpa_s, MSG_DEBUG, + "Interworking: IMSI not available - try to read again through eap_proxy"); wpa_s->mnc_len = eapol_sm_get_eap_proxy_imsi(wpa_s->eapol, wpa_s->imsi, &len); if (wpa_s->mnc_len > 0) { wpa_s->imsi[len] = '\0'; - wpa_printf(MSG_DEBUG, "eap_proxy: IMSI %s (MNC length %d)", - wpa_s->imsi, wpa_s->mnc_len); + wpa_msg(wpa_s, MSG_DEBUG, + "eap_proxy: IMSI %s (MNC length %d)", + wpa_s->imsi, wpa_s->mnc_len); } else { - wpa_printf(MSG_DEBUG, "eap_proxy: IMSI not available"); + wpa_msg(wpa_s, MSG_DEBUG, + "eap_proxy: IMSI not available"); } } #endif /* CONFIG_EAP_PROXY */ @@ -1950,7 +1998,7 @@ static struct wpa_cred * interworking_credentials_available_realm( for (i = 0; i < count; i++) { if (!nai_realm_match(&realm[i], cred->realm)) continue; - if (nai_realm_find_eap(cred, &realm[i])) { + if (nai_realm_find_eap(wpa_s, cred, &realm[i])) { if (cred_no_required_oi_match(cred, bss)) continue; if (!ignore_bw && diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c index 4364a064..65c1b486 100644 --- a/wpa_supplicant/p2p_supplicant.c +++ b/wpa_supplicant/p2p_supplicant.c @@ -1546,6 +1546,7 @@ static void wpas_p2p_clone_config(struct wpa_supplicant *dst, d->dtim_period = s->dtim_period; d->disassoc_low_ack = s->disassoc_low_ack; d->disable_scan_offload = s->disable_scan_offload; + d->passive_scan = s->passive_scan; if (s->wps_nfc_dh_privkey && s->wps_nfc_dh_pubkey) { d->wps_nfc_dh_privkey = wpabuf_dup(s->wps_nfc_dh_privkey); diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c index 08af9fba..0653cc28 100644 --- a/wpa_supplicant/scan.c +++ b/wpa_supplicant/scan.c @@ -724,7 +724,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) #ifdef CONFIG_P2P if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) && - wpa_s->go_params) { + wpa_s->go_params && !wpa_s->conf->passive_scan) { wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during P2P group formation (p2p_in_provisioning=%d show_group_started=%d)", wpa_s->p2p_in_provisioning, wpa_s->show_group_started); @@ -878,6 +878,9 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx) } else if (wpa_s->last_scan_req == MANUAL_SCAN_REQ && wpa_s->manual_scan_passive && params.num_ssids == 0) { wpa_dbg(wpa_s, MSG_DEBUG, "Use passive scan based on manual request"); + } else if (wpa_s->conf->passive_scan) { + wpa_dbg(wpa_s, MSG_DEBUG, + "Use passive scan based on configuration"); } else { wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN; params.num_ssids++; diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c index d34668a5..c2b0990a 100644 --- a/wpa_supplicant/sme.c +++ b/wpa_supplicant/sme.c @@ -384,8 +384,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s, #endif /* CONFIG_IEEE80211R */ #ifdef CONFIG_IEEE80211W - wpa_s->sme.mfp = ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w; + wpa_s->sme.mfp = wpas_get_ssid_pmf(wpa_s, ssid); if (wpa_s->sme.mfp != NO_MGMT_FRAME_PROTECTION) { const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); struct wpa_ie_data _ie; @@ -1547,9 +1546,7 @@ void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa, if (wpa_s->wpa_state != WPA_COMPLETED) return; ssid = wpa_s->current_ssid; - if (ssid == NULL || - (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION) + if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION) return; if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) return; diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c index 79619f2d..911effe4 100644 --- a/wpa_supplicant/wpa_cli.c +++ b/wpa_supplicant/wpa_cli.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - command line interface for wpa_supplicant daemon - * 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,7 +28,7 @@ static const char *wpa_cli_version = "wpa_cli v" VERSION_STR "\n" -"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors"; static const char *wpa_cli_license = diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp index 063347e8..ae0c2408 100644 --- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp +++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp @@ -12,6 +12,7 @@ #include "signalbar.h" #include "wpagui.h" #include "networkconfig.h" +#include "scanresultsitem.h" ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags) @@ -95,7 +96,7 @@ void ScanResults::updateResults() ssid = (*it).mid(pos); } - QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget); + ScanResultsItem *item = new ScanResultsItem(scanResultsWidget); if (item) { item->setText(0, ssid); item->setText(1, bssid); diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp new file mode 100644 index 00000000..9cd937cd --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp @@ -0,0 +1,18 @@ +/* + * wpa_gui - ScanResultsItem class + * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "scanresultsitem.h" + +bool ScanResultsItem::operator< (const QTreeWidgetItem &other) const +{ + int sortCol = treeWidget()->sortColumn(); + if (sortCol == 2 || sortCol == 3) { + return text(sortCol).toInt() < other.text(sortCol).toInt(); + } + return text(sortCol) < other.text(sortCol); +} diff --git a/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h new file mode 100644 index 00000000..835b7c08 --- /dev/null +++ b/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h @@ -0,0 +1,21 @@ +/* + * wpa_gui - ScanResultsItem class + * Copyright (c) 2015, Adrian Nowicki <adinowicki@gmail.com> + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#ifndef SCANRESULTSITEM_H +#define SCANRESULTSITEM_H + +#include <QtGui> + +class ScanResultsItem : public QTreeWidgetItem +{ +public: + ScanResultsItem(QTreeWidget *tree) : QTreeWidgetItem(tree) {} + bool operator< (const QTreeWidgetItem &other) const; +}; + +#endif /* SCANRESULTSITEM_H */ diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro index 3c81929e..69bc0f67 100644 --- a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro +++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro @@ -34,6 +34,7 @@ HEADERS += wpamsg.h \ wpagui.h \ eventhistory.h \ scanresults.h \ + scanresultsitem.h \ signalbar.h \ userdatarequest.h \ networkconfig.h \ @@ -45,6 +46,7 @@ SOURCES += main.cpp \ wpagui.cpp \ eventhistory.cpp \ scanresults.cpp \ + scanresultsitem.cpp \ signalbar.cpp \ userdatarequest.cpp \ networkconfig.cpp \ diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 47243a3f..434847d5 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - * 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. @@ -57,7 +57,7 @@ const char *wpa_supplicant_version = "wpa_supplicant v" VERSION_STR "\n" -"Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi> and contributors"; +"Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi> and contributors"; const char *wpa_supplicant_license = "This software may be distributed under the terms of the BSD license.\n" @@ -962,9 +962,7 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211W if (!(ie->capabilities & WPA_CAPABILITY_MFPC) && - (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w) == - MGMT_FRAME_PROTECTION_REQUIRED) { + wpas_get_ssid_pmf(wpa_s, ssid) == MGMT_FRAME_PROTECTION_REQUIRED) { wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP " "that does not support management frame protection - " "reject"); @@ -1138,10 +1136,18 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE); #endif /* CONFIG_SAE */ if (0) { +#ifdef CONFIG_SUITEB192 + } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) { + wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192; + wpa_dbg(wpa_s, MSG_DEBUG, + "WPA: using KEY_MGMT 802.1X with Suite B (192-bit)"); +#endif /* CONFIG_SUITEB192 */ +#ifdef CONFIG_SUITEB } else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) { wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B; wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X with Suite B"); +#endif /* CONFIG_SUITEB */ #ifdef CONFIG_IEEE80211R } else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) { wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X; @@ -1195,8 +1201,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211W sel = ie.mgmt_group_cipher; - if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION || + if (wpas_get_ssid_pmf(wpa_s, ssid) == NO_MGMT_FRAME_PROTECTION || !(ie.capabilities & WPA_CAPABILITY_MFPC)) sel = 0; if (sel & WPA_CIPHER_AES_128_CMAC) { @@ -1222,8 +1227,7 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s, wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP, wpa_s->mgmt_group_cipher); wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP, - (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w)); + wpas_get_ssid_pmf(wpa_s, ssid)); #endif /* CONFIG_IEEE80211W */ if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) { @@ -2143,7 +2147,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) if (wpa_s->conf->key_mgmt_offload) { if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X || params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_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) params.req_key_mgmt_offload = ssid->proactive_key_caching < 0 ? wpa_s->conf->okc : ssid->proactive_key_caching; @@ -2160,9 +2165,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit) params.drop_unencrypted = use_crypt; #ifdef CONFIG_IEEE80211W - params.mgmt_frame_protection = - ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ? - wpa_s->conf->pmf : ssid->ieee80211w; + params.mgmt_frame_protection = wpas_get_ssid_pmf(wpa_s, ssid); if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) { const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN); struct wpa_ie_data ie; @@ -4889,6 +4892,30 @@ int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) } +int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid) +{ +#ifdef CONFIG_IEEE80211W + if (ssid == NULL || ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT) { + if (wpa_s->conf->pmf == MGMT_FRAME_PROTECTION_OPTIONAL && + !(wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_BIP)) { + /* + * Driver does not support BIP -- ignore pmf=1 default + * since the connection with PMF would fail and the + * configuration does not require PMF to be enabled. + */ + return NO_MGMT_FRAME_PROTECTION; + } + + return wpa_s->conf->pmf; + } + + return ssid->ieee80211w; +#else /* CONFIG_IEEE80211W */ + return NO_MGMT_FRAME_PROTECTION; +#endif /* CONFIG_IEEE80211W */ +} + + int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s) { if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P) diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index d1938fab..7d22000a 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -1113,6 +1113,7 @@ static inline int network_is_persistent_group(struct wpa_ssid *ssid) } int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpas_get_ssid_pmf(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); int wpas_init_ext_pw(struct wpa_supplicant *wpa_s); diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c index 83870433..99e73512 100644 --- a/wpa_supplicant/wpas_glue.c +++ b/wpa_supplicant/wpas_glue.c @@ -1,6 +1,6 @@ /* * WPA Supplicant - Glue code to setup EAPOL and RSN modules - * 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. @@ -968,13 +968,14 @@ int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s) #ifndef CONFIG_NO_WPA -static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek, - const u8 *kck, +static void wpa_supplicant_set_rekey_offload(void *ctx, + const u8 *kek, size_t kek_len, + const u8 *kck, size_t kck_len, const u8 *replay_ctr) { struct wpa_supplicant *wpa_s = ctx; - wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr); + wpa_drv_set_rekey_info(wpa_s, kek, kek_len, kck, kck_len, replay_ctr); } #endif /* CONFIG_NO_WPA */ |
