aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/Makefile5
-rw-r--r--src/ap/drv_callbacks.c14
-rw-r--r--src/ap/ieee802_11.c5
-rw-r--r--src/ap/wps_hostapd.c4
-rw-r--r--src/wps/wps.h135
-rw-r--r--src/wps/wps_enrollee.c32
-rw-r--r--src/wps/wps_registrar.c26
-rw-r--r--src/wps/wps_validate.c1852
-rw-r--r--wpa_supplicant/Makefile5
-rw-r--r--wpa_supplicant/events.c22
-rw-r--r--wpa_supplicant/scan.c34
-rw-r--r--wpa_supplicant/scan.h2
-rw-r--r--wpa_supplicant/wps_supplicant.c22
13 files changed, 2158 insertions, 0 deletions
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 6d344d2..2361c0e 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -327,6 +327,11 @@ OBJS += ../src/wps/wps_nfc_pn531.o
LIBS += ${PN531_PATH}/lib/wpsnfc.dll
LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
endif
ifdef NEED_WPS_OOB
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 26ef584..1e02706 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -20,6 +20,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "wps/wps.h"
#include "hostapd.h"
#include "ieee802_11.h"
#include "sta_info.h"
@@ -139,6 +140,19 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
return -1;
}
} else if (hapd->conf->wps_state) {
+#ifdef CONFIG_WPS_STRICT
+ struct wpabuf *wps;
+ wps = ieee802_11_vendor_ie_concat(ie, ielen,
+ WPS_IE_VENDOR_TYPE);
+ if (wps && wps_validate_assoc_req(wps) < 0) {
+ hapd->drv.sta_disassoc(hapd, sta->addr,
+ WLAN_REASON_INVALID_IE);
+ ap_free_sta(hapd, sta);
+ wpabuf_free(wps);
+ return -1;
+ }
+ wpabuf_free(wps);
+#endif /* CONFIG_WPS_STRICT */
if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
sta->flags |= WLAN_STA_WPS;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index b9f8564..5681bb5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -664,6 +664,11 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
WPS_IE_VENDOR_TYPE);
wpa_ie = NULL;
wpa_ie_len = 0;
+ if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
+ "(Re)Association Request - reject");
+ return WLAN_STATUS_INVALID_IE;
+ }
} else if (hapd->conf->wps_state && wpa_ie == NULL) {
wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
"(Re)Association Request - possible WPS use");
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 0698a8f..c01554d 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -820,6 +820,10 @@ static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
if (wps_ie == NULL)
return 0;
+ if (wps_validate_probe_req(wps_ie) < 0) {
+ wpabuf_free(wps_ie);
+ return 0;
+ }
if (wpabuf_len(wps_ie) > 0) {
wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie);
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 31be0b5..3364a04 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -751,4 +751,139 @@ char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
u16 wps_config_methods_str2bin(const char *str);
+#ifdef CONFIG_WPS_STRICT
+int wps_validate_beacon(const struct wpabuf *wps_ie);
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe);
+int wps_validate_probe_req(const struct wpabuf *wps_ie);
+int wps_validate_assoc_req(const struct wpabuf *wps_ie);
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie);
+int wps_validate_m1(const struct wpabuf *tlvs);
+int wps_validate_m2(const struct wpabuf *tlvs);
+int wps_validate_m2d(const struct wpabuf *tlvs);
+int wps_validate_m3(const struct wpabuf *tlvs);
+int wps_validate_m4(const struct wpabuf *tlvs);
+int wps_validate_m4_encr(const struct wpabuf *tlvs);
+int wps_validate_m5(const struct wpabuf *tlvs);
+int wps_validate_m5_encr(const struct wpabuf *tlvs);
+int wps_validate_m6(const struct wpabuf *tlvs);
+int wps_validate_m6_encr(const struct wpabuf *tlvs);
+int wps_validate_m7(const struct wpabuf *tlvs);
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap);
+int wps_validate_m8(const struct wpabuf *tlvs);
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap);
+int wps_validate_wsc_ack(const struct wpabuf *tlvs);
+int wps_validate_wsc_nack(const struct wpabuf *tlvs);
+int wps_validate_wsc_done(const struct wpabuf *tlvs);
+#else /* CONFIG_WPS_STRICT */
+static inline int wps_validate_beacon(const struct wpabuf *wps_ie){
+ return 0;
+}
+
+static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,
+ int probe)
+{
+ return 0;
+}
+
+static inline int wps_validate_probe_req(const struct wpabuf *wps_ie)
+{
+ return 0;
+}
+
+static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+ return 0;
+}
+
+static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+ return 0;
+}
+
+static inline int wps_validate_m1(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m2(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m3(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m4(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m4_encr(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m5(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m5_encr(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m6(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m6_encr(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m7(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap)
+{
+ return 0;
+}
+
+static inline int wps_validate_m8(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap)
+{
+ return 0;
+}
+
+static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+
+static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+ return 0;
+}
+#endif /* CONFIG_WPS_STRICT */
+
#endif /* WPS_H */
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 550b1f6..8f915b2 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -975,6 +975,12 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps_validate_m4_encr(decrypted) < 0) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
"attribute");
if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -1022,6 +1028,12 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps_validate_m6_encr(decrypted) < 0) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
"attribute");
if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -1069,6 +1081,12 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps_validate_m8_encr(decrypted, wps->wps->ap) < 0) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
"attribute");
if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -1112,22 +1130,32 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
switch (*attr.msg_type) {
case WPS_M2:
+ if (wps_validate_m2(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m2(wps, msg, &attr);
break;
case WPS_M2D:
+ if (wps_validate_m2d(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m2d(wps, &attr);
break;
case WPS_M4:
+ if (wps_validate_m4(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m4(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M4);
break;
case WPS_M6:
+ if (wps_validate_m6(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m6(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M6);
break;
case WPS_M8:
+ if (wps_validate_m8(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m8(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M8);
@@ -1300,8 +1328,12 @@ enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
case WSC_UPnP:
return wps_process_wsc_msg(wps, msg);
case WSC_ACK:
+ if (wps_validate_wsc_ack(msg) < 0)
+ return WPS_FAILURE;
return wps_process_wsc_ack(wps, msg);
case WSC_NACK:
+ if (wps_validate_wsc_nack(msg) < 0)
+ return WPS_FAILURE;
return wps_process_wsc_nack(wps, msg);
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 9574fca..a907eef 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -2288,6 +2288,12 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps_validate_m5_encr(decrypted) < 0) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
"attribute");
if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -2411,6 +2417,12 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps_validate_m7_encr(decrypted, wps->wps->ap || wps->er) < 0) {
+ wpabuf_free(decrypted);
+ wps->state = SEND_WSC_NACK;
+ return WPS_CONTINUE;
+ }
+
wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
"attribute");
if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -2455,6 +2467,8 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
switch (*attr.msg_type) {
case WPS_M1:
+ if (wps_validate_m1(msg) < 0)
+ return WPS_FAILURE;
#ifdef CONFIG_WPS_UPNP
if (wps->wps->wps_upnp && attr.mac_addr) {
/* Remove old pending messages when starting new run */
@@ -2469,16 +2483,22 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
ret = wps_process_m1(wps, &attr);
break;
case WPS_M3:
+ if (wps_validate_m3(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m3(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M3);
break;
case WPS_M5:
+ if (wps_validate_m5(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m5(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M5);
break;
case WPS_M7:
+ if (wps_validate_m7(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_m7(wps, msg, &attr);
if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
wps_fail_event(wps->wps, WPS_M7);
@@ -2803,10 +2823,16 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
case WSC_MSG:
return wps_process_wsc_msg(wps, msg);
case WSC_ACK:
+ if (wps_validate_wsc_ack(msg) < 0)
+ return WPS_FAILURE;
return wps_process_wsc_ack(wps, msg);
case WSC_NACK:
+ if (wps_validate_wsc_nack(msg) < 0)
+ return WPS_FAILURE;
return wps_process_wsc_nack(wps, msg);
case WSC_Done:
+ if (wps_validate_wsc_done(msg) < 0)
+ return WPS_FAILURE;
ret = wps_process_wsc_done(wps, msg);
if (ret == WPS_FAILURE) {
wps->state = SEND_WSC_NACK;
diff --git a/src/wps/wps_validate.c b/src/wps/wps_validate.c
new file mode 100644
index 0000000..dfd9cd0
--- /dev/null
+++ b/src/wps/wps_validate.c
@@ -0,0 +1,1852 @@
+/*
+ * Wi-Fi Protected Setup - Strict protocol validation routines
+ * Copyright (c) 2010, Atheros Communications, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "wps_i.h"
+#include "wps.h"
+
+
+static int wps_validate_version(const u8 *version, int mandatory)
+{
+ if (version == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Version attribute "
+ "missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*version != 0x10) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version attribute "
+ "value 0x%x", *version);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_version2(const u8 *version2, int mandatory)
+{
+ if (version2 == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Version2 attribute "
+ "missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*version2 < 0x20) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Version2 attribute "
+ "value 0x%x", *version2);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_request_type(const u8 *request_type, int mandatory)
+{
+ if (request_type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Request Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*request_type > 0x03) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request Type "
+ "attribute value 0x%x", *request_type);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_response_type(const u8 *response_type, int mandatory)
+{
+ if (response_type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Response Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*response_type > 0x03) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Response Type "
+ "attribute value 0x%x", *response_type);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int valid_config_methods(u16 val, int wps2)
+{
+ if (wps2) {
+ if ((val & 0x6000) && !(val & WPS_CONFIG_DISPLAY)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+ "Display flag without old Display flag "
+ "set");
+ return 0;
+ }
+ if (!(val & 0x6000) && (val & WPS_CONFIG_DISPLAY)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Display flag "
+ "without Physical/Virtual Display flag");
+ return 0;
+ }
+ if ((val & 0x0600) && !(val & WPS_CONFIG_PUSHBUTTON)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Physical/Virtual "
+ "PushButton flag without old PushButton "
+ "flag set");
+ return 0;
+ }
+ if (!(val & 0x0600) && (val & WPS_CONFIG_PUSHBUTTON)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: PushButton flag "
+ "without Physical/Virtual PushButton flag");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static int wps_validate_config_methods(const u8 *config_methods, int wps2,
+ int mandatory)
+{
+ u16 val;
+
+ if (config_methods == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Configuration "
+ "Methods attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+
+ val = WPA_GET_BE16(config_methods);
+ if (!valid_config_methods(val, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+ "Methods attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_ap_config_methods(const u8 *config_methods, int wps2,
+ int mandatory)
+{
+ u16 val;
+
+ if (wps_validate_config_methods(config_methods, wps2, mandatory) < 0)
+ return -1;
+ if (config_methods == NULL)
+ return 0;
+ val = WPA_GET_BE16(config_methods);
+ if (val & WPS_CONFIG_PUSHBUTTON) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration "
+ "Methods attribute value 0x%04x in AP info "
+ "(PushButton not allowed for registering new ER)",
+ val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_uuid_e(const u8 *uuid_e, int mandatory)
+{
+ if (uuid_e == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: UUID-E "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_uuid_r(const u8 *uuid_r, int mandatory)
+{
+ if (uuid_r == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: UUID-R "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_primary_dev_type(const u8 *primary_dev_type,
+ int mandatory)
+{
+ if (primary_dev_type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Primary Device Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_rf_bands(const u8 *rf_bands, int mandatory)
+{
+ if (rf_bands == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: RF Bands "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*rf_bands != WPS_RF_24GHZ && *rf_bands != WPS_RF_50GHZ &&
+ *rf_bands != (WPS_RF_24GHZ | WPS_RF_50GHZ)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Rf Bands "
+ "attribute value 0x%x", *rf_bands);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_assoc_state(const u8 *assoc_state, int mandatory)
+{
+ u16 val;
+ if (assoc_state == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Association State "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(assoc_state);
+ if (val > 4) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Association State "
+ "attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_config_error(const u8 *config_error, int mandatory)
+{
+ u16 val;
+
+ if (config_error == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Configuration Error "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(config_error);
+ if (val > 18) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Configuration Error "
+ "attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_dev_password_id(const u8 *dev_password_id,
+ int mandatory)
+{
+ u16 val;
+
+ if (dev_password_id == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Device Password ID "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(dev_password_id);
+ if (val >= 0x0006 && val <= 0x000f) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Device Password ID "
+ "attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_manufacturer(const u8 *manufacturer, size_t len,
+ int mandatory)
+{
+ if (manufacturer == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Manufacturer "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 0 && manufacturer[len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Manufacturer "
+ "attribute value", manufacturer, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_model_name(const u8 *model_name, size_t len,
+ int mandatory)
+{
+ if (model_name == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Model Name "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 0 && model_name[len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Name "
+ "attribute value", model_name, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_model_number(const u8 *model_number, size_t len,
+ int mandatory)
+{
+ if (model_number == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Model Number "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 0 && model_number[len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Model Number "
+ "attribute value", model_number, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_serial_number(const u8 *serial_number, size_t len,
+ int mandatory)
+{
+ if (serial_number == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Serial Number "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 0 && serial_number[len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Serial "
+ "Number attribute value",
+ serial_number, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_dev_name(const u8 *dev_name, size_t len,
+ int mandatory)
+{
+ if (dev_name == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Device Name "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 0 && dev_name[len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid Device Name "
+ "attribute value", dev_name, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_request_to_enroll(const u8 *request_to_enroll,
+ int mandatory)
+{
+ if (request_to_enroll == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Request to Enroll "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*request_to_enroll > 0x01) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Request to Enroll "
+ "attribute value 0x%x", *request_to_enroll);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_req_dev_type(const u8 *req_dev_type[], size_t num,
+ int mandatory)
+{
+ if (num == 0) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Requested Device "
+ "Type attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_wps_state(const u8 *wps_state, int mandatory)
+{
+ if (wps_state == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Wi-Fi Protected "
+ "Setup State attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*wps_state != WPS_STATE_NOT_CONFIGURED &&
+ *wps_state != WPS_STATE_CONFIGURED) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Wi-Fi Protected "
+ "Setup State attribute value 0x%x", *wps_state);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_ap_setup_locked(const u8 *ap_setup_locked,
+ int mandatory)
+{
+ if (ap_setup_locked == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: AP Setup Locked "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*ap_setup_locked > 1) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid AP Setup Locked "
+ "attribute value 0x%x", *ap_setup_locked);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_selected_registrar(const u8 *selected_registrar,
+ int mandatory)
+{
+ if (selected_registrar == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*selected_registrar > 1) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+ "attribute value 0x%x", *selected_registrar);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_sel_reg_config_methods(const u8 *config_methods,
+ int wps2, int mandatory)
+{
+ u16 val;
+
+ if (config_methods == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Selected Registrar "
+ "Configuration Methods attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+
+ val = WPA_GET_BE16(config_methods);
+ if (!valid_config_methods(val, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Selected Registrar "
+ "Configuration Methods attribute value 0x%04x",
+ val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_authorized_macs(const u8 *authorized_macs, size_t len,
+ int mandatory)
+{
+ if (authorized_macs == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Authorized MACs "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len > 30 && (len % ETH_ALEN) != 0) {
+ wpa_hexdump(MSG_INFO, "WPS-STRICT: Invalid Authorized "
+ "MACs attribute value", authorized_macs, len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_msg_type(const u8 *msg_type, int mandatory)
+{
+ if (msg_type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Message Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*msg_type < WPS_Beacon || *msg_type > WPS_WSC_DONE) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Message Type "
+ "attribute value 0x%x", *msg_type);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_mac_addr(const u8 *mac_addr, int mandatory)
+{
+ if (mac_addr == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: MAC Address "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (mac_addr[0] & 0x01) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid MAC Address "
+ "attribute value " MACSTR, MAC2STR(mac_addr));
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_enrollee_nonce(const u8 *enrollee_nonce, int mandatory)
+{
+ if (enrollee_nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Enrollee Nonce "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_registrar_nonce(const u8 *registrar_nonce,
+ int mandatory)
+{
+ if (registrar_nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Registrar Nonce "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_public_key(const u8 *public_key, size_t len,
+ int mandatory)
+{
+ if (public_key == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Public Key "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len != 192) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Public Key "
+ "attribute length %d", (int) len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int num_bits_set(u16 val)
+{
+ int c;
+ for (c = 0; val; c++)
+ val &= val - 1;
+ return c;
+}
+
+
+static int wps_validate_auth_type_flags(const u8 *flags, int mandatory)
+{
+ u16 val;
+
+ if (flags == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+ "Flags attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(flags);
+ if ((val & ~WPS_AUTH_TYPES) || !(val & WPS_AUTH_WPA2PSK)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+ "Flags attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_auth_type(const u8 *type, int mandatory)
+{
+ u16 val;
+
+ if (type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Authentication Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(type);
+ if ((val & ~WPS_AUTH_TYPES) || val == 0 ||
+ (num_bits_set(val) > 1 &&
+ val != (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK))) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Authentication Type "
+ "attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_encr_type_flags(const u8 *flags, int mandatory)
+{
+ u16 val;
+
+ if (flags == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+ "Flags attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(flags);
+ if ((val & ~WPS_ENCR_TYPES) || !(val & WPS_ENCR_AES)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+ "Flags attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_encr_type(const u8 *type, int mandatory)
+{
+ u16 val;
+
+ if (type == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Encryption Type "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ val = WPA_GET_BE16(type);
+ if ((val & ~WPS_ENCR_TYPES) || val == 0 ||
+ (num_bits_set(val) > 1 && val != (WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encryption Type "
+ "attribute value 0x%04x", val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_conn_type_flags(const u8 *flags, int mandatory)
+{
+ if (flags == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Connection Type "
+ "Flags attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if ((*flags & ~(WPS_CONN_ESS | WPS_CONN_IBSS)) ||
+ !(*flags & WPS_CONN_ESS)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Connection Type "
+ "Flags attribute value 0x%02x", *flags);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_os_version(const u8 *os_version, int mandatory)
+{
+ if (os_version == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: OS Version "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_authenticator(const u8 *authenticator, int mandatory)
+{
+ if (authenticator == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Authenticator "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_e_hash1(const u8 *hash, int mandatory)
+{
+ if (hash == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash1 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_e_hash2(const u8 *hash, int mandatory)
+{
+ if (hash == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: E-Hash2 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_r_hash1(const u8 *hash, int mandatory)
+{
+ if (hash == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash1 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_r_hash2(const u8 *hash, int mandatory)
+{
+ if (hash == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: R-Hash2 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_encr_settings(const u8 *encr_settings, size_t len,
+ int mandatory)
+{
+ if (encr_settings == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Encrypted Settings "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (len < 16) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Encrypted Settings "
+ "attribute length %d", (int) len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_settings_delay_time(const u8 *delay, int mandatory)
+{
+ if (delay == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Settings Delay Time "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_r_snonce1(const u8 *nonce, int mandatory)
+{
+ if (nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce1 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_r_snonce2(const u8 *nonce, int mandatory)
+{
+ if (nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: R-SNonce2 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_e_snonce1(const u8 *nonce, int mandatory)
+{
+ if (nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce1 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_e_snonce2(const u8 *nonce, int mandatory)
+{
+ if (nonce == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: E-SNonce2 "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_key_wrap_auth(const u8 *auth, int mandatory)
+{
+ if (auth == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Key Wrap "
+ "Authenticator attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_ssid(const u8 *ssid, size_t ssid_len, int mandatory)
+{
+ if (ssid == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: SSID "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (ssid_len == 0 || ssid[ssid_len - 1] == 0) {
+ wpa_hexdump_ascii(MSG_INFO, "WPS-STRICT: Invalid SSID "
+ "attribute value", ssid, ssid_len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_network_key_index(const u8 *idx, int mandatory)
+{
+ if (idx == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Network Key Index "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_network_idx(const u8 *idx, int mandatory)
+{
+ if (idx == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Network Index "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+static int wps_validate_network_key(const u8 *key, size_t key_len,
+ const u8 *encr_type, int mandatory)
+{
+ if (key == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (((encr_type == NULL || WPA_GET_BE16(encr_type) != WPS_ENCR_WEP) &&
+ key_len > 8 && key_len < 64 && key[key_len - 1] == 0) ||
+ key_len > 64) {
+ wpa_hexdump_ascii_key(MSG_INFO, "WPS-STRICT: Invalid Network "
+ "Key attribute value", key, key_len);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_network_key_shareable(const u8 *val, int mandatory)
+{
+ if (val == NULL) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Network Key "
+ "Shareable attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+ if (*val > 1) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Network Key "
+ "Shareable attribute value 0x%x", *val);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wps_validate_cred(const u8 *cred, size_t len)
+{
+ struct wps_parse_attr attr;
+ struct wpabuf buf;
+
+ if (cred == NULL)
+ return -1;
+ wpabuf_set(&buf, cred, len);
+ if (wps_parse_msg(&buf, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse Credential");
+ return -1;
+ }
+
+ if (wps_validate_network_idx(attr.network_idx, 0) ||
+ wps_validate_ssid(attr.ssid, attr.ssid_len, 1) ||
+ wps_validate_auth_type(attr.auth_type, 1) ||
+ wps_validate_encr_type(attr.encr_type, 1) ||
+ wps_validate_network_key_index(attr.network_key_idx, 0) ||
+ wps_validate_network_key(attr.network_key, attr.network_key_len,
+ attr.encr_type, 1) ||
+ wps_validate_mac_addr(attr.mac_addr, 1) ||
+ wps_validate_network_key_shareable(attr.network_key_shareable, 0))
+ {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Credential");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+static int wps_validate_credential(const u8 *cred[], size_t len[], size_t num,
+ int mandatory)
+{
+ size_t i;
+
+ if (num == 0) {
+ if (mandatory) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Credential "
+ "attribute missing");
+ return -1;
+ }
+ return 0;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (wps_validate_cred(cred[i], len[i]) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_beacon(const struct wpabuf *wps_ie)
+{
+ struct wps_parse_attr attr;
+ int wps2, sel_reg;
+
+ if (wps_ie == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in Beacon frame");
+ return -1;
+ }
+ if (wps_parse_msg(wps_ie, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+ "Beacon frame");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ sel_reg = attr.selected_registrar != NULL &&
+ *attr.selected_registrar != 0;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_wps_state(attr.wps_state, 1) ||
+ wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+ wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+ wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+ wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+ wps2, sel_reg) ||
+ wps_validate_uuid_e(attr.uuid_e, 0) ||
+ wps_validate_rf_bands(attr.rf_bands, 0) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authorized_macs(attr.authorized_macs,
+ attr.authorized_macs_len, 0)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Beacon frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe)
+{
+ struct wps_parse_attr attr;
+ int wps2, sel_reg;
+
+ if (wps_ie == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+ "%sProbe Response frame", probe ? "" : "Beacon/");
+ return -1;
+ }
+ if (wps_parse_msg(wps_ie, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+ "%sProbe Response frame", probe ? "" : "Beacon/");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ sel_reg = attr.selected_registrar != NULL &&
+ *attr.selected_registrar != 0;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_wps_state(attr.wps_state, 1) ||
+ wps_validate_ap_setup_locked(attr.ap_setup_locked, 0) ||
+ wps_validate_selected_registrar(attr.selected_registrar, 0) ||
+ wps_validate_dev_password_id(attr.dev_password_id, sel_reg) ||
+ wps_validate_sel_reg_config_methods(attr.sel_reg_config_methods,
+ wps2, sel_reg) ||
+ wps_validate_response_type(attr.response_type, probe) ||
+ wps_validate_uuid_e(attr.uuid_e, probe) ||
+ wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+ probe) ||
+ wps_validate_model_name(attr.model_name, attr.model_name_len,
+ probe) ||
+ wps_validate_model_number(attr.model_number, attr.model_number_len,
+ probe) ||
+ wps_validate_serial_number(attr.serial_number,
+ attr.serial_number_len, probe) ||
+ wps_validate_primary_dev_type(attr.primary_dev_type, probe) ||
+ wps_validate_dev_name(attr.dev_name, attr.dev_name_len, probe) ||
+ wps_validate_ap_config_methods(attr.config_methods, wps2, probe) ||
+ wps_validate_rf_bands(attr.rf_bands, 0) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authorized_macs(attr.authorized_macs,
+ attr.authorized_macs_len, 0)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid %sProbe Response "
+ "frame", probe ? "" : "Beacon/");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_probe_req(const struct wpabuf *wps_ie)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (wps_ie == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+ "Probe Request frame");
+ return -1;
+ }
+ if (wps_parse_msg(wps_ie, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+ "Probe Request frame");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_request_type(attr.request_type, 1) ||
+ wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+ wps_validate_uuid_e(attr.uuid_e, attr.uuid_r == NULL) ||
+ wps_validate_uuid_r(attr.uuid_r, attr.uuid_e == NULL) ||
+ wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+ wps_validate_rf_bands(attr.rf_bands, 1) ||
+ wps_validate_assoc_state(attr.assoc_state, 1) ||
+ wps_validate_config_error(attr.config_error, 1) ||
+ wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+ wps2) ||
+ wps_validate_model_name(attr.model_name, attr.model_name_len,
+ wps2) ||
+ wps_validate_model_number(attr.model_number, attr.model_number_len,
+ wps2) ||
+ wps_validate_dev_name(attr.dev_name, attr.dev_name_len, wps2) ||
+ wps_validate_request_to_enroll(attr.request_to_enroll, 0) ||
+ wps_validate_req_dev_type(attr.req_dev_type, attr.num_req_dev_type,
+ 0)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid Probe Request "
+ "frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (wps_ie == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+ "(Re)Association Request frame");
+ return -1;
+ }
+ if (wps_parse_msg(wps_ie, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+ "(Re)Association Request frame");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_request_type(attr.request_type, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+ "Request frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (wps_ie == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No WPS IE in "
+ "(Re)Association Response frame");
+ return -1;
+ }
+ if (wps_parse_msg(wps_ie, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse WPS IE in "
+ "(Re)Association Response frame");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_request_type(attr.request_type, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid (Re)Association "
+ "Response frame");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m1(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M1");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M1");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_uuid_e(attr.uuid_e, 1) ||
+ wps_validate_mac_addr(attr.mac_addr, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+ wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+ wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+ wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+ wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+ wps_validate_wps_state(attr.wps_state, 1) ||
+ wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+ 1) ||
+ wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+ wps_validate_model_number(attr.model_number, attr.model_number_len,
+ 1) ||
+ wps_validate_serial_number(attr.serial_number,
+ attr.serial_number_len, 1) ||
+ wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+ wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+ wps_validate_rf_bands(attr.rf_bands, 1) ||
+ wps_validate_assoc_state(attr.assoc_state, 1) ||
+ wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+ wps_validate_config_error(attr.config_error, 1) ||
+ wps_validate_os_version(attr.os_version, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_request_to_enroll(attr.request_to_enroll, 0)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M1");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m2(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M2");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_uuid_r(attr.uuid_r, 1) ||
+ wps_validate_public_key(attr.public_key, attr.public_key_len, 1) ||
+ wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+ wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+ wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+ wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+ wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+ 1) ||
+ wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+ wps_validate_model_number(attr.model_number, attr.model_number_len,
+ 1) ||
+ wps_validate_serial_number(attr.serial_number,
+ attr.serial_number_len, 1) ||
+ wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+ wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+ wps_validate_rf_bands(attr.rf_bands, 1) ||
+ wps_validate_assoc_state(attr.assoc_state, 1) ||
+ wps_validate_config_error(attr.config_error, 1) ||
+ wps_validate_dev_password_id(attr.dev_password_id, 1) ||
+ wps_validate_os_version(attr.os_version, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M2D");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M2D");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_uuid_r(attr.uuid_r, 1) ||
+ wps_validate_auth_type_flags(attr.auth_type_flags, 1) ||
+ wps_validate_encr_type_flags(attr.encr_type_flags, 1) ||
+ wps_validate_conn_type_flags(attr.conn_type_flags, 1) ||
+ wps_validate_config_methods(attr.config_methods, wps2, 1) ||
+ wps_validate_manufacturer(attr.manufacturer, attr.manufacturer_len,
+ 1) ||
+ wps_validate_model_name(attr.model_name, attr.model_name_len, 1) ||
+ wps_validate_model_number(attr.model_number, attr.model_number_len,
+ 1) ||
+ wps_validate_serial_number(attr.serial_number,
+ attr.serial_number_len, 1) ||
+ wps_validate_primary_dev_type(attr.primary_dev_type, 1) ||
+ wps_validate_dev_name(attr.dev_name, attr.dev_name_len, 1) ||
+ wps_validate_rf_bands(attr.rf_bands, 1) ||
+ wps_validate_assoc_state(attr.assoc_state, 1) ||
+ wps_validate_config_error(attr.config_error, 1) ||
+ wps_validate_os_version(attr.os_version, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M2D");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m3(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M3");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M3");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_e_hash1(attr.e_hash1, 1) ||
+ wps_validate_e_hash2(attr.e_hash2, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M3");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m4(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M4");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_r_hash1(attr.r_hash1, 1) ||
+ wps_validate_r_hash2(attr.r_hash2, 1) ||
+ wps_validate_encr_settings(attr.encr_settings,
+ attr.encr_settings_len, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m4_encr(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M4 encrypted "
+ "settings");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M4 encrypted settings");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_r_snonce1(attr.r_snonce1, 1) ||
+ wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M4 encrypted "
+ "settings");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m5(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M5");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_encr_settings(attr.encr_settings,
+ attr.encr_settings_len, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m5_encr(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M5 encrypted "
+ "settings");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M5 encrypted settings");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_e_snonce1(attr.e_snonce1, 1) ||
+ wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M5 encrypted "
+ "settings");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m6(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M6");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_encr_settings(attr.encr_settings,
+ attr.encr_settings_len, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m6_encr(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M6 encrypted "
+ "settings");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M6 encrypted settings");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_r_snonce2(attr.r_snonce2, 1) ||
+ wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M6 encrypted "
+ "settings");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m7(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M7");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_encr_settings(attr.encr_settings,
+ attr.encr_settings_len, 1) ||
+ wps_validate_settings_delay_time(attr.settings_delay_time, 0) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M7 encrypted "
+ "settings");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M7 encrypted settings");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_e_snonce2(attr.e_snonce2, 1) ||
+ wps_validate_ssid(attr.ssid, attr.ssid_len, !ap) ||
+ wps_validate_mac_addr(attr.mac_addr, !ap) ||
+ wps_validate_auth_type(attr.auth_type, !ap) ||
+ wps_validate_encr_type(attr.encr_type, !ap) ||
+ wps_validate_network_key_index(attr.network_key_idx, 0) ||
+ wps_validate_network_key(attr.network_key, attr.network_key_len,
+ attr.encr_type, !ap) ||
+ wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M7 encrypted "
+ "settings");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m8(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M8");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_encr_settings(attr.encr_settings,
+ attr.encr_settings_len, 1) ||
+ wps_validate_version2(attr.version2, wps2) ||
+ wps_validate_authenticator(attr.authenticator, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in M8 encrypted "
+ "settings");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in M8 encrypted settings");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_ssid(attr.ssid, attr.ssid_len, ap) ||
+ wps_validate_auth_type(attr.auth_type, ap) ||
+ wps_validate_encr_type(attr.encr_type, ap) ||
+ wps_validate_network_key_index(attr.network_key_idx, 0) ||
+ wps_validate_mac_addr(attr.mac_addr, ap) ||
+ wps_validate_credential(attr.cred, attr.cred_len, attr.num_cred,
+ !ap) ||
+ wps_validate_key_wrap_auth(attr.key_wrap_auth, 1)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid M8 encrypted "
+ "settings");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_ACK");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in WSC_ACK");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_ACK");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_NACK");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in WSC_NACK");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_config_error(attr.config_error, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_NACK");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+ struct wps_parse_attr attr;
+ int wps2;
+
+ if (tlvs == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: No TLVs in WSC_Done");
+ return -1;
+ }
+ if (wps_parse_msg(tlvs, &attr) < 0) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Failed to parse attributes "
+ "in WSC_Done");
+ return -1;
+ }
+
+ wps2 = attr.version2 != NULL;
+ if (wps_validate_version(attr.version, 1) ||
+ wps_validate_msg_type(attr.msg_type, 1) ||
+ wps_validate_enrollee_nonce(attr.enrollee_nonce, 1) ||
+ wps_validate_registrar_nonce(attr.registrar_nonce, 1) ||
+ wps_validate_version2(attr.version2, wps2)) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC_Done");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 514f5c6..e6a51c7 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -496,6 +496,11 @@ OBJS += ../src/wps/wps_nfc_pn531.o
LIBS += ${PN531_PATH}/lib/wpsnfc.dll
LIBS += ${PN531_PATH}/lib/libnfc_mapping_pn53x.dll
endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
endif
ifdef NEED_WPS_OOB
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 54f05e5..cc4f1b7 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -30,6 +30,7 @@
#include "ap/hostapd.h"
#include "notify.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "blacklist.h"
#include "wpas_glue.h"
#include "wps_supplicant.h"
@@ -921,6 +922,27 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p = data->assoc_info.resp_ies;
l = data->assoc_info.resp_ies_len;
+#ifdef CONFIG_WPS_STRICT
+ if (wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+ struct wpabuf *wps;
+ wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE);
+ if (wps == NULL) {
+ wpa_printf(MSG_INFO, "WPS-STRICT: AP did not include "
+ "WPS IE in (Re)Association Response");
+ return -1;
+ }
+
+ if (wps_validate_assoc_resp(wps) < 0) {
+ wpabuf_free(wps);
+ wpa_supplicant_deauthenticate(
+ wpa_s, WLAN_REASON_INVALID_IE);
+ return -1;
+ }
+ wpabuf_free(wps);
+ }
+#endif /* CONFIG_WPS_STRICT */
+
/* Go through the IEs and make a copy of the MDIE, if present. */
while (p && l >= 2) {
len = p[1] + 2;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index bb24995..19210ec 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -580,6 +580,40 @@ struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
}
+struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
+ const struct wpa_scan_res *res, u32 vendor_type)
+{
+ struct wpabuf *buf;
+ const u8 *end, *pos;
+
+ if (res->beacon_ie_len == 0)
+ return NULL;
+ buf = wpabuf_alloc(res->beacon_ie_len);
+ if (buf == NULL)
+ return NULL;
+
+ pos = (const u8 *) (res + 1);
+ pos += res->ie_len;
+ end = pos + res->beacon_ie_len;
+
+ while (pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+ vendor_type == WPA_GET_BE32(&pos[2]))
+ wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+ pos += 2 + pos[1];
+ }
+
+ if (wpabuf_len(buf) == 0) {
+ wpabuf_free(buf);
+ buf = NULL;
+ }
+
+ return buf;
+}
+
+
/* Compare function for sorting scan results. Return >0 if @b is considered
* better. */
static int wpa_scan_result_compar(const void *a, const void *b)
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 441fdbb..025b815 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -32,6 +32,8 @@ const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
u32 vendor_type);
struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
u32 vendor_type);
+struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
+ const struct wpa_scan_res *res, u32 vendor_type);
void wpa_scan_results_free(struct wpa_scan_results *res);
#endif /* SCAN_H */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 5a471f4..18d80dd 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -1029,6 +1029,28 @@ int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
ret = 1;
}
+#ifdef CONFIG_WPS_STRICT
+ if (wps_ie) {
+ if (wps_validate_beacon_probe_resp(wps_ie, bss->beacon_ie_len >
+ 0) < 0)
+ ret = 0;
+ if (bss->beacon_ie_len) {
+ struct wpabuf *bcn_wps;
+ bcn_wps = wpa_scan_get_vendor_ie_multi_beacon(
+ bss, WPS_IE_VENDOR_TYPE);
+ if (bcn_wps == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Mandatory WPS IE "
+ "missing from AP Beacon");
+ ret = 0;
+ } else {
+ if (wps_validate_beacon(wps_ie) < 0)
+ ret = 0;
+ wpabuf_free(bcn_wps);
+ }
+ }
+ }
+#endif /* CONFIG_WPS_STRICT */
+
wpabuf_free(wps_ie);
return ret;