Updated through tag hostap_2_5 from git://w1.fi/hostap.git
[mech_eap.git] / libeap / src / ap / wpa_auth_ie.c
index f8a1804..eafb828 100644 (file)
@@ -1,15 +1,9 @@
 /*
  * 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 program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
 #include "wpa_auth_i.h"
 
 
+#ifdef CONFIG_RSN_TESTING
+int rsn_testing = 0;
+#endif /* CONFIG_RSN_TESTING */
+
+
 static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
 {
        struct wpa_ie_hdr *hdr;
        int num_suites;
        u8 *pos, *count;
+       u32 suite;
 
        hdr = (struct wpa_ie_hdr *) buf;
        hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
@@ -37,46 +37,25 @@ static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
        WPA_PUT_LE16(hdr->version, WPA_VERSION);
        pos = (u8 *) (hdr + 1);
 
-       if (conf->wpa_group == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-       } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-       } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP104);
-       } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_WEP40);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
+       if (suite == 0) {
                wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
                           conf->wpa_group);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += WPA_SELECTOR_LEN;
 
-       num_suites = 0;
        count = pos;
        pos += 2;
 
-       if (conf->wpa_pairwise & WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
-               pos += WPA_SELECTOR_LEN;
-               num_suites++;
-       }
-       if (conf->wpa_pairwise & WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
-               pos += WPA_SELECTOR_LEN;
-               num_suites++;
-       }
-       if (conf->wpa_pairwise & WPA_CIPHER_NONE) {
-               RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
-               pos += WPA_SELECTOR_LEN;
-               num_suites++;
-       }
-
+       num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
                           conf->wpa_pairwise);
                return -1;
        }
+       pos += num_suites * WPA_SELECTOR_LEN;
        WPA_PUT_LE16(count, num_suites);
 
        num_suites = 0;
@@ -113,49 +92,48 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                     const u8 *pmkid)
 {
        struct rsn_ie_hdr *hdr;
-       int num_suites;
+       int num_suites, res;
        u8 *pos, *count;
        u16 capab;
+       u32 suite;
 
        hdr = (struct rsn_ie_hdr *) buf;
        hdr->elem_id = WLAN_EID_RSN;
        WPA_PUT_LE16(hdr->version, RSN_VERSION);
        pos = (u8 *) (hdr + 1);
 
-       if (conf->wpa_group == WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-       } else if (conf->wpa_group == WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
-       } else if (conf->wpa_group == WPA_CIPHER_WEP104) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP104);
-       } else if (conf->wpa_group == WPA_CIPHER_WEP40) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_WEP40);
-       } else {
+       suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+       if (suite == 0) {
                wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
                           conf->wpa_group);
                return -1;
        }
+       RSN_SELECTOR_PUT(pos, suite);
        pos += RSN_SELECTOR_LEN;
 
        num_suites = 0;
        count = pos;
        pos += 2;
 
-       if (conf->rsn_pairwise & WPA_CIPHER_CCMP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
-               pos += RSN_SELECTOR_LEN;
-               num_suites++;
-       }
-       if (conf->rsn_pairwise & WPA_CIPHER_TKIP) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
                pos += RSN_SELECTOR_LEN;
                num_suites++;
        }
-       if (conf->rsn_pairwise & WPA_CIPHER_NONE) {
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+#endif /* CONFIG_RSN_TESTING */
+
+       res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+       num_suites += res;
+       pos += res * RSN_SELECTOR_LEN;
+
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
                pos += RSN_SELECTOR_LEN;
                num_suites++;
        }
+#endif /* CONFIG_RSN_TESTING */
 
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
@@ -168,6 +146,14 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        count = pos;
        pos += 2;
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
                RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
                pos += RSN_SELECTOR_LEN;
@@ -202,6 +188,36 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                num_suites++;
        }
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_SAE */
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+               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) {
+               RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_RSN_TESTING */
 
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
@@ -227,6 +243,10 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                        capab |= WPA_CAPABILITY_MFPR;
        }
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing)
+               capab |= BIT(8) | BIT(14) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
        WPA_PUT_LE16(pos, capab);
        pos += 2;
 
@@ -241,7 +261,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
        }
 
 #ifdef CONFIG_IEEE80211W
-       if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+       if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+           conf->group_mgmt_cipher != WPA_CIPHER_AES_128_CMAC) {
                if (pos + 2 + 4 > buf + len)
                        return -1;
                if (pmkid == NULL) {
@@ -251,24 +272,134 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                }
 
                /* Management Group Cipher Suite */
-               RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+               switch (conf->group_mgmt_cipher) {
+               case WPA_CIPHER_AES_128_CMAC:
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+                       break;
+               case WPA_CIPHER_BIP_GMAC_128:
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_128);
+                       break;
+               case WPA_CIPHER_BIP_GMAC_256:
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_GMAC_256);
+                       break;
+               case WPA_CIPHER_BIP_CMAC_256:
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_BIP_CMAC_256);
+                       break;
+               default:
+                       wpa_printf(MSG_DEBUG,
+                                  "Invalid group management cipher (0x%x)",
+                                  conf->group_mgmt_cipher);
+                       return -1;
+               }
                pos += RSN_SELECTOR_LEN;
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_RSN_TESTING
+       if (rsn_testing) {
+               /*
+                * Fill in any defined fields and add extra data to the end of
+                * the element.
+                */
+               int pmkid_count_set = pmkid != NULL;
+               if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+                       pmkid_count_set = 1;
+               /* PMKID Count */
+               WPA_PUT_LE16(pos, 0);
+               pos += 2;
+               if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+                       /* Management Group Cipher Suite */
+                       RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+                       pos += RSN_SELECTOR_LEN;
+               }
+
+               os_memset(pos, 0x12, 17);
+               pos += 17;
+       }
+#endif /* CONFIG_RSN_TESTING */
+
        hdr->len = (pos - buf) - 2;
 
        return pos - buf;
 }
 
 
+static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
+{
+       u8 *len;
+       u16 capab;
+
+       *eid++ = WLAN_EID_VENDOR_SPECIFIC;
+       len = eid++; /* to be filled */
+       WPA_PUT_BE24(eid, OUI_WFA);
+       eid += 3;
+       *eid++ = HS20_OSEN_OUI_TYPE;
+
+       /* Group Data Cipher Suite */
+       RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED);
+       eid += RSN_SELECTOR_LEN;
+
+       /* Pairwise Cipher Suite Count and List */
+       WPA_PUT_LE16(eid, 1);
+       eid += 2;
+       RSN_SELECTOR_PUT(eid, RSN_CIPHER_SUITE_CCMP);
+       eid += RSN_SELECTOR_LEN;
+
+       /* AKM Suite Count and List */
+       WPA_PUT_LE16(eid, 1);
+       eid += 2;
+       RSN_SELECTOR_PUT(eid, RSN_AUTH_KEY_MGMT_OSEN);
+       eid += RSN_SELECTOR_LEN;
+
+       /* RSN Capabilities */
+       capab = 0;
+       if (conf->wmm_enabled) {
+               /* 4 PTKSA replay counters when using WMM */
+               capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+       }
+#ifdef CONFIG_IEEE80211W
+       if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+               capab |= WPA_CAPABILITY_MFPC;
+               if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+                       capab |= WPA_CAPABILITY_MFPR;
+       }
+#endif /* CONFIG_IEEE80211W */
+       WPA_PUT_LE16(eid, capab);
+       eid += 2;
+
+       *len = eid - len - 1;
+
+       return eid;
+}
+
+
 int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
 {
        u8 *pos, buf[128];
        int res;
 
+#ifdef CONFIG_TESTING_OPTIONS
+       if (wpa_auth->conf.own_ie_override_len) {
+               wpa_hexdump(MSG_DEBUG, "WPA: Forced own IE(s) for testing",
+                           wpa_auth->conf.own_ie_override,
+                           wpa_auth->conf.own_ie_override_len);
+               os_free(wpa_auth->wpa_ie);
+               wpa_auth->wpa_ie =
+                       os_malloc(wpa_auth->conf.own_ie_override_len);
+               if (wpa_auth->wpa_ie == NULL)
+                       return -1;
+               os_memcpy(wpa_auth->wpa_ie, wpa_auth->conf.own_ie_override,
+                         wpa_auth->conf.own_ie_override_len);
+               wpa_auth->wpa_ie_len = wpa_auth->conf.own_ie_override_len;
+               return 0;
+       }
+#endif /* CONFIG_TESTING_OPTIONS */
+
        pos = buf;
 
+       if (wpa_auth->conf.wpa == WPA_PROTO_OSEN) {
+               pos = wpa_write_osen(&wpa_auth->conf, pos);
+       }
        if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
                res = wpa_write_rsn_ie(&wpa_auth->conf,
                                       pos, buf + sizeof(buf) - pos, NULL);
@@ -277,8 +408,7 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
                pos += res;
        }
 #ifdef CONFIG_IEEE80211R
-       if (wpa_auth->conf.wpa_key_mgmt &
-           (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+       if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
                res = wpa_write_mdie(&wpa_auth->conf, pos,
                                     buf + sizeof(buf) - pos);
                if (res < 0)
@@ -322,114 +452,6 @@ u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
 }
 
 
-static int wpa_selector_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
-               return WPA_CIPHER_NONE;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
-               return WPA_CIPHER_WEP40;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
-               return WPA_CIPHER_TKIP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
-               return WPA_CIPHER_CCMP;
-       if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
-               return WPA_CIPHER_WEP104;
-       return 0;
-}
-
-
-static int wpa_key_mgmt_to_bitfield(const u8 *s)
-{
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
-               return WPA_KEY_MGMT_IEEE8021X;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
-               return WPA_KEY_MGMT_PSK;
-       if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
-               return WPA_KEY_MGMT_WPA_NONE;
-       return 0;
-}
-
-
-static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
-                               struct wpa_ie_data *data)
-{
-       const struct wpa_ie_hdr *hdr;
-       const u8 *pos;
-       int left;
-       int i, count;
-
-       os_memset(data, 0, sizeof(*data));
-       data->pairwise_cipher = WPA_CIPHER_TKIP;
-       data->group_cipher = WPA_CIPHER_TKIP;
-       data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-       data->mgmt_group_cipher = 0;
-
-       if (wpa_ie_len < sizeof(struct wpa_ie_hdr))
-               return -1;
-
-       hdr = (const struct wpa_ie_hdr *) wpa_ie;
-
-       if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
-           hdr->len != wpa_ie_len - 2 ||
-           RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
-           WPA_GET_LE16(hdr->version) != WPA_VERSION) {
-               return -2;
-       }
-
-       pos = (const u8 *) (hdr + 1);
-       left = wpa_ie_len - sizeof(*hdr);
-
-       if (left >= WPA_SELECTOR_LEN) {
-               data->group_cipher = wpa_selector_to_bitfield(pos);
-               pos += WPA_SELECTOR_LEN;
-               left -= WPA_SELECTOR_LEN;
-       } else if (left > 0)
-                 return -3;
-
-       if (left >= 2) {
-               data->pairwise_cipher = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN)
-                       return -4;
-               for (i = 0; i < count; i++) {
-                       data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1)
-               return -5;
-
-       if (left >= 2) {
-               data->key_mgmt = 0;
-               count = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-               if (count == 0 || left < count * WPA_SELECTOR_LEN)
-                       return -6;
-               for (i = 0; i < count; i++) {
-                       data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
-                       pos += WPA_SELECTOR_LEN;
-                       left -= WPA_SELECTOR_LEN;
-               }
-       } else if (left == 1)
-               return -7;
-
-       if (left >= 2) {
-               data->capabilities = WPA_GET_LE16(pos);
-               pos += 2;
-               left -= 2;
-       }
-
-       if (left > 0) {
-               return -8;
-       }
-
-       return 0;
-}
-
-
 struct wpa_auth_okc_iter_data {
        struct rsn_pmksa_cache_entry *pmksa;
        const u8 *aa;
@@ -483,6 +505,10 @@ 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
                else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
                        selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
@@ -495,36 +521,28 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                        selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+               else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_SAE;
+               else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+                       selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
                else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                        selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
                else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
                        selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
                wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
 
-               selector = RSN_CIPHER_SUITE_CCMP;
-               if (data.pairwise_cipher & WPA_CIPHER_CCMP)
+               selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+                                              data.pairwise_cipher);
+               if (!selector)
                        selector = RSN_CIPHER_SUITE_CCMP;
-               else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
-                       selector = RSN_CIPHER_SUITE_TKIP;
-               else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
-                       selector = RSN_CIPHER_SUITE_WEP104;
-               else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
-                       selector = RSN_CIPHER_SUITE_WEP40;
-               else if (data.pairwise_cipher & WPA_CIPHER_NONE)
-                       selector = RSN_CIPHER_SUITE_NONE;
                wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
 
-               selector = RSN_CIPHER_SUITE_CCMP;
-               if (data.group_cipher & WPA_CIPHER_CCMP)
+               selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+                                              data.group_cipher);
+               if (!selector)
                        selector = RSN_CIPHER_SUITE_CCMP;
-               else if (data.group_cipher & WPA_CIPHER_TKIP)
-                       selector = RSN_CIPHER_SUITE_TKIP;
-               else if (data.group_cipher & WPA_CIPHER_WEP104)
-                       selector = RSN_CIPHER_SUITE_WEP104;
-               else if (data.group_cipher & WPA_CIPHER_WEP40)
-                       selector = RSN_CIPHER_SUITE_WEP40;
-               else if (data.group_cipher & WPA_CIPHER_NONE)
-                       selector = RSN_CIPHER_SUITE_NONE;
                wpa_auth->dot11RSNAGroupCipherSelected = selector;
        } else {
                res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
@@ -536,30 +554,16 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                        selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
                wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
 
-               selector = WPA_CIPHER_SUITE_TKIP;
-               if (data.pairwise_cipher & WPA_CIPHER_CCMP)
-                       selector = WPA_CIPHER_SUITE_CCMP;
-               else if (data.pairwise_cipher & WPA_CIPHER_TKIP)
-                       selector = WPA_CIPHER_SUITE_TKIP;
-               else if (data.pairwise_cipher & WPA_CIPHER_WEP104)
-                       selector = WPA_CIPHER_SUITE_WEP104;
-               else if (data.pairwise_cipher & WPA_CIPHER_WEP40)
-                       selector = WPA_CIPHER_SUITE_WEP40;
-               else if (data.pairwise_cipher & WPA_CIPHER_NONE)
-                       selector = WPA_CIPHER_SUITE_NONE;
+               selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+                                              data.pairwise_cipher);
+               if (!selector)
+                       selector = RSN_CIPHER_SUITE_TKIP;
                wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
 
-               selector = WPA_CIPHER_SUITE_TKIP;
-               if (data.group_cipher & WPA_CIPHER_CCMP)
-                       selector = WPA_CIPHER_SUITE_CCMP;
-               else if (data.group_cipher & WPA_CIPHER_TKIP)
+               selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+                                              data.group_cipher);
+               if (!selector)
                        selector = WPA_CIPHER_SUITE_TKIP;
-               else if (data.group_cipher & WPA_CIPHER_WEP104)
-                       selector = WPA_CIPHER_SUITE_WEP104;
-               else if (data.group_cipher & WPA_CIPHER_WEP40)
-                       selector = WPA_CIPHER_SUITE_WEP40;
-               else if (data.group_cipher & WPA_CIPHER_NONE)
-                       selector = WPA_CIPHER_SUITE_NONE;
                wpa_auth->dot11RSNAGroupCipherSelected = selector;
        }
        if (res) {
@@ -583,6 +587,10 @@ 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
        else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -595,6 +603,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+       else if (key_mgmt & WPA_KEY_MGMT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+       else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
        else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
        else
@@ -626,7 +640,8 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                        return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
                }
 
-               if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+               if (data.mgmt_group_cipher != wpa_auth->conf.group_mgmt_cipher)
+               {
                        wpa_printf(MSG_DEBUG, "Unsupported management group "
                                   "cipher %d", data.mgmt_group_cipher);
                        return WPA_INVALID_MGMT_GROUP_CIPHER;
@@ -656,10 +671,9 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        }
 #endif /* CONFIG_IEEE80211R */
 
-       if (ciphers & WPA_CIPHER_CCMP)
-               sm->pairwise = WPA_CIPHER_CCMP;
-       else
-               sm->pairwise = WPA_CIPHER_TKIP;
+       sm->pairwise = wpa_pick_pairwise_cipher(ciphers, 0);
+       if (sm->pairwise < 0)
+               return WPA_INVALID_PAIRWISE;
 
        /* TODO: clear WPA/WPA2 state if STA changes from one to another */
        if (wpa_ie[0] == WLAN_EID_RSN)
@@ -697,7 +711,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                        break;
                }
        }
-       if (sm->pmksa) {
+       if (sm->pmksa && pmkid) {
                wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
                                 "PMKID found from PMKSA cache "
                                 "eap_type=%d vlan_id=%d",
@@ -719,6 +733,36 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 }
 
 
+#ifdef CONFIG_HS20
+int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
+                     struct wpa_state_machine *sm,
+                     const u8 *osen_ie, size_t osen_ie_len)
+{
+       if (wpa_auth == NULL || sm == NULL)
+               return -1;
+
+       /* TODO: parse OSEN element */
+       sm->wpa_key_mgmt = WPA_KEY_MGMT_OSEN;
+       sm->mgmt_frame_prot = 1;
+       sm->pairwise = WPA_CIPHER_CCMP;
+       sm->wpa = WPA_VERSION_WPA2;
+
+       if (sm->wpa_ie == NULL || sm->wpa_ie_len < osen_ie_len) {
+               os_free(sm->wpa_ie);
+               sm->wpa_ie = os_malloc(osen_ie_len);
+               if (sm->wpa_ie == NULL)
+                       return -1;
+       }
+
+       os_memcpy(sm->wpa_ie, osen_ie, osen_ie_len);
+       sm->wpa_ie_len = osen_ie_len;
+
+       return 0;
+}
+
+#endif /* CONFIG_HS20 */
+
+
 /**
  * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
  * @pos: Pointer to the IE header
@@ -741,6 +785,12 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
                return 0;
        }
 
+       if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+               ie->osen = pos;
+               ie->osen_len = pos[1] + 2;
+               return 0;
+       }
+
        if (pos + 1 + RSN_SELECTOR_LEN < end &&
            pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
            RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
@@ -801,6 +851,25 @@ static int wpa_parse_generic(const u8 *pos, const u8 *end,
        }
 #endif /* CONFIG_IEEE80211W */
 
+#ifdef CONFIG_P2P
+       if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+           RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+               ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+                           ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+               return 0;
+       }
+
+       if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+           RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+               ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+               wpa_hexdump(MSG_DEBUG,
+                           "WPA: IP Address Allocation in EAPOL-Key",
+                           ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+               return 0;
+       }
+#endif /* CONFIG_P2P */
+
        return 0;
 }