Remove src/crypto from default include path
[libeap.git] / hostapd / wpa.c
index 946552c..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 "sha256.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"
@@ -44,13 +43,13 @@ 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;
@@ -104,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)
@@ -288,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;
@@ -316,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)
@@ -347,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,
@@ -375,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);
@@ -388,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;
        }
@@ -424,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);
@@ -452,6 +459,7 @@ 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;
 
@@ -461,6 +469,17 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
                return -1;
        }
 
+       /*
+        * 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;
 }
 
@@ -498,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;
@@ -574,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)
@@ -605,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 */
 
@@ -672,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;
@@ -842,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
@@ -914,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);
 
@@ -986,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);
@@ -1066,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;
@@ -1073,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);
 }
@@ -1109,7 +1178,8 @@ 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);
 }
@@ -1177,18 +1247,18 @@ void wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 }
 
 
-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;
        }
 }
 
@@ -1327,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");
        /*
@@ -1356,21 +1434,21 @@ SM_STATE(WPA_PTK, PTKSTART)
        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 (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
-               return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+               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;
@@ -1496,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);
@@ -1553,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++;
 }
 
 
@@ -1562,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,
@@ -1735,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;
@@ -1770,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++;
 }
 
 
@@ -1941,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);
@@ -2252,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)
@@ -2307,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, sm->wpa_key_mgmt))
+       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;
@@ -2324,9 +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,
-                           WPA_KEY_MGMT_IEEE8021X))
+       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;