aboutsummaryrefslogtreecommitdiffstats
path: root/src/wps
diff options
context:
space:
mode:
authorJouni Malinen <j@w1.fi>2009-12-12 14:40:10 (GMT)
committerJouni Malinen <j@w1.fi>2010-09-09 13:07:47 (GMT)
commit31fcea931d916fd3dec2522822f87a7148b45a99 (patch)
treeefe4ecda6d02fa176ed82da68871ae186dc7261e /src/wps
parentf439079e93dfff93d184df727bb8bedef4a9fcb2 (diff)
downloadhostap-31fcea931d916fd3dec2522822f87a7148b45a99.zip
hostap-31fcea931d916fd3dec2522822f87a7148b45a99.tar.gz
hostap-31fcea931d916fd3dec2522822f87a7148b45a99.tar.bz2
WPS 2.0: Add support for AuthorizedMACs attribute
Advertize list of authorized enrollee MAC addresses in Beacon and Probe Response frames and use these when selecting the AP. In order to provide the list, the enrollee MAC address should be specified whenever adding a new PIN. In addition, add UUID-R into SetSelectedRegistrar action to make it potentially easier for an AP to figure out which ER sent the action should there be multiple ERs using the same IP address.
Diffstat (limited to 'src/wps')
-rw-r--r--src/wps/wps.c69
-rw-r--r--src/wps/wps.h7
-rw-r--r--src/wps/wps_defs.h2
-rw-r--r--src/wps/wps_er.c17
-rw-r--r--src/wps/wps_i.h1
-rw-r--r--src/wps/wps_registrar.c111
-rw-r--r--src/wps/wps_upnp_ap.c8
-rw-r--r--src/wps/wps_upnp_i.h1
8 files changed, 191 insertions, 25 deletions
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 533cbaf..6d4b1cb 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -205,15 +205,8 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg)
}
-/**
- * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
- * @msg: WPS IE contents from Beacon or Probe Response frame
- * Returns: 1 if PIN Registrar is active, 0 if not
- */
-int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+static int is_selected_pin_registrar(struct wps_parse_attr *attr)
{
- struct wps_parse_attr attr;
-
/*
* In theory, this could also verify that attr.sel_reg_config_methods
* includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
@@ -222,17 +215,69 @@ int wps_is_selected_pin_registrar(const struct wpabuf *msg)
* Device Password ID here.
*/
+ if (!attr->selected_registrar || *attr->selected_registrar == 0)
+ return 0;
+
+ if (attr->dev_password_id != NULL &&
+ WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON)
+ return 0;
+
+ return 1;
+}
+
+
+/**
+ * wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * Returns: 1 if PIN Registrar is active, 0 if not
+ */
+int wps_is_selected_pin_registrar(const struct wpabuf *msg)
+{
+ struct wps_parse_attr attr;
+
if (wps_parse_msg(msg, &attr) < 0)
return 0;
- if (!attr.selected_registrar || *attr.selected_registrar == 0)
+ return is_selected_pin_registrar(&attr);
+}
+
+
+/**
+ * wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
+ * @msg: WPS IE contents from Beacon or Probe Response frame
+ * @addr: MAC address to search for
+ * @ver1_compat: Whether to use version 1 compatibility mode
+ * Returns: 1 if address is authorized, 0 if not
+ */
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+ int ver1_compat)
+{
+ struct wps_parse_attr attr;
+ unsigned int i;
+ const u8 *pos;
+
+ if (wps_parse_msg(msg, &attr) < 0)
return 0;
- if (attr.dev_password_id != NULL &&
- WPA_GET_BE16(attr.dev_password_id) == DEV_PW_PUSHBUTTON)
+ if (!attr.version2 && ver1_compat) {
+ /*
+ * Version 1.0 AP - AuthorizedMACs not used, so revert back to
+ * old mechanism of using SelectedRegistrar.
+ */
+ return is_selected_pin_registrar(&attr);
+ }
+
+ if (!attr.authorized_macs)
return 0;
- return 1;
+ pos = attr.authorized_macs;
+ for (i = 0; i < attr.authorized_macs_len / ETH_ALEN; i++) {
+ if (os_memcmp(pos, addr, ETH_ALEN) == 0)
+ return 1;
+ pos += ETH_ALEN;
+ }
+
+ return 0;
}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 8536499..31be0b5 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -197,6 +197,8 @@ int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
int wps_is_selected_pin_registrar(const struct wpabuf *msg);
int wps_ap_priority_compar(const struct wpabuf *wps_a,
const struct wpabuf *wps_b);
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+ int ver1_compat);
const u8 * wps_get_uuid_e(const struct wpabuf *msg);
struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
@@ -707,8 +709,9 @@ struct wps_registrar *
wps_registrar_init(struct wps_context *wps,
const struct wps_registrar_config *cfg);
void wps_registrar_deinit(struct wps_registrar *reg);
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
- const u8 *pin, size_t pin_len, int timeout);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+ const u8 *uuid, const u8 *pin, size_t pin_len,
+ int timeout);
int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_button_pushed(struct wps_registrar *reg);
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index 9f3f152..835eb4c 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -296,4 +296,6 @@ enum wps_response_type {
/* Walk Time for push button configuration (in seconds) */
#define WPS_PBC_WALK_TIME 120
+#define WPS_MAX_AUTHORIZED_MACS 5
+
#endif /* WPS_DEFS_H */
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index fdcc1cb..9f5074a 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -1349,6 +1349,15 @@ static int wps_er_build_sel_reg_config_methods(struct wpabuf *msg,
}
+static int wps_er_build_uuid_r(struct wpabuf *msg, const u8 *uuid_r)
+{
+ wpabuf_put_be16(msg, ATTR_UUID_R);
+ wpabuf_put_be16(msg, WPS_UUID_LEN);
+ wpabuf_put_data(msg, uuid_r, WPS_UUID_LEN);
+ return 0;
+}
+
+
void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
u16 sel_reg_config_methods)
{
@@ -1363,7 +1372,9 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
wps_er_build_selected_registrar(msg, sel_reg) ||
wps_er_build_dev_password_id(msg, dev_passwd_id) ||
wps_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) ||
- wps_build_version2(msg)) {
+ wps_build_version2(msg) ||
+ wps_build_authorized_macs(er->wps->registrar, msg) ||
+ wps_er_build_uuid_r(msg, er->wps->uuid)) {
wpabuf_free(msg);
return;
}
@@ -1690,7 +1701,7 @@ int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
return -1;
/* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
- wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+ wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
return 0;
}
@@ -1751,7 +1762,7 @@ int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
return -1;
/* TODO: add PIN without SetSelectedRegistrar trigger to all APs */
- wps_registrar_add_pin(er->wps->registrar, uuid, pin, pin_len, 0);
+ wps_registrar_add_pin(er->wps->registrar, NULL, uuid, pin, pin_len, 0);
return 0;
}
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 4456ca7..d4378c3 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -275,6 +275,7 @@ int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
int wps_device_store(struct wps_registrar *reg,
struct wps_device_data *dev, const u8 *uuid);
void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
+int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg);
/* ndef.c */
struct wpabuf * ndef_parse_wifi(struct wpabuf *buf);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index dff8753..cbe8a72 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -39,6 +39,7 @@ struct wps_uuid_pin {
#define PIN_EXPIRES BIT(1)
int flags;
struct os_time expiration;
+ u8 enrollee_addr[ETH_ALEN];
};
@@ -127,6 +128,9 @@ struct wps_registrar {
struct wps_registrar_device *devices;
int force_pbc_overlap;
+
+ u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
+ u8 authorized_macs_union[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
};
@@ -136,6 +140,38 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
void *timeout_ctx);
+static void wps_registrar_add_authorized_mac(struct wps_registrar *reg,
+ const u8 *addr)
+{
+ int i;
+ for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+ if (os_memcmp(reg->authorized_macs[i], addr, ETH_ALEN) == 0)
+ return; /* already in list */
+ for (i = WPS_MAX_AUTHORIZED_MACS - 1; i > 0; i--)
+ os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i - 1],
+ ETH_ALEN);
+ os_memcpy(reg->authorized_macs[0], addr, ETH_ALEN);
+}
+
+
+static void wps_registrar_remove_authorized_mac(struct wps_registrar *reg,
+ const u8 *addr)
+{
+ int i;
+ for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++) {
+ if (os_memcmp(reg->authorized_macs, addr, ETH_ALEN) == 0)
+ break;
+ }
+ if (i == WPS_MAX_AUTHORIZED_MACS)
+ return; /* not in the list */
+ for (; i + 1 < WPS_MAX_AUTHORIZED_MACS; i++)
+ os_memcpy(reg->authorized_macs[i], reg->authorized_macs[i + 1],
+ ETH_ALEN);
+ os_memset(reg->authorized_macs[WPS_MAX_AUTHORIZED_MACS - 1], 0,
+ ETH_ALEN);
+}
+
+
static void wps_free_devices(struct wps_registrar_device *dev)
{
struct wps_registrar_device *prev;
@@ -426,6 +462,28 @@ static int wps_build_config_methods_r(struct wps_registrar *reg,
}
+int wps_build_authorized_macs(struct wps_registrar *reg, struct wpabuf *msg)
+{
+ int count = 0;
+
+ while (count < WPS_MAX_AUTHORIZED_MACS) {
+ if (is_zero_ether_addr(reg->authorized_macs_union[count]))
+ break;
+ count++;
+ }
+
+ if (count == 0)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)", count);
+ wpabuf_put_be16(msg, ATTR_AUTHORIZED_MACS);
+ wpabuf_put_be16(msg, count * ETH_ALEN);
+ wpabuf_put_data(msg, reg->authorized_macs_union, count * ETH_ALEN);
+
+ return 0;
+}
+
+
/**
* wps_registrar_init - Initialize WPS Registrar data
* @wps: Pointer to longterm WPS context
@@ -499,20 +557,24 @@ void wps_registrar_deinit(struct wps_registrar *reg)
/**
* wps_registrar_add_pin - Configure a new PIN for Registrar
* @reg: Registrar data from wps_registrar_init()
+ * @addr: Enrollee MAC address or %NULL if not known
* @uuid: UUID-E or %NULL for wildcard (any UUID)
* @pin: PIN (Device Password)
* @pin_len: Length of pin in octets
* @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
* Returns: 0 on success, -1 on failure
*/
-int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
- const u8 *pin, size_t pin_len, int timeout)
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+ const u8 *uuid, const u8 *pin, size_t pin_len,
+ int timeout)
{
struct wps_uuid_pin *p;
p = os_zalloc(sizeof(*p));
if (p == NULL)
return -1;
+ if (addr)
+ os_memcpy(p->enrollee_addr, addr, ETH_ALEN);
if (uuid == NULL)
p->wildcard_uuid = 1;
else
@@ -539,6 +601,8 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
reg->selected_registrar = 1;
reg->pbc = 0;
+ if (addr)
+ wps_registrar_add_authorized_mac(reg, addr);
wps_registrar_selected_registrar_changed(reg);
eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
@@ -561,7 +625,10 @@ static void wps_registrar_expire_pins(struct wps_registrar *reg)
os_time_before(&pin->expiration, &now)) {
wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
pin->uuid, WPS_UUID_LEN);
+ wps_registrar_remove_authorized_mac(
+ reg, pin->enrollee_addr);
wps_remove_pin(pin);
+ wps_registrar_selected_registrar_changed(reg);
}
}
}
@@ -582,7 +649,10 @@ int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid)
if (os_memcmp(pin->uuid, uuid, WPS_UUID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "WPS: Invalidated PIN for UUID",
pin->uuid, WPS_UUID_LEN);
+ wps_registrar_remove_authorized_mac(
+ reg, pin->enrollee_addr);
wps_remove_pin(pin);
+ wps_registrar_selected_registrar_changed(reg);
return 0;
}
}
@@ -901,17 +971,17 @@ static int wps_set_ie(struct wps_registrar *reg)
if (reg->set_ie_cb == NULL)
return 0;
- wpa_printf(MSG_DEBUG, "WPS: Build Beacon and Probe Response IEs");
-
- beacon = wpabuf_alloc(300);
+ beacon = wpabuf_alloc(400);
if (beacon == NULL)
return -1;
- probe = wpabuf_alloc(400);
+ probe = wpabuf_alloc(500);
if (probe == NULL) {
wpabuf_free(beacon);
return -1;
}
+ wpa_printf(MSG_DEBUG, "WPS: Build Beacon IEs");
+
if (wps_build_version(beacon) ||
wps_build_wps_state(reg->wps, beacon) ||
wps_build_ap_setup_locked(reg->wps, beacon) ||
@@ -919,7 +989,15 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_sel_reg_dev_password_id(reg, beacon) ||
wps_build_sel_reg_config_methods(reg, beacon) ||
wps_build_version2(beacon) ||
- wps_build_version(probe) ||
+ wps_build_authorized_macs(reg, beacon)) {
+ wpabuf_free(beacon);
+ wpabuf_free(probe);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "WPS: Build Probe Response IEs");
+
+ if (wps_build_version(probe) ||
wps_build_wps_state(reg->wps, probe) ||
wps_build_ap_setup_locked(reg->wps, probe) ||
wps_build_selected_registrar(reg, probe) ||
@@ -931,7 +1009,8 @@ static int wps_set_ie(struct wps_registrar *reg)
wps_build_device_attrs(&reg->wps->dev, probe) ||
wps_build_probe_config_methods(reg, probe) ||
wps_build_rf_bands(&reg->wps->dev, probe) ||
- wps_build_version2(probe)) {
+ wps_build_version2(probe) ||
+ wps_build_authorized_macs(reg, probe)) {
wpabuf_free(beacon);
wpabuf_free(probe);
return -1;
@@ -2672,6 +2751,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
} else {
wps_registrar_pin_completed(wps->wps->registrar);
}
+ /* TODO: maintain AuthorizedMACs somewhere separately for each ER and
+ * merge them into APs own list.. */
wps_success_event(wps->wps);
@@ -2767,6 +2848,7 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
struct subscription *s)
{
+ int i, j;
wpa_printf(MSG_DEBUG, "WPS: External Registrar selected (dev_pw_id=%d "
"config_methods=0x%x)",
s->dev_password_id, s->config_methods);
@@ -2776,6 +2858,17 @@ static void wps_registrar_sel_reg_add(struct wps_registrar *reg,
if (reg->sel_reg_config_methods_override == -1)
reg->sel_reg_config_methods_override = 0;
reg->sel_reg_config_methods_override |= s->config_methods;
+ for (i = 0; i < WPS_MAX_AUTHORIZED_MACS; i++)
+ if (is_zero_ether_addr(reg->authorized_macs_union[i]))
+ break;
+ for (j = 0; i < WPS_MAX_AUTHORIZED_MACS && j < WPS_MAX_AUTHORIZED_MACS;
+ j++) {
+ if (is_zero_ether_addr(s->authorized_macs[j]))
+ break;
+ os_memcpy(reg->authorized_macs_union[i],
+ s->authorized_macs[j], ETH_ALEN);
+ i++;
+ }
}
#endif /* CONFIG_WPS_UPNP */
@@ -2821,6 +2914,8 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg)
reg->sel_reg_union = reg->selected_registrar;
reg->sel_reg_dev_password_id_override = -1;
reg->sel_reg_config_methods_override = -1;
+ os_memcpy(reg->authorized_macs_union, reg->authorized_macs,
+ WPS_MAX_AUTHORIZED_MACS * ETH_ALEN);
if (reg->selected_registrar) {
reg->sel_reg_config_methods_override =
reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c
index d0bcc28..501dacb 100644
--- a/src/wps/wps_upnp_ap.c
+++ b/src/wps/wps_upnp_ap.c
@@ -46,6 +46,7 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
s->reg = reg;
eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);
+ os_memset(s->authorized_macs, 0, sizeof(s->authorized_macs));
if (attr.selected_registrar == NULL || *attr.selected_registrar == 0) {
wpa_printf(MSG_DEBUG, "WPS: SetSelectedRegistrar: Disable "
"Selected Registrar");
@@ -56,6 +57,13 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg,
WPA_GET_BE16(attr.dev_password_id) : DEV_PW_DEFAULT;
s->config_methods = attr.sel_reg_config_methods ?
WPA_GET_BE16(attr.sel_reg_config_methods) : -1;
+ if (attr.authorized_macs) {
+ int count = attr.authorized_macs_len / ETH_ALEN;
+ if (count > WPS_MAX_AUTHORIZED_MACS)
+ count = WPS_MAX_AUTHORIZED_MACS;
+ os_memcpy(s->authorized_macs, attr.authorized_macs,
+ count * ETH_ALEN);
+ }
eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
upnp_er_set_selected_timeout, s, NULL);
}
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index b31875a..918a12a 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -96,6 +96,7 @@ struct subscription {
u8 selected_registrar;
u16 dev_password_id;
u16 config_methods;
+ u8 authorized_macs[WPS_MAX_AUTHORIZED_MACS][ETH_ALEN];
struct wps_registrar *reg;
};