mesh: Add MESH_PMKSA_GET/ADD commands
These commnds are mesh version of PMKSA_GET/ADD commands. So the usage
and security risk is similar to them. Refer to
commit 3459381dd2
('External persistent
storage for PMKSA cache entries') also.
The MESH_PMKSA_GET command requires peer MAC address or "any" as an
argument and outputs appropriate stored PMKSA cache. And the
MESH_PMKSA_ADD command receives an output of MESH_PMKSA_GET and re-store
the PMKSA cache into wpa_supplicant. By using re-stored PMKSA cache,
wpa_supplicant can skip commit message creation which can use
significant CPU resources.
The output of the MESH_PMKSA_GET command uses the following format:
<BSSID> <PMKID> <PMK> <expiration in seconds>
The example of MESH_PMKSA_ADD command is this.
MESH_PMKSA_ADD 02:00:00:00:03:00 231dc1c9fa2eed0354ea49e8ff2cc2dc cb0f6c9cab358a8146488566ca155421ab4f3ea4a6de2120050c149b797018fe 42930
MESH_PMKSA_ADD 02:00:00:00:04:00 d7e595916611640d3e4e8eac02909c3c eb414a33c74831275f25c2357b3c12e3d8bd2f2aab6cf781d6ade706be71321a 43180
This functionality is disabled by default and can be enabled with
CONFIG_PMKSA_CACHE_EXTERNAL=y build configuration option.
Signed-off-by: Masashi Honma <masashi.honma@gmail.com>
This commit is contained in:
parent
117875db33
commit
4d77d80edd
13 changed files with 411 additions and 3 deletions
|
@ -639,3 +639,60 @@ void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
|
|||
{
|
||||
wpa_auth_pmksa_flush(hapd->wpa_auth);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
|
||||
#ifdef CONFIG_MESH
|
||||
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len)
|
||||
{
|
||||
return wpa_auth_pmksa_list_mesh(hapd->wpa_auth, addr, buf, len);
|
||||
}
|
||||
|
||||
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd)
|
||||
{
|
||||
u8 spa[ETH_ALEN];
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
char *pos;
|
||||
int expiration;
|
||||
|
||||
/*
|
||||
* Entry format:
|
||||
* <BSSID> <PMKID> <PMK> <expiration in seconds>
|
||||
*/
|
||||
|
||||
if (hwaddr_aton(cmd, spa))
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(cmd, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmkid, PMKID_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (hexstr2bin(pos, pmk, PMK_LEN) < 0)
|
||||
return NULL;
|
||||
|
||||
pos = os_strchr(pos, ' ');
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos++;
|
||||
|
||||
if (sscanf(pos, "%d", &expiration) != 1)
|
||||
return NULL;
|
||||
|
||||
return wpa_auth_pmksa_create_entry(aa, spa, pmk, pmkid, expiration);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
|
|
@ -32,5 +32,8 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
|
|||
int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
|
||||
size_t len);
|
||||
void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
|
||||
int hostapd_ctrl_iface_pmksa_list_mesh(struct hostapd_data *hapd,
|
||||
const u8 *addr, char *buf, size_t len);
|
||||
void * hostapd_ctrl_iface_pmksa_create_entry(const u8 *aa, char *cmd);
|
||||
|
||||
#endif /* CTRL_IFACE_AP_H */
|
||||
|
|
|
@ -282,7 +282,42 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
|||
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_MAX)
|
||||
|
@ -315,9 +350,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);
|
||||
|
||||
|
@ -331,7 +387,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
|||
|
||||
pmksa_cache_link_entry(pmksa, entry);
|
||||
|
||||
return entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -605,3 +661,70 @@ int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
|
|||
}
|
||||
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 */
|
||||
|
|
|
@ -53,6 +53,13 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
|||
const u8 *aa, const u8 *spa, int session_timeout,
|
||||
struct eapol_state_machine *eapol, int akmp);
|
||||
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);
|
||||
int pmksa_cache_auth_add_entry(struct rsn_pmksa_cache *pmksa,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
|
||||
const struct rsn_pmksa_cache_entry *old_entry,
|
||||
const u8 *aa, const u8 *pmkid);
|
||||
|
@ -65,5 +72,7 @@ int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
|
|||
struct radius_das_attrs *attr);
|
||||
int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
|
||||
void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
|
||||
int pmksa_cache_auth_list_mesh(struct rsn_pmksa_cache *pmksa, const u8 *addr,
|
||||
char *buf, size_t len);
|
||||
|
||||
#endif /* PMKSA_CACHE_H */
|
||||
|
|
|
@ -3850,6 +3850,58 @@ void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
|
|||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PMKSA_CACHE_EXTERNAL
|
||||
#ifdef CONFIG_MESH
|
||||
|
||||
int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
char *buf, size_t len)
|
||||
{
|
||||
if (!wpa_auth || !wpa_auth->pmksa)
|
||||
return 0;
|
||||
|
||||
return pmksa_cache_auth_list_mesh(wpa_auth->pmksa, addr, buf, len);
|
||||
}
|
||||
|
||||
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
|
||||
const u8 *pmkid, int expiration)
|
||||
{
|
||||
struct rsn_pmksa_cache_entry *entry;
|
||||
struct os_reltime now;
|
||||
|
||||
entry = pmksa_cache_auth_create_entry(pmk, PMK_LEN, pmkid, NULL, 0, aa,
|
||||
spa, 0, NULL, WPA_KEY_MGMT_SAE);
|
||||
if (!entry)
|
||||
return NULL;
|
||||
|
||||
os_get_reltime(&now);
|
||||
entry->expiration = now.sec + expiration;
|
||||
return entry;
|
||||
}
|
||||
|
||||
|
||||
int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
|
||||
struct rsn_pmksa_cache_entry *entry)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!wpa_auth || !wpa_auth->pmksa)
|
||||
return -1;
|
||||
|
||||
ret = pmksa_cache_auth_add_entry(wpa_auth->pmksa, entry);
|
||||
if (ret < 0)
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"RSN: Failed to store external PMKSA cache for "
|
||||
MACSTR, MAC2STR(entry->spa));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_MESH */
|
||||
#endif /* CONFIG_PMKSA_CACHE_EXTERNAL */
|
||||
|
||||
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
|
||||
const u8 *pmkid)
|
||||
|
|
|
@ -302,6 +302,13 @@ void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
|
|||
int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
|
||||
size_t len);
|
||||
void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
|
||||
int wpa_auth_pmksa_list_mesh(struct wpa_authenticator *wpa_auth, const u8 *addr,
|
||||
char *buf, size_t len);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_create_entry(const u8 *aa, const u8 *spa, const u8 *pmk,
|
||||
const u8 *pmkid, int expiration);
|
||||
int wpa_auth_pmksa_add_entry(struct wpa_authenticator *wpa_auth,
|
||||
struct rsn_pmksa_cache_entry *entry);
|
||||
struct rsn_pmksa_cache_entry *
|
||||
wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr,
|
||||
const u8 *pmkid);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue