aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@codeaurora.org>2020-02-17 22:06:26 (GMT)
committerJouni Malinen <j@w1.fi>2020-02-17 22:18:47 (GMT)
commit2d4c78aef718b9a3e5947c4fad4bbd634b6eab9d (patch)
tree41e5183946f30e79a9a3f3eccd4aa80856e35007
parentecbf59e6931f304801fa728b191b2b7506908059 (diff)
downloadhostap-2d4c78aef718.zip
hostap-2d4c78aef718.tar.gz
hostap-2d4c78aef718.tar.bz2
Configure received BIGTK on station/supplicant side
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--src/rsn_supp/wpa.c73
-rw-r--r--src/rsn_supp/wpa_ft.c75
-rw-r--r--src/rsn_supp/wpa_i.h2
-rw-r--r--wpa_supplicant/wnm_sta.c9
4 files changed, 154 insertions, 5 deletions
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 981602c..1e209ad 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -1140,14 +1140,66 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
}
+static int wpa_supplicant_install_bigtk(struct wpa_sm *sm,
+ const struct wpa_bigtk_kde *bigtk,
+ int wnm_sleep)
+{
+ size_t len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ u16 keyidx = WPA_GET_LE16(bigtk->keyid);
+
+ /* Detect possible key reinstallation */
+ if ((sm->bigtk.bigtk_len == len &&
+ os_memcmp(sm->bigtk.bigtk, bigtk->bigtk,
+ sm->bigtk.bigtk_len) == 0) ||
+ (sm->bigtk_wnm_sleep.bigtk_len == len &&
+ os_memcmp(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len) == 0)) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: Not reinstalling already in-use BIGTK to the driver (keyidx=%d)",
+ keyidx);
+ return 0;
+ }
+
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "WPA: BIGTK keyid %d pn " COMPACT_MACSTR,
+ keyidx, MAC2STR(bigtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: BIGTK", bigtk->bigtk, len);
+ if (keyidx < 6 || keyidx > 7) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Invalid BIGTK KeyID %d", keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr,
+ keyidx, 0, bigtk->pn, sizeof(bigtk->pn),
+ bigtk->bigtk, len, KEY_FLAG_GROUP_RX) < 0) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+ "WPA: Failed to configure BIGTK to the driver");
+ return -1;
+ }
+
+ if (wnm_sleep) {
+ sm->bigtk_wnm_sleep.bigtk_len = len;
+ os_memcpy(sm->bigtk_wnm_sleep.bigtk, bigtk->bigtk,
+ sm->bigtk_wnm_sleep.bigtk_len);
+ } else {
+ sm->bigtk.bigtk_len = len;
+ os_memcpy(sm->bigtk.bigtk, bigtk->bigtk, sm->bigtk.bigtk_len);
+ }
+
+ return 0;
+}
+
+
static int ieee80211w_set_keys(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *ie)
{
+ size_t len;
+
if (!wpa_cipher_valid_mgmt_group(sm->mgmt_group_cipher))
return 0;
if (ie->igtk) {
- size_t len;
const struct wpa_igtk_kde *igtk;
len = wpa_cipher_key_len(sm->mgmt_group_cipher);
@@ -1159,6 +1211,18 @@ static int ieee80211w_set_keys(struct wpa_sm *sm,
return -1;
}
+ if (ie->bigtk && sm->beacon_prot) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (ie->bigtk_len != WPA_BIGTK_KDE_PREFIX_LEN + len)
+ return -1;
+
+ bigtk = (const struct wpa_bigtk_kde *) ie->bigtk;
+ if (wpa_supplicant_install_bigtk(sm, bigtk, 0) < 0)
+ return -1;
+ }
+
return 0;
}
@@ -3595,6 +3659,13 @@ int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
igtk = (const struct wpa_igtk_kde *) (buf + 2);
if (wpa_supplicant_install_igtk(sm, igtk, 1) < 0)
return -1;
+ } else if (subelem_id == WNM_SLEEP_SUBELEM_BIGTK) {
+ const struct wpa_bigtk_kde *bigtk;
+
+ bigtk = (const struct wpa_bigtk_kde *) (buf + 2);
+ if (sm->beacon_prot &&
+ wpa_supplicant_install_bigtk(sm, bigtk, 1) < 0)
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "Unknown element id");
return -1;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 8a8c545..046bdfd 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -855,6 +855,74 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
}
+static int wpa_ft_process_bigtk_subelem(struct wpa_sm *sm, const u8 *bigtk_elem,
+ size_t bigtk_elem_len)
+{
+ u8 bigtk[WPA_BIGTK_MAX_LEN];
+ size_t bigtk_len;
+ u16 keyidx;
+ const u8 *kek;
+ size_t kek_len;
+
+ if (!sm->beacon_prot || !bigtk_elem ||
+ (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_128 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_GMAC_256 &&
+ sm->mgmt_group_cipher != WPA_CIPHER_BIP_CMAC_256))
+ return 0;
+
+ if (wpa_key_mgmt_fils(sm->key_mgmt)) {
+ kek = sm->ptk.kek2;
+ kek_len = sm->ptk.kek2_len;
+ } else {
+ kek = sm->ptk.kek;
+ kek_len = sm->ptk.kek_len;
+ }
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: Received BIGTK in Reassoc Resp",
+ bigtk_elem, bigtk_elem_len);
+
+ bigtk_len = wpa_cipher_key_len(sm->mgmt_group_cipher);
+ if (bigtk_elem_len != 2 + 6 + 1 + bigtk_len + 8) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem length %lu",
+ (unsigned long) bigtk_elem_len);
+ return -1;
+ }
+ if (bigtk_elem[8] != bigtk_len) {
+ wpa_printf(MSG_DEBUG,
+ "FT: Invalid BIGTK sub-elem Key Length %d",
+ bigtk_elem[8]);
+ return -1;
+ }
+
+ if (aes_unwrap(kek, kek_len, bigtk_len / 8, bigtk_elem + 9, bigtk)) {
+ wpa_printf(MSG_WARNING,
+ "FT: AES unwrap failed - could not decrypt BIGTK");
+ return -1;
+ }
+
+ /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
+
+ keyidx = WPA_GET_LE16(bigtk_elem);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: BIGTK from Reassoc Resp", bigtk,
+ bigtk_len);
+ if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
+ broadcast_ether_addr, keyidx, 0,
+ bigtk_elem + 2, 6, bigtk, bigtk_len,
+ KEY_FLAG_GROUP_RX) < 0) {
+ wpa_printf(MSG_WARNING,
+ "WPA: Failed to set BIGTK to the driver");
+ forced_memzero(bigtk, sizeof(bigtk));
+ return -1;
+ }
+ forced_memzero(bigtk, sizeof(bigtk));
+
+ return 0;
+}
+
+
int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
size_t ies_len, const u8 *src_addr)
{
@@ -1036,10 +1104,9 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
sm->ft_reassoc_completed = 1;
- if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
- return -1;
-
- if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
+ if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0 ||
+ wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0 ||
+ wpa_ft_process_bigtk_subelem(sm, parse.bigtk, parse.bigtk_len) < 0)
return -1;
if (sm->set_ptk_after_assoc) {
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 164adfb..bd44464 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -33,6 +33,8 @@ struct wpa_sm {
struct wpa_gtk gtk_wnm_sleep;
struct wpa_igtk igtk;
struct wpa_igtk igtk_wnm_sleep;
+ struct wpa_bigtk bigtk;
+ struct wpa_bigtk bigtk_wnm_sleep;
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 270be9e..06cb70f 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -280,6 +280,15 @@ static void wnm_sleep_mode_exit_success(struct wpa_supplicant *wpa_s,
wpa_wnmsleep_install_key(wpa_s->wpa,
WNM_SLEEP_SUBELEM_IGTK, ptr);
ptr += 10 + WPA_IGTK_LEN;
+ } else if (*ptr == WNM_SLEEP_SUBELEM_BIGTK) {
+ if (ptr[1] < 2 + 6 + WPA_BIGTK_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "WNM: Too short BIGTK subelem");
+ break;
+ }
+ wpa_wnmsleep_install_key(wpa_s->wpa,
+ WNM_SLEEP_SUBELEM_BIGTK, ptr);
+ ptr += 10 + WPA_BIGTK_LEN;
} else
break; /* skip the loop */
}