From ec5c39a5574d4fbee983ae659ea0834bf48ea14d Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 16 Jan 2019 13:35:19 +0100 Subject: [PATCH] AP: Allow identifying which passphrase station used with wpa_psk_file It is now possible to optionally specify keyid for each wpa_psk_file entry: keyid=something 00:00:00:00:00:00 secretpassphrase When station connects and the passphrase it used has an associated keyid it will be appended to the AP-STA-CONNECTED event string: wlan0: AP-STA-CONNECTED 00:36:76:21:dc:7b keyid=something It's also possible to retrieve it through the control interface: $ hostapd_cli all_sta Selected interface 'ap0' 00:36:76:21:dc:7b ... keyid=something New hostapd is able to read old wpa_psk_file. However, old hostapd will not be able to read the new wpa_psk_file if it includes keyids. Signed-off-by: Michal Kazior --- hostapd/hostapd.wpa_psk | 3 +++ src/ap/ap_config.c | 53 +++++++++++++++++++++++++++++++++++++---- src/ap/ap_config.h | 2 ++ src/ap/ctrl_iface_ap.c | 8 +++++++ src/ap/sta_info.c | 44 ++++++++++++++++++++++++++++++---- src/ap/sta_info.h | 2 ++ 6 files changed, 103 insertions(+), 9 deletions(-) diff --git a/hostapd/hostapd.wpa_psk b/hostapd/hostapd.wpa_psk index 0a9499acd..834d44133 100644 --- a/hostapd/hostapd.wpa_psk +++ b/hostapd/hostapd.wpa_psk @@ -3,7 +3,10 @@ # Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that # anyone can use. PSK can be configured as an ASCII passphrase of 8..63 # characters or as a 256-bit hex PSK (64 hex digits). +# An optional key identifier can be added by prefixing the line with +# keyid= 00:00:00:00:00:00 secret passphrase 00:11:22:33:44:55 another passphrase 00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef +keyid=example_id 00:11:22:33:44:77 passphrase with keyid 00:00:00:00:00:00 another passphrase for all STAs diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c index 0cb302b31..9611dc0b3 100644 --- a/src/ap/ap_config.c +++ b/src/ap/ap_config.c @@ -259,6 +259,12 @@ static int hostapd_config_read_wpa_psk(const char *fname, { FILE *f; char buf[128], *pos; + const char *keyid; + char *context; + char *context2; + char *token; + char *name; + char *value; int line = 0, ret = 0, len, ok; u8 addr[ETH_ALEN]; struct hostapd_wpa_psk *psk; @@ -288,9 +294,35 @@ static int hostapd_config_read_wpa_psk(const char *fname, if (buf[0] == '\0') continue; - if (hwaddr_aton(buf, addr)) { + context = NULL; + keyid = NULL; + while ((token = str_token(buf, " ", &context))) { + if (!os_strchr(token, '=')) + break; + context2 = NULL; + name = str_token(token, "=", &context2); + value = str_token(token, "", &context2); + if (!value) + value = ""; + if (!os_strcmp(name, "keyid")) { + keyid = value; + } else { + wpa_printf(MSG_ERROR, + "Unrecognized '%s=%s' on line %d in '%s'", + name, value, line, fname); + ret = -1; + break; + } + } + + if (ret == -1) + break; + + if (!token) + token = ""; + if (hwaddr_aton(token, addr)) { wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on " - "line %d in '%s'", buf, line, fname); + "line %d in '%s'", token, line, fname); ret = -1; break; } @@ -306,15 +338,14 @@ static int hostapd_config_read_wpa_psk(const char *fname, else os_memcpy(psk->addr, addr, ETH_ALEN); - pos = buf + 17; - if (*pos == '\0') { + pos = str_token(buf, "", &context); + if (!pos) { wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'", line, fname); os_free(psk); ret = -1; break; } - pos++; ok = 0; len = os_strlen(pos); @@ -333,6 +364,18 @@ static int hostapd_config_read_wpa_psk(const char *fname, break; } + if (keyid) { + len = os_strlcpy(psk->keyid, keyid, sizeof(psk->keyid)); + if ((size_t) len >= sizeof(psk->keyid)) { + wpa_printf(MSG_ERROR, + "PSK keyid too long on line %d in '%s'", + line, fname); + os_free(psk); + ret = -1; + break; + } + } + psk->next = ssid->wpa_psk; ssid->wpa_psk = psk; } diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h index 16a4d06b3..8ca80d3f8 100644 --- a/src/ap/ap_config.h +++ b/src/ap/ap_config.h @@ -134,6 +134,7 @@ struct hostapd_vlan { }; #define PMK_LEN 32 +#define KEYID_LEN 32 #define MIN_PASSPHRASE_LEN 8 #define MAX_PASSPHRASE_LEN 63 struct hostapd_sta_wpa_psk_short { @@ -147,6 +148,7 @@ struct hostapd_sta_wpa_psk_short { struct hostapd_wpa_psk { struct hostapd_wpa_psk *next; int group; + char keyid[KEYID_LEN]; u8 psk[PMK_LEN]; u8 addr[ETH_ALEN]; u8 p2p_dev_addr[ETH_ALEN]; diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 21b813ee1..3128aed6f 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -207,6 +207,7 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, char *buf, size_t buflen) { int len, res, ret, i; + const char *keyid; if (!sta) return 0; @@ -341,6 +342,13 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd, len += ret; } + keyid = ap_sta_wpa_get_keyid(hapd, sta); + if (keyid) { + ret = os_snprintf(buf + len, buflen - len, "keyid=%s\n", keyid); + if (!os_snprintf_error(buflen - len, ret)) + len += ret; + } + return len; } diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c index 06f9afcd7..8858a3425 100644 --- a/src/ap/sta_info.c +++ b/src/ap/sta_info.c @@ -1163,6 +1163,32 @@ void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta) #endif /* CONFIG_IEEE80211W */ +const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, + struct sta_info *sta) +{ + struct hostapd_wpa_psk *psk; + struct hostapd_ssid *ssid; + const u8 *pmk; + int pmk_len; + + ssid = &hapd->conf->ssid; + + pmk = wpa_auth_get_pmk(sta->wpa_sm, &pmk_len); + if (!pmk || pmk_len != PMK_LEN) + return NULL; + + for (psk = ssid->wpa_psk; psk; psk = psk->next) + if (os_memcmp(pmk, psk->psk, PMK_LEN) == 0) + break; + if (!psk) + return NULL; + if (!psk || !psk->keyid[0]) + return NULL; + + return psk->keyid; +} + + void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, int authorized) { @@ -1201,7 +1227,11 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, sta->addr, authorized, dev_addr); if (authorized) { + const char *keyid; + char keyid_buf[100]; char ip_addr[100]; + + keyid_buf[0] = '\0'; ip_addr[0] = '\0'; #ifdef CONFIG_P2P if (wpa_auth_get_ip_addr(sta->wpa_sm, ip_addr_buf) == 0) { @@ -1212,14 +1242,20 @@ void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta, } #endif /* CONFIG_P2P */ - wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s", - buf, ip_addr); + keyid = ap_sta_wpa_get_keyid(hapd, sta); + if (keyid) { + os_snprintf(keyid_buf, sizeof(keyid_buf), + " keyid=%s", keyid); + } + + wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED "%s%s%s", + buf, ip_addr, keyid_buf); if (hapd->msg_ctx_parent && hapd->msg_ctx_parent != hapd->msg_ctx) wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO, - AP_STA_CONNECTED "%s%s", - buf, ip_addr); + AP_STA_CONNECTED "%s%s%s", + buf, ip_addr, keyid_buf); } else { wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf); diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h index fe68369f8..ee3f628a4 100644 --- a/src/ap/sta_info.h +++ b/src/ap/sta_info.h @@ -324,6 +324,8 @@ int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta, void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta); void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta); int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta); +const char * ap_sta_wpa_get_keyid(struct hostapd_data *hapd, + struct sta_info *sta); void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta, const u8 *addr, u16 reason);