WPS: Add option for forcing Registrar to use PSK format in Credential
[libeap.git] / hostapd / wpa_auth_ie.c
index 3e011b2..da37f82 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 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
@@ -17,7 +17,7 @@
 #include "common.h"
 #include "config.h"
 #include "ieee802_11.h"
-#include "eapol_sm.h"
+#include "eapol_auth/eapol_auth_sm.h"
 #include "wpa.h"
 #include "pmksa_cache.h"
 #include "wpa_auth_ie.h"
@@ -189,6 +189,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                num_suites++;
        }
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+       if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+               RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+               pos += RSN_SELECTOR_LEN;
+               num_suites++;
+       }
+#endif /* CONFIG_IEEE80211W */
 
        if (num_suites == 0) {
                wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
@@ -203,13 +215,16 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
                capab |= WPA_CAPABILITY_PREAUTH;
        if (conf->peerkey)
                capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
-       if (conf->wme_enabled) {
-               /* 4 PTKSA replay counters when using WME */
+       if (conf->wmm_enabled) {
+               /* 4 PTKSA replay counters when using WMM */
                capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
        }
 #ifdef CONFIG_IEEE80211W
-       if (conf->ieee80211w != WPA_NO_IEEE80211W)
-               capab |= WPA_CAPABILITY_MGMT_FRAME_PROTECTION;
+       if (conf->ieee80211w != WPA_NO_IEEE80211W) {
+               capab |= WPA_CAPABILITY_MFPC;
+               if (conf->ieee80211w == IEEE80211W_REQUIRED)
+                       capab |= WPA_CAPABILITY_MFPR;
+       }
 #endif /* CONFIG_IEEE80211W */
        WPA_PUT_LE16(pos, capab);
        pos += 2;
@@ -414,6 +429,25 @@ static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
 }
 
 
+struct wpa_auth_okc_iter_data {
+       struct rsn_pmksa_cache_entry *pmksa;
+       const u8 *aa;
+       const u8 *spa;
+       const u8 *pmkid;
+};
+
+
+static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
+{
+       struct wpa_auth_okc_iter_data *data = ctx;
+       data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
+                                         data->pmkid);
+       if (data->pmksa)
+               return 1;
+       return 0;
+}
+
+
 int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                        struct wpa_state_machine *sm,
                        const u8 *wpa_ie, size_t wpa_ie_len,
@@ -423,6 +457,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        int ciphers, key_mgmt, res, version;
        u32 selector;
        size_t i;
+       const u8 *pmkid = NULL;
 
        if (wpa_auth == NULL || sm == NULL)
                return WPA_NOT_ENABLED;
@@ -435,6 +470,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else
                version = WPA_PROTO_WPA;
 
+       if (!(wpa_auth->conf.wpa & version)) {
+               wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
+                          version, MAC2STR(sm->addr));
+               return WPA_INVALID_PROTO;
+       }
+
        if (version == WPA_PROTO_RSN) {
                res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
 
@@ -447,6 +488,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
                else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
                        selector = RSN_AUTH_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+               else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+                       selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+               else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+                       selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
                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)
@@ -541,6 +588,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+       else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+       else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+               sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
        else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
                sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
        else
@@ -560,8 +613,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 
 #ifdef CONFIG_IEEE80211W
        if (wpa_auth->conf.ieee80211w == WPA_IEEE80211W_REQUIRED) {
-               if (!(data.capabilities &
-                     WPA_CAPABILITY_MGMT_FRAME_PROTECTION)) {
+               if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
                        wpa_printf(MSG_DEBUG, "Management frame protection "
                                   "required, but client did not enable it");
                        return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
@@ -581,15 +633,14 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        }
 
        if (wpa_auth->conf.ieee80211w == WPA_NO_IEEE80211W ||
-           !(data.capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION))
+           !(data.capabilities & WPA_CAPABILITY_MFPC))
                sm->mgmt_frame_prot = 0;
        else
                sm->mgmt_frame_prot = 1;
 #endif /* CONFIG_IEEE80211W */
 
 #ifdef CONFIG_IEEE80211R
-       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-           sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
                if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
                        wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
                                   "MDIE not included");
@@ -615,22 +666,44 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
        else
                sm->wpa = WPA_VERSION_WPA;
 
+       sm->pmksa = NULL;
        for (i = 0; i < data.num_pmkid; i++) {
                wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
                            &data.pmkid[i * PMKID_LEN], PMKID_LEN);
-               sm->pmksa = pmksa_cache_get(wpa_auth->pmksa, sm->addr,
-                                           &data.pmkid[i * PMKID_LEN]);
+               sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
+                                                &data.pmkid[i * PMKID_LEN]);
                if (sm->pmksa) {
+                       pmkid = sm->pmksa->pmkid;
+                       break;
+               }
+       }
+       for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
+                    i < data.num_pmkid; i++) {
+               struct wpa_auth_okc_iter_data idata;
+               idata.pmksa = NULL;
+               idata.aa = wpa_auth->addr;
+               idata.spa = sm->addr;
+               idata.pmkid = &data.pmkid[i * PMKID_LEN];
+               wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
+               if (idata.pmksa) {
                        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
-                                        "PMKID found from PMKSA cache "
-                                        "eap_type=%d vlan_id=%d",
-                                        sm->pmksa->eap_type_authsrv,
-                                        sm->pmksa->vlan_id);
-                       os_memcpy(wpa_auth->dot11RSNAPMKIDUsed,
-                                 sm->pmksa->pmkid, PMKID_LEN);
+                                        "OKC match for PMKID");
+                       sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
+                                                       idata.pmksa,
+                                                       wpa_auth->addr,
+                                                       idata.pmkid);
+                       pmkid = idata.pmkid;
                        break;
                }
        }
+       if (sm->pmksa) {
+               wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+                                "PMKID found from PMKSA cache "
+                                "eap_type=%d vlan_id=%d",
+                                sm->pmksa->eap_type_authsrv,
+                                sm->pmksa->vlan_id);
+               os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
+       }
 
        if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
                os_free(sm->wpa_ie);
@@ -783,3 +856,9 @@ int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
 
        return ret;
 }
+
+
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
+{
+       return sm ? sm->mgmt_frame_prot : 0;
+}