wpa_supplicant: Update to 29-Aug-2012 TOT

commit 6ffdc2f7bd496ace7a46e055f9714e7db4b1f722
Author: Jouni Malinen <jouni@qca.qualcomm.com>
Date:   Fri Mar 2 22:31:04 2012 +0200

    WFD: Add preliminary WSD request processing and response

    This commit does not yet address support for different device roles,
    i.e., the same set of subelements are returned regardless of which
    role was indicated in the request.

    Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>

Change-Id: I9d63acce719b982c02e589bb59602382e82988c8
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7159c3a..bcd5951 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -91,7 +91,7 @@
 
 	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
 		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
-	else if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+	else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
 		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
 	else
 		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -190,14 +190,17 @@
 #endif /* CONFIG_IEEE80211R */
 		}
 		if (res == 0) {
+			struct rsn_pmksa_cache_entry *sa = NULL;
 			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
 					"machines", sm->pmk, pmk_len);
 			sm->pmk_len = pmk_len;
 			if (sm->proto == WPA_PROTO_RSN &&
 			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
-				pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len,
-						src_addr, sm->own_addr,
-						sm->network_ctx, sm->key_mgmt);
+				sa = pmksa_cache_add(sm->pmksa,
+						     sm->pmk, pmk_len,
+						     src_addr, sm->own_addr,
+						     sm->network_ctx,
+						     sm->key_mgmt);
 			}
 			if (!sm->cur_pmksa && pmkid &&
 			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
@@ -207,6 +210,9 @@
 					"PMKID");
 				abort_cached = 0;
 			}
+
+			if (!sm->cur_pmksa)
+				sm->cur_pmksa = sa;
 		} else {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Failed to get master session key from "
@@ -350,7 +356,7 @@
 			  const struct wpa_eapol_key *key,
 			  struct wpa_ptk *ptk)
 {
-	size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
+	size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt))
 		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
@@ -520,6 +526,11 @@
 		keylen = 16;
 		rsclen = 6;
 		break;
+	case WPA_CIPHER_GCMP:
+		alg = WPA_ALG_GCMP;
+		keylen = 16;
+		rsclen = 6;
+		break;
 	case WPA_CIPHER_TKIP:
 		alg = WPA_ALG_TKIP;
 		keylen = 32;
@@ -579,6 +590,14 @@
 		*key_rsc_len = 6;
 		*alg = WPA_ALG_CCMP;
 		break;
+	case WPA_CIPHER_GCMP:
+		if (keylen != 16 || maxkeylen < 16) {
+			ret = -1;
+			break;
+		}
+		*key_rsc_len = 6;
+		*alg = WPA_ALG_GCMP;
+		break;
 	case WPA_CIPHER_TKIP:
 		if (keylen != 32 || maxkeylen < 32) {
 			ret = -1;
@@ -1125,6 +1144,14 @@
 			goto failed;
 		}
 		break;
+	case WPA_CIPHER_GCMP:
+		if (keylen != 16) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid GCMP key length %d (src=" MACSTR
+				")", keylen, MAC2STR(sm->bssid));
+			goto failed;
+		}
+		break;
 	case WPA_CIPHER_TKIP:
 		if (keylen != 32) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1712,6 +1739,13 @@
 		} else
 			goto out;
 	}
+	if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: GCMP is used, but EAPOL-Key "
+			"descriptor version (%d) is not 2", ver);
+		goto out;
+	}
 
 #ifdef CONFIG_PEERKEY
 	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
@@ -1851,6 +1885,8 @@
 	switch (cipher) {
 	case WPA_CIPHER_CCMP:
 		return 128;
+	case WPA_CIPHER_GCMP:
+		return 128;
 	case WPA_CIPHER_TKIP:
 		return 256;
 	case WPA_CIPHER_WEP104:
@@ -1900,6 +1936,8 @@
 	case WPA_CIPHER_CCMP:
 		return (sm->proto == WPA_PROTO_RSN ?
 			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+	case WPA_CIPHER_GCMP:
+		return RSN_CIPHER_SUITE_GCMP;
 	case WPA_CIPHER_TKIP:
 		return (sm->proto == WPA_PROTO_RSN ?
 			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
@@ -2659,3 +2697,125 @@
 	pmksa_cache_flush(sm->pmksa, network_ctx);
 #endif /* CONFIG_NO_WPA2 */
 }
+
+
+#ifdef CONFIG_IEEE80211V
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
+{
+	struct wpa_gtk_data gd;
+#ifdef CONFIG_IEEE80211W
+	struct wpa_igtk_kde igd;
+	u16 keyidx;
+#endif /* CONFIG_IEEE80211W */
+	u16 keyinfo;
+	u8 keylen;  /* plaintext key len */
+	u8 keydatalen;
+	u8 *key_rsc;
+
+	os_memset(&gd, 0, sizeof(gd));
+#ifdef CONFIG_IEEE80211W
+	os_memset(&igd, 0, sizeof(igd));
+#endif /* CONFIG_IEEE80211W */
+
+	switch (sm->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		keylen = 16;
+		gd.key_rsc_len = 6;
+		gd.alg = WPA_ALG_CCMP;
+		break;
+	case WPA_CIPHER_GCMP:
+		keylen = 16;
+		gd.key_rsc_len = 6;
+		gd.alg = WPA_ALG_GCMP;
+		break;
+	case WPA_CIPHER_TKIP:
+		keylen = 32;
+		gd.key_rsc_len = 6;
+		gd.alg = WPA_ALG_TKIP;
+		break;
+	case WPA_CIPHER_WEP104:
+		keylen = 13;
+		gd.key_rsc_len = 0;
+		gd.alg = WPA_ALG_WEP;
+		break;
+	case WPA_CIPHER_WEP40:
+		keylen = 5;
+		gd.key_rsc_len = 0;
+		gd.alg = WPA_ALG_WEP;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+		return -1;
+	}
+
+	if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+		key_rsc = buf + 5;
+		keyinfo = WPA_GET_LE16(buf+2);
+		keydatalen = buf[1] - 11 - 8;
+		gd.gtk_len = keylen;
+		if (gd.gtk_len != buf[4]) {
+			wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
+				   gd.gtk_len, buf[4]);
+			return -1;
+		}
+		gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
+		gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
+		         sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
+
+		if (keydatalen % 8) {
+			wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+				   "%d", keydatalen);
+			return -1;
+		}
+
+		if (aes_unwrap(sm->ptk.kek, keydatalen / 8, buf + 13, gd.gtk))
+		{
+			wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+				   "could not decrypt GTK");
+			return -1;
+		}
+
+		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
+				gd.gtk, gd.gtk_len);
+		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
+				   "WNM mode");
+			return -1;
+		}
+#ifdef CONFIG_IEEE80211W
+	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+		if (buf[1] != 2 + 6 + WPA_IGTK_LEN + 8) {
+			wpa_printf(MSG_DEBUG, "WPA: Unsupported AES-WRAP len "
+				   "%d", buf[1] - 2 - 6 - 8);
+			return -1;
+		}
+		os_memcpy(igd.keyid, buf + 2, 2);
+		os_memcpy(igd.pn, buf + 4, 6);
+
+		keyidx = WPA_GET_LE16(igd.keyid);
+
+		if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, buf + 10,
+			       igd.igtk)) {
+			wpa_printf(MSG_WARNING, "WNM: AES unwrap failed - "
+				   "could not decrypr IGTK");
+			return -1;
+		}
+
+		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
+				igd.igtk, WPA_IGTK_LEN);
+		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				   keyidx, 0, igd.pn, sizeof(igd.pn),
+				   igd.igtk, WPA_IGTK_LEN) < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
+				   "WNM mode");
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else {
+		wpa_printf(MSG_DEBUG, "Unknown element id");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211V */