/*
* 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"
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);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
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)
}
-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;
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)
* 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,
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);
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;
}
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);
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf)
{
+ struct wpa_group *group;
if (wpa_auth == NULL)
return 0;
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;
}
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 */
{
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);
}
}
-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;
}
}
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;
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,
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);
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;
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;