From bd545de69714a98d1b4ea16a72c4a3d655083add 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 e8f413f41c3..e0967f3f177 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"); @@ -474,7 +474,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 " @@ -2687,7 +2687,8 @@ 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, 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 5a671d74122a1cad016a697009a025b01bb54e1d 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 e0967f3f177..c6d7739cc59 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 " @@ -2688,7 +2689,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 c90545c85d8a5b757d76119a05669c094e278919 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 0e59d7845961b34b2770bb460809fdb62bf88cc1 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: