From be7d95c1a1e72f1f05f70827a6e95de927c4171e Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 6 Jul 2026 15:33:11 +0300 Subject: [PATCH 1/3] Require network_ctx and AKMP match for accepting PMKSA entry When wpa_supplicant was processing EAPOL-Key msg 1/4 with a PMKID indicated by the AP/Authenticator, a PMKSA for the same AA was accepted without enforcing matching network_ctx (i.e., same network configuration block) and AKMP. This could allow misbehaving APs to make wpa_supplicant use an unacceptable PMKSA entry that was generated for a different network for AKMP under certain conditions. This could result in showing a connection to an incorrect network when an attacker has credentials to one network in wpa_supplicant configuration, but not to another network. Fix this by accepting the PMKID to set the PMKSA for an association only if the PMKSA with the same PMKID is for the same network and was generated using the same AKMP. Signed-off-by: Jouni Malinen --- .../wpa_supplicant/src/pasn/pasn_initiator.c | 8 ++++---- .../wpa_supplicant/src/rsn_supp/pmksa_cache.c | 14 ++++++++------ .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 6 +++--- components/wpa_supplicant/src/rsn_supp/wpa.c | 7 ++++--- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/components/wpa_supplicant/src/pasn/pasn_initiator.c b/components/wpa_supplicant/src/pasn/pasn_initiator.c index 17c3aa01939..b23b4c69d4e 100644 --- a/components/wpa_supplicant/src/pasn/pasn_initiator.c +++ b/components/wpa_supplicant/src/pasn/pasn_initiator.c @@ -54,7 +54,7 @@ void pasn_initiator_pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *entry; - entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL); + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0); if (!entry) return; @@ -68,7 +68,7 @@ int pasn_initiator_pmksa_cache_get(struct rsn_pmksa_cache *pmksa, { struct rsn_pmksa_cache_entry *entry; - entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL); + entry = pmksa_cache_get(pmksa, bssid, NULL, NULL, NULL, 0); if (entry) { os_memcpy(pmkid, entry->pmkid, PMKID_LEN); os_memcpy(pmk, entry->pmk, entry->pmk_len); @@ -631,7 +631,7 @@ static struct wpabuf * wpas_pasn_build_auth_1(struct pasn_data *pasn, struct rsn_pmksa_cache_entry *pmksa; pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, pasn->own_addr, - NULL, NULL); + NULL, NULL, pasn->akmp); if (pmksa && pasn->custom_pmkid_valid) pmkid = pasn->custom_pmkid; else if (pmksa) @@ -905,7 +905,7 @@ static int wpas_pasn_set_pmk(struct pasn_data *pasn, } pmksa = pmksa_cache_get(pasn->pmksa, pasn->peer_addr, pasn->own_addr, - pmkid, NULL); + pmkid, NULL, pasn->akmp); if (pmksa) { wpa_printf(MSG_DEBUG, "PASN: Using PMKSA"); diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index 584e8a7a8ff..89c99a0c62b 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -340,7 +340,7 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) */ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, const u8 *pmkid, - const void *network_ctx) + const void *network_ctx, int akmp) { if(!pmksa) return NULL; @@ -351,6 +351,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && (pmkid == NULL || os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && + (!akmp || akmp == entry->akmp) && (network_ctx == NULL || network_ctx == entry->network_ctx)) return entry; entry = entry->next; @@ -394,7 +395,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa, */ struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, - const u8 *aa) + const u8 *aa, int akmp) { if (!pmksa) return NULL; @@ -404,7 +405,8 @@ pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx, if (network_ctx == NULL) return NULL; while (entry) { - if (entry->network_ctx == network_ctx) { + if (entry->network_ctx == network_ctx && + (!akmp || akmp == entry->akmp)) { entry = pmksa_cache_clone_entry(pmksa, entry, aa); if (entry) { wpa_printf(MSG_DEBUG, "RSN: added " @@ -470,14 +472,14 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, sm->cur_pmksa = NULL; if (pmkid) sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr, pmkid, - network_ctx); + network_ctx, sm->key_mgmt); if (sm->cur_pmksa == NULL && bssid) sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr, NULL, - network_ctx); + network_ctx, sm->key_mgmt); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, network_ctx, - bssid); + bssid, sm->key_mgmt); if (sm->cur_pmksa) { wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID", sm->cur_pmksa->pmkid, PMKID_LEN); diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h index b5cc5aabe6f..5beea76d809 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h @@ -55,7 +55,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa); struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, const u8 *pmkid, - const void *network_ctx); + const void *network_ctx, int akmp); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, @@ -71,7 +71,7 @@ int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid, int try_opportunistic); struct rsn_pmksa_cache_entry * pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, - void *network_ctx, const u8 *aa); + void *network_ctx, const u8 *aa, int akmp); void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx, const u8 *pmk, size_t pmk_len); void pmksa_cache_remove(struct rsn_pmksa_cache *pmksa, @@ -93,7 +93,7 @@ static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) static inline struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, - const u8 *pmkid, const void *network_ctx) + const u8 *pmkid, const void *network_ctx, int akmp) { return NULL; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index de26028db6b..bda26a5747d 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -405,7 +405,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * event before receiving this 1/4 message, so try to find a * matching PMKSA cache entry here. */ sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, - pmkid, NULL); + pmkid, sm->network_ctx, sm->key_mgmt); if (sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from PMKSA cache"); @@ -474,7 +474,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, sm->network_ctx, sm->key_mgmt); } if (!sm->cur_pmksa && pmkid && - pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, pmkid, NULL)) + pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, pmkid, + sm->network_ctx, sm->key_mgmt)) { wpa_printf( MSG_DEBUG, "RSN: the new PMK matches with the " @@ -2687,7 +2688,7 @@ int wpa_set_bss(uint8_t *macddr, uint8_t *bssid, uint8_t pairwise_cipher, uint8_ struct rsn_pmksa_cache_entry *pmksa = NULL; if (use_pmk_cache) { pmksa = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, sm->own_addr, - NULL, NULL); + NULL, NULL, 0); if (pmksa && (pmksa->akmp != sm->key_mgmt)) { use_pmk_cache = false; } From babdd168c1a599cd2a271c2a5392002fd9c002e0 Mon Sep 17 00:00:00 2001 From: Jimi Chen Date: Thu, 21 May 2026 06:56:54 +0000 Subject: [PATCH 2/3] SAE: Fix crash due to NULL pointer dereference in H2E parsing In H2E (Hash-to-Element) mode, sae_parse_commit() parses the optional Anti-Clogging Token Container by calling sae_parse_token_container(). However, callers of sae_parse_commit() that do not require retrieving the anti-clogging token (such as PASN initiator/responder and SME auth) pass NULL for the token and token_len output arguments. If the peer sends a Commit frame containing a valid Anti-Clogging Token Container element, sae_parse_token_container() unconditionally sets *token and *token_len, resulting in a NULL pointer dereference (SIGSEGV) and crashing wpa_supplicant. Fix this by adding NULL checks before writing to token and token_len. Update the debug log to print the token directly using 'pos'. Fixes: 5e32fb0170f4 ("SAE: Use Anti-Clogging Token Container element with H2E") Signed-off-by: Amarnath Hullur Subramanyam --- components/wpa_supplicant/src/common/sae.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/wpa_supplicant/src/common/sae.c b/components/wpa_supplicant/src/common/sae.c index 1d11ecfd658..e1295a86ac1 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -1827,10 +1827,12 @@ static void sae_parse_token_container(struct sae_data *sae, pos, end - pos); if (!sae_is_token_container_elem(pos, end)) return; - *token = pos + 3; - *token_len = pos[1] - 1; + if (token) + *token = pos + 3; + if (token_len) + *token_len = pos[1] - 1; wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token (in container)", - *token, *token_len); + pos + 3, pos[1] - 1); } From 654d8a3f420db36074ef1581ba0ec3d8d8cf9ddc Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Wed, 29 Jul 2026 09:07:30 +0530 Subject: [PATCH 3/3] TLS: Avoid discarded-qualifiers Just a build issue fix depending on GCC5+ configuration, fixes: assignment discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] return discards 'const' qualifier from pointer target type [-Werror=discarded-qualifiers] Signed-off-by: Richard Allen --- components/wpa_supplicant/src/tls/tlsv1_client.c | 2 +- components/wpa_supplicant/src/tls/x509v3.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/wpa_supplicant/src/tls/tlsv1_client.c b/components/wpa_supplicant/src/tls/tlsv1_client.c index 431044c57be..0444310215e 100644 --- a/components/wpa_supplicant/src/tls/tlsv1_client.c +++ b/components/wpa_supplicant/src/tls/tlsv1_client.c @@ -614,7 +614,7 @@ int tlsv1_client_prf(struct tlsv1_client *conn, const char *label, int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf, size_t buflen) { - char *cipher; + const char *cipher; switch (conn->rl.cipher_suite) { case TLS_RSA_WITH_RC4_128_MD5: diff --git a/components/wpa_supplicant/src/tls/x509v3.c b/components/wpa_supplicant/src/tls/x509v3.c index 1bbd80ade8d..5695006104a 100644 --- a/components/wpa_supplicant/src/tls/x509v3.c +++ b/components/wpa_supplicant/src/tls/x509v3.c @@ -459,7 +459,7 @@ int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name, } -static char * x509_name_attr_str(enum x509_name_attr_type type) +static const char * x509_name_attr_str(enum x509_name_attr_type type) { switch (type) { case X509_NAME_ATTR_NOT_USED: