#include "sha256.h"
#include "wps_i.h"
#include "wps_dev_attr.h"
+#include "crypto.h"
static int wps_build_mac_addr(struct wps_data *wps, struct wpabuf *msg)
static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
{
- wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State");
+ u8 state;
+ if (wps->wps->ap)
+ state = wps->wps->wps_state;
+ else
+ state = WPS_STATE_NOT_CONFIGURED;
+ wpa_printf(MSG_DEBUG, "WPS: * Wi-Fi Protected Setup State (%d)",
+ state);
wpabuf_put_be16(msg, ATTR_WPS_STATE);
wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, WPS_STATE_CONFIGURED);
+ wpabuf_put_u8(msg, state);
return 0;
}
return NULL;
methods = WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+#ifdef CONFIG_WPS_UFD
+ methods |= WPS_CONFIG_USBA;
+#endif /* CONFIG_WPS_UFD */
+#ifdef CONFIG_WPS_NFC
+ methods |= WPS_CONFIG_NFC_INTERFACE;
+#endif /* CONFIG_WPS_NFC */
if (wps->pbc)
methods |= WPS_CONFIG_PUSHBUTTON;
}
+static int wps_build_ap_settings(struct wps_data *wps, struct wpabuf *plain)
+{
+ if (wps->wps->ap_settings) {
+ wpa_printf(MSG_DEBUG, "WPS: * AP Settings (pre-configured)");
+ wpabuf_put_data(plain, wps->wps->ap_settings,
+ wps->wps->ap_settings_len);
+ return 0;
+ }
+
+ return wps_build_cred_ssid(wps, plain) ||
+ wps_build_cred_mac_addr(wps, plain) ||
+ wps_build_cred_auth_type(wps, plain) ||
+ wps_build_cred_encr_type(wps, plain) ||
+ wps_build_cred_network_key(wps, plain);
+}
+
+
static struct wpabuf * wps_build_m7(struct wps_data *wps)
{
struct wpabuf *msg, *plain;
wpa_printf(MSG_DEBUG, "WPS: Building Message M7");
- plain = wpabuf_alloc(500);
+ plain = wpabuf_alloc(500 + wps->wps->ap_settings_len);
if (plain == NULL)
return NULL;
- msg = wpabuf_alloc(1000);
+ msg = wpabuf_alloc(1000 + wps->wps->ap_settings_len);
if (msg == NULL) {
wpabuf_free(plain);
return NULL;
wps_build_msg_type(msg, WPS_M7) ||
wps_build_registrar_nonce(wps, msg) ||
wps_build_e_snonce2(wps, plain) ||
- (wps->authenticator &&
- (wps_build_cred_ssid(wps, plain) ||
- wps_build_cred_mac_addr(wps, plain) ||
- wps_build_cred_auth_type(wps, plain) ||
- wps_build_cred_encr_type(wps, plain) ||
- wps_build_cred_network_key(wps, plain))) ||
+ (wps->wps->ap && wps_build_ap_settings(wps, plain)) ||
wps_build_key_wrap_auth(wps, plain) ||
wps_build_encr_settings(wps, msg, plain) ||
wps_build_authenticator(wps, msg)) {
}
wpabuf_free(plain);
+ if (wps->wps->ap && wps->wps->registrar) {
+ /*
+ * If the Registrar is only learning our current configuration,
+ * it may not continue protocol run to successful completion.
+ * Store information here to make sure it remains available.
+ */
+ wps_device_store(wps->wps->registrar, &wps->peer_dev,
+ wps->uuid_r);
+ }
+
wps->state = RECV_M8;
return msg;
}
return NULL;
}
- if (wps->authenticator)
+ if (wps->wps->ap)
wps->state = RECV_ACK;
else {
wps_success_event(wps->wps);
*op_code = WSC_MSG;
break;
case RECEIVED_M2D:
- if (wps->authenticator) {
+ if (wps->wps->ap) {
msg = wps_build_wsc_nack(wps);
*op_code = WSC_NACK;
break;
return -1;
}
+#ifdef CONFIG_WPS_OOB
+ if (wps->dev_pw_id != DEV_PW_DEFAULT &&
+ wps->wps->oob_conf.pubkey_hash) {
+ const u8 *addr[1];
+ u8 hash[WPS_HASH_LEN];
+
+ addr[0] = pk;
+ sha256_vector(1, addr, &pk_len, hash);
+ if (os_memcmp(hash,
+ wpabuf_head(wps->wps->oob_conf.pubkey_hash),
+ WPS_OOB_PUBKEY_HASH_LEN) != 0) {
+ wpa_printf(MSG_ERROR, "WPS: Public Key hash error");
+ return -1;
+ }
+ }
+#endif /* CONFIG_WPS_OOB */
+
wpabuf_free(wps->dh_pubkey_r);
wps->dh_pubkey_r = wpabuf_alloc_copy(pk, pk_len);
if (wps->dh_pubkey_r == NULL)
if (wps_derive_keys(wps) < 0)
return -1;
- if (wps->request_type == WPS_REQ_WLAN_MANAGER_REGISTRAR &&
- wps_derive_mgmt_keys(wps) < 0)
- return -1;
-
return 0;
}
wpa_printf(MSG_DEBUG, "WPS: R-Hash1 derived from R-S1 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 1, 1);
return -1;
}
wpa_printf(MSG_DEBUG, "WPS: R-Hash2 derived from R-S2 does "
"not match with the pre-committed value");
wps->config_error = WPS_CFG_DEV_PASSWORD_AUTH_FAILURE;
+ wps_pwd_auth_fail_event(wps->wps, 1, 2);
return -1;
}
wps_process_cred(&attr, &wps->cred))
return -1;
- if (wps->wps->cred_cb)
+ if (wps->wps->cred_cb) {
+ wps->cred.cred_attr = cred - 4;
+ wps->cred.cred_attr_len = cred_len + 4;
wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+ wps->cred.cred_attr = NULL;
+ wps->cred.cred_attr_len = 0;
+ }
return 0;
}
{
size_t i;
- if (wps->authenticator)
+ if (wps->wps->ap)
return 0;
if (num_cred == 0) {
static int wps_process_ap_settings_e(struct wps_data *wps,
- struct wps_parse_attr *attr)
+ struct wps_parse_attr *attr,
+ struct wpabuf *attrs)
{
struct wps_credential cred;
- if (!wps->authenticator)
+ if (!wps->wps->ap)
return 0;
if (wps_process_ap_settings(attr, &cred) < 0)
wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
"Registrar");
- if (wps->wps->cred_cb)
+ if (wps->wps->cred_cb) {
+ cred.cred_attr = wpabuf_head(attrs);
+ cred.cred_attr_len = wpabuf_len(attrs);
wps->wps->cred_cb(wps->wps->cb_ctx, &cred);
+ }
return 0;
}
wps_process_enrollee_nonce(wps, attr->enrollee_nonce) ||
wps_process_uuid_r(wps, attr->uuid_r) ||
wps_process_pubkey(wps, attr->public_key, attr->public_key_len) ||
- wps_process_authenticator(wps, attr->authenticator, msg)) {
+ wps_process_authenticator(wps, attr->authenticator, msg) ||
+ wps_process_device_attrs(&wps->peer_dev, attr)) {
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
}
- if (wps->authenticator && wps->wps->ap_setup_locked) {
+ if (wps->wps->ap && wps->wps->ap_setup_locked) {
wpa_printf(MSG_DEBUG, "WPS: AP Setup is locked - refuse "
"registration of a new Registrar");
wps->config_error = WPS_CFG_SETUP_LOCKED;
wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
wps_process_creds(wps, eattr.cred, eattr.cred_len,
eattr.num_cred) ||
- wps_process_ap_settings_e(wps, &eattr)) {
+ wps_process_ap_settings_e(wps, &eattr, decrypted)) {
wpabuf_free(decrypted);
wps->state = SEND_WSC_NACK;
return WPS_CONTINUE;
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
return WPS_FAILURE;
}
- if (ret == WPS_CONTINUE) {
+ /*
+ * Save a copy of the last message for Authenticator derivation if we
+ * are continuing. However, skip M2D since it is not authenticated and
+ * neither is the ACK/NACK response frame. This allows the possibly
+ * following M2 to be processed correctly by using the previously sent
+ * M1 in Authenticator derivation.
+ */
+ if (ret == WPS_CONTINUE && *attr.msg_type != WPS_M2D) {
/* Save a copy of the last message for Authenticator derivation
*/
wpabuf_free(wps->last_msg);
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
return WPS_FAILURE;
}
- if (wps->state == RECV_ACK && wps->authenticator) {
+ if (wps->state == RECV_ACK && wps->wps->ap) {
wpa_printf(MSG_DEBUG, "WPS: External Registrar registration "
"completed successfully");
wps_success_event(wps->wps);
if (wps_parse_msg(msg, &attr) < 0)
return WPS_FAILURE;
- if (attr.version == NULL || *attr.version != WPS_VERSION) {
+ if (!wps_version_supported(attr.version)) {
wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x",
attr.version ? *attr.version : 0);
return WPS_FAILURE;
"op_code=%d)",
(unsigned long) wpabuf_len(msg), op_code);
+ if (op_code == WSC_UPnP) {
+ /* Determine the OpCode based on message type attribute */
+ struct wps_parse_attr attr;
+ if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
+ if (*attr.msg_type == WPS_WSC_ACK)
+ op_code = WSC_ACK;
+ else if (*attr.msg_type == WPS_WSC_NACK)
+ op_code = WSC_NACK;
+ }
+ }
+
switch (op_code) {
case WSC_MSG:
+ case WSC_UPnP:
return wps_process_wsc_msg(wps, msg);
case WSC_ACK:
return wps_process_wsc_ack(wps, msg);