]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP: Allow identifying which passphrase station used with wpa_psk_file
authorMichal Kazior <michal@plume.com>
Wed, 16 Jan 2019 12:35:19 +0000 (13:35 +0100)
committerJouni Malinen <j@w1.fi>
Sat, 26 Jan 2019 15:52:04 +0000 (17:52 +0200)
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 <michal@plume.com>
hostapd/hostapd.wpa_psk
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/ctrl_iface_ap.c
src/ap/sta_info.c
src/ap/sta_info.h

index 0a9499acd73663f4d835ca5677a545bb43f83e2d..834d4413340455787a2a6f7a023eddf74e5f1ba2 100644 (file)
@@ -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=<keyid_string>
 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
index 0cb302b31817c4836ddd93f6f3e0ac9d8fc85a6f..9611dc0b3fdb30019ee59a0e869922cbdec17b0e 100644 (file)
@@ -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;
        }
index 16a4d06b3b1dc089ef442a44b02548b47ab77098..8ca80d3f82264f219700ea9c817ebe8aa4924b50 100644 (file)
@@ -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];
index 21b813ee18d775b5bf7a6cbfcd2bf8ab88dcdfea..3128aed6feb4e820db11a7b79c75572cae09b115 100644 (file)
@@ -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;
 }
 
index 06f9afcd713e5c12f945c2d949f1631b3122a224..8858a3425907468f871d449e84e950daa3614259 100644 (file)
@@ -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);
 
index fe68369f8fad9c5a9dae5975436eb33fab698e14..ee3f628a41a19b087aa2e3613c9b8f00ebc4c0ea 100644 (file)
@@ -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);