STA: Support Extended Key ID

Support Extended Key ID in wpa_supplicant according to
IEEE Std 802.11-2016 for infrastructure (AP) associations.

Extended Key ID allows to rekey pairwise keys without the otherwise
unavoidable MPDU losses on a busy link. The standard is fully backward
compatible, allowing STAs to also connect to APs not supporting it.

Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
This commit is contained in:
Alexander Wetzel 2020-03-20 20:04:32 +01:00 committed by Jouni Malinen
parent 862aac1fcd
commit b17b7a8e53
17 changed files with 222 additions and 18 deletions

View file

@ -183,7 +183,7 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
int key_info, ver;
u8 bssid[ETH_ALEN], *rbuf, *key_mic, *mic;
if (pairwise && sm->wpa_deny_ptk0_rekey &&
if (pairwise && sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
wpa_sm_get_state(sm) == WPA_COMPLETED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: PTK0 rekey not allowed, reconnecting");
@ -608,6 +608,51 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
}
static int wpa_handle_ext_key_id(struct wpa_sm *sm,
struct wpa_eapol_ie_parse *kde)
{
if (sm->ext_key_id) {
u16 key_id;
if (!kde->key_id) {
wpa_msg(sm->ctx->msg_ctx,
sm->use_ext_key_id ? MSG_INFO : MSG_DEBUG,
"RSN: No Key ID in Extended Key ID handshake");
sm->keyidx_active = 0;
return sm->use_ext_key_id ? -1 : 0;
}
key_id = kde->key_id[0] & 0x03;
if (key_id > 1) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Invalid Extended Key ID: %d", key_id);
return -1;
}
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Using Extended Key ID %d", key_id);
sm->keyidx_active = key_id;
sm->use_ext_key_id = 1;
} else {
if (kde->key_id && (kde->key_id[0] & 0x03)) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: Non-zero Extended Key ID Key ID in PTK0 handshake");
return -1;
}
if (kde->key_id) {
/* This is not supposed to be included here, but ignore
* the case of matching Key ID 0 just in case. */
wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
"RSN: Extended Key ID Key ID 0 in PTK0 handshake");
}
sm->keyidx_active = 0;
sm->use_ext_key_id = 0;
}
return 0;
}
static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
const unsigned char *src_addr,
const struct wpa_eapol_key *key,
@ -626,7 +671,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
return;
}
if (sm->wpa_deny_ptk0_rekey && wpa_sm_get_state(sm) == WPA_COMPLETED) {
if (sm->wpa_deny_ptk0_rekey && !sm->use_ext_key_id &&
wpa_sm_get_state(sm) == WPA_COMPLETED) {
wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"WPA: PTK0 rekey not allowed, reconnecting");
wpa_sm_reconnect(sm);
@ -859,13 +905,14 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
sm->ptk.tk, keylen,
if (wpa_sm_set_key(sm, alg, sm->bssid, sm->keyidx_active, 1, key_rsc,
rsclen, 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 ")",
alg, keylen, MAC2STR(sm->bssid));
"WPA: Failed to set PTK to the driver (alg=%d keylen=%d bssid="
MACSTR " idx=%d key_flag=0x%x)",
alg, keylen, MAC2STR(sm->bssid),
sm->keyidx_active, key_flag);
return -1;
}
@ -879,7 +926,23 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
sm, NULL);
}
return 0;
}
static int wpa_supplicant_activate_ptk(struct wpa_sm *sm)
{
wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
"WPA: Activate PTK (idx=%d bssid=" MACSTR ")",
sm->keyidx_active, MAC2STR(sm->bssid));
if (wpa_sm_set_key(sm, 0, sm->bssid, sm->keyidx_active, 0, NULL, 0,
NULL, 0, KEY_FLAG_PAIRWISE_RX_TX_MODIFY) < 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: Failed to activate PTK for TX (idx=%d bssid="
MACSTR ")", sm->keyidx_active, MAC2STR(sm->bssid));
return -1;
}
return 0;
}
@ -1582,6 +1645,9 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
goto failed;
if (wpa_handle_ext_key_id(sm, &ie))
goto failed;
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
"WPA: ANonce from message 1 of 4-Way Handshake "
@ -1627,6 +1693,10 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
}
#endif /* CONFIG_OCV */
if (sm->use_ext_key_id &&
wpa_supplicant_install_ptk(sm, key, KEY_FLAG_RX))
goto failed;
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
&sm->ptk) < 0) {
goto failed;
@ -1638,7 +1708,14 @@ 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, KEY_FLAG_RX_TX))
int res;
if (sm->use_ext_key_id)
res = wpa_supplicant_activate_ptk(sm);
else
res = wpa_supplicant_install_ptk(sm, key,
KEY_FLAG_RX_TX);
if (res)
goto failed;
}
@ -2880,6 +2957,8 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
sm->keyidx_active = 0;
}
@ -2911,6 +2990,7 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
/* Keys are not needed in the WPA state machine anymore */
wpa_sm_drop_sa(sm);
sm->keyidx_active = 0;
sm->msg_3_of_4_ok = 0;
os_memset(sm->bssid, 0, ETH_ALEN);
@ -3164,6 +3244,12 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_DENY_PTK0_REKEY:
sm->wpa_deny_ptk0_rekey = value;
break;
case WPA_PARAM_EXT_KEY_ID:
sm->ext_key_id = value;
break;
case WPA_PARAM_USE_EXT_KEY_ID:
sm->use_ext_key_id = value;
break;
default:
break;
}
@ -3238,6 +3324,18 @@ int wpa_sm_pmf_enabled(struct wpa_sm *sm)
}
int wpa_sm_ext_key_id(struct wpa_sm *sm)
{
return sm ? sm->ext_key_id : 0;
}
int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
{
return sm ? sm->use_ext_key_id : 0;
}
int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
struct wpa_ie_data rsn;
@ -4253,6 +4351,8 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
if (sm->ext_key_id)
capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
wpabuf_put_le16(buf, capab);
/* PMKID Count */
@ -4680,6 +4780,7 @@ int fils_process_assoc_resp(struct wpa_sm *sm, const u8 *resp, size_t len)
keylen, (long unsigned int) sm->ptk.tk_len);
goto fail;
}
rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
wpa_hexdump_key(MSG_DEBUG, "FILS: Set TK to driver",
sm->ptk.tk, keylen);

View file

@ -102,6 +102,8 @@ enum wpa_sm_conf_params {
WPA_PARAM_OCV,
WPA_PARAM_SAE_PWE,
WPA_PARAM_DENY_PTK0_REKEY,
WPA_PARAM_EXT_KEY_ID,
WPA_PARAM_USE_EXT_KEY_ID,
};
struct rsn_supp_config {
@ -154,6 +156,8 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int wpa_sm_pmf_enabled(struct wpa_sm *sm);
int wpa_sm_ext_key_id(struct wpa_sm *sm);
int wpa_sm_ext_key_id_active(struct wpa_sm *sm);
int wpa_sm_ocv_enabled(struct wpa_sm *sm);
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
@ -300,6 +304,16 @@ static inline int wpa_sm_pmf_enabled(struct wpa_sm *sm)
return 0;
}
static inline int wpa_sm_ext_key_id(struct wpa_sm *sm)
{
return 0;
}
static inline int wpa_sm_ext_key_id_active(struct wpa_sm *sm)
{
return 0;
}
static inline int wpa_sm_ocv_enabled(struct wpa_sm *sm)
{
return 0;

View file

@ -265,6 +265,8 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
if (sm->ext_key_id)
capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;

View file

@ -68,6 +68,10 @@ struct wpa_sm {
int wpa_rsc_relaxation;
int owe_ptk_workaround;
int beacon_prot;
int ext_key_id; /* whether Extended Key ID is enabled */
int use_ext_key_id; /* whether Extended Key ID has been detected
* to be used */
int keyidx_active; /* Key ID for the active TK */
u8 own_addr[ETH_ALEN];
const char *ifname;

View file

@ -221,6 +221,8 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
if (sm->ext_key_id)
capab |= WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST;
WPA_PUT_LE16(pos, capab);
pos += 2;