diff --git a/src/wps/wps.c b/src/wps/wps.c index f7ff2496e..533cbaf67 100644 --- a/src/wps/wps.c +++ b/src/wps/wps.c @@ -307,7 +307,8 @@ struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type) wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); if (wps_build_version(ie) || - wps_build_req_type(ie, req_type)) { + wps_build_req_type(ie, req_type) || + wps_build_version2(ie)) { wpabuf_free(ie); return NULL; } @@ -340,7 +341,8 @@ struct wpabuf * wps_build_assoc_resp_ie(void) wpabuf_put_be32(ie, WPS_DEV_OUI_WFA); if (wps_build_version(ie) || - wps_build_resp_type(ie, WPS_RESP_AP)) { + wps_build_resp_type(ie, WPS_RESP_AP) || + wps_build_version2(ie)) { wpabuf_free(ie); return NULL; } @@ -401,7 +403,8 @@ struct wpabuf * wps_build_probe_req_ie(int pbc, struct wps_device_data *dev, wps_build_assoc_state(NULL, ie) || wps_build_config_error(ie, WPS_CFG_NO_ERROR) || wps_build_dev_password_id(ie, pbc ? DEV_PW_PUSHBUTTON : - DEV_PW_DEFAULT)) { + DEV_PW_DEFAULT) || + wps_build_version2(ie)) { wpabuf_free(ie); return NULL; } diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index 19ff8218c..4de75df2a 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -158,9 +158,24 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg) int wps_build_version(struct wpabuf *msg) { - wpa_printf(MSG_DEBUG, "WPS: * Version"); + /* + * Note: This attribute is deprecated and set to hardcoded 0x10 for + * backwards compatibility reasons. The real version negotiation is + * done with Version2. + */ + wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)"); wpabuf_put_be16(msg, ATTR_VERSION); wpabuf_put_be16(msg, 1); + wpabuf_put_u8(msg, 0x10); + return 0; +} + + +int wps_build_version2(struct wpabuf *msg) +{ + wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION); + wpabuf_put_be16(msg, ATTR_VERSION2); + wpabuf_put_be16(msg, 1); wpabuf_put_u8(msg, WPS_VERSION); return 0; } diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c index 30b0e7921..24374ecde 100644 --- a/src/wps/wps_attr_parse.c +++ b/src/wps/wps_attr_parse.c @@ -32,6 +32,14 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type, } attr->version = pos; break; + case ATTR_VERSION2: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length " + "%u", len); + return -1; + } + attr->version2 = pos; + break; case ATTR_MSG_TYPE: if (len != 1) { wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type " @@ -399,6 +407,49 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type, } attr->ap_setup_locked = pos; break; + case ATTR_SETTINGS_DELAY_TIME: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay " + "Time length %u", len); + return -1; + } + attr->settings_delay_time = pos; + break; + case ATTR_NETWORK_KEY_SHAREABLE: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key " + "Shareable length %u", len); + return -1; + } + attr->network_key_shareable = pos; + break; + case ATTR_REQUEST_TO_ENROLL: + if (len != 1) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll " + "length %u", len); + return -1; + } + attr->request_to_enroll = pos; + break; + case ATTR_AUTHORIZED_MACS: + attr->authorized_macs = pos; + attr->authorized_macs_len = len; + break; + case ATTR_REQUESTED_DEV_TYPE: + if (len != WPS_DEV_TYPE_LEN) { + wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device " + "Type length %u", len); + return -1; + } + if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) { + wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device " + "Type attribute (max %u types)", + MAX_REQ_DEV_TYPE_COUNT); + break; + } + attr->req_dev_type[attr->num_req_dev_type] = pos; + attr->num_req_dev_type++; + break; default: wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x " "len=%u", type, len); diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index b74853c26..d64f1ae13 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -327,7 +327,9 @@ static struct wpabuf * wps_get_oob_cred(struct wps_context *wps) data.wps = wps; data.auth_type = wps->auth_types; data.encr_type = wps->encr_types; - if (wps_build_version(plain) || wps_build_cred(&data, plain)) { + if (wps_build_version(plain) || + wps_build_cred(&data, plain) || + wps_build_version2(plain)) { wpabuf_free(plain); return NULL; } @@ -358,7 +360,8 @@ static struct wpabuf * wps_get_oob_dev_pwd(struct wps_context *wps) } if (wps_build_version(data) || - wps_build_oob_dev_password(data, wps)) { + wps_build_oob_dev_password(data, wps) || + wps_build_version2(data)) { wpa_printf(MSG_ERROR, "WPS: Build OOB device password " "attribute error"); wpabuf_free(data); diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h index 750ca413e..9f3f15241 100644 --- a/src/wps/wps_defs.h +++ b/src/wps/wps_defs.h @@ -15,7 +15,7 @@ #ifndef WPS_DEFS_H #define WPS_DEFS_H -#define WPS_VERSION 0x10 +#define WPS_VERSION 0x20 /* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */ #define WPS_DH_GROUP 5 @@ -124,7 +124,13 @@ enum wps_attribute { ATTR_KEY_PROVIDED_AUTO = 0x1061, ATTR_802_1X_ENABLED = 0x1062, ATTR_APPSESSIONKEY = 0x1063, - ATTR_WEPTRANSMITKEY = 0x1064 + ATTR_WEPTRANSMITKEY = 0x1064, + ATTR_SETTINGS_DELAY_TIME = 0x1065, + ATTR_NETWORK_KEY_SHAREABLE = 0x1066, + ATTR_VERSION2 = 0x1067, + ATTR_REQUEST_TO_ENROLL = 0x1068, + ATTR_AUTHORIZED_MACS = 0x1069, + ATTR_REQUESTED_DEV_TYPE = 0x106a }; /* Device Password ID */ diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c index dff24d491..262922849 100644 --- a/src/wps/wps_enrollee.c +++ b/src/wps/wps_enrollee.c @@ -146,7 +146,8 @@ static struct wpabuf * wps_build_m1(struct wps_data *wps) wps_build_assoc_state(wps, msg) || wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_config_error(msg, WPS_CFG_NO_ERROR) || - wps_build_os_version(&wps->wps->dev, msg)) { + wps_build_os_version(&wps->wps->dev, msg) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -176,6 +177,7 @@ static struct wpabuf * wps_build_m3(struct wps_data *wps) wps_build_msg_type(msg, WPS_M3) || wps_build_registrar_nonce(wps, msg) || wps_build_e_hash(wps, msg) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(msg); return NULL; @@ -208,6 +210,7 @@ static struct wpabuf * wps_build_m5(struct wps_data *wps) wps_build_e_snonce1(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(plain); wpabuf_free(msg); @@ -310,6 +313,7 @@ static struct wpabuf * wps_build_m7(struct wps_data *wps) (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_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(plain); wpabuf_free(msg); @@ -345,7 +349,8 @@ static struct wpabuf * wps_build_wsc_done(struct wps_data *wps) if (wps_build_version(msg) || wps_build_msg_type(msg, WPS_WSC_DONE) || wps_build_enrollee_nonce(wps, msg) || - wps_build_registrar_nonce(wps, msg)) { + wps_build_registrar_nonce(wps, msg) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -373,7 +378,8 @@ static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps) if (wps_build_version(msg) || wps_build_msg_type(msg, WPS_WSC_ACK) || wps_build_enrollee_nonce(wps, msg) || - wps_build_registrar_nonce(wps, msg)) { + wps_build_registrar_nonce(wps, msg) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -396,7 +402,8 @@ static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps) wps_build_msg_type(msg, WPS_WSC_NACK) || wps_build_enrollee_nonce(wps, msg) || wps_build_registrar_nonce(wps, msg) || - wps_build_config_error(msg, wps->config_error)) { + wps_build_config_error(msg, wps->config_error) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -1011,12 +1018,6 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.enrollee_nonce == NULL || os_memcmp(wps->nonce_e, attr.enrollee_nonce, WPS_NONCE_LEN != 0)) { wpa_printf(MSG_DEBUG, "WPS: Mismatch in enrollee nonce"); @@ -1084,12 +1085,6 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; @@ -1136,12 +1131,6 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c index 6d7455e2e..fdcc1cbbe 100644 --- a/src/wps/wps_er.c +++ b/src/wps/wps_er.c @@ -1362,7 +1362,8 @@ void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id, if (wps_build_version(msg) || 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_er_build_sel_reg_config_methods(msg, sel_reg_config_methods) || + wps_build_version2(msg)) { wpabuf_free(msg); return; } diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h index 50e66f6c2..4456ca7f7 100644 --- a/src/wps/wps_i.h +++ b/src/wps/wps_i.h @@ -122,6 +122,7 @@ struct wps_data { struct wps_parse_attr { /* fixed length fields */ const u8 *version; /* 1 octet */ + const u8 *version2; /* 1 octet */ const u8 *msg_type; /* 1 octet */ const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */ const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */ @@ -162,6 +163,9 @@ struct wps_parse_attr { const u8 *request_type; /* 1 octet */ const u8 *response_type; /* 1 octet */ const u8 *ap_setup_locked; /* 1 octet */ + const u8 *settings_delay_time; /* 1 octet */ + const u8 *network_key_shareable; /* 1 octet (Bool) */ + const u8 *request_to_enroll; /* 1 octet (Bool) */ /* variable length fields */ const u8 *manufacturer; @@ -186,12 +190,18 @@ struct wps_parse_attr { size_t eap_type_len; const u8 *eap_identity; /* <= 64 octets */ size_t eap_identity_len; + const u8 *authorized_macs; /* <= 30 octets */ + size_t authorized_macs_len; /* attributes that can occur multiple times */ #define MAX_CRED_COUNT 10 const u8 *cred[MAX_CRED_COUNT]; size_t cred_len[MAX_CRED_COUNT]; size_t num_cred; + +#define MAX_REQ_DEV_TYPE_COUNT 10 + const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT]; + size_t num_req_dev_type; }; /* wps_common.c */ @@ -228,6 +238,7 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg); int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg, struct wpabuf *plain); int wps_build_version(struct wpabuf *msg); +int wps_build_version2(struct wpabuf *msg); int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type); int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg); int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg); @@ -269,10 +280,4 @@ void wps_registrar_selected_registrar_changed(struct wps_registrar *reg); struct wpabuf * ndef_parse_wifi(struct wpabuf *buf); struct wpabuf * ndef_build_wifi(struct wpabuf *buf); -static inline int wps_version_supported(const u8 *version) -{ - /* Require major version match, but allow minor version differences */ - return version && (*version & 0xf0) == (WPS_VERSION & 0xf0); -} - #endif /* WPS_I_H */ diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 81ddf3a2b..dff875373 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -755,11 +755,6 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr, if (wps_parse_msg(wps_data, &attr) < 0) return; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported ProbeReq WPS IE " - "version 0x%x", attr.version ? *attr.version : 0); - return; - } if (attr.config_methods == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Config Methods attribute in " @@ -923,6 +918,7 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_selected_registrar(reg, beacon) || 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_wps_state(reg->wps, probe) || wps_build_ap_setup_locked(reg->wps, probe) || @@ -934,7 +930,8 @@ static int wps_set_ie(struct wps_registrar *reg) wps_build_uuid_e(probe, reg->wps->uuid) || wps_build_device_attrs(®->wps->dev, probe) || wps_build_probe_config_methods(reg, probe) || - wps_build_rf_bands(®->wps->dev, probe)) { + wps_build_rf_bands(®->wps->dev, probe) || + wps_build_version2(probe)) { wpabuf_free(beacon); wpabuf_free(probe); return -1; @@ -1350,6 +1347,7 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps) wps_build_config_error(msg, WPS_CFG_NO_ERROR) || wps_build_dev_password_id(msg, wps->dev_pw_id) || wps_build_os_version(&wps->wps->dev, msg) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(msg); return NULL; @@ -1388,7 +1386,8 @@ static struct wpabuf * wps_build_m2d(struct wps_data *wps) wps_build_rf_bands(&wps->wps->dev, msg) || wps_build_assoc_state(wps, msg) || wps_build_config_error(msg, err) || - wps_build_os_version(&wps->wps->dev, msg)) { + wps_build_os_version(&wps->wps->dev, msg) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -1423,6 +1422,7 @@ static struct wpabuf * wps_build_m4(struct wps_data *wps) wps_build_r_snonce1(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(plain); wpabuf_free(msg); @@ -1457,6 +1457,7 @@ static struct wpabuf * wps_build_m6(struct wps_data *wps) wps_build_r_snonce2(wps, plain) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(plain); wpabuf_free(msg); @@ -1493,6 +1494,7 @@ static struct wpabuf * wps_build_m8(struct wps_data *wps) (!wps->wps->ap && !wps->er && wps_build_ap_settings(wps, plain)) || wps_build_key_wrap_auth(wps, plain) || wps_build_encr_settings(wps, msg, plain) || + wps_build_version2(msg) || wps_build_authenticator(wps, msg)) { wpabuf_free(plain); wpabuf_free(msg); @@ -1518,7 +1520,8 @@ static struct wpabuf * wps_build_wsc_ack(struct wps_data *wps) if (wps_build_version(msg) || wps_build_msg_type(msg, WPS_WSC_ACK) || wps_build_enrollee_nonce(wps, msg) || - wps_build_registrar_nonce(wps, msg)) { + wps_build_registrar_nonce(wps, msg) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -1541,7 +1544,8 @@ static struct wpabuf * wps_build_wsc_nack(struct wps_data *wps) wps_build_msg_type(msg, WPS_WSC_NACK) || wps_build_enrollee_nonce(wps, msg) || wps_build_registrar_nonce(wps, msg) || - wps_build_config_error(msg, wps->config_error)) { + wps_build_config_error(msg, wps->config_error) || + wps_build_version2(msg)) { wpabuf_free(msg); return NULL; } @@ -2362,12 +2366,6 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; @@ -2438,12 +2436,6 @@ static enum wps_process_res wps_process_wsc_ack(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; @@ -2515,12 +2507,6 @@ static enum wps_process_res wps_process_wsc_nack(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; @@ -2600,12 +2586,6 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps, if (wps_parse_msg(msg, &attr) < 0) return WPS_FAILURE; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported message version 0x%x", - attr.version ? *attr.version : 0); - return WPS_FAILURE; - } - if (attr.msg_type == NULL) { wpa_printf(MSG_DEBUG, "WPS: No Message Type attribute"); return WPS_FAILURE; diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c index f99b8592c..6da349881 100644 --- a/src/wps/wps_upnp.c +++ b/src/wps/wps_upnp.c @@ -578,6 +578,7 @@ static struct wpabuf * build_fake_wsc_ack(void) wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE); wpabuf_put_be16(msg, WPS_NONCE_LEN); wpabuf_put(msg, WPS_NONCE_LEN); + wps_build_version2(msg); return msg; } diff --git a/src/wps/wps_upnp_ap.c b/src/wps/wps_upnp_ap.c index 93746dae1..d0bcc2886 100644 --- a/src/wps/wps_upnp_ap.c +++ b/src/wps/wps_upnp_ap.c @@ -42,11 +42,6 @@ int upnp_er_set_selected_registrar(struct wps_registrar *reg, if (wps_parse_msg(msg, &attr) < 0) return -1; - if (!wps_version_supported(attr.version)) { - wpa_printf(MSG_DEBUG, "WPS: Unsupported SetSelectedRegistrar " - "version 0x%x", attr.version ? *attr.version : 0); - return -1; - } s->reg = reg; eloop_cancel_timeout(upnp_er_set_selected_timeout, s, NULL);