]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add Suite B 192-bit AKM
authorJouni Malinen <j@w1.fi>
Sun, 25 Jan 2015 21:32:01 +0000 (23:32 +0200)
committerJouni Malinen <j@w1.fi>
Mon, 26 Jan 2015 23:43:52 +0000 (01:43 +0200)
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 <j@w1.fi>
26 files changed:
hostapd/Android.mk
hostapd/Makefile
hostapd/config_file.c
hostapd/ctrl_iface.c
src/ap/pmksa_cache_auth.c
src/ap/wpa_auth.c
src/ap/wpa_auth_ie.c
src/common/defs.h
src/common/ieee802_11_defs.h
src/common/wpa_common.c
src/common/wpa_common.h
src/drivers/driver_nl80211.c
src/rsn_supp/peerkey.c
src/rsn_supp/peerkey.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/preauth.c
src/rsn_supp/wpa.c
src/rsn_supp/wpa_ie.c
wlantest/ctrl.c
wlantest/sta.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile
wpa_supplicant/config.c
wpa_supplicant/ctrl_iface.c
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/wpa_supplicant.c

index 6767f3c8fe828a21a89b84187a0afbacb75272a4..c8ef46b90552e2e280c3747f5b97a43bb44189e4 100644 (file)
@@ -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
index 886cf2e021d845b682f3a8afc14790680ce6f022..894b652746e6eebc04f6c002982fbfb42f85129c 100644 (file)
@@ -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
index 99cd05286247e9dec14b4b636b59ad8c66786708..7cbb46b46853df45668847e5aa3b56938bebebb7 100644 (file)
@@ -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);
index bef16b157bacac1c30d4d9bf90e50c80299ddbca..54b17dc93b3aa1cf067e9913f8a7216cee0dc218 100644 (file)
@@ -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))
index 650e9a81daf5bb02b7b00847504dfc7a92a8f451..877affe4eadcc2c0c8f59ec3184edbaf8e58ba21 100644 (file)
@@ -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,
index ece949a1ccc5bef7de360f86cdd2f07ae94840f9..1905dc94efef115b5d5f02ae41110ff5fe34d988 100644 (file)
@@ -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;
 }
 
index c926765d04b896444b98c88cbb5904ad70b00288..f2872970affee61d3637b4b930a94624b03e497c 100644 (file)
@@ -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
index 2efb98577b1b59438227ba253f677ce16b094193..b5f4f801eda216bef16454bc6fa5013617ac9c81 100644 (file)
@@ -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)
index 803b8ccc85470d37aba0a37431aa02161c9edf05..97a4537e4a32d9236146e924537fa9d4cb8bd36e 100644 (file)
@@ -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
 
index d4a17a1213ceeb4682cc3b73d97d51ba82b0f66d..de81d53694c2910c3a1e4c0b69e0f99fa2f7da3c 100644 (file)
@@ -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"
 
 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;
 }
 
index ddb4a090f00ce0de2e92f03b2da188e99df23cff..091e317fdd68a2e2f625e1cbe83f61d7fc189ff3 100644 (file)
@@ -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 */
index ea525759ef7edb19a2e4b1542cd39af0e195ec65..ed2f17170c4f38146646008ff3d42b735cf0e258 100644 (file)
@@ -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;
index 43d3af6b74d74249358c310c5745a9e1f60c995f..79764d94b902cc5facb0a8dbf90e01994bab42c0 100644 (file)
@@ -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];
index f3d07f3d3c3ff0bfcd7fcd80a89d2879dc92373f..6ccd948baace5e08ad9fcf889bb0d177a5218e2f 100644 (file)
@@ -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,
index 8af04d0f28d9323dcb92fd005e2149ea2f41f3e6..ef7b6838647651f66f030d09ee0f220d12809cb1 100644 (file)
@@ -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,
index af0e1085a8277c5b0d4743dcd7d9ee397c28b36b..635691200c93c4adae922ca4e012b75c0e0d7835 100644 (file)
@@ -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 */
index 078e9a050d546f4a50637c7fc193c0d8ec5cbc44..b892a66da7b336ae31aef057bbf31f952fe76bd3 100644 (file)
@@ -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;
        }
index 51876eda2ae03c58252febc794887e9ebfc73e5e..cb334df675bebe98ea70d10c4d13725ccc1e8cf0 100644 (file)
@@ -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 {
index 87f347c20d3a7fc6f0ed9ecc723f15731c5f0525..7de0a8aff9b2f56d77d0d8f29c8f4fd1098a2ce0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * wlantest control interface
- * Copyright (c) 2010-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * 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 ? "" : " ");
 }
 
 
index 0cd5bd30dea0e0372c012610ee62777f28b3158f..1268b8a09bd675056a45ecdafbe9d5a5c3e7b2a4 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * STA list
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2015, Jouni Malinen <j@w1.fi>
  *
  * 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 " : "",
index ace198762574341b4c6b9e103ed1d2d9acaab67b..96a969e163f41b981c5a907764f8d1a11a313ea0 100644 (file)
@@ -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
index 81b4df04735745e755404e802328375548eab7af..21486c4c1c5539c19a1e8d65619cc7ac04397748 100644 (file)
@@ -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
index 4a56abc336b8ffa22a92dd352e5ba0c83a02a43f..1ffc2dca214e306914ed48084cf5b0a98f696809 100644 (file)
@@ -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);
index 06db7f70373f5176352654df16ad8d31ecac2449..f2c80a3698eb73147b5f4b51d647a7e9a91beb9f 100644 (file)
@@ -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);
 
index 0b0292070f968525b84d3386fdf4bf9c327b310d..e7c2dd8866057f3c22723c2a41422cdc964f87b1 100644 (file)
@@ -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";
 
index 47243a3f41109a9c50bab5f842fbf26daec84313..71a5cea75a094cac4c2ffd1b076617321a8d4507 100644 (file)
@@ -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.
@@ -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;