Add BIGTK KDE and subelement similarly to IGTK
This provides the BIGTK updates to associated stations similarly to IGTK. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
This commit is contained in:
parent
555dcd75ce
commit
16889aff40
5 changed files with 153 additions and 14 deletions
|
@ -54,6 +54,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
size_t len;
|
||||
size_t gtk_elem_len = 0;
|
||||
size_t igtk_elem_len = 0;
|
||||
size_t bigtk_elem_len = 0;
|
||||
struct wnm_sleep_element wnmsleep_ie;
|
||||
u8 *wnmtfs_ie, *oci_ie;
|
||||
u8 wnmsleep_ie_len, oci_ie_len;
|
||||
|
@ -122,8 +123,10 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
|
||||
#define MAX_GTK_SUBELEM_LEN 45
|
||||
#define MAX_IGTK_SUBELEM_LEN 26
|
||||
#define MAX_BIGTK_SUBELEM_LEN 26
|
||||
mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
|
||||
MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN +
|
||||
MAX_BIGTK_SUBELEM_LEN +
|
||||
oci_ie_len);
|
||||
if (mgmt == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
|
||||
|
@ -157,10 +160,19 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
pos += igtk_elem_len;
|
||||
wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
|
||||
(int) igtk_elem_len);
|
||||
if (hapd->conf->beacon_prot) {
|
||||
res = wpa_wnmsleep_bigtk_subelem(sta->wpa_sm, pos);
|
||||
if (res < 0)
|
||||
goto fail;
|
||||
bigtk_elem_len = res;
|
||||
pos += bigtk_elem_len;
|
||||
wpa_printf(MSG_DEBUG, "Pass 4 bigtk_len = %d",
|
||||
(int) bigtk_elem_len);
|
||||
}
|
||||
|
||||
WPA_PUT_LE16((u8 *)
|
||||
&mgmt->u.action.u.wnm_sleep_resp.keydata_len,
|
||||
gtk_elem_len + igtk_elem_len);
|
||||
gtk_elem_len + igtk_elem_len + bigtk_elem_len);
|
||||
}
|
||||
os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
|
||||
/* copy TFS IE here */
|
||||
|
@ -176,7 +188,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
#endif /* CONFIG_OCV */
|
||||
|
||||
len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
|
||||
igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
|
||||
igtk_elem_len + bigtk_elem_len +
|
||||
wnmsleep_ie_len + wnmtfs_ie_len + oci_ie_len;
|
||||
|
||||
/* In driver, response frame should be forced to sent when STA is in
|
||||
* PS mode */
|
||||
|
@ -189,8 +202,8 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
|
||||
/* when entering wnmsleep
|
||||
* 1. pause the node in driver
|
||||
* 2. mark the node so that AP won't update GTK/IGTK during
|
||||
* WNM Sleep
|
||||
* 2. mark the node so that AP won't update GTK/IGTK/BIGTK
|
||||
* during WNM Sleep
|
||||
*/
|
||||
if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
|
||||
wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
|
||||
|
@ -201,7 +214,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
}
|
||||
/* when exiting wnmsleep
|
||||
* 1. unmark the node
|
||||
* 2. start GTK/IGTK update if MFP is not used
|
||||
* 2. start GTK/IGTK/BIGTK update if MFP is not used
|
||||
* 3. unpause the node in driver
|
||||
*/
|
||||
if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
|
||||
|
@ -221,6 +234,7 @@ static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
|
|||
|
||||
#undef MAX_GTK_SUBELEM_LEN
|
||||
#undef MAX_IGTK_SUBELEM_LEN
|
||||
#undef MAX_BIGTK_SUBELEM_LEN
|
||||
fail:
|
||||
os_free(wnmtfs_ie);
|
||||
os_free(oci_ie);
|
||||
|
|
|
@ -63,6 +63,7 @@ static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
|||
struct wpa_group *group);
|
||||
static void wpa_group_put(struct wpa_authenticator *wpa_auth,
|
||||
struct wpa_group *group);
|
||||
static int ieee80211w_kde_len(struct wpa_state_machine *sm);
|
||||
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos);
|
||||
|
||||
static const u32 eapol_key_timeout_first = 100; /* ms */
|
||||
|
@ -2679,7 +2680,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
|
|||
size_t gtk_len;
|
||||
struct wpa_group *gsm;
|
||||
|
||||
plain = wpabuf_alloc(1000);
|
||||
plain = wpabuf_alloc(1000 + ieee80211w_kde_len(sm));
|
||||
if (!plain)
|
||||
return NULL;
|
||||
|
||||
|
@ -2727,7 +2728,7 @@ static struct wpabuf * fils_prepare_plainbuf(struct wpa_state_machine *sm,
|
|||
gtk, gtk_len);
|
||||
wpabuf_put(plain, tmp2 - tmp);
|
||||
|
||||
/* IGTK KDE */
|
||||
/* IGTK KDE and BIGTK KDE */
|
||||
tmp = wpabuf_put(plain, 0);
|
||||
tmp2 = ieee80211w_kde_add(sm, tmp);
|
||||
wpabuf_put(plain, tmp2 - tmp);
|
||||
|
@ -3105,19 +3106,25 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
|
|||
|
||||
static int ieee80211w_kde_len(struct wpa_state_machine *sm)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if (sm->mgmt_frame_prot) {
|
||||
size_t len;
|
||||
len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
return 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN + len;
|
||||
len += 2 + RSN_SELECTOR_LEN + WPA_IGTK_KDE_PREFIX_LEN;
|
||||
len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
}
|
||||
if (sm->mgmt_frame_prot && sm->wpa_auth->conf.beacon_prot) {
|
||||
len += 2 + RSN_SELECTOR_LEN + WPA_BIGTK_KDE_PREFIX_LEN;
|
||||
len += wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
|
||||
{
|
||||
struct wpa_igtk_kde igtk;
|
||||
struct wpa_bigtk_kde bigtk;
|
||||
struct wpa_group *gsm = sm->group;
|
||||
u8 rsc[WPA_KEY_RSC_LEN];
|
||||
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
|
@ -3146,6 +3153,21 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
|
|||
(const u8 *) &igtk, WPA_IGTK_KDE_PREFIX_LEN + len,
|
||||
NULL, 0);
|
||||
|
||||
if (!sm->wpa_auth->conf.beacon_prot)
|
||||
return pos;
|
||||
|
||||
bigtk.keyid[0] = gsm->GN_bigtk;
|
||||
bigtk.keyid[1] = 0;
|
||||
if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
|
||||
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, rsc) < 0)
|
||||
os_memset(bigtk.pn, 0, sizeof(bigtk.pn));
|
||||
else
|
||||
os_memcpy(bigtk.pn, rsc, sizeof(bigtk.pn));
|
||||
os_memcpy(bigtk.bigtk, gsm->BIGTK[gsm->GN_bigtk - 6], len);
|
||||
pos = wpa_add_kde(pos, RSN_KEY_DATA_BIGTK,
|
||||
(const u8 *) &bigtk, WPA_BIGTK_KDE_PREFIX_LEN + len,
|
||||
NULL, 0);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -3205,7 +3227,7 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
|
|||
}
|
||||
|
||||
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
|
||||
GTK[GN], IGTK, [FTIE], [TIE * 2])
|
||||
GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
|
||||
*/
|
||||
os_memset(rsc, 0, WPA_KEY_RSC_LEN);
|
||||
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
|
||||
|
@ -3978,6 +4000,36 @@ int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
|
|||
return pos - start;
|
||||
}
|
||||
|
||||
|
||||
int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos)
|
||||
{
|
||||
struct wpa_group *gsm = sm->group;
|
||||
u8 *start = pos;
|
||||
size_t len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
|
||||
/*
|
||||
* BIGTK subelement:
|
||||
* Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
|
||||
*/
|
||||
*pos++ = WNM_SLEEP_SUBELEM_BIGTK;
|
||||
*pos++ = 2 + 6 + len;
|
||||
WPA_PUT_LE16(pos, gsm->GN_bigtk);
|
||||
pos += 2;
|
||||
if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos) != 0)
|
||||
return 0;
|
||||
pos += 6;
|
||||
|
||||
os_memcpy(pos, gsm->BIGTK[gsm->GN_bigtk - 6], len);
|
||||
pos += len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WNM: BIGTK Key ID %u in WNM-Sleep Mode exit",
|
||||
gsm->GN_bigtk);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WNM: BIGTK in WNM-Sleep Mode exit",
|
||||
gsm->IGTK[gsm->GN_bigtk - 6], len);
|
||||
|
||||
return pos - start;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_WNM_AP */
|
||||
|
||||
|
||||
|
@ -5074,7 +5126,7 @@ int wpa_auth_resend_m3(struct wpa_state_machine *sm,
|
|||
int wpa_ie_len, secure, gtkidx, encr = 0;
|
||||
|
||||
/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
|
||||
GTK[GN], IGTK, [FTIE], [TIE * 2])
|
||||
GTK[GN], IGTK, [BIGTK], [FTIE], [TIE * 2])
|
||||
*/
|
||||
|
||||
/* Use 0 RSC */
|
||||
|
|
|
@ -438,6 +438,7 @@ void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
|
|||
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_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
|
||||
int wpa_wnmsleep_bigtk_subelem(struct wpa_state_machine *sm, u8 *pos);
|
||||
|
||||
int wpa_auth_uses_sae(struct wpa_state_machine *sm);
|
||||
int wpa_auth_uses_ft_sae(struct wpa_state_machine *sm);
|
||||
|
|
|
@ -2282,6 +2282,54 @@ static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
|||
}
|
||||
|
||||
|
||||
static u8 * wpa_ft_bigtk_subelem(struct wpa_state_machine *sm, size_t *len)
|
||||
{
|
||||
u8 *subelem, *pos;
|
||||
struct wpa_group *gsm = sm->group;
|
||||
size_t subelem_len;
|
||||
const u8 *kek;
|
||||
size_t kek_len;
|
||||
size_t bigtk_len;
|
||||
|
||||
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
|
||||
kek = sm->PTK.kek2;
|
||||
kek_len = sm->PTK.kek2_len;
|
||||
} else {
|
||||
kek = sm->PTK.kek;
|
||||
kek_len = sm->PTK.kek_len;
|
||||
}
|
||||
|
||||
bigtk_len = wpa_cipher_key_len(sm->wpa_auth->conf.group_mgmt_cipher);
|
||||
|
||||
/* Sub-elem ID[1] | Length[1] | KeyID[2] | BIPN[6] | Key Length[1] |
|
||||
* Key[16+8] */
|
||||
subelem_len = 1 + 1 + 2 + 6 + 1 + bigtk_len + 8;
|
||||
subelem = os_zalloc(subelem_len);
|
||||
if (subelem == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = subelem;
|
||||
*pos++ = FTIE_SUBELEM_BIGTK;
|
||||
*pos++ = subelem_len - 2;
|
||||
WPA_PUT_LE16(pos, gsm->GN_bigtk);
|
||||
pos += 2;
|
||||
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_bigtk, pos);
|
||||
pos += 6;
|
||||
*pos++ = bigtk_len;
|
||||
if (aes_wrap(kek, kek_len, bigtk_len / 8,
|
||||
gsm->IGTK[gsm->GN_bigtk - 6], pos)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: BIGTK subelem encryption failed: kek_len=%d",
|
||||
(int) kek_len);
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = subelem_len;
|
||||
return subelem;
|
||||
}
|
||||
|
||||
|
||||
static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
|
||||
u8 *pos, u8 *end, u8 id, u8 descr_count,
|
||||
const u8 *ies, size_t ies_len)
|
||||
|
@ -2511,6 +2559,29 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
|
|||
subelem_len += igtk_len;
|
||||
os_free(igtk);
|
||||
}
|
||||
if (sm->mgmt_frame_prot && conf->beacon_prot) {
|
||||
u8 *bigtk;
|
||||
size_t bigtk_len;
|
||||
u8 *nbuf;
|
||||
|
||||
bigtk = wpa_ft_bigtk_subelem(sm, &bigtk_len);
|
||||
if (!bigtk) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"FT: Failed to add BIGTK subelement");
|
||||
os_free(subelem);
|
||||
return NULL;
|
||||
}
|
||||
nbuf = os_realloc(subelem, subelem_len + bigtk_len);
|
||||
if (!nbuf) {
|
||||
os_free(subelem);
|
||||
os_free(bigtk);
|
||||
return NULL;
|
||||
}
|
||||
subelem = nbuf;
|
||||
os_memcpy(subelem + subelem_len, bigtk, bigtk_len);
|
||||
subelem_len += bigtk_len;
|
||||
os_free(bigtk);
|
||||
}
|
||||
#ifdef CONFIG_OCV
|
||||
if (wpa_auth_uses_ocv(sm)) {
|
||||
struct wpa_channel_info ci;
|
||||
|
|
|
@ -1875,7 +1875,8 @@ enum wnm_sleep_mode_response_status {
|
|||
/* WNM-Sleep Mode subelement IDs */
|
||||
enum wnm_sleep_mode_subelement_id {
|
||||
WNM_SLEEP_SUBELEM_GTK = 0,
|
||||
WNM_SLEEP_SUBELEM_IGTK = 1
|
||||
WNM_SLEEP_SUBELEM_IGTK = 1,
|
||||
WNM_SLEEP_SUBELEM_BIGTK = 2,
|
||||
};
|
||||
|
||||
/* Channel Switch modes (802.11h) */
|
||||
|
|
Loading…
Reference in a new issue