From 03b3e0217c74e9ab0237b06e7b3d5f7486652c23 Mon Sep 17 00:00:00 2001 From: Aditi Date: Thu, 10 Sep 2026 11:27:53 +0530 Subject: [PATCH 1/4] feat(wpa_supplicant): Match SPA when searching PMKSA cache Store the supplicant address (SPA) in PMKSA cache entries and match it when looking up the PMKSA cache. (partially picked from commit 18cbdbf2b1998c374b7ef0c00eec4bf708ff6056) --- .../wpa_supplicant/src/rsn_supp/pmksa_cache.c | 16 ++++++++++------ .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 8 +++++--- components/wpa_supplicant/src/rsn_supp/wpa.c | 9 +++++---- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index 87f8b6871da..f54ce3fa12b 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -136,6 +136,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len, entry->reauth_time = now.sec + dot11RSNAConfigPMKLifetime / 100 * dot11RSNAConfigPMKReauthThreshold; entry->akmp = akmp; os_memcpy(entry->aa, aa, ETH_ALEN); + os_memcpy(entry->spa, spa, ETH_ALEN); entry->network_ctx = network_ctx; return pmksa_cache_add_entry(pmksa, entry); @@ -306,17 +307,20 @@ void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa) * pmksa_cache_get - Fetch a PMKSA cache entry * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init() * @aa: Authenticator address or %NULL to match any + * @spa: Supplicant address or %NULL to skip SPA matching (not recommended) * @pmkid: PMKID or %NULL to match any * @network_ctx: Network context or %NULL to match any * Returns: Pointer to PMKSA cache entry or %NULL if no match was found */ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa, - const u8 *aa, const u8 *pmkid, + const u8 *aa, const u8 *spa, const u8 *pmkid, const void *network_ctx) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; while (entry) { if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) && + (spa == NULL || + os_memcmp(entry->spa, spa, ETH_ALEN) == 0) && (pmkid == NULL || os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) && (network_ctx == NULL || network_ctx == entry->network_ctx)) @@ -435,10 +439,10 @@ 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, pmkid, + sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, sm->own_addr, pmkid, network_ctx); if (sm->cur_pmksa == NULL && bssid) - sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL, + sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, sm->own_addr, NULL, network_ctx); if (sm->cur_pmksa == NULL && try_opportunistic && bssid) sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, @@ -471,7 +475,7 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) struct rsn_pmksa_cache_entry *entry; struct os_reltime now; ret = os_snprintf(pos, buf + len - pos, - "Index / AA / PMKID / expiration (in seconds) / " + "Index / AA / SPA / PMKID / expiration (in seconds) / " "opportunistic\n"); if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; @@ -481,8 +485,8 @@ int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len) os_get_reltime(&now); while (entry) { i++; - ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ", - i, MAC2STR(entry->aa)); + ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " " MACSTR " ", + i, MAC2STR(entry->aa), MAC2STR(entry->spa)); if (os_snprintf_error(buf + len - pos, ret)) return pos - buf; pos += ret; diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h index 2bdf3d4d156..8954f97f4c0 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.h @@ -20,6 +20,8 @@ struct rsn_pmksa_cache_entry { os_time_t expiration; int akmp; /* WPA_KEY_MGMT_* */ u8 aa[ETH_ALEN]; + /** Supplicant MAC (SPA) this PMKSA was created for; used when matching cache */ + u8 spa[ETH_ALEN]; os_time_t reauth_time; @@ -52,7 +54,7 @@ pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx, struct wpa_sm *sm); 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 *pmkid, + const u8 *aa, const u8 *spa, const u8 *pmkid, const void *network_ctx); int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len); struct rsn_pmksa_cache_entry * @@ -88,8 +90,8 @@ 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 *pmkid, - const void *network_ctx) +pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa, + const u8 *pmkid, const void *network_ctx) { return NULL; } diff --git a/components/wpa_supplicant/src/rsn_supp/wpa.c b/components/wpa_supplicant/src/rsn_supp/wpa.c index f11bdfeeb2c..79b63fa37e4 100644 --- a/components/wpa_supplicant/src/rsn_supp/wpa.c +++ b/components/wpa_supplicant/src/rsn_supp/wpa.c @@ -404,8 +404,8 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm, * not have enough time to get the association information * 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, pmkid, - NULL); + sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, + pmkid, NULL); if (sm->cur_pmksa) { wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from PMKSA cache"); @@ -454,7 +454,7 @@ 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, pmkid, NULL)) + pmksa_cache_get(sm->pmksa, src_addr, sm->own_addr, pmkid, NULL)) { wpa_printf( MSG_DEBUG, "RSN: the new PMK matches with the " @@ -2377,7 +2377,8 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, struct rsn_pmksa_cache_entry *pmksa = NULL; if (use_pmk_cache) { - pmksa = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, NULL, NULL); + pmksa = pmksa_cache_get(sm->pmksa, (const u8 *)bssid, sm->own_addr, + NULL, NULL); if (pmksa && (pmksa->akmp != sm->key_mgmt)) { use_pmk_cache = false; } From 9c825298fc8ab180a92280ef1bb2f7e089b07918 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Mon, 6 Jul 2026 15:33:11 +0300 Subject: [PATCH 2/4] 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/rsn_supp/pmksa_cache.c | 14 ++++++++------ .../wpa_supplicant/src/rsn_supp/pmksa_cache.h | 6 +++--- components/wpa_supplicant/src/rsn_supp/wpa.c | 7 ++++--- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c index f54ce3fa12b..71da36830ed 100644 --- a/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c +++ b/components/wpa_supplicant/src/rsn_supp/pmksa_cache.c @@ -314,7 +314,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) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; while (entry) { @@ -323,6 +323,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; @@ -366,7 +367,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) { struct rsn_pmksa_cache_entry *entry = pmksa->pmksa; @@ -374,7 +375,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 " @@ -440,14 +442,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 8954f97f4c0..c023492ab37 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); @@ -91,7 +91,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 79b63fa37e4..e41f2755a65 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"); @@ -454,7 +454,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 " @@ -2378,7 +2379,7 @@ int wpa_set_bss(char *macddr, char * bssid, u8 pairwise_cipher, u8 group_cipher, 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 9de31f008ca2fa77187ed9cd3ddec4e7832e1f6b Mon Sep 17 00:00:00 2001 From: Jimi Chen Date: Thu, 21 May 2026 06:56:54 +0000 Subject: [PATCH 3/4] 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 192b4f6c769..8e5e941c724 100644 --- a/components/wpa_supplicant/src/common/sae.c +++ b/components/wpa_supplicant/src/common/sae.c @@ -1828,10 +1828,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 08064bc03bc412a32e2952a415730df4a33cf8f1 Mon Sep 17 00:00:00 2001 From: Richard Allen Date: Wed, 29 Jul 2026 09:07:30 +0530 Subject: [PATCH 4/4] 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: