From 5e3b5197cc37a7a85613f6ba5f7041342cd66511 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 25 Jan 2015 23:32:01 +0200 Subject: [PATCH] Add Suite B 192-bit AKM WPA-EAP-SUITE-B-192 can now be used to select 192-bit level Suite B into use as the key management method. Signed-off-by: Jouni Malinen --- hostapd/Android.mk | 5 + hostapd/Makefile | 5 + hostapd/config_file.c | 8 +- hostapd/ctrl_iface.c | 10 +- src/ap/pmksa_cache_auth.c | 6 +- src/ap/wpa_auth.c | 99 ++++++++++++------ src/ap/wpa_auth_ie.c | 11 +- src/common/defs.h | 14 ++- src/common/ieee802_11_defs.h | 3 +- src/common/wpa_common.c | 61 ++++++++++- src/common/wpa_common.h | 36 ++++++- src/drivers/driver_nl80211.c | 6 +- src/rsn_supp/peerkey.c | 10 +- src/rsn_supp/peerkey.h | 2 +- src/rsn_supp/pmksa_cache.c | 6 +- src/rsn_supp/preauth.c | 5 +- src/rsn_supp/wpa.c | 132 +++++++++++++++++------- src/rsn_supp/wpa_ie.c | 4 +- wlantest/ctrl.c | 5 +- wlantest/sta.c | 6 +- wpa_supplicant/Android.mk | 5 + wpa_supplicant/Makefile | 5 + wpa_supplicant/config.c | 22 +++- wpa_supplicant/ctrl_iface.c | 14 ++- wpa_supplicant/dbus/dbus_new_handlers.c | 10 +- wpa_supplicant/wpa_supplicant.c | 13 ++- 26 files changed, 397 insertions(+), 106 deletions(-) diff --git a/hostapd/Android.mk b/hostapd/Android.mk index 6767f3c8f..c8ef46b90 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 diff --git a/hostapd/Makefile b/hostapd/Makefile index 886cf2e02..894b65274 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 diff --git a/hostapd/config_file.c b/hostapd/config_file.c index 99cd05286..7cbb46b46 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 + * Copyright (c) 2003-2015, Jouni Malinen * * 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 bef16b157..54b17dc93 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 + * Copyright (c) 2004-2015, Jouni Malinen * * 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/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c index 650e9a81d..877affe4e 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 + * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen * * 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 ece949a1c..1905dc94e 100644 --- a/src/ap/wpa_auth.c +++ b/src/ap/wpa_auth.c @@ -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) { @@ -1488,13 +1506,17 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) || version == WPA_KEY_INFO_TYPE_AES_128_CMAC) { if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, - (key_data_len - 8) / 8, buf, - (u8 *) (key + 1))) { + (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); + 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, @@ -1502,9 +1524,14 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, inc_byte_array(sm->group->Counter, WPA_NONCE_LEN); os_memcpy(ek, key->key_iv, 16); os_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len); - 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(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); @@ -1514,6 +1541,8 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, } 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 " @@ -1521,9 +1550,11 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth, os_free(hdr); return; } + + 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->key_mic); + (u8 *) hdr, len, key_mic); #ifdef CONFIG_TESTING_OPTIONS if (!pairwise && wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 && @@ -1531,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 */ } @@ -1580,25 +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[WPA_EAPOL_KEY_MIC_MAX_LEN]; - size_t mic_len = 16; + 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, mic_len); - os_memset(key->key_mic, 0, mic_len); + 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, key->key_mic) || - os_memcmp_const(mic, key->key_mic, mic_len) != 0) + data, data_len, key192->key_mic) || + os_memcmp_const(mic, key192->key_mic, mic_len) != 0) ret = -1; - os_memcpy(key->key_mic, mic, mic_len); + os_memcpy(key192->key_mic, mic, mic_len); return ret; } diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c index c926765d0..f2872970a 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 + * Copyright (c) 2004-2015, Jouni Malinen * * 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 2efb98577..b5f4f801e 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 + * Copyright (c) 2004-2015, Jouni Malinen * * 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 803b8ccc8..97a4537e4 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 + * Copyright (c) 2002-2015, Jouni Malinen * 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 d4a17a121..de81d5369 100644 --- a/src/common/wpa_common.c +++ b/src/common/wpa_common.c @@ -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" @@ -21,12 +22,24 @@ 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; } @@ -54,7 +67,7 @@ static unsigned int wpa_kek_len(int akmp) 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 @@ -83,6 +96,13 @@ int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver, 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; } @@ -452,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; } @@ -1034,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) @@ -1113,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"; } @@ -1141,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 ddb4a090f..091e317fd 100644 --- a/src/common/wpa_common.h +++ b/src/common/wpa_common.h @@ -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,9 +191,24 @@ struct wpa_eapol_key { /* followed by key_data_length bytes of key_data */ } STRUCT_PACKED; -#define WPA_EAPOL_KEY_MIC_MAX_LEN 16 -#define WPA_KCK_MAX_LEN 16 -#define WPA_KEK_MAX_LEN 16 +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 /** @@ -386,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); @@ -431,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/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index ea525759e..ed2f17170 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -4463,7 +4463,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) { @@ -4491,6 +4492,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; diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c index 43d3af6b7..79764d94b 100644 --- a/src/rsn_supp/peerkey.c +++ b/src/rsn_supp/peerkey.c @@ -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 | @@ -113,7 +115,7 @@ static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, } wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, dst, - ETH_P_EAPOL, rbuf, rlen, err->key_mic); + 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 | @@ -165,7 +169,7 @@ static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3"); wpa_eapol_key_send(sm, sm->ptk.kck, sm->ptk.kck_len, ver, src_addr, - ETH_P_EAPOL, rbuf, rlen, reply->key_mic); + ETH_P_EAPOL, rbuf, rlen, reply192->key_mic); return 0; } @@ -907,7 +911,7 @@ 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[WPA_EAPOL_KEY_MIC_MAX_LEN]; diff --git a/src/rsn_supp/peerkey.h b/src/rsn_supp/peerkey.h index f3d07f3d3..6ccd948ba 100644 --- a/src/rsn_supp/peerkey.h +++ b/src/rsn_supp/peerkey.h @@ -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 8af04d0f2..ef7b68386 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 + * Copyright (c) 2004-2009, 2011-2015, Jouni Malinen * * 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 af0e1085a..635691200 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 + * Copyright (c) 2003-2015, Jouni Malinen * * 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 078e9a050..b892a66da 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -39,7 +39,7 @@ 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 = 16; + size_t mic_len = wpa_mic_len(sm->key_mgmt); if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) { /* @@ -88,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)) @@ -110,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) ? @@ -131,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, sm->ptk.kck_len, ver, bssid, - ETH_P_EAPOL, rbuf, rlen, - key_info & WPA_KEY_INFO_MIC ? reply->key_mic : NULL); + ETH_P_EAPOL, rbuf, rlen, key_mic); } @@ -305,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) { @@ -349,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) ? @@ -371,15 +385,21 @@ 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, ptk->kck_len, ver, dst, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); + rbuf, rlen, key_mic); return 0; } @@ -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, ptk->kck_len, ver, dst, ETH_P_EAPOL, - rbuf, rlen, reply->key_mic); + rbuf, rlen, key_mic); return 0; } @@ -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, sm->ptk.kck_len, ver, sm->bssid, - ETH_P_EAPOL, rbuf, rlen, reply->key_mic); + ETH_P_EAPOL, rbuf, rlen, key_mic); return 0; } @@ -1451,13 +1487,13 @@ 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[WPA_EAPOL_KEY_MIC_MAX_LEN]; int ok = 0; - size_t mic_len = 16; + size_t mic_len = wpa_mic_len(sm->key_mgmt); os_memcpy(mic, key->key_mic, mic_len); if (sm->tptk_set) { @@ -1586,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); @@ -1608,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 */ } @@ -1643,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; } @@ -1680,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)", @@ -1703,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) { @@ -1713,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; } @@ -1870,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 */ @@ -1965,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; } diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c index 51876eda2..cb334df67 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 + * Copyright (c) 2003-2015, Jouni Malinen * * 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/wlantest/ctrl.c b/wlantest/ctrl.c index 87f347c20..7de0a8aff 100644 --- a/wlantest/ctrl.c +++ b/wlantest/ctrl.c @@ -1,6 +1,6 @@ /* * wlantest control interface - * Copyright (c) 2010-2013, Jouni Malinen + * Copyright (c) 2010-2015, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -954,6 +954,9 @@ static void info_print_key_mgmt(char *buf, size_t len, int key_mgmt) if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) pos += os_snprintf(pos, end - pos, "%sEAP-SUITE-B", pos == buf ? "" : " "); + if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) + pos += os_snprintf(pos, end - pos, "%sEAP-SUITE-B-192", + pos == buf ? "" : " "); } diff --git a/wlantest/sta.c b/wlantest/sta.c index 0cd5bd30d..1268b8a09 100644 --- a/wlantest/sta.c +++ b/wlantest/sta.c @@ -1,6 +1,6 @@ /* * STA list - * Copyright (c) 2010, Jouni Malinen + * Copyright (c) 2010-2015, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -170,7 +170,7 @@ skip_rsn_wpa: wpa_printf(MSG_INFO, "STA " MACSTR " proto=%s%s%s%s" "pairwise=%s%s%s%s%s%s%s" - "key_mgmt=%s%s%s%s%s%s%s%s%s%s" + "key_mgmt=%s%s%s%s%s%s%s%s%s%s%s" "rsn_capab=%s%s%s%s%s", MAC2STR(sta->addr), sta->proto == 0 ? "OPEN " : "", @@ -199,6 +199,8 @@ skip_rsn_wpa: sta->key_mgmt & WPA_KEY_MGMT_OSEN ? "OSEN " : "", sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B ? "EAP-SUITE-B " : "", + sta->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 ? + "EAP-SUITE-B-192 " : "", sta->rsn_capab & WPA_CAPABILITY_PREAUTH ? "PREAUTH " : "", sta->rsn_capab & WPA_CAPABILITY_NO_PAIRWISE ? "NO_PAIRWISE " : "", diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk index ace198762..96a969e16 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 diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 81b4df047..21486c4c1 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 diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index 4a56abc33..1ffc2dca2 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 + * Copyright (c) 2003-2015, Jouni Malinen * * 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); diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 06db7f703..f2c80a369 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 + * Copyright (c) 2004-2015, Jouni Malinen * * 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); diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index 0b0292070..e7c2dd886 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 and Red Hat, Inc. * Copyright (c) 2009-2010, Witold Sowa - * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2009-2015, Jouni Malinen * * 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/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index 47243a3f4..71a5cea75 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 + * Copyright (c) 2003-2015, Jouni Malinen * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -1138,10 +1138,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; @@ -2143,7 +2151,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;