aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/dbus.doxygen6
-rw-r--r--hostapd/Makefile2
-rw-r--r--hostapd/config_file.c10
-rw-r--r--hostapd/ctrl_iface.c5
-rw-r--r--hostapd/hostapd.conf42
-rw-r--r--src/ap/ap_config.c47
-rw-r--r--src/ap/ap_config.h8
-rw-r--r--src/ap/ap_drv_ops.c15
-rw-r--r--src/ap/ap_drv_ops.h3
-rw-r--r--src/ap/beacon.c6
-rw-r--r--src/ap/ctrl_iface_ap.c20
-rw-r--r--src/ap/dfs.c13
-rw-r--r--src/ap/dpp_hostapd.c35
-rw-r--r--src/ap/drv_callbacks.c20
-rw-r--r--src/ap/hostapd.c8
-rw-r--r--src/ap/hw_features.c96
-rw-r--r--src/ap/hw_features.h6
-rw-r--r--src/ap/ieee802_11.c196
-rw-r--r--src/ap/ieee802_11.h1
-rw-r--r--src/ap/ieee802_11_he.c25
-rw-r--r--src/ap/ieee802_11_ht.c8
-rw-r--r--src/ap/ieee802_11_shared.c35
-rw-r--r--src/ap/ieee802_11_vht.c5
-rw-r--r--src/ap/sta_info.c3
-rw-r--r--src/ap/wpa_auth.c17
-rw-r--r--src/ap/wpa_auth.h2
-rw-r--r--src/ap/wpa_auth_ft.c17
-rw-r--r--src/ap/wpa_auth_glue.c15
-rw-r--r--src/ap/wpa_auth_i.h3
-rw-r--r--src/ap/wpa_auth_ie.c186
-rw-r--r--src/ap/wpa_auth_ie.h33
-rw-r--r--src/common/common_module_tests.c126
-rw-r--r--src/common/dpp.c315
-rw-r--r--src/common/dpp.h31
-rw-r--r--src/common/hw_features_common.c71
-rw-r--r--src/common/hw_features_common.h3
-rw-r--r--src/common/ieee802_11_common.c136
-rw-r--r--src/common/ieee802_11_common.h14
-rw-r--r--src/common/ieee802_11_defs.h48
-rw-r--r--src/common/qca-vendor.h119
-rw-r--r--src/common/sae.c1032
-rw-r--r--src/common/sae.h39
-rw-r--r--src/common/wpa_common.c290
-rw-r--r--src/common/wpa_common.h60
-rw-r--r--src/crypto/crypto.h34
-rw-r--r--src/crypto/crypto_openssl.c73
-rw-r--r--src/crypto/crypto_wolfssl.c59
-rw-r--r--src/drivers/driver.h32
-rw-r--r--src/drivers/driver_nl80211.c62
-rw-r--r--src/drivers/driver_nl80211.h1
-rw-r--r--src/drivers/driver_nl80211_capa.c32
-rw-r--r--src/fst/fst.c9
-rw-r--r--src/fst/fst.h7
-rw-r--r--src/p2p/p2p.c11
-rw-r--r--src/rsn_supp/pmksa_cache.c2
-rw-r--r--src/rsn_supp/wpa.c179
-rw-r--r--src/rsn_supp/wpa.h13
-rw-r--r--src/rsn_supp/wpa_ft.c21
-rw-r--r--src/rsn_supp/wpa_i.h7
-rw-r--r--src/rsn_supp/wpa_ie.c264
-rw-r--r--src/rsn_supp/wpa_ie.h49
-rw-r--r--src/utils/json.c2
-rw-r--r--src/wps/wps_attr_build.c9
-rw-r--r--src/wps/wps_attr_process.c9
-rw-r--r--tests/fuzzing/eapol-key-auth/eapol-key-auth.c3
-rw-r--r--tests/hwsim/auth_serv/index.txt2
-rw-r--r--tests/hwsim/auth_serv/ocsp-multi-server-cache.derbin346 -> 346 bytes
-rw-r--r--tests/hwsim/auth_serv/ocsp-req.derbin76 -> 76 bytes
-rw-r--r--tests/hwsim/auth_serv/ocsp-server-cache.derbin343 -> 343 bytes
-rw-r--r--tests/hwsim/auth_serv/server-certpol.pem41
-rw-r--r--tests/hwsim/auth_serv/server-certpol2.pem36
-rw-r--r--tests/hwsim/auth_serv/server-eku-client-server.pem41
-rw-r--r--tests/hwsim/auth_serv/server-eku-client.pem41
-rw-r--r--tests/hwsim/auth_serv/server-extra.pkcs12bin2426 -> 2426 bytes
-rw-r--r--tests/hwsim/auth_serv/server-no-dnsname.pem41
-rw-r--r--tests/hwsim/auth_serv/server.pem39
-rw-r--r--tests/hwsim/auth_serv/server.pkcs12bin1685 -> 1685 bytes
-rw-r--r--tests/hwsim/auth_serv/test-ca/index.txt7
-rw-r--r--tests/hwsim/auth_serv/test-ca/serial2
-rw-r--r--tests/hwsim/auth_serv/user.pem41
-rw-r--r--tests/hwsim/auth_serv/user.pkcs12bin1653 -> 1653 bytes
-rw-r--r--tests/hwsim/auth_serv/user2.pkcs12bin2414 -> 2414 bytes
-rw-r--r--tests/hwsim/auth_serv/user3.pkcs12bin2356 -> 2356 bytes
-rwxr-xr-xtests/hwsim/start.sh2
-rw-r--r--tests/hwsim/test_ap_eap.py2
-rw-r--r--tests/hwsim/test_ap_ft.py17
-rw-r--r--tests/hwsim/test_ap_pmf.py81
-rw-r--r--tests/hwsim/test_dbus.py79
-rw-r--r--tests/hwsim/test_dpp.py37
-rw-r--r--tests/hwsim/test_he.py1008
-rw-r--r--tests/hwsim/test_sae.py373
-rw-r--r--tests/hwsim/test_scan.py17
-rw-r--r--tests/hwsim/test_sigma_dut.py224
-rw-r--r--tests/hwsim/test_wmediumd.py19
-rw-r--r--tests/hwsim/test_wpas_ap.py50
-rw-r--r--tests/hwsim/test_wpas_mesh.py4
-rwxr-xr-xtests/hwsim/vm/parallel-vm.py2
-rw-r--r--tests/test-eapol.c2
-rw-r--r--wpa_supplicant/README-DPP4
-rw-r--r--wpa_supplicant/ap.c18
-rw-r--r--wpa_supplicant/config.c16
-rw-r--r--wpa_supplicant/config.h8
-rw-r--r--wpa_supplicant/config_file.c5
-rw-r--r--wpa_supplicant/config_ssid.h19
-rw-r--r--wpa_supplicant/ctrl_iface.c9
-rw-r--r--wpa_supplicant/dbus/dbus_new.c10
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c179
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h2
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers_p2p.c69
-rw-r--r--wpa_supplicant/defconfig2
-rw-r--r--wpa_supplicant/dpp_supplicant.c115
-rw-r--r--wpa_supplicant/events.c75
-rw-r--r--wpa_supplicant/ibss_rsn.c3
-rw-r--r--wpa_supplicant/interworking.c2
-rw-r--r--wpa_supplicant/op_classes.c73
-rw-r--r--wpa_supplicant/rrm.c3
-rw-r--r--wpa_supplicant/scan.c109
-rw-r--r--wpa_supplicant/scan.h2
-rw-r--r--wpa_supplicant/sme.c144
-rw-r--r--wpa_supplicant/wpa_cli.c6
-rw-r--r--wpa_supplicant/wpa_priv.c5
-rw-r--r--wpa_supplicant/wpa_supplicant.c262
-rw-r--r--wpa_supplicant/wpa_supplicant.conf18
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h8
-rw-r--r--wpa_supplicant/wpas_glue.c4
125 files changed, 6390 insertions, 1038 deletions
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 072ed34..9bca70c 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -1043,6 +1043,12 @@ fi.w1.wpa_supplicant1.CreateInterface.
<h3>WpsPriority - s - (read/write)</h3>
<p>Priority for the networks added through WPS</p>
</li>
+
+ <li>
+ <h3>MACAddressRandomizationMask - a{say} - (read/write)</h3>
+ <p>Masks to show which bits not to randomize with MAC address randomization. Possible keys are "scan", "sched_scan", and "pno". Values must be an array of 6 bytes.</p>
+ <p>When this property is set, the new dictionary replaces the old value, rather than merging them together. Leaving a key out of the dictionary will turn off MAC address randomization for that scan type.</p>
+ </li>
</ul>
\subsection dbus_interface_signals Signals
diff --git a/hostapd/Makefile b/hostapd/Makefile
index 42bb9e4..955e278 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -121,6 +121,7 @@ CFLAGS += -DPACKAGE="hostapd" -DWPA_TRACE_BFD
LIBS += -lbfd -ldl -liberty -lz
LIBS_c += -lbfd -ldl -liberty -lz
LIBS_h += -lbfd -ldl -liberty -lz
+LIBS_n += -lbfd -ldl -liberty -lz
endif
endif
@@ -1313,7 +1314,6 @@ NOBJS += ../src/utils/wpa_debug.o
NOBJS += ../src/utils/wpabuf.o
ifdef CONFIG_WPA_TRACE
NOBJS += ../src/utils/trace.o
-LIBS_n += -lbfd
endif
HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index db9d582..40066ad 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3136,6 +3136,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "acs_exclude_dfs") == 0) {
conf->acs_exclude_dfs = atoi(pos);
+ } else if (os_strcmp(buf, "op_class") == 0) {
+ conf->op_class = atoi(pos);
} else if (os_strcmp(buf, "channel") == 0) {
if (os_strcmp(pos, "acs_survey") == 0) {
#ifndef CONFIG_ACS
@@ -3150,6 +3152,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
conf->channel = atoi(pos);
conf->acs = conf->channel == 0;
}
+ } else if (os_strcmp(buf, "edmg_channel") == 0) {
+ conf->edmg_channel = atoi(pos);
+ } else if (os_strcmp(buf, "enable_edmg") == 0) {
+ conf->enable_edmg = atoi(pos);
} else if (os_strcmp(buf, "chanlist") == 0) {
if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
@@ -4178,6 +4184,10 @@ static int hostapd_config_fill(struct hostapd_config *conf,
}
} else if (os_strcmp(buf, "sae_require_mfp") == 0) {
bss->sae_require_mfp = atoi(pos);
+ } else if (os_strcmp(buf, "sae_confirm_immediate") == 0) {
+ bss->sae_confirm_immediate = atoi(pos);
+ } else if (os_strcmp(buf, "sae_pwe") == 0) {
+ bss->sae_pwe = atoi(pos);
} else if (os_strcmp(buf, "local_pwr_constraint") == 0) {
int val = atoi(pos);
if (val < 0 || val > 255) {
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 8d9d1a3..2c44d1e 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1424,6 +1424,11 @@ static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
if (ieee802_11_update_beacons(hapd->iface))
wpa_printf(MSG_DEBUG,
"Failed to update beacons with WMM parameters");
+ } else if (os_strcmp(cmd, "wpa_passphrase") == 0 ||
+ os_strcmp(cmd, "sae_password") == 0 ||
+ os_strcmp(cmd, "sae_pwe") == 0) {
+ if (hapd->started)
+ hostapd_setup_sae_pt(hapd->conf);
}
}
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index e6d8472..4cbe451 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -146,7 +146,8 @@ ssid=test
# Operation mode (a = IEEE 802.11a (5 GHz), b = IEEE 802.11b (2.4 GHz),
# g = IEEE 802.11g (2.4 GHz), ad = IEEE 802.11ad (60 GHz); a/g options are used
# with IEEE 802.11n (HT), too, to specify band). For IEEE 802.11ac (VHT), this
-# needs to be set to hw_mode=a. When using ACS (see channel parameter), a
+# needs to be set to hw_mode=a. For IEEE 802.11ax (HE) on 6 GHz this needs
+# to be set to hw_mode=a. When using ACS (see channel parameter), a
# special value "any" can be used to indicate that any support band can be used.
# This special case is currently supported only with drivers with which
# offloaded ACS is used.
@@ -163,6 +164,12 @@ hw_mode=g
# which will enable the ACS survey based algorithm.
channel=1
+# Global operating class (IEEE 802.11, Annex E, Table E-4)
+# This option allows hostapd to specify the operating class of the channel
+# configured with the channel parameter. channel and op_class together can
+# uniquely identify channels across different bands, including the 6 GHz band.
+#op_class=131
+
# ACS tuning - Automatic Channel Selection
# See: http://wireless.kernel.org/en/users/Documentation/acs
#
@@ -799,6 +806,11 @@ wmm_ac_vo_acm=0
#he_rts_threshold=0
# HE operating channel information; see matching vht_* parameters for details.
+# On the 6 GHz band the center freq calculation starts from 5.940 GHz offset.
+# For example idx=3 would result in 5955 MHz center frequency. In addition,
+# he_oper_chwidth is ignored, and the channel width is derived from the
+# configured operating class or center frequency indexes (see
+# IEEE P802.11ax/D4.3 Annex E, Table E-4).
#he_oper_chwidth
#he_oper_centr_freq_seg0_idx
#he_oper_centr_freq_seg1_idx
@@ -1743,6 +1755,21 @@ own_ip_addr=127.0.0.1
# MFP while SAE stations are required to negotiate MFP if sae_require_mfp=1.
#sae_require_mfp=0
+# SAE Confirm behavior
+# By default, AP will send out only SAE Commit message in response to a received
+# SAE Commit message. This parameter can be set to 1 to override that behavior
+# to send both SAE Commit and SAE Confirm messages without waiting for the STA
+# to send its SAE Confirm message first.
+#sae_confirm_immediate=0
+
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default)
+# 1 = hash-to-element only
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+#sae_pwe=0
+
# FILS Cache Identifier (16-bit value in hexdump format)
#fils_cache_id=0011
@@ -2666,6 +2693,19 @@ own_ip_addr=127.0.0.1
# airtime.
#airtime_bss_limit=1
+##### EDMG support ############################################################
+#
+# Enable EDMG capability for AP mode in the 60 GHz band. Default value is false.
+# To configure channel bonding for an EDMG AP use edmg_channel below.
+# If enable_edmg is set and edmg_channel is not set, EDMG CB1 will be
+# configured.
+#enable_edmg=1
+#
+# Configure channel bonding for AP mode in the 60 GHz band.
+# This parameter is relevant only if enable_edmg is set.
+# Default value is 0 (no channel bonding).
+#edmg_channel=9
+
##### TESTING OPTIONS #########################################################
#
# The options in this section are only available when the build configuration
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 6704ade..58fc3e9 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -16,6 +16,7 @@
#include "common/ieee802_1x_defs.h"
#include "common/eapol_common.h"
#include "common/dhcp.h"
+#include "common/sae.h"
#include "eap_common/eap_wsc_common.h"
#include "eap_server/eap.h"
#include "wpa_auth.h"
@@ -434,10 +435,50 @@ static int hostapd_derive_psk(struct hostapd_ssid *ssid)
}
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf)
+{
+#ifdef CONFIG_SAE
+ struct hostapd_ssid *ssid = &conf->ssid;
+ struct sae_password_entry *pw;
+
+ if (conf->sae_pwe == 0)
+ return 0; /* PT not needed */
+
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ if (ssid->wpa_passphrase) {
+ ssid->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) ssid->wpa_passphrase,
+ os_strlen(ssid->wpa_passphrase),
+ NULL);
+ if (!ssid->pt)
+ return -1;
+ }
+
+ for (pw = conf->sae_passwords; pw; pw = pw->next) {
+ sae_deinit_pt(pw->pt);
+ pw->pt = sae_derive_pt(conf->sae_groups, ssid->ssid,
+ ssid->ssid_len,
+ (const u8 *) pw->password,
+ os_strlen(pw->password),
+ pw->identifier);
+ if (!pw->pt)
+ return -1;
+ }
+#endif /* CONFIG_SAE */
+
+ return 0;
+}
+
+
int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
struct hostapd_ssid *ssid = &conf->ssid;
+ if (hostapd_setup_sae_pt(conf) < 0)
+ return -1;
+
if (ssid->wpa_passphrase != NULL) {
if (ssid->wpa_psk != NULL) {
wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
@@ -643,6 +684,9 @@ static void hostapd_config_free_sae_passwords(struct hostapd_bss_config *conf)
pw = pw->next;
str_clear_free(tmp->password);
os_free(tmp->identifier);
+#ifdef CONFIG_SAE
+ sae_deinit_pt(tmp->pt);
+#endif /* CONFIG_SAE */
os_free(tmp);
}
}
@@ -679,6 +723,9 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
#ifdef CONFIG_FULL_DYNAMIC_VLAN
os_free(conf->ssid.vlan_tagged_interface);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#ifdef CONFIG_SAE
+ sae_deinit_pt(conf->ssid.pt);
+#endif /* CONFIG_SAE */
hostapd_config_free_eap_users(conf->eap_user);
os_free(conf->eap_user_sqlite);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index d6052e1..2a0c984 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -99,6 +99,7 @@ struct hostapd_ssid {
struct hostapd_wpa_psk *wpa_psk;
char *wpa_passphrase;
char *wpa_psk_file;
+ struct sae_pt *pt;
struct hostapd_wep_keys wep;
@@ -251,6 +252,7 @@ struct sae_password_entry {
char *identifier;
u8 peer_addr[ETH_ALEN];
int vlan_id;
+ struct sae_pt *pt;
};
struct dpp_controller_conf {
@@ -649,6 +651,8 @@ struct hostapd_bss_config {
unsigned int sae_anti_clogging_threshold;
unsigned int sae_sync;
int sae_require_mfp;
+ int sae_confirm_immediate;
+ int sae_pwe;
int *sae_groups;
struct sae_password_entry *sae_passwords;
@@ -871,7 +875,10 @@ struct hostapd_config {
u16 beacon_int;
int rts_threshold;
int fragm_threshold;
+ u8 op_class;
u8 channel;
+ int enable_edmg;
+ u8 edmg_channel;
u8 acs;
struct wpa_freq_range_list acs_ch_list;
int acs_exclude_dfs;
@@ -1100,5 +1107,6 @@ int hostapd_config_check(struct hostapd_config *conf, int full_config);
void hostapd_set_security_params(struct hostapd_bss_config *bss,
int full_config);
int hostapd_sae_pw_id_in_use(struct hostapd_bss_config *conf);
+int hostapd_setup_sae_pt(struct hostapd_bss_config *conf);
#endif /* HOSTAPD_CONFIG_H */
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 095810f..204274f 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -107,6 +107,10 @@ int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
goto fail;
#endif /* CONFIG_FILS */
+ pos = hostapd_eid_rsnxe(hapd, buf, sizeof(buf));
+ if (add_buf_data(&assocresp, buf, pos - buf) < 0)
+ goto fail;
+
if (add_buf(&beacon, hapd->wps_beacon_ie) < 0 ||
add_buf(&proberesp, hapd->wps_probe_resp_ie) < 0)
goto fail;
@@ -346,7 +350,7 @@ int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
u16 auth_alg)
{
if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
- return 0;
+ return -EOPNOTSUPP;
return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
}
@@ -538,7 +542,8 @@ int hostapd_flush(struct hostapd_data *hapd)
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
int he_enabled,
int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1)
@@ -546,7 +551,8 @@ int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
struct hostapd_freq_params data;
struct hostapd_hw_modes *cmode = hapd->iface->current_mode;
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, edmg,
+ edmg_channel, ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth,
center_segment0, center_segment1,
@@ -808,7 +814,8 @@ int hostapd_start_dfs_cac(struct hostapd_iface *iface,
return -1;
}
- if (hostapd_set_freq_params(&data, mode, freq, channel, ht_enabled,
+ if (hostapd_set_freq_params(&data, mode, freq, channel, 0, 0,
+ ht_enabled,
vht_enabled, he_enabled, sec_channel_offset,
oper_chwidth, center_segment0,
center_segment1,
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index ca7f7ab..79b1302 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -62,7 +62,8 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
const u8 *addr, int idx, u8 *seq);
int hostapd_flush(struct hostapd_data *hapd);
int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled, int vht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled, int vht_enabled,
int he_enabled, int sec_channel_offset, int oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 6c94f95..331c09b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -499,7 +499,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#endif /* CONFIG_FST */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
pos = hostapd_eid_vht_capabilities(hapd, pos, 0);
pos = hostapd_eid_vht_operation(hapd, pos);
pos = hostapd_eid_txpower_envelope(hapd, pos);
@@ -1434,7 +1435,8 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
if (cmode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
- iconf->channel, iconf->ieee80211n,
+ iconf->channel, iconf->enable_edmg,
+ iconf->edmg_channel, iconf->ieee80211n,
iconf->ieee80211ac, iconf->ieee80211ax,
iconf->secondary_channel,
hostapd_get_oper_chwidth(iconf),
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 2c4953d..bde61ee 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -709,6 +709,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
ret = os_snprintf(buf + len, buflen - len,
"channel=%u\n"
+ "edmg_enable=%d\n"
+ "edmg_channel=%d\n"
"secondary_channel=%d\n"
"ieee80211n=%d\n"
"ieee80211ac=%d\n"
@@ -716,6 +718,8 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
"beacon_int=%u\n"
"dtim_period=%d\n",
iface->conf->channel,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n && !hapd->conf->disable_11n ?
iface->conf->secondary_channel : 0,
iface->conf->ieee80211n && !hapd->conf->disable_11n,
@@ -727,6 +731,22 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf,
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
+
+#ifdef CONFIG_IEEE80211AX
+ if (iface->conf->ieee80211ax) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "he_oper_chwidth=%d\n"
+ "he_oper_centr_freq_seg0_idx=%d\n"
+ "he_oper_centr_freq_seg1_idx=%d\n",
+ iface->conf->he_oper_chwidth,
+ iface->conf->he_oper_centr_freq_seg0_idx,
+ iface->conf->he_oper_centr_freq_seg1_idx);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+#endif /* CONFIG_IEEE80211AX */
+
if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) {
ret = os_snprintf(buf + len, buflen - len,
"vht_oper_chwidth=%d\n"
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 2de338d..db7130a 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -515,6 +515,7 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
int n_chans = 1, i;
struct hostapd_hw_modes *mode;
int frequency = freq;
+ int frequency2 = 0;
int ret = 0;
mode = iface->current_mode;
@@ -542,6 +543,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
n_chans = 4;
frequency = cf1 - 30;
break;
+ case CHAN_WIDTH_80P80:
+ n_chans = 4;
+ frequency = cf1 - 30;
+ frequency2 = cf2 - 30;
+ break;
case CHAN_WIDTH_160:
n_chans = 8;
frequency = cf1 - 70;
@@ -557,6 +563,11 @@ static int set_dfs_state(struct hostapd_iface *iface, int freq, int ht_enabled,
for (i = 0; i < n_chans; i++) {
ret += set_dfs_state_freq(iface, frequency, state);
frequency = frequency + 20;
+
+ if (chan_width == CHAN_WIDTH_80P80) {
+ ret += set_dfs_state_freq(iface, frequency2, state);
+ frequency2 = frequency2 + 20;
+ }
}
return ret;
@@ -960,6 +971,8 @@ static int hostapd_dfs_start_channel_switch(struct hostapd_iface *iface)
iface->conf->hw_mode,
channel->freq,
channel->chan,
+ iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
iface->conf->ieee80211n,
iface->conf->ieee80211ac,
iface->conf->ieee80211ax,
diff --git a/src/ap/dpp_hostapd.c b/src/ap/dpp_hostapd.c
index effcc7a..085d423 100644
--- a/src/ap/dpp_hostapd.c
+++ b/src/ap/dpp_hostapd.c
@@ -607,47 +607,48 @@ static void hostapd_dpp_rx_auth_req(struct hostapd_data *hapd, const u8 *src,
static void hostapd_dpp_handle_config_obj(struct hostapd_data *hapd,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_AKM "%s",
- dpp_akm_str(auth->akm));
- if (auth->ssid_len)
+ dpp_akm_str(conf->akm));
+ if (conf->ssid_len)
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
- } else if (auth->passphrase[0]) {
+ conf->connector);
+ } else if (conf->passphrase[0]) {
char hex[64 * 2 + 1];
wpa_snprintf_hex(hex, sizeof(hex),
- (const u8 *) auth->passphrase,
- os_strlen(auth->passphrase));
+ (const u8 *) conf->passphrase,
+ os_strlen(conf->passphrase));
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PASS "%s",
hex);
- } else if (auth->psk_set) {
+ } else if (conf->psk_set) {
char hex[PMK_LEN * 2 + 1];
- wpa_snprintf_hex(hex, sizeof(hex), auth->psk, PMK_LEN);
+ wpa_snprintf_hex(hex, sizeof(hex), conf->psk, PMK_LEN);
wpa_msg(hapd->msg_ctx, MSG_INFO, DPP_EVENT_CONFOBJ_PSK "%s",
hex);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(hapd->msg_ctx, MSG_INFO,
DPP_EVENT_C_SIGN_KEY "%s", hex);
os_free(hex);
@@ -720,7 +721,7 @@ static void hostapd_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
if (dpp_test == DPP_TEST_REJECT_CONFIG) {
@@ -1568,7 +1569,7 @@ int hostapd_dpp_configurator_sign(struct hostapd_data *hapd, const char *cmd)
if (dpp_set_configurator(hapd->iface->interfaces->dpp, hapd->msg_ctx,
auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 1) == 0) {
- hostapd_dpp_handle_config_obj(hapd, auth);
+ hostapd_dpp_handle_config_obj(hapd, auth, &auth->conf_obj[0]);
ret = 0;
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 57c1434..e5ce76d 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -16,6 +16,7 @@
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
#include "common/dpp.h"
+#include "common/sae.h"
#include "crypto/random.h"
#include "p2p/p2p.h"
#include "wps/wps.h"
@@ -319,6 +320,8 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
ie, ielen,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
if (res != WPA_IE_OK) {
@@ -341,6 +344,9 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
reason = WLAN_REASON_CIPHER_SUITE_REJECTED;
status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+ } else if (res == WPA_INVALID_PMKID) {
+ reason = WLAN_REASON_INVALID_PMKID;
+ status = WLAN_STATUS_INVALID_PMKID;
} else {
reason = WLAN_REASON_INVALID_IE;
status = WLAN_STATUS_INVALID_IE;
@@ -396,6 +402,20 @@ int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
}
}
#endif /* CONFIG_IEEE80211R_AP */
+#ifdef CONFIG_SAE
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ reason = WLAN_REASON_UNSPECIFIED;
+ goto fail;
+ }
+#endif /* CONFIG_SAE */
} else if (hapd->conf->wps_state) {
#ifdef CONFIG_WPS
struct wpabuf *wps;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index bf7b1f8..3686438 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -1590,6 +1590,9 @@ static int setup_interface2(struct hostapd_iface *iface)
wpa_printf(MSG_DEBUG, "Interface initialization will be completed in a callback (ACS)");
return 0;
}
+ ret = hostapd_check_edmg_capab(iface);
+ if (ret < 0)
+ goto fail;
ret = hostapd_check_ht_capab(iface);
if (ret < 0)
goto fail;
@@ -1914,6 +1917,8 @@ static int hostapd_setup_interface_complete_sync(struct hostapd_iface *iface,
if (!delay_apply_cfg &&
hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
hapd->iconf->channel,
+ hapd->iconf->enable_edmg,
+ hapd->iconf->edmg_channel,
hapd->iconf->ieee80211n,
hapd->iconf->ieee80211ac,
hapd->iconf->ieee80211ax,
@@ -3282,7 +3287,8 @@ static int hostapd_change_config_freq(struct hostapd_data *hapd,
if (old_params &&
hostapd_set_freq_params(old_params, conf->hw_mode,
hostapd_hw_get_freq(hapd, conf->channel),
- conf->channel, conf->ieee80211n,
+ conf->channel, conf->enable_edmg,
+ conf->edmg_channel, conf->ieee80211n,
conf->ieee80211ac, conf->ieee80211ax,
conf->secondary_channel,
hostapd_get_oper_chwidth(conf),
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index c1f19e2..2fefaf8 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -704,6 +704,32 @@ int hostapd_check_ht_capab(struct hostapd_iface *iface)
}
+int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ struct hostapd_hw_modes *mode = iface->hw_features;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 0;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+
+ if (mode->edmg.channels && ieee802_edmg_is_allowed(mode->edmg, edmg))
+ return 0;
+
+ wpa_printf(MSG_WARNING, "Requested EDMG configuration is not valid");
+ wpa_printf(MSG_INFO, "EDMG capab: channels 0x%x, bw_config %d",
+ mode->edmg.channels, mode->edmg.bw_config);
+ wpa_printf(MSG_INFO,
+ "Requested EDMG configuration: channels 0x%x, bw_config %d",
+ edmg.channels, edmg.bw_config);
+ return -1;
+}
+
+
static int hostapd_is_usable_chan(struct hostapd_iface *iface,
int channel, int primary)
{
@@ -730,6 +756,67 @@ static int hostapd_is_usable_chan(struct hostapd_iface *iface,
}
+static int hostapd_is_usable_edmg(struct hostapd_iface *iface)
+{
+ int i, contiguous = 0;
+ int num_of_enabled = 0;
+ int max_contiguous = 0;
+ struct ieee80211_edmg_config edmg;
+
+ if (!iface->conf->enable_edmg)
+ return 1;
+
+ hostapd_encode_edmg_chan(iface->conf->enable_edmg,
+ iface->conf->edmg_channel,
+ iface->conf->channel,
+ &edmg);
+ if (!(edmg.channels & BIT(iface->conf->channel - 1)))
+ return 0;
+
+ /* 60 GHz channels 1..6 */
+ for (i = 0; i < 6; i++) {
+ if (edmg.channels & BIT(i)) {
+ contiguous++;
+ num_of_enabled++;
+ } else {
+ contiguous = 0;
+ continue;
+ }
+
+ /* P802.11ay defines that the total number of subfields
+ * set to one does not exceed 4.
+ */
+ if (num_of_enabled > 4)
+ return 0;
+
+ if (!hostapd_is_usable_chan(iface, i + 1, 1))
+ return 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Check if the EDMG configuration is valid under the limitations
+ * of P802.11ay.
+ */
+ /* check bw_config against contiguous EDMG channels */
+ switch (edmg.bw_config) {
+ case EDMG_BW_CONFIG_4:
+ if (!max_contiguous)
+ return 0;
+ break;
+ case EDMG_BW_CONFIG_5:
+ if (max_contiguous < 2)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+
static int hostapd_is_usable_chans(struct hostapd_iface *iface)
{
int secondary_chan;
@@ -743,6 +830,9 @@ static int hostapd_is_usable_chans(struct hostapd_iface *iface)
if (!hostapd_is_usable_chan(iface, iface->conf->channel, 1))
return 0;
+ if (!hostapd_is_usable_edmg(iface))
+ return 0;
+
if (!iface->conf->secondary_channel)
return 1;
@@ -871,6 +961,7 @@ out:
int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
int i;
+ int freq = -1;
if (iface->num_hw_features < 1)
return -1;
@@ -887,9 +978,14 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
}
iface->current_mode = NULL;
+ if (iface->conf->channel && iface->conf->op_class)
+ freq = ieee80211_chan_to_freq(NULL, iface->conf->op_class,
+ iface->conf->channel);
for (i = 0; i < iface->num_hw_features; i++) {
struct hostapd_hw_modes *mode = &iface->hw_features[i];
if (mode->mode == iface->conf->hw_mode) {
+ if (freq > 0 && !hw_get_chan(mode, freq))
+ continue;
iface->current_mode = mode;
break;
}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index ca7f22b..902a19f 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -21,6 +21,7 @@ const char * hostapd_hw_mode_txt(int mode);
int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_check_edmg_capab(struct hostapd_iface *iface);
int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode);
void hostapd_stop_setup_timers(struct hostapd_iface *iface);
@@ -61,6 +62,11 @@ static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
return 0;
}
+static inline int hostapd_check_edmg_capab(struct hostapd_iface *iface)
+{
+ return 0;
+}
+
static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
struct hostapd_hw_modes *mode)
{
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 2ef490b..92ae026 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -98,6 +98,8 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ if (hapd->conf->sae_pwe == 1)
+ num++;
if (num > 8) {
/* rest of the rates are encoded in Extended supported
* rates element */
@@ -124,6 +126,11 @@ u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (hapd->conf->sae_pwe == 1 && count < 8) {
+ count++;
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -141,6 +148,8 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
num++;
if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
num++;
+ if (hapd->conf->sae_pwe == 1)
+ num++;
if (num <= 8)
return eid;
num -= 8;
@@ -170,6 +179,12 @@ u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
}
+ if (hapd->conf->sae_pwe == 1) {
+ count++;
+ if (count > 8)
+ *pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY;
+ }
+
return pos;
}
@@ -388,15 +403,25 @@ static void sae_set_state(struct sta_info *sta, enum sae_state state,
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
- struct sta_info *sta, int update)
+ struct sta_info *sta, int update,
+ int status_code)
{
struct wpabuf *buf;
const char *password = NULL;
struct sae_password_entry *pw;
const char *rx_id = NULL;
+ int use_pt = 0;
+ struct sae_pt *pt = NULL;
- if (sta->sae->tmp)
+ if (sta->sae->tmp) {
rx_id = sta->sae->tmp->pw_id;
+ use_pt = sta->sae->tmp->h2e;
+ }
+
+ if (status_code == WLAN_STATUS_SUCCESS)
+ use_pt = 0;
+ else if (status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT)
+ use_pt = 1;
for (pw = hapd->conf->sae_passwords; pw; pw = pw->next) {
if (!is_broadcast_ether_addr(pw->peer_addr) &&
@@ -408,16 +433,24 @@ static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
os_strcmp(rx_id, pw->identifier) != 0)
continue;
password = pw->password;
+ pt = pw->pt;
break;
}
- if (!password)
- password = hapd->conf->ssid.wpa_passphrase;
if (!password) {
+ password = hapd->conf->ssid.wpa_passphrase;
+ pt = hapd->conf->ssid.pt;
+ }
+ if (!password || (use_pt && !pt)) {
wpa_printf(MSG_DEBUG, "SAE: No password available");
return NULL;
}
- if (update &&
+ if (update && use_pt &&
+ sae_prepare_commit_pt(sta->sae, pt, hapd->own_addr, sta->addr,
+ NULL) < 0)
+ return NULL;
+
+ if (update && !use_pt &&
sae_prepare_commit(hapd->own_addr, sta->addr,
(u8 *) password, os_strlen(password), rx_id,
sta->sae) < 0) {
@@ -462,19 +495,22 @@ static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
static int auth_sae_send_commit(struct hostapd_data *hapd,
struct sta_info *sta,
- const u8 *bssid, int update)
+ const u8 *bssid, int update, int status_code)
{
struct wpabuf *data;
int reply_res;
+ u16 status;
- data = auth_build_sae_commit(hapd, sta, update);
+ data = auth_build_sae_commit(hapd, sta, update, status_code);
if (!data && sta->sae->tmp && sta->sae->tmp->pw_id)
return WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER;
if (data == NULL)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ status = (sta->sae->tmp && sta->sae->tmp->h2e) ?
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT : WLAN_STATUS_SUCCESS;
reply_res = send_auth_reply(hapd, sta->addr, bssid, WLAN_AUTH_SAE, 1,
- WLAN_STATUS_SUCCESS, wpabuf_head(data),
+ status, wpabuf_head(data),
wpabuf_len(data), "sae-send-commit");
wpabuf_free(data);
@@ -663,7 +699,7 @@ static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
switch (sta->sae->state) {
case SAE_COMMITTED:
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
eloop_register_timeout(0,
hapd->dot11RSNASAERetransPeriod * 1000,
auth_sae_retransmit_timer, hapd, sta);
@@ -761,8 +797,8 @@ void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *bssid, u8 auth_transaction, int allow_reuse,
- int *sta_removed)
+ const u8 *bssid, u16 auth_transaction, u16 status_code,
+ int allow_reuse, int *sta_removed)
{
int ret;
@@ -777,8 +813,11 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
switch (sta->sae->state) {
case SAE_NOTHING:
if (auth_transaction == 1) {
+ if (sta->sae->tmp)
+ sta->sae->tmp->h2e = status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT;
ret = auth_sae_send_commit(hapd, sta, bssid,
- !allow_reuse);
+ !allow_reuse, status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -787,14 +826,17 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_UNSPECIFIED_FAILURE;
/*
- * In mesh case, both Commit and Confirm can be sent
- * immediately. In infrastructure BSS, only a single
- * Authentication frame (Commit) is expected from the AP
- * here and the second one (Confirm) will be sent once
- * the STA has sent its second Authentication frame
- * (Confirm).
+ * In mesh case, both Commit and Confirm are sent
+ * immediately. In infrastructure BSS, by default, only
+ * a single Authentication frame (Commit) is expected
+ * from the AP here and the second one (Confirm) will
+ * be sent once the STA has sent its second
+ * Authentication frame (Confirm). This behavior can be
+ * overridden with explicit configuration so that the
+ * infrastructure BSS case sends both frames together.
*/
- if (hapd->conf->mesh & MESH_ENABLED) {
+ if ((hapd->conf->mesh & MESH_ENABLED) ||
+ hapd->conf->sae_confirm_immediate) {
/*
* Send both Commit and Confirm immediately
* based on SAE finite state machine
@@ -845,7 +887,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 0);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 0,
+ status_code);
if (ret)
return ret;
@@ -868,7 +911,7 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
* additional events.
*/
return sae_sm_step(hapd, sta, bssid, auth_transaction,
- 0, sta_removed);
+ WLAN_STATUS_SUCCESS, 0, sta_removed);
}
break;
case SAE_CONFIRMED:
@@ -878,7 +921,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
return WLAN_STATUS_SUCCESS;
sta->sae->sync++;
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
@@ -906,7 +950,8 @@ static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
*sta_removed = 1;
} else if (auth_transaction == 1) {
wpa_printf(MSG_DEBUG, "SAE: Start reauthentication");
- ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+ ret = auth_sae_send_commit(hapd, sta, bssid, 1,
+ status_code);
if (ret)
return ret;
sae_set_state(sta, SAE_COMMITTED, "Sent Commit");
@@ -976,6 +1021,64 @@ static void sae_pick_next_group(struct hostapd_data *hapd, struct sta_info *sta)
}
+static int sae_status_success(struct hostapd_data *hapd, u16 status_code)
+{
+ return (hapd->conf->sae_pwe == 0 &&
+ status_code == WLAN_STATUS_SUCCESS) ||
+ (hapd->conf->sae_pwe == 1 &&
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT) ||
+ (hapd->conf->sae_pwe == 2 &&
+ (status_code == WLAN_STATUS_SUCCESS ||
+ status_code == WLAN_STATUS_SAE_HASH_TO_ELEMENT));
+}
+
+
+static int sae_is_group_enabled(struct hostapd_data *hapd, int group)
+{
+ int *groups = hapd->conf->sae_groups;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int check_sae_rejected_groups(struct hostapd_data *hapd,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sae_is_group_enabled(hapd, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
const struct ieee80211_mgmt *mgmt, size_t len,
u16 auth_transaction, u16 status_code)
@@ -1013,7 +1116,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_TESTING_OPTIONS */
if (!sta->sae) {
if (auth_transaction != 1 ||
- status_code != WLAN_STATUS_SUCCESS) {
+ !sae_status_success(hapd, status_code)) {
resp = -1;
goto remove_sta;
}
@@ -1080,7 +1183,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
* Authentication frame, and the commit-scalar and
* COMMIT-ELEMENT previously sent.
*/
- resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0);
+ resp = auth_sae_send_commit(hapd, sta, mgmt->bssid, 0,
+ status_code);
if (resp != WLAN_STATUS_SUCCESS) {
wpa_printf(MSG_ERROR,
"SAE: Failed to send commit message");
@@ -1103,7 +1207,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
goto remove_sta;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (!sae_status_success(hapd, status_code))
goto remove_sta;
if (!(hapd->conf->mesh & MESH_ENABLED) &&
@@ -1136,7 +1240,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
((const u8 *) mgmt) + len -
mgmt->u.auth.variable, &token,
- &token_len, groups);
+ &token_len, groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (resp == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message from " MACSTR " due to reflection attack",
@@ -1166,6 +1271,13 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
if (resp != WLAN_STATUS_SUCCESS)
goto reply;
+ if (sta->sae->tmp &&
+ check_sae_rejected_groups(
+ hapd, sta->sae->tmp->peer_rejected_groups) < 0) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto remove_sta;
+ }
+
if (!token && use_sae_anti_clogging(hapd) && !allow_reuse) {
wpa_printf(MSG_DEBUG,
"SAE: Request anti-clogging token from "
@@ -1180,7 +1292,7 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
- allow_reuse, &sta_removed);
+ status_code, allow_reuse, &sta_removed);
} else if (auth_transaction == 2) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1221,8 +1333,8 @@ static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
}
sta->sae->rc = peer_send_confirm;
}
- resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction, 0,
- &sta_removed);
+ resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction,
+ status_code, 0, &sta_removed);
} else {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1283,7 +1395,7 @@ int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
if (sta->sae->state != SAE_NOTHING)
return -1;
- ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0, -1);
if (ret)
return -1;
@@ -1552,6 +1664,8 @@ void handle_auth_fils(struct hostapd_data *hapd, struct sta_info *sta,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
elems.rsn_ie - 2, elems.rsn_ie_len + 2,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len, NULL, 0);
resp = wpa_res_to_status_code(res);
if (resp != WLAN_STATUS_SUCCESS)
@@ -2863,7 +2977,7 @@ u16 owe_process_rsn_ie(struct hostapd_data *hapd,
rsn_ie_len += 2;
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq, rsn_ie, rsn_ie_len,
- NULL, 0, owe_dh, owe_dh_len);
+ NULL, 0, NULL, 0, owe_dh, owe_dh_len);
status = wpa_res_to_status_code(res);
if (status != WLAN_STATUS_SUCCESS)
goto end;
@@ -3071,6 +3185,8 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
hapd->iface->freq,
wpa_ie, wpa_ie_len,
+ elems.rsnxe ? elems.rsnxe - 2 : NULL,
+ elems.rsnxe ? elems.rsnxe_len + 2 : 0,
elems.mdie, elems.mdie_len,
elems.owe_dh, elems.owe_dh_len);
resp = wpa_res_to_status_code(res);
@@ -3146,6 +3262,17 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
MAC2STR(sta->addr), sta->auth_alg);
return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
}
+
+ if (hapd->conf->sae_pwe == 2 &&
+ sta->auth_alg == WLAN_AUTH_SAE &&
+ sta->sae && sta->sae->tmp && !sta->sae->tmp->h2e &&
+ elems.rsnxe && elems.rsnxe_len >= 1 &&
+ (elems.rsnxe[0] & BIT(WLAN_RSNX_CAPAB_SAE_H2E))) {
+ wpa_printf(MSG_INFO, "SAE: " MACSTR
+ " indicates support for SAE H2E, but did not use it",
+ MAC2STR(sta->addr));
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ }
#endif /* CONFIG_SAE */
#ifdef CONFIG_OWE
@@ -3555,7 +3682,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac &&
+ !is_6ghz_op_class(hapd->iconf->op_class)) {
u32 nsts = 0, sta_nsts;
if (sta && hapd->conf->use_sta_nsts && sta->vht_capabilities) {
@@ -3599,6 +3727,8 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
}
#endif /* CONFIG_FST */
+ p = hostapd_eid_rsnxe(hapd, p, buf + buflen - p);
+
#ifdef CONFIG_OWE
if ((hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_OWE) &&
sta && sta->owe_ecdh && status_code == WLAN_STATUS_SUCCESS &&
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index b8453c9..f592da5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -192,5 +192,6 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
int ap_seg1_idx, int *bandwidth, int *seg1_idx);
void auth_sae_process_commit(void *eloop_ctx, void *user_ctx);
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len);
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_he.c b/src/ap/ieee802_11_he.c
index 42b05d7..abd3940 100644
--- a/src/ap/ieee802_11_he.c
+++ b/src/ap/ieee802_11_he.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "beacon.h"
@@ -170,6 +171,9 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
if (!hapd->iface->current_mode)
return eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ oper_size += 5;
+
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 1 + oper_size;
*pos++ = WLAN_EID_EXT_HE_OPERATION;
@@ -198,9 +202,26 @@ u8 * hostapd_eid_he_operation(struct hostapd_data *hapd, u8 *eid)
/* TODO: conditional MaxBSSID Indicator subfield */
- oper->he_oper_params = host_to_le32(params);
+ pos += 6; /* skip the fixed part */
+
+ if (is_6ghz_op_class(hapd->iconf->op_class)) {
+ u8 seg0 = hostapd_get_oper_centr_freq_seg0_idx(hapd->iconf);
+
+ if (!seg0)
+ seg0 = hapd->iconf->channel;
- pos += oper_size;
+ params |= HE_OPERATION_6GHZ_OPER_INFO;
+ *pos++ = hapd->iconf->channel; /* Primary Channel */
+ *pos++ = center_idx_to_bw_6ghz(seg0); /* Control: Channel Width
+ */
+ /* Channel Center Freq Seg0/Seg0 */
+ *pos++ = seg0;
+ *pos++ = hostapd_get_oper_centr_freq_seg1_idx(hapd->iconf);
+ /* Minimum Rate */
+ *pos++ = 6; /* TODO: what should be set here? */
+ }
+
+ oper->he_oper_params = host_to_le32(params);
return pos;
}
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 214855d..6db9365 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -27,7 +27,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
- hapd->conf->disable_11n)
+ hapd->conf->disable_11n || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_CAP;
@@ -84,7 +84,8 @@ u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_ht_operation *oper;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+ if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
*pos++ = WLAN_EID_HT_OPERATION;
@@ -113,7 +114,8 @@ u8 * hostapd_eid_secondary_channel(struct hostapd_data *hapd, u8 *eid)
u8 sec_ch;
if (!hapd->cs_freq_params.channel ||
- !hapd->cs_freq_params.sec_channel_offset)
+ !hapd->cs_freq_params.sec_channel_offset ||
+ is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (hapd->cs_freq_params.sec_channel_offset == -1)
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 5007088..0b828e9 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -400,14 +400,22 @@ u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
u8 *pos = eid;
u8 len = 0, i;
- if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+ if (hapd->conf->qos_map_set_len ||
+ (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)))
len = 5;
- if (len < 4 && hapd->conf->interworking)
+ if (len < 4 &&
+ (hapd->conf->time_advertisement == 2 || hapd->conf->interworking))
len = 4;
- if (len < 3 && hapd->conf->wnm_sleep_mode)
+ if (len < 3 &&
+ (hapd->conf->wnm_sleep_mode || hapd->conf->bss_transition))
len = 3;
- if (len < 1 && hapd->iconf->obss_interval)
+ if (len < 1 &&
+ (hapd->iconf->obss_interval ||
+ (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)))
len = 1;
+ if (len < 2 &&
+ (hapd->conf->proxy_arp || hapd->conf->coloc_intf_reporting))
+ len = 2;
if (len < 7 && hapd->conf->ssid.utf8_ssid)
len = 7;
if (len < 9 &&
@@ -996,3 +1004,22 @@ int get_tx_parameters(struct sta_info *sta, int ap_max_chanwidth,
return 0;
}
#endif /* CONFIG_OCV */
+
+
+u8 * hostapd_eid_rsnxe(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+ u8 *pos = eid;
+
+ if (!(hapd->conf->wpa & WPA_PROTO_RSN) ||
+ (hapd->conf->sae_pwe != 1 && hapd->conf->sae_pwe != 2) ||
+ len < 3)
+ return pos;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos;
+}
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 269345f..f50f142 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -26,7 +26,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid, u32 nsts)
struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!mode)
+ if (!mode || is_6ghz_op_class(hapd->iconf->op_class))
return eid;
if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
@@ -76,6 +76,9 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
struct ieee80211_vht_operation *oper;
u8 *pos = eid;
+ if (is_6ghz_op_class(hapd->iconf->op_class))
+ return eid;
+
*pos++ = WLAN_EID_VHT_OPERATION;
*pos++ = sizeof(*oper);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index d7734ee..cbb8752 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1406,7 +1406,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1425,6 +1425,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_HT ? "[HT]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_HE ? "[HE]" : ""),
(flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 1c82ccf..7b690d7 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -708,6 +708,7 @@ static void wpa_free_sta_sm(struct wpa_state_machine *sm)
#endif /* CONFIG_IEEE80211R_AP */
os_free(sm->last_rx_eapol_key);
os_free(sm->wpa_ie);
+ os_free(sm->rsnxe);
wpa_group_put(sm->wpa_auth, sm->group);
#ifdef CONFIG_DPP2
wpabuf_clear_free(sm->dpp_z);
@@ -2936,6 +2937,22 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
WLAN_REASON_PREV_AUTH_NOT_VALID);
return;
}
+ if ((!sm->rsnxe && kde.rsnxe) ||
+ (sm->rsnxe && !kde.rsnxe) ||
+ (sm->rsnxe && kde.rsnxe &&
+ (sm->rsnxe_len != kde.rsnxe_len ||
+ os_memcmp(sm->rsnxe, kde.rsnxe, sm->rsnxe_len) != 0))) {
+ wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+ "RSNXE from (Re)AssocReq did not match the one in EAPOL-Key msg 2/4");
+ wpa_hexdump(MSG_DEBUG, "RSNXE in AssocReq",
+ sm->rsnxe, sm->rsnxe_len);
+ wpa_hexdump(MSG_DEBUG, "RSNXE in EAPOL-Key msg 2/4",
+ kde.rsnxe, kde.rsnxe_len);
+ /* MLME-DEAUTHENTICATE.request */
+ wpa_sta_disconnect(wpa_auth, sm->addr,
+ WLAN_REASON_PREV_AUTH_NOT_VALID);
+ return;
+ }
#ifdef CONFIG_OCV
if (wpa_auth_uses_ocv(sm)) {
struct wpa_channel_info ci;
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 2f1b1de..f627838 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -230,6 +230,7 @@ struct wpa_auth_config {
unsigned int fils_cache_id_set:1;
u8 fils_cache_id[FILS_CACHE_ID_LEN];
#endif /* CONFIG_FILS */
+ int sae_pwe;
};
typedef enum {
@@ -318,6 +319,7 @@ enum {
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len);
int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 771f6dd..a599be2 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -2418,6 +2418,8 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
u8 *fte_mic, *elem_count;
size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
int res;
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
@@ -2580,6 +2582,13 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
if (ric_start == pos)
ric_start = NULL;
+ res = wpa_write_rsnxe(&sm->wpa_auth->conf, rsnxe, sizeof(rsnxe));
+ if (res < 0)
+ return NULL;
+ rsnxe_len = res;
+ if (auth_alg == WLAN_AUTH_FT && rsnxe_len)
+ *elem_count += 1;
+
if (wpa_key_mgmt_fils(sm->wpa_key_mgmt)) {
kck = sm->PTK.kck2;
kck_len = sm->PTK.kck2_len;
@@ -2592,6 +2601,7 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
+ rsnxe_len ? rsnxe : NULL, rsnxe_len,
fte_mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return NULL;
@@ -3249,6 +3259,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -3268,6 +3280,8 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -3286,6 +3300,9 @@ u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
parse.rsn - 2, parse.rsn_len + 2);
+ wpa_hexdump(MSG_MSGDUMP, "FT: RSNXE",
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0);
return WLAN_STATUS_INVALID_FTIE;
}
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index c0786ce..ddab950 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -130,6 +130,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
os_memcpy(wconf->fils_cache_id, conf->fils_cache_id,
FILS_CACHE_ID_LEN);
#endif /* CONFIG_FILS */
+ wconf->sae_pwe = conf->sae_pwe;
}
@@ -890,18 +891,28 @@ hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int ret;
wpa_printf(MSG_DEBUG, "Add station entry for " MACSTR
" based on WPA authenticator callback",
MAC2STR(sta_addr));
- if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+ ret = hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT);
+
+ /*
+ * The expected return values from hostapd_add_sta_node() are
+ * 0: successfully added STA entry
+ * -EOPNOTSUPP: driver or driver wrapper does not support/need this
+ * operations
+ * any other negative value: error in adding the STA entry */
+ if (ret < 0 && ret != -EOPNOTSUPP)
return NULL;
sta = ap_sta_add(hapd, sta_addr);
if (sta == NULL)
return NULL;
- if (hapd->driver && hapd->driver->add_sta_node)
+ if (ret == 0)
sta->added_unassoc = 1;
+
sta->ft_over_ds = 1;
if (sta->wpa_sm) {
sta->auth_alg = WLAN_AUTH_FT;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 0d3ab27..a993f50 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -102,6 +102,8 @@ struct wpa_state_machine {
u8 *wpa_ie;
size_t wpa_ie_len;
+ u8 *rsnxe;
+ size_t rsnxe_len;
enum {
WPA_VERSION_NO_WPA = 0 /* WPA not used */,
@@ -267,6 +269,7 @@ struct ft_remote_seq {
int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
const u8 *pmkid);
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len);
void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
logger_level level, const char *txt);
void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index a285e25..2e6d059 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -372,6 +372,26 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
}
+int wpa_write_rsnxe(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+ u8 *pos = buf;
+
+ if (conf->sae_pwe != 1 && conf->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
+
+ if (len < 3)
+ return -1;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos - buf;
+}
+
+
static u8 * wpa_write_osen(struct wpa_auth_config *conf, u8 *eid)
{
u8 *len;
@@ -456,6 +476,11 @@ int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
if (res < 0)
return res;
pos += res;
+ res = wpa_write_rsnxe(&wpa_auth->conf, pos,
+ buf + sizeof(buf) - pos);
+ if (res < 0)
+ return res;
+ pos += res;
}
#ifdef CONFIG_IEEE80211R_AP
if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
@@ -524,6 +549,7 @@ static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int freq,
const u8 *wpa_ie, size_t wpa_ie_len,
+ const u8 *rsnxe, size_t rsnxe_len,
const u8 *mdie, size_t mdie_len,
const u8 *owe_dh, size_t owe_dh_len)
{
@@ -927,6 +953,21 @@ int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
sm->wpa_ie_len = wpa_ie_len;
+ if (rsnxe && rsnxe_len) {
+ if (!sm->rsnxe || sm->rsnxe_len < rsnxe_len) {
+ os_free(sm->rsnxe);
+ sm->rsnxe = os_malloc(rsnxe_len);
+ if (!sm->rsnxe)
+ return WPA_ALLOC_FAIL;
+ }
+ os_memcpy(sm->rsnxe, rsnxe, rsnxe_len);
+ sm->rsnxe_len = rsnxe_len;
+ } else {
+ os_free(sm->rsnxe);
+ sm->rsnxe = NULL;
+ sm->rsnxe_len = 0;
+ }
+
return WPA_IE_OK;
}
@@ -961,151 +1002,6 @@ int wpa_validate_osen(struct wpa_authenticator *wpa_auth,
#endif /* CONFIG_HS20 */
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- return 0;
- }
-
- if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
- ie->osen = pos;
- ie->osen_len = pos[1] + 2;
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
-
-
-/**
- * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
-#ifdef CONFIG_IEEE80211R_AP
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
-#endif /* CONFIG_IEEE80211R_AP */
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
-
- return ret;
-}
-
-
int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
{
return sm ? sm->mgmt_frame_prot : 0;
diff --git a/src/ap/wpa_auth_ie.h b/src/ap/wpa_auth_ie.h
index ad9409e..dd44b9e 100644
--- a/src/ap/wpa_auth_ie.h
+++ b/src/ap/wpa_auth_ie.h
@@ -9,39 +9,6 @@
#ifndef WPA_AUTH_IE_H
#define WPA_AUTH_IE_H
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
- const u8 *igtk;
- size_t igtk_len;
-#ifdef CONFIG_IEEE80211R_AP
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
-#endif /* CONFIG_IEEE80211R_AP */
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-
- const u8 *osen;
- size_t osen_len;
-};
-
-int wpa_parse_kde_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
const u8 *data2, size_t data2_len);
int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
diff --git a/src/common/common_module_tests.c b/src/common/common_module_tests.c
index 30c5247..fb0cf43 100644
--- a/src/common/common_module_tests.c
+++ b/src/common/common_module_tests.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "utils/module_tests.h"
#include "crypto/crypto.h"
+#include "crypto/dh_groups.h"
#include "ieee802_11_common.h"
#include "ieee802_11_defs.h"
#include "gas.h"
@@ -258,6 +259,7 @@ static int sae_tests(void)
/* IEEE P802.11-REVmd/D2.1, Annex J.10 */
const u8 addr1[ETH_ALEN] = { 0x82, 0x7b, 0x91, 0x9d, 0xd4, 0xb9 };
const u8 addr2[ETH_ALEN] = { 0x1e, 0xec, 0x49, 0xea, 0x64, 0x88 };
+ const char *ssid = "byteme";
const char *pw = "mekmitasdigoat";
const char *pwid = "psk4internet";
const u8 local_rand[] = {
@@ -338,6 +340,72 @@ static int sae_tests(void)
};
struct wpabuf *buf = NULL;
struct crypto_bignum *mask = NULL;
+ const u8 pwe_19_x[32] = {
+ 0x19, 0xd3, 0x37, 0xc9, 0x30, 0x79, 0x2b, 0x47,
+ 0x2b, 0x14, 0x5f, 0xc1, 0x5b, 0x98, 0x64, 0x0a,
+ 0x0e, 0x7d, 0x3b, 0xb0, 0x7d, 0xc0, 0xad, 0xee,
+ 0x6f, 0xc9, 0xdf, 0x75, 0xde, 0xc2, 0xd6, 0x94
+ };
+ const u8 pwe_19_y[32] = {
+ 0xb7, 0x8a, 0x02, 0x39, 0x20, 0x29, 0xe7, 0xf4,
+ 0x52, 0x41, 0x3d, 0x35, 0x8c, 0x88, 0xd9, 0x16,
+ 0xc8, 0x90, 0xba, 0x40, 0xd9, 0x93, 0xe3, 0x2d,
+ 0xd0, 0x0f, 0xfb, 0x58, 0xee, 0x62, 0x74, 0x98
+ };
+ const u8 pwe_15[384] = {
+ 0x59, 0x00, 0x9a, 0x32, 0xbb, 0x37, 0x84, 0x60,
+ 0x27, 0xeb, 0x70, 0x20, 0x57, 0x34, 0xf1, 0xb4,
+ 0xde, 0x1b, 0x48, 0xfc, 0x0e, 0xa5, 0xb8, 0x65,
+ 0xb1, 0xa0, 0xd4, 0xb9, 0x42, 0x1d, 0x6d, 0xdf,
+ 0x8b, 0x86, 0xeb, 0x4a, 0x2c, 0x2e, 0x38, 0x06,
+ 0x52, 0xae, 0x67, 0x39, 0xed, 0x7d, 0x0c, 0xd0,
+ 0xea, 0x30, 0x6e, 0x50, 0xe7, 0xb1, 0x8d, 0x91,
+ 0xf0, 0x05, 0x1f, 0x16, 0xf5, 0x45, 0xa7, 0x37,
+ 0x21, 0x0d, 0x8a, 0x69, 0x9a, 0xd1, 0xf1, 0x8c,
+ 0x2b, 0xbb, 0xd8, 0x21, 0xa2, 0x8f, 0xcc, 0xd1,
+ 0x35, 0x98, 0x66, 0xf3, 0x3c, 0x03, 0xba, 0x70,
+ 0x72, 0x4e, 0xe4, 0x23, 0xb5, 0x2e, 0x96, 0x5f,
+ 0xdd, 0xd1, 0xae, 0x71, 0xb1, 0xc1, 0x4b, 0x69,
+ 0x4e, 0x60, 0x0a, 0x08, 0x02, 0xa1, 0x6e, 0x80,
+ 0x68, 0x0a, 0xe7, 0x97, 0x9f, 0x5b, 0xbf, 0xa8,
+ 0x77, 0xda, 0x5b, 0x26, 0x13, 0x0a, 0xab, 0x92,
+ 0x79, 0x87, 0xa3, 0x85, 0x78, 0x74, 0xae, 0xae,
+ 0x01, 0xf0, 0x31, 0x8a, 0xc3, 0x96, 0xce, 0xaa,
+ 0x57, 0xbf, 0xb3, 0x57, 0xce, 0x2d, 0x2d, 0x36,
+ 0xda, 0x02, 0x5b, 0x12, 0xeb, 0xff, 0x13, 0x00,
+ 0x9e, 0xf7, 0xae, 0xe0, 0x47, 0xa4, 0x5d, 0x0a,
+ 0x88, 0x65, 0xbc, 0x66, 0x23, 0x3e, 0xf2, 0xf1,
+ 0xa0, 0x64, 0x5c, 0x6b, 0xdc, 0x81, 0xe9, 0x3c,
+ 0x46, 0x4f, 0x83, 0xcf, 0x9f, 0x55, 0x33, 0x8f,
+ 0xaa, 0x60, 0x4b, 0xd7, 0x21, 0x73, 0x6b, 0xdb,
+ 0x26, 0xad, 0x2f, 0xb7, 0xe2, 0x42, 0x56, 0x33,
+ 0xdb, 0xd6, 0xb2, 0x3a, 0x7d, 0x75, 0x87, 0xda,
+ 0x86, 0xc4, 0xe9, 0x41, 0x8d, 0x63, 0x19, 0x8e,
+ 0x8b, 0x17, 0x95, 0xfe, 0x2b, 0x96, 0xa0, 0x38,
+ 0xf1, 0xe2, 0x1d, 0x42, 0xa9, 0xe3, 0x8a, 0xa1,
+ 0x61, 0x62, 0x10, 0xf8, 0xb3, 0xb2, 0x2c, 0x7b,
+ 0xdf, 0xba, 0x74, 0xb2, 0x5b, 0xf6, 0xa9, 0xae,
+ 0x1d, 0x21, 0x0d, 0xc0, 0x48, 0x20, 0xfc, 0x28,
+ 0xf6, 0x22, 0xd2, 0xf6, 0x9c, 0x71, 0x3f, 0x9f,
+ 0x32, 0xd6, 0xbb, 0x9b, 0xd3, 0x87, 0x25, 0xcf,
+ 0x62, 0xd1, 0x68, 0xba, 0x55, 0x3b, 0x74, 0x2b,
+ 0x1d, 0x5a, 0xe4, 0x94, 0x59, 0x3b, 0x13, 0x21,
+ 0x15, 0x87, 0x3b, 0x09, 0x0e, 0xcf, 0x35, 0x60,
+ 0x04, 0xa8, 0xde, 0xa1, 0x09, 0xca, 0xb8, 0x35,
+ 0x1e, 0x16, 0x61, 0xed, 0xa1, 0x1f, 0x8c, 0x92,
+ 0x83, 0xa5, 0x27, 0x92, 0xf2, 0x80, 0xc3, 0xcb,
+ 0xdd, 0x3c, 0x0c, 0xf5, 0x8d, 0x69, 0xb3, 0xe4,
+ 0xd5, 0x49, 0x4d, 0x62, 0xcb, 0xb8, 0xe3, 0x9f,
+ 0x89, 0xb5, 0x57, 0xff, 0xef, 0x12, 0x37, 0x05,
+ 0xb6, 0x35, 0xe5, 0xc6, 0xd9, 0x23, 0xe2, 0xeb,
+ 0xe4, 0x0d, 0x1a, 0x30, 0x8f, 0x73, 0x70, 0x3a,
+ 0xef, 0x5a, 0xd1, 0x8c, 0x18, 0x34, 0x1e, 0xf0,
+ 0xb9, 0x08, 0x57, 0xab, 0xcb, 0x5c, 0x87, 0x10
+ };
+ int pt_groups[] = { 19, 20, 21, 25, 26, 28, 29, 30, 15, 0 };
+ struct sae_pt *pt_info, *pt;
+ u8 addr1b[ETH_ALEN] = { 0x3b, 0x36, 0xc2, 0x8b, 0x83, 0x03 };
+ u8 addr2b[ETH_ALEN] = { 0x58, 0x36, 0xc0, 0x64, 0x2d, 0x31 };
os_memset(&sae, 0, sizeof(sae));
buf = wpabuf_alloc(1000);
@@ -377,7 +445,7 @@ static int sae_tests(void)
}
if (sae_parse_commit(&sae, peer_commit, sizeof(peer_commit), NULL, NULL,
- NULL) != 0 ||
+ NULL, 0) != 0 ||
sae_process_commit(&sae) < 0)
goto fail;
@@ -411,6 +479,62 @@ static int sae_tests(void)
if (sae_check_confirm(&sae, peer_confirm, sizeof(peer_confirm)) < 0)
goto fail;
+ pt_info = sae_derive_pt(pt_groups,
+ (const u8 *) ssid, os_strlen(ssid),
+ (const u8 *) pw, os_strlen(pw), pwid);
+ if (!pt_info)
+ goto fail;
+
+ for (pt = pt_info; pt; pt = pt->next) {
+ if (pt->group == 19) {
+ struct crypto_ec_point *pwe;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len = sizeof(pwe_19_x);
+
+ pwe = sae_derive_pwe_from_pt_ecc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_ec_point_to_bin(pt->ec, pwe, bin,
+ bin + prime_len) < 0 ||
+ os_memcmp(pwe_19_x, bin, prime_len) != 0 ||
+ os_memcmp(pwe_19_y, bin + prime_len,
+ prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_ec_point_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_ec_point_deinit(pwe, 1);
+ }
+
+ if (pt->group == 15) {
+ struct crypto_bignum *pwe;
+ u8 bin[SAE_MAX_PRIME_LEN];
+ size_t prime_len = sizeof(pwe_15);
+
+ pwe = sae_derive_pwe_from_pt_ffc(pt, addr1b, addr2b);
+ if (!pwe) {
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ if (crypto_bignum_to_bin(pwe, bin, sizeof(bin),
+ prime_len) < 0 ||
+ os_memcmp(pwe_15, bin, prime_len) != 0) {
+ wpa_printf(MSG_ERROR,
+ "SAE: PT/PWE test vector mismatch");
+ crypto_bignum_deinit(pwe, 1);
+ sae_deinit_pt(pt);
+ goto fail;
+ }
+ crypto_bignum_deinit(pwe, 1);
+ }
+ }
+
+ sae_deinit_pt(pt_info);
+
ret = 0;
fail:
sae_clear_data(&sae);
diff --git a/src/common/dpp.c b/src/common/dpp.c
index c76d872..ab7072c 100644
--- a/src/common/dpp.c
+++ b/src/common/dpp.c
@@ -742,6 +742,34 @@ const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len)
}
+static const u8 * dpp_get_attr_next(const u8 *prev, const u8 *buf, size_t len,
+ u16 req_id, u16 *ret_len)
+{
+ u16 id, alen;
+ const u8 *pos, *end = buf + len;
+
+ if (!prev)
+ pos = buf;
+ else
+ pos = prev + WPA_GET_LE16(prev - 2);
+ while (end - pos >= 4) {
+ id = WPA_GET_LE16(pos);
+ pos += 2;
+ alen = WPA_GET_LE16(pos);
+ pos += 2;
+ if (alen > end - pos)
+ return NULL;
+ if (id == req_id) {
+ *ret_len = alen;
+ return pos;
+ }
+ pos += alen;
+ }
+
+ return NULL;
+}
+
+
int dpp_check_attrs(const u8 *buf, size_t len)
{
const u8 *pos, *end;
@@ -4360,8 +4388,8 @@ void dpp_configuration_free(struct dpp_configuration *conf)
}
-static int dpp_configuration_parse(struct dpp_authentication *auth,
- const char *cmd)
+static int dpp_configuration_parse_helper(struct dpp_authentication *auth,
+ const char *cmd, int idx)
{
const char *pos, *end;
struct dpp_configuration *conf_sta = NULL, *conf_ap = NULL;
@@ -4372,6 +4400,7 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
conf_sta = dpp_configuration_alloc(pos + 10);
if (!conf_sta)
goto fail;
+ conf_sta->netrole = DPP_NETROLE_STA;
conf = conf_sta;
}
@@ -4380,6 +4409,7 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
conf_ap = dpp_configuration_alloc(pos + 9);
if (!conf_ap)
goto fail;
+ conf_ap->netrole = DPP_NETROLE_AP;
conf = conf_ap;
}
@@ -4457,8 +4487,15 @@ static int dpp_configuration_parse(struct dpp_authentication *auth,
if (!dpp_configuration_valid(conf))
goto fail;
- auth->conf_sta = conf_sta;
- auth->conf_ap = conf_ap;
+ if (idx == 0) {
+ auth->conf_sta = conf_sta;
+ auth->conf_ap = conf_ap;
+ } else if (idx == 1) {
+ auth->conf2_sta = conf_sta;
+ auth->conf2_ap = conf_ap;
+ } else {
+ goto fail;
+ }
return 0;
fail:
@@ -4468,6 +4505,41 @@ fail:
}
+static int dpp_configuration_parse(struct dpp_authentication *auth,
+ const char *cmd)
+{
+ const char *pos;
+ char *tmp;
+ size_t len;
+ int res;
+
+ pos = os_strstr(cmd, " @CONF-OBJ-SEP@ ");
+ if (!pos)
+ return dpp_configuration_parse_helper(auth, cmd, 0);
+
+ len = pos - cmd;
+ tmp = os_malloc(len + 1);
+ if (!tmp)
+ goto fail;
+ os_memcpy(tmp, cmd, len);
+ tmp[len] = '\0';
+ res = dpp_configuration_parse_helper(auth, cmd, 0);
+ str_clear_free(tmp);
+ if (res)
+ goto fail;
+ res = dpp_configuration_parse_helper(auth, cmd + len, 1);
+ if (res)
+ goto fail;
+ return 0;
+fail:
+ dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
+ dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
+ return -1;
+}
+
+
static struct dpp_configurator *
dpp_configurator_get_id(struct dpp_global *dpp, unsigned int id)
{
@@ -4513,6 +4585,12 @@ int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
auth->send_conn_status = atoi(pos);
}
+ pos = os_strstr(cmd, " akm_use_selector=");
+ if (pos) {
+ pos += 18;
+ auth->akm_use_selector = atoi(pos);
+ }
+
if (dpp_configuration_parse(auth, cmd) < 0) {
wpa_msg(msg_ctx, MSG_INFO,
"DPP: Failed to set configurator parameters");
@@ -4524,18 +4602,26 @@ int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
void dpp_auth_deinit(struct dpp_authentication *auth)
{
+ unsigned int i;
+
if (!auth)
return;
dpp_configuration_free(auth->conf_ap);
+ dpp_configuration_free(auth->conf2_ap);
dpp_configuration_free(auth->conf_sta);
+ dpp_configuration_free(auth->conf2_sta);
EVP_PKEY_free(auth->own_protocol_key);
EVP_PKEY_free(auth->peer_protocol_key);
wpabuf_free(auth->req_msg);
wpabuf_free(auth->resp_msg);
wpabuf_free(auth->conf_req);
- os_free(auth->connector);
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ struct dpp_config_obj *conf = &auth->conf_obj[i];
+
+ os_free(conf->connector);
+ wpabuf_free(conf->c_sign_key);
+ }
wpabuf_free(auth->net_access_key);
- wpabuf_free(auth->c_sign_key);
dpp_bootstrap_info_free(auth->tmp_own_bi);
#ifdef CONFIG_TESTING_OPTIONS
os_free(auth->config_obj_override);
@@ -4646,8 +4732,21 @@ static void dpp_build_legacy_cred_params(struct wpabuf *buf,
}
+static const char * dpp_netrole_str(enum dpp_netrole netrole)
+{
+ switch (netrole) {
+ case DPP_NETROLE_STA:
+ return "sta";
+ case DPP_NETROLE_AP:
+ return "ap";
+ default:
+ return "??";
+ }
+}
+
+
static struct wpabuf *
-dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_dpp(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf = NULL;
@@ -4668,6 +4767,7 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
size_t extra_len = 1000;
int incl_legacy;
enum dpp_akm akm;
+ const char *akm_str;
if (!auth->conf) {
wpa_printf(MSG_INFO,
@@ -4721,7 +4821,8 @@ dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap,
#endif /* CONFIG_TESTING_OPTIONS */
wpabuf_printf(dppcon, "{\"groups\":[{\"groupId\":\"%s\",",
conf->group_id ? conf->group_id : "*");
- wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta");
+ wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],",
+ dpp_netrole_str(conf->netrole));
#ifdef CONFIG_TESTING_OPTIONS
skip_groups:
#endif /* CONFIG_TESTING_OPTIONS */
@@ -4820,7 +4921,11 @@ skip_groups:
if (!buf)
goto fail;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(akm))
+ akm_str = dpp_akm_selector_str(akm);
+ else
+ akm_str = dpp_akm_str(akm);
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
if (incl_legacy) {
dpp_build_legacy_cred_params(buf, conf);
wpabuf_put_str(buf, ",");
@@ -4861,16 +4966,21 @@ fail:
static struct wpabuf *
-dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
+dpp_build_conf_obj_legacy(struct dpp_authentication *auth,
struct dpp_configuration *conf)
{
struct wpabuf *buf;
+ const char *akm_str;
buf = dpp_build_conf_start(auth, conf, 1000);
if (!buf)
return NULL;
- wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", dpp_akm_str(conf->akm));
+ if (auth->akm_use_selector && dpp_akm_ver2(conf->akm))
+ akm_str = dpp_akm_selector_str(conf->akm);
+ else
+ akm_str = dpp_akm_str(conf->akm);
+ wpabuf_printf(buf, "\"cred\":{\"akm\":\"%s\",", akm_str);
dpp_build_legacy_cred_params(buf, conf);
wpabuf_put_str(buf, "}}");
@@ -4882,29 +4992,37 @@ dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap,
static struct wpabuf *
-dpp_build_conf_obj(struct dpp_authentication *auth, int ap)
+dpp_build_conf_obj(struct dpp_authentication *auth, int ap, int idx)
{
struct dpp_configuration *conf;
#ifdef CONFIG_TESTING_OPTIONS
if (auth->config_obj_override) {
+ if (idx != 0)
+ return NULL;
wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override");
return wpabuf_alloc_copy(auth->config_obj_override,
os_strlen(auth->config_obj_override));
}
#endif /* CONFIG_TESTING_OPTIONS */
- conf = ap ? auth->conf_ap : auth->conf_sta;
+ if (idx == 0)
+ conf = ap ? auth->conf_ap : auth->conf_sta;
+ else if (idx == 1)
+ conf = ap ? auth->conf2_ap : auth->conf2_sta;
+ else
+ conf = NULL;
if (!conf) {
- wpa_printf(MSG_DEBUG,
- "DPP: No configuration available for Enrollee(%s) - reject configuration request",
- ap ? "ap" : "sta");
+ if (idx == 0)
+ wpa_printf(MSG_DEBUG,
+ "DPP: No configuration available for Enrollee(%s) - reject configuration request",
+ ap ? "ap" : "sta");
return NULL;
}
if (dpp_akm_dpp(conf->akm))
- return dpp_build_conf_obj_dpp(auth, ap, conf);
- return dpp_build_conf_obj_legacy(auth, ap, conf);
+ return dpp_build_conf_obj_dpp(auth, conf);
+ return dpp_build_conf_obj_legacy(auth, conf);
}
@@ -4912,7 +5030,7 @@ static struct wpabuf *
dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
u16 e_nonce_len, int ap)
{
- struct wpabuf *conf;
+ struct wpabuf *conf, *conf2 = NULL;
size_t clear_len, attr_len;
struct wpabuf *clear = NULL, *msg = NULL;
u8 *wrapped;
@@ -4920,10 +5038,11 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
size_t len[1];
enum dpp_status_error status;
- conf = dpp_build_conf_obj(auth, ap);
+ conf = dpp_build_conf_obj(auth, ap, 0);
if (conf) {
wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
wpabuf_head(conf), wpabuf_len(conf));
+ conf2 = dpp_build_conf_obj(auth, ap, 1);
}
status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE;
auth->conf_resp_status = status;
@@ -4932,6 +5051,8 @@ dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
clear_len = 4 + e_nonce_len;
if (conf)
clear_len += 4 + wpabuf_len(conf);
+ if (conf2)
+ clear_len += 4 + wpabuf_len(conf2);
if (auth->peer_version >= 2 && auth->send_conn_status && !ap)
clear_len += 4;
clear = wpabuf_alloc(clear_len);
@@ -4981,6 +5102,14 @@ skip_e_nonce:
wpabuf_put_le16(clear, wpabuf_len(conf));
wpabuf_put_buf(clear, conf);
}
+ if (auth->peer_version >= 2 && conf2) {
+ wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ);
+ wpabuf_put_le16(clear, wpabuf_len(conf2));
+ wpabuf_put_buf(clear, conf2);
+ } else if (conf2) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: Second Config Object available, but peer does not support more than one");
+ }
if (auth->peer_version >= 2 && auth->send_conn_status && !ap) {
wpa_printf(MSG_DEBUG, "DPP: sendConnStatus");
@@ -5035,6 +5164,7 @@ skip_wrapped_data:
"DPP: Configuration Response attributes", msg);
out:
wpabuf_free(conf);
+ wpabuf_free(conf2);
wpabuf_free(clear);
return msg;
@@ -5272,7 +5402,7 @@ fail:
}
-static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
+static int dpp_parse_cred_legacy(struct dpp_config_obj *conf,
struct json_token *cred)
{
struct json_token *pass, *psk_hex;
@@ -5289,28 +5419,28 @@ static int dpp_parse_cred_legacy(struct dpp_authentication *auth,
pass->string, len);
if (len < 8 || len > 63)
return -1;
- os_strlcpy(auth->passphrase, pass->string,
- sizeof(auth->passphrase));
+ os_strlcpy(conf->passphrase, pass->string,
+ sizeof(conf->passphrase));
} else if (psk_hex && psk_hex->type == JSON_STRING) {
- if (dpp_akm_sae(auth->akm) && !dpp_akm_psk(auth->akm)) {
+ if (dpp_akm_sae(conf->akm) && !dpp_akm_psk(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Unexpected psk_hex with akm=sae");
return -1;
}
if (os_strlen(psk_hex->string) != PMK_LEN * 2 ||
- hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) {
+ hexstr2bin(psk_hex->string, conf->psk, PMK_LEN) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding");
return -1;
}
wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK",
- auth->psk, PMK_LEN);
- auth->psk_set = 1;
+ conf->psk, PMK_LEN);
+ conf->psk_set = 1;
} else {
wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found");
return -1;
}
- if (dpp_akm_sae(auth->akm) && !auth->passphrase[0]) {
+ if (dpp_akm_sae(conf->akm) && !conf->passphrase[0]) {
wpa_printf(MSG_DEBUG, "DPP: No pass for sae found");
return -1;
}
@@ -5478,6 +5608,7 @@ int dpp_key_expired(const char *timestamp, os_time_t *expiry)
static int dpp_parse_connector(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
const unsigned char *payload,
u16 payload_len)
{
@@ -5605,7 +5736,7 @@ static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash)
}
-static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
+static void dpp_copy_csign(struct dpp_config_obj *conf, EVP_PKEY *csign)
{
unsigned char *der = NULL;
int der_len;
@@ -5613,13 +5744,14 @@ static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign)
der_len = i2d_PUBKEY(csign, &der);
if (der_len <= 0)
return;
- wpabuf_free(auth->c_sign_key);
- auth->c_sign_key = wpabuf_alloc_copy(der, der_len);
+ wpabuf_free(conf->c_sign_key);
+ conf->c_sign_key = wpabuf_alloc_copy(der, der_len);
OPENSSL_free(der);
}
-static void dpp_copy_netaccesskey(struct dpp_authentication *auth)
+static void dpp_copy_netaccesskey(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
unsigned char *der = NULL;
int der_len;
@@ -5813,6 +5945,7 @@ fail:
static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
+ struct dpp_config_obj *conf,
struct json_token *cred)
{
struct dpp_signed_connector_info info;
@@ -5824,10 +5957,10 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
os_memset(&info, 0, sizeof(info));
- if (dpp_akm_psk(auth->akm) || dpp_akm_sae(auth->akm)) {
+ if (dpp_akm_psk(conf->akm) || dpp_akm_sae(conf->akm)) {
wpa_printf(MSG_DEBUG,
"DPP: Legacy credential included in Connector credential");
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
return -1;
}
@@ -5866,16 +5999,17 @@ static int dpp_parse_cred_dpp(struct dpp_authentication *auth,
signed_connector) != DPP_STATUS_OK)
goto fail;
- if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) {
+ if (dpp_parse_connector(auth, conf,
+ info.payload, info.payload_len) < 0) {
wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector");
goto fail;
}
- os_free(auth->connector);
- auth->connector = os_strdup(signed_connector);
+ os_free(conf->connector);
+ conf->connector = os_strdup(signed_connector);
- dpp_copy_csign(auth, csign_pub);
- dpp_copy_netaccesskey(auth);
+ dpp_copy_csign(conf, csign_pub);
+ dpp_copy_netaccesskey(auth, conf);
ret = 0;
fail:
@@ -5906,8 +6040,32 @@ const char * dpp_akm_str(enum dpp_akm akm)
}
+const char * dpp_akm_selector_str(enum dpp_akm akm)
+{
+ switch (akm) {
+ case DPP_AKM_DPP:
+ return "506F9A02";
+ case DPP_AKM_PSK:
+ return "000FAC02+000FAC06";
+ case DPP_AKM_SAE:
+ return "000FAC08";
+ case DPP_AKM_PSK_SAE:
+ return "000FAC02+000FAC06+000FAC08";
+ case DPP_AKM_SAE_DPP:
+ return "506F9A02+000FAC08";
+ case DPP_AKM_PSK_SAE_DPP:
+ return "506F9A02+000FAC08+000FAC02+000FAC06";
+ default:
+ return "??";
+ }
+}
+
+
static enum dpp_akm dpp_akm_from_str(const char *akm)
{
+ const char *pos;
+ int dpp = 0, psk = 0, sae = 0;
+
if (os_strcmp(akm, "psk") == 0)
return DPP_AKM_PSK;
if (os_strcmp(akm, "sae") == 0)
@@ -5920,6 +6078,38 @@ static enum dpp_akm dpp_akm_from_str(const char *akm)
return DPP_AKM_SAE_DPP;
if (os_strcmp(akm, "dpp+psk+sae") == 0)
return DPP_AKM_PSK_SAE_DPP;
+
+ pos = akm;
+ while (*pos) {
+ if (os_strlen(pos) < 8)
+ break;
+ if (os_strncasecmp(pos, "506F9A02", 8) == 0)
+ dpp = 1;
+ else if (os_strncasecmp(pos, "000FAC02", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC06", 8) == 0)
+ psk = 1;
+ else if (os_strncasecmp(pos, "000FAC08", 8) == 0)
+ sae = 1;
+ pos += 8;
+ if (*pos != '+')
+ break;
+ pos++;
+ }
+
+ if (dpp && psk && sae)
+ return DPP_AKM_PSK_SAE_DPP;
+ if (dpp && sae)
+ return DPP_AKM_SAE_DPP;
+ if (dpp)
+ return DPP_AKM_DPP;
+ if (psk && sae)
+ return DPP_AKM_PSK_SAE;
+ if (sae)
+ return DPP_AKM_SAE;
+ if (psk)
+ return DPP_AKM_PSK;
+
return DPP_AKM_UNKNOWN;
}
@@ -5929,6 +6119,7 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
{
int ret = -1;
struct json_token *root, *token, *discovery, *cred;
+ struct dpp_config_obj *conf;
root = json_parse((const char *) conf_obj, conf_obj_len);
if (!root)
@@ -5967,8 +6158,17 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
dpp_auth_fail(auth, "Too long discovery::ssid string value");
goto fail;
}
- auth->ssid_len = os_strlen(token->string);
- os_memcpy(auth->ssid, token->string, auth->ssid_len);
+
+ if (auth->num_conf_obj == DPP_MAX_CONF_OBJ) {
+ wpa_printf(MSG_DEBUG,
+ "DPP: No room for this many Config Objects - ignore this one");
+ json_free(root);
+ return 0;
+ }
+ conf = &auth->conf_obj[auth->num_conf_obj++];
+
+ conf->ssid_len = os_strlen(token->string);
+ os_memcpy(conf->ssid, token->string, conf->ssid_len);
cred = json_get_member(root, "cred");
if (!cred || cred->type != JSON_OBJECT) {
@@ -5981,13 +6181,13 @@ static int dpp_parse_conf_obj(struct dpp_authentication *auth,
dpp_auth_fail(auth, "No cred::akm string value found");
goto fail;
}
- auth->akm = dpp_akm_from_str(token->string);
+ conf->akm = dpp_akm_from_str(token->string);
- if (dpp_akm_legacy(auth->akm)) {
- if (dpp_parse_cred_legacy(auth, cred) < 0)
+ if (dpp_akm_legacy(conf->akm)) {
+ if (dpp_parse_cred_legacy(conf, cred) < 0)
goto fail;
- } else if (dpp_akm_dpp(auth->akm)) {
- if (dpp_parse_cred_dpp(auth, cred) < 0)
+ } else if (dpp_akm_dpp(conf->akm)) {
+ if (dpp_parse_cred_dpp(auth, conf, cred) < 0)
goto fail;
} else {
wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s",
@@ -6084,17 +6284,22 @@ int dpp_conf_resp_rx(struct dpp_authentication *auth,
goto fail;
}
- conf_obj = dpp_get_attr(unwrapped, unwrapped_len,
- DPP_ATTR_CONFIG_OBJ, &conf_obj_len);
+ conf_obj = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
if (!conf_obj) {
dpp_auth_fail(auth,
"Missing required Configuration Object attribute");
goto fail;
}
- wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
- conf_obj, conf_obj_len);
- if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
- goto fail;
+ while (conf_obj) {
+ wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON",
+ conf_obj, conf_obj_len);
+ if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0)
+ goto fail;
+ conf_obj = dpp_get_attr_next(conf_obj, unwrapped, unwrapped_len,
+ DPP_ATTR_CONFIG_OBJ,
+ &conf_obj_len);
+ }
#ifdef CONFIG_DPP2
status = dpp_get_attr(unwrapped, unwrapped_len,
@@ -6592,11 +6797,11 @@ int dpp_configurator_own_config(struct dpp_authentication *auth,
auth->own_protocol_key = dpp_gen_keypair(auth->curve);
if (!auth->own_protocol_key)
return -1;
- dpp_copy_netaccesskey(auth);
+ dpp_copy_netaccesskey(auth, &auth->conf_obj[0]);
auth->peer_protocol_key = auth->own_protocol_key;
- dpp_copy_csign(auth, auth->conf->csign);
+ dpp_copy_csign(&auth->conf_obj[0], auth->conf->csign);
- conf_obj = dpp_build_conf_obj(auth, ap);
+ conf_obj = dpp_build_conf_obj(auth, ap, 0);
if (!conf_obj)
goto fail;
ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj),
diff --git a/src/common/dpp.h b/src/common/dpp.h
index 21b58dd..0be26d7 100644
--- a/src/common/dpp.h
+++ b/src/common/dpp.h
@@ -161,10 +161,16 @@ enum dpp_akm {
DPP_AKM_PSK_SAE_DPP,
};
+enum dpp_netrole {
+ DPP_NETROLE_STA,
+ DPP_NETROLE_AP,
+};
+
struct dpp_configuration {
u8 ssid[32];
size_t ssid_len;
enum dpp_akm akm;
+ enum dpp_netrole netrole;
/* For DPP configuration (connector) */
os_time_t netaccesskey_expiry;
@@ -178,6 +184,8 @@ struct dpp_configuration {
int psk_set;
};
+#define DPP_MAX_CONF_OBJ 10
+
struct dpp_authentication {
void *msg_ctx;
u8 peer_version;
@@ -231,20 +239,26 @@ struct dpp_authentication {
struct wpabuf *conf_req;
const struct wpabuf *conf_resp; /* owned by GAS server */
struct dpp_configuration *conf_ap;
+ struct dpp_configuration *conf2_ap;
struct dpp_configuration *conf_sta;
+ struct dpp_configuration *conf2_sta;
struct dpp_configurator *conf;
- char *connector; /* received signedConnector */
- u8 ssid[SSID_MAX_LEN];
- u8 ssid_len;
- char passphrase[64];
- u8 psk[PMK_LEN];
- int psk_set;
- enum dpp_akm akm;
+ struct dpp_config_obj {
+ char *connector; /* received signedConnector */
+ u8 ssid[SSID_MAX_LEN];
+ u8 ssid_len;
+ char passphrase[64];
+ u8 psk[PMK_LEN];
+ int psk_set;
+ enum dpp_akm akm;
+ struct wpabuf *c_sign_key;
+ } conf_obj[DPP_MAX_CONF_OBJ];
+ unsigned int num_conf_obj;
struct wpabuf *net_access_key;
os_time_t net_access_key_expiry;
- struct wpabuf *c_sign_key;
int send_conn_status;
int conn_status_requested;
+ int akm_use_selector;
#ifdef CONFIG_TESTING_OPTIONS
char *config_obj_override;
char *discovery_override;
@@ -465,6 +479,7 @@ const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
int dpp_check_attrs(const u8 *buf, size_t len);
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
const char * dpp_akm_str(enum dpp_akm akm);
+const char * dpp_akm_selector_str(enum dpp_akm akm);
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
size_t buflen);
void dpp_configurator_free(struct dpp_configurator *conf);
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
index 3fdbf89..1ad8d7c 100644
--- a/src/common/hw_features_common.c
+++ b/src/common/hw_features_common.c
@@ -360,7 +360,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ int freq, int channel, int enable_edmg,
+ u8 edmg_channel, int ht_enabled,
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
@@ -381,6 +382,74 @@ int hostapd_set_freq_params(struct hostapd_freq_params *data,
data->center_freq2 = 0;
data->bandwidth = sec_channel_offset ? 40 : 20;
+ hostapd_encode_edmg_chan(enable_edmg, edmg_channel, channel,
+ &data->edmg);
+
+ if (is_6ghz_freq(freq)) {
+ if (!data->he_enabled) {
+ wpa_printf(MSG_ERROR,
+ "Can't set 6 GHz mode - HE isn't enabled");
+ return -1;
+ }
+
+ if (center_idx_to_bw_6ghz(channel) != 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid control channel for 6 GHz band");
+ return -1;
+ }
+
+ if (!center_segment0) {
+ if (center_segment1) {
+ wpa_printf(MSG_ERROR,
+ "Segment 0 center frequency isn't set");
+ return -1;
+ }
+
+ data->center_freq1 = data->freq;
+ data->bandwidth = 20;
+ } else {
+ int freq1, freq2 = 0;
+ int bw = center_idx_to_bw_6ghz(center_segment0);
+
+ if (bw < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid center frequency index for 6 GHz");
+ return -1;
+ }
+
+ freq1 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment0);
+ if (freq1 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 0 center frequency for 6 GHz");
+ return -1;
+ }
+
+ if (center_segment1) {
+ if (center_idx_to_bw_6ghz(center_segment1) != 2 ||
+ bw != 2) {
+ wpa_printf(MSG_ERROR,
+ "6 GHz 80+80 MHz configuration doesn't use valid 80 MHz channels");
+ return -1;
+ }
+
+ freq2 = ieee80211_chan_to_freq(NULL, 131,
+ center_segment1);
+ if (freq2 < 0) {
+ wpa_printf(MSG_ERROR,
+ "Invalid segment 1 center frequency for UHB");
+ return -1;
+ }
+ }
+
+ data->bandwidth = (1 << (u8) bw) * 20;
+ data->center_freq1 = freq1;
+ data->center_freq2 = freq2;
+ }
+
+ return 0;
+ }
+
if (data->vht_enabled) switch (oper_chwidth) {
case CHANWIDTH_USE_HT:
if (center_segment1 ||
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
index 2d2a539..c86e195 100644
--- a/src/common/hw_features_common.h
+++ b/src/common/hw_features_common.h
@@ -31,7 +31,8 @@ int check_40mhz_2g4(struct hostapd_hw_modes *mode,
int sec_chan);
int hostapd_set_freq_params(struct hostapd_freq_params *data,
enum hostapd_hw_mode mode,
- int freq, int channel, int ht_enabled,
+ int freq, int channel, int edmg, u8 edmg_channel,
+ int ht_enabled,
int vht_enabled, int he_enabled,
int sec_channel_offset,
int oper_chwidth, int center_segment0,
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index f833ae8..21ca194 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -365,6 +365,10 @@ ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
elems->rsn_ie = pos;
elems->rsn_ie_len = elen;
break;
+ case WLAN_EID_RSNX:
+ elems->rsnxe = pos;
+ elems->rsnxe_len = elen;
+ break;
case WLAN_EID_PWR_CAPABILITY:
if (elen < 2)
break;
@@ -882,6 +886,19 @@ enum hostapd_hw_mode ieee80211_freq_to_channel_ext(unsigned int freq,
return HOSTAPD_MODE_IEEE80211AD;
}
+ if (freq > 5940 && freq <= 7105) {
+ int bw;
+ u8 idx = (freq - 5940) / 5;
+
+ bw = center_idx_to_bw_6ghz(idx);
+ if (bw < 0)
+ return NUM_HOSTAPD_MODES;
+
+ *channel = idx;
+ *op_class = 131 + bw;
+ return HOSTAPD_MODE_IEEE80211A;
+ }
+
return NUM_HOSTAPD_MODES;
}
@@ -1161,6 +1178,14 @@ static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
if (chan < 36 || chan > 128)
return -1;
return 5000 + 5 * chan;
+ case 131: /* UHB channels, 20 MHz: 1, 5, 9.. */
+ case 132: /* UHB channels, 40 MHz: 3, 11, 19.. */
+ case 133: /* UHB channels, 80 MHz: 7, 23, 39.. */
+ case 134: /* UHB channels, 160 MHz: 15, 47, 79.. */
+ case 135: /* UHB channels, 80+80 MHz: 7, 23, 39.. */
+ if (chan < 1 || chan > 233)
+ return -1;
+ return 5940 + chan * 5;
case 180: /* 60 GHz band, channels 1..6 */
if (chan < 1 || chan > 6)
return -1;
@@ -1492,6 +1517,7 @@ const char * status2str(u16 status)
S2S(FILS_AUTHENTICATION_FAILURE)
S2S(UNKNOWN_AUTHENTICATION_SERVER)
S2S(UNKNOWN_PASSWORD_IDENTIFIER)
+ S2S(SAE_HASH_TO_ELEMENT)
}
return "UNKNOWN";
#undef S2S
@@ -1590,6 +1616,7 @@ const struct oper_class_map global_op_class[] = {
{ HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 129, 50, 114, 16, BW160, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211A, 130, 36, 161, 4, BW80P80, P2P_SUPP },
+ { HOSTAPD_MODE_IEEE80211A, 131, 1, 233, 4, BW20, P2P_SUPP },
{ HOSTAPD_MODE_IEEE80211AD, 180, 1, 4, 1, BW2160, P2P_SUPP },
{ -1, 0, 0, 0, 0, BW20, NO_P2P_SUPP }
};
@@ -1904,6 +1931,43 @@ int oper_class_bw_to_int(const struct oper_class_map *map)
}
+int center_idx_to_bw_6ghz(u8 idx)
+{
+ /* channels: 1, 5, 9, 13... */
+ if ((idx & 0x3) == 0x1)
+ return 0; /* 20 MHz */
+ /* channels 3, 11, 19... */
+ if ((idx & 0x7) == 0x3)
+ return 1; /* 40 MHz */
+ /* channels 7, 23, 39.. */
+ if ((idx & 0xf) == 0x7)
+ return 2; /* 80 MHz */
+ /* channels 15, 47, 79...*/
+ if ((idx & 0x1f) == 0xf)
+ return 3; /* 160 MHz */
+
+ return -1;
+}
+
+
+int is_6ghz_freq(int freq)
+{
+ if (freq < 5940 || freq > 7105)
+ return 0;
+
+ if (center_idx_to_bw_6ghz((freq - 5940) / 5) < 0)
+ return 0;
+
+ return 1;
+}
+
+
+int is_6ghz_op_class(u8 op_class)
+{
+ return op_class >= 131 && op_class <= 135;
+}
+
+
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len)
{
@@ -2012,3 +2076,75 @@ int ieee802_11_ext_capab(const u8 *ie, unsigned int capab)
return 0;
return !!(ie[2 + capab / 8] & BIT(capab % 8));
}
+
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg)
+{
+ if (!edmg_enable) {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ return;
+ }
+
+ /* Only EDMG CB1 and EDMG CB2 contiguous channels supported for now */
+ switch (edmg_channel) {
+ case EDMG_CHANNEL_9:
+ edmg->channels = EDMG_CHANNEL_9_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_10:
+ edmg->channels = EDMG_CHANNEL_10_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_11:
+ edmg->channels = EDMG_CHANNEL_11_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_12:
+ edmg->channels = EDMG_CHANNEL_12_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ case EDMG_CHANNEL_13:
+ edmg->channels = EDMG_CHANNEL_13_SUBCHANNELS;
+ edmg->bw_config = EDMG_BW_CONFIG_5;
+ return;
+ default:
+ if (primary_channel > 0 && primary_channel < 7) {
+ edmg->channels = BIT(primary_channel - 1);
+ edmg->bw_config = EDMG_BW_CONFIG_4;
+ } else {
+ edmg->channels = 0;
+ edmg->bw_config = 0;
+ }
+ break;
+ }
+}
+
+
+/* Check if the requested EDMG configuration is a subset of the allowed
+ * EDMG configuration. */
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested)
+{
+ /*
+ * The validation check if the requested EDMG configuration
+ * is a subset of the allowed EDMG configuration:
+ * 1. Check that the requested channels are part (set) of the allowed
+ * channels.
+ * 2. P802.11ay defines the values of bw_config between 4 and 15.
+ * (bw config % 4) will give us 4 groups inside bw_config definition,
+ * inside each group we can check the subset just by comparing the
+ * bw_config value.
+ * Between this 4 groups, there is no subset relation - as a result of
+ * the P802.11ay definition.
+ * bw_config defined by IEEE P802.11ay/D4.0, 9.4.2.251, Table 13.
+ */
+ if (((requested.channels & allowed.channels) != requested.channels) ||
+ ((requested.bw_config % 4) > (allowed.bw_config % 4)) ||
+ requested.bw_config > allowed.bw_config)
+ return 0;
+
+ return 1;
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 9b045b4..052f333 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -40,6 +40,7 @@ struct ieee802_11_elems {
const u8 *ext_supp_rates;
const u8 *wpa_ie;
const u8 *rsn_ie;
+ const u8 *rsnxe;
const u8 *wmm; /* WMM Information or Parameter Element */
const u8 *wmm_tspec;
const u8 *wps_ie;
@@ -102,6 +103,7 @@ struct ieee802_11_elems {
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
+ u8 rsnxe_len;
u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
u8 wmm_tspec_len;
u8 wps_ie_len;
@@ -220,6 +222,9 @@ u8 country_to_global_op_class(const char *country, u8 op_class);
const struct oper_class_map * get_oper_class(const char *country, u8 op_class);
int oper_class_bw_to_int(const struct oper_class_map *map);
+int center_idx_to_bw_6ghz(u8 idx);
+int is_6ghz_freq(int freq);
+int is_6ghz_op_class(u8 op_class);
int ieee802_11_parse_candidate_list(const char *pos, u8 *nei_rep,
size_t nei_rep_len);
@@ -273,4 +278,13 @@ static inline int for_each_element_completed(const struct element *element,
return (const u8 *) element == (const u8 *) data + datalen;
}
+struct ieee80211_edmg_config;
+
+void hostapd_encode_edmg_chan(int edmg_enable, u8 edmg_channel,
+ int primary_channel,
+ struct ieee80211_edmg_config *edmg);
+
+int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
+ struct ieee80211_edmg_config requested);
+
#endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 214ba0e..fbed051 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -204,6 +204,7 @@
#define WLAN_STATUS_FILS_AUTHENTICATION_FAILURE 112
#define WLAN_STATUS_UNKNOWN_AUTHENTICATION_SERVER 113
#define WLAN_STATUS_UNKNOWN_PASSWORD_IDENTIFIER 123
+#define WLAN_STATUS_SAE_HASH_TO_ELEMENT 126
/* Reason codes (IEEE Std 802.11-2016, 9.4.1.7, Table 9-45) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -446,6 +447,7 @@
#define WLAN_EID_FILS_INDICATION 240
#define WLAN_EID_DILS 241
#define WLAN_EID_FRAGMENT 242
+#define WLAN_EID_RSNX 244
#define WLAN_EID_EXTENSION 255
/* Element ID Extension (EID 255) values */
@@ -470,6 +472,9 @@
#define WLAN_EID_EXT_HE_MU_EDCA_PARAMS 38
#define WLAN_EID_EXT_SPATIAL_REUSE 39
#define WLAN_EID_EXT_OCV_OCI 54
+#define WLAN_EID_EXT_EDMG_CAPABILITIES 61
+#define WLAN_EID_EXT_EDMG_OPERATION 62
+#define WLAN_EID_EXT_REJECTED_GROUPS 92
/* Extended Capabilities field */
#define WLAN_EXT_CAPAB_20_40_COEX 0
@@ -552,6 +557,11 @@
#define WLAN_EXT_CAPAB_SAE_PW_ID 81
#define WLAN_EXT_CAPAB_SAE_PW_ID_EXCLUSIVELY 82
+/* Extended RSN Capabilities */
+/* bits 0-3: Field length (n-1) */
+#define WLAN_RSNX_CAPAB_PROTECTED_TWT 4
+#define WLAN_RSNX_CAPAB_SAE_H2E 5
+
/* Action frame categories (IEEE Std 802.11-2016, 9.4.1.11, Table 9-76) */
#define WLAN_ACTION_SPECTRUM_MGMT 0
#define WLAN_ACTION_QOS 1
@@ -1217,6 +1227,7 @@ struct ieee80211_ampe_ie {
#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+#define BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY 123
/* VHT Defines */
#define VHT_CAP_MAX_MPDU_LENGTH_7991 ((u32) BIT(0))
@@ -2174,6 +2185,10 @@ struct ieee80211_spatial_reuse {
BIT(10) | BIT(11) | \
BIT(12) | BIT(13)))
#define HE_OPERATION_RTS_THRESHOLD_OFFSET 4
+#define HE_OPERATION_VHT_OPER_INFO ((u32) BIT(14))
+#define HE_OPERATION_COHOSTED_BSS ((u32) BIT(15))
+#define HE_OPERATION_ER_SU_DISABLE ((u32) BIT(16))
+#define HE_OPERATION_6GHZ_OPER_INFO ((u32) BIT(17))
#define HE_OPERATION_BSS_COLOR_MASK ((u32) (BIT(24) | BIT(25) | \
BIT(26) | BIT(27) | \
BIT(28) | BIT(29)))
@@ -2221,6 +2236,39 @@ struct ieee80211_he_mu_edca_parameter_set {
/* B7: Reserved if sent by an AP; More Data Ack if sent by a non-AP STA */
#define HE_QOS_INFO_MORE_DATA_ACK ((u8) (BIT(7)))
+/* IEEE P802.11ay/D4.0, 9.4.2.251 - EDMG Operation element */
+#define EDMG_BSS_OPERATING_CHANNELS_OFFSET 6
+#define EDMG_OPERATING_CHANNEL_WIDTH_OFFSET 7
+
+/* IEEE P802.11ay/D4.0, 29.3.4 - Channelization */
+enum edmg_channel {
+ EDMG_CHANNEL_9 = 9,
+ EDMG_CHANNEL_10 = 10,
+ EDMG_CHANNEL_11 = 11,
+ EDMG_CHANNEL_12 = 12,
+ EDMG_CHANNEL_13 = 13,
+};
+
+/* Represent CB2 contiguous channels */
+#define EDMG_CHANNEL_9_SUBCHANNELS (BIT(0) | BIT(1)) /* channels 1 and 2 */
+#define EDMG_CHANNEL_10_SUBCHANNELS (BIT(1) | BIT(2)) /* channels 2 and 3 */
+#define EDMG_CHANNEL_11_SUBCHANNELS (BIT(2) | BIT(3)) /* channels 3 and 4 */
+#define EDMG_CHANNEL_12_SUBCHANNELS (BIT(3) | BIT(4)) /* channels 4 and 5 */
+#define EDMG_CHANNEL_13_SUBCHANNELS (BIT(4) | BIT(5)) /* channels 5 and 6 */
+
+/**
+ * enum edmg_bw_config - Allowed channel bandwidth configurations
+ * @EDMG_BW_CONFIG_4: 2.16 GHz
+ * @EDMG_BW_CONFIG_5: 2.16 GHz and 4.32 GHz
+ *
+ * IEEE P802.11ay/D4.0, 9.4.2.251 (EDMG Operation element),
+ * Table 13 (Channel BW Configuration subfield definition)
+ */
+enum edmg_bw_config {
+ EDMG_BW_CONFIG_4 = 4,
+ EDMG_BW_CONFIG_5 = 5,
+};
+
/* DPP Public Action frame identifiers - OUI_WFA */
#define DPP_OUI_TYPE 0x1A
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index 0022a8c..a0a0fb5 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -589,10 +589,11 @@ enum qca_radiotap_vendor_ids {
* by the firmware to user space for persistent storage. The attributes
* defined in enum qca_vendor_attr_interop_issues_ap are used to deliver
* the parameters.
- * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command is used to send OEM data
- * binary blobs from application/service to firmware. The attributes
- * defined in enum qca_wlan_vendor_attr_oem_data_params are used to deliver
- * the parameters.
+ * @QCA_NL80211_VENDOR_SUBCMD_OEM_DATA: This command/event is used to
+ * send/receive OEM data binary blobs to/from application/service to/from
+ * firmware. The attributes defined in enum
+ * qca_wlan_vendor_attr_oem_data_params are used to deliver the
+ * parameters.
* @QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT: This command/event is used
* to send/receive avoid frequency data using
* enum qca_wlan_vendor_attr_avoid_frequency_ext.
@@ -600,6 +601,14 @@ enum qca_radiotap_vendor_ids {
* QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY since existing command/event
* is using stream of bytes instead of structured data using vendor
* attributes.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE: This vendor subcommand is used to
+ * add the STA node details in driver/firmware. Attributes for this event
+ * are specified in enum qca_wlan_vendor_attr_add_sta_node_params.
+ * @QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE: This command is used to set BT
+ * coex chain mode from application/service.
+ * The attributes defined in enum qca_vendor_attr_btc_chain_mode are used
+ * to deliver the parameters.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -773,6 +782,8 @@ enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_INTEROP_ISSUES_AP = 181,
QCA_NL80211_VENDOR_SUBCMD_OEM_DATA = 182,
QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY_EXT = 183,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE = 184,
+ QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE = 185,
};
enum qca_wlan_vendor_attr {
@@ -5473,8 +5484,18 @@ enum qca_wlan_vendor_attr_spectral_cap {
* u8 attribute.
*/
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_DEFAULT_AGC_MAX_GAIN = 10,
- /* Flag attribute to indicate agile spectral scan capability */
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 20/40/80 MHz modes.
+ */
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL = 11,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 160 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_160 = 12,
+ /* Flag attribute to indicate agile spectral scan capability
+ * for 80+80 MHz mode.
+ */
+ QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AGILE_SPECTRAL_80_80 = 13,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_SPECTRAL_SCAN_CAP_MAX =
@@ -7899,17 +7920,42 @@ enum qca_vendor_attr_interop_issues_ap {
QCA_WLAN_VENDOR_ATTR_INTEROP_ISSUES_AP_AFTER_LAST - 1
};
-/*
- * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command
+/**
+ * enum qca_vendor_oem_device_type - Represents the target device in firmware.
+ * It is used by QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_VIRTUAL: The command is intended for
+ * a virtual device.
+ *
+ * @QCA_VENDOR_OEM_DEVICE_PHYSICAL: The command is intended for
+ * a physical device.
+ */
+enum qca_vendor_oem_device_type {
+ QCA_VENDOR_OEM_DEVICE_VIRTUAL = 0,
+ QCA_VENDOR_OEM_DEVICE_PHYSICAL = 1,
+};
+
+/**
+ * enum qca_wlan_vendor_attr_oem_data_params - Used by the vendor command/event
* QCA_NL80211_VENDOR_SUBCMD_OEM_DATA.
*
* @QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA: The binary blob for the vendor
- * command QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this attribute.
+ * command/event QCA_NL80211_VENDOR_SUBCMD_OEM_DATA are carried through this
+ * attribute.
* NLA_BINARY attribute, the max size is 1024 bytes.
+ *
+ * @QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO: The binary blob will be routed
+ * based on this field. This optional attribute is included to specify whether
+ * the device type is a virtual device or a physical device for the
+ * command/event. This attribute can be omitted for a virtual device (default)
+ * command/event.
+ * This u8 attribute is used to carry information for the device type using
+ * values defined by enum qca_vendor_oem_device_type.
*/
enum qca_wlan_vendor_attr_oem_data_params {
QCA_WLAN_VENDOR_ATTR_OEM_DATA_INVALID = 0,
QCA_WLAN_VENDOR_ATTR_OEM_DATA_CMD_DATA = 1,
+ QCA_WLAN_VENDOR_ATTR_OEM_DEVICE_INFO = 2,
/* keep last */
QCA_WLAN_VENDOR_ATTR_OEM_DATA_PARAMS_AFTER_LAST,
@@ -7943,4 +7989,61 @@ enum qca_wlan_vendor_attr_avoid_frequency_ext {
QCA_WLAN_VENDOR_ATTR_AVOID_FREQUENCY_AFTER_LAST - 1
};
+/*
+ * enum qca_wlan_vendor_attr_add_sta_node_params - Used by the vendor command
+ * QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE.
+ */
+enum qca_wlan_vendor_attr_add_sta_node_params {
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_INVALID = 0,
+ /* 6 byte MAC address of STA */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR = 1,
+ /* Authentication algorithm used by the station of size u16;
+ * defined in enum nl80211_auth_type.
+ */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO = 2,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_MAX =
+ QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_PARAM_AFTER_LAST - 1
+};
+
+/**
+ * enum qca_btc_chain_mode - Specifies BT coex chain mode.
+ * This enum defines the valid set of values of BT coex chain mode.
+ * These values are used by attribute %QCA_VENDOR_ATTR_BTC_CHAIN_MODE of
+ * %QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_BTC_CHAIN_SHARED: chains of BT and WLAN 2.4G are shared.
+ * @QCA_BTC_CHAIN_SEPARATED: chains of BT and WLAN 2.4G are separated.
+ */
+enum qca_btc_chain_mode {
+ QCA_BTC_CHAIN_SHARED = 0,
+ QCA_BTC_CHAIN_SEPARATED = 1,
+};
+
+/**
+ * enum qca_vendor_attr_btc_chain_mode - Specifies attributes for BT coex
+ * chain mode.
+ * Attributes for data used by QCA_NL80211_VENDOR_SUBCMD_BTC_CHAIN_MODE.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE: u32 attribute.
+ * Indicates the BT coex chain mode, are 32-bit values from
+ * enum qca_btc_chain_mode. This attribute is mandatory.
+ *
+ * @QCA_VENDOR_ATTR_COEX_BTC_CHAIN_MODE_RESTART: flag attribute.
+ * If set, vdev should be restarted when BT coex chain mode is updated.
+ * This attribute is optional.
+ */
+enum qca_vendor_attr_btc_chain_mode {
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_INVALID = 0,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE = 1,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_RESTART = 2,
+
+ /* Keep last */
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST,
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_MAX =
+ QCA_VENDOR_ATTR_BTC_CHAIN_MODE_LAST - 1,
+};
+
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index 3960914..2ab168b 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -12,6 +12,8 @@
#include "utils/const_time.h"
#include "crypto/crypto.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
+#include "crypto/sha512.h"
#include "crypto/random.h"
#include "crypto/dh_groups.h"
#include "ieee802_11_defs.h"
@@ -107,6 +109,8 @@ void sae_clear_temp_data(struct sae_data *sae)
crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
wpabuf_free(tmp->anti_clogging_token);
+ wpabuf_free(tmp->own_rejected_groups);
+ wpabuf_free(tmp->peer_rejected_groups);
os_free(tmp->pw_id);
bin_clear_free(tmp, sizeof(*tmp));
sae->tmp = NULL;
@@ -525,6 +529,742 @@ fail:
}
+static int hkdf_extract(size_t hash_len, const u8 *salt, size_t salt_len,
+ size_t num_elem, const u8 *addr[], const size_t len[],
+ u8 *prk)
+{
+ if (hash_len == 32)
+ return hmac_sha256_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_vector(salt, salt_len, num_elem, addr, len,
+ prk);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int hkdf_expand(size_t hash_len, const u8 *prk, size_t prk_len,
+ const char *info, u8 *okm, size_t okm_len)
+{
+ size_t info_len = os_strlen(info);
+
+ if (hash_len == 32)
+ return hmac_sha256_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return hmac_sha384_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return hmac_sha512_kdf(prk, prk_len, NULL,
+ (const u8 *) info, info_len,
+ okm, okm_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
+static int sswu_curve_param(int group, int *z)
+{
+ switch (group) {
+ case 19:
+ case 20:
+ case 21:
+ case 28:
+ *z = -2;
+ return 0;
+ case 25:
+ case 29:
+ *z = -5;
+ return 0;
+ case 26:
+ *z = -11;
+ return 0;
+ case 30:
+ *z = 2;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void debug_print_bignum(const char *title, const struct crypto_bignum *a,
+ size_t prime_len)
+{
+ u8 *bin;
+
+ bin = os_malloc(prime_len);
+ if (bin && crypto_bignum_to_bin(a, bin, prime_len, prime_len) >= 0)
+ wpa_hexdump_key(MSG_DEBUG, title, bin, prime_len);
+ else
+ wpa_printf(MSG_DEBUG, "Could not print bignum (%s)", title);
+ bin_clear_free(bin, prime_len);
+}
+
+
+static struct crypto_ec_point * sswu(struct crypto_ec *ec, int group,
+ const struct crypto_bignum *u)
+{
+ int z_int;
+ const struct crypto_bignum *a, *b, *prime;
+ struct crypto_bignum *u2, *t1, *t2, *z, *t, *zero, *one, *two, *three,
+ *x1a, *x1b, *y = NULL;
+ struct crypto_bignum *x1 = NULL, *x2, *gx1, *gx2, *v = NULL;
+ unsigned int m_is_zero, is_qr, is_eq;
+ size_t prime_len;
+ u8 bin[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin1[SAE_MAX_ECC_PRIME_LEN];
+ u8 bin2[SAE_MAX_ECC_PRIME_LEN];
+ u8 x_y[2 * SAE_MAX_ECC_PRIME_LEN];
+ struct crypto_ec_point *p = NULL;
+
+ if (sswu_curve_param(group, &z_int) < 0)
+ return NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ a = crypto_ec_get_a(ec);
+ b = crypto_ec_get_b(ec);
+
+ u2 = crypto_bignum_init();
+ t1 = crypto_bignum_init();
+ t2 = crypto_bignum_init();
+ z = crypto_bignum_init_uint(abs(z_int));
+ t = crypto_bignum_init();
+ zero = crypto_bignum_init_uint(0);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ three = crypto_bignum_init_uint(3);
+ x1a = crypto_bignum_init();
+ x1b = crypto_bignum_init();
+ x2 = crypto_bignum_init();
+ gx1 = crypto_bignum_init();
+ gx2 = crypto_bignum_init();
+ if (!u2 || !t1 || !t2 || !z || !t || !zero || !one || !two || !three ||
+ !x1a || !x1b || !x2 || !gx1 || !gx2)
+ goto fail;
+
+ if (z_int < 0 && crypto_bignum_sub(prime, z, z) < 0)
+ goto fail;
+
+ /* m = z^2 * u^4 + z * u^2 */
+ /* --> tmp = z * u^2, m = tmp^2 + tmp */
+
+ /* u2 = u^2
+ * t1 = z * u2
+ * t2 = t1^2
+ * m = t1 = t1 + t2 */
+ if (crypto_bignum_sqrmod(u, prime, u2) < 0 ||
+ crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_sqrmod(t1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: m", t1, prime_len);
+
+ /* l = CEQ(m, 0)
+ * t = CSEL(l, 0, inverse(m); where inverse(x) is calculated as
+ * x^(p-2) modulo p which will handle m == 0 case correctly */
+ /* TODO: Make sure crypto_bignum_is_zero() is constant time */
+ m_is_zero = const_time_eq(crypto_bignum_is_zero(t1), 1);
+ /* t = m^(p-2) modulo p */
+ if (crypto_bignum_sub(prime, two, t2) < 0 ||
+ crypto_bignum_exptmod(t1, t2, prime, t) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: t", t, prime_len);
+
+ /* b / (z * a) */
+ if (crypto_bignum_mulmod(z, a, prime, t1) < 0 ||
+ crypto_bignum_inverse(t1, prime, t1) < 0 ||
+ crypto_bignum_mulmod(b, t1, prime, x1a) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1a = b / (z * a)", x1a, prime_len);
+
+ /* (-b/a) * (1 + t) */
+ if (crypto_bignum_sub(prime, b, t1) < 0 ||
+ crypto_bignum_inverse(a, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(one, t, prime, t2) < 0 ||
+ crypto_bignum_mulmod(t1, t2, prime, x1b) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x1b = (-b/a) * (1 + t)", x1b, prime_len);
+
+ /* x1 = CSEL(CEQ(m, 0), x1a, x1b) */
+ if (crypto_bignum_to_bin(x1a, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x1b, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(m_is_zero, bin1, bin2, prime_len, bin);
+ x1 = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: x1 = CSEL(l, x1a, x1b)", x1, prime_len);
+
+ /* gx1 = x1^3 + a * x1 + b */
+ if (crypto_bignum_exptmod(x1, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x1, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1 = x1^3 + a * x1 + b", gx1, prime_len);
+
+ /* x2 = z * u^2 * x1 */
+ if (crypto_bignum_mulmod(z, u2, prime, t1) < 0 ||
+ crypto_bignum_mulmod(t1, x1, prime, x2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: x2 = z * u^2 * x1", x2, prime_len);
+
+ /* gx2 = x2^3 + a * x2 + b */
+ if (crypto_bignum_exptmod(x2, three, prime, t1) < 0 ||
+ crypto_bignum_mulmod(a, x2, prime, t2) < 0 ||
+ crypto_bignum_addmod(t1, t2, prime, t1) < 0 ||
+ crypto_bignum_addmod(t1, b, prime, gx2) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx2 = x2^3 + a * x2 + b", gx2, prime_len);
+
+ /* l = gx1 is a quadratic residue modulo p
+ * --> gx1^((p-1)/2) modulo p is zero or one */
+ if (crypto_bignum_sub(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 1, t1) < 0 ||
+ crypto_bignum_exptmod(gx1, t1, prime, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: gx1^((p-1)/2) modulo p", t1, prime_len);
+ is_qr = const_time_eq(crypto_bignum_is_zero(t1) |
+ crypto_bignum_is_one(t1), 1);
+
+ /* v = CSEL(l, gx1, gx2) */
+ if (crypto_bignum_to_bin(gx1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(gx2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, bin);
+ v = crypto_bignum_init_set(bin, prime_len);
+ debug_print_bignum("SSWU: v = CSEL(l, gx1, gx2)", v, prime_len);
+
+ /* x = CSEL(l, x1, x2) */
+ if (crypto_bignum_to_bin(x1, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(x2, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_qr, bin1, bin2, prime_len, x_y);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: x = CSEL(l, x1, x2)", x_y, prime_len);
+
+ /* y = sqrt(v)
+ * For prime p such that p = 3 mod 4 --> v^((p+1)/4) */
+ if (crypto_bignum_to_bin(prime, bin1, sizeof(bin1), prime_len) < 0)
+ goto fail;
+ if ((bin1[prime_len - 1] & 0x03) != 3) {
+ wpa_printf(MSG_DEBUG, "SSWU: prime does not have p = 3 mod 4");
+ goto fail;
+ }
+ y = crypto_bignum_init();
+ if (!y ||
+ crypto_bignum_add(prime, one, t1) < 0 ||
+ crypto_bignum_rshift(t1, 2, t1) < 0 ||
+ crypto_bignum_exptmod(v, t1, prime, y) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: y = sqrt(v)", y, prime_len);
+
+ /* l = CEQ(LSB(u), LSB(y)) */
+ if (crypto_bignum_to_bin(u, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(y, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ is_eq = const_time_eq(bin1[prime_len - 1] & 0x01,
+ bin2[prime_len - 1] & 0x01);
+
+ /* P = CSEL(l, (x,y), (x, p-y)) */
+ if (crypto_bignum_sub(prime, y, t1) < 0)
+ goto fail;
+ debug_print_bignum("SSWU: p - y", t1, prime_len);
+ if (crypto_bignum_to_bin(y, bin1, sizeof(bin1), prime_len) < 0 ||
+ crypto_bignum_to_bin(t1, bin2, sizeof(bin2), prime_len) < 0)
+ goto fail;
+ const_time_select_bin(is_eq, bin1, bin2, prime_len, &x_y[prime_len]);
+
+ /* output P */
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.x", x_y, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SSWU: P.y", &x_y[prime_len], prime_len);
+ p = crypto_ec_point_from_bin(ec, x_y);
+
+fail:
+ crypto_bignum_deinit(u2, 1);
+ crypto_bignum_deinit(t1, 1);
+ crypto_bignum_deinit(t2, 1);
+ crypto_bignum_deinit(z, 0);
+ crypto_bignum_deinit(t, 1);
+ crypto_bignum_deinit(x1a, 1);
+ crypto_bignum_deinit(x1b, 1);
+ crypto_bignum_deinit(x1, 1);
+ crypto_bignum_deinit(x2, 1);
+ crypto_bignum_deinit(gx1, 1);
+ crypto_bignum_deinit(gx2, 1);
+ crypto_bignum_deinit(y, 1);
+ crypto_bignum_deinit(v, 1);
+ crypto_bignum_deinit(zero, 0);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(three, 0);
+ forced_memzero(bin, sizeof(bin));
+ forced_memzero(bin1, sizeof(bin1));
+ forced_memzero(bin2, sizeof(bin2));
+ forced_memzero(x_y, sizeof(x_y));
+ return p;
+}
+
+
+static int sae_pwd_seed(size_t hash_len, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier, u8 *pwd_seed)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ size_t num_elem;
+
+ /* pwd-seed = HKDF-Extract(ssid, password [ || identifier ]) */
+ addr[0] = password;
+ len[0] = password_len;
+ num_elem = 1;
+ wpa_hexdump_ascii(MSG_DEBUG, "SAE: SSID", ssid, ssid_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "SAE: password",
+ password, password_len);
+ if (identifier) {
+ wpa_printf(MSG_DEBUG, "SAE: password identifier: %s",
+ identifier);
+ addr[num_elem] = (const u8 *) identifier;
+ len[num_elem] = os_strlen(identifier);
+ num_elem++;
+ }
+ if (hkdf_extract(hash_len, ssid, ssid_len, num_elem, addr, len,
+ pwd_seed) < 0)
+ return -1;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-seed", pwd_seed, hash_len);
+ return 0;
+}
+
+
+size_t sae_ecc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 256 / 8)
+ return 32;
+ if (prime_len <= 384 / 8)
+ return 48;
+ return 64;
+}
+
+
+struct crypto_ec_point *
+sae_derive_pt_ecc(struct crypto_ec *ec, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t pwd_value_len, hash_len, prime_len;
+ const struct crypto_bignum *prime;
+ struct crypto_bignum *bn = NULL;
+ struct crypto_ec_point *p1 = NULL, *p2 = NULL, *pt = NULL;
+
+ prime = crypto_ec_get_prime(ec);
+ prime_len = crypto_ec_prime_len(ec);
+ if (prime_len > SAE_MAX_ECC_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u1 P1", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u1 P1", pwd_value, pwd_value_len) <
+ 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u1 P1)",
+ pwd_value, pwd_value_len);
+
+ /* u1 = pwd-value modulo p */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u1", pwd_value, prime_len);
+
+ /* P1 = SSWU(u1) */
+ p1 = sswu(ec, group, bn);
+ if (!p1)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element u2 P2", len)
+ */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element u2 P2", pwd_value,
+ pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value (u2 P2)",
+ pwd_value, pwd_value_len);
+
+ /* u2 = pwd-value modulo p */
+ crypto_bignum_deinit(bn, 1);
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ if (!bn || crypto_bignum_mod(bn, prime, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: u2", pwd_value, prime_len);
+
+ /* P2 = SSWU(u2) */
+ p2 = sswu(ec, group, bn);
+ if (!p2)
+ goto fail;
+
+ /* PT = elem-op(P1, P2) */
+ pt = crypto_ec_point_init(ec);
+ if (!pt)
+ goto fail;
+ if (crypto_ec_point_add(ec, p1, p2, pt) < 0) {
+ crypto_ec_point_deinit(pt, 1);
+ pt = NULL;
+ }
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_ec_point_deinit(p1, 1);
+ crypto_ec_point_deinit(p2, 1);
+ return pt;
+}
+
+
+size_t sae_ffc_prime_len_2_hash_len(size_t prime_len)
+{
+ if (prime_len <= 2048 / 8)
+ return 32;
+ if (prime_len <= 3072 / 8)
+ return 48;
+ return 64;
+}
+
+
+static struct crypto_bignum *
+sae_derive_pt_ffc(const struct dh_group *dh, int group,
+ const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ size_t hash_len, prime_len, pwd_value_len;
+ struct crypto_bignum *prime, *order;
+ struct crypto_bignum *one = NULL, *two = NULL, *bn = NULL, *tmp = NULL,
+ *pt = NULL;
+ u8 pwd_seed[64];
+ u8 pwd_value[SAE_MAX_PRIME_LEN + SAE_MAX_PRIME_LEN / 2];
+
+ prime = crypto_bignum_init_set(dh->prime, dh->prime_len);
+ order = crypto_bignum_init_set(dh->order, dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = dh->prime_len;
+ if (prime_len > SAE_MAX_PRIME_LEN)
+ goto fail;
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+
+ /* len = olen(p) + ceil(olen(p)/2) */
+ pwd_value_len = prime_len + (prime_len + 1) / 2;
+ if (pwd_value_len > sizeof(pwd_value))
+ goto fail;
+
+ if (sae_pwd_seed(hash_len, ssid, ssid_len, password, password_len,
+ identifier, pwd_seed) < 0)
+ goto fail;
+
+ /* pwd-value = HKDF-Expand(pwd-seed, "SAE Hash to Element", len) */
+ if (hkdf_expand(hash_len, pwd_seed, hash_len,
+ "SAE Hash to Element", pwd_value, pwd_value_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value",
+ pwd_value, pwd_value_len);
+
+ /* pwd-value = (pwd-value modulo (p-2)) + 2 */
+ bn = crypto_bignum_init_set(pwd_value, pwd_value_len);
+ one = crypto_bignum_init_uint(1);
+ two = crypto_bignum_init_uint(2);
+ tmp = crypto_bignum_init();
+ if (!bn || !one || !two || !tmp ||
+ crypto_bignum_sub(prime, two, tmp) < 0 ||
+ crypto_bignum_mod(bn, tmp, bn) < 0 ||
+ crypto_bignum_add(bn, two, bn) < 0 ||
+ crypto_bignum_to_bin(bn, pwd_value, sizeof(pwd_value),
+ prime_len) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: pwd-value(reduced)",
+ pwd_value, prime_len);
+
+ /* PT = pwd-value^((p-1)/q) modulo p */
+ pt = crypto_bignum_init();
+ if (!pt ||
+ crypto_bignum_sub(prime, one, tmp) < 0 ||
+ crypto_bignum_div(tmp, order, tmp) < 0 ||
+ crypto_bignum_exptmod(bn, tmp, prime, pt) < 0) {
+ crypto_bignum_deinit(pt, 1);
+ pt = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PT", pt, prime_len);
+
+fail:
+ forced_memzero(pwd_seed, sizeof(pwd_seed));
+ forced_memzero(pwd_value, sizeof(pwd_value));
+ crypto_bignum_deinit(bn, 1);
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(two, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pt;
+}
+
+
+static struct sae_pt *
+sae_derive_pt_group(int group, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PT - group %d", group);
+
+ pt = os_zalloc(sizeof(*pt));
+ if (!pt)
+ return NULL;
+
+ pt->group = group;
+ pt->ec = crypto_ec_init(group);
+ if (pt->ec) {
+ pt->ecc_pt = sae_derive_pt_ecc(pt->ec, group, ssid, ssid_len,
+ password, password_len,
+ identifier);
+ if (!pt->ecc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+ }
+
+ pt->dh = dh_groups_get(group);
+ if (!pt->dh) {
+ wpa_printf(MSG_DEBUG, "SAE: Unsupported group %d", group);
+ goto fail;
+ }
+
+ pt->ffc_pt = sae_derive_pt_ffc(pt->dh, group, ssid, ssid_len,
+ password, password_len, identifier);
+ if (!pt->ffc_pt) {
+ wpa_printf(MSG_DEBUG, "SAE: Failed to derive PT");
+ goto fail;
+ }
+
+ return pt;
+fail:
+ sae_deinit_pt(pt);
+ return NULL;
+}
+
+
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier)
+{
+ struct sae_pt *pt = NULL, *last = NULL, *tmp;
+ int default_groups[] = { 19, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+ for (i = 0; groups[i] > 0; i++) {
+ tmp = sae_derive_pt_group(groups[i], ssid, ssid_len, password,
+ password_len, identifier);
+ if (!tmp)
+ continue;
+
+ if (last)
+ last->next = tmp;
+ else
+ pt = tmp;
+ last = tmp;
+ }
+
+ return pt;
+}
+
+
+static void sae_max_min_addr(const u8 *addr[], size_t len[],
+ const u8 *addr1, const u8 *addr2)
+{
+ len[0] = ETH_ALEN;
+ len[1] = ETH_ALEN;
+ if (os_memcmp(addr1, addr2, ETH_ALEN) > 0) {
+ addr[0] = addr1;
+ addr[1] = addr2;
+ } else {
+ addr[0] = addr2;
+ addr[1] = addr1;
+ }
+}
+
+
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ u8 bin[SAE_MAX_ECC_PRIME_LEN * 2];
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ const struct crypto_bignum *order;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_ec_point *pwe = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime_len = crypto_ec_prime_len(pt->ec);
+ if (crypto_ec_point_to_bin(pt->ec, pt->ecc_pt,
+ bin, bin + prime_len) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PT.y", bin + prime_len, prime_len);
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ order = crypto_ec_get_order(pt->ec);
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_ec_point_init(pt->ec);
+ if (!pwe ||
+ crypto_ec_point_mul(pt->ec, pt->ecc_pt, val, pwe) < 0 ||
+ crypto_ec_point_to_bin(pt->ec, pwe, bin, bin + prime_len) < 0) {
+ crypto_ec_point_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.x", bin, prime_len);
+ wpa_hexdump_key(MSG_DEBUG, "SAE: PWE.y", bin + prime_len, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ return pwe;
+}
+
+
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2)
+{
+ size_t prime_len;
+ const u8 *addr[2];
+ size_t len[2];
+ u8 salt[64], hash[64];
+ size_t hash_len;
+ struct crypto_bignum *tmp = NULL, *val = NULL, *one = NULL;
+ struct crypto_bignum *pwe = NULL, *order = NULL, *prime = NULL;
+
+ wpa_printf(MSG_DEBUG, "SAE: Derive PWE from PT");
+ prime = crypto_bignum_init_set(pt->dh->prime, pt->dh->prime_len);
+ order = crypto_bignum_init_set(pt->dh->order, pt->dh->order_len);
+ if (!prime || !order)
+ goto fail;
+ prime_len = pt->dh->prime_len;
+
+ sae_max_min_addr(addr, len, addr1, addr2);
+
+ /* val = H(0^n,
+ * MAX(STA-A-MAC, STA-B-MAC) || MIN(STA-A-MAC, STA-B-MAC)) */
+ wpa_printf(MSG_DEBUG, "SAE: val = H(0^n, MAX(addrs) || MIN(addrs))");
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ os_memset(salt, 0, hash_len);
+ if (hkdf_extract(hash_len, salt, hash_len, 2, addr, len, hash) < 0)
+ goto fail;
+ wpa_hexdump(MSG_DEBUG, "SAE: val", hash, hash_len);
+
+ /* val = val modulo (q - 1) + 1 */
+ tmp = crypto_bignum_init();
+ val = crypto_bignum_init_set(hash, hash_len);
+ one = crypto_bignum_init_uint(1);
+ if (!tmp || !val || !one ||
+ crypto_bignum_sub(order, one, tmp) < 0 ||
+ crypto_bignum_mod(val, tmp, val) < 0 ||
+ crypto_bignum_add(val, one, val) < 0)
+ goto fail;
+ debug_print_bignum("SAE: val(reduced to 1..q-1)", val, prime_len);
+
+ /* PWE = scalar-op(val, PT) */
+ pwe = crypto_bignum_init();
+ if (!pwe || crypto_bignum_exptmod(pt->ffc_pt, val, prime, pwe) < 0) {
+ crypto_bignum_deinit(pwe, 1);
+ pwe = NULL;
+ goto fail;
+ }
+ debug_print_bignum("SAE: PWE", pwe, prime_len);
+
+fail:
+ crypto_bignum_deinit(tmp, 1);
+ crypto_bignum_deinit(val, 1);
+ crypto_bignum_deinit(one, 0);
+ crypto_bignum_deinit(prime, 0);
+ crypto_bignum_deinit(order, 0);
+ return pwe;
+}
+
+
+void sae_deinit_pt(struct sae_pt *pt)
+{
+ struct sae_pt *prev;
+
+ while (pt) {
+ crypto_ec_point_deinit(pt->ecc_pt, 1);
+ crypto_bignum_deinit(pt->ffc_pt, 1);
+ crypto_ec_deinit(pt->ec);
+ prev = pt;
+ pt = pt->next;
+ os_free(prev);
+ }
+}
+
+
static int sae_derive_commit_element_ecc(struct sae_data *sae,
struct crypto_bignum *mask)
{
@@ -604,10 +1344,66 @@ int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
identifier) < 0) ||
(sae->tmp->dh && sae_derive_pwe_ffc(sae, addr1, addr2, password,
password_len,
- identifier) < 0) ||
- sae_derive_commit(sae) < 0)
+ identifier) < 0))
return -1;
- return 0;
+
+ sae->tmp->h2e = 0;
+ return sae_derive_commit(sae);
+}
+
+
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups)
+{
+ if (!sae->tmp)
+ return -1;
+
+ while (pt) {
+ if (pt->group == sae->group)
+ break;
+ pt = pt->next;
+ }
+ if (!pt) {
+ wpa_printf(MSG_INFO, "SAE: Could not find PT for group %u",
+ sae->group);
+ return -1;
+ }
+
+ sae->tmp->own_addr_higher = os_memcmp(addr1, addr2, ETH_ALEN) > 0;
+ wpabuf_free(sae->tmp->own_rejected_groups);
+ sae->tmp->own_rejected_groups = NULL;
+ if (rejected_groups) {
+ int count, i;
+ struct wpabuf *groups;
+
+ count = int_array_len(rejected_groups);
+ groups = wpabuf_alloc(count * 2);
+ if (!groups)
+ return -1;
+ for (i = 0; i < count; i++)
+ wpabuf_put_le16(groups, rejected_groups[i]);
+ sae->tmp->own_rejected_groups = groups;
+ }
+
+ if (pt->ec) {
+ crypto_ec_point_deinit(sae->tmp->pwe_ecc, 1);
+ sae->tmp->pwe_ecc = sae_derive_pwe_from_pt_ecc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ecc)
+ return -1;
+ }
+
+ if (pt->dh) {
+ crypto_bignum_deinit(sae->tmp->pwe_ffc, 1);
+ sae->tmp->pwe_ffc = sae_derive_pwe_from_pt_ffc(pt, addr1,
+ addr2);
+ if (!sae->tmp->pwe_ffc)
+ return -1;
+ }
+
+ sae->tmp->h2e = 1;
+ return sae_derive_commit(sae);
}
@@ -685,32 +1481,99 @@ fail:
}
+static int sae_kdf_hash(size_t hash_len, const u8 *k, const char *label,
+ const u8 *context, size_t context_len,
+ u8 *out, size_t out_len)
+{
+ if (hash_len == 32)
+ return sha256_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#ifdef CONFIG_SHA384
+ if (hash_len == 48)
+ return sha384_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_SHA512
+ if (hash_len == 64)
+ return sha512_prf(k, hash_len, label,
+ context, context_len, out, out_len);
+#endif /* CONFIG_SHA512 */
+ return -1;
+}
+
+
static int sae_derive_keys(struct sae_data *sae, const u8 *k)
{
- u8 null_key[SAE_KEYSEED_KEY_LEN], val[SAE_MAX_PRIME_LEN];
- u8 keyseed[SHA256_MAC_LEN];
- u8 keys[SAE_KCK_LEN + SAE_PMK_LEN];
+ u8 zero[SAE_MAX_HASH_LEN], val[SAE_MAX_PRIME_LEN];
+ const u8 *salt;
+ struct wpabuf *rejected_groups = NULL;
+ u8 keyseed[SAE_MAX_HASH_LEN];
+ u8 keys[SAE_MAX_HASH_LEN + SAE_PMK_LEN];
struct crypto_bignum *tmp;
int ret = -1;
+ size_t hash_len, salt_len, prime_len = sae->tmp->prime_len;
+ const u8 *addr[1];
+ size_t len[1];
tmp = crypto_bignum_init();
if (tmp == NULL)
goto fail;
- /* keyseed = H(<0>32, k)
- * KCK || PMK = KDF-512(keyseed, "SAE KCK and PMK",
+ /* keyseed = H(salt, k)
+ * KCK || PMK = KDF-Hash-Length(keyseed, "SAE KCK and PMK",
* (commit-scalar + peer-commit-scalar) modulo r)
* PMKID = L((commit-scalar + peer-commit-scalar) modulo r, 0, 128)
*/
+ if (!sae->tmp->h2e)
+ hash_len = SHA256_MAC_LEN;
+ else if (sae->tmp->dh)
+ hash_len = sae_ffc_prime_len_2_hash_len(prime_len);
+ else
+ hash_len = sae_ecc_prime_len_2_hash_len(prime_len);
+ if (sae->tmp->h2e && (sae->tmp->own_rejected_groups ||
+ sae->tmp->peer_rejected_groups)) {
+ struct wpabuf *own, *peer;
+
+ own = sae->tmp->own_rejected_groups;
+ peer = sae->tmp->peer_rejected_groups;
+ salt_len = 0;
+ if (own)
+ salt_len += wpabuf_len(own);
+ if (peer)
+ salt_len += wpabuf_len(peer);
+ rejected_groups = wpabuf_alloc(salt_len);
+ if (!rejected_groups)
+ goto fail;
+ if (sae->tmp->own_addr_higher) {
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ } else {
+ if (peer)
+ wpabuf_put_buf(rejected_groups, peer);
+ if (own)
+ wpabuf_put_buf(rejected_groups, own);
+ }
+ salt = wpabuf_head(rejected_groups);
+ salt_len = wpabuf_len(rejected_groups);
+ } else {
+ os_memset(zero, 0, hash_len);
+ salt = zero;
+ salt_len = hash_len;
+ }
+ wpa_hexdump(MSG_DEBUG, "SAE: salt for keyseed derivation",
+ salt, salt_len);
+ addr[0] = k;
+ len[0] = prime_len;
+ if (hkdf_extract(hash_len, salt, salt_len, 1, addr, len, keyseed) < 0)
+ goto fail;
+ wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, hash_len);
- os_memset(null_key, 0, sizeof(null_key));
- hmac_sha256(null_key, sizeof(null_key), k, sae->tmp->prime_len,
- keyseed);
- wpa_hexdump_key(MSG_DEBUG, "SAE: keyseed", keyseed, sizeof(keyseed));
-
- crypto_bignum_add(sae->tmp->own_commit_scalar, sae->peer_commit_scalar,
- tmp);
- crypto_bignum_mod(tmp, sae->tmp->order, tmp);
+ if (crypto_bignum_add(sae->tmp->own_commit_scalar,
+ sae->peer_commit_scalar, tmp) < 0 ||
+ crypto_bignum_mod(tmp, sae->tmp->order, tmp) < 0)
+ goto fail;
/* IEEE Std 802.11-2016 is not exactly clear on the encoding of the bit
* string that is needed for KCK, PMK, and PMKID derivation, but it
* seems to make most sense to encode the
@@ -719,19 +1582,23 @@ static int sae_derive_keys(struct sae_data *sae, const u8 *k)
* octets). */
crypto_bignum_to_bin(tmp, val, sizeof(val), sae->tmp->order_len);
wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
- if (sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
- val, sae->tmp->order_len, keys, sizeof(keys)) < 0)
+ if (sae_kdf_hash(hash_len, keyseed, "SAE KCK and PMK",
+ val, sae->tmp->order_len,
+ keys, hash_len + SAE_PMK_LEN) < 0)
goto fail;
- os_memset(keyseed, 0, sizeof(keyseed));
- os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
- os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ forced_memzero(keyseed, sizeof(keyseed));
+ os_memcpy(sae->tmp->kck, keys, hash_len);
+ sae->tmp->kck_len = hash_len;
+ os_memcpy(sae->pmk, keys + hash_len, SAE_PMK_LEN);
os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
- os_memset(keys, 0, sizeof(keys));
- wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
+ forced_memzero(keys, sizeof(keys));
+ wpa_hexdump_key(MSG_DEBUG, "SAE: KCK",
+ sae->tmp->kck, sae->tmp->kck_len);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
ret = 0;
fail:
+ wpabuf_free(rejected_groups);
crypto_bignum_deinit(tmp, 0);
return ret;
}
@@ -794,6 +1661,16 @@ void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
wpa_printf(MSG_DEBUG, "SAE: own Password Identifier: %s",
identifier);
}
+
+ if (sae->tmp->h2e && sae->tmp->own_rejected_groups) {
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: own Rejected Groups",
+ sae->tmp->own_rejected_groups);
+ wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
+ wpabuf_put_u8(buf,
+ 1 + wpabuf_len(sae->tmp->own_rejected_groups));
+ wpabuf_put_u8(buf, WLAN_EID_EXT_REJECTED_GROUPS);
+ wpabuf_put_buf(buf, sae->tmp->own_rejected_groups);
+ }
}
@@ -849,9 +1726,19 @@ static int sae_is_password_id_elem(const u8 *pos, const u8 *end)
}
+static int sae_is_rejected_groups_elem(const u8 *pos, const u8 *end)
+{
+ return end - pos >= 3 &&
+ pos[0] == WLAN_EID_EXTENSION &&
+ pos[1] >= 2 &&
+ end - pos - 2 >= pos[1] &&
+ pos[2] == WLAN_EID_EXT_REJECTED_GROUPS;
+}
+
+
static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
const u8 *end, const u8 **token,
- size_t *token_len)
+ size_t *token_len, int h2e)
{
size_t scalar_elem_len, tlen;
const u8 *elem;
@@ -872,6 +1759,8 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
* fields, so use that length as a requirement for the received
* token and check for the presence of possible Password
* Identifier element based on the element header information.
+ * When parsing H2E case, also consider the Rejected Groupd element
+ * similarly.
*/
tlen = end - (*pos + scalar_elem_len);
@@ -889,12 +1778,27 @@ static void sae_parse_commit_token(struct sae_data *sae, const u8 **pos,
* this frame. */
return;
}
+ if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Rejected Groups takes out all available extra octets, so
+ * there can be no Anti-Clogging token in this frame. */
+ return;
+ }
elem += SHA256_MAC_LEN;
if (sae_is_password_id_elem(elem, end)) {
/* Password Identifier element is included in the end, so
* remove its length from the Anti-Clogging token field. */
tlen -= 2 + elem[1];
+ elem += 2 + elem[1];
+ if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Also remove Rejected Groups element from the
+ * Anti-Clogging token field length */
+ tlen -= 2 + elem[1];
+ }
+ } else if (h2e && sae_is_rejected_groups_elem(elem, end)) {
+ /* Rejected Groups element is included in the end, so
+ * remove its length from the Anti-Clogging token field. */
+ tlen -= 2 + elem[1];
}
wpa_hexdump(MSG_DEBUG, "SAE: Anti-Clogging Token", *pos, tlen);
@@ -1061,11 +1965,11 @@ static u16 sae_parse_commit_element(struct sae_data *sae, const u8 **pos,
static int sae_parse_password_identifier(struct sae_data *sae,
- const u8 *pos, const u8 *end)
+ const u8 **pos, const u8 *end)
{
wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
- pos, end - pos);
- if (!sae_is_password_id_elem(pos, end)) {
+ *pos, end - *pos);
+ if (!sae_is_password_id_elem(*pos, end)) {
if (sae->tmp->pw_id) {
wpa_printf(MSG_DEBUG,
"SAE: No Password Identifier included, but expected one (%s)",
@@ -1078,8 +1982,8 @@ static int sae_parse_password_identifier(struct sae_data *sae,
}
if (sae->tmp->pw_id &&
- (pos[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
- os_memcmp(sae->tmp->pw_id, pos + 3, pos[1] - 1) != 0)) {
+ ((*pos)[1] - 1 != (int) os_strlen(sae->tmp->pw_id) ||
+ os_memcmp(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1) != 0)) {
wpa_printf(MSG_DEBUG,
"SAE: The included Password Identifier does not match the expected one (%s)",
sae->tmp->pw_id);
@@ -1087,19 +1991,39 @@ static int sae_parse_password_identifier(struct sae_data *sae,
}
os_free(sae->tmp->pw_id);
- sae->tmp->pw_id = os_malloc(pos[1]);
+ sae->tmp->pw_id = os_malloc((*pos)[1]);
if (!sae->tmp->pw_id)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
- os_memcpy(sae->tmp->pw_id, pos + 3, pos[1] - 1);
- sae->tmp->pw_id[pos[1] - 1] = '\0';
+ os_memcpy(sae->tmp->pw_id, (*pos) + 3, (*pos)[1] - 1);
+ sae->tmp->pw_id[(*pos)[1] - 1] = '\0';
wpa_hexdump_ascii(MSG_DEBUG, "SAE: Received Password Identifier",
- sae->tmp->pw_id, pos[1] - 1);
+ sae->tmp->pw_id, (*pos)[1] - 1);
+ *pos = *pos + 2 + (*pos)[1];
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+static int sae_parse_rejected_groups(struct sae_data *sae,
+ const u8 *pos, const u8 *end)
+{
+ wpa_hexdump(MSG_DEBUG, "SAE: Possible elements at the end of the frame",
+ pos, end - pos);
+ if (!sae_is_rejected_groups_elem(pos, end))
+ return WLAN_STATUS_SUCCESS;
+ wpabuf_free(sae->tmp->peer_rejected_groups);
+ sae->tmp->peer_rejected_groups = wpabuf_alloc(pos[1] - 1);
+ if (!sae->tmp->peer_rejected_groups)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
+ wpabuf_put_data(sae->tmp->peer_rejected_groups, pos + 3, pos[1] - 1);
+ wpa_hexdump_buf(MSG_DEBUG, "SAE: Received Rejected Groups list",
+ sae->tmp->peer_rejected_groups);
return WLAN_STATUS_SUCCESS;
}
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups)
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e)
{
const u8 *pos = data, *end = data + len;
u16 res;
@@ -1113,7 +2037,7 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
pos += 2;
/* Optional Anti-Clogging Token */
- sae_parse_commit_token(sae, &pos, end, token, token_len);
+ sae_parse_commit_token(sae, &pos, end, token, token_len, h2e);
/* commit-scalar */
res = sae_parse_commit_scalar(sae, &pos, end);
@@ -1126,10 +2050,17 @@ u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
return res;
/* Optional Password Identifier element */
- res = sae_parse_password_identifier(sae, pos, end);
+ res = sae_parse_password_identifier(sae, &pos, end);
if (res != WLAN_STATUS_SUCCESS)
return res;
+ /* Conditional Rejected Groups element */
+ if (h2e) {
+ res = sae_parse_rejected_groups(sae, pos, end);
+ if (res != WLAN_STATUS_SUCCESS)
+ return res;
+ }
+
/*
* Check whether peer-commit-scalar and PEER-COMMIT-ELEMENT are same as
* the values we sent which would be evidence of a reflection attack.
@@ -1191,8 +2122,8 @@ static int sae_cn_confirm(struct sae_data *sae, const u8 *sc,
len[3] = sae->tmp->prime_len;
addr[4] = element2;
len[4] = element2_len;
- return hmac_sha256_vector(sae->tmp->kck, sizeof(sae->tmp->kck),
- 5, addr, len, confirm);
+ return hkdf_extract(sae->tmp->kck_len, sae->tmp->kck, sae->tmp->kck_len,
+ 5, addr, len, confirm);
}
@@ -1244,10 +2175,13 @@ static int sae_cn_confirm_ffc(struct sae_data *sae, const u8 *sc,
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
{
const u8 *sc;
+ size_t hash_len;
if (sae->tmp == NULL)
return;
+ hash_len = sae->tmp->kck_len;
+
/* Send-Confirm */
sc = wpabuf_put(buf, 0);
wpabuf_put_le16(buf, sae->send_confirm);
@@ -1259,29 +2193,33 @@ void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf)
sae->tmp->own_commit_element_ecc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ecc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
else
sae_cn_confirm_ffc(sae, sc, sae->tmp->own_commit_scalar,
sae->tmp->own_commit_element_ffc,
sae->peer_commit_scalar,
sae->tmp->peer_commit_element_ffc,
- wpabuf_put(buf, SHA256_MAC_LEN));
+ wpabuf_put(buf, hash_len));
}
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
{
- u8 verifier[SHA256_MAC_LEN];
+ u8 verifier[SAE_MAX_HASH_LEN];
+ size_t hash_len;
+
+ if (!sae->tmp)
+ return -1;
- if (len < 2 + SHA256_MAC_LEN) {
+ hash_len = sae->tmp->kck_len;
+ if (len < 2 + hash_len) {
wpa_printf(MSG_DEBUG, "SAE: Too short confirm message");
return -1;
}
wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", WPA_GET_LE16(data));
- if (!sae->tmp || !sae->peer_commit_scalar ||
- !sae->tmp->own_commit_scalar) {
+ if (!sae->peer_commit_scalar || !sae->tmp->own_commit_scalar) {
wpa_printf(MSG_DEBUG, "SAE: Temporary data not yet available");
return -1;
}
@@ -1306,12 +2244,12 @@ int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len)
return -1;
}
- if (os_memcmp_const(verifier, data + 2, SHA256_MAC_LEN) != 0) {
+ if (os_memcmp_const(verifier, data + 2, hash_len) != 0) {
wpa_printf(MSG_DEBUG, "SAE: Confirm mismatch");
wpa_hexdump(MSG_DEBUG, "SAE: Received confirm",
- data + 2, SHA256_MAC_LEN);
+ data + 2, hash_len);
wpa_hexdump(MSG_DEBUG, "SAE: Calculated verifier",
- verifier, SHA256_MAC_LEN);
+ verifier, hash_len);
return -1;
}
diff --git a/src/common/sae.h b/src/common/sae.h
index 10f9302..b3787e4 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -12,17 +12,18 @@
#define SAE_KCK_LEN 32
#define SAE_PMK_LEN 32
#define SAE_PMKID_LEN 16
-#define SAE_KEYSEED_KEY_LEN 32
#define SAE_MAX_PRIME_LEN 512
#define SAE_MAX_ECC_PRIME_LEN 66
-#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN)
-#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_PRIME_LEN)
+#define SAE_MAX_HASH_LEN 64
+#define SAE_COMMIT_MAX_LEN (2 + 3 * SAE_MAX_PRIME_LEN + 255)
+#define SAE_CONFIRM_MAX_LEN (2 + SAE_MAX_HASH_LEN)
/* Special value returned by sae_parse_commit() */
#define SAE_SILENTLY_DISCARD 65535
struct sae_temporary_data {
- u8 kck[SAE_KCK_LEN];
+ u8 kck[SAE_MAX_HASH_LEN];
+ size_t kck_len;
struct crypto_bignum *own_commit_scalar;
struct crypto_bignum *own_commit_element_ffc;
struct crypto_ec_point *own_commit_element_ecc;
@@ -43,6 +44,20 @@ struct sae_temporary_data {
char *pw_id;
int vlan_id;
u8 bssid[ETH_ALEN];
+ struct wpabuf *own_rejected_groups;
+ struct wpabuf *peer_rejected_groups;
+ unsigned int h2e:1;
+ unsigned int own_addr_higher:1;
+};
+
+struct sae_pt {
+ struct sae_pt *next;
+ int group;
+ struct crypto_ec *ec;
+ struct crypto_ec_point *ecc_pt;
+
+ const struct dh_group *dh;
+ struct crypto_bignum *ffc_pt;
};
enum sae_state {
@@ -68,14 +83,28 @@ void sae_clear_data(struct sae_data *sae);
int sae_prepare_commit(const u8 *addr1, const u8 *addr2,
const u8 *password, size_t password_len,
const char *identifier, struct sae_data *sae);
+int sae_prepare_commit_pt(struct sae_data *sae, const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2,
+ int *rejected_groups);
int sae_process_commit(struct sae_data *sae);
void sae_write_commit(struct sae_data *sae, struct wpabuf *buf,
const struct wpabuf *token, const char *identifier);
u16 sae_parse_commit(struct sae_data *sae, const u8 *data, size_t len,
- const u8 **token, size_t *token_len, int *allowed_groups);
+ const u8 **token, size_t *token_len, int *allowed_groups,
+ int h2e);
void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
const char * sae_state_txt(enum sae_state state);
+struct sae_pt * sae_derive_pt(int *groups, const u8 *ssid, size_t ssid_len,
+ const u8 *password, size_t password_len,
+ const char *identifier);
+struct crypto_ec_point *
+sae_derive_pwe_from_pt_ecc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+struct crypto_bignum *
+sae_derive_pwe_from_pt_ffc(const struct sae_pt *pt,
+ const u8 *addr1, const u8 *addr2);
+void sae_deinit_pt(struct sae_pt *pt);
#endif /* SAE_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 142dace..ea9f7a2 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -686,7 +686,7 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
len[2] = ETH_ALEN;
addr[3] = bssid;
len[3] = ETH_ALEN;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_sta;
len[4] = g_sta_len;
addr[5] = g_ap;
@@ -717,7 +717,7 @@ int fils_key_auth_sk(const u8 *ick, size_t ick_len, const u8 *snonce,
addr[1] = snonce;
addr[2] = bssid;
addr[3] = sta_addr;
- if (g_sta && g_ap_len && g_ap && g_ap_len) {
+ if (g_sta && g_sta_len && g_ap && g_ap_len) {
addr[4] = g_ap;
len[4] = g_ap_len;
addr[5] = g_sta;
@@ -750,10 +750,12 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic)
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic)
{
- const u8 *addr[9];
- size_t len[9];
+ const u8 *addr[10];
+ size_t len[10];
size_t i, num_elem = 0;
u8 zero_mic[24];
size_t mic_len, fte_fixed_len;
@@ -820,6 +822,12 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
num_elem++;
}
+ if (rsnxe) {
+ addr[num_elem] = rsnxe;
+ len[num_elem] = rsnxe_len;
+ num_elem++;
+ }
+
for (i = 0; i < num_elem; i++)
wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
#ifdef CONFIG_SHA384
@@ -961,6 +969,13 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
update_use_sha384 = 0;
}
break;
+ case WLAN_EID_RSNX:
+ wpa_hexdump(MSG_DEBUG, "FT: RSNXE", pos, len);
+ if (len < 1)
+ break;
+ parse->rsnxe = pos;
+ parse->rsnxe_len = len;
+ break;
case WLAN_EID_MOBILITY_DOMAIN:
wpa_hexdump(MSG_DEBUG, "FT: MDE", pos, len);
if (len < sizeof(struct rsn_mdie))
@@ -1043,6 +1058,8 @@ int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
prot_ie_count--;
if (parse->ftie)
prot_ie_count--;
+ if (parse->rsnxe)
+ prot_ie_count--;
if (prot_ie_count < 0) {
wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
"the protected IE count");
@@ -2586,3 +2603,266 @@ int fils_domain_name_hash(const char *domain, u8 *hash)
return 0;
}
#endif /* CONFIG_FILS */
+
+
+/**
+ * wpa_parse_vendor_specific - Parse Vendor Specific IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ unsigned int oui;
+
+ if (pos[1] < 4) {
+ wpa_printf(MSG_MSGDUMP,
+ "Too short vendor specific IE ignored (len=%u)",
+ pos[1]);
+ return 1;
+ }
+
+ oui = WPA_GET_BE24(&pos[2]);
+ if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
+ if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
+ ie->wmm, ie->wmm_len);
+ } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
+ ie->wmm = &pos[2];
+ ie->wmm_len = pos[1];
+ wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
+ ie->wmm, ie->wmm_len);
+ }
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+ pos[2 + WPA_SELECTOR_LEN] == 1 &&
+ pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+ ie->wpa_ie = pos;
+ ie->wpa_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+ ie->wpa_ie, ie->wpa_ie_len);
+ return 0;
+ }
+
+ if (pos[1] >= 4 && WPA_GET_BE32(pos + 2) == OSEN_IE_VENDOR_TYPE) {
+ ie->osen = pos;
+ ie->osen_len = pos[1] + 2;
+ return 0;
+ }
+
+ if (1 + RSN_SELECTOR_LEN < end - pos &&
+ pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+ ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
+ ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
+ ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
+ RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
+ ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: IP Address Allocation in EAPOL-Key",
+ ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
+ ie->oci = pos + 2 + RSN_SELECTOR_LEN;
+ ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
+ wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
+ pos, pos[1] + 2);
+ return 0;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
+
+ os_memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
+ if (2 + pos[1] > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "WPA: EAPOL-Key Key Data underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data", buf, len);
+ ret = -1;
+ break;
+ }
+ if (*pos == WLAN_EID_RSN) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+ ie->rsn_ie, ie->rsn_ie_len);
+ } else if (*pos == WLAN_EID_RSNX) {
+ ie->rsnxe = pos;
+ ie->rsnxe_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSNXE in EAPOL-Key",
+ ie->rsnxe, ie->rsnxe_len);
+ } else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+ ie->mdie = pos;
+ ie->mdie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+ ie->mdie, ie->mdie_len);
+ } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+ ie->ftie = pos;
+ ie->ftie_len = pos[1] + 2;
+ wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+ ie->ftie, ie->ftie_len);
+ } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+ if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+ ie->reassoc_deadline = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+ "in EAPOL-Key",
+ ie->reassoc_deadline, pos[1] + 2);
+ } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+ ie->key_lifetime = pos;
+ wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+ "in EAPOL-Key",
+ ie->key_lifetime, pos[1] + 2);
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+ "EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ } else if (*pos == WLAN_EID_LINK_ID) {
+ if (pos[1] >= 18) {
+ ie->lnkid = pos;
+ ie->lnkid_len = pos[1] + 2;
+ }
+ } else if (*pos == WLAN_EID_EXT_CAPAB) {
+ ie->ext_capab = pos;
+ ie->ext_capab_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_SUPP_RATES) {
+ ie->supp_rates = pos;
+ ie->supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+ ie->ext_supp_rates = pos;
+ ie->ext_supp_rates_len = pos[1] + 2;
+ } else if (*pos == WLAN_EID_HT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
+ ie->ht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_VHT_AID) {
+ if (pos[1] >= 2)
+ ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
+ } else if (*pos == WLAN_EID_VHT_CAP &&
+ pos[1] >= sizeof(struct ieee80211_vht_capabilities))
+ {
+ ie->vht_capabilities = pos + 2;
+ } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
+ ie->qosinfo = pos[2];
+ } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
+ ie->supp_channels = pos + 2;
+ ie->supp_channels_len = pos[1];
+ } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
+ /*
+ * The value of the Length field of the Supported
+ * Operating Classes element is between 2 and 253.
+ * Silently skip invalid elements to avoid interop
+ * issues when trying to use the value.
+ */
+ if (pos[1] >= 2 && pos[1] <= 253) {
+ ie->supp_oper_classes = pos + 2;
+ ie->supp_oper_classes_len = pos[1];
+ }
+ } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+ ret = wpa_parse_generic(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+
+ ret = wpa_parse_vendor_specific(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "WPA: Unrecognized EAPOL-Key Key Data IE",
+ pos, 2 + pos[1]);
+ }
+ }
+
+ return ret;
+}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 35bec04..beb1ecd 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -364,7 +364,9 @@ int wpa_ft_mic(const u8 *kck, size_t kck_len, const u8 *sta_addr,
const u8 *mdie, size_t mdie_len,
const u8 *ftie, size_t ftie_len,
const u8 *rsnie, size_t rsnie_len,
- const u8 *ric, size_t ric_len, u8 *mic);
+ const u8 *ric, size_t ric_len,
+ const u8 *rsnxe, size_t rsnxe_len,
+ u8 *mic);
int wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
const u8 *ssid, size_t ssid_len,
const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
@@ -461,11 +463,67 @@ struct wpa_ft_ies {
size_t ric_len;
int key_mgmt;
int pairwise_cipher;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
};
int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse,
int use_sha384);
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *gtk;
+ size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+ const u8 *igtk;
+ size_t igtk_len;
+ const u8 *mdie;
+ size_t mdie_len;
+ const u8 *ftie;
+ size_t ftie_len;
+ const u8 *ip_addr_req;
+ const u8 *ip_addr_alloc;
+ const u8 *oci;
+ size_t oci_len;
+ const u8 *osen;
+ size_t osen_len;
+ const u8 *rsnxe;
+ size_t rsnxe_len;
+ const u8 *reassoc_deadline;
+ const u8 *key_lifetime;
+ const u8 *lnkid;
+ size_t lnkid_len;
+ const u8 *ext_capab;
+ size_t ext_capab_len;
+ const u8 *supp_rates;
+ size_t supp_rates_len;
+ const u8 *ext_supp_rates;
+ size_t ext_supp_rates_len;
+ const u8 *ht_capabilities;
+ const u8 *vht_capabilities;
+ const u8 *supp_channels;
+ size_t supp_channels_len;
+ const u8 *supp_oper_classes;
+ size_t supp_oper_classes_len;
+ u8 qosinfo;
+ u16 aid;
+ const u8 *wmm;
+ size_t wmm_len;
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie);
+static inline int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie)
+{
+ return wpa_parse_kde_ies(buf, len, ie);
+}
+
+
int wpa_cipher_key_len(int cipher);
int wpa_cipher_rsc_len(int cipher);
enum wpa_alg wpa_cipher_to_alg(int cipher);
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 15f8ad0..440da03 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -519,6 +519,13 @@ struct crypto_bignum * crypto_bignum_init(void);
struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
/**
+ * crypto_bignum_init_set - Allocate memory for bignum and set the value (uint)
+ * @val: Value to set
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val);
+
+/**
* crypto_bignum_deinit - Free bignum
* @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
* @clear: Whether to clear the value from memory
@@ -613,6 +620,19 @@ int crypto_bignum_div(const struct crypto_bignum *a,
struct crypto_bignum *c);
/**
+ * crypto_bignum_addmod - d = a + b (mod c)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum
+ * @d: Bignum; used to store the result of (a + b) % c
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d);
+
+/**
* crypto_bignum_mulmod - d = a * b (mod c)
* @a: Bignum
* @b: Bignum
@@ -626,6 +646,17 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
struct crypto_bignum *d);
/**
+ * crypto_bignum_sqrmod - c = a^2 (mod b)
+ * @a: Bignum
+ * @b: Bignum
+ * @c: Bignum; used to store the result of a^2 % b
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c);
+
+/**
* crypto_bignum_rshift - r = a >> n
* @a: Bignum
* @n: Number of bits
@@ -731,6 +762,9 @@ const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
*/
const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e);
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e);
+
/**
* struct crypto_ec_point - Elliptic curve point
*
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index bab33a5..783b293 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1283,6 +1283,24 @@ struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ BIGNUM *bn;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ bn = BN_new();
+ if (!bn)
+ return NULL;
+ if (BN_set_word(bn, val) != 1) {
+ BN_free(bn);
+ return NULL;
+ }
+ return (struct crypto_bignum *) bn;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (clear)
@@ -1449,6 +1467,28 @@ int crypto_bignum_div(const struct crypto_bignum *a,
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_add((BIGNUM *) d, (const BIGNUM *) a, (const BIGNUM *) b,
+ (const BIGNUM *) c, bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *c,
@@ -1472,6 +1512,27 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ int res;
+ BN_CTX *bnctx;
+
+ if (TEST_FAIL())
+ return -1;
+
+ bnctx = BN_CTX_new();
+ if (!bnctx)
+ return -1;
+ res = BN_mod_sqr((BIGNUM *) c, (const BIGNUM *) a, (const BIGNUM *) b,
+ bnctx);
+ BN_CTX_free(bnctx);
+
+ return res ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1682,6 +1743,18 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
if (clear)
diff --git a/src/crypto/crypto_wolfssl.c b/src/crypto/crypto_wolfssl.c
index 4cedab4..85ce565 100644
--- a/src/crypto/crypto_wolfssl.c
+++ b/src/crypto/crypto_wolfssl.c
@@ -1042,6 +1042,26 @@ struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len)
}
+struct crypto_bignum * crypto_bignum_init_uint(unsigned int val)
+{
+ mp_int *a;
+
+ if (TEST_FAIL())
+ return NULL;
+
+ a = (mp_int *) crypto_bignum_init();
+ if (!a)
+ return NULL;
+
+ if (mp_set_int(a, val) != MP_OKAY) {
+ os_free(a);
+ a = NULL;
+ }
+
+ return (struct crypto_bignum *) a;
+}
+
+
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
{
if (!n)
@@ -1151,7 +1171,7 @@ int crypto_bignum_sub(const struct crypto_bignum *a,
if (TEST_FAIL())
return -1;
- return mp_add((mp_int *) a, (mp_int *) b,
+ return mp_sub((mp_int *) a, (mp_int *) b,
(mp_int *) r) == MP_OKAY ? 0 : -1;
}
@@ -1168,6 +1188,19 @@ int crypto_bignum_div(const struct crypto_bignum *a,
}
+int crypto_bignum_addmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ const struct crypto_bignum *c,
+ struct crypto_bignum *d)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_addmod((mp_int *) a, (mp_int *) b, (mp_int *) c,
+ (mp_int *) d) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_mulmod(const struct crypto_bignum *a,
const struct crypto_bignum *b,
const struct crypto_bignum *m,
@@ -1181,6 +1214,18 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
}
+int crypto_bignum_sqrmod(const struct crypto_bignum *a,
+ const struct crypto_bignum *b,
+ struct crypto_bignum *c)
+{
+ if (TEST_FAIL())
+ return -1;
+
+ return mp_sqrmod((mp_int *) a, (mp_int *) b,
+ (mp_int *) c) == MP_OKAY ? 0 : -1;
+}
+
+
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
struct crypto_bignum *r)
{
@@ -1386,6 +1431,18 @@ const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e)
}
+const struct crypto_bignum * crypto_ec_get_a(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->a;
+}
+
+
+const struct crypto_bignum * crypto_ec_get_b(struct crypto_ec *e)
+{
+ return (const struct crypto_bignum *) &e->b;
+}
+
+
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
{
ecc_point *point = (ecc_point *) p;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index e9d0e47..ad68a07 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -213,6 +213,24 @@ enum ieee80211_op_mode {
};
/**
+ * struct ieee80211_edmg_config - EDMG configuration
+ *
+ * This structure describes most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration
+ *
+ * @channels: Bitmap that indicates the 2.16 GHz channel(s)
+ * that are allowed to be used for transmissions.
+ * Bit 0 indicates channel 1, bit 1 indicates channel 2, etc.
+ * Set to 0 to indicate EDMG not supported.
+ * @bw_config: Channel BW Configuration subfield encodes
+ * the allowed channel bandwidth configurations
+ */
+struct ieee80211_edmg_config {
+ u8 channels;
+ enum edmg_bw_config bw_config;
+};
+
+/**
* struct hostapd_hw_modes - Supported hardware mode information
*/
struct hostapd_hw_modes {
@@ -272,6 +290,12 @@ struct hostapd_hw_modes {
* he_capab - HE (IEEE 802.11ax) capabilities
*/
struct he_capabilities he_capab[IEEE80211_MODE_NUM];
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
@@ -493,7 +517,7 @@ struct wpa_driver_scan_params {
* mac_addr - MAC address used with randomization. The address cannot be
* a multicast one, i.e., bit 0 of byte 0 should not be set.
*/
- const u8 *mac_addr;
+ u8 *mac_addr;
/**
* mac_addr_mask - MAC address mask used with randomization.
@@ -744,6 +768,12 @@ struct hostapd_freq_params {
* bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
*/
int bandwidth;
+
+ /**
+ * This structure describes the most essential parameters needed
+ * for IEEE 802.11ay EDMG configuration.
+ */
+ struct ieee80211_edmg_config edmg;
};
/**
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index b8aa0a0..4c8dcad 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -4454,6 +4454,15 @@ static int nl80211_put_freq_params(struct nl_msg *msg,
wpa_printf(MSG_DEBUG, " * channel_type=%d", ct);
if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
return -ENOBUFS;
+ } else if (freq->edmg.channels && freq->edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ freq->edmg.channels, freq->edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ freq->edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ freq->edmg.bw_config))
+ return -1;
} else {
wpa_printf(MSG_DEBUG, " * channel_type=%d",
NL80211_CHAN_NO_HT);
@@ -5533,6 +5542,18 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
return -1;
}
+ if (params->freq.edmg.channels && params->freq.edmg.bw_config) {
+ wpa_printf(MSG_DEBUG,
+ " * EDMG configuration: channels=0x%x bw_config=%d",
+ params->freq.edmg.channels,
+ params->freq.edmg.bw_config);
+ if (nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_CHANNELS,
+ params->freq.edmg.channels) ||
+ nla_put_u8(msg, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG,
+ params->freq.edmg.bw_config))
+ return -1;
+ }
+
if (params->bg_scan_period >= 0) {
wpa_printf(MSG_DEBUG, " * bg scan period=%d",
params->bg_scan_period);
@@ -5741,7 +5762,8 @@ static int nl80211_connect_common(struct wpa_driver_nl80211_data *drv,
nl80211_put_fils_connect_params(drv, params, msg) != 0)
return -1;
- if ((params->auth_alg & WPA_AUTH_ALG_SAE) &&
+ if ((params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) &&
(!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) &&
nla_put_flag(msg, NL80211_ATTR_EXTERNAL_AUTH_SUPPORT))
return -1;
@@ -5896,7 +5918,8 @@ static int wpa_driver_nl80211_associate(
if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
return -1;
- if (params->auth_alg & WPA_AUTH_ALG_SAE) {
+ if (params->key_mgmt_suite == WPA_KEY_MGMT_SAE ||
+ params->key_mgmt_suite == WPA_KEY_MGMT_FT_SAE) {
nl_connect = bss->nl_connect;
bss->use_nl_connect = 1;
} else {
@@ -9535,6 +9558,40 @@ fail:
return -1;
}
+
+static int nl80211_add_sta_node(void *priv, const u8 *addr, u16 auth_alg)
+{
+ struct i802_bss *bss = priv;
+ struct wpa_driver_nl80211_data *drv = bss->drv;
+ struct nl_msg *msg;
+ struct nlattr *params;
+
+ if (!drv->add_sta_node_vendor_cmd_avail)
+ return -EOPNOTSUPP;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Add STA node");
+
+ if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+ nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+ QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE) ||
+ !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+ (addr &&
+ nla_put(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_MAC_ADDR, ETH_ALEN,
+ addr)) ||
+ nla_put_u16(msg, QCA_WLAN_VENDOR_ATTR_ADD_STA_NODE_AUTH_ALGO,
+ auth_alg)) {
+ nlmsg_free(msg);
+ wpa_printf(MSG_ERROR,
+ "%s: err in adding vendor_cmd and vendor_data",
+ __func__);
+ return -1;
+ }
+ nla_nest_end(msg, params);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
#endif /* CONFIG_DRIVER_NL80211_QCA */
@@ -11199,6 +11256,7 @@ const struct wpa_driver_ops wpa_driver_nl80211_ops = {
.ignore_assoc_disallow = nl80211_ignore_assoc_disallow,
#endif /* CONFIG_MBO */
.set_bssid_blacklist = nl80211_set_bssid_blacklist,
+ .add_sta_node = nl80211_add_sta_node,
#endif /* CONFIG_DRIVER_NL80211_QCA */
.configure_data_frame_filters = nl80211_configure_data_frame_filters,
.get_ext_capab = nl80211_get_ext_capab,
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 7498269..716504c 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -172,6 +172,7 @@ struct wpa_driver_nl80211_data {
unsigned int fetch_bss_trans_status:1;
unsigned int roam_vendor_cmd_avail:1;
unsigned int get_supported_akm_suites_avail:1;
+ unsigned int add_sta_node_vendor_cmd_avail:1;
u64 vendor_scan_cookie;
u64 remain_on_chan_cookie;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 8318b10..d8630bb 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -787,6 +787,9 @@ static int wiphy_info_handler(struct nl_msg *msg, void *arg)
case QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_AKMS:
drv->get_supported_akm_suites_avail = 1;
break;
+ case QCA_NL80211_VENDOR_SUBCMD_ADD_STA_NODE:
+ drv->add_sta_node_vendor_cmd_avail = 1;
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
}
}
@@ -1202,10 +1205,13 @@ int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B |
- WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192 |
WPA_DRIVER_CAPA_KEY_MGMT_OWE |
WPA_DRIVER_CAPA_KEY_MGMT_DPP;
+ if (drv->capa.enc & (WPA_DRIVER_CAPA_ENC_CCMP_256 |
+ WPA_DRIVER_CAPA_ENC_GCMP_256))
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_SUITE_B_192;
+
if (drv->capa.flags & WPA_DRIVER_FLAGS_SME)
drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA256 |
WPA_DRIVER_CAPA_KEY_MGMT_FILS_SHA384 |
@@ -1337,6 +1343,23 @@ static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
}
+static int phy_info_edmg_capa(struct hostapd_hw_modes *mode,
+ struct nlattr *bw_config,
+ struct nlattr *channels)
+{
+ if (!bw_config || !channels)
+ return NL_OK;
+
+ mode->edmg.bw_config = nla_get_u8(bw_config);
+ mode->edmg.channels = nla_get_u8(channels);
+
+ if (!mode->edmg.channels || !mode->edmg.bw_config)
+ return NL_STOP;
+
+ return NL_OK;
+}
+
+
static void phy_info_freq(struct hostapd_hw_modes *mode,
struct hostapd_channel_data *chan,
struct nlattr *tb_freq[])
@@ -1694,7 +1717,12 @@ static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
- ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+ ret = phy_info_edmg_capa(mode,
+ tb_band[NL80211_BAND_ATTR_EDMG_BW_CONFIG],
+ tb_band[NL80211_BAND_ATTR_EDMG_CHANNELS]);
+ if (ret == NL_OK)
+ ret = phy_info_freqs(phy_info, mode,
+ tb_band[NL80211_BAND_ATTR_FREQS]);
if (ret == NL_OK)
ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
if (ret != NL_OK) {
diff --git a/src/fst/fst.c b/src/fst/fst.c
index 32cd941..fbe1175 100644
--- a/src/fst/fst.c
+++ b/src/fst/fst.c
@@ -214,6 +214,15 @@ Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
}
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr)
+{
+ fst_printf_iface(iface, MSG_DEBUG, "new MAC address " MACSTR,
+ MAC2STR(addr));
+ os_memcpy(iface->own_addr, addr, sizeof(iface->own_addr));
+ fst_group_update_ie(fst_iface_get_group(iface));
+}
+
+
enum mb_band_id fst_hw_mode_to_band(enum hostapd_hw_mode mode)
{
switch (mode) {
diff --git a/src/fst/fst.h b/src/fst/fst.h
index 2967491..7ba60d5 100644
--- a/src/fst/fst.h
+++ b/src/fst/fst.h
@@ -279,6 +279,13 @@ void fst_notify_peer_disconnected(struct fst_iface *iface, const u8 *addr);
Boolean fst_are_ifaces_aggregated(struct fst_iface *iface1,
struct fst_iface *iface2);
+/**
+ * fst_update_mac_addr - Notify FST about MAC address change
+ * @iface: FST interface object
+ * @addr: New MAC address
+ */
+void fst_update_mac_addr(struct fst_iface *iface, const u8 *addr);
+
#else /* CONFIG_FST */
static inline int fst_global_init(void)
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index a08ba02..7c1a8a5 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -3451,12 +3451,18 @@ static void p2p_prov_disc_resp_cb(struct p2p_data *p2p, int success)
p2p->pending_action_state = P2P_NO_PENDING_ACTION;
- if (!success)
+ if (!success) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
return;
+ }
if (!p2p->cfg->prov_disc_resp_cb ||
- p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1)
+ p2p->cfg->prov_disc_resp_cb(p2p->cfg->cb_ctx) < 1) {
+ if (p2p->state == P2P_SEARCH)
+ p2p_continue_find(p2p);
return;
+ }
p2p_dbg(p2p,
"Post-Provision Discovery operations started - do not try to continue other P2P operations");
@@ -4915,6 +4921,7 @@ int p2p_send_action(struct p2p_data *p2p, unsigned int freq, const u8 *dst,
res = p2p->cfg->send_action(p2p->cfg->cb_ctx, freq, dst, src, bssid,
buf, len, wait_time, &scheduled);
if (res == 0 && scheduled && p2p->in_listen && freq > 0 &&
+ p2p->drv_in_listen > 0 &&
(unsigned int) p2p->drv_in_listen != freq) {
p2p_dbg(p2p,
"Stop listen on %d MHz to allow a frame to be sent immediately on %d MHz",
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index d720f7b..cd4b050 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -277,7 +277,7 @@ pmksa_cache_add_entry(struct rsn_pmksa_cache *pmksa,
* pmksa_cache_flush - Flush PMKSA cache entries for a specific network
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @network_ctx: Network configuration context or %NULL to flush all entries
- * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk: PMK to match for or %NULL to match all PMKs
* @pmk_len: PMK length
*/
void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 6372634..504feaf 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -655,51 +655,51 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+ kde_buf = os_malloc(kde_len +
+ 2 + RSN_SELECTOR_LEN + 3 +
+ sm->assoc_rsnxe_len +
+ 2 + RSN_SELECTOR_LEN + 1);
+ if (!kde_buf)
+ goto failed;
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
+ pos = kde + kde_len;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
- if (!kde_buf) {
- wpa_printf(MSG_WARNING,
- "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
- goto failed;
- }
-
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
kde_len = pos - kde;
}
#endif /* CONFIG_OCV */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
+ os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ kde_len += sm->assoc_rsnxe_len;
+ }
+
#ifdef CONFIG_P2P
if (sm->p2p) {
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
- if (kde_buf) {
- u8 *pos;
- wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
- "into EAPOL-Key 2/4");
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + 1;
- RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
- pos += RSN_SELECTOR_LEN;
- *pos++ = 0x01;
- kde_len = pos - kde;
- }
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
}
#endif /* CONFIG_P2P */
@@ -1365,6 +1365,16 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
return -1;
}
+ if ((sm->ap_rsnxe && !ie->rsnxe) ||
+ (!sm->ap_rsnxe && ie->rsnxe) ||
+ (sm->ap_rsnxe && ie->rsnxe &&
+ (sm->ap_rsnxe_len != ie->rsnxe_len ||
+ os_memcmp(sm->ap_rsnxe, ie->rsnxe, sm->ap_rsnxe_len) != 0))) {
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+ "WPA: RSNXE mismatch between Beacon/ProbeResp and EAPOL-Key msg 3/4");
+ return -1;
+ }
+
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt) &&
wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
@@ -2662,8 +2672,10 @@ void wpa_sm_deinit(struct wpa_sm *sm)
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
os_free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_rsnxe);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
+ os_free(sm->ap_rsnxe);
wpa_sm_drop_sa(sm);
os_free(sm->ctx);
#ifdef CONFIG_IEEE80211R
@@ -3038,6 +3050,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
default:
break;
}
@@ -3216,6 +3231,83 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
/**
+ * wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @rsnxe: Pointer to buffer for RSNXE
+ * @rsnxe_len: Pointer to the length of the rsne buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len)
+{
+ int res;
+
+ if (!sm)
+ return -1;
+
+ res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
+ if (res < 0)
+ return -1;
+ *rsnxe_len = res;
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
+
+ if (sm->assoc_rsnxe) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Leave previously set RSNXE default",
+ sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ } else if (*rsnxe_len > 0) {
+ /*
+ * Make a copy of the RSNXE so that 4-Way Handshake gets the
+ * correct version of the IE even if it gets changed.
+ */
+ sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = *rsnxe_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in (Re)Association Request
+ * frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_rsnxe_default().
+ */
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->assoc_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: clearing own RSNXE");
+ sm->assoc_rsnxe = NULL;
+ sm->assoc_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
+ sm->assoc_rsnxe = os_memdup(ie, len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
@@ -3284,6 +3376,39 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
/**
+ * wpa_sm_set_ap_rsnxe - Set AP RSNXE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->ap_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: clearing AP RSNXE");
+ sm->ap_rsnxe = NULL;
+ sm->ap_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: set AP RSNXE", ie, len);
+ sm->ap_rsnxe = os_memdup(ie, len);
+ if (!sm->ap_rsnxe)
+ return -1;
+
+ sm->ap_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @data: Pointer to data area for parsing results
@@ -3996,8 +4121,10 @@ static int fils_ft_build_assoc_req_rsne(struct wpa_sm *sm, struct wpabuf *buf)
/* RSN Capabilities */
capab = 0;
- if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ if (sm->mfp)
capab |= WPA_CAPABILITY_MFPC;
+ if (sm->mfp == 2)
+ capab |= WPA_CAPABILITY_MFPR;
if (sm->ocv)
capab |= WPA_CAPABILITY_OCVC;
wpabuf_put_le16(buf, capab);
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index ae9cd64..f1fbb1b 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -98,7 +98,8 @@ enum wpa_sm_conf_params {
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
WPA_PARAM_MFP,
- WPA_PARAM_OCV
+ WPA_PARAM_OCV,
+ WPA_PARAM_SAE_PWE,
};
struct rsn_supp_config {
@@ -134,8 +135,12 @@ void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len);
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len);
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
@@ -260,6 +265,12 @@ static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
return -1;
}
+static inline int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
return 0;
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index a6da347..2b8b41f 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -18,6 +18,7 @@
#include "drivers/driver.h"
#include "wpa.h"
#include "wpa_i.h"
+#include "wpa_ie.h"
#include "pmksa_cache.h"
#ifdef CONFIG_IEEE80211R
@@ -171,6 +172,9 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
struct rsn_ie_hdr *rsnie;
u16 capab;
int mdie_len;
+ u8 rsnxe[10];
+ size_t rsnxe_len;
+ int res;
sm->ft_completed = 0;
sm->ft_reassoc_completed = 0;
@@ -359,6 +363,13 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
pos += ric_ies_len;
}
+ res = wpa_gen_rsnxe(sm, rsnxe, sizeof(rsnxe));
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+ rsnxe_len = res;
+
if (kck) {
/*
* IEEE Std 802.11r-2008, 11A.8.4
@@ -370,14 +381,18 @@ static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
* MDIE
* FTIE (with MIC field set to 0)
* RIC-Request (if present)
+ * RSNXE (if present)
*/
/* Information element count */
*elem_count = 3 + ieee802_11_ie_count(ric_ies, ric_ies_len);
+ if (rsnxe_len)
+ *elem_count += 1;
if (wpa_ft_mic(kck, kck_len, sm->own_addr, target_ap, 5,
((u8 *) mdie) - 2, 2 + sizeof(*mdie),
ftie_pos, 2 + *ftie_len,
(u8 *) rsnie, 2 + rsnie->len, ric_ies,
- ric_ies_len, fte_mic) < 0) {
+ ric_ies_len, rsnxe_len ? rsnxe : NULL, rsnxe_len,
+ fte_mic) < 0) {
wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
os_free(buf);
return NULL;
@@ -961,6 +976,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
count = 3;
if (parse.ric)
count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+ if (parse.rsnxe)
+ count++;
if (fte_elem_count != count) {
wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
"Control: received %u expected %u",
@@ -981,6 +998,8 @@ int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
parse.ftie - 2, parse.ftie_len + 2,
parse.rsn - 2, parse.rsn_len + 2,
parse.ric, parse.ric_len,
+ parse.rsnxe ? parse.rsnxe - 2 : NULL,
+ parse.rsnxe ? parse.rsnxe_len + 2 : 0,
mic) < 0) {
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
return -1;
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 129dfb1..2a43342 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -85,11 +85,14 @@ struct wpa_sm {
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
+ int sae_pwe; /* SAE PWE generation options */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
- u8 *ap_wpa_ie, *ap_rsn_ie;
- size_t ap_wpa_ie_len, ap_rsn_ie_len;
+ u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
+ size_t assoc_rsnxe_len;
+ u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
+ size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
#ifdef CONFIG_TDLS
struct wpa_tdls_peer *tdls;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 809f208..03c0d7e 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -342,259 +342,23 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
}
-/**
- * wpa_parse_vendor_specific - Parse Vendor Specific IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_vendor_specific(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
{
- unsigned int oui;
-
- if (pos[1] < 4) {
- wpa_printf(MSG_MSGDUMP, "Too short vendor specific IE ignored (len=%u)",
- pos[1]);
- return 1;
- }
-
- oui = WPA_GET_BE24(&pos[2]);
- if (oui == OUI_MICROSOFT && pos[5] == WMM_OUI_TYPE && pos[1] > 4) {
- if (pos[6] == WMM_OUI_SUBTYPE_INFORMATION_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM IE",
- ie->wmm, ie->wmm_len);
- } else if (pos[6] == WMM_OUI_SUBTYPE_PARAMETER_ELEMENT) {
- ie->wmm = &pos[2];
- ie->wmm_len = pos[1];
- wpa_hexdump(MSG_DEBUG, "WPA: WMM Parameter Element",
- ie->wmm, ie->wmm_len);
- }
- }
- return 0;
-}
-
-
-/**
- * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
- * @pos: Pointer to the IE header
- * @end: Pointer to the end of the Key Data buffer
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, 1 if end mark is found, -1 on failure
- */
-static int wpa_parse_generic(const u8 *pos, const u8 *end,
- struct wpa_eapol_ie_parse *ie)
-{
- if (pos[1] == 0)
- return 1;
-
- if (pos[1] >= 6 &&
- RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
- pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- ie->wpa_ie = pos;
- ie->wpa_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
- ie->wpa_ie, ie->wpa_ie_len);
- return 0;
- }
-
- if (1 + RSN_SELECTOR_LEN < end - pos &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
- ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
- ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
- ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
- ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
- if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
- ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
- ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-
-#ifdef CONFIG_P2P
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_REQ) {
- ie->ip_addr_req = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: IP Address Request in EAPOL-Key",
- ie->ip_addr_req, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
+ u8 *pos = rsnxe;
- if (pos[1] >= RSN_SELECTOR_LEN + 3 * 4 &&
- RSN_SELECTOR_GET(pos + 2) == WFA_KEY_DATA_IP_ADDR_ALLOC) {
- ie->ip_addr_alloc = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG,
- "WPA: IP Address Allocation in EAPOL-Key",
- ie->ip_addr_alloc, pos[1] - RSN_SELECTOR_LEN);
- return 0;
- }
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_OCV
- if (pos[1] >= RSN_SELECTOR_LEN + 1 &&
- RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_OCI) {
- ie->oci = pos + 2 + RSN_SELECTOR_LEN;
- ie->oci_len = pos[1] - RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "WPA: OCI KDE in EAPOL-Key",
- pos, pos[1] + 2);
- return 0;
- }
-#endif /* CONFIG_OCV */
-
- return 0;
-}
+ if (!wpa_key_mgmt_sae(sm->key_mgmt))
+ return 0; /* SAE not in use */
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
+ if (rsnxe_len < 3)
+ return -1;
-/**
- * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
- * @buf: Pointer to the Key Data buffer
- * @len: Key Data Length
- * @ie: Pointer to parsed IE data
- * Returns: 0 on success, -1 on failure
- */
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie)
-{
- const u8 *pos, *end;
- int ret = 0;
-
- os_memset(ie, 0, sizeof(*ie));
- for (pos = buf, end = pos + len; end - pos > 1; pos += 2 + pos[1]) {
- if (pos[0] == 0xdd &&
- ((pos == buf + len - 1) || pos[1] == 0)) {
- /* Ignore padding */
- break;
- }
- if (2 + pos[1] > end - pos) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d pos=%d)",
- pos[0], pos[1], (int) (pos - buf));
- wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
- buf, len);
- ret = -1;
- break;
- }
- if (*pos == WLAN_EID_RSN) {
- ie->rsn_ie = pos;
- ie->rsn_ie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
- ie->rsn_ie, ie->rsn_ie_len);
- } else if (*pos == WLAN_EID_MOBILITY_DOMAIN &&
- pos[1] >= sizeof(struct rsn_mdie)) {
- ie->mdie = pos;
- ie->mdie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
- ie->mdie, ie->mdie_len);
- } else if (*pos == WLAN_EID_FAST_BSS_TRANSITION &&
- pos[1] >= sizeof(struct rsn_ftie)) {
- ie->ftie = pos;
- ie->ftie_len = pos[1] + 2;
- wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
- ie->ftie, ie->ftie_len);
- } else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
- if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
- ie->reassoc_deadline = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
- "in EAPOL-Key",
- ie->reassoc_deadline, pos[1] + 2);
- } else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
- ie->key_lifetime = pos;
- wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
- "in EAPOL-Key",
- ie->key_lifetime, pos[1] + 2);
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
- "EAPOL-Key Key Data IE",
- pos, 2 + pos[1]);
- }
- } else if (*pos == WLAN_EID_LINK_ID) {
- if (pos[1] >= 18) {
- ie->lnkid = pos;
- ie->lnkid_len = pos[1] + 2;
- }
- } else if (*pos == WLAN_EID_EXT_CAPAB) {
- ie->ext_capab = pos;
- ie->ext_capab_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_SUPP_RATES) {
- ie->supp_rates = pos;
- ie->supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
- ie->ext_supp_rates = pos;
- ie->ext_supp_rates_len = pos[1] + 2;
- } else if (*pos == WLAN_EID_HT_CAP &&
- pos[1] >= sizeof(struct ieee80211_ht_capabilities)) {
- ie->ht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_VHT_AID) {
- if (pos[1] >= 2)
- ie->aid = WPA_GET_LE16(pos + 2) & 0x3fff;
- } else if (*pos == WLAN_EID_VHT_CAP &&
- pos[1] >= sizeof(struct ieee80211_vht_capabilities))
- {
- ie->vht_capabilities = pos + 2;
- } else if (*pos == WLAN_EID_QOS && pos[1] >= 1) {
- ie->qosinfo = pos[2];
- } else if (*pos == WLAN_EID_SUPPORTED_CHANNELS) {
- ie->supp_channels = pos + 2;
- ie->supp_channels_len = pos[1];
- } else if (*pos == WLAN_EID_SUPPORTED_OPERATING_CLASSES) {
- /*
- * The value of the Length field of the Supported
- * Operating Classes element is between 2 and 253.
- * Silently skip invalid elements to avoid interop
- * issues when trying to use the value.
- */
- if (pos[1] >= 2 && pos[1] <= 253) {
- ie->supp_oper_classes = pos + 2;
- ie->supp_oper_classes_len = pos[1];
- }
- } else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
- ret = wpa_parse_generic(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
-
- ret = wpa_parse_vendor_specific(pos, end, ie);
- if (ret < 0)
- break;
- if (ret > 0) {
- ret = 0;
- break;
- }
- } else {
- wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
- "Key Data IE", pos, 2 + pos[1]);
- }
- }
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
- return ret;
+ return pos - rsnxe;
}
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 77ebe21..6dc6cf5 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -11,54 +11,7 @@
struct wpa_sm;
-struct wpa_eapol_ie_parse {
- const u8 *wpa_ie;
- size_t wpa_ie_len;
- const u8 *rsn_ie;
- size_t rsn_ie_len;
- const u8 *pmkid;
- const u8 *gtk;
- size_t gtk_len;
- const u8 *mac_addr;
- size_t mac_addr_len;
- const u8 *igtk;
- size_t igtk_len;
- const u8 *mdie;
- size_t mdie_len;
- const u8 *ftie;
- size_t ftie_len;
- const u8 *reassoc_deadline;
- const u8 *key_lifetime;
- const u8 *lnkid;
- size_t lnkid_len;
- const u8 *ext_capab;
- size_t ext_capab_len;
- const u8 *supp_rates;
- size_t supp_rates_len;
- const u8 *ext_supp_rates;
- size_t ext_supp_rates_len;
- const u8 *ht_capabilities;
- const u8 *vht_capabilities;
- const u8 *supp_channels;
- size_t supp_channels_len;
- const u8 *supp_oper_classes;
- size_t supp_oper_classes_len;
- u8 qosinfo;
- u16 aid;
- const u8 *wmm;
- size_t wmm_len;
-#ifdef CONFIG_P2P
- const u8 *ip_addr_req;
- const u8 *ip_addr_alloc;
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_OCV
- const u8 *oci;
- size_t oci_len;
-#endif /* CONFIG_OCV */
-};
-
-int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
- struct wpa_eapol_ie_parse *ie);
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
#endif /* WPA_IE_H */
diff --git a/src/utils/json.c b/src/utils/json.c
index b644339..3e5e214 100644
--- a/src/utils/json.c
+++ b/src/utils/json.c
@@ -51,7 +51,7 @@ void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
*txt++ = data[i];
} else {
txt += os_snprintf(txt, end - txt, "\\u%04x",
- data[i]);
+ (unsigned char) data[i]);
}
break;
}
diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c
index 4e872f3..5ec7133 100644
--- a/src/wps/wps_attr_build.c
+++ b/src/wps/wps_attr_build.c
@@ -175,7 +175,9 @@ int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg);
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0)
+ return -1;
wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
@@ -371,8 +373,9 @@ int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
u8 hash[SHA256_MAC_LEN];
wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
- wpabuf_len(msg), hash);
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
+ wpabuf_len(msg), hash) < 0)
+ return -1;
wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
wpabuf_put_be16(msg, WPS_KWA_LEN);
diff --git a/src/wps/wps_attr_process.c b/src/wps/wps_attr_process.c
index e8c4579..44436a4 100644
--- a/src/wps/wps_attr_process.c
+++ b/src/wps/wps_attr_process.c
@@ -39,9 +39,10 @@ int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
len[0] = wpabuf_len(wps->last_msg);
addr[1] = wpabuf_head(msg);
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
- hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
- if (os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
+ if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
return -1;
}
@@ -70,8 +71,8 @@ int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
return -1;
}
- hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
- if (os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
+ if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 ||
+ os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
return -1;
}
diff --git a/tests/fuzzing/eapol-key-auth/eapol-key-auth.c b/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
index 0fffa78..a909114 100644
--- a/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
+++ b/tests/fuzzing/eapol-key-auth/eapol-key-auth.c
@@ -261,7 +261,8 @@ static int auth_init(struct wpa *wpa)
}
if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, 2412, supp_ie,
- supp_ie_len, NULL, 0, NULL, 0) != WPA_IE_OK) {
+ supp_ie_len, NULL, 0, NULL, 0, NULL, 0) !=
+ WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
}
diff --git a/tests/hwsim/auth_serv/index.txt b/tests/hwsim/auth_serv/index.txt
index e61cecf..7e48c3f 100644
--- a/tests/hwsim/auth_serv/index.txt
+++ b/tests/hwsim/auth_serv/index.txt
@@ -5,4 +5,4 @@ V 150215083008Z D8D3E3A6CBE3CCCB unknown /C=FI/O=w1.fi/CN=server5.w1.fi
V 150228224144Z D8D3E3A6CBE3CCCC unknown /C=FI/O=w1.fi/CN=server6.w1.fi
V 160111185024Z D8D3E3A6CBE3CCCD unknown /C=FI/O=w1.fi/CN=ocsp.w1.fi
V 150929211300Z D8D3E3A6CBE3CCD1 unknown /C=FI/O=w1.fi/CN=Test User
-V 191003221355Z D8D3E3A6CBE3CD17 unknown /C=FI/O=w1.fi/CN=server.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD1F unknown /C=FI/O=w1.fi/CN=server.w1.fi
diff --git a/tests/hwsim/auth_serv/ocsp-multi-server-cache.der b/tests/hwsim/auth_serv/ocsp-multi-server-cache.der
index 36be811..2e0e88b 100644
--- a/tests/hwsim/auth_serv/ocsp-multi-server-cache.der
+++ b/tests/hwsim/auth_serv/ocsp-multi-server-cache.der
Binary files differ
diff --git a/tests/hwsim/auth_serv/ocsp-req.der b/tests/hwsim/auth_serv/ocsp-req.der
index 3a70e38..92ae099 100644
--- a/tests/hwsim/auth_serv/ocsp-req.der
+++ b/tests/hwsim/auth_serv/ocsp-req.der
Binary files differ
diff --git a/tests/hwsim/auth_serv/ocsp-server-cache.der b/tests/hwsim/auth_serv/ocsp-server-cache.der
index 3d45879..97696b7 100644
--- a/tests/hwsim/auth_serv/ocsp-server-cache.der
+++ b/tests/hwsim/auth_serv/ocsp-server-cache.der
Binary files differ
diff --git a/tests/hwsim/auth_serv/server-certpol.pem b/tests/hwsim/auth_serv/server-certpol.pem
index 5bc0fd1..2c81113 100644
--- a/tests/hwsim/auth_serv/server-certpol.pem
+++ b/tests/hwsim/auth_serv/server-certpol.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162909 (0xd8d3e3a6cbe3cd1d)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:23
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Jun 11 00:12:34 2019 GMT
- Not After : Jun 10 00:12:34 2020 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server-policies.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (3072 bit)
+ RSA Public-Key: (3072 bit)
Modulus:
00:d2:a6:ef:9b:bd:60:63:a1:75:ad:4b:d3:6f:59:
5e:84:fa:64:a0:64:24:0b:78:48:fc:8d:66:8b:2f:
@@ -58,18 +59,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
- ad:cc:03:e6:6b:f0:05:4b:27:41:2a:4d:23:dc:89:76:1d:61:
- 7f:b6:06:fc:48:8b:ce:1a:c2:c4:43:49:6a:41:9b:5e:65:ce:
- a7:e6:62:df:44:96:3e:0e:d9:26:20:f2:2a:53:5d:35:c8:f7:
- 15:d2:60:29:50:c7:20:50:a1:df:7a:41:cd:1d:a6:3a:e8:3f:
- 5d:1c:38:ed:73:f6:ee:41:ff:8a:54:c4:b5:94:ba:b7:c6:cd:
- 82:c8:c2:7d:dc:4d:27:2f:f1:77:40:20:7c:5a:6b:ce:3e:9d:
- e5:17:d1:5d:0a:79:66:59:fb:c9:08:cc:24:09:4d:53:ae:4f:
- fb:c6
+ 6d:bc:df:42:16:4b:a1:22:ba:a6:06:f3:70:ce:f7:37:7b:4d:
+ cf:e5:37:cc:5d:e4:b0:6c:09:09:b1:eb:32:3b:54:ab:95:41:
+ ef:6a:0b:d9:ab:0d:23:8f:39:cf:1e:93:a2:f4:65:a6:ae:e2:
+ 75:35:63:7b:8f:45:08:e3:00:5a:28:a1:26:e3:19:0f:bf:08:
+ 12:2d:c0:7b:72:2a:48:af:a6:a6:82:1d:b5:7a:f3:ac:6e:0b:
+ 85:47:7a:54:2c:25:a6:38:68:4d:5c:80:6b:79:0a:70:db:aa:
+ 8a:ee:10:61:2c:e5:14:26:e5:52:bc:a9:fc:88:a9:6e:f9:ab:
+ 09:cf
-----BEGIN CERTIFICATE-----
-MIIDxTCCAy6gAwIBAgIJANjT46bL480dMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTA2
-MTEwMDEyMzRaFw0yMDA2MTAwMDEyMzRaMD0xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIDxTCCAy6gAwIBAgIJANjT46bL480jMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMD0xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEeMBwGA1UEAwwVc2VydmVyLXBvbGljaWVzLncxLmZpMIIBojANBgkq
hkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0qbvm71gY6F1rUvTb1lehPpkoGQkC3hI
/I1miy9uHUQrrsNtlLrLozS+C05HjVvZmaaoBwmHVbI3fkdnXHRfLIN5sghHtOxP
@@ -84,8 +85,8 @@ BgNVHQ4EFgQUPq0NTX76okrV9THqtrS/g7FVfscwHwYDVR0jBBgwFoAUuJLe/YoY
szDDn1XzM120yCmKQRQwNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUFBzABhhlodHRw
Oi8vc2VydmVyLncxLmZpOjg4ODgvMCAGA1UdEQQZMBeCFXNlcnZlci1wb2xpY2ll
cy53MS5maTAYBgNVHSAEETAPMA0GCysGAQQBgr5oAQMBMBMGA1UdJQQMMAoGCCsG
-AQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBAK3MA+Zr8AVLJ0EqTSPciXYdYX+2BvxI
-i84awsRDSWpBm15lzqfmYt9Elj4O2SYg8ipTXTXI9xXSYClQxyBQod96Qc0dpjro
-P10cOO1z9u5B/4pUxLWUurfGzYLIwn3cTScv8XdAIHxaa84+neUX0V0KeWZZ+8kI
-zCQJTVOuT/vG
+AQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBAG2830IWS6EiuqYG83DO9zd7Tc/lN8xd
+5LBsCQmx6zI7VKuVQe9qC9mrDSOPOc8ek6L0Zaau4nU1Y3uPRQjjAFoooSbjGQ+/
+CBItwHtyKkivpqaCHbV686xuC4VHelQsJaY4aE1cgGt5CnDbqoruEGEs5RQm5VK8
+qfyIqW75qwnP
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-certpol2.pem b/tests/hwsim/auth_serv/server-certpol2.pem
index b200b76..d96af29 100644
--- a/tests/hwsim/auth_serv/server-certpol2.pem
+++ b/tests/hwsim/auth_serv/server-certpol2.pem
@@ -2,12 +2,12 @@ Certificate:
Data:
Version: 3 (0x2)
Serial Number:
- d8:d3:e3:a6:cb:e3:cd:1e
+ d8:d3:e3:a6:cb:e3:cd:24
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Aug 16 12:58:24 2019 GMT
- Not After : Aug 15 12:58:24 2020 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server-policies2.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
@@ -59,18 +59,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
- 89:0d:37:6e:dd:ac:99:70:c3:21:20:ad:00:6e:62:19:a9:d2:
- eb:0c:af:e7:76:3a:dc:9e:7d:0b:cf:0e:73:48:48:41:4c:53:
- 19:85:14:25:36:32:b4:52:14:ab:3d:0a:eb:ce:0d:0a:66:e5:
- a5:81:b5:09:90:96:c9:09:49:bd:b4:7a:f3:15:3a:2e:53:2c:
- 8a:62:83:20:72:4e:71:d1:89:ff:41:72:39:a0:a3:98:07:91:
- a1:72:ef:ef:29:20:66:ce:7d:38:6f:bc:ad:f1:4f:51:26:87:
- 42:05:95:65:ce:27:44:64:86:a5:ed:8b:85:eb:7f:30:ca:07:
- 72:e3
+ 2c:96:45:a3:b5:47:2d:b8:0e:f9:e2:d8:5d:a5:0c:99:cb:3f:
+ 82:e8:81:2a:ec:c8:82:e2:c4:0a:16:b8:19:87:7d:b8:bb:e8:
+ e6:3c:bc:24:63:f0:82:98:23:1b:eb:39:89:01:b6:d0:e2:e0:
+ 53:67:14:a3:34:76:af:ef:4a:7e:50:bb:be:9b:64:14:dc:04:
+ 27:08:d2:9e:ef:16:2e:33:c1:fa:8a:29:0b:78:9e:e4:4f:c4:
+ 14:8b:cd:fb:cd:98:2c:d9:f9:66:e1:1a:25:80:b9:c7:53:84:
+ 80:b6:40:88:09:6a:1f:04:1c:fa:b7:c2:7c:90:8e:bc:da:84:
+ b3:e1
-----BEGIN CERTIFICATE-----
-MIIDxzCCAzCgAwIBAgIJANjT46bL480eMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTA4
-MTYxMjU4MjRaFw0yMDA4MTUxMjU4MjRaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIDxzCCAzCgAwIBAgIJANjT46bL480kMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMD4xCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEfMB0GA1UEAwwWc2VydmVyLXBvbGljaWVzMi53MS5maTCCAaIwDQYJ
KoZIhvcNAQEBBQADggGPADCCAYoCggGBAOZQ0SgFJ2zUQtNCx8xTqWvCo6sgbxc0
neQdMdDEaGVC1ei9qrjk6fbuLnXNaoz2jqqvbHzrNVBVscKz+KfQHqMzJmhAIBN0
@@ -85,8 +85,8 @@ HQYDVR0OBBYEFE4Bi37Cd5ThaLPEKTUkBQvehEqJMB8GA1UdIwQYMBaAFLiS3v2K
GLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkwJzAlBggrBgEFBQcwAYYZaHR0
cDovL3NlcnZlci53MS5maTo4ODg4LzAhBgNVHREEGjAYghZzZXJ2ZXItcG9saWNp
ZXMyLncxLmZpMBgGA1UdIAQRMA8wDQYLKwYBBAGCvmgBAwIwEwYDVR0lBAwwCgYI
-KwYBBQUHAwEwDQYJKoZIhvcNAQELBQADgYEAiQ03bt2smXDDISCtAG5iGanS6wyv
-53Y63J59C88Oc0hIQUxTGYUUJTYytFIUqz0K684NCmblpYG1CZCWyQlJvbR68xU6
-LlMsimKDIHJOcdGJ/0FyOaCjmAeRoXLv7ykgZs59OG+8rfFPUSaHQgWVZc4nRGSG
-pe2Lhet/MMoHcuM=
+KwYBBQUHAwEwDQYJKoZIhvcNAQELBQADgYEALJZFo7VHLbgO+eLYXaUMmcs/guiB
+KuzIguLECha4GYd9uLvo5jy8JGPwgpgjG+s5iQG20OLgU2cUozR2r+9KflC7vptk
+FNwEJwjSnu8WLjPB+oopC3ie5E/EFIvN+82YLNn5ZuEaJYC5x1OEgLZAiAlqHwQc
++rfCfJCOvNqEs+E=
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-eku-client-server.pem b/tests/hwsim/auth_serv/server-eku-client-server.pem
index cdf2a51..2d299ae 100644
--- a/tests/hwsim/auth_serv/server-eku-client-server.pem
+++ b/tests/hwsim/auth_serv/server-eku-client-server.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162906 (0xd8d3e3a6cbe3cd1a)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:22
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Oct 3 22:13:55 2018 GMT
- Not After : Oct 3 22:13:55 2019 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server6.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ RSA Public-Key: (1024 bit)
Modulus:
00:ca:30:1e:fd:13:6a:02:28:51:9a:0e:a9:1e:72:
7e:e7:5a:c8:cb:0c:7e:8a:99:81:8d:05:b3:09:b0:
@@ -36,18 +37,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Client Authentication, TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
- 6d:25:9d:07:b2:54:61:8a:27:71:bb:94:3f:9d:20:60:41:68:
- 7c:f6:c1:56:c8:22:a4:4c:3c:59:67:3a:db:a3:10:6f:fc:0b:
- 83:81:2b:1a:e3:b9:a4:7b:50:ba:94:fa:43:4d:08:3f:22:f6:
- a9:ee:92:0b:30:d1:46:e8:d5:05:a5:38:cc:4c:b2:13:8d:a9:
- 9c:7d:7d:26:c8:9c:b4:b2:58:df:87:a7:05:6e:f1:51:93:46:
- 13:77:91:3c:f0:d7:19:02:e9:4a:95:e6:d1:7b:71:22:6d:79:
- a0:45:94:98:15:bf:be:bd:bb:a7:d2:36:8b:56:4d:7c:2a:cc:
- 07:0a
+ 1c:47:3b:a1:09:82:7d:f8:84:e2:b4:0c:26:5b:bb:f2:9a:62:
+ 80:ae:8e:fa:c6:4d:4b:83:73:b9:b1:d4:f8:61:5b:bb:ff:00:
+ e4:86:a1:c9:9d:a2:99:e8:70:6b:41:81:4c:12:22:74:60:54:
+ 8c:34:e8:01:a3:d5:4d:47:11:ec:39:71:2b:dc:b4:dc:2b:5d:
+ 49:df:49:bf:ad:de:e6:e6:6a:76:06:74:a5:50:9c:bc:46:ce:
+ a4:4f:5c:f3:0c:bc:08:c5:f7:a8:aa:bf:4a:60:d6:a1:30:82:
+ 6f:94:f1:68:09:0d:d5:94:64:e5:3f:ee:be:5d:ce:5d:91:99:
+ 60:c2
-----BEGIN CERTIFICATE-----
-MIIChzCCAfCgAwIBAgIJANjT46bL480aMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
-MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIChzCCAfCgAwIBAgIJANjT46bL480iMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNi53MS5maTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAyjAe/RNqAihRmg6pHnJ+51rIywx+ipmBjQWzCbCphueuRPrg
x+7zGLQxZeMFb2ZO4+SFgZtHf1+1FiuwWZGcxVXT08osgc7wJ6hU3g5P2PARvQsQ
@@ -55,8 +56,8 @@ Vjgm36k6lRWTphbt0h60tcCoYY6uEAT95ibKSg2QS7msyZTysWuXa2Ak6r0CAwEA
AaOBpDCBoTAJBgNVHRMEAjAAMB0GA1UdDgQWBBTHxu/1YdKgCIFqa0Qs9XL32t5b
uTAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wHQYDVR0l
-BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBAG0lnQey
-VGGKJ3G7lD+dIGBBaHz2wVbIIqRMPFlnOtujEG/8C4OBKxrjuaR7ULqU+kNNCD8i
-9qnukgsw0Ubo1QWlOMxMshONqZx9fSbInLSyWN+HpwVu8VGTRhN3kTzw1xkC6UqV
-5tF7cSJteaBFlJgVv769u6fSNotWTXwqzAcK
+BBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMA0GCSqGSIb3DQEBCwUAA4GBABxHO6EJ
+gn34hOK0DCZbu/KaYoCujvrGTUuDc7mx1PhhW7v/AOSGocmdopnocGtBgUwSInRg
+VIw06AGj1U1HEew5cSvctNwrXUnfSb+t3ubmanYGdKVQnLxGzqRPXPMMvAjF96iq
+v0pg1qEwgm+U8WgJDdWUZOU/7r5dzl2RmWDC
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-eku-client.pem b/tests/hwsim/auth_serv/server-eku-client.pem
index 17fbaa0..5e39ec0 100644
--- a/tests/hwsim/auth_serv/server-eku-client.pem
+++ b/tests/hwsim/auth_serv/server-eku-client.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162905 (0xd8d3e3a6cbe3cd19)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:21
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Oct 3 22:13:55 2018 GMT
- Not After : Oct 3 22:13:55 2019 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server5.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ RSA Public-Key: (1024 bit)
Modulus:
00:a3:99:e9:e2:e1:17:60:3b:70:34:1a:74:5c:46:
e3:b8:bd:bb:aa:c9:f3:ee:fb:12:30:a0:69:c3:74:
@@ -36,18 +37,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- 66:75:73:86:b8:50:8d:7a:43:9e:fe:ab:ac:61:39:f8:46:03:
- 86:9d:31:9b:d7:98:e5:1a:a6:4f:f7:5e:bb:1c:dc:a6:6d:c2:
- f1:1c:a0:00:e3:1c:d0:2f:71:f3:c1:51:83:e5:1c:36:55:de:
- 37:9b:71:26:5f:b3:38:58:34:d7:f8:1a:3f:f5:c6:d3:12:85:
- cf:73:ac:a4:f0:d0:52:23:e9:95:9e:3e:f8:7e:3a:07:a8:76:
- 68:87:f1:19:79:d7:a3:47:3e:ab:f8:22:34:68:3d:3e:84:6c:
- d6:4b:be:12:4c:6e:0a:98:20:23:b0:72:f7:f8:33:4f:42:e9:
- 12:9e
+ 96:f9:cb:e1:73:60:40:d6:85:d1:ed:a5:14:fc:c1:98:15:2a:
+ bd:02:dd:54:bf:69:ac:9d:b7:af:5c:62:b0:85:32:a2:04:27:
+ d4:98:98:d0:99:53:a9:03:88:33:fa:41:7f:a2:e8:ca:7f:6d:
+ f0:ad:7a:b2:49:1c:be:43:5a:dd:58:1b:bc:32:ae:86:10:00:
+ 30:44:f8:44:85:34:dc:fb:05:a3:8a:ab:f4:48:6e:f3:c4:6e:
+ c7:a0:39:82:bd:15:3b:0b:ea:78:10:2d:43:6c:73:c0:60:f8:
+ 1c:ad:c1:bf:df:6e:05:b9:db:3f:0c:3e:72:23:bd:56:f6:2a:
+ a5:e6
-----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL480ZMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
-MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL480hMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyNS53MS5maTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAo5np4uEXYDtwNBp0XEbjuL27qsnz7vsSMKBpw3Q4gDq6I1LH
wWrPut1B49JpNaSmYGwxH4W9Vmx7CWPNp1FrhECQd36XaHs4tcQVO3Q3NCi6euLX
@@ -55,8 +56,8 @@ hFN4dk0Wt7jfCXLnhyZ0LATKxc4p9bTO2yjrRUdCj+2IWqMjSZt7vDnhAVMCAwEA
AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBQzFp07FxWCKzRuOOjMIr9Jp14q
KzAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADgYEAZnVzhrhQjXpDnv6rrGE5
-+EYDhp0xm9eY5RqmT/deuxzcpm3C8RygAOMc0C9x88FRg+UcNlXeN5txJl+zOFg0
-1/gaP/XG0xKFz3OspPDQUiPplZ4++H46B6h2aIfxGXnXo0c+q/giNGg9PoRs1ku+
-EkxuCpggI7By9/gzT0LpEp4=
+BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADgYEAlvnL4XNgQNaF0e2lFPzB
+mBUqvQLdVL9prJ23r1xisIUyogQn1JiY0JlTqQOIM/pBf6Loyn9t8K16skkcvkNa
+3VgbvDKuhhAAMET4RIU03PsFo4qr9Ehu88Rux6A5gr0VOwvqeBAtQ2xzwGD4HK3B
+v99uBbnbPww+ciO9VvYqpeY=
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server-extra.pkcs12 b/tests/hwsim/auth_serv/server-extra.pkcs12
index 822af70..7c963a6 100644
--- a/tests/hwsim/auth_serv/server-extra.pkcs12
+++ b/tests/hwsim/auth_serv/server-extra.pkcs12
Binary files differ
diff --git a/tests/hwsim/auth_serv/server-no-dnsname.pem b/tests/hwsim/auth_serv/server-no-dnsname.pem
index 44f90f7..432f9b6 100644
--- a/tests/hwsim/auth_serv/server-no-dnsname.pem
+++ b/tests/hwsim/auth_serv/server-no-dnsname.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162904 (0xd8d3e3a6cbe3cd18)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:20
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Oct 3 22:13:55 2018 GMT
- Not After : Oct 3 22:13:55 2019 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server3.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ RSA Public-Key: (1024 bit)
Modulus:
00:db:fc:0f:a1:48:87:68:86:c4:9e:7a:f8:18:28:
77:6d:a3:58:0f:db:be:6b:d4:43:43:c4:ba:17:37:
@@ -36,18 +37,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
- 06:f7:a9:82:0d:61:44:10:b3:f6:6b:6d:3b:11:49:f5:22:e0:
- 2d:99:a7:df:e1:19:b4:d4:c1:f0:d7:97:8c:c2:db:f5:59:39:
- cc:bc:3f:c0:bd:f9:7d:97:b5:05:04:8c:1d:7a:10:cf:ac:95:
- 85:7b:ae:b2:da:9b:a6:da:05:c9:a6:68:66:c4:f4:cc:71:4f:
- 85:77:98:2e:a6:96:0f:d0:38:8d:fb:0b:03:9f:3e:89:01:15:
- 9f:0e:73:4b:57:13:5c:f4:05:1c:96:35:be:cc:18:28:e5:d6:
- eb:93:6a:2f:a9:c5:5e:5a:d0:6d:04:c3:98:e2:b2:d8:f2:c4:
- 8a:64
+ 17:8a:95:bc:a7:76:e0:b7:b6:b6:47:5a:41:44:0f:43:76:1f:
+ 50:87:f6:64:fe:e9:3a:fb:73:04:df:7b:57:7a:34:ba:ab:bc:
+ ab:d1:18:59:bf:6e:9b:4d:8c:3f:15:65:dd:e9:3c:86:01:69:
+ d5:2b:c3:23:65:9c:07:ef:4a:52:09:c7:3a:68:8e:14:4d:4a:
+ 78:23:0c:ec:8d:37:13:2d:ac:ac:6e:d1:f8:5c:a1:1f:50:50:
+ 00:fd:ab:e9:f6:ae:f2:c4:78:3c:44:e3:5e:b0:c6:6d:a0:06:
+ 98:c9:e2:d1:9a:d7:8b:09:af:f4:10:06:e1:9f:1e:de:d0:c3:
+ b9:1c
-----BEGIN CERTIFICATE-----
-MIICfTCCAeagAwIBAgIJANjT46bL480YMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
-MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICfTCCAeagAwIBAgIJANjT46bL480gMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMDUxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEWMBQGA1UEAwwNc2VydmVyMy53MS5maTCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEA2/wPoUiHaIbEnnr4GCh3baNYD9u+a9RDQ8S6FzebqP+WonMU
ExyuGQ+BVDUQZJTjZGW+mwsW0p6SmHeH4pqZ/B1XDIoNTCEvrmfXY2HrkVtYL61n
@@ -55,8 +56,8 @@ ZmXkgwfKajal5iD2XJkn22PlhtgrfB2QRIEiIXcKAwXD62Nhs0wywIeHOkcCAwEA
AaOBmjCBlzAJBgNVHRMEAjAAMB0GA1UdDgQWBBSOmk9NRq1ZrH9MnL5tW9eZY43H
cDAfBgNVHSMEGDAWgBS4kt79ihizMMOfVfMzXbTIKYpBFDA1BggrBgEFBQcBAQQp
MCcwJQYIKwYBBQUHMAGGGWh0dHA6Ly9zZXJ2ZXIudzEuZmk6ODg4OC8wEwYDVR0l
-BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADgYEABvepgg1hRBCz9mttOxFJ
-9SLgLZmn3+EZtNTB8NeXjMLb9Vk5zLw/wL35fZe1BQSMHXoQz6yVhXuustqbptoF
-yaZoZsT0zHFPhXeYLqaWD9A4jfsLA58+iQEVnw5zS1cTXPQFHJY1vswYKOXW65Nq
-L6nFXlrQbQTDmOKy2PLEimQ=
+BAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADgYEAF4qVvKd24Le2tkdaQUQP
+Q3YfUIf2ZP7pOvtzBN97V3o0uqu8q9EYWb9um02MPxVl3ek8hgFp1SvDI2WcB+9K
+UgnHOmiOFE1KeCMM7I03Ey2srG7R+FyhH1BQAP2r6fau8sR4PETjXrDGbaAGmMni
+0ZrXiwmv9BAG4Z8e3tDDuRw=
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server.pem b/tests/hwsim/auth_serv/server.pem
index 93b39b9..a8baa17 100644
--- a/tests/hwsim/auth_serv/server.pem
+++ b/tests/hwsim/auth_serv/server.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162903 (0xd8d3e3a6cbe3cd17)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:1f
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Oct 3 22:13:55 2018 GMT
- Not After : Oct 3 22:13:55 2019 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=server.w1.fi
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ RSA Public-Key: (1024 bit)
Modulus:
00:ba:a0:77:55:22:14:85:55:65:9b:64:2c:ad:ed:
9b:dd:65:31:c9:da:60:50:ce:38:d6:34:dc:e8:bc:
@@ -38,18 +39,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
- b6:98:ae:d9:9b:9a:44:49:b2:06:ee:af:36:83:cb:cd:cb:c9:
- f3:38:6d:65:cb:e9:81:d2:25:dd:76:12:5c:da:3f:a1:0e:11:
- a5:04:ed:05:29:2d:66:94:82:a2:80:67:d1:d8:78:71:72:5f:
- 10:c3:51:a2:7b:f5:0b:5f:ec:70:12:99:cb:65:6f:50:7f:2b:
- 05:7c:b4:d7:1b:21:77:66:47:33:f3:a7:d6:fb:ce:97:fe:5f:
- fd:df:1f:1d:6f:ef:22:5a:c6:78:d2:2b:07:1e:55:ec:80:62:
- 06:7a:be:6a:0d:4d:96:c2:d5:df:76:56:b0:85:6a:f8:a0:27:
- 62:31
+ 0b:dc:4c:f7:63:b6:7b:db:79:a9:6b:d3:70:cb:c1:51:30:2d:
+ 76:d3:20:6a:95:3a:fe:93:4b:6a:28:86:2f:1c:1c:ea:25:92:
+ b5:86:a8:08:ea:c4:0e:15:e1:b9:fd:b3:f0:d8:5a:bf:58:f7:
+ 57:a3:2d:fa:0e:ca:17:e4:42:bc:1d:40:f4:c6:01:76:ea:f3:
+ d3:44:d6:5b:19:1a:24:ba:c2:6e:d9:7b:10:00:f2:2c:37:9a:
+ fb:3e:74:2e:aa:92:b0:db:e0:92:d4:3e:66:89:37:08:71:dd:
+ 53:3f:83:6b:74:0e:3e:e5:1e:2f:f1:0f:b0:fb:ed:90:82:b4:
+ d7:ce
-----BEGIN CERTIFICATE-----
-MIIClTCCAf6gAwIBAgIJANjT46bL480XMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
-MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDQxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIIClTCCAf6gAwIBAgIJANjT46bL480fMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMDQxCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTEVMBMGA1UEAwwMc2VydmVyLncxLmZpMIGfMA0GCSqGSIb3DQEBAQUA
A4GNADCBiQKBgQC6oHdVIhSFVWWbZCyt7ZvdZTHJ2mBQzjjWNNzovBueMOcS41Ns
ye1IA3mBaZjOirh3RzZFz8bg8XsecYlU9wHMIq2gQrGoNZ5gqjqYUdD/H+6+jQpj
@@ -58,7 +59,7 @@ o4GzMIGwMAkGA1UdEwQCMAAwHQYDVR0OBBYEFDFPEFxnn75OiNbcxaueEoiGaQJP
MB8GA1UdIwQYMBaAFLiS3v2KGLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkw
JzAlBggrBgEFBQcwAYYZaHR0cDovL3NlcnZlci53MS5maTo4ODg4LzAXBgNVHREE
EDAOggxzZXJ2ZXIudzEuZmkwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcN
-AQELBQADgYEAtpiu2ZuaREmyBu6vNoPLzcvJ8zhtZcvpgdIl3XYSXNo/oQ4RpQTt
-BSktZpSCooBn0dh4cXJfEMNRonv1C1/scBKZy2VvUH8rBXy01xshd2ZHM/On1vvO
-l/5f/d8fHW/vIlrGeNIrBx5V7IBiBnq+ag1NlsLV33ZWsIVq+KAnYjE=
+AQELBQADgYEAC9xM92O2e9t5qWvTcMvBUTAtdtMgapU6/pNLaiiGLxwc6iWStYao
+COrEDhXhuf2z8Nhav1j3V6Mt+g7KF+RCvB1A9MYBdurz00TWWxkaJLrCbtl7EADy
+LDea+z50LqqSsNvgktQ+Zok3CHHdUz+Da3QOPuUeL/EPsPvtkIK0184=
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/server.pkcs12 b/tests/hwsim/auth_serv/server.pkcs12
index ba2516c..a5b698e 100644
--- a/tests/hwsim/auth_serv/server.pkcs12
+++ b/tests/hwsim/auth_serv/server.pkcs12
Binary files differ
diff --git a/tests/hwsim/auth_serv/test-ca/index.txt b/tests/hwsim/auth_serv/test-ca/index.txt
index 0c11f45..6c94cb6 100644
--- a/tests/hwsim/auth_serv/test-ca/index.txt
+++ b/tests/hwsim/auth_serv/test-ca/index.txt
@@ -44,3 +44,10 @@ V 191003221355Z D8D3E3A6CBE3CD1A unknown /C=FI/O=w1.fi/CN=server6.w1.fi
V 191003221355Z D8D3E3A6CBE3CD1B unknown /C=FI/O=w1.fi/CN=Test User
V 200610001234Z D8D3E3A6CBE3CD1D unknown /C=FI/O=w1.fi/CN=server-policies.w1.fi
V 200815125824Z D8D3E3A6CBE3CD1E unknown /C=FI/O=w1.fi/CN=server-policies2.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD1F unknown /C=FI/O=w1.fi/CN=server.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD20 unknown /C=FI/O=w1.fi/CN=server3.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD21 unknown /C=FI/O=w1.fi/CN=server5.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD22 unknown /C=FI/O=w1.fi/CN=server6.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD23 unknown /C=FI/O=w1.fi/CN=server-policies.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD24 unknown /C=FI/O=w1.fi/CN=server-policies2.w1.fi
+V 201003130223Z D8D3E3A6CBE3CD25 unknown /C=FI/O=w1.fi/CN=Test User
diff --git a/tests/hwsim/auth_serv/test-ca/serial b/tests/hwsim/auth_serv/test-ca/serial
index 195aece..1394bbf 100644
--- a/tests/hwsim/auth_serv/test-ca/serial
+++ b/tests/hwsim/auth_serv/test-ca/serial
@@ -1 +1 @@
-D8D3E3A6CBE3CD1F
+D8D3E3A6CBE3CD26
diff --git a/tests/hwsim/auth_serv/user.pem b/tests/hwsim/auth_serv/user.pem
index 6912200..f0b0962 100644
--- a/tests/hwsim/auth_serv/user.pem
+++ b/tests/hwsim/auth_serv/user.pem
@@ -1,16 +1,17 @@
Certificate:
Data:
Version: 3 (0x2)
- Serial Number: 15624081837803162907 (0xd8d3e3a6cbe3cd1b)
- Signature Algorithm: sha256WithRSAEncryption
+ Serial Number:
+ d8:d3:e3:a6:cb:e3:cd:25
+ Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FI, O=w1.fi, CN=Root CA
Validity
- Not Before: Oct 3 22:13:55 2018 GMT
- Not After : Oct 3 22:13:55 2019 GMT
+ Not Before: Oct 4 13:02:23 2019 GMT
+ Not After : Oct 3 13:02:23 2020 GMT
Subject: C=FI, O=w1.fi, CN=Test User
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
- Public-Key: (1024 bit)
+ RSA Public-Key: (1024 bit)
Modulus:
00:a6:96:2e:9b:22:8c:df:94:be:8b:89:49:f6:78:
76:a2:60:7e:14:95:f3:96:fe:ab:19:25:03:34:64:
@@ -36,18 +37,18 @@ Certificate:
X509v3 Extended Key Usage:
TLS Web Client Authentication
Signature Algorithm: sha256WithRSAEncryption
- b3:49:8e:c8:93:0a:80:77:7b:dc:de:29:0d:d6:9b:a3:4c:ae:
- 99:59:8d:37:e0:dd:3f:3a:63:6c:08:b9:74:b7:2c:27:80:b8:
- ff:6b:c4:0c:60:d7:b9:a2:2c:ab:00:04:43:d8:9d:89:91:43:
- 02:07:c9:96:66:d6:ea:8d:83:ee:d1:62:9b:0d:ab:01:c3:6e:
- 12:2a:a1:b0:9f:2f:f4:dd:45:aa:08:a3:c9:47:9e:5a:05:09:
- b7:81:3a:b5:d0:e9:56:88:f6:d9:17:6f:62:1e:ab:39:93:df:
- f2:ad:6a:c2:05:7c:7f:39:2f:19:2a:ab:dd:34:4e:38:37:aa:
- ee:30
+ 98:05:c3:45:76:9e:87:4b:6b:68:56:71:81:6c:3d:99:29:02:
+ 6e:00:9d:fd:2b:8a:81:c3:d4:57:f7:43:34:08:df:4a:f0:59:
+ a4:3c:aa:86:a2:e2:06:3f:2c:41:b8:db:aa:e1:25:b3:8f:ab:
+ 85:ff:da:de:e4:3c:a6:12:3a:25:27:c5:17:f5:6c:9e:4d:54:
+ 36:60:df:f1:95:8f:dd:a6:97:13:ab:9f:d8:39:1f:88:29:3a:
+ 90:73:65:08:78:e9:64:b3:c0:34:a2:b4:a9:8e:b7:f9:f8:3f:
+ fb:b6:cb:58:2d:55:2a:57:55:b9:08:c1:6b:b8:f2:25:a2:9a:
+ 95:a2
-----BEGIN CERTIFICATE-----
-MIICeTCCAeKgAwIBAgIJANjT46bL480bMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
-BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xODEw
-MDMyMjEzNTVaFw0xOTEwMDMyMjEzNTVaMDExCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
+MIICeTCCAeKgAwIBAgIJANjT46bL480lMA0GCSqGSIb3DQEBCwUAMC8xCzAJBgNV
+BAYTAkZJMQ4wDAYDVQQKDAV3MS5maTEQMA4GA1UEAwwHUm9vdCBDQTAeFw0xOTEw
+MDQxMzAyMjNaFw0yMDEwMDMxMzAyMjNaMDExCzAJBgNVBAYTAkZJMQ4wDAYDVQQK
DAV3MS5maTESMBAGA1UEAwwJVGVzdCBVc2VyMIGfMA0GCSqGSIb3DQEBAQUAA4GN
ADCBiQKBgQCmli6bIozflL6LiUn2eHaiYH4UlfOW/qsZJQM0ZHQBPqiffPFHYWBM
gpIofCugDsuHv1nr1/NhIjsU86sx9lqVH7h6uCw8qWFTeJvoPlDswtZE50PNvD5O
@@ -55,8 +56,8 @@ gpIofCugDsuHv1nr1/NhIjsU86sx9lqVH7h6uCw8qWFTeJvoPlDswtZE50PNvD5O
MIGXMAkGA1UdEwQCMAAwHQYDVR0OBBYEFIHe3+laABrKZ9YG3WWyTsWaBEN9MB8G
A1UdIwQYMBaAFLiS3v2KGLMww59V8zNdtMgpikEUMDUGCCsGAQUFBwEBBCkwJzAl
BggrBgEFBQcwAYYZaHR0cDovL3NlcnZlci53MS5maTo4ODg4LzATBgNVHSUEDDAK
-BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQCzSY7IkwqAd3vc3ikN1pujTK6Z
-WY034N0/OmNsCLl0tywngLj/a8QMYNe5oiyrAARD2J2JkUMCB8mWZtbqjYPu0WKb
-DasBw24SKqGwny/03UWqCKPJR55aBQm3gTq10OlWiPbZF29iHqs5k9/yrWrCBXx/
-OS8ZKqvdNE44N6ruMA==
+BggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOBgQCYBcNFdp6HS2toVnGBbD2ZKQJu
+AJ39K4qBw9RX90M0CN9K8FmkPKqGouIGPyxBuNuq4SWzj6uF/9re5DymEjolJ8UX
+9WyeTVQ2YN/xlY/dppcTq5/YOR+IKTqQc2UIeOlks8A0orSpjrf5+D/7tstYLVUq
+V1W5CMFruPIlopqVog==
-----END CERTIFICATE-----
diff --git a/tests/hwsim/auth_serv/user.pkcs12 b/tests/hwsim/auth_serv/user.pkcs12
index bd8abd5..30fd179 100644
--- a/tests/hwsim/auth_serv/user.pkcs12
+++ b/tests/hwsim/auth_serv/user.pkcs12
Binary files differ
diff --git a/tests/hwsim/auth_serv/user2.pkcs12 b/tests/hwsim/auth_serv/user2.pkcs12
index de39b79..f2eeed8 100644
--- a/tests/hwsim/auth_serv/user2.pkcs12
+++ b/tests/hwsim/auth_serv/user2.pkcs12
Binary files differ
diff --git a/tests/hwsim/auth_serv/user3.pkcs12 b/tests/hwsim/auth_serv/user3.pkcs12
index 3100ca9..e40af9d 100644
--- a/tests/hwsim/auth_serv/user3.pkcs12
+++ b/tests/hwsim/auth_serv/user3.pkcs12
Binary files differ
diff --git a/tests/hwsim/start.sh b/tests/hwsim/start.sh
index a8e4da0..de2b5f0 100755
--- a/tests/hwsim/start.sh
+++ b/tests/hwsim/start.sh
@@ -181,7 +181,7 @@ for i in unknown revoked; do
done
openssl ocsp -reqout $LOGDIR/ocsp-req.der -issuer $DIR/auth_serv/ca.pem \
- -sha256 -serial 0xD8D3E3A6CBE3CD17 -no_nonce >> $LOGDIR/ocsp.log 2>&1
+ -sha256 -serial 0xD8D3E3A6CBE3CD1F -no_nonce >> $LOGDIR/ocsp.log 2>&1
for i in "" "-unknown" "-revoked"; do
openssl ocsp -index $DIR/auth_serv/index$i.txt \
-rsigner $DIR/auth_serv/ca.pem \
diff --git a/tests/hwsim/test_ap_eap.py b/tests/hwsim/test_ap_eap.py
index 04143c4..c6e724a 100644
--- a/tests/hwsim/test_ap_eap.py
+++ b/tests/hwsim/test_ap_eap.py
@@ -2726,7 +2726,7 @@ def test_ap_wpa2_eap_ttls_server_cert_hash(dev, apdev):
"""WPA2-Enterprise connection using EAP-TTLS and server certificate hash"""
check_cert_probe_support(dev[0])
skip_with_fips(dev[0])
- srv_cert_hash = "4704e62784f36cc5fd964c6410402f4938773bb471dce9d42939bf22fdbdb2dd"
+ srv_cert_hash = "f6b9d0b2bc3f106ff01542161647036992de889267005d93fac1c7274bfca5bb"
params = hostapd.wpa2_eap_params(ssid="test-wpa2-eap")
hapd = hostapd.add_ap(apdev[0], params)
dev[0].connect("test-wpa2-eap", key_mgmt="WPA-EAP", eap="TTLS",
diff --git a/tests/hwsim/test_ap_ft.py b/tests/hwsim/test_ap_ft.py
index 1556158..66ca8cf 100644
--- a/tests/hwsim/test_ap_ft.py
+++ b/tests/hwsim/test_ap_ft.py
@@ -955,7 +955,7 @@ def test_ap_ft_over_ds_pull_vlan(dev, apdev):
run_roams(dev[0], apdev, hapd0, hapd1, ssid, passphrase, over_ds=True,
conndev="brvlan1")
-def start_ft_sae(dev, apdev, wpa_ptk_rekey=None):
+def start_ft_sae(dev, apdev, wpa_ptk_rekey=None, sae_pwe=None):
if "SAE" not in dev.get_capability("auth_alg"):
raise HwsimSkip("SAE not supported")
ssid = "test-ft"
@@ -965,11 +965,15 @@ def start_ft_sae(dev, apdev, wpa_ptk_rekey=None):
params['wpa_key_mgmt'] = "FT-SAE"
if wpa_ptk_rekey:
params['wpa_ptk_rekey'] = str(wpa_ptk_rekey)
+ if sae_pwe is not None:
+ params['sae_pwe'] = sae_pwe
hapd0 = hostapd.add_ap(apdev[0], params)
params = ft_params2(ssid=ssid, passphrase=passphrase)
params['wpa_key_mgmt'] = "FT-SAE"
if wpa_ptk_rekey:
params['wpa_ptk_rekey'] = str(wpa_ptk_rekey)
+ if sae_pwe is not None:
+ params['sae_pwe'] = sae_pwe
hapd1 = hostapd.add_ap(apdev[1], params)
key_mgmt = hapd1.get_config()['key_mgmt']
if key_mgmt.split(' ')[0] != "FT-SAE":
@@ -983,6 +987,15 @@ def test_ap_ft_sae(dev, apdev):
hapd0, hapd1 = start_ft_sae(dev[0], apdev)
run_roams(dev[0], apdev, hapd0, hapd1, "test-ft", "12345678", sae=True)
+def test_ap_ft_sae_h2e(dev, apdev):
+ """WPA2-PSK-FT-SAE AP (H2E)"""
+ try:
+ dev[0].set("sae_pwe", "2")
+ hapd0, hapd1 = start_ft_sae(dev[0], apdev, sae_pwe="2")
+ run_roams(dev[0], apdev, hapd0, hapd1, "test-ft", "12345678", sae=True)
+ finally:
+ dev[0].set("sae_pwe", "0")
+
def test_ap_ft_sae_ptk_rekey0(dev, apdev):
"""WPA2-PSK-FT-SAE AP and PTK rekey triggered by station"""
hapd0, hapd1 = start_ft_sae(dev[0], apdev)
@@ -1858,7 +1871,7 @@ def test_ap_ft_ap_oom4(dev, apdev):
if dev[0].get_status_field('bssid') != bssid1:
raise Exception("Did not roam to AP1")
- with fail_test(hapd0, 1, "wpa_auth_get_seqnum;wpa_ft_gtk_subelem"):
+ with fail_test(hapd0, 1, "i802_get_seqnum;wpa_ft_gtk_subelem"):
dev[0].roam(bssid0)
if dev[0].get_status_field('bssid') != bssid0:
raise Exception("Did not roam to AP0")
diff --git a/tests/hwsim/test_ap_pmf.py b/tests/hwsim/test_ap_pmf.py
index 59bbb13..be9b5d2 100644
--- a/tests/hwsim/test_ap_pmf.py
+++ b/tests/hwsim/test_ap_pmf.py
@@ -247,6 +247,87 @@ def test_ap_pmf_assoc_comeback2(dev, apdev):
dev[0].p2p_interface_addr()) < 1:
raise Exception("AP did not use reassociation comeback request")
+def test_ap_pmf_ap_dropping_sa(dev, apdev):
+ """WPA2-PSK PMF AP dropping SA"""
+ ssid = "pmf"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+ params["ieee80211w"] = "2"
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+ Wlantest.setup(hapd)
+ wt = Wlantest()
+ wt.flush()
+ wt.add_passphrase("12345678")
+ dev[0].connect(ssid, psk="12345678", ieee80211w="2",
+ key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
+ addr0 = dev[0].own_addr()
+ dev[0].dump_monitor()
+ hapd.wait_sta()
+ # Drop SA and association at the AP locally without notifying the STA. This
+ # results in the STA getting unprotected Deauthentication frames when trying
+ # to transmit the next Class 3 frame.
+ if "OK" not in hapd.request("DEAUTHENTICATE " + addr0 + " tx=0"):
+ raise Exception("DEAUTHENTICATE command failed")
+ ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=1)
+ if ev is not None:
+ raise Exception("Unexpected disconnection event after DEAUTHENTICATE tx=0: " + ev)
+ dev[0].request("DATA_TEST_CONFIG 1")
+ dev[0].request("DATA_TEST_TX " + bssid + " " + addr0)
+ ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
+ dev[0].request("DATA_TEST_CONFIG 0")
+ if ev is None or "locally_generated=1" not in ev:
+ raise Exception("Locally generated disconnection not reported")
+
+def test_ap_pmf_valid_broadcast_deauth(dev, apdev):
+ """WPA2-PSK PMF AP sending valid broadcast deauth without dropping SA"""
+ run_ap_pmf_valid(dev, apdev, False, True)
+
+def test_ap_pmf_valid_broadcast_disassoc(dev, apdev):
+ """WPA2-PSK PMF AP sending valid broadcast disassoc without dropping SA"""
+ run_ap_pmf_valid(dev, apdev, True, True)
+
+def test_ap_pmf_valid_unicast_deauth(dev, apdev):
+ """WPA2-PSK PMF AP sending valid unicast deauth without dropping SA"""
+ run_ap_pmf_valid(dev, apdev, False, False)
+
+def test_ap_pmf_valid_unicast_disassoc(dev, apdev):
+ """WPA2-PSK PMF AP sending valid unicast disassoc without dropping SA"""
+ run_ap_pmf_valid(dev, apdev, True, False)
+
+def run_ap_pmf_valid(dev, apdev, disassociate, broadcast):
+ ssid = "pmf"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params["wpa_key_mgmt"] = "WPA-PSK-SHA256"
+ params["ieee80211w"] = "2"
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = hapd.own_addr()
+ Wlantest.setup(hapd)
+ wt = Wlantest()
+ wt.flush()
+ wt.add_passphrase("12345678")
+ dev[0].connect(ssid, psk="12345678", ieee80211w="2",
+ key_mgmt="WPA-PSK-SHA256", proto="WPA2", scan_freq="2412")
+ addr0 = dev[0].own_addr()
+ dev[0].dump_monitor()
+ hapd.wait_sta()
+ cmd = "DISASSOCIATE " if disassociate else "DEAUTHENTICATE "
+ cmd += "ff:ff:ff:ff:ff:ff" if broadcast else addr0
+ cmd += " test=1"
+ if "OK" not in hapd.request(cmd):
+ raise Exception("hostapd command failed")
+ sta = hapd.get_sta(addr0)
+ if not sta:
+ raise Exception("STA entry lost")
+ ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
+ if ev is None:
+ raise Exception("Disconnection not reported")
+ if "locally_generated=1" in ev:
+ raise Exception("Unexpected locally generated disconnection")
+
+ # Wait for SA Query procedure to fail and association comeback to succeed
+ dev[0].wait_connected()
+
def start_wpas_ap(ssid):
wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
wpas.interface_add("wlan5", drv_params="use_monitor=1")
diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py
index 33a6b76..41661b8 100644
--- a/tests/hwsim/test_dbus.py
+++ b/tests/hwsim/test_dbus.py
@@ -1153,6 +1153,85 @@ def test_dbus_scan(dev, apdev):
raise Exception("FlushBSS() did not remove scan results from BSSs property")
iface.FlushBSS(1)
+def test_dbus_scan_rand(dev, apdev):
+ """D-Bus MACAddressRandomizationMask property Get/Set"""
+ try:
+ run_dbus_scan_rand(dev, apdev)
+ finally:
+ dev[0].request("MAC_RAND_SCAN all enable=0")
+
+def run_dbus_scan_rand(dev, apdev):
+ (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+ iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+ res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ if len(res) != 0:
+ logger.info(str(res))
+ raise Exception("Unexpected initial MACAddressRandomizationMask value")
+
+ try:
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask", "foo",
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ raise Exception("Invalid Set accepted")
+ except dbus.exceptions.DBusException as e:
+ if "InvalidArgs: invalid message format" not in str(e):
+ raise Exception("Unexpected error message: " + str(e))
+
+ try:
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ {"foo": "bar"},
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ raise Exception("Invalid Set accepted")
+ except dbus.exceptions.DBusException as e:
+ if "wpas_dbus_setter_mac_address_randomization_mask: mask was not a byte array" not in str(e):
+ raise Exception("Unexpected error message: " + str(e))
+
+ try:
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ {"foo": dbus.ByteArray(b'123456')},
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ raise Exception("Invalid Set accepted")
+ except dbus.exceptions.DBusException as e:
+ if 'wpas_dbus_setter_mac_address_randomization_mask: bad scan type "foo"' not in str(e):
+ raise Exception("Unexpected error message: " + str(e))
+
+ try:
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ {"scan": dbus.ByteArray(b'12345')},
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ raise Exception("Invalid Set accepted")
+ except dbus.exceptions.DBusException as e:
+ if 'wpas_dbus_setter_mac_address_randomization_mask: malformed MAC mask given' not in str(e):
+ raise Exception("Unexpected error message: " + str(e))
+
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ {"scan": dbus.ByteArray(b'123456')},
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ if len(res) != 1:
+ logger.info(str(res))
+ raise Exception("Unexpected MACAddressRandomizationMask value")
+
+ try:
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ {"scan": dbus.ByteArray(b'123456'),
+ "sched_scan": dbus.ByteArray(b'987654')},
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ except dbus.exceptions.DBusException as e:
+ # sched_scan is unlikely to be supported
+ pass
+
+ if_obj.Set(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ dbus.Dictionary({}, signature='sv'),
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ res = if_obj.Get(WPAS_DBUS_IFACE, "MACAddressRandomizationMask",
+ dbus_interface=dbus.PROPERTIES_IFACE)
+ if len(res) != 0:
+ logger.info(str(res))
+ raise Exception("Unexpected MACAddressRandomizationMask value")
+
def test_dbus_scan_busy(dev, apdev):
"""D-Bus scan trigger rejection when busy with previous scan"""
(bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
diff --git a/tests/hwsim/test_dpp.py b/tests/hwsim/test_dpp.py
index 123d57a..12156cd 100644
--- a/tests/hwsim/test_dpp.py
+++ b/tests/hwsim/test_dpp.py
@@ -4799,3 +4799,40 @@ def test_dpp_mud_url_hostapd(dev, apdev):
dev[0].dpp_auth_init(uri=uri, conf="ap-dpp", configurator=conf_id)
wait_auth_success(hapd, dev[0], configurator=dev[0], enrollee=hapd)
update_hapd_config(hapd)
+
+def test_dpp_config_save(dev, apdev, params):
+ """DPP configuration saving"""
+ config = os.path.join(params['logdir'], 'dpp_config_save.conf')
+ run_dpp_config_save(dev, apdev, config, "test", '"test"')
+
+def test_dpp_config_save2(dev, apdev, params):
+ """DPP configuration saving (2)"""
+ config = os.path.join(params['logdir'], 'dpp_config_save2.conf')
+ run_dpp_config_save(dev, apdev, config, "\\u0001*", '012a')
+
+def test_dpp_config_save3(dev, apdev, params):
+ """DPP configuration saving (3)"""
+ config = os.path.join(params['logdir'], 'dpp_config_save3.conf')
+ run_dpp_config_save(dev, apdev, config, "\\u0001*\\u00c2\\u00bc\\u00c3\\u009e\\u00c3\\u00bf", '012ac2bcc39ec3bf')
+
+def run_dpp_config_save(dev, apdev, config, conf_ssid, exp_ssid):
+ with open(config, "w") as f:
+ f.write("update_config=1\n" +
+ "dpp_config_processing=1\n")
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add("wlan5", config=config)
+ check_dpp_capab(wpas)
+ conf = '{"wi-fi_tech":"infra", "discovery":{"ssid":"' + conf_ssid + '"},"cred":{"akm":"psk","pass":"secret passphrase"}}'
+ dev[1].set("dpp_config_obj_override", conf)
+ dpp_dev = [wpas, dev[1]]
+ run_dpp_qr_code_auth_unicast(dpp_dev, apdev, "prime256v1",
+ require_conf_success=True)
+ if "OK" not in wpas.request("SAVE_CONFIG"):
+ raise Exception("Failed to save configuration file")
+ with open(config, "r") as f:
+ data = f.read()
+ logger.info("Saved configuration:\n" + data)
+ if 'ssid=' + exp_ssid + '\n' not in data:
+ raise Exception("SSID not saved")
+ if 'psk="secret passphrase"' not in data:
+ raise Exception("Passphtase not saved")
diff --git a/tests/hwsim/test_he.py b/tests/hwsim/test_he.py
index d6087c3..f042d71 100644
--- a/tests/hwsim/test_he.py
+++ b/tests/hwsim/test_he.py
@@ -4,7 +4,18 @@
# This software may be distributed under the terms of the BSD license.
# See README for more details.
+import logging
+logger = logging.getLogger()
+import os
+import subprocess, time
+
+import hwsim_utils
import hostapd
+from wpasupplicant import WpaSupplicant
+from utils import *
+from test_dfs import wait_dfs_event
+from test_ap_csa import csa_supported
+from test_ap_ht import clear_scan_cache
def test_he_open(dev, apdev):
"""HE AP with open mode configuration"""
@@ -65,3 +76,1000 @@ def test_he_params(dev, apdev):
if hapd.get_status_field("ieee80211ax") != "1":
raise Exception("STATUS did not indicate ieee80211ac=1")
dev[0].connect("he", key_mgmt="NONE", scan_freq="2412")
+
+def he_supported():
+ cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+ reg = cmd.stdout.read()
+ if "@ 80)" in reg or "@ 160)" in reg:
+ return True
+ return False
+
+def test_he80(dev, apdev):
+ """HE with 80 MHz channel width"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_capab": "[MAX-MPDU-11454]",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sig = dev[0].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=5180" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=80 MHz" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ est = dev[0].get_bss(bssid)['est_throughput']
+ if est != "390001":
+ raise Exception("Unexpected BSS est_throughput: " + est)
+ status = dev[0].get_status()
+ if status["ieee80211ac"] != "1":
+ raise Exception("Unexpected STATUS ieee80211ac value (STA)")
+ status = hapd.get_status()
+ logger.info("hostapd STATUS: " + str(status))
+ if status["ieee80211n"] != "1":
+ raise Exception("Unexpected STATUS ieee80211n value")
+ if status["ieee80211ac"] != "1":
+ raise Exception("Unexpected STATUS ieee80211ac value")
+ if status["ieee80211ax"] != "1":
+ raise Exception("Unexpected STATUS ieee80211ax value")
+ if status["secondary_channel"] != "1":
+ raise Exception("Unexpected STATUS secondary_channel value")
+ if status["vht_oper_chwidth"] != "1":
+ raise Exception("Unexpected STATUS vht_oper_chwidth value")
+ if status["vht_oper_centr_freq_seg0_idx"] != "42":
+ raise Exception("Unexpected STATUS vht_oper_centr_freq_seg0_idx value")
+ if "vht_caps_info" not in status:
+ raise Exception("Missing vht_caps_info")
+ if status["he_oper_chwidth"] != "1":
+ raise Exception("Unexpected STATUS he_oper_chwidth value")
+ if status["he_oper_centr_freq_seg0_idx"] != "42":
+ raise Exception("Unexpected STATUS he_oper_centr_freq_seg0_idx value")
+
+ sta = hapd.get_sta(dev[0].own_addr())
+ logger.info("hostapd STA: " + str(sta))
+ if "[HT]" not in sta['flags']:
+ raise Exception("Missing STA flag: HT")
+ if "[VHT]" not in sta['flags']:
+ raise Exception("Missing STA flag: VHT")
+ if "[HE]" not in sta['flags']:
+ raise Exception("Missing STA flag: HE")
+
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ clear_regdom(hapd, dev)
+
+def test_he_wifi_generation(dev, apdev):
+ """HE and wifi_generation"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_capab": "[MAX-MPDU-11454]",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ status = dev[0].get_status()
+ if 'wifi_generation' not in status:
+ # For now, assume this is because of missing kernel support
+ raise HwsimSkip("Association Request IE reporting not supported")
+ #raise Exception("Missing wifi_generation information")
+ if status['wifi_generation'] != "6":
+ raise Exception("Unexpected wifi_generation value: " + status['wifi_generation'])
+
+ wpas = WpaSupplicant(global_iface='/tmp/wpas-wlan5')
+ wpas.interface_add("wlan5", drv_params="force_connect_cmd=1")
+ wpas.connect("he", key_mgmt="NONE", scan_freq="5180")
+ status = wpas.get_status()
+ if 'wifi_generation' not in status:
+ # For now, assume this is because of missing kernel support
+ raise HwsimSkip("Association Request IE reporting not supported")
+ #raise Exception("Missing wifi_generation information (connect)")
+ if status['wifi_generation'] != "6":
+ raise Exception("Unexpected wifi_generation value (connect): " + status['wifi_generation'])
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ clear_regdom(hapd, dev)
+
+def he80_test(apdev, dev, channel, ht_capab):
+ clear_scan_cache(apdev)
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": str(channel),
+ "ht_capab": ht_capab,
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev, params)
+ bssid = apdev['bssid']
+
+ dev[0].connect("he", key_mgmt="NONE",
+ scan_freq=str(5000 + 5 * channel))
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he80b(dev, apdev):
+ """HE with 80 MHz channel width (HT40- channel 40)"""
+ he80_test(apdev[0], dev, 40, "[HT40-]")
+
+def test_he80c(dev, apdev):
+ """HE with 80 MHz channel width (HT40+ channel 44)"""
+ he80_test(apdev[0], dev, 44, "[HT40+]")
+
+def test_he80d(dev, apdev):
+ """HE with 80 MHz channel width (HT40- channel 48)"""
+ he80_test(apdev[0], dev, 48, "[HT40-]")
+
+def test_he80_params(dev, apdev):
+ """HE with 80 MHz channel width and number of optional features enabled"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+][SHORT-GI-40][DSS_CCK-40]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_capab": "[MAX-MPDU-11454][RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP0]",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "require_vht": "1",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "he_su_beamformer": "1",
+ "he_mu_beamformer": "1",
+ "he_bss_color":"1",
+ "he_default_pe_duration":"1",
+ "he_twt_required":"1",
+ "he_rts_threshold":"1"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[1].connect("he", key_mgmt="NONE", scan_freq="5180",
+ disable_vht="1", wait_connect=False)
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ dev[2].connect("he", key_mgmt="NONE", scan_freq="5180",
+ disable_sgi="1")
+ ev = dev[1].wait_event(["CTRL-EVENT-ASSOC-REJECT"])
+ if ev is None:
+ raise Exception("Association rejection timed out")
+ if "status_code=104" not in ev:
+ raise Exception("Unexpected rejection status code")
+ dev[1].request("DISCONNECT")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sta0 = hapd.get_sta(dev[0].own_addr())
+ sta2 = hapd.get_sta(dev[2].own_addr())
+ capab0 = int(sta0['vht_caps_info'], base=16)
+ capab2 = int(sta2['vht_caps_info'], base=16)
+ if capab0 & 0x60 == 0:
+ raise Exception("dev[0] did not support SGI")
+ if capab2 & 0x60 != 0:
+ raise Exception("dev[2] claimed support for SGI")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev, count=3)
+
+def test_he80_invalid(dev, apdev):
+ """HE with invalid 80 MHz channel configuration (seg1)"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "vht_oper_centr_freq_seg1_idx": "159",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "he_oper_centr_freq_seg1_idx": "155",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ # This fails due to unexpected seg1 configuration
+ ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+ if ev is None:
+ raise Exception("AP-DISABLED not reported")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he80_invalid2(dev, apdev):
+ """HE with invalid 80 MHz channel configuration (seg0)"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "46",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ # This fails due to invalid seg0 configuration
+ ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+ if ev is None:
+ raise Exception("AP-DISABLED not reported")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he_20(devs, apdevs):
+ """HE and 20 MHz channel"""
+ dev = devs[0]
+ ap = apdevs[0]
+ try:
+ hapd = None
+ params = {"ssid": "test-he20",
+ "country_code": "DE",
+ "hw_mode": "a",
+ "channel": "36",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "ht_capab": "",
+ "vht_capab": "",
+ "vht_oper_chwidth": "0",
+ "vht_oper_centr_freq_seg0_idx": "0",
+ "supported_rates": "60 120 240 360 480 540",
+ "require_vht": "1",
+ "he_oper_chwidth": "0",
+ "he_oper_centr_freq_seg0_idx": "0"}
+ hapd = hostapd.add_ap(ap, params)
+ dev.connect("test-he20", scan_freq="5180", key_mgmt="NONE")
+ hwsim_utils.test_connectivity(dev, hapd)
+ finally:
+ dev.request("DISCONNECT")
+ clear_regdom(hapd, devs)
+
+def test_he_40(devs, apdevs):
+ """HE and 40 MHz channel"""
+ dev = devs[0]
+ ap = apdevs[0]
+ try:
+ hapd = None
+ params = {"ssid": "test-he40",
+ "country_code": "DE",
+ "hw_mode": "a",
+ "channel": "36",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "ht_capab": "[HT40+]",
+ "vht_capab": "",
+ "vht_oper_chwidth": "0",
+ "vht_oper_centr_freq_seg0_idx": "38",
+ "he_oper_chwidth": "0",
+ "he_oper_centr_freq_seg0_idx": "38",
+ "he_su_beamformer": "1",
+ "he_mu_beamformer": "1"}
+ hapd = hostapd.add_ap(ap, params)
+ dev.connect("test-he40", scan_freq="5180", key_mgmt="NONE")
+ hwsim_utils.test_connectivity(dev, hapd)
+ finally:
+ dev.request("DISCONNECT")
+ clear_regdom(hapd, devs)
+
+def test_he160(dev, apdev, params):
+ """HE with 160 MHz channel width (1) [long]"""
+ if not params['long']:
+ raise HwsimSkip("Skip test case with long duration due to --long not specified")
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "2",
+ "vht_oper_centr_freq_seg0_idx": "50",
+ "he_oper_chwidth": "2",
+ "he_oper_centr_freq_seg0_idx": "50",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+
+ ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
+ if "DFS-CAC-START" not in ev:
+ raise Exception("Unexpected DFS event")
+
+ state = hapd.get_status_field("state")
+ if state != "DFS":
+ if state == "DISABLED" and not os.path.exists("dfs"):
+ # Not all systems have recent enough CRDA version and
+ # wireless-regdb changes to support 160 MHz and DFS. For now,
+ # do not report failures for this test case.
+ raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
+ raise Exception("Unexpected interface state: " + state)
+
+ logger.info("Waiting for CAC to complete")
+
+ ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
+ if "success=1" not in ev:
+ raise Exception("CAC failed")
+ if "freq=5180" not in ev:
+ raise Exception("Unexpected DFS freq result")
+
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
+ if not ev:
+ raise Exception("AP setup timed out")
+
+ state = hapd.get_status_field("state")
+ if state != "ENABLED":
+ raise Exception("Unexpected interface state")
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ dev[0].wait_regdom(country_ie=True)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sig = dev[0].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=5180" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=160 MHz" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ if hapd:
+ hapd.request("DISABLE")
+ dev[0].disconnect_and_stop_scan()
+ subprocess.call(['iw', 'reg', 'set', '00'])
+ dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
+ dev[0].flush_scan_cache()
+
+def test_he160b(dev, apdev, params):
+ """HE with 160 MHz channel width (2) [long]"""
+ if not params['long']:
+ raise HwsimSkip("Skip test case with long duration due to --long not specified")
+ try:
+ hapd = None
+
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "104",
+ "ht_capab": "[HT40-]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "2",
+ "vht_oper_centr_freq_seg0_idx": "114",
+ "he_oper_chwidth": "2",
+ "he_oper_centr_freq_seg0_idx": "114",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[1], params, wait_enabled=False)
+
+ ev = wait_dfs_event(hapd, "DFS-CAC-START", 5)
+ if "DFS-CAC-START" not in ev:
+ raise Exception("Unexpected DFS event(2)")
+
+ state = hapd.get_status_field("state")
+ if state != "DFS":
+ if state == "DISABLED" and not os.path.exists("dfs"):
+ # Not all systems have recent enough CRDA version and
+ # wireless-regdb changes to support 160 MHz and DFS. For now,
+ # do not report failures for this test case.
+ raise HwsimSkip("CRDA or wireless-regdb did not support 160 MHz")
+ raise Exception("Unexpected interface state: " + state)
+
+ logger.info("Waiting for CAC to complete")
+
+ ev = wait_dfs_event(hapd, "DFS-CAC-COMPLETED", 70)
+ if "success=1" not in ev:
+ raise Exception("CAC failed(2)")
+ if "freq=5520" not in ev:
+ raise Exception("Unexpected DFS freq result(2)")
+
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=5)
+ if not ev:
+ raise Exception("AP setup timed out(2)")
+
+ state = hapd.get_status_field("state")
+ if state != "ENABLED":
+ raise Exception("Unexpected interface state(2)")
+
+ freq = hapd.get_status_field("freq")
+ if freq != "5520":
+ raise Exception("Unexpected frequency(2)")
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5520")
+ dev[0].wait_regdom(country_ie=True)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sig = dev[0].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=5520" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=160 MHz" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ if hapd:
+ hapd.request("DISABLE")
+ dev[0].disconnect_and_stop_scan()
+ subprocess.call(['iw', 'reg', 'set', '00'])
+ dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
+ dev[0].flush_scan_cache()
+
+def test_he160_no_dfs_100_plus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (100 plus)"""
+ run_ap_he160_no_dfs(dev, apdev, "100", "[HT40+]")
+
+def test_he160_no_dfs(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (104 minus)"""
+ run_ap_he160_no_dfs(dev, apdev, "104", "[HT40-]")
+
+def test_he160_no_dfs_108_plus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (108 plus)"""
+ run_ap_he160_no_dfs(dev, apdev, "108", "[HT40+]")
+
+def test_he160_no_dfs_112_minus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (112 minus)"""
+ run_ap_he160_no_dfs(dev, apdev, "112", "[HT40-]")
+
+def test_he160_no_dfs_116_plus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (116 plus)"""
+ run_ap_he160_no_dfs(dev, apdev, "116", "[HT40+]")
+
+def test_he160_no_dfs_120_minus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (120 minus)"""
+ run_ap_he160_no_dfs(dev, apdev, "120", "[HT40-]")
+
+def test_he160_no_dfs_124_plus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (124 plus)"""
+ run_ap_he160_no_dfs(dev, apdev, "124", "[HT40+]")
+
+def test_he160_no_dfs_128_minus(dev, apdev):
+ """HE with 160 MHz channel width and no DFS (128 minus)"""
+ run_ap_he160_no_dfs(dev, apdev, "128", "[HT40-]")
+
+def run_ap_he160_no_dfs(dev, apdev, channel, ht_capab):
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "ZA",
+ "hw_mode": "a",
+ "channel": channel,
+ "ht_capab": ht_capab,
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "2",
+ "vht_oper_centr_freq_seg0_idx": "114",
+ "he_oper_chwidth": "2",
+ "he_oper_centr_freq_seg0_idx": "114",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ ev = hapd.wait_event(["AP-ENABLED"], timeout=2)
+ if not ev:
+ cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+ reg = cmd.stdout.readlines()
+ for r in reg:
+ if "5490" in r and "DFS" in r:
+ raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
+ raise Exception("AP setup timed out")
+
+ freq = str(int(channel) * 5 + 5000)
+ dev[0].connect("he", key_mgmt="NONE", scan_freq=freq)
+ dev[0].wait_regdom(country_ie=True)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sig = dev[0].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=" + freq not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=160 MHz" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he160_no_ht40(dev, apdev):
+ """HE with 160 MHz channel width and HT40 disabled"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "ZA",
+ "hw_mode": "a",
+ "channel": "108",
+ "ht_capab": "",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "2",
+ "vht_oper_centr_freq_seg0_idx": "114",
+ "he_oper_chwidth": "2",
+ "he_oper_centr_freq_seg0_idx": "114",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ ev = hapd.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=2)
+ if not ev:
+ cmd = subprocess.Popen(["iw", "reg", "get"], stdout=subprocess.PIPE)
+ reg = cmd.stdout.readlines()
+ for r in reg:
+ if "5490" in r and "DFS" in r:
+ raise HwsimSkip("ZA regulatory rule did not have DFS requirement removed")
+ raise Exception("AP setup timed out")
+ if "AP-ENABLED" in ev:
+ # This was supposed to fail due to sec_channel_offset == 0
+ raise Exception("Unexpected AP-ENABLED")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he80plus80(dev, apdev):
+ """HE with 80+80 MHz channel width"""
+ try:
+ hapd = None
+ hapd2 = None
+ params = {"ssid": "he",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "52",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "3",
+ "vht_oper_centr_freq_seg0_idx": "58",
+ "vht_oper_centr_freq_seg1_idx": "155",
+ "he_oper_chwidth": "3",
+ "he_oper_centr_freq_seg0_idx": "58",
+ "he_oper_centr_freq_seg1_idx": "155",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ # This will actually fail since DFS on 80+80 is not yet supported
+ ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+ # ignore result to avoid breaking the test once 80+80 DFS gets enabled
+
+ params = {"ssid": "he2",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "3",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "vht_oper_centr_freq_seg1_idx": "155",
+ "he_oper_chwidth": "3",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "he_oper_centr_freq_seg1_idx": "155"}
+ hapd2 = hostapd.add_ap(apdev[1], params, wait_enabled=False)
+
+ ev = hapd2.wait_event(["AP-ENABLED", "AP-DISABLED"], timeout=5)
+ if not ev:
+ raise Exception("AP setup timed out(2)")
+ if "AP-DISABLED" in ev:
+ # Assume this failed due to missing regulatory update for now
+ raise HwsimSkip("80+80 MHz channel not supported in regulatory information")
+
+ state = hapd2.get_status_field("state")
+ if state != "ENABLED":
+ raise Exception("Unexpected interface state(2)")
+
+ dev[1].connect("he2", key_mgmt="NONE", scan_freq="5180")
+ hwsim_utils.test_connectivity(dev[1], hapd2)
+ sig = dev[1].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=5180" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=80+80 MHz" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ if "CENTER_FRQ1=5210" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(3): " + str(sig))
+ if "CENTER_FRQ2=5775" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(4): " + str(sig))
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ dev[1].request("DISCONNECT")
+ if hapd:
+ hapd.request("DISABLE")
+ if hapd2:
+ hapd2.request("DISABLE")
+ subprocess.call(['iw', 'reg', 'set', '00'])
+ dev[0].flush_scan_cache()
+ dev[1].flush_scan_cache()
+
+def test_he80plus80_invalid(dev, apdev):
+ """HE with invalid 80+80 MHz channel"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "3",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "vht_oper_centr_freq_seg1_idx": "0",
+ "he_oper_chwidth": "3",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "he_oper_centr_freq_seg1_idx": "0",
+ 'ieee80211d': '1',
+ 'ieee80211h': '1'}
+ hapd = hostapd.add_ap(apdev[0], params, wait_enabled=False)
+ # This fails due to missing(invalid) seg1 configuration
+ ev = hapd.wait_event(["AP-DISABLED"], timeout=5)
+ if ev is None:
+ raise Exception("AP-DISABLED not reported")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80/160 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he80_csa(dev, apdev):
+ """HE with 80 MHz channel width and CSA"""
+ csa_supported(dev[0])
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "US",
+ "hw_mode": "a",
+ "channel": "149",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "155",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "155"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5745")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ hapd.request("CHAN_SWITCH 5 5180 ht vht he blocktx center_freq1=5210 sec_channel_offset=1 bandwidth=80")
+ ev = hapd.wait_event(["CTRL-EVENT-STARTED-CHANNEL-SWITCH"], timeout=10)
+ if ev is None:
+ raise Exception("Channel switch start event not seen")
+ if "freq=5180" not in ev:
+ raise Exception("Unexpected channel in CS started")
+ ev = hapd.wait_event(["CTRL-EVENT-CHANNEL-SWITCH"], timeout=10)
+ if ev is None:
+ raise Exception("Channel switch completion event not seen")
+ if "freq=5180" not in ev:
+ raise Exception("Unexpected channel in CS completed")
+ ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
+ if ev is None:
+ raise Exception("CSA finished event timed out")
+ if "freq=5180" not in ev:
+ raise Exception("Unexpected channel in CSA finished event")
+ time.sleep(0.5)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ hapd.request("CHAN_SWITCH 5 5745")
+ ev = hapd.wait_event(["AP-CSA-FINISHED"], timeout=10)
+ if ev is None:
+ raise Exception("CSA finished event timed out")
+ if "freq=5745" not in ev:
+ raise Exception("Unexpected channel in CSA finished event")
+ time.sleep(0.5)
+ hwsim_utils.test_connectivity(dev[0], hapd)
+
+ # This CSA to same channel will fail in kernel, so use this only for
+ # extra code coverage.
+ hapd.request("CHAN_SWITCH 5 5745")
+ hapd.wait_event(["AP-CSA-FINISHED"], timeout=1)
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ clear_regdom(hapd, dev)
+
+def test_he_on_24ghz(dev, apdev):
+ """Subset of HE features on 2.4 GHz"""
+ hapd = None
+ params = {"ssid": "test-he-2g",
+ "hw_mode": "g",
+ "channel": "1",
+ "ieee80211n": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "0",
+ "vht_oper_centr_freq_seg0_idx": "1",
+ "he_oper_chwidth": "0",
+ "he_oper_centr_freq_seg0_idx": "1"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ try:
+ dev[0].connect("test-he-2g", scan_freq="2412", key_mgmt="NONE")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sta = hapd.get_sta(dev[0].own_addr())
+
+ dev[1].connect("test-he-2g", scan_freq="2412", key_mgmt="NONE")
+ sta = hapd.get_sta(dev[1].own_addr())
+
+ finally:
+ dev[0].request("DISCONNECT")
+ dev[1].request("DISCONNECT")
+ if hapd:
+ hapd.request("DISABLE")
+ subprocess.call(['iw', 'reg', 'set', '00'])
+ dev[0].flush_scan_cache()
+ dev[1].flush_scan_cache()
+
+def test_he80_pwr_constraint(dev, apdev):
+ """HE with 80 MHz channel width and local power constraint"""
+ hapd = None
+ try:
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211d": "1",
+ "local_pwr_constraint": "3",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ dev[0].wait_regdom(country_ie=True)
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ if hapd:
+ hapd.request("DISABLE")
+ dev[0].disconnect_and_stop_scan()
+ subprocess.call(['iw', 'reg', 'set', '00'])
+ dev[0].wait_event(["CTRL-EVENT-REGDOM-CHANGE"], timeout=0.5)
+ dev[0].flush_scan_cache()
+
+def test_he_use_sta_nsts(dev, apdev):
+ """HE with 80 MHz channel width and use_sta_nsts=1"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42",
+ "use_sta_nsts": "1"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="5180")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ clear_regdom(hapd, dev)
+
+def test_he_tkip(dev, apdev):
+ """HE and TKIP"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "wpa": "1",
+ "wpa_key_mgmt": "WPA-PSK",
+ "wpa_pairwise": "TKIP",
+ "wpa_passphrase": "12345678",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].connect("he", psk="12345678", scan_freq="5180")
+ hwsim_utils.test_connectivity(dev[0], hapd)
+ sig = dev[0].request("SIGNAL_POLL").splitlines()
+ if "FREQUENCY=5180" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(1): " + str(sig))
+ if "WIDTH=20 MHz (no HT)" not in sig:
+ raise Exception("Unexpected SIGNAL_POLL value(2): " + str(sig))
+ status = hapd.get_status()
+ logger.info("hostapd STATUS: " + str(status))
+ if status["ieee80211n"] != "0":
+ raise Exception("Unexpected STATUS ieee80211n value")
+ if status["ieee80211ac"] != "0":
+ raise Exception("Unexpected STATUS ieee80211ac value")
+ if status["ieee80211ax"] != "1":
+ raise Exception("Unexpected STATUS ieee80211ax value")
+ if status["secondary_channel"] != "0":
+ raise Exception("Unexpected STATUS secondary_channel value")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ clear_regdom(hapd, dev)
+
+def test_he_40_fallback_to_20(devs, apdevs):
+ """HE and 40 MHz channel configuration falling back to 20 MHz"""
+ dev = devs[0]
+ ap = apdevs[0]
+ try:
+ hapd = None
+ params = {"ssid": "test-he40",
+ "country_code": "US",
+ "hw_mode": "a",
+ "basic_rates": "60 120 240",
+ "channel": "161",
+ "ieee80211d": "1",
+ "ieee80211h": "1",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "ht_capab": "[HT40+][SHORT-GI-20][SHORT-GI-40][DSSS_CCK-40]",
+ "vht_capab": "[RXLDPC][SHORT-GI-80][TX-STBC-2BY1][RX-STBC1][MAX-MPDU-11454][MAX-A-MPDU-LEN-EXP7]",
+ "vht_oper_chwidth": "0",
+ "vht_oper_centr_freq_seg0_idx": "155",
+ "he_oper_chwidth": "0",
+ "he_oper_centr_freq_seg0_idx": "155"}
+ hapd = hostapd.add_ap(ap, params)
+ dev.connect("test-he40", scan_freq="5805", key_mgmt="NONE")
+ dev.wait_regdom(country_ie=True)
+ hwsim_utils.test_connectivity(dev, hapd)
+ finally:
+ clear_regdom(hapd, devs)
+
+def test_he80_to_24g_he(dev, apdev):
+ """HE with 80 MHz channel width reconfigured to 2.4 GHz HE"""
+ try:
+ hapd = None
+ params = {"ssid": "he",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "ieee80211ax": "1",
+ "vht_oper_chwidth": "1",
+ "vht_capab": "[MAX-MPDU-11454]",
+ "vht_oper_centr_freq_seg0_idx": "42",
+ "he_oper_chwidth": "1",
+ "he_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ hapd.disable()
+ hapd.set("ieee80211ac", "0")
+ hapd.set("hw_mode", "g")
+ hapd.set("channel", "1")
+ hapd.set("ht_capab", "")
+ hapd.set("vht_capab", "")
+ hapd.set("he_oper_chwidth", "")
+ hapd.set("he_oper_centr_freq_seg0_idx", "")
+ hapd.set("vht_oper_chwidth", "")
+ hapd.set("vht_oper_centr_freq_seg0_idx", "")
+ hapd.enable()
+
+ dev[0].connect("he", key_mgmt="NONE", scan_freq="2412")
+ except Exception as e:
+ if isinstance(e, Exception) and str(e) == "AP startup failed":
+ if not he_supported():
+ raise HwsimSkip("80 MHz channel not supported in regulatory information")
+ raise
+ finally:
+ dev[0].request("DISCONNECT")
+ clear_regdom(hapd, dev)
diff --git a/tests/hwsim/test_sae.py b/tests/hwsim/test_sae.py
index 8824ad4..e45287d 100644
--- a/tests/hwsim/test_sae.py
+++ b/tests/hwsim/test_sae.py
@@ -749,6 +749,168 @@ def test_sae_proto_ffc(dev, apdev):
hapd.set("ext_mgmt_frame_handling", "0")
hapd.dump_monitor()
+
+def test_sae_proto_commit_delayed(dev, apdev):
+ """SAE protocol testing - Commit delayed"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].request("SET sae_groups 19")
+
+ dev[0].scan_for_bss(bssid, freq=2412)
+ hapd.set("ext_mgmt_frame_handling", "1")
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412", wait_connect=False)
+
+ logger.info("Commit")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (commit)")
+ if req['subtype'] == 11:
+ break
+ req = None
+ if not req:
+ raise Exception("Authentication frame (commit) not received")
+
+ hapd.dump_monitor()
+ time.sleep(2.5)
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+
+ logger.info("Commit/Confirm")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (confirm)")
+ if req['subtype'] == 11:
+ trans, = struct.unpack('<H', req['payload'][2:4])
+ if trans == 1:
+ logger.info("Extra Commit")
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+ continue
+ break
+ req = None
+ if not req:
+ raise Exception("Authentication frame (confirm) not received")
+
+ hapd.dump_monitor()
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+
+ logger.info("Association Request")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (AssocReq)")
+ if req['subtype'] == 0:
+ break
+ req = None
+ if not req:
+ raise Exception("Association Request frame not received")
+
+ hapd.dump_monitor()
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+ ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
+ if ev is None:
+ raise Exception("Management frame TX status not reported (1)")
+ if "stype=1 ok=1" not in ev:
+ raise Exception("Unexpected management frame TX status (1): " + ev)
+ cmd = "MGMT_TX_STATUS_PROCESS %s" % (" ".join(ev.split(' ')[1:4]))
+ if "OK" not in hapd.request(cmd):
+ raise Exception("MGMT_TX_STATUS_PROCESS failed")
+
+ hapd.set("ext_mgmt_frame_handling", "0")
+
+ dev[0].wait_connected()
+
+def test_sae_proto_commit_replay(dev, apdev):
+ """SAE protocol testing - Commit replay"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ params = hostapd.wpa2_params(ssid="test-sae",
+ passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ hapd = hostapd.add_ap(apdev[0], params)
+ bssid = apdev[0]['bssid']
+
+ dev[0].request("SET sae_groups 19")
+
+ dev[0].scan_for_bss(bssid, freq=2412)
+ hapd.set("ext_mgmt_frame_handling", "1")
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412", wait_connect=False)
+
+ logger.info("Commit")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (commit)")
+ if req['subtype'] == 11:
+ break
+ req = None
+ if not req:
+ raise Exception("Authentication frame (commit) not received")
+
+ hapd.dump_monitor()
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+ logger.info("Replay Commit")
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+
+ logger.info("Confirm")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (confirm)")
+ if req['subtype'] == 11:
+ trans, = struct.unpack('<H', req['payload'][2:4])
+ if trans == 1:
+ logger.info("Extra Commit")
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+ continue
+ break
+ req = None
+ if not req:
+ raise Exception("Authentication frame (confirm) not received")
+
+ hapd.dump_monitor()
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+
+ logger.info("Association Request")
+ for i in range(0, 10):
+ req = hapd.mgmt_rx()
+ if req is None:
+ raise Exception("MGMT RX wait timed out (AssocReq)")
+ if req['subtype'] == 0:
+ break
+ req = None
+ if not req:
+ raise Exception("Association Request frame not received")
+
+ hapd.dump_monitor()
+ hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
+ for i in range(0, 10):
+ ev = hapd.wait_event(["MGMT-TX-STATUS"], timeout=5)
+ if ev is None:
+ raise Exception("Management frame TX status not reported (1)")
+ if "stype=11 ok=1" in ev:
+ continue
+ if "stype=12 ok=1" in ev:
+ continue
+ if "stype=1 ok=1" not in ev:
+ raise Exception("Unexpected management frame TX status (1): " + ev)
+ cmd = "MGMT_TX_STATUS_PROCESS %s" % (" ".join(ev.split(' ')[1:4]))
+ if "OK" not in hapd.request(cmd):
+ raise Exception("MGMT_TX_STATUS_PROCESS failed")
+ break
+
+ hapd.set("ext_mgmt_frame_handling", "0")
+
+ dev[0].wait_connected()
+
def test_sae_proto_confirm_replay(dev, apdev):
"""SAE protocol testing - Confirm replay"""
if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -777,10 +939,6 @@ def test_sae_proto_confirm_replay(dev, apdev):
if not req:
raise Exception("Authentication frame (commit) not received")
- bssid = hapd.own_addr().replace(':', '')
- addr = dev[0].own_addr().replace(':', '')
- hdr = "b0003a01" + bssid + addr + bssid + "1000"
-
hapd.dump_monitor()
hapd.request("MGMT_RX_PROCESS freq=2412 datarate=0 ssi_signal=-30 frame=" + binascii.hexlify(req['frame']).decode())
@@ -1697,3 +1855,210 @@ def test_sae_sync(dev, apdev):
dev[i].select_network(id[i])
for i in range(0, 2):
dev[i].wait_connected(timeout=10)
+
+def test_sae_confirm_immediate(dev, apdev):
+ """SAE and AP sending Confirm message without waiting STA"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ params = hostapd.wpa2_params(ssid="test-sae", passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_confirm_immediate'] = '1'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].request("SET sae_groups ")
+ dev[0].connect("test-sae", psk="12345678", key_mgmt="SAE", scan_freq="2412")
+
+def test_sae_pwe_group_19(dev, apdev):
+ """SAE PWE derivation options with group 19"""
+ run_sae_pwe_group(dev, apdev, 19)
+
+def test_sae_pwe_group_20(dev, apdev):
+ """SAE PWE derivation options with group 20"""
+ run_sae_pwe_group(dev, apdev, 20)
+
+def test_sae_pwe_group_21(dev, apdev):
+ """SAE PWE derivation options with group 21"""
+ run_sae_pwe_group(dev, apdev, 21)
+
+def test_sae_pwe_group_25(dev, apdev):
+ """SAE PWE derivation options with group 25"""
+ run_sae_pwe_group(dev, apdev, 25)
+
+def test_sae_pwe_group_28(dev, apdev):
+ """SAE PWE derivation options with group 28"""
+ run_sae_pwe_group(dev, apdev, 28)
+
+def test_sae_pwe_group_29(dev, apdev):
+ """SAE PWE derivation options with group 29"""
+ run_sae_pwe_group(dev, apdev, 29)
+
+def test_sae_pwe_group_30(dev, apdev):
+ """SAE PWE derivation options with group 30"""
+ run_sae_pwe_group(dev, apdev, 30)
+
+def test_sae_pwe_group_1(dev, apdev):
+ """SAE PWE derivation options with group 1"""
+ run_sae_pwe_group(dev, apdev, 1)
+
+def test_sae_pwe_group_2(dev, apdev):
+ """SAE PWE derivation options with group 2"""
+ run_sae_pwe_group(dev, apdev, 2)
+
+def test_sae_pwe_group_5(dev, apdev):
+ """SAE PWE derivation options with group 5"""
+ run_sae_pwe_group(dev, apdev, 5)
+
+def test_sae_pwe_group_14(dev, apdev):
+ """SAE PWE derivation options with group 14"""
+ run_sae_pwe_group(dev, apdev, 14)
+
+def test_sae_pwe_group_15(dev, apdev):
+ """SAE PWE derivation options with group 15"""
+ run_sae_pwe_group(dev, apdev, 15)
+
+def test_sae_pwe_group_16(dev, apdev):
+ """SAE PWE derivation options with group 16"""
+ run_sae_pwe_group(dev, apdev, 16)
+
+def test_sae_pwe_group_22(dev, apdev):
+ """SAE PWE derivation options with group 22"""
+ run_sae_pwe_group(dev, apdev, 22)
+
+def test_sae_pwe_group_23(dev, apdev):
+ """SAE PWE derivation options with group 23"""
+ run_sae_pwe_group(dev, apdev, 23)
+
+def test_sae_pwe_group_24(dev, apdev):
+ """SAE PWE derivation options with group 24"""
+ run_sae_pwe_group(dev, apdev, 24)
+
+def start_sae_pwe_ap(apdev, group, sae_pwe):
+ params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_groups'] = str(group)
+ params['sae_pwe'] = str(sae_pwe)
+ return hostapd.add_ap(apdev, params)
+
+def run_sae_pwe_group(dev, apdev, group):
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ tls = dev[0].request("GET tls_library")
+ if group in [27, 28, 29, 30]:
+ if tls.startswith("OpenSSL") and "run=OpenSSL 1." in tls:
+ logger.info("Add Brainpool EC groups since OpenSSL is new enough")
+ else:
+ raise HwsimSkip("Brainpool curve not supported")
+ start_sae_pwe_ap(apdev[0], group, 2)
+ try:
+ check_sae_pwe_group(dev[0], group, 0)
+ check_sae_pwe_group(dev[0], group, 1)
+ check_sae_pwe_group(dev[0], group, 2)
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
+
+def check_sae_pwe_group(dev, group, sae_pwe):
+ dev.set("sae_groups", str(group))
+ dev.set("sae_pwe", str(sae_pwe))
+ dev.connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412")
+ dev.request("REMOVE_NETWORK all")
+ dev.wait_disconnected()
+ dev.dump_monitor()
+
+def test_sae_pwe_h2e_only_ap(dev, apdev):
+ """SAE PWE derivation with H2E-only AP"""
+ start_sae_pwe_ap(apdev[0], 19, 1)
+ try:
+ check_sae_pwe_group(dev[0], 19, 1)
+ check_sae_pwe_group(dev[0], 19, 2)
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
+
+ dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE", scan_freq="2412",
+ wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+ if ev is None:
+ raise Exception("No indication of mismatching network seen")
+
+def test_sae_pwe_loop_only_ap(dev, apdev):
+ """SAE PWE derivation with loop-only AP"""
+ start_sae_pwe_ap(apdev[0], 19, 0)
+ try:
+ check_sae_pwe_group(dev[0], 19, 0)
+ check_sae_pwe_group(dev[0], 19, 2)
+ dev[0].set("sae_pwe", "1")
+ dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412", wait_connect=False)
+ ev = dev[0].wait_event(["CTRL-EVENT-NETWORK-NOT-FOUND"], timeout=10)
+ if ev is None:
+ raise Exception("No indication of mismatching network seen")
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
+
+def test_sae_h2e_rejected_groups(dev, apdev):
+ """SAE H2E and rejected groups indication"""
+ params = hostapd.wpa2_params(ssid="sae-pwe", passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_groups'] = "19"
+ params['sae_pwe'] = "1"
+ hapd = hostapd.add_ap(apdev[0], params)
+ try:
+ dev[0].set("sae_groups", "21 20 19")
+ dev[0].set("sae_pwe", "1")
+ dev[0].connect("sae-pwe", psk="12345678", key_mgmt="SAE",
+ scan_freq="2412")
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
+
+def test_sae_h2e_password_id(dev, apdev):
+ """SAE H2E and password identifier"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ params = hostapd.wpa2_params(ssid="test-sae")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_pwe'] = '1'
+ params['sae_password'] = 'secret|id=pw id'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ try:
+ dev[0].request("SET sae_groups ")
+ dev[0].set("sae_pwe", "1")
+ dev[0].connect("test-sae", sae_password="secret",
+ sae_password_id="pw id",
+ key_mgmt="SAE", scan_freq="2412")
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
+
+def test_sae_auth_restart(dev, apdev):
+ """SAE and authentication restarts with H2E/looping"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ params = hostapd.wpa2_params(ssid="test-sae")
+ params['wpa_key_mgmt'] = 'SAE'
+ params['sae_pwe'] = '2'
+ params['sae_password'] = 'secret|id=pw id'
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ try:
+ dev[0].request("SET sae_groups ")
+ for pwe in [1, 0, 1]:
+ dev[0].set("sae_pwe", str(pwe))
+ dev[0].connect("test-sae", sae_password="secret",
+ sae_password_id="pw id",
+ key_mgmt="SAE", scan_freq="2412")
+ # Disconnect without hostapd removing the STA entry so that the
+ # following SAE authentication instance starts with an existing
+ # STA entry that has maintained some SAE state.
+ hapd.set("ext_mgmt_frame_handling", "1")
+ dev[0].request("REMOVE_NETWORK all")
+ req = hapd.mgmt_rx()
+ dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+ hapd.set("ext_mgmt_frame_handling", "0")
+ finally:
+ dev[0].set("sae_groups", "")
+ dev[0].set("sae_pwe", "0")
diff --git a/tests/hwsim/test_scan.py b/tests/hwsim/test_scan.py
index 0b302d5..a1e4171 100644
--- a/tests/hwsim/test_scan.py
+++ b/tests/hwsim/test_scan.py
@@ -1886,3 +1886,20 @@ def test_connect_mbssid_open_1(dev, apdev):
# able to start connection attempt.
dev[0].request("REMOVE_NETWORK all")
dev[0].dump_monitor()
+
+def test_scan_only_one(dev, apdev):
+ """Test that scanning with a single active AP only returns that one"""
+ dev[0].flush_scan_cache()
+ hostapd.add_ap(apdev[0], {"ssid": "test-scan"})
+ bssid = apdev[0]['bssid']
+
+ check_scan(dev[0], "use_id=1", test_busy=True)
+ dev[0].scan_for_bss(bssid, freq="2412")
+
+ status, stdout = hostapd.cmd_execute(dev[0], ['iw', dev[0].ifname, 'scan', 'dump'])
+ if status != 0:
+ raise Exception("iw scan dump failed with code %d" % status)
+ lines = stdout.split('\n')
+ entries = len(list(filter(lambda x: x.startswith('BSS '), lines)))
+ if entries != 1:
+ raise Exception("expected to find 1 BSS entry, got %d" % entries)
diff --git a/tests/hwsim/test_sigma_dut.py b/tests/hwsim/test_sigma_dut.py
index 2f41e70..38bb50c 100644
--- a/tests/hwsim/test_sigma_dut.py
+++ b/tests/hwsim/test_sigma_dut.py
@@ -20,7 +20,7 @@ import hostapd
from utils import HwsimSkip
from hwsim import HWSimRadio
import hwsim_utils
-from test_dpp import check_dpp_capab, update_hapd_config
+from test_dpp import check_dpp_capab, update_hapd_config, wait_auth_success
from test_suite_b import check_suite_b_192_capa, suite_b_as_params, suite_b_192_rsa_ap_params
from test_ap_eap import check_eap_capa, int_eap_server_params
from test_ap_hs20 import hs20_ap_params
@@ -297,6 +297,29 @@ def test_sigma_dut_sae(dev, apdev):
stop_sigma_dut(sigma)
+def test_sigma_dut_sae_pmkid_include(dev, apdev):
+ """sigma_dut controlled SAE association with PMKID"""
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+
+ ifname = dev[0].ifname
+ sigma = start_sigma_dut(ifname)
+
+ ssid = "test-sae"
+ params = hostapd.wpa2_params(ssid=ssid, passphrase="12345678")
+ params['wpa_key_mgmt'] = 'SAE'
+ params["ieee80211w"] = "2"
+ params["sae_confirm_immediate"] = "1"
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ sigma_dut_cmd_check("sta_reset_default,interface,%s" % ifname)
+ sigma_dut_cmd_check("sta_set_ip_config,interface,%s,dhcp,0,ip,127.0.0.11,mask,255.255.255.0" % ifname)
+ sigma_dut_cmd_check("sta_set_security,interface,%s,ssid,%s,passphrase,%s,type,SAE,encpType,aes-ccmp,keymgmttype,wpa2,PMKID_Include,enable" % (ifname, "test-sae", "12345678"))
+ sigma_dut_cmd_check("sta_associate,interface,%s,ssid,%s,channel,1" % (ifname, "test-sae"))
+ sigma_dut_wait_connected(ifname)
+ sigma_dut_cmd_check("sta_reset_default,interface," + ifname)
+ stop_sigma_dut(sigma)
+
def test_sigma_dut_sae_password(dev, apdev):
"""sigma_dut controlled SAE association and long password"""
if "SAE" not in dev[0].get_capability("auth_alg"):
@@ -496,6 +519,40 @@ def test_sigma_dut_ap_psk_sha256(dev, apdev, params):
finally:
stop_sigma_dut(sigma)
+def test_sigma_dut_ap_psk_deauth(dev, apdev, params):
+ """sigma_dut controlled AP and deauth commands"""
+ logdir = os.path.join(params['logdir'],
+ "sigma_dut_ap_psk_deauth.sigma-hostapd")
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir, debug=True)
+ try:
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-psk,MODE,11ng")
+ sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-PSK,PSK,12345678,PMF,Required")
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+
+ dev[0].connect("test-psk", key_mgmt="WPA-PSK-SHA256",
+ psk="12345678", ieee80211w="2", scan_freq="2412")
+ addr = dev[0].own_addr()
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("ap_deauth_sta,NAME,AP,sta_mac_address," + addr)
+ ev = dev[0].wait_disconnected()
+ dev[0].dump_monitor()
+ if "locally_generated=1" in ev:
+ raise Exception("Unexpected disconnection reason")
+ dev[0].wait_connected()
+ dev[0].dump_monitor()
+
+ sigma_dut_cmd_check("ap_deauth_sta,NAME,AP,sta_mac_address," + addr + ",disconnect,silent")
+ ev = dev[0].wait_event(["CTRL-EVENT-DISCONNECTED"], timeout=5)
+ if ev and "locally_generated=1" not in ev:
+ raise Exception("Unexpected disconnection")
+
+ sigma_dut_cmd_check("ap_reset_default")
+ finally:
+ stop_sigma_dut(sigma)
+
def test_sigma_dut_eap_ttls(dev, apdev, params):
"""sigma_dut controlled STA and EAP-TTLS parameters"""
logdir = params['logdir']
@@ -803,6 +860,30 @@ def test_sigma_dut_ap_sae(dev, apdev, params):
finally:
stop_sigma_dut(sigma)
+def test_sigma_dut_ap_sae_confirm_immediate(dev, apdev, params):
+ """sigma_dut controlled AP with SAE Confirm immediate"""
+ logdir = os.path.join(params['logdir'],
+ "sigma_dut_ap_sae_confirm_immediate.sigma-hostapd")
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ sigma_dut_cmd_check("ap_reset_default")
+ sigma_dut_cmd_check("ap_set_wireless,NAME,AP,CHANNEL,1,SSID,test-sae,MODE,11ng")
+ sigma_dut_cmd_check("ap_set_security,NAME,AP,KEYMGNT,WPA2-SAE,PSK,12345678,SAE_Confirm_Immediate,enable")
+ sigma_dut_cmd_check("ap_config_commit,NAME,AP")
+
+ dev[0].request("SET sae_groups ")
+ dev[0].connect("test-sae", key_mgmt="SAE", psk="12345678",
+ ieee80211w="2", scan_freq="2412")
+ if dev[0].get_status_field('sae_group') != '19':
+ raise Exception("Expected default SAE group not used")
+
+ sigma_dut_cmd_check("ap_reset_default")
+ finally:
+ stop_sigma_dut(sigma)
+
def test_sigma_dut_ap_sae_password(dev, apdev, params):
"""sigma_dut controlled AP with SAE and long password"""
logdir = os.path.join(params['logdir'],
@@ -1212,13 +1293,33 @@ def test_sigma_dut_dpp_qr_resp_8(dev, apdev):
"""sigma_dut DPP/QR responder (conf index 8)"""
run_sigma_dut_dpp_qr_resp(dev, apdev, 8)
+def test_sigma_dut_dpp_qr_resp_9(dev, apdev):
+ """sigma_dut DPP/QR responder (conf index 9)"""
+ run_sigma_dut_dpp_qr_resp(dev, apdev, 9)
+
+def test_sigma_dut_dpp_qr_resp_10(dev, apdev):
+ """sigma_dut DPP/QR responder (conf index 10)"""
+ run_sigma_dut_dpp_qr_resp(dev, apdev, 10)
+
def test_sigma_dut_dpp_qr_resp_chan_list(dev, apdev):
"""sigma_dut DPP/QR responder (channel list override)"""
run_sigma_dut_dpp_qr_resp(dev, apdev, 1, chan_list='81/2 81/6 81/1',
listen_chan=2)
+def test_sigma_dut_dpp_qr_resp_status_query(dev, apdev):
+ """sigma_dut DPP/QR responder status query"""
+ params = hostapd.wpa2_params(ssid="DPPNET01",
+ passphrase="ThisIsDppPassphrase")
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ try:
+ dev[1].set("dpp_config_processing", "2")
+ run_sigma_dut_dpp_qr_resp(dev, apdev, 3, status_query=True)
+ finally:
+ dev[1].set("dpp_config_processing", "0")
+
def run_sigma_dut_dpp_qr_resp(dev, apdev, conf_idx, chan_list=None,
- listen_chan=None):
+ listen_chan=None, status_query=False):
check_dpp_capab(dev[0])
check_dpp_capab(dev[1])
sigma = start_sigma_dut(dev[0].ifname)
@@ -1240,10 +1341,14 @@ def run_sigma_dut_dpp_qr_resp(dev, apdev, conf_idx, chan_list=None,
cmd = "dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Responder,DPPConfIndex,%d,DPPAuthDirection,Single,DPPProvisioningRole,Configurator,DPPConfEnrolleeRole,STA,DPPSigningKeyECC,P-256,DPPBS,QR,DPPTimeout,6" % conf_idx
if listen_chan:
cmd += ",DPPListenChannel," + str(listen_chan)
+ if status_query:
+ cmd += ",DPPStatusQuery,Yes"
res = sigma_dut_cmd(cmd, timeout=10)
t.join()
if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
raise Exception("Unexpected result: " + res)
+ if status_query and "StatusResult,0" not in res:
+ raise Exception("Status query did not succeed: " + res)
finally:
stop_sigma_dut(sigma)
@@ -2403,6 +2508,121 @@ def run_sigma_dut_ap_dpp_self_config(dev, apdev):
dev[0].wait_disconnected()
sigma_dut_cmd_check("ap_reset_default")
+
+def test_sigma_dut_ap_dpp_relay(dev, apdev, params):
+ """sigma_dut DPP AP as Relay to Controller"""
+ logdir = os.path.join(params['logdir'],
+ "sigma_dut_ap_dpp_relay.sigma-hostapd")
+ with HWSimRadio() as (radio, iface):
+ sigma = start_sigma_dut(iface, hostapd_logdir=logdir)
+ try:
+ run_sigma_dut_ap_dpp_relay(dev, apdev)
+ finally:
+ stop_sigma_dut(sigma)
+ dev[1].request("DPP_CONTROLLER_STOP")
+
+def run_sigma_dut_ap_dpp_relay(dev, apdev):
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+
+ # Controller
+ conf_id = dev[1].dpp_configurator_add()
+ dev[1].set("dpp_configurator_params",
+ " conf=sta-dpp configurator=%d" % conf_id)
+ id_c = dev[1].dpp_bootstrap_gen()
+ uri_c = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id_c)
+ res = dev[1].request("DPP_BOOTSTRAP_INFO %d" % id_c)
+ pkhash = None
+ for line in res.splitlines():
+ name, value = line.split('=')
+ if name == "pkhash":
+ pkhash = value
+ break
+ if not pkhash:
+ raise Exception("Could not fetch public key hash from Controller")
+ if "OK" not in dev[1].request("DPP_CONTROLLER_START"):
+ raise Exception("Failed to start Controller")
+
+ sigma_dut_cmd_check("ap_reset_default,program,DPP")
+ sigma_dut_cmd_check("ap_preset_testparameters,program,DPP,DPPConfiguratorAddress,127.0.0.1,DPPConfiguratorPKHash," + pkhash)
+ res = sigma_dut_cmd_check("dev_exec_action,program,DPP,DPPActionType,GetLocalBootstrap,DPPCryptoIdentifier,P-256,DPPBS,QR")
+
+ dev[0].dpp_auth_init(uri=uri_c, role="enrollee")
+ wait_auth_success(dev[1], dev[0], configurator=dev[1], enrollee=dev[0])
+
+ sigma_dut_cmd_check("ap_reset_default")
+
+def dpp_init_tcp_enrollee(dev, id1):
+ logger.info("Starting DPP initiator/enrollee (TCP) in a thread")
+ time.sleep(1)
+ cmd = "DPP_AUTH_INIT peer=%d role=enrollee tcp_addr=127.0.0.1" % id1
+ if "OK" not in dev.request(cmd):
+ raise Exception("Failed to initiate DPP Authentication")
+ ev = dev.wait_event(["DPP-CONF-RECEIVED"], timeout=5)
+ if ev is None:
+ raise Exception("DPP configuration not completed (Enrollee)")
+ logger.info("DPP initiator/enrollee done")
+
+def test_sigma_dut_dpp_tcp_conf_resp(dev, apdev):
+ """sigma_dut DPP TCP Configurator (Controller) as responder"""
+ run_sigma_dut_dpp_tcp_conf_resp(dev)
+
+def run_sigma_dut_dpp_tcp_conf_resp(dev, status_query=False):
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+ sigma = start_sigma_dut(dev[0].ifname)
+ try:
+ cmd = "dev_exec_action,program,DPP,DPPActionType,GetLocalBootstrap,DPPCryptoIdentifier,P-256,DPPBS,QR"
+ res = sigma_dut_cmd(cmd)
+ if "status,COMPLETE" not in res:
+ raise Exception("dev_exec_action did not succeed: " + res)
+ hex = res.split(',')[3]
+ uri = from_hex(hex)
+ logger.info("URI from sigma_dut: " + uri)
+
+ id1 = dev[1].dpp_qr_code(uri)
+
+ t = threading.Thread(target=dpp_init_tcp_enrollee, args=(dev[1], id1))
+ t.start()
+ cmd = "dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Responder,DPPConfIndex,1,DPPAuthDirection,Single,DPPProvisioningRole,Configurator,DPPConfEnrolleeRole,STA,DPPSigningKeyECC,P-256,DPPBS,QR,DPPOverTCP,yes,DPPTimeout,6"
+ if status_query:
+ cmd += ",DPPStatusQuery,Yes"
+ res = sigma_dut_cmd(cmd, timeout=10)
+ t.join()
+ if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
+ raise Exception("Unexpected result: " + res)
+ if status_query and "StatusResult,0" not in res:
+ raise Exception("Status query did not succeed: " + res)
+ finally:
+ stop_sigma_dut(sigma)
+
+def test_sigma_dut_dpp_tcp_enrollee_init(dev, apdev):
+ """sigma_dut DPP TCP Enrollee as initiator"""
+ check_dpp_capab(dev[0])
+ check_dpp_capab(dev[1])
+ sigma = start_sigma_dut(dev[0].ifname)
+ try:
+ # Controller
+ conf_id = dev[1].dpp_configurator_add()
+ dev[1].set("dpp_configurator_params",
+ " conf=sta-dpp configurator=%d" % conf_id)
+ id_c = dev[1].dpp_bootstrap_gen()
+ uri_c = dev[1].request("DPP_BOOTSTRAP_GET_URI %d" % id_c)
+ if "OK" not in dev[1].request("DPP_CONTROLLER_START"):
+ raise Exception("Failed to start Controller")
+
+ res = sigma_dut_cmd("dev_exec_action,program,DPP,DPPActionType,SetPeerBootstrap,DPPBootstrappingdata,%s,DPPBS,QR" % to_hex(uri_c))
+ if "status,COMPLETE" not in res:
+ raise Exception("dev_exec_action did not succeed: " + res)
+
+ cmd = "dev_exec_action,program,DPP,DPPActionType,AutomaticDPP,DPPAuthRole,Initiator,DPPAuthDirection,Single,DPPProvisioningRole,Enrollee,DPPConfEnrolleeRole,STA,DPPBS,QR,DPPOverTCP,127.0.0.1,DPPTimeout,6"
+ res = sigma_dut_cmd(cmd, timeout=10)
+ if "BootstrapResult,OK,AuthResult,OK,ConfResult,OK" not in res:
+ raise Exception("Unexpected result: " + res)
+ finally:
+ stop_sigma_dut(sigma)
+ dev[1].request("DPP_CONTROLLER_STOP")
+
def test_sigma_dut_preconfigured_profile(dev, apdev):
"""sigma_dut controlled connection using preconfigured profile"""
try:
diff --git a/tests/hwsim/test_wmediumd.py b/tests/hwsim/test_wmediumd.py
index 0a88101..a9d4c8e 100644
--- a/tests/hwsim/test_wmediumd.py
+++ b/tests/hwsim/test_wmediumd.py
@@ -9,6 +9,7 @@ from utils import HwsimSkip
from wpasupplicant import WpaSupplicant
from tshark import run_tshark
from test_ap_open import _test_ap_open
+from test_scan import test_scan_only_one as _test_scan_only_one
from test_wpas_mesh import check_mesh_support, check_mesh_group_added
from test_wpas_mesh import check_mesh_peer_connected, add_open_mesh_network
from test_wpas_mesh import check_mesh_group_removed
@@ -462,3 +463,21 @@ def _test_wmediumd_path_rann(dev, apdev):
dev[i].mesh_group_remove()
check_mesh_group_removed(dev[i])
dev[i].dump_monitor()
+
+def test_wmediumd_scan_only_one(dev, apdev, params):
+ """
+ Test that scanning with a single active AP only returns that one
+ (with wmediumd enabled)
+ """
+ fd, fn = tempfile.mkstemp()
+ try:
+ f = os.fdopen(fd, 'w')
+ f.write(CFG % (apdev[0]['bssid'], dev[0].own_addr()))
+ f.close()
+ p = start_wmediumd(fn, params)
+ try:
+ _test_scan_only_one(dev, apdev)
+ finally:
+ stop_wmediumd(p, params)
+ finally:
+ os.unlink(fn)
diff --git a/tests/hwsim/test_wpas_ap.py b/tests/hwsim/test_wpas_ap.py
index 8507497..5d6dfed 100644
--- a/tests/hwsim/test_wpas_ap.py
+++ b/tests/hwsim/test_wpas_ap.py
@@ -762,3 +762,53 @@ def test_wpas_ap_async_fail(dev):
dev[0].wait_disconnected()
finally:
clear_regdom_dev(dev)
+
+def test_wpas_ap_sae(dev):
+ """wpa_supplicant AP mode - SAE using psk"""
+ run_wpas_ap_sae(dev, False)
+
+def test_wpas_ap_sae_password(dev):
+ """wpa_supplicant AP mode - SAE using sae_password"""
+ run_wpas_ap_sae(dev, True)
+
+def test_wpas_ap_sae_pwe_1(dev):
+ """wpa_supplicant AP mode - SAE using sae_password and sae_pwe=1"""
+ try:
+ dev[0].set("sae_pwe", "1")
+ dev[1].set("sae_pwe", "1")
+ run_wpas_ap_sae(dev, True, sae_password_id=True)
+ finally:
+ dev[0].set("sae_pwe", "0")
+ dev[1].set("sae_pwe", "0")
+
+def run_wpas_ap_sae(dev, sae_password, sae_password_id=False):
+ if "SAE" not in dev[0].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ if "SAE" not in dev[1].get_capability("auth_alg"):
+ raise HwsimSkip("SAE not supported")
+ dev[0].request("SET sae_groups ")
+ id = dev[0].add_network()
+ dev[0].set_network(id, "mode", "2")
+ dev[0].set_network_quoted(id, "ssid", "wpas-ap-sae")
+ dev[0].set_network(id, "proto", "WPA2")
+ dev[0].set_network(id, "key_mgmt", "SAE")
+ dev[0].set_network(id, "pairwise", "CCMP")
+ dev[0].set_network(id, "group", "CCMP")
+ if sae_password:
+ dev[0].set_network_quoted(id, "sae_password", "12345678")
+ else:
+ dev[0].set_network_quoted(id, "psk", "12345678")
+ if sae_password_id:
+ pw_id = "pw id"
+ dev[0].set_network_quoted(id, "sae_password_id", pw_id)
+ else:
+ pw_id = None
+ dev[0].set_network(id, "frequency", "2412")
+ dev[0].set_network(id, "scan_freq", "2412")
+ dev[0].set_network(id, "wps_disabled", "1")
+ dev[0].select_network(id)
+ wait_ap_ready(dev[0])
+
+ dev[1].request("SET sae_groups ")
+ dev[1].connect("wpas-ap-sae", key_mgmt="SAE", sae_password="12345678",
+ sae_password_id=pw_id, scan_freq="2412")
diff --git a/tests/hwsim/test_wpas_mesh.py b/tests/hwsim/test_wpas_mesh.py
index 12b00f7..5f9c83e 100644
--- a/tests/hwsim/test_wpas_mesh.py
+++ b/tests/hwsim/test_wpas_mesh.py
@@ -1668,17 +1668,21 @@ def test_wpas_mesh_pmksa_caching_ext(dev, apdev):
dev[1].mesh_group_remove()
check_mesh_group_removed(dev[1])
+ check_mesh_peer_disconnected(dev[0])
dev[0].dump_monitor()
dev[1].dump_monitor()
res = dev[1].get_pmksa(addr0)
if res is not None:
raise Exception("Unexpected PMKSA cache entry remaining")
+ time.sleep(0.1)
if "OK" not in dev[1].request("MESH_PMKSA_ADD " + res2):
raise Exception("MESH_PMKSA_ADD failed")
dev[1].mesh_group_add(id)
check_mesh_group_added(dev[1])
check_mesh_peer_connected(dev[1])
+ check_mesh_peer_connected(dev[0])
+ time.sleep(0.1)
dev[0].dump_monitor()
dev[1].dump_monitor()
pmksa1b = dev[1].get_pmksa(addr0)
diff --git a/tests/hwsim/vm/parallel-vm.py b/tests/hwsim/vm/parallel-vm.py
index 7eb44a9..24e4a61 100755
--- a/tests/hwsim/vm/parallel-vm.py
+++ b/tests/hwsim/vm/parallel-vm.py
@@ -50,6 +50,8 @@ long_tests = ["ap_roam_open",
"discovery_pd_retries",
"ap_wps_setup_locked_timeout",
"ap_vht160",
+ 'he160',
+ 'he160b',
"dfs_radar",
"dfs",
"dfs_ht40_minus",
diff --git a/tests/test-eapol.c b/tests/test-eapol.c
index 0dd65e4..944e4cf 100644
--- a/tests/test-eapol.c
+++ b/tests/test-eapol.c
@@ -504,7 +504,7 @@ static int auth_init(struct wpa *wpa)
}
if (wpa_validate_wpa_ie(wpa->auth_group, wpa->auth, 2412, wpa->supp_ie,
- wpa->supp_ie_len, NULL, 0, NULL, 0) !=
+ wpa->supp_ie_len, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
diff --git a/wpa_supplicant/README-DPP b/wpa_supplicant/README-DPP
index 96b1735..457e32e 100644
--- a/wpa_supplicant/README-DPP
+++ b/wpa_supplicant/README-DPP
@@ -118,7 +118,9 @@ On successfully adding QR Code, a bootstrapping info id is returned.
Send provisioning request to enrollee. (conf is ap-dpp if enrollee is an
AP. conf is sta-dpp if enrollee is a client)
-> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> configurator=<configurator-id>
+> dpp_auth_init peer=<qr-code-id> conf=<ap-dpp|sta-dpp> ssid=<SSID hexdump> configurator=<configurator-id>
+or for legacy (PSK/SAE) provisioning for a station Enrollee:
+> dpp_auth_init peer=<qr-code-id> conf=sta-psk ssid=<SSID hexdump> pass=<passphrase hexdump>
The DPP values will be printed in the console. Save this values into the
config file. If the enrollee is an AP, we need to manually write these
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 725e096..59ca153 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -434,6 +434,8 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
pw->next = bss->sae_passwords;
bss->sae_passwords = pw;
}
+
+ bss->sae_pwe = wpa_s->conf->sae_pwe;
#endif /* CONFIG_SAE */
if (wpa_s->conf->go_interworking) {
@@ -773,6 +775,20 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
ssid->frequency = 2462; /* default channel 11 */
params.freq.freq = ssid->frequency;
+ if (ssid->mode == WPAS_MODE_AP && ssid->enable_edmg) {
+ u8 primary_channel;
+
+ if (ieee80211_freq_to_chan(ssid->frequency, &primary_channel) ==
+ NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_WARNING,
+ "EDMG: Failed to get the primary channel");
+ return -1;
+ }
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg, ssid->edmg_channel,
+ primary_channel, &params.freq.edmg);
+ }
+
params.wpa_proto = ssid->proto;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
@@ -911,6 +927,8 @@ int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
wpa_s->assoc_freq = ssid->frequency;
+ wpa_s->ap_iface->conf->enable_edmg = ssid->enable_edmg;
+ wpa_s->ap_iface->conf->edmg_channel = ssid->edmg_channel;
#if defined(CONFIG_P2P) && defined(CONFIG_ACS)
if (wpa_s->p2p_go_do_acs) {
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 5ad6fc7..33b3505 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -12,6 +12,7 @@
#include "utils/uuid.h"
#include "utils/ip_addr.h"
#include "common/ieee802_1x_defs.h"
+#include "common/sae.h"
#include "crypto/sha1.h"
#include "rsn_supp/wpa.h"
#include "eap_peer/eap.h"
@@ -2481,6 +2482,8 @@ static const struct parse_data ssid_fields[] = {
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 70200) },
{ INT_RANGE(fixed_freq, 0, 1) },
+ { INT_RANGE(enable_edmg, 0, 1) },
+ { INT_RANGE(edmg_channel, 9, 13) },
#ifdef CONFIG_ACS
{ INT_RANGE(acs, 0, 1) },
#endif /* CONFIG_ACS */
@@ -2763,6 +2766,9 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid)
dl_list_del(&psk->list);
bin_clear_free(psk, sizeof(*psk));
}
+#ifdef CONFIG_SAE
+ sae_deinit_pt(ssid->pt);
+#endif /* CONFIG_SAE */
bin_clear_free(ssid, sizeof(*ssid));
}
@@ -3102,6 +3108,15 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
}
ret = -1;
}
+#ifdef CONFIG_SAE
+ if (os_strcmp(var, "ssid") == 0 ||
+ os_strcmp(var, "psk") == 0 ||
+ os_strcmp(var, "sae_password") == 0 ||
+ os_strcmp(var, "sae_password_id") == 0) {
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ }
+#endif /* CONFIG_SAE */
break;
}
if (i == NUM_SSID_FIELDS) {
@@ -4982,6 +4997,7 @@ static const struct global_parse_data global_fields[] = {
{ INT(okc), 0 },
{ INT(pmf), 0 },
{ FUNC(sae_groups), 0 },
+ { INT_RANGE(sae_pwe, 0, 2), 0 },
{ INT_RANGE(sae_pmkid_in_assoc, 0, 1), 0 },
{ INT(dtim_period), 0 },
{ INT(beacon_int), 0 },
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 1734e00..326ac61 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -1165,6 +1165,14 @@ struct wpa_config {
int *sae_groups;
/**
+ * sae_pwe - SAE mechanism for PWE derivation
+ * 0 = hunting-and-pecking loop only
+ * 1 = hash-to-element only
+ * 2 = both hunting-and-pecking loop and hash-to-element enabled
+ */
+ int sae_pwe;
+
+ /**
* sae_pmkid_in_assoc - Whether to include PMKID in SAE Assoc Req
*/
int sae_pmkid_in_assoc;
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5005aa9..cf4b7bc 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -847,6 +847,8 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
INT(mode);
INT(no_auto_peer);
INT(frequency);
+ INT(enable_edmg);
+ INT(edmg_channel);
INT(fixed_freq);
#ifdef CONFIG_ACS
INT(acs);
@@ -1405,6 +1407,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config)
fprintf(f, "\n");
}
+ if (config->sae_pwe)
+ fprintf(f, "sae_pwe=%d\n", config->sae_pwe);
+
if (config->sae_pmkid_in_assoc)
fprintf(f, "sae_pmkid_in_assoc=%d\n",
config->sae_pmkid_in_assoc);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 649f8c8..98db1fe 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -213,6 +213,8 @@ struct wpa_ssid {
*/
char *sae_password_id;
+ struct sae_pt *pt;
+
/**
* ext_psk - PSK/passphrase name in external storage
*
@@ -484,6 +486,23 @@ struct wpa_ssid {
int frequency;
/**
+ * enable_edmg - Enable EDMG feature in STA/AP mode
+ *
+ * This flag is used for enabling the EDMG capability in STA/AP mode.
+ */
+ int enable_edmg;
+
+ /**
+ * edmg_channel - EDMG channel number
+ *
+ * This value is used to configure the EDMG channel bonding feature.
+ * In AP mode it defines the EDMG channel to start the AP on.
+ * in STA mode it defines the EDMG channel to use for connection
+ * (if supported by AP).
+ */
+ u8 edmg_channel;
+
+ /**
* fixed_freq - Use fixed frequency for IBSS
*/
int fixed_freq;
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 65d0271..7f8ec4a 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -2876,6 +2876,15 @@ static int wpa_supplicant_ctrl_iface_scan_result(
}
if (bss_is_dmg(bss)) {
const char *s;
+
+ if (get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION)) {
+ ret = os_snprintf(pos, end - pos, "[EDMG]");
+ if (os_snprintf_error(end - pos, ret))
+ return -1;
+ pos += ret;
+ }
+
ret = os_snprintf(pos, end - pos, "[DMG]");
if (os_snprintf_error(end - pos, ret))
return -1;
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index fc2fc2e..5e6b522 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3803,6 +3803,12 @@ static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
NULL,
NULL
},
+ { "MACAddressRandomizationMask", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ "a{say}",
+ wpas_dbus_getter_mac_address_randomization_mask,
+ wpas_dbus_setter_mac_address_randomization_mask,
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL }
};
@@ -4791,8 +4797,8 @@ void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
if (!wpa_s->dbus_groupobj_path) {
wpa_printf(MSG_DEBUG,
- "%s: Group object '%s' already unregistered",
- __func__, wpa_s->dbus_groupobj_path);
+ "%s: Group object has already unregistered",
+ __func__);
return;
}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index d2c84e5..2582092 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -984,8 +984,7 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
const struct wpa_dbus_property_desc *property_desc,
DBusMessageIter *iter, DBusError *error, void *user_data)
{
- const char *capabilities[10] = { NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL };
+ const char *capabilities[11];
size_t num_items = 0;
#ifdef CONFIG_FILS
struct wpa_global *global = user_data;
@@ -1028,6 +1027,9 @@ dbus_bool_t wpas_dbus_getter_global_capabilities(
#ifdef CONFIG_SHA384
capabilities[num_items++] = "sha384";
#endif /* CONFIG_SHA384 */
+#ifdef CONFIG_OWE
+ capabilities[num_items++] = "owe";
+#endif /* CONFIG_OWE */
return wpas_dbus_simple_array_property_getter(iter,
DBUS_TYPE_STRING,
@@ -3984,6 +3986,173 @@ out:
/**
+ * wpas_dbus_setter_mac_address_randomization_mask - Set masks used for
+ * MAC address randomization
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
+ *
+ * Setter for "MACAddressRandomizationMask" property.
+ */
+dbus_bool_t wpas_dbus_setter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ const char *key;
+ unsigned int rand_type = 0;
+ const u8 *mask;
+ int mask_len;
+ unsigned int rand_types_to_disable = MAC_ADDR_RAND_ALL;
+
+ dbus_message_iter_recurse(iter, &variant_iter);
+ if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY) {
+ dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+ "invalid message format");
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&variant_iter, &dict_iter);
+ while (dbus_message_iter_get_arg_type(&dict_iter) ==
+ DBUS_TYPE_DICT_ENTRY) {
+ dbus_message_iter_recurse(&dict_iter, &entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_STRING) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: key not a string", __func__);
+ return FALSE;
+ }
+ dbus_message_iter_get_basic(&entry_iter, &key);
+ dbus_message_iter_next(&entry_iter);
+ if (dbus_message_iter_get_arg_type(&entry_iter) !=
+ DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&entry_iter) !=
+ DBUS_TYPE_BYTE) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: mask was not a byte array",
+ __func__);
+ return FALSE;
+ }
+ dbus_message_iter_recurse(&entry_iter, &array_iter);
+ dbus_message_iter_get_fixed_array(&array_iter, &mask,
+ &mask_len);
+
+ if (os_strcmp(key, "scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCAN;
+ } else if (os_strcmp(key, "sched_scan") == 0) {
+ rand_type = MAC_ADDR_RAND_SCHED_SCAN;
+ } else if (os_strcmp(key, "pno") == 0) {
+ rand_type = MAC_ADDR_RAND_PNO;
+ } else {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: bad scan type \"%s\"",
+ __func__, key);
+ return FALSE;
+ }
+
+ if (mask_len != ETH_ALEN) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: malformed MAC mask given",
+ __func__);
+ return FALSE;
+ }
+
+ if (wpas_enable_mac_addr_randomization(
+ wpa_s, rand_type, wpa_s->perm_addr, mask)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to set up MAC address randomization for %s",
+ __func__, key);
+ return FALSE;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: Enabled MAC address randomization for %s with mask: "
+ MACSTR, wpa_s->ifname, key, MAC2STR(mask));
+ rand_types_to_disable &= ~rand_type;
+ dbus_message_iter_next(&dict_iter);
+ }
+
+ if (rand_types_to_disable &&
+ wpas_disable_mac_addr_randomization(wpa_s, rand_types_to_disable)) {
+ dbus_set_error(error, DBUS_ERROR_FAILED,
+ "%s: failed to disable MAC address randomization",
+ __func__);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+dbus_bool_t wpas_dbus_getter_mac_address_randomization_mask(
+ const struct wpa_dbus_property_desc *property_desc,
+ DBusMessageIter *iter, DBusError *error, void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
+ unsigned int i;
+ u8 mask_buf[ETH_ALEN];
+ /* Read docs on dbus_message_iter_append_fixed_array() for why this
+ * is necessary... */
+ u8 *mask = mask_buf;
+ static const struct {
+ const char *key;
+ unsigned int type;
+ } types[] = {
+ { "scan", MAC_ADDR_RAND_SCAN },
+ { "sched_scan", MAC_ADDR_RAND_SCHED_SCAN },
+ { "pno", MAC_ADDR_RAND_PNO }
+ };
+
+ if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+ "a{say}", &variant_iter) ||
+ !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+ "{say}", &dict_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(types); i++) {
+ if (wpas_mac_addr_rand_scan_get_mask(wpa_s, types[i].type,
+ mask))
+ continue;
+
+ if (!dbus_message_iter_open_container(&dict_iter,
+ DBUS_TYPE_DICT_ENTRY,
+ NULL, &entry_iter) ||
+ !dbus_message_iter_append_basic(&entry_iter,
+ DBUS_TYPE_STRING,
+ &types[i].key) ||
+ !dbus_message_iter_open_container(&entry_iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter,
+ DBUS_TYPE_BYTE,
+ &mask,
+ ETH_ALEN) ||
+ !dbus_message_iter_close_container(&entry_iter,
+ &array_iter) ||
+ !dbus_message_iter_close_container(&dict_iter,
+ &entry_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+ "no memory");
+ return FALSE;
+ }
+ }
+
+ if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
+ !dbus_message_iter_close_container(iter, &variant_iter)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/**
* wpas_dbus_getter_sta_address - Return the address of a connected station
* @iter: Pointer to incoming dbus message iter
* @error: Location to store error on failure
@@ -4491,7 +4660,7 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
DBusMessageIter iter_dict, variant_iter;
const char *group;
const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
- const char *key_mgmt[15]; /* max 15 key managements may be supported */
+ const char *key_mgmt[16]; /* max 16 key managements may be supported */
int n;
if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -4544,6 +4713,10 @@ static dbus_bool_t wpas_dbus_get_bss_security_prop(
if (ie_data->key_mgmt & WPA_KEY_MGMT_FT_SAE)
key_mgmt[n++] = "ft-sae";
#endif /* CONFIG_SAE */
+#ifdef CONFIG_OWE
+ if (ie_data->key_mgmt & WPA_KEY_MGMT_OWE)
+ key_mgmt[n++] = "owe";
+#endif /* CONFIG_OWE */
if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
key_mgmt[n++] = "wpa-none";
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index d922ce1..afa26ef 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -177,6 +177,8 @@ DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_engine_path);
DECLARE_ACCESSOR(wpas_dbus_getter_pkcs11_module_path);
DECLARE_ACCESSOR(wpas_dbus_getter_blobs);
DECLARE_ACCESSOR(wpas_dbus_getter_stas);
+DECLARE_ACCESSOR(wpas_dbus_getter_mac_address_randomization_mask);
+DECLARE_ACCESSOR(wpas_dbus_setter_mac_address_randomization_mask);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_address);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_aid);
DECLARE_ACCESSOR(wpas_dbus_getter_sta_caps);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 8cdd885..19715eb 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -40,6 +40,14 @@ static int wpas_dbus_validate_dbus_ipaddr(struct wpa_dbus_dict_entry entry)
}
+static dbus_bool_t no_p2p_mgmt_interface(DBusError *error)
+{
+ dbus_set_error_const(error, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+ return FALSE;
+}
+
+
/**
* Parses out the mac address from the peer object path.
* @peer_path - object path of the form
@@ -78,6 +86,22 @@ wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
}
+/**
+ * wpas_dbus_error_no_p2p_mgmt_iface - Return a new InterfaceUnknown error
+ * message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an unknown interface error.
+ */
+static DBusMessage * wpas_dbus_error_no_p2p_mgmt_iface(DBusMessage *message)
+{
+ wpa_printf(MSG_DEBUG, "dbus: Could not find P2P mgmt interface");
+ return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+ "Could not find P2P mgmt interface");
+}
+
+
DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
@@ -145,6 +169,10 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto error_nop2p;
+ }
if (wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types,
req_dev_types, NULL, 0, 0, NULL, freq))
@@ -157,8 +185,9 @@ DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
error_clear:
wpa_dbus_dict_entry_clear(&entry);
error:
- os_free(req_dev_types);
reply = wpas_dbus_error_invalid_args(message, entry.key);
+error_nop2p:
+ os_free(req_dev_types);
return reply;
}
@@ -166,7 +195,9 @@ error:
DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
struct wpa_supplicant *wpa_s)
{
- wpas_p2p_stop_find(wpa_s->global->p2p_init_wpa_s);
+ wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (wpa_s)
+ wpas_p2p_stop_find(wpa_s);
return NULL;
}
@@ -185,6 +216,8 @@ DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
return wpas_dbus_error_unknown_error(message,
@@ -204,6 +237,8 @@ DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
return wpas_dbus_error_no_memory(message);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
return dbus_message_new_error(message,
@@ -245,6 +280,8 @@ DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_ext_listen(wpa_s, period, interval))
return wpas_dbus_error_unknown_error(
@@ -350,6 +387,10 @@ DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
}
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
if (pg_object_path != NULL) {
char *net_id_str;
@@ -433,6 +474,12 @@ static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
"P2P is not available for this interface");
return FALSE;
}
+ if (!wpa_s->global->p2p_init_wpa_s) {
+ if (out_reply)
+ *out_reply = wpas_dbus_error_no_p2p_mgmt_iface(
+ message);
+ return no_p2p_mgmt_interface(error);
+ }
return TRUE;
}
@@ -822,6 +869,8 @@ DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
return wpas_dbus_error_invalid_args(message, NULL);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
WPAS_P2P_PD_FOR_GO_NEG, NULL) < 0)
@@ -1882,6 +1931,8 @@ dbus_bool_t wpas_dbus_getter_p2p_peer_groups(
wpa_s = peer_args->wpa_s;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
if (wpa_s_go) {
@@ -1963,6 +2014,9 @@ dbus_bool_t wpas_dbus_getter_persistent_groups(
dbus_bool_t success = FALSE;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return no_p2p_mgmt_interface(error);
+
if (!wpa_s->parent->dbus_new_path)
return FALSE;
@@ -2077,6 +2131,11 @@ DBusMessage * wpas_dbus_handler_add_persistent_group(
dbus_message_iter_init(message, &iter);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto err;
+ }
+
if (wpa_s->parent->dbus_new_path)
ssid = wpa_config_add_network(wpa_s->conf);
if (ssid == NULL) {
@@ -2159,6 +2218,10 @@ DBusMessage * wpas_dbus_handler_remove_persistent_group(
DBUS_TYPE_INVALID);
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s) {
+ reply = wpas_dbus_error_no_p2p_mgmt_iface(message);
+ goto out;
+ }
/*
* Extract the network ID and ensure the network is actually a child of
@@ -2235,6 +2298,8 @@ DBusMessage * wpas_dbus_handler_remove_all_persistent_groups(
struct wpa_config *config;
wpa_s = wpa_s->global->p2p_init_wpa_s;
+ if (!wpa_s)
+ return wpas_dbus_error_no_p2p_mgmt_iface(message);
config = wpa_s->conf;
ssid = config->ssid;
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 6ae07a4..792ab24 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -362,7 +362,7 @@ CONFIG_BACKEND=file
#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
# Add support for new DBus control interface
-# (fi.w1.hostap.wpa_supplicant1)
+# (fi.w1.wpa_supplicant1)
CONFIG_CTRL_IFACE_DBUS_NEW=y
# Add introspection support for new DBus control interface
diff --git a/wpa_supplicant/dpp_supplicant.c b/wpa_supplicant/dpp_supplicant.c
index b4341f1..425eff9 100644
--- a/wpa_supplicant/dpp_supplicant.c
+++ b/wpa_supplicant/dpp_supplicant.c
@@ -958,12 +958,13 @@ static void wpas_dpp_start_gas_server(struct wpa_supplicant *wpa_s)
static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
#ifdef CONFIG_DPP2
- if (auth->akm == DPP_AKM_SAE) {
+ if (conf->akm == DPP_AKM_SAE) {
#ifdef CONFIG_SAE
struct wpa_driver_capa capa;
int res;
@@ -990,27 +991,27 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
wpa_config_set_network_defaults(ssid);
ssid->disabled = 1;
- ssid->ssid = os_malloc(auth->ssid_len);
+ ssid->ssid = os_malloc(conf->ssid_len);
if (!ssid->ssid)
goto fail;
- os_memcpy(ssid->ssid, auth->ssid, auth->ssid_len);
- ssid->ssid_len = auth->ssid_len;
+ os_memcpy(ssid->ssid, conf->ssid, conf->ssid_len);
+ ssid->ssid_len = conf->ssid_len;
- if (auth->connector) {
+ if (conf->connector) {
ssid->key_mgmt = WPA_KEY_MGMT_DPP;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_REQUIRED;
- ssid->dpp_connector = os_strdup(auth->connector);
+ ssid->dpp_connector = os_strdup(conf->connector);
if (!ssid->dpp_connector)
goto fail;
}
- if (auth->c_sign_key) {
- ssid->dpp_csign = os_malloc(wpabuf_len(auth->c_sign_key));
+ if (conf->c_sign_key) {
+ ssid->dpp_csign = os_malloc(wpabuf_len(conf->c_sign_key));
if (!ssid->dpp_csign)
goto fail;
- os_memcpy(ssid->dpp_csign, wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
- ssid->dpp_csign_len = wpabuf_len(auth->c_sign_key);
+ os_memcpy(ssid->dpp_csign, wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
+ ssid->dpp_csign_len = wpabuf_len(conf->c_sign_key);
}
if (auth->net_access_key) {
@@ -1025,31 +1026,31 @@ static struct wpa_ssid * wpas_dpp_add_network(struct wpa_supplicant *wpa_s,
ssid->dpp_netaccesskey_expiry = auth->net_access_key_expiry;
}
- if (!auth->connector || dpp_akm_psk(auth->akm) ||
- dpp_akm_sae(auth->akm)) {
- if (!auth->connector)
+ if (!conf->connector || dpp_akm_psk(conf->akm) ||
+ dpp_akm_sae(conf->akm)) {
+ if (!conf->connector)
ssid->key_mgmt = 0;
- if (dpp_akm_psk(auth->akm))
+ if (dpp_akm_psk(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_PSK_SHA256 | WPA_KEY_MGMT_FT_PSK;
- if (dpp_akm_sae(auth->akm))
+ if (dpp_akm_sae(conf->akm))
ssid->key_mgmt |= WPA_KEY_MGMT_SAE |
WPA_KEY_MGMT_FT_SAE;
ssid->ieee80211w = MGMT_FRAME_PROTECTION_OPTIONAL;
- if (auth->passphrase[0]) {
+ if (conf->passphrase[0]) {
if (wpa_config_set_quoted(ssid, "psk",
- auth->passphrase) < 0)
+ conf->passphrase) < 0)
goto fail;
wpa_config_update_psk(ssid);
ssid->export_keys = 1;
} else {
- ssid->psk_set = auth->psk_set;
- os_memcpy(ssid->psk, auth->psk, PMK_LEN);
+ ssid->psk_set = conf->psk_set;
+ os_memcpy(ssid->psk, conf->psk, PMK_LEN);
}
}
- os_memcpy(wpa_s->dpp_last_ssid, auth->ssid, auth->ssid_len);
- wpa_s->dpp_last_ssid_len = auth->ssid_len;
+ os_memcpy(wpa_s->dpp_last_ssid, conf->ssid, conf->ssid_len);
+ wpa_s->dpp_last_ssid_len = conf->ssid_len;
return ssid;
fail:
@@ -1060,14 +1061,15 @@ fail:
static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
struct wpa_ssid *ssid;
if (wpa_s->conf->dpp_config_processing < 1)
return 0;
- ssid = wpas_dpp_add_network(wpa_s, auth);
+ ssid = wpas_dpp_add_network(wpa_s, auth, conf);
if (!ssid)
return -1;
@@ -1081,49 +1083,56 @@ static int wpas_dpp_process_config(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "DPP: Failed to update configuration");
#endif /* CONFIG_NO_CONFIG_WRITE */
+ return 0;
+}
+
+
+static void wpas_dpp_post_process_config(struct wpa_supplicant *wpa_s,
+ struct dpp_authentication *auth)
+{
if (wpa_s->conf->dpp_config_processing < 2)
- return 0;
+ return;
#ifdef CONFIG_DPP2
if (auth->peer_version >= 2) {
wpa_printf(MSG_DEBUG,
"DPP: Postpone connection attempt to wait for completion of DPP Configuration Result");
auth->connect_on_tx_status = 1;
- return 0;
+ return;
}
#endif /* CONFIG_DPP2 */
wpas_dpp_try_to_connect(wpa_s);
- return 0;
}
static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
- struct dpp_authentication *auth)
+ struct dpp_authentication *auth,
+ struct dpp_config_obj *conf)
{
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONF_RECEIVED);
- if (auth->ssid_len)
+ if (conf->ssid_len)
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONFOBJ_SSID "%s",
- wpa_ssid_txt(auth->ssid, auth->ssid_len));
- if (auth->connector) {
+ wpa_ssid_txt(conf->ssid, conf->ssid_len));
+ if (conf->connector) {
/* TODO: Save the Connector and consider using a command
* to fetch the value instead of sending an event with
* it. The Connector could end up being larger than what
* most clients are ready to receive as an event
* message. */
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_CONNECTOR "%s",
- auth->connector);
+ conf->connector);
}
- if (auth->c_sign_key) {
+ if (conf->c_sign_key) {
char *hex;
size_t hexlen;
- hexlen = 2 * wpabuf_len(auth->c_sign_key) + 1;
+ hexlen = 2 * wpabuf_len(conf->c_sign_key) + 1;
hex = os_malloc(hexlen);
if (hex) {
wpa_snprintf_hex(hex, hexlen,
- wpabuf_head(auth->c_sign_key),
- wpabuf_len(auth->c_sign_key));
+ wpabuf_head(conf->c_sign_key),
+ wpabuf_len(conf->c_sign_key));
wpa_msg(wpa_s, MSG_INFO, DPP_EVENT_C_SIGN_KEY "%s",
hex);
os_free(hex);
@@ -1151,7 +1160,7 @@ static int wpas_dpp_handle_config_obj(struct wpa_supplicant *wpa_s,
}
}
- return wpas_dpp_process_config(wpa_s, auth);
+ return wpas_dpp_process_config(wpa_s, auth, conf);
}
@@ -1165,6 +1174,7 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
struct dpp_authentication *auth = wpa_s->dpp_auth;
int res;
enum dpp_status_error status = DPP_STATUS_CONFIG_REJECTED;
+ unsigned int i;
wpa_s->dpp_gas_dialog_token = -1;
@@ -1202,9 +1212,14 @@ static void wpas_dpp_gas_resp_cb(void *ctx, const u8 *addr, u8 dialog_token,
goto fail;
}
- res = wpas_dpp_handle_config_obj(wpa_s, auth);
- if (res < 0)
- goto fail;
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res < 0)
+ goto fail;
+ }
+ if (auth->num_conf_obj)
+ wpas_dpp_post_process_config(wpa_s, auth);
status = DPP_STATUS_OK;
#ifdef CONFIG_TESTING_OPTIONS
@@ -1522,8 +1537,19 @@ static int wpas_dpp_process_conf_obj(void *ctx,
struct dpp_authentication *auth)
{
struct wpa_supplicant *wpa_s = ctx;
+ unsigned int i;
+ int res = -1;
+
+ for (i = 0; i < auth->num_conf_obj; i++) {
+ res = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[i]);
+ if (res)
+ break;
+ }
+ if (!res)
+ wpas_dpp_post_process_config(wpa_s, auth);
- return wpas_dpp_handle_config_obj(wpa_s, auth);
+ return res;
}
#endif /* CONFIG_DPP2 */
@@ -2193,7 +2219,10 @@ int wpas_dpp_configurator_sign(struct wpa_supplicant *wpa_s, const char *cmd)
wpas_dpp_set_testing_options(wpa_s, auth);
if (dpp_set_configurator(wpa_s->dpp, wpa_s, auth, cmd) == 0 &&
dpp_configurator_own_config(auth, curve, 0) == 0)
- ret = wpas_dpp_handle_config_obj(wpa_s, auth);
+ ret = wpas_dpp_handle_config_obj(wpa_s, auth,
+ &auth->conf_obj[0]);
+ if (!ret)
+ wpas_dpp_post_process_config(wpa_s, auth);
dpp_auth_deinit(auth);
os_free(curve);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index ba9a5ac..21ce943 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -850,6 +850,19 @@ static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
continue;
}
+#ifdef CONFIG_SAE
+ if (flagged && ((rate_ie[j] & 0x7f) ==
+ BSS_MEMBERSHIP_SELECTOR_SAE_H2E_ONLY)) {
+ if (wpa_s->conf->sae_pwe == 0) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " SAE H2E disabled");
+ return 0;
+ }
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
if (!flagged)
continue;
@@ -1249,6 +1262,19 @@ struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
continue;
}
+#ifdef CONFIG_SAE
+ if (wpa_s->conf->sae_pwe == 1 &&
+ wpa_key_mgmt_sae(ssid->key_mgmt) &&
+ (!(ie = wpa_bss_get_ie(bss, WLAN_EID_RSNX)) ||
+ ie[1] < 1 ||
+ !(ie[2] & BIT(WLAN_RSNX_CAPAB_SAE_H2E)))) {
+ if (debug_print)
+ wpa_dbg(wpa_s, MSG_DEBUG,
+ " skip - SAE H2E required, but not supported by the AP");
+ continue;
+ }
+#endif /* CONFIG_SAE */
+
#ifndef CONFIG_IBSS_RSN
if (ssid->mode == WPAS_MODE_IBSS &&
!(ssid->key_mgmt & (WPA_KEY_MGMT_NONE |
@@ -2385,7 +2411,7 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
@@ -2457,22 +2483,29 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
@@ -2634,14 +2667,19 @@ no_pfs:
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
}
+ if (p[0] == WLAN_EID_RSNX && p[1] >= 1)
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, p, len);
+
l -= len;
p += len;
}
if (!wpa_found && data->assoc_info.beacon_ies)
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
- if (!rsn_found && data->assoc_info.beacon_ies)
+ if (!rsn_found && data->assoc_info.beacon_ies) {
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
+ }
if (wpa_found || rsn_found)
wpa_s->ap_ies_from_associnfo = 1;
@@ -2661,7 +2699,7 @@ no_pfs:
static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
{
- const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+ const u8 *bss_wpa = NULL, *bss_rsn = NULL, *bss_rsnx = NULL;
if (!wpa_s->current_bss || !wpa_s->current_ssid)
return -1;
@@ -2672,11 +2710,14 @@ static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSNX);
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
return 0;
@@ -2728,6 +2769,9 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
int ft_completed, already_authorized;
int new_bss = 0;
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ struct wpa_bss *bss;
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_AP
if (wpa_s->ap_iface) {
@@ -2951,15 +2995,21 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wmm_ac_restore_tspecs(wpa_s);
}
+#if defined(CONFIG_FILS) || defined(CONFIG_MBO)
+ bss = wpa_bss_get_bssid(wpa_s, bssid);
+#endif /* CONFIG_FILS || CONFIG_MBO */
#ifdef CONFIG_FILS
if (wpa_key_mgmt_fils(wpa_s->key_mgmt)) {
- struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, bssid);
const u8 *fils_cache_id = wpa_bss_get_fils_cache_id(bss);
if (fils_cache_id)
wpa_sm_set_fils_cache_id(wpa_s->wpa, fils_cache_id);
}
#endif /* CONFIG_FILS */
+
+#ifdef CONFIG_MBO
+ wpas_mbo_check_pmf(wpa_s, bss, wpa_s->current_ssid);
+#endif /* CONFIG_MBO */
}
@@ -3004,7 +3054,8 @@ static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
int locally_generated)
{
if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
- !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+ !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+ wpa_key_mgmt_sae(wpa_s->key_mgmt))
return 0; /* Not in 4-way handshake with PSK */
/*
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 6934c47..36c0aff 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -111,6 +111,7 @@ static int supp_get_beacon_ie(void *ctx)
wpa_printf(MSG_DEBUG, "SUPP: %s", __func__);
/* TODO: get correct RSN IE */
+ wpa_sm_set_ap_rsnxe(peer->supp, NULL, 0);
return wpa_sm_set_ap_rsn_ie(peer->supp,
(u8 *) "\x30\x14\x01\x00"
"\x00\x0f\xac\x04"
@@ -464,7 +465,7 @@ static int ibss_rsn_auth_init(struct ibss_rsn *ibss_rsn,
"\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x04"
"\x01\x00\x00\x0f\xac\x02"
- "\x00\x00", 22, NULL, 0, NULL, 0) !=
+ "\x00\x00", 22, NULL, 0, NULL, 0, NULL, 0) !=
WPA_IE_OK) {
wpa_printf(MSG_DEBUG, "AUTH: wpa_validate_wpa_ie() failed");
return -1;
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 0261bb7..d8e9c95 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -2262,7 +2262,7 @@ int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
realm++;
wpa_msg(wpa_s, MSG_DEBUG,
"Interworking: Search for match with SIM/USIM domain %s",
- realm);
+ realm ? realm : "[NULL]");
if (realm &&
domain_name_list_contains(domain_names, realm, 1))
return 1;
diff --git a/wpa_supplicant/op_classes.c b/wpa_supplicant/op_classes.c
index 5c103ec..b15ac9e 100644
--- a/wpa_supplicant/op_classes.c
+++ b/wpa_supplicant/op_classes.c
@@ -16,13 +16,19 @@
#include "wpa_supplicant_i.h"
-static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode, u8 chan,
+static enum chan_allowed allow_channel(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 chan,
unsigned int *flags)
{
int i;
+ int is_6ghz = op_class >= 131 && op_class <= 135;
for (i = 0; i < mode->num_channels; i++) {
- if (mode->channels[i].chan == chan)
+ int chan_is_6ghz;
+
+ chan_is_6ghz = mode->channels[i].freq > 5940 &&
+ mode->channels[i].freq <= 7105;
+ if (is_6ghz == chan_is_6ghz && mode->channels[i].chan == chan)
break;
}
@@ -62,7 +68,8 @@ static int get_center_80mhz(struct hostapd_hw_modes *mode, u8 channel)
}
-static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
+static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode,
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -77,7 +84,8 @@ static enum chan_allowed verify_80mhz(struct hostapd_hw_modes *mode, u8 channel)
unsigned int flags;
u8 adj_chan = center_chan - 6 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70)) ||
@@ -120,7 +128,7 @@ static int get_center_160mhz(struct hostapd_hw_modes *mode, u8 channel)
static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
- u8 channel)
+ u8 op_class, u8 channel)
{
u8 center_chan;
unsigned int i;
@@ -135,7 +143,8 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
unsigned int flags;
u8 adj_chan = center_chan - 14 + i * 4;
- if (allow_channel(mode, adj_chan, &flags) == NOT_ALLOWED)
+ if (allow_channel(mode, op_class, adj_chan, &flags) ==
+ NOT_ALLOWED)
return NOT_ALLOWED;
if ((i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150)) ||
@@ -159,42 +168,42 @@ static enum chan_allowed verify_160mhz(struct hostapd_hw_modes *mode,
}
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw)
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw)
{
unsigned int flag = 0;
enum chan_allowed res, res2;
- res2 = res = allow_channel(mode, channel, &flag);
+ res2 = res = allow_channel(mode, op_class, channel, &flag);
if (bw == BW40MINUS) {
if (!(flag & HOSTAPD_CHAN_HT40MINUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel - 4, NULL);
+ res2 = allow_channel(mode, op_class, channel - 4, NULL);
} else if (bw == BW40PLUS) {
if (!(flag & HOSTAPD_CHAN_HT40PLUS))
return NOT_ALLOWED;
- res2 = allow_channel(mode, channel + 4, NULL);
+ res2 = allow_channel(mode, op_class, channel + 4, NULL);
} else if (bw == BW80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
} else if (bw == BW160) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 160 MHz specific version.
*/
- res2 = res = verify_160mhz(mode, channel);
+ res2 = res = verify_160mhz(mode, op_class, channel);
} else if (bw == BW80P80) {
/*
* channel is a center channel and as such, not necessarily a
* valid 20 MHz channels. Override earlier allow_channel()
* result and use only the 80 MHz specific version.
*/
- res2 = res = verify_80mhz(mode, channel);
+ res2 = res = verify_80mhz(mode, op_class, channel);
}
if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -284,7 +293,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
u8 channels[] = { 42, 58, 106, 122, 138, 155 };
for (i = 0; i < ARRAY_SIZE(channels); i++) {
- if (verify_channel(mode, channels[i], op_class->bw) !=
+ if (verify_channel(mode, op_class->op_class,
+ channels[i], op_class->bw) !=
NOT_ALLOWED)
return 1;
}
@@ -294,25 +304,35 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
if (op_class->op_class == 129) {
/* Check if either 160 MHz channels is allowed */
- return verify_channel(mode, 50, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 114, op_class->bw) != NOT_ALLOWED;
+ return verify_channel(mode, op_class->op_class, 50,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 114,
+ op_class->bw) != NOT_ALLOWED;
}
if (op_class->op_class == 130) {
/* Need at least two non-contiguous 80 MHz segments */
found = 0;
- if (verify_channel(mode, 42, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 58, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 42,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 58,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 122, op_class->bw) != NOT_ALLOWED ||
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 122,
+ op_class->bw) != NOT_ALLOWED ||
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 106, op_class->bw) != NOT_ALLOWED &&
- verify_channel(mode, 138, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 106,
+ op_class->bw) != NOT_ALLOWED &&
+ verify_channel(mode, op_class->op_class, 138,
+ op_class->bw) != NOT_ALLOWED)
found++;
- if (verify_channel(mode, 155, op_class->bw) != NOT_ALLOWED)
+ if (verify_channel(mode, op_class->op_class, 155,
+ op_class->bw) != NOT_ALLOWED)
found++;
if (found >= 2)
@@ -324,7 +344,8 @@ static int wpas_op_class_supported(struct wpa_supplicant *wpa_s,
found = 0;
for (chan = op_class->min_chan; chan <= op_class->max_chan;
chan += op_class->inc) {
- if (verify_channel(mode, chan, op_class->bw) != NOT_ALLOWED) {
+ if (verify_channel(mode, op_class->op_class, chan,
+ op_class->bw) != NOT_ALLOWED) {
found = 1;
break;
}
diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index e0723df..b78ff10 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -528,7 +528,8 @@ static int * wpas_add_channels(const struct oper_class_map *op,
next_freq = freqs;
for (i = 0; i < num_chans; i++) {
u8 chan = channels ? channels[i] : op->min_chan + i * op->inc;
- enum chan_allowed res = verify_channel(mode, chan, op->bw);
+ enum chan_allowed res = verify_channel(mode, op->op_class, chan,
+ op->bw);
if (res == NOT_ALLOWED || (res == NO_IR && active))
continue;
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 7abb028..4d158a9 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -79,6 +79,33 @@ static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
#endif /* CONFIG_WPS */
+static int wpa_setup_mac_addr_rand_params(struct wpa_driver_scan_params *params,
+ const u8 *mac_addr)
+{
+ u8 *tmp;
+
+ if (params->mac_addr) {
+ params->mac_addr_mask = NULL;
+ os_free(params->mac_addr);
+ params->mac_addr = NULL;
+ }
+
+ params->mac_addr_rand = 1;
+
+ if (!mac_addr)
+ return 0;
+
+ tmp = os_malloc(2 * ETH_ALEN);
+ if (!tmp)
+ return -1;
+
+ os_memcpy(tmp, mac_addr, 2 * ETH_ALEN);
+ params->mac_addr = tmp;
+ params->mac_addr_mask = tmp + ETH_ALEN;
+ return 0;
+}
+
+
/**
* wpa_supplicant_enabled_networks - Check whether there are enabled networks
* @wpa_s: Pointer to wpa_supplicant data
@@ -169,6 +196,10 @@ static void wpas_trigger_scan_cb(struct wpa_radio_work *work, int deinit)
return;
}
+ if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(params, wpa_s->mac_addr_scan);
+
if (wpas_update_random_addr_disassoc(wpa_s) < 0) {
wpa_msg(wpa_s, MSG_INFO,
"Failed to assign random MAC address for a scan");
@@ -1211,13 +1242,8 @@ ssid_list_set:
#endif /* CONFIG_P2P */
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_scan) {
- params.mac_addr = wpa_s->mac_addr_scan;
- params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_scan);
if (!is_zero_ether_addr(wpa_s->next_scan_bssid)) {
struct wpa_bss *bss;
@@ -1286,6 +1312,7 @@ scan:
wpabuf_free(extra_ie);
os_free(params.freqs);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
@@ -1664,20 +1691,16 @@ scan:
wpa_setband_scan_freqs(wpa_s, scan_params);
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_sched_scan) {
- params.mac_addr = wpa_s->mac_addr_sched_scan;
- params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
- ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params,
+ wpa_s->mac_addr_sched_scan);
wpa_scan_set_relative_rssi_params(wpa_s, scan_params);
ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params);
wpabuf_free(extra_ie);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret) {
wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
if (prev_state != wpa_s->wpa_state)
@@ -2535,23 +2558,9 @@ wpa_scan_clone_params(const struct wpa_driver_scan_params *src)
params->sched_scan_plans_num = src->sched_scan_plans_num;
}
- if (src->mac_addr_rand) {
- params->mac_addr_rand = src->mac_addr_rand;
-
- if (src->mac_addr && src->mac_addr_mask) {
- u8 *mac_addr;
-
- mac_addr = os_malloc(2 * ETH_ALEN);
- if (!mac_addr)
- goto failed;
-
- os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
- os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
- ETH_ALEN);
- params->mac_addr = mac_addr;
- params->mac_addr_mask = mac_addr + ETH_ALEN;
- }
- }
+ if (src->mac_addr_rand &&
+ wpa_setup_mac_addr_rand_params(params, src->mac_addr))
+ goto failed;
if (src->bssid) {
u8 *bssid;
@@ -2738,18 +2747,14 @@ int wpas_start_pno(struct wpa_supplicant *wpa_s)
}
if ((wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) &&
- wpa_s->wpa_state <= WPA_SCANNING) {
- params.mac_addr_rand = 1;
- if (wpa_s->mac_addr_pno) {
- params.mac_addr = wpa_s->mac_addr_pno;
- params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
- }
- }
+ wpa_s->wpa_state <= WPA_SCANNING)
+ wpa_setup_mac_addr_rand_params(&params, wpa_s->mac_addr_pno);
wpa_scan_set_relative_rssi_params(wpa_s, &params);
ret = wpa_supplicant_start_sched_scan(wpa_s, &params);
os_free(params.filter_ssids);
+ os_free(params.mac_addr);
if (ret == 0)
wpa_s->pno = 1;
else
@@ -2843,6 +2848,32 @@ int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
}
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask)
+{
+ const u8 *to_copy;
+
+ if ((wpa_s->mac_addr_rand_enable & type) != type)
+ return -1;
+
+ if (type == MAC_ADDR_RAND_SCAN) {
+ to_copy = wpa_s->mac_addr_scan;
+ } else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+ to_copy = wpa_s->mac_addr_sched_scan;
+ } else if (type == MAC_ADDR_RAND_PNO) {
+ to_copy = wpa_s->mac_addr_pno;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "scan: Invalid MAC randomization type=0x%x",
+ type);
+ return -1;
+ }
+
+ os_memcpy(mask, to_copy + ETH_ALEN, ETH_ALEN);
+ return 0;
+}
+
+
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s)
{
struct wpa_radio_work *work;
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 2aa0a8b..58caa78 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -52,6 +52,8 @@ void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
unsigned int type, const u8 *addr,
const u8 *mask);
+int wpas_mac_addr_rand_scan_get_mask(struct wpa_supplicant *wpa_s,
+ unsigned int type, u8 *mask);
int wpas_abort_ongoing_scan(struct wpa_supplicant *wpa_s);
void filter_scan_res(struct wpa_supplicant *wpa_s,
struct wpa_scan_results *res);
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index ad533a1..cfb5bb3 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -84,11 +84,16 @@ static int sme_set_sae_group(struct wpa_supplicant *wpa_s)
static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
const u8 *bssid, int external,
- int reuse)
+ int reuse, int *ret_use_pt)
{
struct wpabuf *buf;
size_t len;
const char *password;
+ struct wpa_bss *bss;
+ int use_pt = 0;
+
+ if (ret_use_pt)
+ *ret_use_pt = 0;
#ifdef CONFIG_TESTING_OPTIONS
if (wpa_s->sae_commit_override) {
@@ -117,6 +122,7 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
os_memcmp(bssid, wpa_s->sme.sae.tmp->bssid, ETH_ALEN) == 0) {
wpa_printf(MSG_DEBUG,
"SAE: Reuse previously generated PWE on a retry with the same AP");
+ use_pt = wpa_s->sme.sae.tmp->h2e;
goto reuse_data;
}
if (sme_set_sae_group(wpa_s) < 0) {
@@ -124,7 +130,31 @@ static struct wpabuf * sme_auth_build_sae_commit(struct wpa_supplicant *wpa_s,
return NULL;
}
- if (sae_prepare_commit(wpa_s->own_addr, bssid,
+ if (wpa_s->conf->sae_pwe == 1 || wpa_s->conf->sae_pwe == 2) {
+ bss = wpa_bss_get_bssid_latest(wpa_s, bssid);
+ if (bss) {
+ const u8 *rsnxe;
+
+ rsnxe = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
+ if (rsnxe && rsnxe[1] >= 1)
+ use_pt = !!(rsnxe[2] &
+ BIT(WLAN_RSNX_CAPAB_SAE_H2E));
+ }
+
+ if (wpa_s->conf->sae_pwe == 1 && !use_pt) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cannot use H2E with the selected AP");
+ return NULL;
+ }
+ }
+
+ if (use_pt &&
+ sae_prepare_commit_pt(&wpa_s->sme.sae, ssid->pt,
+ wpa_s->own_addr, bssid,
+ wpa_s->sme.sae_rejected_groups) < 0)
+ return NULL;
+ if (!use_pt &&
+ sae_prepare_commit(wpa_s->own_addr, bssid,
(u8 *) password, os_strlen(password),
ssid->sae_password_id,
&wpa_s->sme.sae) < 0) {
@@ -143,10 +173,13 @@ reuse_data:
return NULL;
if (!external) {
wpabuf_put_le16(buf, 1); /* Transaction seq# */
- wpabuf_put_le16(buf, WLAN_STATUS_SUCCESS);
+ wpabuf_put_le16(buf, use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
}
sae_write_commit(&wpa_s->sme.sae, buf, wpa_s->sme.sae_token,
ssid->sae_password_id);
+ if (ret_use_pt)
+ *ret_use_pt = use_pt;
return buf;
}
@@ -558,6 +591,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -651,7 +692,7 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
if (start)
resp = sme_auth_build_sae_commit(wpa_s, ssid,
bss->bssid, 0,
- start == 2);
+ start == 2, NULL);
else
resp = sme_auth_build_sae_confirm(wpa_s, 0);
if (resp == NULL) {
@@ -851,6 +892,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -905,7 +948,8 @@ void sme_authenticate(struct wpa_supplicant *wpa_s,
static int sme_external_auth_build_buf(struct wpabuf *buf,
struct wpabuf *params,
const u8 *sa, const u8 *da,
- u16 auth_transaction, u16 seq_num)
+ u16 auth_transaction, u16 seq_num,
+ u16 status_code)
{
struct ieee80211_mgmt *resp;
@@ -920,7 +964,7 @@ static int sme_external_auth_build_buf(struct wpabuf *buf,
resp->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
resp->seq_ctrl = host_to_le16(seq_num << 4);
resp->u.auth.auth_transaction = host_to_le16(auth_transaction);
- resp->u.auth.status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+ resp->u.auth.status_code = host_to_le16(status_code);
if (params)
wpabuf_put_buf(buf, params);
@@ -933,8 +977,9 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
struct wpabuf *resp, *buf;
+ int use_pt;
- resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0);
+ resp = sme_auth_build_sae_commit(wpa_s, ssid, bssid, 1, 0, &use_pt);
if (!resp) {
wpa_printf(MSG_DEBUG, "SAE: Failed to build SAE commit");
return -1;
@@ -949,7 +994,9 @@ static int sme_external_auth_send_sae_commit(struct wpa_supplicant *wpa_s,
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- bssid, 1, wpa_s->sme.seq_num);
+ bssid, 1, wpa_s->sme.seq_num,
+ use_pt ? WLAN_STATUS_SAE_HASH_TO_ELEMENT :
+ WLAN_STATUS_SUCCESS);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1018,7 +1065,8 @@ static void sme_external_auth_send_sae_confirm(struct wpa_supplicant *wpa_s,
}
wpa_s->sme.seq_num++;
sme_external_auth_build_buf(buf, resp, wpa_s->own_addr,
- da, 2, wpa_s->sme.seq_num);
+ da, 2, wpa_s->sme.seq_num,
+ WLAN_STATUS_SUCCESS);
wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1, 0);
wpabuf_free(resp);
wpabuf_free(buf);
@@ -1055,6 +1103,52 @@ void sme_external_auth_trigger(struct wpa_supplicant *wpa_s,
}
+static int sme_sae_is_group_enabled(struct wpa_supplicant *wpa_s, int group)
+{
+ int *groups = wpa_s->conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ int i;
+
+ if (!groups)
+ groups = default_groups;
+
+ for (i = 0; groups[i] > 0; i++) {
+ if (groups[i] == group)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int sme_check_sae_rejected_groups(struct wpa_supplicant *wpa_s,
+ const struct wpabuf *groups)
+{
+ size_t i, count;
+ const u8 *pos;
+
+ if (!groups)
+ return 0;
+
+ pos = wpabuf_head(groups);
+ count = wpabuf_len(groups) / 2;
+ for (i = 0; i < count; i++) {
+ int enabled;
+ u16 group;
+
+ group = WPA_GET_LE16(pos);
+ pos += 2;
+ enabled = sme_sae_is_group_enabled(wpa_s, group);
+ wpa_printf(MSG_DEBUG, "SAE: Rejected group %u is %s",
+ group, enabled ? "enabled" : "disabled");
+ if (enabled)
+ return 1;
+ }
+
+ return 0;
+}
+
+
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
u16 status_code, const u8 *data, size_t len,
int external, const u8 *sa)
@@ -1109,6 +1203,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
wpa_s->sme.sae.state == SAE_COMMITTED &&
(external || wpa_s->current_bss) && wpa_s->current_ssid) {
wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported");
+ int_array_add_unique(&wpa_s->sme.sae_rejected_groups,
+ wpa_s->sme.sae.group);
wpa_s->sme.sae_group_index++;
if (sme_set_sae_group(wpa_s) < 0)
return -1; /* no other groups enabled */
@@ -1133,7 +1229,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
return -1;
}
- if (status_code != WLAN_STATUS_SUCCESS)
+ if (status_code != WLAN_STATUS_SUCCESS &&
+ status_code != WLAN_STATUS_SAE_HASH_TO_ELEMENT)
return -1;
if (auth_transaction == 1) {
@@ -1145,12 +1242,16 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if ((!external && wpa_s->current_bss == NULL) ||
wpa_s->current_ssid == NULL)
return -1;
- if (wpa_s->sme.sae.state != SAE_COMMITTED)
- return -1;
+ if (wpa_s->sme.sae.state != SAE_COMMITTED) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Ignore commit message while waiting for confirm");
+ return 0;
+ }
if (groups && groups[0] <= 0)
groups = NULL;
res = sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL,
- groups);
+ groups, status_code ==
+ WLAN_STATUS_SAE_HASH_TO_ELEMENT);
if (res == SAE_SILENTLY_DISCARD) {
wpa_printf(MSG_DEBUG,
"SAE: Drop commit message due to reflection attack");
@@ -1159,6 +1260,12 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
if (res != WLAN_STATUS_SUCCESS)
return -1;
+ if (wpa_s->sme.sae.tmp &&
+ sme_check_sae_rejected_groups(
+ wpa_s,
+ wpa_s->sme.sae.tmp->peer_rejected_groups) < 0)
+ return -1;
+
if (sae_process_commit(&wpa_s->sme.sae) < 0) {
wpa_printf(MSG_DEBUG, "SAE: Failed to process peer "
"commit");
@@ -1174,6 +1281,8 @@ static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
sme_external_auth_send_sae_confirm(wpa_s, sa);
return 0;
} else if (auth_transaction == 2) {
+ if (status_code != WLAN_STATUS_SUCCESS)
+ return -1;
wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm");
if (wpa_s->sme.sae.state != SAE_CONFIRMED)
return -1;
@@ -1803,6 +1912,11 @@ pfs_fail:
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
@@ -2027,6 +2141,10 @@ void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
void sme_deinit(struct wpa_supplicant *wpa_s)
{
sme_clear_on_disassoc(wpa_s);
+#ifdef CONFIG_SAE
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE */
eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fa24121..47cec0b 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1427,20 +1427,18 @@ static const char *network_fields[] = {
#ifdef IEEE8021X_EAPOL
"eap_workaround", "pac_file", "fragment_size", "ocsp",
#endif /* IEEE8021X_EAPOL */
-#ifdef CONFIG_MESH
- "mode", "no_auto_peer", "mesh_rssi_threshold",
-#else /* CONFIG_MESH */
"mode",
-#endif /* CONFIG_MESH */
"proactive_key_caching", "disabled", "id_str",
"ieee80211w",
"mixed_cell", "frequency", "fixed_freq",
#ifdef CONFIG_MESH
+ "no_auto_peer", "mesh_rssi_threshold",
"mesh_basic_rates", "dot11MeshMaxRetries",
"dot11MeshRetryTimeout", "dot11MeshConfirmTimeout",
"dot11MeshHoldingTimeout",
#endif /* CONFIG_MESH */
"wpa_ptk_rekey", "bgscan", "ignore_broadcast_ssid",
+ "enable_edmg", "edmg_channel",
#ifdef CONFIG_P2P
"go_p2p_dev_addr", "p2p_client_list", "psk_list",
#endif /* CONFIG_P2P */
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index b3ad45e..f197352 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -598,7 +598,7 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
dst_addr = buf;
- os_memcpy(&proto, buf + ETH_ALEN, 2);
+ os_memcpy(&proto, (char *) buf + ETH_ALEN, 2);
if (!wpa_priv_allowed_l2_proto(proto)) {
wpa_printf(MSG_DEBUG, "Refused l2_packet send for ethertype "
@@ -607,7 +607,8 @@ static void wpa_priv_cmd_l2_send(struct wpa_priv_interface *iface,
}
res = l2_packet_send(iface->l2[idx], dst_addr, proto,
- buf + ETH_ALEN + 2, len - ETH_ALEN - 2);
+ (unsigned char *) buf + ETH_ALEN + 2,
+ len - ETH_ALEN - 2);
wpa_printf(MSG_DEBUG, "L2 send[idx=%d]: res=%d", idx, res);
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index e7ddaa1..6688d71 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -402,7 +402,10 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
@@ -1233,14 +1236,16 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
{
struct wpa_ie_data ie;
int sel, proto;
- const u8 *bss_wpa, *bss_rsn, *bss_osen;
+ const u8 *bss_wpa, *bss_rsn, *bss_rsnx, *bss_osen;
if (bss) {
bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+ bss_rsnx = wpa_bss_get_ie(bss, WLAN_EID_RSNX);
bss_osen = wpa_bss_get_vendor_ie(bss, OSEN_IE_VENDOR_TYPE);
- } else
- bss_wpa = bss_rsn = bss_osen = NULL;
+ } else {
+ bss_wpa = bss_rsn = bss_rsnx = bss_osen = NULL;
+ }
if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
@@ -1371,7 +1376,9 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
bss_wpa ? 2 + bss_wpa[1] : 0) ||
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
- bss_rsn ? 2 + bss_rsn[1] : 0))
+ bss_rsn ? 2 + bss_rsn[1] : 0) ||
+ wpa_sm_set_ap_rsnxe(wpa_s->wpa, bss_rsnx,
+ bss_rsnx ? 2 + bss_rsnx[1] : 0))
return -1;
}
@@ -1573,12 +1580,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OCV
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
@@ -1927,6 +1942,36 @@ int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s)
}
+static void wpa_s_setup_sae_pt(struct wpa_config *conf, struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_SAE
+ int *groups = conf->sae_groups;
+ int default_groups[] = { 19, 20, 21, 0 };
+ const char *password;
+
+ if (!groups || groups[0] <= 0)
+ groups = default_groups;
+
+ password = ssid->sae_password;
+ if (!password)
+ password = ssid->passphrase;
+
+ if (conf->sae_pwe == 0 || !password) {
+ /* PT derivation not needed */
+ sae_deinit_pt(ssid->pt);
+ ssid->pt = NULL;
+ return;
+ }
+
+ if (ssid->pt)
+ return; /* PT already derived */
+ ssid->pt = sae_derive_pt(groups, ssid->ssid, ssid->ssid_len,
+ (const u8 *) password, os_strlen(password),
+ ssid->sae_password_id);
+#endif /* CONFIG_SAE */
+}
+
+
static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit);
/**
@@ -1973,6 +2018,14 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (wpa_s->current_bss && wpa_s->current_bss != bss) {
os_get_reltime(&wpa_s->roam_start);
}
+ } else {
+#ifdef CONFIG_SAE
+#ifdef CONFIG_SME
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SME */
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+#endif /* CONFIG_SAE */
}
if (rand_style > 0 && !wpa_s->reassoc_same_ess) {
@@ -2433,7 +2486,8 @@ skip_ht40:
}
if (hostapd_set_freq_params(&vht_freq, mode->mode, freq->freq,
- freq->channel, freq->ht_enabled,
+ freq->channel, ssid->enable_edmg,
+ ssid->edmg_channel, freq->ht_enabled,
vht_freq.vht_enabled, freq->he_enabled,
freq->sec_channel_offset,
chwidth, seg0, seg1, vht_caps,
@@ -2951,6 +3005,12 @@ pfs_fail:
}
#endif /* CONFIG_IEEE80211R */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3022,6 +3082,117 @@ static void wpas_update_fils_connect_params(struct wpa_supplicant *wpa_s)
#endif /* CONFIG_FILS && IEEE8021X_EAPOL */
+static u8 wpa_ie_get_edmg_oper_chans(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_BSS_OPERATING_CHANNELS_OFFSET];
+}
+
+
+static u8 wpa_ie_get_edmg_oper_chan_width(const u8 *edmg_ie)
+{
+ if (!edmg_ie || edmg_ie[1] < 6)
+ return 0;
+ return edmg_ie[EDMG_OPERATING_CHANNEL_WIDTH_OFFSET];
+}
+
+
+/* Returns the intersection of two EDMG configurations.
+ * Note: The current implementation is limited to CB2 only (CB1 included),
+ * i.e., the implementation supports up to 2 contiguous channels.
+ * For supporting non-contiguous (aggregated) channels and for supporting
+ * CB3 and above, this function will need to be extended.
+ */
+static struct ieee80211_edmg_config
+get_edmg_intersection(struct ieee80211_edmg_config a,
+ struct ieee80211_edmg_config b,
+ u8 primary_channel)
+{
+ struct ieee80211_edmg_config result;
+ int i, contiguous = 0;
+ int max_contiguous = 0;
+
+ result.channels = b.channels & a.channels;
+ if (!result.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: cannot intersect channels 0x%x and 0x%x",
+ a.channels, b.channels);
+ goto fail;
+ }
+
+ if (!(result.channels & BIT(primary_channel - 1))) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: the primary channel %d is not one of the intersected channels 0x%x",
+ primary_channel, result.channels);
+ goto fail;
+ }
+
+ /* Find max contiguous channels */
+ for (i = 0; i < 6; i++) {
+ if (result.channels & BIT(i))
+ contiguous++;
+ else
+ contiguous = 0;
+
+ if (contiguous > max_contiguous)
+ max_contiguous = contiguous;
+ }
+
+ /* Assuming AP and STA supports ONLY contiguous channels,
+ * bw configuration can have value between 4-7.
+ */
+ if ((b.bw_config < a.bw_config))
+ result.bw_config = b.bw_config;
+ else
+ result.bw_config = a.bw_config;
+
+ if ((max_contiguous >= 2 && result.bw_config < EDMG_BW_CONFIG_5) ||
+ (max_contiguous >= 1 && result.bw_config < EDMG_BW_CONFIG_4)) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG not possible: not enough contiguous channels %d for supporting CB1 or CB2",
+ max_contiguous);
+ goto fail;
+ }
+
+ return result;
+
+fail:
+ result.channels = 0;
+ result.bw_config = 0;
+ return result;
+}
+
+
+static struct ieee80211_edmg_config
+get_supported_edmg(struct wpa_supplicant *wpa_s,
+ struct hostapd_freq_params *freq,
+ struct ieee80211_edmg_config request_edmg)
+{
+ enum hostapd_hw_mode hw_mode;
+ struct hostapd_hw_modes *mode = NULL;
+ u8 primary_channel;
+
+ if (!wpa_s->hw.modes)
+ goto fail;
+
+ hw_mode = ieee80211_freq_to_chan(freq->freq, &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto fail;
+
+ mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, hw_mode);
+ if (!mode)
+ goto fail;
+
+ return get_edmg_intersection(mode->edmg, request_edmg, primary_channel);
+
+fail:
+ request_edmg.channels = 0;
+ request_edmg.bw_config = 0;
+ return request_edmg;
+}
+
+
#ifdef CONFIG_MBO
void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s)
{
@@ -3057,6 +3228,7 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
struct wpa_ssid *ssid = cwork->ssid;
struct wpa_supplicant *wpa_s = work->wpa_s;
u8 *wpa_ie;
+ const u8 *edmg_ie_oper;
int use_crypt, ret, i, bssid_changed;
unsigned int cipher_pairwise, cipher_group, cipher_group_mgmt;
struct wpa_driver_associate_params params;
@@ -3149,6 +3321,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
if (!wpa_ie) {
@@ -3240,6 +3414,71 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
params.beacon_int = wpa_s->conf->beacon_int;
}
+ if (bss && ssid->enable_edmg)
+ edmg_ie_oper = get_ie_ext((const u8 *) (bss + 1), bss->ie_len,
+ WLAN_EID_EXT_EDMG_OPERATION);
+ else
+ edmg_ie_oper = NULL;
+
+ if (edmg_ie_oper) {
+ params.freq.edmg.channels =
+ wpa_ie_get_edmg_oper_chans(edmg_ie_oper);
+ params.freq.edmg.bw_config =
+ wpa_ie_get_edmg_oper_chan_width(edmg_ie_oper);
+ wpa_printf(MSG_DEBUG,
+ "AP supports EDMG channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+
+ /* User may ask for specific EDMG channel for EDMG connection
+ * (must be supported by AP)
+ */
+ if (ssid->edmg_channel) {
+ struct ieee80211_edmg_config configured_edmg;
+ enum hostapd_hw_mode hw_mode;
+ u8 primary_channel;
+
+ hw_mode = ieee80211_freq_to_chan(bss->freq,
+ &primary_channel);
+ if (hw_mode == NUM_HOSTAPD_MODES)
+ goto edmg_fail;
+
+ hostapd_encode_edmg_chan(ssid->enable_edmg,
+ ssid->edmg_channel,
+ primary_channel,
+ &configured_edmg);
+
+ if (ieee802_edmg_is_allowed(params.freq.edmg,
+ configured_edmg)) {
+ params.freq.edmg = configured_edmg;
+ wpa_printf(MSG_DEBUG,
+ "Use EDMG channel %d for connection",
+ ssid->edmg_channel);
+ } else {
+ edmg_fail:
+ params.freq.edmg.channels = 0;
+ params.freq.edmg.bw_config = 0;
+ wpa_printf(MSG_WARNING,
+ "EDMG channel %d not supported by AP, fallback to DMG",
+ ssid->edmg_channel);
+ }
+ }
+
+ if (params.freq.edmg.channels) {
+ wpa_printf(MSG_DEBUG,
+ "EDMG before: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ params.freq.edmg = get_supported_edmg(wpa_s,
+ &params.freq,
+ params.freq.edmg);
+ wpa_printf(MSG_DEBUG,
+ "EDMG after: channels 0x%x, bw_config %d",
+ params.freq.edmg.channels,
+ params.freq.edmg.bw_config);
+ }
+ }
+
params.pairwise_suite = cipher_pairwise;
params.group_suite = cipher_group;
params.mgmt_group_suite = cipher_group_mgmt;
@@ -3800,9 +4039,15 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
+#if defined(CONFIG_SAE) && defined(CONFIG_SME)
+ os_free(wpa_s->sme.sae_rejected_groups);
+ wpa_s->sme.sae_rejected_groups = NULL;
+#endif /* CONFIG_SAE && CONFIG_SME */
wpa_s->last_owe_group = 0;
- if (ssid)
+ if (ssid) {
ssid->owe_transition_bss_select_count = 0;
+ wpa_s_setup_sae_pt(wpa_s->conf, ssid);
+ }
if (wpa_s->connect_without_scan ||
wpa_supplicant_fast_associate(wpa_s) != 1) {
@@ -4381,6 +4626,11 @@ int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
wpas_wps_update_mac_addr(wpa_s);
+#ifdef CONFIG_FST
+ if (wpa_s->fst)
+ fst_update_mac_addr(wpa_s->fst, wpa_s->own_addr);
+#endif /* CONFIG_FST */
+
return 0;
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 0babadc..ba511b9 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -425,6 +425,14 @@ fast_reauth=1
# since all implementations are required to support group 19.
#sae_groups=19 20 21
+# SAE mechanism for PWE derivation
+# 0 = hunting-and-pecking loop only (default)
+# 1 = hash-to-element only
+# 2 = both hunting-and-pecking loop and hash-to-element enabled
+# Note: The default value is likely to change from 0 to 2 once the new
+# hash-to-element mechanism has received more interoperability testing.
+#sae_pwe=0
+
# Default value for DTIM period (if not overridden in network block)
#dtim_period=2
@@ -1548,6 +1556,16 @@ fast_reauth=1
# Set to 1 to disable BSS transition management
#disable_btm=0
+# Enable EDMG capability in STA/AP mode, default value is false
+#enable_edmg=1
+
+# This value is used to configure the channel bonding feature.
+# Default value is 0.
+# Relevant only if enable_edmg is true
+# In AP mode it defines the EDMG channel to use for AP operation.
+# In STA mode it defines the EDMG channel for connection (if supported by AP).
+#edmg_channel=9
+
# Example blocks:
# Simple case: WPA-PSK, PSK as an ASCII passphrase, allow all valid ciphers
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index af93806..8c5defc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -614,6 +614,9 @@ struct wpa_supplicant {
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;
@@ -810,6 +813,7 @@ struct wpa_supplicant {
u8 ext_auth_bssid[ETH_ALEN];
u8 ext_auth_ssid[SSID_MAX_LEN];
size_t ext_auth_ssid_len;
+ int *sae_rejected_groups;
#endif /* CONFIG_SAE */
} sme;
#endif /* CONFIG_SME */
@@ -1422,8 +1426,8 @@ enum chan_allowed {
NOT_ALLOWED, NO_IR, ALLOWED
};
-enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 channel,
- u8 bw);
+enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,
+ u8 channel, u8 bw);
size_t wpas_supp_op_class_ie(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
int freq, u8 *pos, size_t len);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 62af7f6..d80b8f2 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -396,6 +396,10 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
ret = -1;
+
+ ie = wpa_bss_get_ie(curr, WLAN_EID_RSNX);
+ if (wpa_sm_set_ap_rsnxe(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+ ret = -1;
} else {
ret = -1;
}