WPS: Add wps_check_pin command for processing PIN from user input
UIs can use this command to process a PIN entered by a user and to validate the checksum digit (if present).
This commit is contained in:
parent
fa37511fa7
commit
3981cb3cb8
6 changed files with 168 additions and 0 deletions
|
@ -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
|
network. hostapd uses the control interface as an input channel for
|
||||||
these events.
|
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
|
When a client device (WPS Enrollee) connects to hostapd (WPS
|
||||||
Registrar) in order to start PIN mode negotiation for WPS, an
|
Registrar) in order to start PIN mode negotiation for WPS, an
|
||||||
identifier (Enrollee UUID) is sent. hostapd will need to be configured
|
identifier (Enrollee UUID) is sent. hostapd will need to be configured
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "ap/wps_hostapd.h"
|
#include "ap/wps_hostapd.h"
|
||||||
#include "ap/ctrl_iface_ap.h"
|
#include "ap/ctrl_iface_ap.h"
|
||||||
#include "wps/wps_defs.h"
|
#include "wps/wps_defs.h"
|
||||||
|
#include "wps/wps.h"
|
||||||
#include "ctrl_iface.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
|
#ifdef CONFIG_WPS_OOB
|
||||||
static int hostapd_ctrl_iface_wps_oob(struct hostapd_data *hapd, char *txt)
|
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) {
|
} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
|
||||||
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
|
if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
|
||||||
reply_len = -1;
|
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) {
|
} else if (os_strcmp(buf, "WPS_PBC") == 0) {
|
||||||
if (hostapd_wps_button_pushed(hapd))
|
if (hostapd_wps_button_pushed(hapd))
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
|
|
@ -90,6 +90,7 @@ static const char *commands_help =
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
#ifdef CONFIG_WPS
|
#ifdef CONFIG_WPS
|
||||||
" wps_pin <uuid> <pin> [timeout] [addr] add WPS Enrollee PIN\n"
|
" 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"
|
" wps_pbc indicate button pushed to initiate PBC\n"
|
||||||
#ifdef CONFIG_WPS_OOB
|
#ifdef CONFIG_WPS_OOB
|
||||||
" wps_oob <type> <path> <method> use WPS with out-of-band (UFD)\n"
|
" 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,
|
static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -608,6 +635,7 @@ static struct hostapd_cli_cmd hostapd_cli_commands[] = {
|
||||||
#endif /* CONFIG_IEEE80211W */
|
#endif /* CONFIG_IEEE80211W */
|
||||||
#ifdef CONFIG_WPS
|
#ifdef CONFIG_WPS
|
||||||
{ "wps_pin", hostapd_cli_cmd_wps_pin },
|
{ "wps_pin", hostapd_cli_cmd_wps_pin },
|
||||||
|
{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
|
||||||
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
|
{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
|
||||||
#ifdef CONFIG_WPS_OOB
|
#ifdef CONFIG_WPS_OOB
|
||||||
{ "wps_oob", hostapd_cli_cmd_wps_oob },
|
{ "wps_oob", hostapd_cli_cmd_wps_oob },
|
||||||
|
|
|
@ -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
|
network. wpa_supplicant uses the control interface as an input channel
|
||||||
for these events.
|
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
|
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
|
for each WPS registration session. wpa_supplicant can do this with a
|
||||||
control interface request, e.g., by calling wpa_cli:
|
control interface request, e.g., by calling wpa_cli:
|
||||||
|
|
|
@ -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
|
#ifdef CONFIG_WPS_OOB
|
||||||
static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
|
static int wpa_supplicant_ctrl_iface_wps_oob(struct wpa_supplicant *wpa_s,
|
||||||
char *cmd)
|
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_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
|
||||||
reply,
|
reply,
|
||||||
reply_size);
|
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) {
|
} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
|
||||||
if (wpas_wps_cancel(wpa_s))
|
if (wpas_wps_cancel(wpa_s))
|
||||||
reply_len = -1;
|
reply_len = -1;
|
||||||
|
|
|
@ -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,
|
static int wpa_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
|
||||||
char *argv[])
|
char *argv[])
|
||||||
{
|
{
|
||||||
|
@ -2271,6 +2297,9 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
|
||||||
cli_cmd_flag_sensitive,
|
cli_cmd_flag_sensitive,
|
||||||
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
|
"<BSSID> [PIN] = start WPS PIN method (returns PIN, if not "
|
||||||
"hardcoded)" },
|
"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,
|
{ "wps_cancel", wpa_cli_cmd_wps_cancel, cli_cmd_flag_none,
|
||||||
"Cancels the pending WPS operation" },
|
"Cancels the pending WPS operation" },
|
||||||
#ifdef CONFIG_WPS_OOB
|
#ifdef CONFIG_WPS_OOB
|
||||||
|
|
Loading…
Reference in a new issue