]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WPS: Add wps_check_pin command for processing PIN from user input
authorJouni Malinen <jouni.malinen@atheros.com>
Thu, 23 Sep 2010 17:30:52 +0000 (10:30 -0700)
committerJouni Malinen <j@w1.fi>
Thu, 23 Sep 2010 17:30:52 +0000 (10:30 -0700)
UIs can use this command to process a PIN entered by a user and to
validate the checksum digit (if present).

hostapd/README-WPS
hostapd/ctrl_iface.c
hostapd/hostapd_cli.c
wpa_supplicant/README-WPS
wpa_supplicant/ctrl_iface.c
wpa_supplicant/wpa_cli.c

index 64561d025645bb97e28221a073584f7091e93226..63b62a56a1ece750da03d68ead335bdd7f3247c4 100644 (file)
@@ -120,6 +120,13 @@ pushbutton event (for PBC) to allow a new WPS Enrollee to join the
 network. hostapd uses the control interface as an input channel for
 these events.
 
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
+processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
+the checksum digit is incorrect, or the processed PIN (non-digit
+characters removed) if the PIN is valid.
+
 When a client device (WPS Enrollee) connects to hostapd (WPS
 Registrar) in order to start PIN mode negotiation for WPS, an
 identifier (Enrollee UUID) is sent. hostapd will need to be configured
index bd25e1c89437e5c2d5dac7b23ea9466a7a5ca39e..7f628f1456b5feaf463ed22aaeb8e1676d190fef 100644 (file)
@@ -35,6 +35,7 @@
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "wps/wps_defs.h"
+#include "wps/wps.h"
 #include "ctrl_iface.h"
 
 
@@ -369,6 +370,51 @@ static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
 }
 
 
+static int hostapd_ctrl_iface_wps_check_pin(
+       struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
+{
+       char pin[9];
+       size_t len;
+       char *pos;
+       int ret;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+                             (u8 *) cmd, os_strlen(cmd));
+       for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+               if (*pos < '0' || *pos > '9')
+                       continue;
+               pin[len++] = *pos;
+               if (len == 9) {
+                       wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+                       return -1;
+               }
+       }
+       if (len != 4 && len != 8) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+               return -1;
+       }
+       pin[len] = '\0';
+
+       if (len == 8) {
+               unsigned int pin_val;
+               pin_val = atoi(pin);
+               if (!wps_pin_valid(pin_val)) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+                       ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+                       if (ret < 0 || (size_t) ret >= buflen)
+                               return -1;
+                       return ret;
+               }
+       }
+
+       ret = os_snprintf(buf, buflen, "%s", pin);
+       if (ret < 0 || (size_t) ret >= buflen)
+               return -1;
+
+       return ret;
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
 {
@@ -589,6 +635,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
        } else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
                if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
                        reply_len = -1;
+       } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+               reply_len = hostapd_ctrl_iface_wps_check_pin(
+                       hapd, buf + 14, reply, reply_size);
        } else if (os_strcmp(buf, "WPS_PBC") == 0) {
                if (hostapd_wps_button_pushed(hapd))
                        reply_len = -1;
index e80de487dde884e7d871b0ba5890697ecc16b386..5ca793b49647516538c6ff188e730b79a87f325a 100644 (file)
@@ -90,6 +90,7 @@ static const char *commands_help =
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
 "   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
+"   wps_check_pin <PIN>  verify PIN checksum\n"
 "   wps_pbc              indicate button pushed to initiate PBC\n"
 #ifdef CONFIG_WPS_OOB
 "   wps_oob <type> <path> <method>  use WPS with out-of-band (UFD)\n"
@@ -370,6 +371,32 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
 }
 
 
+static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+                                        char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1 && argc != 2) {
+               printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
+                      "- PIN to be verified\n");
+               return -1;
+       }
+
+       if (argc == 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
+                                 argv[0], argv[1]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
+                                 argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_CHECK_PIN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
                                   char *argv[])
 {
@@ -608,6 +635,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
 #endif /* CONFIG_IEEE80211W */
 #ifdef CONFIG_WPS
        { "wps_pin", hostapd_cli_cmd_wps_pin },
+       { "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
        { "wps_pbc", hostapd_cli_cmd_wps_pbc },
 #ifdef CONFIG_WPS_OOB
        { "wps_oob", hostapd_cli_cmd_wps_oob },
index 7c28836886b161d112487b191a1e0a0cc69292f7..8a773e201a77e01528093def4e20414342cd1a8e 100644 (file)
@@ -94,6 +94,13 @@ pushbutton event (for PBC) to allow a new WPS Enrollee to join the
 network. wpa_supplicant uses the control interface as an input channel
 for these events.
 
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "wpa_cli wps_check_pin <PIN>" can be used to do such processing.
+It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if the checksum
+digit is incorrect, or the processed PIN (non-digit characters removed)
+if the PIN is valid.
+
 If the client device has a display, a random PIN has to be generated
 for each WPS registration session. wpa_supplicant can do this with a
 control interface request, e.g., by calling wpa_cli:
index 8c5dcdf981586e86a08c8f7c2f577febaa860df3..ac5d067f898732eae1cb07559056d6fe8f31b622 100644 (file)
@@ -261,6 +261,51 @@ static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpa_supplicant_ctrl_iface_wps_check_pin(
+       struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+       char pin[9];
+       size_t len;
+       char *pos;
+       int ret;
+
+       wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+                             (u8 *) cmd, os_strlen(cmd));
+       for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+               if (*pos < '0' || *pos > '9')
+                       continue;
+               pin[len++] = *pos;
+               if (len == 9) {
+                       wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+                       return -1;
+               }
+       }
+       if (len != 4 && len != 8) {
+               wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+               return -1;
+       }
+       pin[len] = '\0';
+
+       if (len == 8) {
+               unsigned int pin_val;
+               pin_val = atoi(pin);
+               if (!wps_pin_valid(pin_val)) {
+                       wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+                       ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+                       if (ret < 0 || (size_t) ret >= buflen)
+                               return -1;
+                       return ret;
+               }
+       }
+
+       ret = os_snprintf(buf, buflen, "%s", pin);
+       if (ret < 0 || (size_t) ret >= buflen)
+               return -1;
+
+       return ret;
+}
+
+
 #ifdef CONFIG_WPS_OOB
 static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
                                             char *cmd)
@@ -2715,6 +2760,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
                reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
                                                              reply,
                                                              reply_size);
+       } else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+               reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
+                       wpa_s, buf + 14, reply, reply_size);
        } else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
                if (wpas_wps_cancel(wpa_s))
                        reply_len = -1;
index 855f720ad4c0d6794664b5d7836354c6ec976d5e..00fb0dccae9935861140b493a347d9571253aac1 100644 (file)
@@ -615,6 +615,32 @@ static int wpa_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
 }
 
 
+static int wpa_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+                                    char *argv[])
+{
+       char cmd[256];
+       int res;
+
+       if (argc != 1 && argc != 2) {
+               printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
+                      "- PIN to be verified\n");
+               return -1;
+       }
+
+       if (argc == 2)
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
+                                 argv[0], argv[1]);
+       else
+               res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
+                                 argv[0]);
+       if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+               printf("Too long WPS_CHECK_PIN command.\n");
+               return -1;
+       }
+       return wpa_ctrl_command(ctrl, cmd);
+}
+
+
 static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
                                  char *argv[])
 {
@@ -2271,6 +2297,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
          cli_cmd_flag_sensitive,
          "<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
          "hardcoded)" },
+       { "wps_check_pin", wpa_cli_cmd_wps_check_pin,
+         cli_cmd_flag_sensitive,
+         "<PIN> = verify PIN checksum" },
        { "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
          "Cancels the pending WPS operation" },
 #ifdef CONFIG_WPS_OOB