]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Add support for dynamic AP PIN management
authorJouni Malinen <j@w1.fi>
Tue, 24 Aug 2010 13:35:37 +0000 (16:35 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 24 Aug 2010 13:35:37 +0000 (16:35 +0300)
A new hostapd_cli command, wps_ap_pin, can now be used to manage
AP PIN at runtime. This can be used to generate a random AP PIN and
to only enable the AP PIN for short period (e.g., based on user
action on the AP device). Use of random AP PIN that is only enabled
for short duration is highly recommended to avoid security issues
with a static AP PIN.

hostapd/README-WPS
hostapd/ctrl_iface.c
hostapd/hostapd.conf
hostapd/hostapd_cli.c
src/ap/wps_hostapd.c
src/ap/wps_hostapd.h
src/common/wpa_ctrl.h
src/wps/wps_upnp.c
src/wps/wps_upnp.h

index b5fa86b2afcee008219a77857ae8efcaa467d766..74f211348edebbbb7679804de7e111f247060799 100644 (file)
@@ -195,6 +195,33 @@ which will generate a new WPA PSK in the same way as the PIN method
 described above.
 
 
+When an external Registrar is used, the AP can act as an Enrollee and
+use its AP PIN. A static AP PIN (e.g., one one a label in the AP
+device) can be configured in hostapd.conf (ap_pin parameter). A more
+secure option is to use hostapd_cli wps_ap_pin command to enable the
+AP PIN only based on user action (and even better security by using a
+random AP PIN for each session, i.e., by using "wps_ap_pin random"
+command with a timeout value). Following commands are available for
+managing the dynamic AP PIN operations:
+
+hostapd_cli wps_ap_pin disable
+- disable AP PIN (i.e., do not allow external Registrars to use it to
+  learn the current AP settings or to reconfigure the AP)
+
+hostapd_cli wps_ap_pin random [timeout]
+- generate a random AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli wps_ap_pin get
+- fetch the current AP PIN
+
+hostapd_cli wps_ap_pin set <PIN> [timeout]
+- set the AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+
 Credential generation and configuration changes
 -----------------------------------------------
 
index 9ef576df265984a766afc79ba9d0eee6b88727ad..9c47ba8bb76da7f6f2163fc3ca8d7a3c920af241 100644 (file)
@@ -313,6 +313,59 @@ static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
        return hostapd_wps_start_oob(hapd, txt, path, method, name);
 }
 #endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
+                                        char *buf, size_t buflen)
+{
+       int timeout = 300;
+       char *pos;
+       const char *pin_txt;
+
+       pos = os_strchr(txt, ' ');
+       if (pos)
+               *pos++ = '\0';
+
+       if (os_strcmp(txt, "disable") == 0) {
+               hostapd_wps_ap_pin_disable(hapd);
+               return os_snprintf(buf, buflen, "OK\n");
+       }
+
+       if (os_strcmp(txt, "random") == 0) {
+               if (pos)
+                       timeout = atoi(pos);
+               pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
+               if (pin_txt == NULL)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin_txt);
+       }
+
+       if (os_strcmp(txt, "get") == 0) {
+               pin_txt = hostapd_wps_ap_pin_get(hapd);
+               if (pin_txt == NULL)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin_txt);
+       }
+
+       if (os_strcmp(txt, "set") == 0) {
+               char *pin;
+               if (pos == NULL)
+                       return -1;
+               pin = pos;
+               pos = os_strchr(pos, ' ');
+               if (pos) {
+                       *pos++ = '\0';
+                       timeout = atoi(pos);
+               }
+               if (os_strlen(pin) > buflen)
+                       return -1;
+               if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
+                       return -1;
+               return os_snprintf(buf, buflen, "%s", pin);
+       }
+
+       return -1;
+}
 #endif /* CONFIG_WPS */
 
 
@@ -426,6 +479,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
                if (hostapd_ctrl_iface_wps_oob(hapd, buf + 8))
                        reply_len = -1;
 #endif /* CONFIG_WPS_OOB */
+       } else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
+                                                         reply, reply_size);
 #endif /* CONFIG_WPS */
        } else {
                os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
index e948c20d9ca11c3942b2cf8bbd818572f4fe5e27..56b54cf5d95d15333336304e091952c26f00e800 100644 (file)
@@ -916,9 +916,13 @@ own_ip_addr=127.0.0.1
 #      nfc_interface push_button keypad
 #config_methods=label display push_button keypad
 
-# Access point PIN for initial configuration and adding Registrars
+# Static access point PIN for initial configuration and adding Registrars
 # If not set, hostapd will not allow external WPS Registrars to control the
-# access point.
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
 #ap_pin=12345670
 
 # Skip building of automatic WPS credential
index 889018a2dfbbaba0958853f44af0c3c842db04f4..589530e419fc60e74a8ab72ddcf705cad28d3ecf 100644 (file)
@@ -94,6 +94,7 @@ static const char *commands_help =
 #ifdef CONFIG_WPS_OOB
 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
 #endif /* CONFIG_WPS_OOB */
+"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
 #endif /* CONFIG_WPS */
 "   help                 show this usage help\n"
 "   interface [ifname]   show interfaces/select interface\n"
@@ -405,6 +406,27 @@ static int hostapd_cli_cmd_wps_oob(struct wpa_ctrl *ctrl, int argc,
        return wpa_ctrl_command(ctrl, cmd);
 }
 #endif /* CONFIG_WPS_OOB */
+
+
+static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+                                     char *argv[])
+{
+       char buf[64];
+       if (argc < 1) {
+               printf("Invalid 'wps_ap_pin' command - at least one argument "
+                      "is required.\n");
+               return -1;
+       }
+       if (argc > 2)
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
+                        argv[0], argv[1], argv[2]);
+       else if (argc > 1)
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
+                        argv[0], argv[1]);
+       else
+               snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
+       return wpa_ctrl_command(ctrl, buf);
+}
 #endif /* CONFIG_WPS */
 
 
@@ -567,6 +589,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
 #ifdef CONFIG_WPS_OOB
        { "wps_oob", hostapd_cli_cmd_wps_oob },
 #endif /* CONFIG_WPS_OOB */
+       { "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
 #endif /* CONFIG_WPS */
        { "help", hostapd_cli_cmd_help },
        { "interface", hostapd_cli_cmd_interface },
index d0e7e0a95045989a7f1b39cff56c18ac35501cc8..bc747ce19a2f512cb049ae289ed77ae3a0eb4d64 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -42,6 +42,7 @@ static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 
 static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
                                    const u8 *ie, size_t ie_len);
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
 
 static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
@@ -432,7 +433,6 @@ static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
        wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
        hapd->wps->ap_setup_locked = 0;
        wps_registrar_update_ie(hapd->wps->registrar);
-
 }
 
 
@@ -683,6 +683,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
 void hostapd_deinit_wps(struct hostapd_data *hapd)
 {
        eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+       eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
        if (hapd->wps == NULL)
                return;
 #ifdef CONFIG_WPS_UPNP
@@ -942,3 +943,72 @@ int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
                return 0;
        return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
 }
+
+
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+       struct hostapd_data *hapd = eloop_data;
+       wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+       hostapd_wps_ap_pin_disable(hapd);
+}
+
+
+static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
+{
+       wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+       hapd->ap_pin_failures = 0;
+       hapd->conf->ap_setup_locked = 0;
+       if (hapd->wps->ap_setup_locked) {
+               wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+               hapd->wps->ap_setup_locked = 0;
+               wps_registrar_update_ie(hapd->wps->registrar);
+       }
+       eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+       if (timeout > 0)
+               eloop_register_timeout(timeout, 0,
+                                      hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+{
+       wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = NULL;
+       upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
+       eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+       unsigned int pin;
+       char pin_txt[9];
+
+       pin = wps_generate_pin();
+       os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = os_strdup(pin_txt);
+       upnp_wps_set_ap_pin(hapd->wps_upnp, pin_txt);
+       hostapd_wps_ap_pin_enable(hapd, timeout);
+       return hapd->conf->ap_pin;
+}
+
+
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
+{
+       return hapd->conf->ap_pin;
+}
+
+
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+                          int timeout)
+{
+       os_free(hapd->conf->ap_pin);
+       hapd->conf->ap_pin = os_strdup(pin);
+       if (hapd->conf->ap_pin == NULL)
+               return -1;
+       upnp_wps_set_ap_pin(hapd->wps_upnp, hapd->conf->ap_pin);
+       hostapd_wps_ap_pin_enable(hapd, timeout);
+       return 0;
+}
index 0b574032e5e78969353fdc0e8fda59f3169ddf09..e978a1cf668d5ede663917b09ab2f5a6c0f53ec9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / WPS integration
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2010, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -28,6 +28,11 @@ int hostapd_wps_start_oob(struct hostapd_data *hapd, char *device_type,
                          char *path, char *method, char *name);
 int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
                            char *buf, size_t buflen);
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+                          int timeout);
 
 #else /* CONFIG_WPS */
 
index 0c4a965e275af7bb94212cc06c7e8f4c39bd2904..54aa988f4071f07953b25c1b8313ca87413f1863 100644 (file)
@@ -94,6 +94,8 @@ extern "C" {
 #define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
 #define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
 #define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
+#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
+#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
 #define AP_STA_CONNECTED "AP-STA-CONNECTED "
 #define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
 
index f4f209ce53c1a6b9f665746a92e6ae6f47141ebf..f99b8592ca36b1d71911b27a2cfaf6f659d22d5a 100644 (file)
@@ -1074,3 +1074,20 @@ int upnp_wps_subscribers(struct upnp_wps_device_sm *sm)
 {
        return !dl_list_empty(&sm->subscriptions);
 }
+
+
+int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin)
+{
+       if (sm == NULL)
+               return 0;
+
+       os_free(sm->ctx->ap_pin);
+       if (ap_pin) {
+               sm->ctx->ap_pin = os_strdup(ap_pin);
+               if (sm->ctx->ap_pin == NULL)
+                       return -1;
+       } else
+               sm->ctx->ap_pin = NULL;
+
+       return 0;
+}
index 1467db3becccc4acea8c8bb52dae5fdbc1f013dc..06bc31fe7ffdfb6f4b4aa6aef41ad04376bd193c 100644 (file)
@@ -46,5 +46,6 @@ int upnp_wps_device_send_wlan_event(struct upnp_wps_device_sm *sm,
                                    enum upnp_wps_wlanevent_type ev_type,
                                    const struct wpabuf *msg);
 int upnp_wps_subscribers(struct upnp_wps_device_sm *sm);
+int upnp_wps_set_ap_pin(struct upnp_wps_device_sm *sm, const char *ap_pin);
 
 #endif /* WPS_UPNP_H */