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");
}
+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,
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);
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;
}
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;
}
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 "
}
#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;
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;
}
#ifdef CONFIG_P2P
os_memset(sm->p2p_ip_addr, 0, sizeof(sm->p2p_ip_addr));
#endif /* CONFIG_P2P */
+
+ sm->keyidx_active = 0;
}
/* 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);
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;
}
}
+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;
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 */
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);