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 <jouni.malinen@oss.qualcomm.com>
This commit is contained in:
Jouni Malinen
2026-07-06 15:33:11 +03:00
committed by Kapil Gupta
parent 9afd391d1d
commit 35ba8e5032
3 changed files with 15 additions and 12 deletions

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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 "
@@ -2367,7 +2368,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;
}