WNM: Fix GTK/IGTK encoding in WNM-Sleep Mode Exit frame

These subelements do not use AES key wrap (MFP is used instead).

Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2012-12-16 19:46:10 +02:00
parent 5d247692f6
commit 835822d404

View file

@ -2444,108 +2444,62 @@ void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos) int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{ {
u8 *subelem;
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
size_t subelem_len, pad_len; u8 *start = pos;
const u8 *key;
size_t key_len;
u8 keybuf[32];
/* GTK subslement */
key_len = gsm->GTK_len;
if (key_len > sizeof(keybuf))
return 0;
/*
* Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
* than 16 bytes.
*/
pad_len = key_len % 8;
if (pad_len)
pad_len = 8 - pad_len;
if (key_len + pad_len < 16)
pad_len += 8;
if (pad_len) {
os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
os_memset(keybuf + key_len, 0, pad_len);
keybuf[key_len] = 0xdd;
key_len += pad_len;
key = keybuf;
} else
key = gsm->GTK[gsm->GN - 1];
/* /*
* GTK subelement:
* Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] | * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
* Key[5..32] | 8 padding. * Key[5..32]
*/ */
subelem_len = 13 + key_len + 8; *pos++ = WNM_SLEEP_SUBELEM_GTK;
subelem = os_zalloc(subelem_len); *pos++ = 11 + gsm->GTK_len;
if (subelem == NULL)
return 0;
subelem[0] = WNM_SLEEP_SUBELEM_GTK;
subelem[1] = 11 + key_len + 8;
/* Key ID in B0-B1 of Key Info */ /* Key ID in B0-B1 of Key Info */
WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03); WPA_PUT_LE16(pos, gsm->GN & 0x03);
subelem[4] = gsm->GTK_len; pos += 2;
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5) != 0) *pos++ = gsm->GTK_len;
{ if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
os_free(subelem);
return 0; return 0;
} pos += 8;
if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) { os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
os_free(subelem); pos += gsm->GTK_len;
return 0;
}
os_memcpy(pos, subelem, subelem_len); wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
gsm->GN);
wpa_hexdump_key(MSG_DEBUG, "Plaintext GTK", wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
gsm->GTK[gsm->GN - 1], gsm->GTK_len); gsm->GTK[gsm->GN - 1], gsm->GTK_len);
os_free(subelem);
return subelem_len; return pos - start;
} }
#ifdef CONFIG_IEEE80211W #ifdef CONFIG_IEEE80211W
int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos) int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
{ {
u8 *subelem, *ptr;
struct wpa_group *gsm = sm->group; struct wpa_group *gsm = sm->group;
size_t subelem_len; u8 *start = pos;
/* IGTK subelement /*
* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | * IGTK subelement:
* Key[16] | 8 padding */ * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8; */
subelem = os_zalloc(subelem_len); *pos++ = WNM_SLEEP_SUBELEM_IGTK;
if (subelem == NULL) *pos++ = 2 + 6 + WPA_IGTK_LEN;
WPA_PUT_LE16(pos, gsm->GN_igtk);
pos += 2;
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
return 0; return 0;
pos += 6;
ptr = subelem; os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
*ptr++ = WNM_SLEEP_SUBELEM_IGTK; pos += WPA_IGTK_LEN;
*ptr++ = subelem_len - 2;
WPA_PUT_LE16(ptr, gsm->GN_igtk);
ptr += 2;
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, ptr) != 0) {
os_free(subelem);
return 0;
}
ptr += 6;
if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], ptr)) {
os_free(subelem);
return -1;
}
os_memcpy(pos, subelem, subelem_len); wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
gsm->GN_igtk);
wpa_hexdump_key(MSG_DEBUG, "Plaintext IGTK", wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN); gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
os_free(subelem);
return subelem_len; return pos - start;
} }
#endif /* CONFIG_IEEE80211W */ #endif /* CONFIG_IEEE80211W */
#endif /* CONFIG_WNM */ #endif /* CONFIG_WNM */