MFP + FT: Added support for sending IGTK in FTIE
This commit is contained in:
parent
565861976d
commit
b27f13ed28
2 changed files with 212 additions and 74 deletions
|
@ -371,6 +371,17 @@ static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
static inline int wpa_auth_get_seqnum_igtk(struct wpa_authenticator *wpa_auth,
|
||||||
|
const u8 *addr, int idx, u8 *seq)
|
||||||
|
{
|
||||||
|
if (wpa_auth->cb.get_seqnum_igtk == NULL)
|
||||||
|
return -1;
|
||||||
|
return wpa_auth->cb.get_seqnum_igtk(wpa_auth->cb.ctx, addr, idx, seq);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
|
|
||||||
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||||
{
|
{
|
||||||
u8 *subelem;
|
u8 *subelem;
|
||||||
|
@ -426,6 +437,38 @@ static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||||
|
{
|
||||||
|
u8 *subelem, *pos;
|
||||||
|
struct wpa_group *gsm = sm->group;
|
||||||
|
size_t subelem_len;
|
||||||
|
|
||||||
|
/* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16+8] */
|
||||||
|
subelem_len = 1 + 1 + 2 + 6 + WPA_IGTK_LEN + 8;
|
||||||
|
subelem = os_zalloc(subelem_len);
|
||||||
|
if (subelem == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pos = subelem;
|
||||||
|
*pos++ = FTIE_SUBELEM_IGTK;
|
||||||
|
*pos++ = subelem_len - 2;
|
||||||
|
WPA_PUT_LE16(pos, gsm->GN_igtk);
|
||||||
|
pos += 2;
|
||||||
|
wpa_auth_get_seqnum_igtk(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
|
||||||
|
pos += 6;
|
||||||
|
if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
|
||||||
|
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
|
||||||
|
os_free(subelem);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*len = subelem_len;
|
||||||
|
return subelem;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
|
|
||||||
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||||
size_t max_len, int auth_alg)
|
size_t max_len, int auth_alg)
|
||||||
{
|
{
|
||||||
|
@ -467,6 +510,28 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
||||||
subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
|
subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
|
||||||
r0kh_id = sm->r0kh_id;
|
r0kh_id = sm->r0kh_id;
|
||||||
r0kh_id_len = sm->r0kh_id_len;
|
r0kh_id_len = sm->r0kh_id_len;
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
if (sm->mgmt_frame_prot) {
|
||||||
|
u8 *igtk;
|
||||||
|
size_t igtk_len;
|
||||||
|
u8 *nbuf;
|
||||||
|
igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
|
||||||
|
if (igtk == NULL) {
|
||||||
|
os_free(subelem);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
nbuf = os_realloc(subelem, subelem_len + igtk_len);
|
||||||
|
if (nbuf == NULL) {
|
||||||
|
os_free(subelem);
|
||||||
|
os_free(igtk);
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
subelem = nbuf;
|
||||||
|
os_memcpy(subelem + subelem_len, igtk, igtk_len);
|
||||||
|
subelem_len += igtk_len;
|
||||||
|
os_free(igtk);
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
} else {
|
} else {
|
||||||
r0kh_id = conf->r0_key_holder;
|
r0kh_id = conf->r0_key_holder;
|
||||||
r0kh_id_len = conf->r0_key_holder_len;
|
r0kh_id_len = conf->r0_key_holder_len;
|
||||||
|
|
|
@ -286,6 +286,8 @@ struct wpa_ft_ies {
|
||||||
const u8 *rsn_pmkid;
|
const u8 *rsn_pmkid;
|
||||||
const u8 *tie;
|
const u8 *tie;
|
||||||
size_t tie_len;
|
size_t tie_len;
|
||||||
|
const u8 *igtk;
|
||||||
|
size_t igtk_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -323,6 +325,12 @@ static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
|
||||||
parse->r0kh_id = pos + 2;
|
parse->r0kh_id = pos + 2;
|
||||||
parse->r0kh_id_len = pos[1];
|
parse->r0kh_id_len = pos[1];
|
||||||
break;
|
break;
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
case FTIE_SUBELEM_IGTK:
|
||||||
|
parse->igtk = pos + 2;
|
||||||
|
parse->igtk_len = pos[1];
|
||||||
|
break;
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += 2 + pos[1];
|
pos += 2 + pos[1];
|
||||||
|
@ -581,17 +589,147 @@ int wpa_ft_is_completed(struct wpa_sm *sm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
|
||||||
|
size_t gtk_elem_len)
|
||||||
|
{
|
||||||
|
u8 gtk[32];
|
||||||
|
int keyidx;
|
||||||
|
wpa_alg alg;
|
||||||
|
size_t gtk_len, keylen, rsc_len;
|
||||||
|
|
||||||
|
if (gtk_elem == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
|
||||||
|
gtk_elem, gtk_elem_len);
|
||||||
|
|
||||||
|
if (gtk_elem_len < 10 + 24 || (gtk_elem_len - 10) % 8 ||
|
||||||
|
gtk_elem_len - 18 > sizeof(gtk)) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
|
||||||
|
"length %lu", (unsigned long) gtk_elem_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gtk_len = gtk_elem_len - 18;
|
||||||
|
if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 10, gtk)) {
|
||||||
|
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
|
||||||
|
"decrypt GTK");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (sm->group_cipher) {
|
||||||
|
case WPA_CIPHER_CCMP:
|
||||||
|
keylen = 16;
|
||||||
|
rsc_len = 6;
|
||||||
|
alg = WPA_ALG_CCMP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_TKIP:
|
||||||
|
keylen = 32;
|
||||||
|
rsc_len = 6;
|
||||||
|
alg = WPA_ALG_TKIP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_WEP104:
|
||||||
|
keylen = 13;
|
||||||
|
rsc_len = 0;
|
||||||
|
alg = WPA_ALG_WEP;
|
||||||
|
break;
|
||||||
|
case WPA_CIPHER_WEP40:
|
||||||
|
keylen = 5;
|
||||||
|
rsc_len = 0;
|
||||||
|
alg = WPA_ALG_WEP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
|
||||||
|
sm->group_cipher);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gtk_len < keylen) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Key Info[1] | Key Length[1] | RSC[8] | Key[5..32]. */
|
||||||
|
|
||||||
|
keyidx = gtk_elem[0] & 0x03;
|
||||||
|
|
||||||
|
if (gtk_elem[1] != keylen) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
|
||||||
|
"negotiated %lu",
|
||||||
|
gtk_elem[1], (unsigned long) keylen);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
|
||||||
|
if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
|
||||||
|
keyidx, 0, gtk_elem + 2, rsc_len, gtk, keylen) <
|
||||||
|
0) {
|
||||||
|
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
|
||||||
|
"driver.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef CONFIG_IEEE80211W
|
||||||
|
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
|
||||||
|
size_t igtk_elem_len)
|
||||||
|
{
|
||||||
|
u8 igtk[WPA_IGTK_LEN];
|
||||||
|
u16 keyidx;
|
||||||
|
|
||||||
|
if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (igtk_elem == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
|
||||||
|
igtk_elem, igtk_elem_len);
|
||||||
|
|
||||||
|
if (igtk_elem_len != 2 + 6 + 24) {
|
||||||
|
wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
|
||||||
|
"length %lu", (unsigned long) igtk_elem_len);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 8, igtk)) {
|
||||||
|
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
|
||||||
|
"decrypt IGTK");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* KeyID[2] | PN[6] | Key[16+8] */
|
||||||
|
|
||||||
|
keyidx = WPA_GET_LE16(igtk_elem);
|
||||||
|
|
||||||
|
wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
|
||||||
|
WPA_IGTK_LEN);
|
||||||
|
if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff",
|
||||||
|
keyidx, 0, igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) <
|
||||||
|
0) {
|
||||||
|
wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
|
||||||
|
"driver.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
|
|
||||||
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
||||||
size_t ies_len, const u8 *src_addr)
|
size_t ies_len, const u8 *src_addr)
|
||||||
{
|
{
|
||||||
struct wpa_ft_ies parse;
|
struct wpa_ft_ies parse;
|
||||||
struct rsn_mdie *mdie;
|
struct rsn_mdie *mdie;
|
||||||
struct rsn_ftie *ftie;
|
struct rsn_ftie *ftie;
|
||||||
size_t count, gtk_len, keylen, rsc_len;
|
size_t count;
|
||||||
u8 mic[16];
|
u8 mic[16];
|
||||||
u8 gtk[32];
|
|
||||||
int keyidx;
|
|
||||||
wpa_alg alg;
|
|
||||||
|
|
||||||
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
|
wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
|
||||||
|
|
||||||
|
@ -681,78 +819,13 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse.gtk == NULL) {
|
if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
|
||||||
wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
|
|
||||||
parse.gtk, parse.gtk_len);
|
|
||||||
|
|
||||||
if (parse.gtk_len < 10 + 24 || (parse.gtk_len - 10) % 8 ||
|
|
||||||
parse.gtk_len - 18 > sizeof(gtk)) {
|
|
||||||
wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
|
|
||||||
"length %lu", (unsigned long) parse.gtk_len);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
gtk_len = parse.gtk_len - 18;
|
#ifdef CONFIG_IEEE80211W
|
||||||
if (aes_unwrap(sm->ptk.kek, gtk_len / 8, parse.gtk + 10, gtk)) {
|
if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
|
||||||
wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
|
|
||||||
"decrypt GTK");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
#endif /* CONFIG_IEEE80211W */
|
||||||
|
|
||||||
switch (sm->group_cipher) {
|
|
||||||
case WPA_CIPHER_CCMP:
|
|
||||||
keylen = 16;
|
|
||||||
rsc_len = 6;
|
|
||||||
alg = WPA_ALG_CCMP;
|
|
||||||
break;
|
|
||||||
case WPA_CIPHER_TKIP:
|
|
||||||
keylen = 32;
|
|
||||||
rsc_len = 6;
|
|
||||||
alg = WPA_ALG_TKIP;
|
|
||||||
break;
|
|
||||||
case WPA_CIPHER_WEP104:
|
|
||||||
keylen = 13;
|
|
||||||
rsc_len = 0;
|
|
||||||
alg = WPA_ALG_WEP;
|
|
||||||
break;
|
|
||||||
case WPA_CIPHER_WEP40:
|
|
||||||
keylen = 5;
|
|
||||||
rsc_len = 0;
|
|
||||||
alg = WPA_ALG_WEP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
|
|
||||||
sm->group_cipher);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gtk_len < keylen) {
|
|
||||||
wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Key Info[1] | Key Length[1] | RSC[8] | Key[5..32]. */
|
|
||||||
|
|
||||||
keyidx = parse.gtk[0] & 0x03;
|
|
||||||
|
|
||||||
if (parse.gtk[1] != keylen) {
|
|
||||||
wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
|
|
||||||
"negotiated %lu",
|
|
||||||
parse.gtk[1], (unsigned long) keylen);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
|
|
||||||
if (wpa_sm_set_key(sm, alg, (u8 *) "\xff\xff\xff\xff\xff\xff",
|
|
||||||
keyidx, 0, parse.gtk + 2, rsc_len, gtk, keylen) < 0)
|
|
||||||
{
|
|
||||||
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
|
|
||||||
"driver.");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue