aboutsummaryrefslogtreecommitdiffstats
path: root/src/rsn_supp/wpa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rsn_supp/wpa.c')
-rw-r--r--src/rsn_supp/wpa.c170
1 files changed, 165 insertions, 5 deletions
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 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
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 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
#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 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
"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 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
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 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
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 @@ static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
*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 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
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 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
} 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 @@ static int wpa_cipher_bits(int cipher)
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 @@ static u32 wpa_cipher_suite(struct wpa_sm *sm, int cipher)
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 @@ void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
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 */