diff options
Diffstat (limited to 'src/rsn_supp/wpa.c')
-rw-r--r-- | src/rsn_supp/wpa.c | 170 |
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 */ |