[PATCH 22/29] EPPKE: Skip MIC Element inclusion in auth_data for M3 Auth frame

Sai Pratyusha Magam smagam at qti.qualcomm.com
Thu Dec 11 05:14:36 PST 2025


From: Kavita Kavita <kavita.kavita at oss.qualcomm.com>

According to the IEEE Std802.11-2024 specification (Table 9‑70),
the MIC (Message Integrity Code) element must be the last element
in the authentication frame body, and it is present only in certain
authentication frames as defined in Table 9-71. For the EPPKE
(Enhanced Privacy Protection Key Exchange Authentication protocol
as specified in section 12.16.9 of IEEE P802.11bi/D2.0, the MIC is
mandatory as specified in Table 9‑71.

In the SME-supplicant case, userspace constructs the authentication
frame body and appends the MIC element after computing the MIC over
that body. And passes it to kernel via %NL80211_ATTR_AUTH_DATA
with %NL80211_CMD_AUTHENTICATE.

In MLO connections, the userspace constructs most of the
authentication frame body, excluding the MLE, which kernel
appends later. If userspace computes the MIC before this, it produces
an incorrect value over an incomplete frame body.
Moreover, the MIC element must be the last element in the frame to
comply with the specification. Since kernel appends the MLE
after the MIC calculated in the userspace, the ordering is violated.

Add support for passing the Key Confirmation Key (KCK) to the kernel
via %NL80211_CMD_AUTHENTICATE using %NL80211_ATTR_KEY_KCK, allowing
kernel to generate the MIC as required.

Signed-off-by: Kavita Kavita <kavita.kavita at oss.qualcomm.com>
Signed-off-by: Ainy Kumari <ainy.kumari at oss.qualcomm.com>
---
 src/drivers/driver.h         | 2 ++
 src/drivers/driver_nl80211.c | 8 ++++++++
 src/pasn/pasn_initiator.c    | 4 ++++
 wpa_supplicant/sme.c         | 7 +++++++
 4 files changed, 21 insertions(+)

diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 126ec56a1..2bbe7f621 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -766,6 +766,8 @@ struct wpa_driver_auth_params {
 	const u8 *wep_key[4];
 	size_t wep_key_len[4];
 	int wep_tx_keyidx;
+	const u8 *kck[WPA_KCK_MAX_LEN];
+	size_t kck_len;
 	int local_state_change;
 	u32 hash_alg;
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index daf22320a..a4f24fea5 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4419,6 +4419,14 @@ retry:
 		wpa_printf(MSG_DEBUG, "  * Hash Algo %d", hash_alg);
 		if (nla_put_u32(msg, NL80211_ATTR_HASH_ALG, hash_alg))
 			goto fail;
+
+		if (params->kck && params->kck_len > 0) {
+			wpa_hexdump(MSG_DEBUG, "  * kck", params->kck,
+				    params->kck_len);
+			if (nla_put(msg, NL80211_ATTR_KEY_KCK,
+				    params->kck_len, params->kck))
+				goto fail;
+		}
 	}
 #endif /* CONFIG_ENC_ASSOC */
 	type = get_nl_auth_type(params->auth_alg);
diff --git a/src/pasn/pasn_initiator.c b/src/pasn/pasn_initiator.c
index 814014051..32daf9c05 100644
--- a/src/pasn/pasn_initiator.c
+++ b/src/pasn/pasn_initiator.c
@@ -741,6 +741,9 @@ struct wpabuf *wpas_pasn_build_auth_3(struct pasn_data *pasn,
 
 	wpa_pasn_add_extra_ies(buf, pasn->extra_ies, pasn->extra_ies_len);
 
+	if (pasn->auth_alg == WLAN_AUTH_EPPKE)
+		goto skip_mic;
+
 	/* Add the MIC */
 	mic_len = pasn_mic_len(pasn->akmp, pasn->cipher, pasn->pmk_len);
 	wpabuf_put_u8(buf, WLAN_EID_MIC);
@@ -769,6 +772,7 @@ struct wpabuf *wpas_pasn_build_auth_3(struct pasn_data *pasn,
 
 	os_memcpy(ptr, mic, mic_len);
 
+skip_mic:
 	pasn->trans_seq++;
 
 	wpa_printf(MSG_DEBUG, "PASN: frame 3: Success");
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 478ce5b60..b1ce116af 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -1174,6 +1174,13 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 			params.hash_alg = wpa_s->pasn.hash_alg;
 		} else {
 			resp = wpas_pasn_build_auth_3(&wpa_s->pasn, 0);
+
+			struct wpa_ptk *ptk = pasn_get_ptk(&wpa_s->pasn);
+
+			if (ptk && ptk->kck && ptk->kck_len > 0) {
+				os_memcpy(params.kck, ptk->kck, ptk->kck_len);
+				params.kck_len = ptk->kck_len;
+			}
 		}
 		params.auth_data = wpabuf_head(resp);
 		params.auth_data_len = wpabuf_len(resp);
-- 
2.34.1




More information about the Hostap mailing list