From 68db9ab047b74b2795d57a62641b7f5d73ceda9c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 16 Dec 2012 12:48:34 +0200 Subject: [PATCH] WNM: Fix GTK/IGTK parsing for WNM-Sleep Mode Response frame These fields do not use AES keywrap. Instead, they are protected with management frame protection (and not included if PMF is disabled). Signed-hostap: Jouni Malinen --- src/rsn_supp/wpa.c | 30 +++-------------------------- wpa_supplicant/wnm_sta.c | 41 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c index 3c45f3a02..5d1de4c39 100644 --- a/src/rsn_supp/wpa.c +++ b/src/rsn_supp/wpa.c @@ -2637,7 +2637,6 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) #endif /* CONFIG_IEEE80211W */ u16 keyinfo; u8 keylen; /* plaintext key len */ - u8 keydatalen; u8 *key_rsc; os_memset(&gd, 0, sizeof(gd)); @@ -2655,8 +2654,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) if (subelem_id == WNM_SLEEP_SUBELEM_GTK) { key_rsc = buf + 5; - keyinfo = WPA_GET_LE16(buf+2); - keydatalen = buf[1] - 11 - 8; + keyinfo = WPA_GET_LE16(buf + 2); gd.gtk_len = keylen; if (gd.gtk_len != buf[4]) { wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d", @@ -2667,18 +2665,7 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) 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; - } + os_memcpy(gd.gtk, buf + 13, gd.gtk_len); wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)", gd.gtk, gd.gtk_len); @@ -2689,22 +2676,11 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf) } #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; - } + os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN); wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)", igd.igtk, WPA_IGTK_LEN); diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c index 20f0d62e3..f1a1337b9 100644 --- a/wpa_supplicant/wnm_sta.c +++ b/wpa_supplicant/wnm_sta.c @@ -156,8 +156,17 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "action=%d token = %d key_len_total = %d", frm[0], frm[1], key_len_total); pos += 4 + key_len_total; + if (pos > frm + len) { + wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field"); + return; + } while (pos - frm < len) { u8 ie_len = *(pos + 1); + if (pos + 2 + ie_len > frm + len) { + wpa_printf(MSG_INFO, "WNM: Invalid IE len %u", ie_len); + break; + } + wpa_hexdump(MSG_DEBUG, "WNM: Element", pos, 2 + ie_len); if (*pos == WLAN_EID_WNMSLEEP) wnmsleep_ie = (struct wnm_sleep_element *) pos; else if (*pos == WLAN_EID_TFS_RESP) { @@ -210,9 +219,33 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, do { /* point to key data field */ u8 *ptr = (u8 *) frm + 1 + 1 + 2; - while (ptr < (u8 *) frm + 4 + key_len_total) { + u8 *end = ptr + key_len_total; + wpa_hexdump_key(MSG_DEBUG, "WNM: Key Data", + ptr, key_len_total); + while (ptr + 1 < end) { + if (ptr + 2 + ptr[1] > end) { + wpa_printf(MSG_DEBUG, + "WNM: Invalid Key " + "Data element " + "length"); + if (end > ptr) + wpa_hexdump(MSG_DEBUG, "WNM: Remaining data", ptr, end - ptr); + break; + } if (*ptr == WNM_SLEEP_SUBELEM_GTK) { + if (ptr[1] < 11 + 5) { + wpa_printf(MSG_DEBUG, + "WNM: Too short GTK subelem"); + break; + } gtk_len = *(ptr + 4); + if (ptr[1] < 11 + gtk_len || + gtk_len < 5 || gtk_len > 32) + { + wpa_printf(MSG_DEBUG, + "WNM: Invalid GTK subelem"); + break; + } wpa_wnmsleep_install_key( wpa_s->wpa, WNM_SLEEP_SUBELEM_GTK, @@ -221,6 +254,12 @@ static void ieee802_11_rx_wnmsleep_resp(struct wpa_supplicant *wpa_s, #ifdef CONFIG_IEEE80211W } else if (*ptr == WNM_SLEEP_SUBELEM_IGTK) { + if (ptr[1] < 2 + 6 + + WPA_IGTK_LEN) { + wpa_printf(MSG_DEBUG, + "WNM: Too short IGTK subelem"); + break; + } wpa_wnmsleep_install_key( wpa_s->wpa, WNM_SLEEP_SUBELEM_IGTK,