Browse Source

Added support for using SHA256-based stronger key derivation for WPA2

IEEE 802.11w/D6.0 defines new AKMPs to indicate SHA256-based algorithms for
key derivation (and AES-CMAC for EAPOL-Key MIC). Add support for using new
AKMPs and clean up AKMP processing with helper functions in defs.h.
Jouni Malinen 16 years ago
parent
commit
565861976d

+ 2 - 0
hostapd/ChangeLog

@@ -13,6 +13,8 @@ ChangeLog for hostapd
 	* updated management frame protection to use IEEE 802.11w/D6.0
 	* updated management frame protection to use IEEE 802.11w/D6.0
 	  (adds a new association ping to protect against unauthenticated
 	  (adds a new association ping to protect against unauthenticated
 	  authenticate or (re)associate request frames dropping association)
 	  authenticate or (re)associate request frames dropping association)
+	* added support for using SHA256-based stronger key derivation for WPA2
+	  (IEEE 802.11w)
 
 
 2008-08-10 - v0.6.4
 2008-08-10 - v0.6.4
 	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
 	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2

+ 6 - 0
hostapd/config.c

@@ -817,6 +817,12 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
 		else if (os_strcmp(start, "FT-EAP") == 0)
 		else if (os_strcmp(start, "FT-EAP") == 0)
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
 		else {
 		else {
 			printf("Line %d: invalid key_mgmt '%s'\n",
 			printf("Line %d: invalid key_mgmt '%s'\n",
 			       line, start);
 			       line, start);

+ 2 - 1
hostapd/hostapd.conf

@@ -653,7 +653,8 @@ own_ip_addr=127.0.0.1
 #wpa_psk_file=/etc/hostapd.wpa_psk
 #wpa_psk_file=/etc/hostapd.wpa_psk
 
 
 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
-# entries are separated with a space.
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
 # (dot11RSNAConfigAuthenticationSuitesTable)
 # (dot11RSNAConfigAuthenticationSuitesTable)
 #wpa_key_mgmt=WPA-PSK WPA-EAP
 #wpa_key_mgmt=WPA-PSK WPA-EAP
 
 

+ 5 - 8
hostapd/ieee802_1x.c

@@ -719,8 +719,7 @@ void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
 	}
 	}
 
 
 	if (!hapd->conf->ieee802_1x ||
 	if (!hapd->conf->ieee802_1x ||
-	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK ||
-	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_FT_PSK)
+	    wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
 		return;
 		return;
 
 
 	if (!sta->eapol_sm) {
 	if (!sta->eapol_sm) {
@@ -802,8 +801,7 @@ void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
 	int force_1x = 0;
 	int force_1x = 0;
 
 
 	if ((!force_1x && !hapd->conf->ieee802_1x) ||
 	if ((!force_1x && !hapd->conf->ieee802_1x) ||
-	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_PSK ||
-	    wpa_auth_sta_key_mgmt(sta->wpa_sm) == WPA_KEY_MGMT_FT_PSK)
+	    wpa_key_mgmt_wpa_psk(wpa_auth_sta_key_mgmt(sta->wpa_sm)))
 		return;
 		return;
 
 
 	if (sta->eapol_sm == NULL) {
 	if (sta->eapol_sm == NULL) {
@@ -1938,10 +1936,9 @@ int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
 			  "dot1xAuthSessionTerminateCause=999\n"
 			  "dot1xAuthSessionTerminateCause=999\n"
 			  "dot1xAuthSessionUserName=%s\n",
 			  "dot1xAuthSessionUserName=%s\n",
 			  sta->acct_session_id_hi, sta->acct_session_id_lo,
 			  sta->acct_session_id_hi, sta->acct_session_id_lo,
-			  (wpa_auth_sta_key_mgmt(sta->wpa_sm) ==
-			   WPA_KEY_MGMT_IEEE8021X ||
-			   wpa_auth_sta_key_mgmt(sta->wpa_sm) ==
-			   WPA_KEY_MGMT_FT_IEEE8021X) ? 1 : 2,
+			  (wpa_key_mgmt_wpa_ieee8021x(
+				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
+			  1 : 2,
 			  (unsigned int) (time(NULL) -
 			  (unsigned int) (time(NULL) -
 					  sta->acct_session_start),
 					  sta->acct_session_start),
 			  sm->identity);
 			  sm->identity);

+ 7 - 1
hostapd/peerkey.c

@@ -1,6 +1,6 @@
 /*
 /*
  * hostapd - PeerKey for Direct Link Setup (DLS)
  * hostapd - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "common.h"
 #include "eloop.h"
 #include "eloop.h"
 #include "sha1.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "wpa.h"
 #include "wpa.h"
 #include "defs.h"
 #include "defs.h"
 #include "wpa_auth_i.h"
 #include "wpa_auth_i.h"
@@ -309,8 +310,13 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
 	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
 	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
 	pos += WPA_NONCE_LEN;
 	pos += WPA_NONCE_LEN;
 	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
 	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
+#ifdef CONFIG_IEEE80211W
+	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		   smk, PMK_LEN);
+#else /* CONFIG_IEEE80211W */
 	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
 	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
 		 smk, PMK_LEN);
 		 smk, PMK_LEN);
+#endif /* CONFIG_IEEE80211W */
 
 
 	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
 
 

+ 18 - 8
hostapd/pmksa_cache.c

@@ -1,6 +1,6 @@
 /*
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2006, 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -20,6 +20,7 @@
 #include "common.h"
 #include "common.h"
 #include "eloop.h"
 #include "eloop.h"
 #include "sha1.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "ieee802_1x.h"
 #include "ieee802_1x.h"
 #include "eapol_sm.h"
 #include "eapol_sm.h"
 #include "pmksa_cache.h"
 #include "pmksa_cache.h"
@@ -46,23 +47,29 @@ struct rsn_pmksa_cache {
  * @pmk_len: Length of pmk in bytes
  * @pmk_len: Length of pmk in bytes
  * @aa: Authenticator address
  * @aa: Authenticator address
  * @spa: Supplicant address
  * @spa: Supplicant address
+ * @use_sha256: Whether to use SHA256-based KDF
  *
  *
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
  * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
  */
  */
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
-	       u8 *pmkid)
+	       u8 *pmkid, int use_sha256)
 {
 {
 	char *title = "PMK Name";
 	char *title = "PMK Name";
 	const u8 *addr[3];
 	const u8 *addr[3];
 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
-	unsigned char hash[SHA1_MAC_LEN];
+	unsigned char hash[SHA256_MAC_LEN];
 
 
 	addr[0] = (u8 *) title;
 	addr[0] = (u8 *) title;
 	addr[1] = aa;
 	addr[1] = aa;
 	addr[2] = spa;
 	addr[2] = spa;
 
 
-	hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
 	os_memcpy(pmkid, hash, PMKID_LEN);
 	os_memcpy(pmkid, hash, PMKID_LEN);
 }
 }
 
 
@@ -248,6 +255,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
  * @spa: Supplicant address
  * @spa: Supplicant address
  * @session_timeout: Session timeout
  * @session_timeout: Session timeout
  * @eapol: Pointer to EAPOL state machine data
  * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  *
  *
  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
@@ -258,7 +266,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
 struct rsn_pmksa_cache_entry *
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *aa, const u8 *spa, int session_timeout,
 		const u8 *aa, const u8 *spa, int session_timeout,
-		struct eapol_state_machine *eapol)
+		struct eapol_state_machine *eapol, int akmp)
 {
 {
 	struct rsn_pmksa_cache_entry *entry, *pos;
 	struct rsn_pmksa_cache_entry *entry, *pos;
 	struct os_time now;
 	struct os_time now;
@@ -271,14 +279,15 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		return NULL;
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
 	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
 	os_get_time(&now);
 	os_get_time(&now);
 	entry->expiration = now.sec;
 	entry->expiration = now.sec;
 	if (session_timeout > 0)
 	if (session_timeout > 0)
 		entry->expiration += session_timeout;
 		entry->expiration += session_timeout;
 	else
 	else
 		entry->expiration += dot11RSNAConfigPMKLifetime;
 		entry->expiration += dot11RSNAConfigPMKLifetime;
-	entry->akmp = WPA_KEY_MGMT_IEEE8021X;
+	entry->akmp = akmp;
 	os_memcpy(entry->spa, spa, ETH_ALEN);
 	os_memcpy(entry->spa, spa, ETH_ALEN);
 	pmksa_cache_from_eapol_data(entry, eapol);
 	pmksa_cache_from_eapol_data(entry, eapol);
 
 
@@ -412,7 +421,8 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
 	while (entry) {
 	while (entry) {
 		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
 		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
 			continue;
 			continue;
-		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid);
+		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
+			  wpa_key_mgmt_sha256(entry->akmp));
 		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
 		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
 			return entry;
 			return entry;
 		entry = entry->next;
 		entry = entry->next;

+ 3 - 3
hostapd/pmksa_cache.h

@@ -1,6 +1,6 @@
 /*
 /*
  * hostapd - PMKSA cache for IEEE 802.11i RSN
  * hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2006, 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -49,7 +49,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
 struct rsn_pmksa_cache_entry *
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *aa, const u8 *spa, int session_timeout,
 		const u8 *aa, const u8 *spa, int session_timeout,
-		struct eapol_state_machine *eapol);
+		struct eapol_state_machine *eapol, int akmp);
 struct rsn_pmksa_cache_entry *
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
 pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
 		    const struct rsn_pmksa_cache_entry *old_entry,
 		    const struct rsn_pmksa_cache_entry *old_entry,
@@ -57,6 +57,6 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
 			       struct eapol_state_machine *eapol);
 			       struct eapol_state_machine *eapol);
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
-	       u8 *pmkid);
+	       u8 *pmkid, int use_sha256);
 
 
 #endif /* PMKSA_CACHE_H */
 #endif /* PMKSA_CACHE_H */

+ 30 - 25
hostapd/wpa.c

@@ -21,6 +21,7 @@
 #include "eapol_sm.h"
 #include "eapol_sm.h"
 #include "wpa.h"
 #include "wpa.h"
 #include "sha1.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "rc4.h"
 #include "rc4.h"
 #include "aes_wrap.h"
 #include "aes_wrap.h"
 #include "crypto.h"
 #include "crypto.h"
@@ -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)
 static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
 {
 {
+	int ret = 0;
 #ifdef CONFIG_IEEE80211R
 #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 */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
+		ret = 1;
+#endif /* CONFIG_IEEE80211W */
+	return ret;
 }
 }
 
 
 
 
@@ -847,8 +852,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, addr, ETH_ALEN);
 	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
 	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",
 	sha1_prf(gmk, WPA_GMK_LEN, "Group key expansion",
 		 data, sizeof(data), gtk, gtk_len);
 		 data, sizeof(data), gtk, gtk_len);
+#endif /* CONFIG_IEEE80211W */
 
 
 	wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "GMK", gmk, WPA_GMK_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
 	wpa_hexdump_key(MSG_DEBUG, "GTK", gtk, gtk_len);
@@ -1171,8 +1181,7 @@ SM_STATE(WPA_PTK, INITIALIZE)
 	wpa_remove_ptk(sm);
 	wpa_remove_ptk(sm);
 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
 	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
 	sm->TimeoutCtr = 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_auth_set_eapol(sm->wpa_auth, sm->addr,
 				   WPA_EAPOL_authorized, 0);
 				   WPA_EAPOL_authorized, 0);
 	}
 	}
@@ -1290,7 +1299,7 @@ SM_STATE(WPA_PTK, PTKSTART)
 	 * one possible PSK for this STA.
 	 * one possible PSK for this STA.
 	 */
 	 */
 	if (sm->wpa == WPA_VERSION_WPA2 &&
 	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 = buf;
 		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
 		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
 		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
 		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
@@ -1305,7 +1314,8 @@ SM_STATE(WPA_PTK, PTKSTART)
 			 * available with pre-calculated PMKID.
 			 * available with pre-calculated PMKID.
 			 */
 			 */
 			rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
 			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_send_eapol(sm->wpa_auth, sm,
@@ -1319,14 +1329,14 @@ static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
 			  struct wpa_ptk *ptk)
 			  struct wpa_ptk *ptk)
 {
 {
 #ifdef CONFIG_IEEE80211R
 #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))
 		return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 		return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
 
 
 	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
 	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
 		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
 		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
-		       (u8 *) ptk, sizeof(*ptk));
+		       (u8 *) ptk, sizeof(*ptk),
+		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1345,8 +1355,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 	 * WPA-PSK: iterate through possible PSKs and select the one matching
 	 * WPA-PSK: iterate through possible PSKs and select the one matching
 	 * the packet */
 	 * the packet */
 	for (;;) {
 	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);
 			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
 			if (pmk == NULL)
 			if (pmk == NULL)
 				break;
 				break;
@@ -1361,8 +1370,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 			break;
 			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;
 			break;
 	}
 	}
 
 
@@ -1374,8 +1382,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
 
 
 	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
 	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
 		/* PSK may have changed from the previous choice, so update
 		 * state machine data based on whatever PSK was selected here.
 		 * state machine data based on whatever PSK was selected here.
 		 */
 		 */
@@ -1537,8 +1544,7 @@ SM_STATE(WPA_PTK, PTKINITDONE)
 		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
 		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
 		sm->pairwise_set = TRUE;
 		sm->pairwise_set = TRUE;
 
 
-		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_auth_set_eapol(sm->wpa_auth, sm->addr,
 					   WPA_EAPOL_authorized, 1);
 					   WPA_EAPOL_authorized, 1);
 		}
 		}
@@ -1600,13 +1606,11 @@ SM_STEP(WPA_PTK)
 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
 		SM_ENTER(WPA_PTK, AUTHENTICATION2);
 		break;
 		break;
 	case WPA_PTK_AUTHENTICATION2:
 	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_auth_get_eapol(sm->wpa_auth, sm->addr,
 				       WPA_EAPOL_keyRun) > 0)
 				       WPA_EAPOL_keyRun) > 0)
 			SM_ENTER(WPA_PTK, INITPMK);
 			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 */)
 			 /* FIX: && 802.1X::keyRun */)
 			SM_ENTER(WPA_PTK, INITPSK);
 			SM_ENTER(WPA_PTK, INITPSK);
 		break;
 		break;
@@ -2252,7 +2256,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
 
 
 	if (pmksa_cache_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
 	if (pmksa_cache_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
 			    sm->wpa_auth->addr, sm->addr, session_timeout,
 			    sm->wpa_auth->addr, sm->addr, session_timeout,
-			    eapol))
+			    eapol, sm->wpa_key_mgmt))
 		return 0;
 		return 0;
 
 
 	return -1;
 	return -1;
@@ -2268,7 +2272,8 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
 		return -1;
 		return -1;
 
 
 	if (pmksa_cache_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
 	if (pmksa_cache_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
-			    sta_addr, session_timeout, eapol))
+			    sta_addr, session_timeout, eapol,
+			    WPA_KEY_MGMT_IEEE8021X))
 		return 0;
 		return 0;
 
 
 	return -1;
 	return -1;

+ 26 - 3
hostapd/wpa_auth_ie.c

@@ -1,6 +1,6 @@
 /*
 /*
  * hostapd - WPA/RSN IE and KDE definitions
  * 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -189,6 +189,18 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
 		num_suites++;
 		num_suites++;
 	}
 	}
 #endif /* CONFIG_IEEE80211R */
 #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) {
 	if (num_suites == 0) {
 		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
 		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
@@ -470,6 +482,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
 			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
 			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
 #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)
 		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
 			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
 		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
@@ -564,6 +582,12 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
 	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
 #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)
 	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
 	else
 	else
@@ -610,8 +634,7 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_IEEE80211W */
 #endif /* CONFIG_IEEE80211W */
 
 
 #ifdef CONFIG_IEEE80211R
 #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) {
 		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
 			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
 			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
 				   "MDIE not included");
 				   "MDIE not included");

+ 32 - 2
src/common/defs.h

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - Common definitions
  * WPA Supplicant - Common 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -40,6 +40,35 @@ typedef enum { FALSE = 0, TRUE = 1 } Boolean;
 #define WPA_KEY_MGMT_WPA_NONE BIT(4)
 #define WPA_KEY_MGMT_WPA_NONE BIT(4)
 #define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
 #define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
 #define WPA_KEY_MGMT_FT_PSK BIT(6)
 #define WPA_KEY_MGMT_FT_PSK BIT(6)
+#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
+#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
+
+static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
+{
+	return akm == WPA_KEY_MGMT_IEEE8021X ||
+		akm == WPA_KEY_MGMT_FT_IEEE8021X ||
+		akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
+}
+
+static inline int wpa_key_mgmt_wpa_psk(int akm)
+{
+	return akm == WPA_KEY_MGMT_PSK ||
+		akm == WPA_KEY_MGMT_FT_PSK ||
+		akm == WPA_KEY_MGMT_PSK_SHA256;
+}
+
+static inline int wpa_key_mgmt_ft(int akm)
+{
+	return akm == WPA_KEY_MGMT_FT_PSK ||
+		akm == WPA_KEY_MGMT_FT_IEEE8021X;
+}
+
+static inline int wpa_key_mgmt_sha256(int akm)
+{
+	return akm == WPA_KEY_MGMT_PSK_SHA256 ||
+		akm == WPA_KEY_MGMT_IEEE8021X_SHA256;
+}
+
 
 
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_RSN BIT(1)
 #define WPA_PROTO_RSN BIT(1)
@@ -55,7 +84,8 @@ typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
 	       CIPHER_WEP104 } wpa_cipher;
 	       CIPHER_WEP104 } wpa_cipher;
 typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
 typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
 	       KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE,
 	       KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE,
-	       KEY_MGMT_FT_802_1X, KEY_MGMT_FT_PSK
+	       KEY_MGMT_FT_802_1X, KEY_MGMT_FT_PSK,
+	       KEY_MGMT_802_1X_SHA256, KEY_MGMT_PSK_SHA256
 } wpa_key_mgmt;
 } wpa_key_mgmt;
 
 
 /**
 /**

+ 16 - 2
src/common/wpa_common.c

@@ -79,6 +79,7 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
  * @nonce2: SNonce or ANonce
  * @nonce2: SNonce or ANonce
  * @ptk: Buffer for pairwise transient key
  * @ptk: Buffer for pairwise transient key
  * @ptk_len: Length of PTK
  * @ptk_len: Length of PTK
+ * @use_sha256: Whether to use SHA256-based KDF
  *
  *
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * PTK = PRF-X(PMK, "Pairwise key expansion",
  * PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -92,7 +93,7 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		    const u8 *addr1, const u8 *addr2,
 		    const u8 *addr1, const u8 *addr2,
 		    const u8 *nonce1, const u8 *nonce2,
 		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len)
+		    u8 *ptk, size_t ptk_len, int use_sha256)
 {
 {
 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
 	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
 
 
@@ -114,7 +115,14 @@ void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 			  WPA_NONCE_LEN);
 			  WPA_NONCE_LEN);
 	}
 	}
 
 
-	sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len);
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+			   ptk, ptk_len);
+	else
+#endif /* CONFIG_IEEE80211W */
+		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
+			 ptk_len);
 
 
 	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
 	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
 		   MAC2STR(addr1), MAC2STR(addr2));
 		   MAC2STR(addr1), MAC2STR(addr2));
@@ -214,6 +222,12 @@ static int rsn_key_mgmt_to_bitfield(const u8 *s)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
 		return WPA_KEY_MGMT_FT_PSK;
 		return WPA_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
+		return WPA_KEY_MGMT_IEEE8021X_SHA256;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
+		return WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
 	return 0;
 	return 0;
 }
 }
 #endif /* CONFIG_NO_WPA2 */
 #endif /* CONFIG_NO_WPA2 */

+ 2 - 2
src/common/wpa_common.h

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA definitions shared between hostapd and wpa_supplicant
  * WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -294,7 +294,7 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		    const u8 *addr1, const u8 *addr2,
 		    const u8 *addr1, const u8 *addr2,
 		    const u8 *nonce1, const u8 *nonce2,
 		    const u8 *nonce1, const u8 *nonce2,
-		    u8 *ptk, size_t ptk_len);
+		    u8 *ptk, size_t ptk_len, int use_sha256);
 
 
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
 int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
 int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,

+ 31 - 12
src/rsn_supp/peerkey.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
 
 
 #include "common.h"
 #include "common.h"
 #include "sha1.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "eloop.h"
 #include "eloop.h"
 #include "wpa.h"
 #include "wpa.h"
 #include "wpa_i.h"
 #include "wpa_i.h"
@@ -239,15 +240,19 @@ static int wpa_supplicant_process_smk_m2(
 	/* TODO: find existing entry and if found, use that instead of adding
 	/* TODO: find existing entry and if found, use that instead of adding
 	 * a new one; how to handle the case where both ends initiate at the
 	 * a new one; how to handle the case where both ends initiate at the
 	 * same time? */
 	 * same time? */
-	peerkey = os_malloc(sizeof(*peerkey));
+	peerkey = os_zalloc(sizeof(*peerkey));
 	if (peerkey == NULL)
 	if (peerkey == NULL)
 		return -1;
 		return -1;
-	os_memset(peerkey, 0, sizeof(*peerkey));
 	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
 	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
 	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
 	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
 	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
 	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
 	peerkey->rsnie_i_len = kde.rsn_ie_len;
 	peerkey->rsnie_i_len = kde.rsn_ie_len;
 	peerkey->cipher = cipher;
 	peerkey->cipher = cipher;
+#ifdef CONFIG_IEEE80211W
+	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			   WPA_KEY_MGMT_PSK_SHA256))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
 
 
 	if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
 	if (os_get_random(peerkey->pnonce, WPA_NONCE_LEN)) {
 		wpa_msg(sm->ctx->ctx, MSG_WARNING,
 		wpa_msg(sm->ctx->ctx, MSG_WARNING,
@@ -294,18 +299,20 @@ static int wpa_supplicant_process_smk_m2(
  * @mac_p: Peer MAC address
  * @mac_p: Peer MAC address
  * @inonce: Initiator Nonce
  * @inonce: Initiator Nonce
  * @mac_i: Initiator MAC address
  * @mac_i: Initiator MAC address
+ * @use_sha256: Whether to use SHA256-based KDF
  *
  *
  * 8.5.1.4 Station to station (STK) key hierarchy
  * 8.5.1.4 Station to station (STK) key hierarchy
  * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
  * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
  */
  */
 static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
 static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
-		      const u8 *inonce, const u8 *mac_i, u8 *smkid)
+		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
+		      int use_sha256)
 {
 {
 	char *title = "SMK Name";
 	char *title = "SMK Name";
 	const u8 *addr[5];
 	const u8 *addr[5];
 	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
 	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
 				ETH_ALEN };
 				ETH_ALEN };
-	unsigned char hash[SHA1_MAC_LEN];
+	unsigned char hash[SHA256_MAC_LEN];
 
 
 	addr[0] = (u8 *) title;
 	addr[0] = (u8 *) title;
 	addr[1] = pnonce;
 	addr[1] = pnonce;
@@ -313,7 +320,12 @@ static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
 	addr[3] = inonce;
 	addr[3] = inonce;
 	addr[4] = mac_i;
 	addr[4] = mac_i;
 
 
-	hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
 	os_memcpy(smkid, hash, PMKID_LEN);
 	os_memcpy(smkid, hash, PMKID_LEN);
 }
 }
 
 
@@ -578,11 +590,13 @@ static int wpa_supplicant_process_smk_m45(
 
 
 	if (peerkey->initiator) {
 	if (peerkey->initiator) {
 		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
 		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
-			  peerkey->inonce, sm->own_addr, peerkey->smkid);
+			  peerkey->inonce, sm->own_addr, peerkey->smkid,
+			  peerkey->use_sha256);
 		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
 		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
 	} else {
 	} else {
 		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
 		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
-			  peerkey->inonce, peerkey->addr, peerkey->smkid);
+			  peerkey->inonce, peerkey->addr, peerkey->smkid,
+			  peerkey->use_sha256);
 	}
 	}
 	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
 	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
 
 
@@ -695,7 +709,8 @@ static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
 	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 		       sm->own_addr, peerkey->addr,
 		       sm->own_addr, peerkey->addr,
 		       peerkey->pnonce, key->key_nonce,
 		       peerkey->pnonce, key->key_nonce,
-		       (u8 *) stk, sizeof(*stk));
+		       (u8 *) stk, sizeof(*stk),
+		       peerkey->use_sha256);
 	/* Supplicant: swap tx/rx Mic keys */
 	/* Supplicant: swap tx/rx Mic keys */
 	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
 	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
 	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
 	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
@@ -927,7 +942,8 @@ int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
 		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
 			       sm->own_addr, peerkey->addr,
 			       sm->own_addr, peerkey->addr,
 			       peerkey->inonce, key->key_nonce,
 			       peerkey->inonce, key->key_nonce,
-			       (u8 *) &peerkey->stk, sizeof(peerkey->stk));
+			       (u8 *) &peerkey->stk, sizeof(peerkey->stk),
+			       peerkey->use_sha256);
 		peerkey->stk_set = 1;
 		peerkey->stk_set = 1;
 	}
 	}
 
 
@@ -1016,12 +1032,15 @@ int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
 
 
 	/* TODO: find existing entry and if found, use that instead of adding
 	/* TODO: find existing entry and if found, use that instead of adding
 	 * a new one */
 	 * a new one */
-	peerkey = os_malloc(sizeof(*peerkey));
+	peerkey = os_zalloc(sizeof(*peerkey));
 	if (peerkey == NULL)
 	if (peerkey == NULL)
 		return -1;
 		return -1;
-	os_memset(peerkey, 0, sizeof(*peerkey));
 	peerkey->initiator = 1;
 	peerkey->initiator = 1;
 	os_memcpy(peerkey->addr, peer, ETH_ALEN);
 	os_memcpy(peerkey->addr, peer, ETH_ALEN);
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
 
 
 	/* SMK M1:
 	/* SMK M1:
 	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
 	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,

+ 2 - 1
src/rsn_supp/peerkey.h

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
  * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
- * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -34,6 +34,7 @@ struct wpa_peerkey {
 	int cipher; /* Selected cipher (WPA_CIPHER_*) */
 	int cipher; /* Selected cipher (WPA_CIPHER_*) */
 	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
 	int replay_counter_set;
 	int replay_counter_set;
+	int use_sha256; /* whether AKMP indicate SHA256-based derivations */
 
 
 	struct wpa_ptk stk, tstk;
 	struct wpa_ptk stk, tstk;
 	int stk_set, tstk_set;
 	int stk_set, tstk_set;

+ 18 - 9
src/rsn_supp/pmksa_cache.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - RSN PMKSA cache
  * WPA Supplicant - RSN PMKSA cache
- * Copyright (c) 2004-2006, 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -18,6 +18,7 @@
 #include "wpa.h"
 #include "wpa.h"
 #include "eloop.h"
 #include "eloop.h"
 #include "sha1.h"
 #include "sha1.h"
+#include "sha256.h"
 #include "wpa_i.h"
 #include "wpa_i.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "pmksa_cache.h"
 #include "pmksa_cache.h"
@@ -43,23 +44,29 @@ struct rsn_pmksa_cache {
  * @pmk_len: Length of pmk in bytes
  * @pmk_len: Length of pmk in bytes
  * @aa: Authenticator address
  * @aa: Authenticator address
  * @spa: Supplicant address
  * @spa: Supplicant address
+ * @use_sha256: Whether to use SHA256-based KDF
  *
  *
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
  * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
  * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
  */
  */
-void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
-	       u8 *pmkid)
+static void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa,
+		      const u8 *spa, u8 *pmkid, int use_sha256)
 {
 {
 	char *title = "PMK Name";
 	char *title = "PMK Name";
 	const u8 *addr[3];
 	const u8 *addr[3];
 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
 	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
-	unsigned char hash[SHA1_MAC_LEN];
+	unsigned char hash[SHA256_MAC_LEN];
 
 
 	addr[0] = (u8 *) title;
 	addr[0] = (u8 *) title;
 	addr[1] = aa;
 	addr[1] = aa;
 	addr[2] = spa;
 	addr[2] = spa;
 
 
-	hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
 	os_memcpy(pmkid, hash, PMKID_LEN);
 	os_memcpy(pmkid, hash, PMKID_LEN);
 }
 }
 
 
@@ -145,6 +152,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  * @aa: Authenticator address
  * @aa: Authenticator address
  * @spa: Supplicant address
  * @spa: Supplicant address
  * @network_ctx: Network configuration context for this PMK
  * @network_ctx: Network configuration context for this PMK
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  * Returns: Pointer to the added PMKSA cache entry or %NULL on error
  *
  *
  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
  * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
@@ -154,7 +162,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
  */
  */
 struct rsn_pmksa_cache_entry *
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, void *network_ctx)
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
 {
 	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
 	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
 	struct os_time now;
 	struct os_time now;
@@ -167,12 +175,13 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		return NULL;
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
 	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
 	os_get_time(&now);
 	os_get_time(&now);
 	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
 	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
 	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
 	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
 		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
 		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
-	entry->akmp = WPA_KEY_MGMT_IEEE8021X;
+	entry->akmp = akmp;
 	os_memcpy(entry->aa, aa, ETH_ALEN);
 	os_memcpy(entry->aa, aa, ETH_ALEN);
 	entry->network_ctx = network_ctx;
 	entry->network_ctx = network_ctx;
 
 
@@ -324,7 +333,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
 
 
 	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
 	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
 				    aa, pmksa->sm->own_addr,
 				    aa, pmksa->sm->own_addr,
-				    old_entry->network_ctx);
+				    old_entry->network_ctx, old_entry->akmp);
 	if (new_entry == NULL)
 	if (new_entry == NULL)
 		return NULL;
 		return NULL;
 
 

+ 3 - 3
src/rsn_supp/pmksa_cache.h

@@ -1,6 +1,6 @@
 /*
 /*
  * wpa_supplicant - WPA2/RSN PMKSA cache functions
  * wpa_supplicant - WPA2/RSN PMKSA cache functions
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -56,7 +56,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
 int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
 int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
 struct rsn_pmksa_cache_entry *
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, void *network_ctx);
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
 void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -100,7 +100,7 @@ static inline int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
 
 
 static inline struct rsn_pmksa_cache_entry *
 static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, void *network_ctx)
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
 {
 	return NULL;
 	return NULL;
 }
 }

+ 5 - 3
src/rsn_supp/preauth.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - RSN pre-authentication
  * WPA Supplicant - RSN pre-authentication
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -104,7 +104,8 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
 			sm->pmk_len = pmk_len;
 			sm->pmk_len = pmk_len;
 			pmksa_cache_add(sm->pmksa, pmk, pmk_len,
 			pmksa_cache_add(sm->pmksa, pmk, pmk_len,
 					sm->preauth_bssid, sm->own_addr,
 					sm->preauth_bssid, sm->own_addr,
-					sm->network_ctx);
+					sm->network_ctx,
+					WPA_KEY_MGMT_IEEE8021X);
 		} else {
 		} else {
 			wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: failed to get "
 			wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: failed to get "
 				"master session key from pre-auth EAPOL state "
 				"master session key from pre-auth EAPOL state "
@@ -304,7 +305,8 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
 	if (sm->preauth_eapol ||
 	if (sm->preauth_eapol ||
 	    sm->proto != WPA_PROTO_RSN ||
 	    sm->proto != WPA_PROTO_RSN ||
 	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
 	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
-	    sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X) {
+	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
 		wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state "
 		wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state "
 			"for new pre-authentication");
 			"for new pre-authentication");
 		return; /* invalid state for new pre-auth */
 		return; /* invalid state for new pre-auth */

+ 35 - 22
src/rsn_supp/wpa.c

@@ -77,6 +77,12 @@ static const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
 	case WPA_KEY_MGMT_FT_PSK:
 	case WPA_KEY_MGMT_FT_PSK:
 		return "FT-PSK";
 		return "FT-PSK";
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return "WPA2-EAP-SHA256";
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return "WPA2-PSK-SHA256";
+#endif /* CONFIG_IEEE80211W */
 	default:
 	default:
 		return "UNKNOWN";
 		return "UNKNOWN";
 	}
 	}
@@ -140,8 +146,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 	int key_info, ver;
 	int key_info, ver;
 	u8 bssid[ETH_ALEN], *rbuf;
 	u8 bssid[ETH_ALEN], *rbuf;
 
 
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
 		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
 		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
 	else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
 	else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
 		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
 		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
@@ -216,8 +221,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
 		sm->xxkey_len = 0;
 		sm->xxkey_len = 0;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
-	} else if ((sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-		    sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) && sm->eapol) {
+	} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
 		int res, pmk_len;
 		int res, pmk_len;
 		pmk_len = PMK_LEN;
 		pmk_len = PMK_LEN;
 		res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
 		res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
@@ -244,7 +248,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 					"machines", sm->pmk, pmk_len);
 					"machines", sm->pmk, pmk_len);
 			sm->pmk_len = pmk_len;
 			sm->pmk_len = pmk_len;
 			pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, src_addr,
 			pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, src_addr,
-					sm->own_addr, sm->network_ctx);
+					sm->own_addr, sm->network_ctx,
+					sm->key_mgmt);
 			if (!sm->cur_pmksa && pmkid &&
 			if (!sm->cur_pmksa && pmkid &&
 			    pmksa_cache_get(sm->pmksa, src_addr, pmkid)) {
 			    pmksa_cache_get(sm->pmksa, src_addr, pmkid)) {
 				wpa_printf(MSG_DEBUG, "RSN: the new PMK "
 				wpa_printf(MSG_DEBUG, "RSN: the new PMK "
@@ -268,8 +273,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 		}
 		}
 	}
 	}
 
 
-	if (abort_cached && (sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-			     sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)) {
+	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) {
 		/* Send EAPOL-Start to trigger full EAP authentication. */
 		/* Send EAPOL-Start to trigger full EAP authentication. */
 		u8 *buf;
 		u8 *buf;
 		size_t buflen;
 		size_t buflen;
@@ -356,14 +360,14 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
 			  struct wpa_ptk *ptk)
 			  struct wpa_ptk *ptk)
 {
 {
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+	if (wpa_key_mgmt_ft(sm->key_mgmt))
 		return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
 		return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
 
 
 	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
 	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
 		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
 		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
-		       (u8 *) ptk, sizeof(*ptk));
+		       (u8 *) ptk, sizeof(*ptk),
+		       wpa_key_mgmt_sha256(sm->key_mgmt));
 	return 0;
 	return 0;
 }
 }
 
 
@@ -458,8 +462,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
 			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
 			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
 			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
 			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
 		eapol_sm_notify_portValid(sm->eapol, TRUE);
 		eapol_sm_notify_portValid(sm->eapol, TRUE);
-		if (sm->key_mgmt == WPA_KEY_MGMT_PSK ||
-		    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+		if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
 			eapol_sm_notify_eap_success(sm->eapol, TRUE);
 			eapol_sm_notify_eap_success(sm->eapol, TRUE);
 		/*
 		/*
 		 * Start preauthentication after a short wait to avoid a
 		 * Start preauthentication after a short wait to avoid a
@@ -478,8 +481,7 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
 	}
 	}
 
 
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		/* Prepare for the next transition */
 		/* Prepare for the next transition */
 		wpa_ft_prepare_auth_request(sm);
 		wpa_ft_prepare_auth_request(sm);
 	}
 	}
@@ -834,8 +836,7 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
 	}
 	}
 
 
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		struct rsn_mdie *mdie;
 		struct rsn_mdie *mdie;
 		/* TODO: verify that full MDIE matches with the one from scan
 		/* TODO: verify that full MDIE matches with the one from scan
 		 * results, not only mobility domain */
 		 * results, not only mobility domain */
@@ -1463,8 +1464,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 	}
 	}
 
 
 #ifdef CONFIG_IEEE80211R
 #ifdef CONFIG_IEEE80211R
-	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X ||
-	    sm->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
 		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
 		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 			wpa_printf(MSG_INFO, "FT: AP did not use "
 			wpa_printf(MSG_INFO, "FT: AP did not use "
@@ -1473,6 +1473,15 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
 		}
 		}
 	} else
 	} else
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			wpa_printf(MSG_INFO, "WPA: AP did not use the "
+				   "negotiated AES-128-CMAC.");
+			goto out;
+		}
+	} else
+#endif /* CONFIG_IEEE80211W */
 	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
 	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
 		wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
@@ -1651,6 +1660,12 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
 	case WPA_KEY_MGMT_FT_PSK:
 	case WPA_KEY_MGMT_FT_PSK:
 		return RSN_AUTH_KEY_MGMT_FT_PSK;
 		return RSN_AUTH_KEY_MGMT_FT_PSK;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
 	case WPA_KEY_MGMT_WPA_NONE:
 	case WPA_KEY_MGMT_WPA_NONE:
 		return WPA_AUTH_KEY_MGMT_NONE;
 		return WPA_AUTH_KEY_MGMT_NONE;
 	default:
 	default:
@@ -1708,10 +1723,8 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
 	} else
 	} else
 		pmkid_txt[0] = '\0';
 		pmkid_txt[0] = '\0';
 
 
-	if ((sm->key_mgmt == WPA_KEY_MGMT_PSK ||
-	     sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-	     sm->key_mgmt == WPA_KEY_MGMT_FT_PSK ||
-	     sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) &&
+	if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+	     wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
 	    sm->proto == WPA_PROTO_RSN)
 	    sm->proto == WPA_PROTO_RSN)
 		rsna = 1;
 		rsna = 1;
 	else
 	else

+ 7 - 1
src/rsn_supp/wpa_ie.c

@@ -1,6 +1,6 @@
 /*
 /*
  * wpa_supplicant - WPA/RSN IE and KDE processing
  * wpa_supplicant - WPA/RSN IE and KDE processing
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -316,6 +316,12 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+#endif /* CONFIG_IEEE80211W */
 	} else {
 	} else {
 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
 			   key_mgmt);
 			   key_mgmt);

+ 2 - 0
wpa_supplicant/ChangeLog

@@ -4,6 +4,8 @@ ChangeLog for wpa_supplicant
 	* added support for SHA-256 as X.509 certificate digest when using the
 	* added support for SHA-256 as X.509 certificate digest when using the
 	  internal X.509/TLSv1 implementation
 	  internal X.509/TLSv1 implementation
 	* updated management frame protection to use IEEE 802.11w/D6.0
 	* updated management frame protection to use IEEE 802.11w/D6.0
+	* added support for using SHA256-based stronger key derivation for WPA2
+	  (IEEE 802.11w)
 
 
 2008-08-10 - v0.6.4
 2008-08-10 - v0.6.4
 	* added support for EAP Sequences in EAP-FAST Phase 2
 	* added support for EAP Sequences in EAP-FAST Phase 2

+ 17 - 1
wpa_supplicant/config.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant / Configuration parser and common functions
  * WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -500,6 +500,12 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
 		else if (os_strcmp(start, "FT-EAP") == 0)
 		else if (os_strcmp(start, "FT-EAP") == 0)
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
 			val |= WPA_KEY_MGMT_FT_IEEE8021X;
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
 		else {
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
 				   line, start);
@@ -596,6 +602,16 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
 				   pos == buf ? "" : " ");
 				   pos == buf ? "" : " ");
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
 
 
+#ifdef CONFIG_IEEE80211W
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+				   pos == buf ? "" : " ");
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_IEEE80211W */
+
 	return buf;
 	return buf;
 }
 }
 #endif /* NO_CONFIG_WRITE */
 #endif /* NO_CONFIG_WRITE */

+ 3 - 2
wpa_supplicant/config_file.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant / Configuration backend: text file
  * WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -104,7 +104,8 @@ static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
 		wpa_config_update_psk(ssid);
 		wpa_config_update_psk(ssid);
 	}
 	}
 
 
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)) &&
+	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+			       WPA_KEY_MGMT_PSK_SHA256)) &&
 	    !ssid->psk_set) {
 	    !ssid->psk_set) {
 		wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
 		wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
 			   "management, but no PSK configured.", line);
 			   "management, but no PSK configured.", line);

+ 3 - 2
wpa_supplicant/config_winreg.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant / Configuration backend: Windows registry
  * WPA Supplicant / Configuration backend: Windows registry
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -264,7 +264,8 @@ static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
 		wpa_config_update_psk(ssid);
 		wpa_config_update_psk(ssid);
 	}
 	}
 
 
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK)) &&
+	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+			       WPA_KEY_MGMT_PSK_SHA256)) &&
 	    !ssid->psk_set) {
 	    !ssid->psk_set) {
 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
 			   "but no PSK configured for network '" TSTR "'.",
 			   "but no PSK configured for network '" TSTR "'.",

+ 21 - 4
wpa_supplicant/ctrl_iface.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant / Control interface (shared code for all backends)
  * WPA Supplicant / Control interface (shared code for all backends)
- * 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
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -285,9 +285,8 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
 		pos += ret;
 		pos += ret;
 	}
 	}
 
 
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
 		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
 		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
 					  verbose);
 					  verbose);
 		if (res >= 0)
 		if (res >= 0)
@@ -493,6 +492,24 @@ static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
 		first = 0;
 		first = 0;
 	}
 	}
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#endif /* CONFIG_IEEE80211W */
 
 
 	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
 	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
 
 

+ 11 - 11
wpa_supplicant/events.c

@@ -58,8 +58,9 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
 		   "AP");
 		   "AP");
 	if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
 	if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
 			      WPA_KEY_MGMT_WPA_NONE |
 			      WPA_KEY_MGMT_WPA_NONE |
-			      WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X))
-	{
+			      WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
+			      WPA_KEY_MGMT_PSK_SHA256 |
+			      WPA_KEY_MGMT_IEEE8021X_SHA256)) {
 		u8 wpa_ie[80];
 		u8 wpa_ie[80];
 		size_t wpa_ie_len = sizeof(wpa_ie);
 		size_t wpa_ie_len = sizeof(wpa_ie);
 		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
 		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -99,8 +100,7 @@ void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
 	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
 	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
 	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
 	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK)
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 	wpa_s->ap_ies_from_associnfo = 0;
 	wpa_s->ap_ies_from_associnfo = 0;
 }
 }
@@ -500,7 +500,10 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
 			}
 			}
 
 
 			if ((ssid->key_mgmt & 
 			if ((ssid->key_mgmt & 
-			     (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK)) &&
+			     (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
+			      WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK |
+			      WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			      WPA_KEY_MGMT_PSK_SHA256)) &&
 			    (wpa_ie_len != 0 || rsn_ie_len != 0)) {
 			    (wpa_ie_len != 0 || rsn_ie_len != 0)) {
 				wpa_printf(MSG_DEBUG, "   skip - "
 				wpa_printf(MSG_DEBUG, "   skip - "
 					   "WPA network");
 					   "WPA network");
@@ -750,8 +753,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 		eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
 		eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
 		eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
 		eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
 	}
 	}
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK || ft_completed)
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 	/* 802.1X::portControl = Auto */
 	/* 802.1X::portControl = Auto */
 	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
 	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
@@ -767,8 +769,7 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 
 
 	if (wpa_s->driver_4way_handshake &&
 	if (wpa_s->driver_4way_handshake &&
-	    (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	     wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK)) {
+	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
 		/*
 		/*
 		 * We are done; the driver will take care of RSN 4-way
 		 * We are done; the driver will take care of RSN 4-way
 		 * handshake.
 		 * handshake.
@@ -797,8 +798,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
 	}
 	}
 
 
 	if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
 	if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
-	    (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	     wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK)) {
+	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
 		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
 		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
 			"pre-shared key may be incorrect");
 			"pre-shared key may be incorrect");
 	}
 	}

+ 30 - 18
wpa_supplicant/wpa_supplicant.c

@@ -251,8 +251,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 	struct eapol_config eapol_conf;
 	struct eapol_config eapol_conf;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
 
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
 		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
 	}
 	}
@@ -282,8 +281,8 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
 	if (wpa_s->conf)
 	if (wpa_s->conf)
 		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
 	eapol_conf.workaround = ssid->eap_workaround;
 	eapol_conf.workaround = ssid->eap_workaround;
-	eapol_conf.eap_disabled = wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-		wpa_s->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	eapol_conf.eap_disabled =
+		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
 #endif /* IEEE8021X_EAPOL */
 #endif /* IEEE8021X_EAPOL */
@@ -562,8 +561,7 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
 	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
 	 * pkcs11_engine_path, pkcs11_module_path.
 	 * pkcs11_engine_path, pkcs11_module_path.
 	 */
 	 */
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
 		/*
 		/*
 		 * Clear forced success to clear EAP state for next
 		 * Clear forced success to clear EAP state for next
 		 * authentication.
 		 * authentication.
@@ -634,6 +632,10 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
 		return KEY_MGMT_FT_802_1X;
 		return KEY_MGMT_FT_802_1X;
 	case WPA_KEY_MGMT_FT_PSK:
 	case WPA_KEY_MGMT_FT_PSK:
 		return KEY_MGMT_FT_PSK;
 		return KEY_MGMT_FT_PSK;
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return KEY_MGMT_PSK_SHA256;
 	case WPA_KEY_MGMT_PSK:
 	case WPA_KEY_MGMT_PSK:
 	default:
 	default:
 		return KEY_MGMT_PSK;
 		return KEY_MGMT_PSK;
@@ -822,6 +824,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
 		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
 #endif /* CONFIG_IEEE80211R */
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT 802.1X with SHA256");
+	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT PSK with SHA256");
+#endif /* CONFIG_IEEE80211W */
 	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
 	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
 		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
 		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
 		wpa_msg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
@@ -864,7 +876,8 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 		return -1;
 		return -1;
 	}
 	}
 
 
-	if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK))
+	if (ssid->key_mgmt &
+	    (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
 		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
 		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
 	else
 	else
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
@@ -950,7 +963,9 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 		    wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
 		    wpa_scan_get_ie(bss, WLAN_EID_RSN)) &&
 	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
 	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
 			       WPA_KEY_MGMT_FT_IEEE8021X |
 			       WPA_KEY_MGMT_FT_IEEE8021X |
-			       WPA_KEY_MGMT_FT_PSK))) {
+			       WPA_KEY_MGMT_FT_PSK |
+			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			       WPA_KEY_MGMT_PSK_SHA256))) {
 		int try_opportunistic;
 		int try_opportunistic;
 		try_opportunistic = ssid->proactive_key_caching &&
 		try_opportunistic = ssid->proactive_key_caching &&
 			(ssid->proto & WPA_PROTO_RSN);
 			(ssid->proto & WPA_PROTO_RSN);
@@ -968,7 +983,8 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
 	} else if (ssid->key_mgmt &
 	} else if (ssid->key_mgmt &
 		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
 		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
 		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
 		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-		    WPA_KEY_MGMT_FT_IEEE8021X)) {
+		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
+		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
 		wpa_ie_len = sizeof(wpa_ie);
 		wpa_ie_len = sizeof(wpa_ie);
 		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
 		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
 					      wpa_ie, &wpa_ie_len)) {
 					      wpa_ie, &wpa_ie_len)) {
@@ -1428,15 +1444,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 
 
 	if (wpa_s->eapol_received == 0 &&
 	if (wpa_s->eapol_received == 0 &&
 	    (!wpa_s->driver_4way_handshake ||
 	    (!wpa_s->driver_4way_handshake ||
-	     (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
-	      wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK) ||
+	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
 	     wpa_s->wpa_state != WPA_COMPLETED)) {
 	     wpa_s->wpa_state != WPA_COMPLETED)) {
 		/* Timeout for completing IEEE 802.1X and WPA authentication */
 		/* Timeout for completing IEEE 802.1X and WPA authentication */
 		wpa_supplicant_req_auth_timeout(
 		wpa_supplicant_req_auth_timeout(
 			wpa_s,
 			wpa_s,
-			(wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
-			 wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) ?
+			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
 			70 : 10, 0);
 			70 : 10, 0);
 	}
 	}
 	wpa_s->eapol_received++;
 	wpa_s->eapol_received++;
@@ -1454,15 +1468,13 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
 	 * still sent to the current BSSID (if available), though. */
 	 * still sent to the current BSSID (if available), though. */
 
 
 	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
 	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
-	if (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
-	    wpa_s->key_mgmt != WPA_KEY_MGMT_FT_PSK &&
+	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
 	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
 	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
 		return;
 		return;
 	wpa_drv_poll(wpa_s);
 	wpa_drv_poll(wpa_s);
 	if (!wpa_s->driver_4way_handshake)
 	if (!wpa_s->driver_4way_handshake)
 		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
 		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
-	else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-		 wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
 		/*
 		/*
 		 * Set portValid = TRUE here since we are going to skip 4-way
 		 * Set portValid = TRUE here since we are going to skip 4-way
 		 * handshake processing which would normally set portValid. We
 		 * handshake processing which would normally set portValid. We

+ 2 - 0
wpa_supplicant/wpa_supplicant.conf

@@ -211,6 +211,8 @@ fast_reauth=1
 # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
 # IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
 #	generated WEP keys
 #	generated WEP keys
 # NONE = WPA is not used; plaintext or static WEP could be used
 # NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
+# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
 # If not set, this defaults to: WPA-PSK WPA-EAP
 # If not set, this defaults to: WPA-PSK WPA-EAP
 #
 #
 # auth_alg: list of allowed IEEE 802.11 authentication algorithms
 # auth_alg: list of allowed IEEE 802.11 authentication algorithms

+ 4 - 7
wpa_supplicant/wpas_glue.c

@@ -1,6 +1,6 @@
 /*
 /*
  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
  * WPA Supplicant - Glue code to setup EAPOL and RSN modules
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License version 2 as
@@ -122,8 +122,7 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
 	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
 	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
 	 * extra copy here */
 	 * extra copy here */
 
 
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_PSK ||
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
 		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
 		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
 		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
 		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
@@ -225,8 +224,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
 	if (!success || !wpa_s->driver_4way_handshake)
 	if (!success || !wpa_s->driver_4way_handshake)
 		return;
 		return;
 
 
-	if (wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-	    wpa_s->key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X)
+	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
 		return;
 		return;
 
 
 	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
 	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
@@ -265,8 +263,7 @@ static void wpa_supplicant_notify_eapol_done(void *ctx)
 {
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_supplicant *wpa_s = ctx;
 	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
 	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
-	    wpa_s->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
 		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
 		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
 	} else {
 	} else {
 		wpa_supplicant_cancel_auth_timeout(wpa_s);
 		wpa_supplicant_cancel_auth_timeout(wpa_s);