Remove src/crypto from default include path
[libeap.git] / hostapd / wpa.c
index 4502808..73425e6 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, 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
 #ifndef CONFIG_NATIVE_WINDOWS
 
 #include "common.h"
+#include "eloop.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "eapol_auth/eapol_auth_sm.h"
 #include "config.h"
-#include "eapol_sm.h"
 #include "wpa.h"
-#include "sha1.h"
-#include "rc4.h"
-#include "aes_wrap.h"
-#include "crypto.h"
-#include "eloop.h"
 #include "ieee802_11.h"
 #include "pmksa_cache.h"
 #include "state_machine.h"
@@ -42,13 +42,14 @@ static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
 static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
 static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
                              struct wpa_group *group);
+static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+                         struct wpa_group *group);
 
-/* Default timeouts are 100 ms, but this seems to be a bit too fast for most
- * WPA Supplicants, so use a bit longer timeout. */
-static const u32 dot11RSNAConfigGroupUpdateTimeOut = 1000; /* ms */
-static const u32 dot11RSNAConfigGroupUpdateCount = 3;
-static const u32 dot11RSNAConfigPairwiseUpdateTimeOut = 1000; /* ms */
-static const u32 dot11RSNAConfigPairwiseUpdateCount = 3;
+static const u32 dot11RSNAConfigGroupUpdateCount = 4;
+static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
+static const u32 eapol_key_timeout_first = 100; /* ms */
+static const u32 eapol_key_timeout_subseq = 1000; /* ms */
 
 /* TODO: make these configurable */
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -102,7 +103,7 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
 
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
                                   int vlan_id,
-                                  const char *alg, const u8 *addr, int idx,
+                                  wpa_alg alg, const u8 *addr, int idx,
                                   u8 *key, size_t key_len)
 {
        if (wpa_auth->cb.set_key == NULL)
@@ -207,12 +208,16 @@ static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
 
 static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
 {
+       int ret = 0;
 #ifdef CONFIG_IEEE80211R
-       return sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-               sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK;
-#else /* CONFIG_IEEE80211R */
-       return 0;
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+               ret = 1;
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+       if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
+               ret = 1;
+#endif /* CONFIG_IEEE80211W */
+       return ret;
 }
 
 
@@ -255,6 +260,17 @@ static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
 }
 
 
+static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+       struct wpa_authenticator *wpa_auth = eloop_ctx;
+       struct wpa_state_machine *sm = timeout_ctx;
+
+       wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+       wpa_request_new_ptk(sm);
+       wpa_sm_step(sm);
+}
+
+
 static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
 {
        if (sm->pmksa == ctx)
@@ -271,21 +287,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
 }
 
 
-static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-                                        int vlan_id)
+static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
 {
-       struct wpa_group *group;
-       u8 buf[ETH_ALEN + 8 + sizeof(group)];
-       u8 rkey[32];
-
-       group = os_zalloc(sizeof(struct wpa_group));
-       if (group == NULL)
-               return NULL;
-
-       group->GTKAuthenticator = TRUE;
-       group->vlan_id = vlan_id;
-
-       switch (wpa_auth->conf.wpa_group) {
+       switch (cipher) {
        case WPA_CIPHER_CCMP:
                group->GTK_len = 16;
                break;
@@ -299,6 +303,24 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
                group->GTK_len = 5;
                break;
        }
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+                                        int vlan_id)
+{
+       struct wpa_group *group;
+       u8 buf[ETH_ALEN + 8 + sizeof(group)];
+       u8 rkey[32];
+
+       group = os_zalloc(sizeof(struct wpa_group));
+       if (group == NULL)
+               return NULL;
+
+       group->GTKAuthenticator = TRUE;
+       group->vlan_id = vlan_id;
+
+       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
 
        /* Counter = PRF-256(Random number, "Init Counter",
         *                   Local MAC Address || Time)
@@ -330,6 +352,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
  * wpa_init - Initialize WPA authenticator
  * @addr: Authenticator address
  * @conf: Configuration for WPA authenticator
+ * @cb: Callback functions for WPA authenticator
  * Returns: Pointer to WPA authenticator data or %NULL on failure
  */
 struct wpa_authenticator * wpa_init(const u8 *addr,
@@ -358,7 +381,8 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
                return NULL;
        }
 
-       wpa_auth->pmksa = pmksa_cache_init(wpa_auth_pmksa_free_cb, wpa_auth);
+       wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
+                                               wpa_auth);
        if (wpa_auth->pmksa == NULL) {
                wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
                os_free(wpa_auth->wpa_ie);
@@ -371,7 +395,7 @@ struct wpa_authenticator * wpa_init(const u8 *addr,
        if (wpa_auth->ft_pmk_cache == NULL) {
                wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
                os_free(wpa_auth->wpa_ie);
-               pmksa_cache_deinit(wpa_auth->pmksa);
+               pmksa_cache_auth_deinit(wpa_auth->pmksa);
                os_free(wpa_auth);
                return NULL;
        }
@@ -407,7 +431,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
                wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
 #endif /* CONFIG_PEERKEY */
 
-       pmksa_cache_deinit(wpa_auth->pmksa);
+       pmksa_cache_auth_deinit(wpa_auth->pmksa);
 
 #ifdef CONFIG_IEEE80211R
        wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
@@ -435,15 +459,27 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
                 struct wpa_auth_config *conf)
 {
+       struct wpa_group *group;
        if (wpa_auth == NULL)
                return 0;
 
        os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+       if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+               wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+               return -1;
+       }
+
        /*
-        * TODO:
-        * Disassociate stations if configuration changed
-        * Update WPA/RSN IE
+        * Reinitialize GTK to make sure it is suitable for the new
+        * configuration.
         */
+       group = wpa_auth->group;
+       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+       group->GInit = TRUE;
+       wpa_group_sm_step(wpa_auth, group);
+       group->GInit = FALSE;
+       wpa_group_sm_step(wpa_auth, group);
+
        return 0;
 }
 
@@ -481,7 +517,7 @@ void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_IEEE80211R */
 
        if (sm->started) {
-               os_memset(sm->key_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+               os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
                sm->ReAuthenticationRequest = TRUE;
                wpa_sm_step(sm);
                return;
@@ -499,6 +535,18 @@ void wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
 }
 
 
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
+{
+       /* WPA/RSN was not used - clear WPA state. This is needed if the STA
+        * reassociates back to the same AP while the previous entry for the
+        * STA has not yet been removed. */
+       if (sm == NULL)
+               return;
+
+       sm->wpa_key_mgmt = 0;
+}
+
+
 static void wpa_free_sta_sm(struct wpa_state_machine *sm)
 {
        os_free(sm->last_rx_eapol_key);
@@ -523,6 +571,7 @@ void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
 
        eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
        eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
+       eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
        if (sm->in_step_loop) {
                /* Must not free state machine while wpa_sm_step() is running.
                 * Freeing will be completed in the end of wpa_sm_step(). */
@@ -544,6 +593,21 @@ static void wpa_request_new_ptk(struct wpa_state_machine *sm)
 }
 
 
+static int wpa_replay_counter_valid(struct wpa_state_machine *sm,
+                                   const u8 *replay_counter)
+{
+       int i;
+       for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+               if (!sm->key_replay[i].valid)
+                       break;
+               if (os_memcmp(replay_counter, sm->key_replay[i].counter,
+                             WPA_REPLAY_COUNTER_LEN) == 0)
+                       return 1;
+       }
+       return 0;
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
                 struct wpa_state_machine *sm,
                 u8 *data, size_t data_len)
@@ -575,6 +639,22 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                return;
        }
 
+       if (sm->wpa == WPA_VERSION_WPA2) {
+               if (key->type != EAPOL_KEY_TYPE_RSN) {
+                       wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+                                  "unexpected type %d in RSN mode",
+                                  key->type);
+                       return;
+               }
+       } else {
+               if (key->type != EAPOL_KEY_TYPE_WPA) {
+                       wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+                                  "unexpected type %d in WPA mode",
+                                  key->type);
+                       return;
+               }
+       }
+
        /* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
         * are set */
 
@@ -642,14 +722,18 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        }
 
        if (!(key_info & WPA_KEY_INFO_REQUEST) &&
-           (!sm->key_replay_counter_valid ||
-            os_memcmp(key->replay_counter, sm->key_replay_counter,
-                      WPA_REPLAY_COUNTER_LEN) != 0)) {
+           !wpa_replay_counter_valid(sm, key->replay_counter)) {
+               int i;
                wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
                                 "received EAPOL-Key %s with unexpected "
                                 "replay counter", msgtxt);
-               wpa_hexdump(MSG_DEBUG, "expected replay counter",
-                           sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
+               for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+                       if (!sm->key_replay[i].valid)
+                               break;
+                       wpa_hexdump(MSG_DEBUG, "pending replay counter",
+                                   sm->key_replay[i].counter,
+                                   WPA_REPLAY_COUNTER_LEN);
+               }
                wpa_hexdump(MSG_DEBUG, "received replay counter",
                            key->replay_counter, WPA_REPLAY_COUNTER_LEN);
                return;
@@ -812,8 +896,12 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                        wpa_rekey_gtk(wpa_auth, NULL);
                }
        } else {
-               /* Do not allow the same key replay counter to be reused. */
-               sm->key_replay_counter_valid = FALSE;
+               /* Do not allow the same key replay counter to be reused. This
+                * does also invalidate all other pending replay counters if
+                * retransmissions were used, i.e., we will only process one of
+                * the pending replies and ignore rest if more than one is
+                * received. */
+               sm->key_replay[0].valid = FALSE;
        }
 
 #ifdef CONFIG_PEERKEY
@@ -847,8 +935,13 @@ static void wpa_gmk_to_gtk(const u8 *gmk, const u8 *addr, const u8 *gnonce,
        os_memcpy(data, addr, ETH_ALEN);
        os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
 
+#ifdef CONFIG_IEEE80211W
+       sha256_prf(gmk, WPA_GMK_LEN, "Group key expansion",
+                  data, sizeof(data), gtk, gtk_len);
+#else /* CONFIG_IEEE80211W */
        sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
                 data, sizeof(data), gtk, gtk_len);
+#endif /* CONFIG_IEEE80211W */
 
        wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
        wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
@@ -879,6 +972,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        int key_data_len, pad_len = 0;
        u8 *buf, *pos;
        int version, pairwise;
+       int i;
 
        len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
 
@@ -951,10 +1045,16 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                WPA_PUT_BE16(key->key_length, 0);
 
        /* FIX: STSL: what to use as key_replay_counter? */
-       inc_byte_array(sm->key_replay_counter, WPA_REPLAY_COUNTER_LEN);
-       os_memcpy(key->replay_counter, sm->key_replay_counter,
+       for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
+               sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
+               os_memcpy(sm->key_replay[i].counter,
+                         sm->key_replay[i - 1].counter,
+                         WPA_REPLAY_COUNTER_LEN);
+       }
+       inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
+       os_memcpy(key->replay_counter, sm->key_replay[0].counter,
                  WPA_REPLAY_COUNTER_LEN);
-       sm->key_replay_counter_valid = TRUE;
+       sm->key_replay[0].valid = TRUE;
 
        if (nonce)
                os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
@@ -1031,6 +1131,7 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
 {
        int timeout_ms;
        int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+       int ctr;
 
        if (sm == NULL)
                return;
@@ -1038,8 +1139,11 @@ static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        __wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
                         keyidx, encr, 0);
 
-       timeout_ms = pairwise ? dot11RSNAConfigPairwiseUpdateTimeOut :
-               dot11RSNAConfigGroupUpdateTimeOut;
+       ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
+       if (ctr == 1)
+               timeout_ms = eapol_key_timeout_first;
+       else
+               timeout_ms = eapol_key_timeout_subseq;
        eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
                               wpa_send_eapol_timeout, wpa_auth, sm);
 }
@@ -1074,13 +1178,17 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
 {
        sm->PTK_valid = FALSE;
        os_memset(&sm->PTK, 0, sizeof(sm->PTK));
-       wpa_auth_set_key(sm->wpa_auth, 0, "none", sm->addr, 0, (u8 *) "", 0);
+       wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, (u8 *) "",
+                        0);
        sm->pairwise_set = FALSE;
+       eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
 }
 
 
 void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 {
+       int remove_ptk = 1;
+
        if (sm == NULL)
                return;
 
@@ -1097,6 +1205,15 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
                break;
        case WPA_REAUTH:
        case WPA_REAUTH_EAPOL:
+               if (sm->GUpdateStationKeys) {
+                       /*
+                        * Reauthentication cancels the pending group key
+                        * update for this STA.
+                        */
+                       sm->group->GKeyDoneStations--;
+                       sm->GUpdateStationKeys = FALSE;
+                       sm->PtkGroupInit = TRUE;
+               }
                sm->ReAuthenticationRequest = TRUE;
                break;
        case WPA_ASSOC_FT:
@@ -1113,28 +1230,35 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
        sm->ft_completed = 0;
 #endif /* CONFIG_IEEE80211R */
 
-       sm->PTK_valid = FALSE;
-       os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+#ifdef CONFIG_IEEE80211W
+       if (sm->mgmt_frame_prot && event == WPA_AUTH)
+               remove_ptk = 0;
+#endif /* CONFIG_IEEE80211W */
 
-       if (event != WPA_REAUTH_EAPOL)
-               wpa_remove_ptk(sm);
+       if (remove_ptk) {
+               sm->PTK_valid = FALSE;
+               os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+               if (event != WPA_REAUTH_EAPOL)
+                       wpa_remove_ptk(sm);
+       }
 
        wpa_sm_step(sm);
 }
 
 
-static const char * wpa_alg_txt(int alg)
+static wpa_alg wpa_alg_enum(int alg)
 {
        switch (alg) {
        case WPA_CIPHER_CCMP:
-               return "CCMP";
+               return WPA_ALG_CCMP;
        case WPA_CIPHER_TKIP:
-               return "TKIP";
+               return WPA_ALG_TKIP;
        case WPA_CIPHER_WEP104:
        case WPA_CIPHER_WEP40:
-               return "WEP";
+               return WPA_ALG_WEP;
        default:
-               return "";
+               return WPA_ALG_NONE;
        }
 }
 
@@ -1162,8 +1286,7 @@ SM_STATE(WPA_PTK, INITIALIZE)
        wpa_remove_ptk(sm);
        wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
        sm->TimeoutCtr = 0;
-       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK ||
-           sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+       if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
                wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
                                   WPA_EAPOL_authorized, 0);
        }
@@ -1274,6 +1397,14 @@ SM_STATE(WPA_PTK, PTKSTART)
        SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
        sm->PTKRequest = FALSE;
        sm->TimeoutEvt = FALSE;
+
+       sm->TimeoutCtr++;
+       if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+               /* No point in sending the EAPOL-Key - we will disconnect
+                * immediately following this. */
+               return;
+       }
+
        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                        "sending 1/4 msg of 4-Way Handshake");
        /*
@@ -1281,7 +1412,7 @@ SM_STATE(WPA_PTK, PTKSTART)
         * one possible PSK for this STA.
         */
        if (sm->wpa == WPA_VERSION_WPA2 &&
-           sm->wpa_key_mgmt != WPA_KEY_MGMT_PSK) {
+           wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
                pmkid = buf;
                pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
                pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
@@ -1296,28 +1427,29 @@ SM_STATE(WPA_PTK, PTKSTART)
                         * available with pre-calculated PMKID.
                         */
                        rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
-                                 sm->addr, &pmkid[2 + RSN_SELECTOR_LEN]);
+                                 sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+                                 wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
                }
        }
        wpa_send_eapol(sm->wpa_auth, sm,
                       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
                       sm->ANonce, pmkid, pmkid_len, 0, 0);
-       sm->TimeoutCtr++;
 }
 
 
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
                          struct wpa_ptk *ptk)
 {
+       size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
 #ifdef CONFIG_IEEE80211R
-       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-           sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK)
-               return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+       if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+               return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
 #endif /* CONFIG_IEEE80211R */
 
        wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
                       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
-                      (u8 *) ptk, sizeof(*ptk));
+                      (u8 *) ptk, ptk_len,
+                      wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
 
        return 0;
 }
@@ -1336,8 +1468,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
         * WPA-PSK: iterate through possible PSKs and select the one matching
         * the packet */
        for (;;) {
-               if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK ||
-                   sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+               if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
                        pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
                        if (pmk == NULL)
                                break;
@@ -1352,8 +1483,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        break;
                }
 
-               if (sm->wpa_key_mgmt != WPA_KEY_MGMT_PSK &&
-                   sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+               if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
                        break;
        }
 
@@ -1365,8 +1495,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 
        eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 
-       if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK ||
-           sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+       if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
                /* PSK may have changed from the previous choice, so update
                 * state machine data based on whatever PSK was selected here.
                 */
@@ -1445,6 +1574,14 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 
        SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
        sm->TimeoutEvt = FALSE;
+
+       sm->TimeoutCtr++;
+       if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+               /* No point in sending the EAPOL-Key - we will disconnect
+                * immediately following this. */
+               return;
+       }
+
        /* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, GTK[GN])
         */
        os_memset(rsc, 0, WPA_KEY_RSC_LEN);
@@ -1502,7 +1639,6 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                       WPA_KEY_INFO_KEY_TYPE,
                       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
        os_free(kde);
-       sm->TimeoutCtr++;
 }
 
 
@@ -1511,13 +1647,13 @@ SM_STATE(WPA_PTK, PTKINITDONE)
        SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
        if (sm->Pair) {
-               char *alg;
+               wpa_alg alg;
                int klen;
                if (sm->pairwise == WPA_CIPHER_TKIP) {
-                       alg = "TKIP";
+                       alg = WPA_ALG_TKIP;
                        klen = 32;
                } else {
-                       alg = "CCMP";
+                       alg = WPA_ALG_CCMP;
                        klen = 16;
                }
                if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
@@ -1528,8 +1664,14 @@ SM_STATE(WPA_PTK, PTKINITDONE)
                /* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
                sm->pairwise_set = TRUE;
 
-               if (sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK ||
-                   sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+               if (sm->wpa_auth->conf.wpa_ptk_rekey) {
+                       eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+                       eloop_register_timeout(sm->wpa_auth->conf.
+                                              wpa_ptk_rekey, 0, wpa_rekey_ptk,
+                                              sm->wpa_auth, sm);
+               }
+
+               if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
                        wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
                                           WPA_EAPOL_authorized, 1);
                }
@@ -1591,13 +1733,11 @@ SM_STEP(WPA_PTK)
                SM_ENTER(WPA_PTK, AUTHENTICATION2);
                break;
        case WPA_PTK_AUTHENTICATION2:
-               if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-                    sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) &&
+               if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
                    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
                                       WPA_EAPOL_keyRun) > 0)
                        SM_ENTER(WPA_PTK, INITPMK);
-               else if ((sm->wpa_key_mgmt == WPA_KEY_MGMT_PSK ||
-                         sm->wpa_key_mgmt == WPA_KEY_MGMT_FT_PSK)
+               else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
                         /* FIX: && 802.1X::keyRun */)
                        SM_ENTER(WPA_PTK, INITPSK);
                break;
@@ -1680,6 +1820,14 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        size_t kde_len;
 
        SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
+
+       sm->GTimeoutCtr++;
+       if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+               /* No point in sending the EAPOL-Key - we will disconnect
+                * immediately following this. */
+               return;
+       }
+
        if (sm->wpa == WPA_VERSION_WPA)
                sm->PInitAKeys = FALSE;
        sm->TimeoutEvt = FALSE;
@@ -1715,7 +1863,6 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
                       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
        if (sm->wpa == WPA_VERSION_WPA2)
                os_free(kde);
-       sm->GTimeoutCtr++;
 }
 
 
@@ -1747,9 +1894,10 @@ SM_STATE(WPA_PTK_GROUP, KEYERROR)
 
 SM_STEP(WPA_PTK_GROUP)
 {
-       if (sm->Init)
+       if (sm->Init || sm->PtkGroupInit) {
                SM_ENTER(WPA_PTK_GROUP, IDLE);
-       else switch (sm->wpa_ptk_group_state) {
+               sm->PtkGroupInit = FALSE;
+       } else switch (sm->wpa_ptk_group_state) {
        case WPA_PTK_GROUP_IDLE:
                if (sm->GUpdateStationKeys ||
                    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
@@ -1831,8 +1979,18 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
                                "Not in PTKINITDONE; skip Group Key update");
                return 0;
        }
-       sm->group->GKeyDoneStations++;
-       sm->GUpdateStationKeys = TRUE;
+       if (sm->GUpdateStationKeys) {
+               /*
+                * This should not really happen, but just in case, make sure
+                * we do not count the same STA twice in GKeyDoneStations.
+                */
+               wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+                               "GUpdateStationKeys already set - do not "
+                               "increment GKeyDoneStations");
+       } else {
+               sm->group->GKeyDoneStations++;
+               sm->GUpdateStationKeys = TRUE;
+       }
        wpa_sm_step(sm);
        return 0;
 }
@@ -1875,13 +2033,13 @@ static void wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
        group->changed = TRUE;
        group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
        wpa_auth_set_key(wpa_auth, group->vlan_id,
-                        wpa_alg_txt(wpa_auth->conf.wpa_group),
+                        wpa_alg_enum(wpa_auth->conf.wpa_group),
                         NULL, group->GN, group->GTK[group->GN - 1],
                         group->GTK_len);
 
 #ifdef CONFIG_IEEE80211W
        if (wpa_auth->conf.ieee80211w != WPA_NO_IEEE80211W) {
-               wpa_auth_set_key(wpa_auth, group->vlan_id, "IGTK",
+               wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
                                 NULL, group->GN_igtk,
                                 group->IGTK[group->GN_igtk - 4],
                                 WPA_IGTK_LEN);
@@ -2186,6 +2344,12 @@ int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
 }
 
 
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
+{
+       return sm->pairwise;
+}
+
+
 int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
 {
        if (sm == NULL)
@@ -2241,9 +2405,9 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
        if (sm == NULL || sm->wpa != WPA_VERSION_WPA2)
                return -1;
 
-       if (pmksa_cache_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
-                           sm->wpa_auth->addr, sm->addr, session_timeout,
-                           eapol))
+       if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+                                sm->wpa_auth->addr, sm->addr, session_timeout,
+                                eapol, sm->wpa_key_mgmt))
                return 0;
 
        return -1;
@@ -2258,8 +2422,9 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
        if (wpa_auth == NULL)
                return -1;
 
-       if (pmksa_cache_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
-                           sta_addr, session_timeout, eapol))
+       if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+                                sta_addr, session_timeout, eapol,
+                                WPA_KEY_MGMT_IEEE8021X))
                return 0;
 
        return -1;