[Patch v9 05/16] Introduce and add key_flag

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the new attribute "key_flag" which will in the following patches
replace the boolean "set_tx" with something also able to handle
"Extended Key ID for Individually Addressed Frames" from
IEEE 802.11-2016.

The following flag are defined:

  KEY_FLAG_MODIFY
    Set when an already installed key must be updated.
    So far the only use-case is changing RX/TX status of installed
    keys. Must not be set when deleting a key.

  KEY_FLAG_DEFAULT
    Set when the key is also a default key. Must not be set when
    deleting a key. (This is the replacement for set_tx.)

  KEY_FLAG_RX
    The key is valid for RX. Must not be set when deleting a key.

  KEY_FLAG_TX
    The key is valid for TX. Must not be set when deleting a key.

  KEY_FLAG_GROUP
    The key is a broadcast or group key.

  KEY_FLAG_PAIRWISE
    The key is a pairwise key.

  KEY_FLAG_PMK
    The key is a Pairwise Master Key (PMK).

Predefined and needed flag combinations so far are:

  KEY_FLAG_GROUP_RX_TX
    WEP key not used as default key (yet).

  KEY_FLAG_GROUP_RX_TX_DEFAULT
    Default WEP or WPA-NONE key.

  KEY_FLAG_GROUP_RX
    GTK key valid for RX only.

  KEY_FLAG_GROUP_TX_DEFAULT
    GTK key valid for TX only, immediately taking over TX.

  KEY_FLAG_PAIRWISE_RX_TX
    Pairwise key immediately becoming the active pairwise key.

  KEY_FLAG_PAIRWISE_RX
    Pairwise key not yet valid for TX. (Only usable with Extended Key ID
    support.)

  KEY_FLAG_PAIRWISE_RX_TX_MODIFY
    Enable TX for a pairwise key installed with KEY_FLAG_PAIRWISE_RX.

  KEY_FLAG_RX_TX
    Not a valid standalone key type and can only used in combination
    with other flags to mark a key for RX/TX.

This patch is not changing any functionality. It just adds the new
key_flag to all hostapd/wpa_supplicant set_key() functions without using
it, yet.

Signed-off-by: Alexander Wetzel <alexander@xxxxxxxxxxxxxx>
---
 hostapd/ctrl_iface.c            | 45 +++++++++++++++++++++++----------
 src/ap/ap_drv_ops.c             |  4 +--
 src/ap/ap_drv_ops.h             |  2 +-
 src/ap/hostapd.c                | 16 +++++++-----
 src/ap/ieee802_11.c             |  5 +++-
 src/ap/ieee802_1x.c             |  8 +++---
 src/ap/wpa_auth.c               | 18 ++++++++-----
 src/ap/wpa_auth.h               |  3 ++-
 src/ap/wpa_auth_ft.c            |  7 ++---
 src/ap/wpa_auth_glue.c          |  4 +--
 src/common/defs.h               | 22 ++++++++++++++++
 src/drivers/driver.h            | 43 ++++++++++++++++++++++++++++++-
 src/drivers/driver_atheros.c    |  3 ++-
 src/drivers/driver_bsd.c        |  3 ++-
 src/drivers/driver_hostap.c     |  3 ++-
 src/drivers/driver_ndis.c       | 12 +++++----
 src/drivers/driver_nl80211.c    | 11 +++++---
 src/drivers/driver_openbsd.c    |  3 ++-
 src/drivers/driver_privsep.c    |  3 ++-
 src/drivers/driver_wext.c       |  8 +++---
 src/drivers/driver_wext.h       |  3 ++-
 src/rsn_supp/tdls.c             |  7 ++---
 src/rsn_supp/wpa.c              | 17 ++++++++-----
 src/rsn_supp/wpa.h              |  2 +-
 src/rsn_supp/wpa_ft.c           | 11 +++++---
 src/rsn_supp/wpa_i.h            |  5 ++--
 tests/hwsim/test_ap_ciphers.py  |  2 +-
 wpa_supplicant/ctrl_iface.c     | 26 ++++++++++++-------
 wpa_supplicant/driver_i.h       |  6 +++--
 wpa_supplicant/ibss_rsn.c       | 11 ++++----
 wpa_supplicant/mesh_mpm.c       |  9 ++++---
 wpa_supplicant/mesh_rsn.c       | 10 +++++---
 wpa_supplicant/wpa_supplicant.c | 12 ++++++---
 wpa_supplicant/wpas_glue.c      | 13 ++++++----
 34 files changed, 249 insertions(+), 108 deletions(-)

diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index cb4d8fac2..98dcf09a4 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -2155,7 +2155,8 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					hapd->last_igtk_alg,
 					broadcast_ether_addr,
 					hapd->last_igtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_igtk_len) < 0)
+					zero, hapd->last_igtk_len,
+					KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
@@ -2164,7 +2165,8 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					   broadcast_ether_addr,
 					   hapd->last_igtk_key_idx, 1, NULL, 0,
 					   hapd->last_igtk,
-					   hapd->last_igtk_len);
+					   hapd->last_igtk_len,
+					   KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	if (is_broadcast_ether_addr(addr)) {
@@ -2179,7 +2181,8 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					hapd->last_gtk_alg,
 					broadcast_ether_addr,
 					hapd->last_gtk_key_idx, 1, NULL, 0,
-					zero, hapd->last_gtk_len) < 0)
+					zero, hapd->last_gtk_len,
+					KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			return -1;
 
 		/* Set the previously configured key to reset its TSC */
@@ -2187,7 +2190,8 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 					   hapd->last_gtk_alg,
 					   broadcast_ether_addr,
 					   hapd->last_gtk_key_idx, 1, NULL, 0,
-					   hapd->last_gtk, hapd->last_gtk_len);
+					   hapd->last_gtk, hapd->last_gtk_len,
+					   KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	sta = ap_get_sta(hapd, addr);
@@ -2204,13 +2208,15 @@ static int hostapd_ctrl_reset_pn(struct hostapd_data *hapd, const char *cmd)
 	 * in the driver. */
 	if (hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 				sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				zero, sta->last_tk_len) < 0)
+				zero, sta->last_tk_len,
+				KEY_FLAG_PAIRWISE_RX_TX) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 				   sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-				   sta->last_tk, sta->last_tk_len);
+				   sta->last_tk, sta->last_tk_len,
+				   KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
@@ -2219,11 +2225,12 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
 	u8 addr[ETH_ALEN];
 	const char *pos = cmd;
 	enum wpa_alg alg;
+	enum key_flag key_flag;
 	int idx, set_tx;
 	u8 seq[6], key[WPA_TK_MAX_LEN];
 	size_t key_len;
 
-	/* parameters: alg addr idx set_tx seq key */
+	/* parameters: alg addr idx set_tx seq key key_flag */
 
 	alg = atoi(pos);
 	pos = os_strchr(pos, ' ');
@@ -2252,13 +2259,24 @@ static int hostapd_ctrl_set_key(struct hostapd_data *hapd, const char *cmd)
 	if (*pos != ' ')
 		return -1;
 	pos++;
-	key_len = os_strlen(pos) / 2;
+	if (!os_strchr(pos, ' '))
+		return -1;
+	key_len = (os_strchr(pos, ' ') - pos) / 2;
 	if (hexstr2bin(pos, key, key_len) < 0)
 		return -1;
+	pos += 2 * key_len;
+	if (*pos != ' ')
+		return -1;
+
+	pos++;
+	key_flag = atoi(pos);
+	pos = os_strchr(pos, ' ');
+	if (pos)
+		return -1;
 
 	wpa_printf(MSG_INFO, "TESTING: Set key");
 	return hostapd_drv_set_key(hapd->conf->iface, hapd, alg, addr, idx,
-				   set_tx, seq, 6, key, key_len);
+				   set_tx, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -2274,7 +2292,8 @@ static void restore_tk(void *ctx1, void *ctx2)
 	 * preventing encryption of a single EAPOL frame. */
 	hostapd_drv_set_key(hapd->conf->iface, hapd, sta->last_tk_alg,
 			    sta->addr, sta->last_tk_key_idx, 1, NULL, 0,
-			    sta->last_tk, sta->last_tk_len);
+			    sta->last_tk, sta->last_tk_len,
+			    KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
@@ -2298,7 +2317,7 @@ static int hostapd_ctrl_resend_m1(struct hostapd_data *hapd, const char *cmd)
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M1 to " MACSTR, MAC2STR(sta->addr));
@@ -2328,7 +2347,7 @@ static int hostapd_ctrl_resend_m3(struct hostapd_data *hapd, const char *cmd)
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO, "TESTING: Send M3 to " MACSTR, MAC2STR(sta->addr));
@@ -2358,7 +2377,7 @@ static int hostapd_ctrl_resend_group_m1(struct hostapd_data *hapd,
 			   MAC2STR(sta->addr));
 		hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_NONE,
 				    sta->addr, sta->last_tk_key_idx, 0, NULL, 0,
-				    NULL, 0);
+				    NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	wpa_printf(MSG_INFO,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 35ecf4102..62f41b758 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -682,13 +682,13 @@ int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
 			enum wpa_alg alg, const u8 *addr,
 			int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_flag key_flag)
 {
 	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
 		return 0;
 	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
 				     key_idx, set_tx, seq, seq_len, key,
-				     key_len);
+				     key_len, key_flag);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index b0170df58..ca31ade86 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -91,7 +91,7 @@ int hostapd_drv_set_key(const char *ifname,
 			enum wpa_alg alg, const u8 *addr,
 			int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len);
+			const u8 *key, size_t key_len, enum key_flag key_flag);
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
 			  const void *msg, size_t len, int noack,
 			  const u16 *csa_offs, size_t csa_offs_len,
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 55dd11e06..0276515d7 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -292,8 +292,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 	if (!ifname || !hapd->drv_priv)
 		return;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
-					0, NULL, 0, NULL, 0)) {
+		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i, 0,
+					NULL, 0, NULL, 0, KEY_FLAG_GROUP)) {
 			wpa_printf(MSG_DEBUG, "Failed to clear default "
 				   "encryption keys (ifname=%s keyidx=%d)",
 				   ifname, i);
@@ -302,8 +302,8 @@ static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
 	if (hapd->conf->ieee80211w) {
 		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
 			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
-						NULL, i, 0, NULL,
-						0, NULL, 0)) {
+						NULL, i, 0, NULL, 0,
+						NULL, 0, KEY_FLAG_GROUP)) {
 				wpa_printf(MSG_DEBUG, "Failed to clear "
 					   "default mgmt encryption keys "
 					   "(ifname=%s keyidx=%d)", ifname, i);
@@ -330,7 +330,8 @@ static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
 	    hostapd_drv_set_key(hapd->conf->iface,
 				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
 				1, NULL, 0, ssid->wep.key[idx],
-				ssid->wep.len[idx])) {
+				ssid->wep.len[idx],
+				KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
 		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
 		errors++;
 	}
@@ -556,7 +557,10 @@ static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
 		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
 					i == hapd->conf->ssid.wep.idx, NULL, 0,
 					hapd->conf->ssid.wep.key[i],
-					hapd->conf->ssid.wep.len[i])) {
+					hapd->conf->ssid.wep.len[i],
+					i == hapd->conf->ssid.wep.idx ?
+					     KEY_FLAG_GROUP_RX_TX_DEFAULT :
+					     KEY_FLAG_GROUP_RX_TX)) {
 			wpa_printf(MSG_WARNING, "Could not set WEP "
 				   "encryption.");
 			return -1;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 84dea20ca..bee65ac3b 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -4880,7 +4880,10 @@ static void hostapd_set_wds_encryption(struct hostapd_data *hapd,
 		if (ssid->wep.key[i] &&
 		    hostapd_drv_set_key(ifname_wds, hapd, WPA_ALG_WEP, NULL, i,
 					i == ssid->wep.idx, NULL, 0,
-					ssid->wep.key[i], ssid->wep.len[i])) {
+					ssid->wep.key[i], ssid->wep.len[i],
+					i == ssid->wep.idx ?
+					     KEY_FLAG_GROUP_RX_TX_DEFAULT :
+					     KEY_FLAG_GROUP_RX_TX)) {
 			wpa_printf(MSG_WARNING,
 				   "Could not set WEP keys for WDS interface; %s",
 				   ifname_wds);
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index d0810310c..9b26ff1d7 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -285,7 +285,8 @@ static void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
 		 * has ACKed EAPOL-Key frame */
 		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
 					sta->addr, 0, 1, NULL, 0, ikey,
-					hapd->conf->individual_wep_key_len)) {
+					hapd->conf->individual_wep_key_len,
+					KEY_FLAG_PAIRWISE_RX_TX)) {
 			wpa_printf(MSG_ERROR,
 				   "Could not set individual WEP encryption");
 		}
@@ -2179,7 +2180,8 @@ static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
 				broadcast_ether_addr,
 				eapol->default_wep_key_idx, 1, NULL, 0,
 				eapol->default_wep_key,
-				hapd->conf->default_wep_key_len)) {
+				hapd->conf->default_wep_key_len,
+				KEY_FLAG_GROUP_RX_TX_DEFAULT)) {
 		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_WARNING,
 			       "failed to configure a new broadcast key");
@@ -2471,7 +2473,7 @@ int ieee802_1x_init(struct hostapd_data *hapd)
 		for (i = 0; i < 4; i++)
 			hostapd_drv_set_key(hapd->conf->iface, hapd,
 					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-					    NULL, 0);
+					    NULL, 0, KEY_FLAG_GROUP_RX_TX);
 
 		ieee802_1x_rekey(hapd, NULL);
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 5c52f0f76..7298e4928 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -136,12 +136,13 @@ static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
 	if (wpa_auth->cb->set_key == NULL)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_flag);
 }
 
 
@@ -1723,7 +1724,7 @@ void wpa_remove_ptk(struct wpa_state_machine *sm)
 	sm->PTK_valid = FALSE;
 	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
 	if (wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL,
-			     0))
+			     0, KEY_FLAG_PAIRWISE))
 		wpa_printf(MSG_DEBUG,
 			   "RSN: PTK removal from the driver failed");
 	sm->pairwise_set = FALSE;
@@ -2766,7 +2767,7 @@ int fils_set_tk(struct wpa_state_machine *sm)
 
 	wpa_printf(MSG_DEBUG, "FILS: Configure TK to the driver");
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen)) {
+			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX)) {
 		wpa_printf(MSG_DEBUG, "FILS: Failed to set TK to the driver");
 		return -1;
 	}
@@ -3391,7 +3392,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
 		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
 		int klen = wpa_cipher_key_len(sm->pairwise);
 		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-				     sm->PTK.tk, klen)) {
+				     sm->PTK.tk, klen,
+				     KEY_FLAG_PAIRWISE_RX_TX)) {
 			wpa_sta_disconnect(sm->wpa_auth, sm->addr,
 					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 			return;
@@ -3983,7 +3985,8 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
 			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
 			     broadcast_ether_addr, group->GN,
-			     group->GTK[group->GN - 1], group->GTK_len) < 0)
+			     group->GTK[group->GN - 1], group->GTK_len,
+			     KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 		ret = -1;
 
 	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
@@ -3996,7 +3999,8 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 		if (ret == 0 &&
 		    wpa_auth_set_key(wpa_auth, group->vlan_id, alg,
 				     broadcast_ether_addr, group->GN_igtk,
-				     group->IGTK[group->GN_igtk - 4], len) < 0)
+				     group->IGTK[group->GN_igtk - 4],
+				     len, KEY_FLAG_GROUP_TX_DEFAULT) < 0)
 			ret = -1;
 	}
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 0e44cbe0b..64c261964 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -260,7 +260,8 @@ struct wpa_auth_callbacks {
 			      int *vlan_id);
 	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
 	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
-		       const u8 *addr, int idx, u8 *key, size_t key_len);
+		       const u8 *addr, int idx, u8 *key, size_t key_len,
+		       enum key_flag key_flag);
 	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
 	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
 			  size_t data_len, int encrypt);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index d24feb560..462876195 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2622,12 +2622,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
-				   u8 *key, size_t key_len)
+				   u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
 	if (wpa_auth->cb->set_key == NULL)
 		return -1;
 	return wpa_auth->cb->set_key(wpa_auth->cb_ctx, vlan_id, alg, addr, idx,
-				     key, key_len);
+				     key, key_len, key_flag);
 }
 
 
@@ -2660,7 +2661,7 @@ void wpa_ft_install_ptk(struct wpa_state_machine *sm)
 	 * optimized by adding the STA entry earlier.
 	 */
 	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
-			     sm->PTK.tk, klen))
+			     sm->PTK.tk, klen, KEY_FLAG_PAIRWISE_RX_TX))
 		return;
 
 	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 951c7364b..84e21fe11 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -362,7 +362,7 @@ static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
 
 static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 				    const u8 *addr, int idx, u8 *key,
-				    size_t key_len)
+				    size_t key_len, enum key_flag key_flag)
 {
 	struct hostapd_data *hapd = ctx;
 	const char *ifname = hapd->conf->iface;
@@ -403,7 +403,7 @@ static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
-				   key, key_len);
+				   key, key_len, key_flag);
 }
 
 
diff --git a/src/common/defs.h b/src/common/defs.h
index 1cf027340..a4e002f5e 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -429,4 +429,26 @@ enum ptk0_rekey_handling {
 	PTK0_REKEY_ALLOW_NEVER
 };
 
+enum key_flag {
+	KEY_FLAG_MODIFY			= BIT(0),
+	KEY_FLAG_DEFAULT		= BIT(1),
+	KEY_FLAG_RX			= BIT(2),
+	KEY_FLAG_TX			= BIT(3),
+	KEY_FLAG_GROUP			= BIT(4),
+	KEY_FLAG_PAIRWISE		= BIT(5),
+	KEY_FLAG_PMK			= BIT(6),
+	/* Used flag combinations */
+	KEY_FLAG_RX_TX			= KEY_FLAG_RX | KEY_FLAG_TX,
+	KEY_FLAG_GROUP_RX_TX		= KEY_FLAG_GROUP | KEY_FLAG_RX_TX,
+	KEY_FLAG_GROUP_RX_TX_DEFAULT	= KEY_FLAG_GROUP_RX_TX |
+					  KEY_FLAG_DEFAULT,
+	KEY_FLAG_GROUP_RX		= KEY_FLAG_GROUP | KEY_FLAG_RX,
+	KEY_FLAG_GROUP_TX_DEFAULT	= KEY_FLAG_GROUP | KEY_FLAG_TX |
+					  KEY_FLAG_DEFAULT,
+	KEY_FLAG_PAIRWISE_RX_TX		= KEY_FLAG_PAIRWISE | KEY_FLAG_RX_TX,
+	KEY_FLAG_PAIRWISE_RX		= KEY_FLAG_PAIRWISE | KEY_FLAG_RX,
+	KEY_FLAG_PAIRWISE_RX_TX_MODIFY	= KEY_FLAG_PAIRWISE_RX_TX |
+					  KEY_FLAG_MODIFY,
+};
+
 #endif /* DEFS_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6288fe103..a89122c37 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -2335,6 +2335,47 @@ struct wpa_driver_ops {
 	 *	8-byte Rx Mic Key
 	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
 	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
+	 * @key_flag: Additional key flags:
+	 *	%KEY_FLAG_MODIFY
+	 *	  Set when an already installed key must be updated.
+	 *	  So far the only use-case is changing RX/TX status of
+	 *	  installed keys. Must not be set when deleting a key.
+	 *	%KEY_FLAG_DEFAULT
+	 *	  Set when the key is also a default key. Must not be set when
+	 *	  deleting a key.
+	 *	%KEY_FLAG_RX
+	 *	  The key is valid for RX. Must not be set when deleting a key.
+	 *	%KEY_FLAG_TX
+	 *	  The key is valid for TX. Must not be set when deleting a key.
+	 *	%KEY_FLAG_GROUP
+	 *	  The key is a broadcast or group key.
+	 *	%KEY_FLAG_PAIRWISE
+	 *	  The key is a pairwise key.
+	 *	%KEY_FLAG_PMK
+	 *	  The key is a Pairwise Master Key (PMK).
+	 *
+	 *	Valid and pre-defined combinations are:
+	 *	%KEY_FLAG_GROUP_RX_TX
+	 *	  WEP key not to be installed as default key.
+	 *	%KEY_FLAG_GROUP_RX_TX_DEFAULT
+	 *	  Default WEP or WPA-NONE key.
+	 *	%KEY_FLAG_GROUP_RX
+	 *	  GTK key valid for RX only.
+	 *	%KEY_FLAG_GROUP_TX_DEFAULT
+	 *	  GTK key valid for TX only, immediately taking over TX.
+	 *	%KEY_FLAG_PAIRWISE_RX_TX
+	 *	  Pairwise key immediately becoming the active pairwise key.
+	 *	%KEY_FLAG_PAIRWISE_RX
+	 *	  Pairwise key not yet valid for TX. (Only usable when Extended
+	 *	  Key ID is supported by the driver.)
+	 *	%KEY_FLAG_PAIRWISE_RX_TX_MODIFY
+	 *	  Enable TX for a pairwise key installed with
+	 *	  KEY_FLAG_PAIRWISE_RX.
+	 *
+	 *	Not a valid standalone key type but pre-defined to be combined
+	 *	with other key_flags:
+	 *	%KEY_FLAG_RX_TX
+	 *	  RX/TX key.
 	 *
 	 * Returns: 0 on success, -1 on failure
 	 *
@@ -2359,7 +2400,7 @@ struct wpa_driver_ops {
 	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+		       const u8 *key, size_t key_len, enum key_flag key_flag);
 
 	/**
 	 * init - Initialize driver interface
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index de25e4e4e..4d9e9011c 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -494,7 +494,8 @@ atheros_del_key(void *priv, const u8 *addr, int key_idx)
 static int
 atheros_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 		const u8 *addr, int key_idx, int set_tx, const u8 *seq,
-		size_t seq_len, const u8 *key, size_t key_len)
+		size_t seq_len, const u8 *key, size_t key_len,
+		enum key_flag key_flag)
 {
 	struct atheros_driver_data *drv = priv;
 	struct ieee80211req_key wk;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index 8667ee519..5ee6eb730 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -333,7 +333,8 @@ bsd_ctrl_iface(void *priv, int enable)
 static int
 bsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+	    size_t seq_len, const u8 *key, size_t key_len,
+	    enum key_flag key_flag)
 {
 	struct ieee80211req_key wk;
 #ifdef IEEE80211_KEY_NOREPLAY
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index dbe7fafc8..818188ada 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -400,7 +400,8 @@ static int wpa_driver_hostap_set_key(const char *ifname, void *priv,
 				     enum wpa_alg alg, const u8 *addr,
 				     int key_idx, int set_tx,
 				     const u8 *seq, size_t seq_len,
-				     const u8 *key, size_t key_len)
+				     const u8 *key, size_t key_len,
+				     enum key_flag key_flag)
 {
 	struct hostap_driver_data *drv = priv;
 	struct prism2_hostapd_param *param;
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index 5b4b9247e..3f542e8ee 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -932,7 +932,8 @@ static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
 
 static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
 				   int pairwise, int key_idx, int set_tx,
-				   const u8 *key, size_t key_len)
+				   const u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
 	NDIS_802_11_WEP *wep;
 	size_t len;
@@ -967,7 +968,8 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
 				   enum wpa_alg alg, const u8 *addr,
 				   int key_idx, int set_tx,
 				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
+				   const u8 *key, size_t key_len,
+				   enum key_flag key_flag)
 {
 	struct wpa_driver_ndis_data *drv = priv;
 	size_t len, i;
@@ -993,7 +995,7 @@ static int wpa_driver_ndis_set_key(const char *ifname, void *priv,
 
 	if (alg == WPA_ALG_WEP) {
 		return wpa_driver_ndis_add_wep(drv, pairwise, key_idx, set_tx,
-					       key, key_len);
+					       key, key_len, key_flag);
 	}
 
 	len = 12 + 6 + 6 + 8 + key_len;
@@ -1075,7 +1077,7 @@ wpa_driver_ndis_associate(void *priv,
 						bcast, i,
 						i == params->wep_tx_keyidx,
 						NULL, 0, params->wep_key[i],
-						params->wep_key_len[i]);
+						params->wep_key_len[i], 0);
 		}
 	}
 
@@ -1112,7 +1114,7 @@ wpa_driver_ndis_associate(void *priv,
 			wpa_driver_ndis_set_key(drv->ifname, drv, WPA_ALG_WEP,
 						bcast, 0, 1,
 						NULL, 0, dummy_key,
-						sizeof(dummy_key));
+						sizeof(dummy_key), 0);
 		}
 #endif /* CONFIG_WPS */
 	} else {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 967a24225..64d16d1b4 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -3015,7 +3015,8 @@ static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
 				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+				      const u8 *key, size_t key_len,
+				      enum key_flag key_flag)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ifindex;
@@ -3493,7 +3494,7 @@ retry:
 					   NULL, i,
 					   i == params->wep_tx_keyidx, NULL, 0,
 					   params->wep_key[i],
-					   params->wep_key_len[i]);
+					   params->wep_key_len[i], 0);
 		if (params->wep_tx_keyidx != i)
 			continue;
 		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
@@ -8653,11 +8654,13 @@ static int driver_nl80211_set_key(const char *ifname, void *priv,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
 	struct i802_bss *bss = priv;
 	return wpa_driver_nl80211_set_key(ifname, bss, alg, addr, key_idx,
-					  set_tx, seq, seq_len, key, key_len);
+					  set_tx, seq, seq_len, key, key_len,
+					  key_flag);
 }
 
 
diff --git a/src/drivers/driver_openbsd.c b/src/drivers/driver_openbsd.c
index c06e75c0f..a96045121 100644
--- a/src/drivers/driver_openbsd.c
+++ b/src/drivers/driver_openbsd.c
@@ -71,7 +71,8 @@ wpa_driver_openbsd_get_capa(void *priv, struct wpa_driver_capa *capa)
 static int
 wpa_driver_openbsd_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 	    const unsigned char *addr, int key_idx, int set_tx, const u8 *seq,
-	    size_t seq_len, const u8 *key, size_t key_len)
+	    size_t seq_len, const u8 *key, size_t key_len,
+	    enum key_flag key_flag)
 {
 	struct openbsd_driver_data *drv = priv;
 	struct ieee80211_keyavail keyavail;
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index 55cf61885..f8840f848 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -209,7 +209,8 @@ static int wpa_driver_privsep_set_key(const char *ifname, void *priv,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
 				      const u8 *seq, size_t seq_len,
-				      const u8 *key, size_t key_len)
+				      const u8 *key, size_t key_len,
+				      enum key_flag key_flag)
 {
 	struct wpa_driver_privsep_data *drv = priv;
 	struct privsep_cmd_set_key cmd;
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 32c297138..368443f57 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -1712,7 +1712,8 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
 				       const u8 *addr, int key_idx,
 				       int set_tx, const u8 *seq,
 				       size_t seq_len,
-				       const u8 *key, size_t key_len)
+				       const u8 *key, size_t key_len,
+				       enum key_flag key_flag)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
@@ -1829,7 +1830,8 @@ static int wpa_driver_wext_set_key_ext(void *priv, enum wpa_alg alg,
 int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 			    const u8 *addr, int key_idx,
 			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len)
+			    const u8 *key, size_t key_len,
+			    enum key_flag key_flag)
 {
 	struct wpa_driver_wext_data *drv = priv;
 	struct iwreq iwr;
@@ -1841,7 +1843,7 @@ int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 		   (unsigned long) seq_len, (unsigned long) key_len);
 
 	ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
-					  seq, seq_len, key, key_len);
+					  seq, seq_len, key, key_len, key_flag);
 	if (ret == 0)
 		return 0;
 
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index b4b5960a7..66a01ce1c 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -55,7 +55,8 @@ int wpa_driver_wext_set_mode(void *priv, int mode);
 int wpa_driver_wext_set_key(const char *ifname, void *priv, enum wpa_alg alg,
 			    const u8 *addr, int key_idx,
 			    int set_tx, const u8 *seq, size_t seq_len,
-			    const u8 *key, size_t key_len);
+			    const u8 *key, size_t key_len,
+			    enum key_flag key_flag);
 int wpa_driver_wext_scan(void *priv, struct wpa_driver_scan_params *params);
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
 
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 704c95e68..bb8973942 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -178,7 +178,7 @@ static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
 static int wpa_tdls_del_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	if (wpa_sm_set_key(sm, WPA_ALG_NONE, peer->addr,
-			   0, 0, NULL, 0, NULL, 0) < 0) {
+			   0, 0, NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to delete TPK-TK from "
 			   "the driver");
 		return -1;
@@ -227,8 +227,9 @@ static int wpa_tdls_set_key(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 
 	wpa_printf(MSG_DEBUG, "TDLS: Configure pairwise key for peer " MACSTR,
 		   MAC2STR(peer->addr));
-	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1,
-			   rsc, sizeof(rsc), peer->tpk.tk, key_len) < 0) {
+	if (wpa_sm_set_key(sm, alg, peer->addr, -1, 1, rsc, sizeof(rsc),
+			   peer->tpk.tk, key_len,
+			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_printf(MSG_WARNING, "TDLS: Failed to set TPK to the "
 			   "driver");
 		return -1;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e8931ff08..e42e55785 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -804,7 +804,8 @@ static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
 
 
 static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
-				      const struct wpa_eapol_key *key)
+				      const struct wpa_eapol_key *key,
+				      enum key_flag key_flag)
 {
 	int keylen, rsclen;
 	enum wpa_alg alg;
@@ -849,7 +850,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
 	}
 
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+			   sm->ptk.tk, keylen,
+			   KEY_FLAG_PAIRWISE | key_flag) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set PTK to the "
 			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
@@ -942,7 +944,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
 	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
 		if (wpa_sm_set_key(sm, gd->alg, NULL,
 				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
-				   _gtk, gd->gtk_len) < 0) {
+				   _gtk, gd->gtk_len,
+				   KEY_FLAG_GROUP_RX_TX_DEFAULT) < 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 				"WPA: Failed to set GTK to the driver "
 				"(Group only)");
@@ -951,7 +954,7 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
 		}
 	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
 				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
-				  _gtk, gd->gtk_len) < 0) {
+				  _gtk, gd->gtk_len, KEY_FLAG_GROUP_RX) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: Failed to set GTK to "
 			"the driver (alg=%d keylen=%d keyidx=%d)",
@@ -1105,7 +1108,7 @@ static int wpa_supplicant_install_igtk(struct wpa_sm *sm,
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr,
 			   keyidx, 0, igtk->pn, sizeof(igtk->pn),
-			   igtk->igtk, len) < 0) {
+			   igtk->igtk, len, KEY_FLAG_GROUP_RX) < 0) {
 		if (keyidx == 0x0400 || keyidx == 0x0500) {
 			/* Assume the AP has broken PMF implementation since it
 			 * seems to have swapped the KeyID bytes. The AP cannot
@@ -1560,7 +1563,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
 	sm->renew_snonce = 1;
 
 	if (key_info & WPA_KEY_INFO_INSTALL) {
-		if (wpa_supplicant_install_ptk(sm, key))
+		if (wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX_TX))
 			goto failed;
 	}
 
@@ -4587,7 +4590,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
 	wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
 			sm->ptk.tk, keylen);
 	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, null_rsc, rsclen,
-			   sm->ptk.tk, keylen) < 0) {
+			   sm->ptk.tk, keylen, KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"FILS: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
 			MACSTR ")",
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ef77475cb..b0272097b 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -31,7 +31,7 @@ struct wpa_sm_ctx {
 	int (*set_key)(void *ctx, enum wpa_alg alg,
 		       const u8 *addr, int key_idx, int set_tx,
 		       const u8 *seq, size_t seq_len,
-		       const u8 *key, size_t key_len);
+		       const u8 *key, size_t key_len, enum key_flag key_flag);
 	void * (*get_network_ctx)(void *ctx);
 	int (*get_bssid)(void *ctx, u8 *bssid);
 	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index 2b8b41fa5..8a8c545d3 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -422,8 +422,9 @@ static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
 	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
 
-	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
-			   sizeof(null_rsc), (u8 *) sm->ptk.tk, keylen) < 0) {
+	if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc, sizeof(null_rsc),
+			   (u8 *) sm->ptk.tk, keylen,
+			   KEY_FLAG_PAIRWISE_RX_TX) < 0) {
 		wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
 		return -1;
 	}
@@ -773,7 +774,8 @@ static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
 		os_memcpy(gtk + 24, tmp, 8);
 	}
 	if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
-			   gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
+			   gtk_elem + 3, rsc_len, gtk, keylen,
+			   KEY_FLAG_GROUP_RX) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
 			   "driver.");
 		return -1;
@@ -840,7 +842,8 @@ static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
 			igtk_len);
 	if (wpa_sm_set_key(sm, wpa_cipher_to_alg(sm->mgmt_group_cipher),
 			   broadcast_ether_addr, keyidx, 0,
-			   igtk_elem + 2, 6, igtk, igtk_len) < 0) {
+			   igtk_elem + 2, 6, igtk, igtk_len,
+			   KEY_FLAG_GROUP_RX) < 0) {
 		wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
 			   "driver.");
 		forced_memzero(igtk, sizeof(igtk));
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 8faaa85a3..634d19bfb 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -205,11 +205,12 @@ static inline void wpa_sm_reconnect(struct wpa_sm *sm)
 static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
 				 const u8 *addr, int key_idx, int set_tx,
 				 const u8 *seq, size_t seq_len,
-				 const u8 *key, size_t key_len)
+				 const u8 *key, size_t key_len,
+				 enum key_flag key_flag)
 {
 	WPA_ASSERT(sm->ctx->set_key);
 	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
-				seq, seq_len, key, key_len);
+				seq, seq_len, key, key_len, key_flag);
 }
 
 static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
diff --git a/tests/hwsim/test_ap_ciphers.py b/tests/hwsim/test_ap_ciphers.py
index 48903ede9..c138fe571 100644
--- a/tests/hwsim/test_ap_ciphers.py
+++ b/tests/hwsim/test_ap_ciphers.py
@@ -874,7 +874,7 @@ def test_ap_wpa2_delayed_m1_m3_zero_tk(dev, apdev):
     if "OK" not in hapd.request("RESEND_M3 " + addr):
         raise Exception("RESEND_M3 failed")
 
-    if "OK" not in hapd.request("SET_KEY 3 %s %d %d %s %s" % (addr, 0, 1, 6*"00", 16*"00")):
+    if "OK" not in hapd.request("SET_KEY 3 %s %d %d %s %s %d" % (addr, 0, 1, 6*"00", 16*"00", 44)):
         raise Exception("SET_KEY failed")
     time.sleep(0.1)
     hwsim_utils.test_connectivity(dev[0], hapd, timeout=1, broadcast=False,
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 339d8198c..65dcb90f1 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5345,15 +5345,21 @@ static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
 {
 	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
 	/* MLME-DELETEKEYS.request */
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
-	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL,
+			0, KEY_FLAG_GROUP);
 
 	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
-			0);
+			0, KEY_FLAG_PAIRWISE);
 	/* MLME-SETPROTECTION.request(None) */
 	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
 				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
@@ -9351,13 +9357,15 @@ static int wpas_ctrl_reset_pn(struct wpa_supplicant *wpa_s)
 	 * in the driver. */
 	if (wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			    wpa_s->last_tk_key_idx, 1, zero, 6,
-			    zero, wpa_s->last_tk_len) < 0)
+			    zero, wpa_s->last_tk_len,
+			    KEY_FLAG_PAIRWISE_RX_TX) < 0)
 		return -1;
 
 	/* Set the previously configured key to reset its TSC/RSC */
 	return wpa_drv_set_key(wpa_s, wpa_s->last_tk_alg, wpa_s->last_tk_addr,
 			       wpa_s->last_tk_key_idx, 1, zero, 6,
-			       wpa_s->last_tk, wpa_s->last_tk_len);
+			       wpa_s->last_tk, wpa_s->last_tk_len,
+			       KEY_FLAG_PAIRWISE_RX_TX);
 }
 
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index f8d63a07b..11146d34a 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -147,7 +147,8 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
 	if (alg != WPA_ALG_NONE) {
 		if (key_idx >= 0 && key_idx <= 6)
@@ -158,7 +159,8 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
 	if (wpa_s->driver->set_key) {
 		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
 					      alg, addr, key_idx, set_tx,
-					      seq, seq_len, key, key_len);
+					      seq, seq_len, key, key_len,
+					      key_flag);
 	}
 	return -1;
 }
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 93a683551..68d063bbc 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -140,7 +140,7 @@ static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
 static int supp_set_key(void *ctx, enum wpa_alg alg,
 			const u8 *addr, int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
-			const u8 *key, size_t key_len)
+			const u8 *key, size_t key_len, enum key_flag key_flag)
 {
 	struct ibss_rsn_peer *peer = ctx;
 
@@ -167,7 +167,7 @@ static int supp_set_key(void *ctx, enum wpa_alg alg,
 	if (is_broadcast_ether_addr(addr))
 		addr = peer->addr;
 	return wpa_drv_set_key(peer->ibss_rsn->wpa_s, alg, addr, key_idx,
-			       set_tx, seq, seq_len, key, key_len);
+			       set_tx, seq, seq_len, key, key_len, key_flag);
 }
 
 
@@ -303,7 +303,8 @@ static int auth_send_eapol(void *ctx, const u8 *addr, const u8 *data,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_flag key_flag)
 {
 	struct ibss_rsn *ibss_rsn = ctx;
 	u8 seq[6];
@@ -342,7 +343,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	}
 
 	return wpa_drv_set_key(ibss_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -855,7 +856,7 @@ static void ibss_rsn_handle_auth_1_of_2(struct ibss_rsn *ibss_rsn,
 		wpa_printf(MSG_DEBUG, "RSN: Clear pairwise key for peer "
 			   MACSTR, MAC2STR(addr));
 		wpa_drv_set_key(ibss_rsn->wpa_s, WPA_ALG_NONE, addr, 0, 0,
-				NULL, 0, NULL, 0);
+				NULL, 0, NULL, 0, KEY_FLAG_PAIRWISE);
 	}
 
 	if (peer &&
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index c7c85929f..31dd1d3c6 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -877,7 +877,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 		wpa_hexdump_key(MSG_DEBUG, "mesh: MTK", sta->mtk, sta->mtk_len);
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->pairwise_cipher),
 				sta->addr, 0, 0, seq, sizeof(seq),
-				sta->mtk, sta->mtk_len);
+				sta->mtk, sta->mtk_len,
+				KEY_FLAG_PAIRWISE_RX_TX);
 
 		wpa_hexdump_key(MSG_DEBUG, "mesh: RX MGTK Key RSC",
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc));
@@ -886,7 +887,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 		wpa_drv_set_key(wpa_s, wpa_cipher_to_alg(conf->group_cipher),
 				sta->addr, sta->mgtk_key_id, 0,
 				sta->mgtk_rsc, sizeof(sta->mgtk_rsc),
-				sta->mgtk, sta->mgtk_len);
+				sta->mgtk, sta->mgtk_len,
+				KEY_FLAG_GROUP_RX);
 
 		if (sta->igtk_len) {
 			wpa_hexdump_key(MSG_DEBUG, "mesh: RX IGTK Key RSC",
@@ -898,7 +900,8 @@ static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
 				wpa_cipher_to_alg(conf->mgmt_group_cipher),
 				sta->addr, sta->igtk_key_id, 0,
 				sta->igtk_rsc, sizeof(sta->igtk_rsc),
-				sta->igtk, sta->igtk_len);
+				sta->igtk, sta->igtk_len,
+				KEY_FLAG_GROUP_RX);
 		}
 	}
 
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index e730b6336..f19bfbfc6 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -100,7 +100,8 @@ static const u8 *auth_get_psk(void *ctx, const u8 *addr,
 
 
 static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
-			const u8 *addr, int idx, u8 *key, size_t key_len)
+			const u8 *addr, int idx, u8 *key, size_t key_len,
+			enum key_flag key_flag)
 {
 	struct mesh_rsn *mesh_rsn = ctx;
 	u8 seq[6];
@@ -118,7 +119,7 @@ static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
 	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
 
 	return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
-			       1, seq, 6, key, key_len);
+			       1, seq, 6, key, key_len, key_flag);
 }
 
 
@@ -196,7 +197,8 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
 		wpa_drv_set_key(rsn->wpa_s,
 				wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
 				rsn->igtk_key_id, 1,
-				seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
+				seq, sizeof(seq), rsn->igtk, rsn->igtk_len,
+				KEY_FLAG_GROUP_TX_DEFAULT);
 	}
 
 	/* group privacy / data frames */
@@ -204,7 +206,7 @@ static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
 			rsn->mgtk, rsn->mgtk_len);
 	wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
 			rsn->mgtk_key_id, 1, seq, sizeof(seq),
-			rsn->mgtk, rsn->mgtk_len);
+			rsn->mgtk, rsn->mgtk_len, KEY_FLAG_GROUP_TX_DEFAULT);
 
 	return 0;
 }
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e6460fa4a..4f0861c99 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -142,7 +142,10 @@ int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 		set = 1;
 		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
 				i, i == ssid->wep_tx_keyidx, NULL, 0,
-				ssid->wep_key[i], ssid->wep_key_len[i]);
+				ssid->wep_key[i], ssid->wep_key_len[i],
+				i == ssid->wep_tx_keyidx ?
+				     KEY_FLAG_GROUP_RX_TX_DEFAULT :
+				     KEY_FLAG_GROUP_RX_TX);
 	}
 
 	return set;
@@ -200,7 +203,8 @@ int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
 	/* TODO: should actually remember the previously used seq#, both for TX
 	 * and RX from each STA.. */
 
-	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen,
+			      KEY_FLAG_GROUP_RX_TX_DEFAULT);
 	os_memset(key, 0, sizeof(key));
 	return ret;
 }
@@ -734,12 +738,12 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
 		if (wpa_s->keys_cleared & BIT(i))
 			continue;
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, i, 0, NULL, 0,
-				NULL, 0);
+				NULL, 0, KEY_FLAG_GROUP);
 	}
 	if (!(wpa_s->keys_cleared & BIT(0)) && addr &&
 	    !is_zero_ether_addr(addr)) {
 		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
-				0);
+				0, KEY_FLAG_PAIRWISE);
 		/* MLME-SETPROTECTION.request(None) */
 		wpa_drv_mlme_setprotection(
 			wpa_s, addr,
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 1f78e2d93..5bf2c2e4f 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -242,7 +242,9 @@ static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
 	}
 	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
 			       unicast ? wpa_s->bssid : NULL,
-			       keyidx, unicast, NULL, 0, key, keylen);
+			       keyidx, unicast, NULL, 0, key, keylen,
+			       unicast ? KEY_FLAG_PAIRWISE_RX_TX :
+					 KEY_FLAG_GROUP_RX_TX_DEFAULT);
 }
 
 
@@ -341,7 +343,7 @@ static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol,
 			"handshake", pmk, pmk_len);
 
 	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
-			    pmk_len)) {
+			    pmk_len, KEY_FLAG_PMK)) {
 		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
 	}
 
@@ -498,7 +500,8 @@ static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
 static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 				  const u8 *addr, int key_idx, int set_tx,
 				  const u8 *seq, size_t seq_len,
-				  const u8 *key, size_t key_len)
+				  const u8 *key, size_t key_len,
+				  enum key_flag key_flag)
 {
 	struct wpa_supplicant *wpa_s = _wpa_s;
 	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
@@ -523,7 +526,7 @@ static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
-			       key, key_len);
+			       key, key_len, key_flag);
 }
 
 
@@ -1176,7 +1179,7 @@ static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
 	if (wpa_s->conf->key_mgmt_offload &&
 	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
 		return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
-				       NULL, 0, pmk, pmk_len);
+				       NULL, 0, pmk, pmk_len, KEY_FLAG_PMK);
 	else
 		return 0;
 }
-- 
2.24.1


_______________________________________________
Hostap mailing list
Hostap@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/hostap



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux