summaryrefslogtreecommitdiffstats
path: root/contrib/wpa/src/ap/pmksa_cache_auth.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wpa/src/ap/pmksa_cache_auth.c')
-rw-r--r--contrib/wpa/src/ap/pmksa_cache_auth.c245
1 files changed, 223 insertions, 22 deletions
diff --git a/contrib/wpa/src/ap/pmksa_cache_auth.c b/contrib/wpa/src/ap/pmksa_cache_auth.c
index 877affe..15e2c49 100644
--- a/contrib/wpa/src/ap/pmksa_cache_auth.c
+++ b/contrib/wpa/src/ap/pmksa_cache_auth.c
@@ -38,6 +38,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
{
+ os_free(entry->vlan_desc);
os_free(entry->identity);
wpabuf_free(entry->cui);
#ifndef CONFIG_NO_RADIUS
@@ -91,6 +92,20 @@ void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
}
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+ while (pmksa->pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+ }
+}
+
+
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -126,6 +141,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
+ struct vlan_description *vlan_desc;
+
if (eapol == NULL)
return;
@@ -146,14 +163,22 @@ static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = eapol->eap_type_authsrv;
- entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
- entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
- entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
+ vlan_desc = ((struct sta_info *) eapol->sta)->vlan_desc;
+ if (vlan_desc && vlan_desc->notempty) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
+
+ entry->acct_multi_session_id = eapol->acct_multi_session_id;
}
-void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+void pmksa_cache_to_eapol_data(struct hostapd_data *hapd,
+ struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
if (entry == NULL || eapol == NULL)
@@ -186,10 +211,11 @@ void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- ((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+#ifndef CONFIG_NO_VLAN
+ ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
- eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
- eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
+ eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -234,6 +260,7 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
@@ -250,15 +277,50 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
- const u8 *pmk, size_t pmk_len,
+ const u8 *pmk, size_t pmk_len, const u8 *pmkid,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
- struct rsn_pmksa_cache_entry *entry, *pos;
+ struct rsn_pmksa_cache_entry *entry;
+
+ entry = pmksa_cache_auth_create_entry(pmk, pmk_len, pmkid, kck, kck_len,
+ aa, spa, session_timeout, eapol,
+ akmp);
+
+ if (pmksa_cache_auth_add_entry(pmksa, entry) < 0)
+ return NULL;
+
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_create_entry - Create a PMKSA cache entry
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @pmkid: Calculated PMKID
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function creates a PMKSA entry.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_create_entry(const u8 *pmk, size_t pmk_len, const u8 *pmkid,
+ const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, int session_timeout,
+ struct eapol_state_machine *eapol, int akmp)
+{
+ struct rsn_pmksa_cache_entry *entry;
struct os_reltime now;
- if (pmk_len > PMK_LEN)
+ if (pmk_len > PMK_LEN_MAX)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
@@ -269,13 +331,14 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ if (pmkid)
+ os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+ else if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
- rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
- wpa_key_mgmt_sha256(akmp));
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid, akmp);
os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)
@@ -286,9 +349,30 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
os_memcpy(entry->spa, spa, ETH_ALEN);
pmksa_cache_from_eapol_data(entry, eapol);
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_add_entry - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @entry: Pointer to PMKSA cache entry
+ *
+ * This function adds PMKSA cache entry to the PMKSA cache. If an old entry is
+ * already in the cache for the same Supplicant, this entry will be replaced
+ * with the new entry. PMKID will be calculated based on the PMK.
+ */
+int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry)
+{
+ struct rsn_pmksa_cache_entry *pos;
+
+ if (entry == NULL)
+ return -1;
+
/* Replace an old entry for the same STA (if found) with the new entry
*/
- pos = pmksa_cache_auth_get(pmksa, spa, NULL);
+ pos = pmksa_cache_auth_get(pmksa, entry->spa, NULL);
if (pos)
pmksa_cache_free_entry(pmksa, pos);
@@ -302,7 +386,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
pmksa_cache_link_entry(pmksa, entry);
- return entry;
+ return 0;
}
@@ -337,7 +421,13 @@ pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
radius_copy_class(&entry->radius_class, &old_entry->radius_class);
#endif /* CONFIG_NO_RADIUS */
entry->eap_type_authsrv = old_entry->eap_type_authsrv;
- entry->vlan_id = old_entry->vlan_id;
+ if (old_entry->vlan_desc) {
+ entry->vlan_desc = os_zalloc(sizeof(struct vlan_description));
+ if (entry->vlan_desc)
+ *entry->vlan_desc = *old_entry->vlan_desc;
+ } else {
+ entry->vlan_desc = NULL;
+ }
entry->opportunistic = 1;
pmksa_cache_link_entry(pmksa, entry);
@@ -427,7 +517,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
continue;
rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
- wpa_key_mgmt_sha256(entry->akmp));
+ entry->akmp);
if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
return entry;
}
@@ -471,12 +561,11 @@ static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
if (attr->acct_multi_session_id) {
char buf[20];
- if (attr->acct_multi_session_id_len != 17)
+ if (attr->acct_multi_session_id_len != 16)
return 0;
- os_snprintf(buf, sizeof(buf), "%08X+%08X",
- entry->acct_multi_session_id_hi,
- entry->acct_multi_session_id_lo);
- if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+ os_snprintf(buf, sizeof(buf), "%016llX",
+ (unsigned long long) entry->acct_multi_session_id);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 16) != 0)
return 0;
match++;
}
@@ -526,3 +615,115 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
return found ? 0 : -1;
}
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+ int i, ret;
+ char *pos = buf;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = pmksa->pmksa;
+ while (entry) {
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->spa));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+ PMKID_LEN);
+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ (int) (entry->expiration - now.sec),
+ entry->opportunistic);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
+
+
+#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
+#ifdef CONFIG_MESH
+
+/**
+ * pmksa_cache_auth_list_mesh - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @addr: MAC address of the peer (NULL means any)
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA_GET command to store
+ * in external storage.
+ */
+int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
+ char *buf, size_t len)
+{
+ int ret;
+ char *pos, *end;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ pos = buf;
+ end = buf + len;
+ os_get_reltime(&now);
+
+
+ /*
+ * Entry format:
+ * <BSSID> <PMKID> <PMK> <expiration in seconds>
+ */
+ for (entry = pmksa->pmksa; entry; entry = entry->next) {
+ if (addr && os_memcmp(entry->spa, addr, ETH_ALEN) != 0)
+ continue;
+
+ ret = os_snprintf(pos, end - pos, MACSTR " ",
+ MAC2STR(entry->spa));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmkid,
+ PMKID_LEN);
+
+ ret = os_snprintf(pos, end - pos, " ");
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+
+ pos += wpa_snprintf_hex(pos, end - pos, entry->pmk,
+ entry->pmk_len);
+
+ ret = os_snprintf(pos, end - pos, " %d\n",
+ (int) (entry->expiration - now.sec));
+ if (os_snprintf_error(end - pos, ret))
+ return 0;
+ pos += ret;
+ }
+
+ return pos - buf;
+}
+
+#endif /* CONFIG_MESH */
+#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
OpenPOWER on IntegriCloud